diff --git a/testssl.sh b/testssl.sh index 9f92e34..8633084 100755 --- a/testssl.sh +++ b/testssl.sh @@ -712,6 +712,9 @@ fixme() { pr_warning "fixme: $1"; } fixmeln_term() { pr_warningln_term "fixme: $1"; } fixmeln() { pr_warningln "fixme: $1"; } +pr_url() { out_term "$1"; out_html "$1"; } +pr_boldurl() { pr_bold_term "$1"; out_html "$1"; } + ### color switcher (see e.g. https://linuxtidbits.wordpress.com/2008/08/11/output-color-on-bash-scripts/ ### http://www.tldp.org/HOWTO/Bash-Prompt-HOWTO/x405.html set_color_functions() { @@ -2343,7 +2346,7 @@ openssl2rfc() { [[ "$1" == "${TLS_CIPHER_OSSL_NAME[i]}" ]] && rfcname="${TLS_CIPHER_RFC_NAME[i]}" && break done [[ "$rfcname" == "-" ]] && rfcname="" - [[ -n "$rfcname" ]] && out "$rfcname" + [[ -n "$rfcname" ]] && retstring "$rfcname" return 0 } @@ -2355,7 +2358,7 @@ rfc2openssl() { [[ "$1" == "${TLS_CIPHER_RFC_NAME[i]}" ]] && ossl_name="${TLS_CIPHER_OSSL_NAME[i]}" && break done [[ "$ossl_name" == "-" ]] && ossl_name="" - [[ -n "$ossl_name" ]] && out "$ossl_name" + [[ -n "$ossl_name" ]] && retstring "$ossl_name" return 0 } @@ -2990,7 +2993,7 @@ run_cipher_per_proto() { fi outln neat_header - outln " -ssl2 22 SSLv2\n -ssl3 00 SSLv3\n -tls1 01 TLS 1\n -tls1_1 02 TLS 1.1\n -tls1_2 03 TLS 1.2"| while read proto proto_hex proto_text; do + retstring " -ssl2 22 SSLv2\n -ssl3 00 SSLv3\n -tls1 01 TLS 1\n -tls1_1 02 TLS 1.1\n -tls1_2 03 TLS 1.2\n" | while read proto proto_hex proto_text; do "$using_sockets" || locally_supported "$proto" "$proto_text" || continue "$using_sockets" && out "$proto_text " outln @@ -3289,7 +3292,7 @@ create_client_simulation_tls_clienthello() { if [[ $offset -ge $tls_handshake_ascii_len ]]; then # No extensions - out "$tls_handshake_ascii" + retstring "$tls_handshake_ascii" return 0 fi @@ -4363,7 +4366,7 @@ run_prototest_openssl() { # idempotent function to add SSL/TLS protocols. It should ease testing # PROTOS_OFFERED's content is in openssl terminology add_tls_offered() { - grep -w "$1" <<< "$PROTOS_OFFERED" || PROTOS_OFFERED+="$1 " + grep -qw "$1" <<< "$PROTOS_OFFERED" || PROTOS_OFFERED+="$1 " } # function which checks whether SSLv2 - TLS 1.2 is being offereed @@ -5190,7 +5193,7 @@ cipher_pref_check() { pr_bold " Cipher order" - retstring " ssl3 00 SSLv3\n tls1 01 TLSv1\n tls1_1 02 TLSv1.1\n tls1_2 03 TLSv1.2\n"| while read p proto_hex proto; do + retstring " ssl3 00 SSLv3\n tls1 01 TLSv1\n tls1_1 02 TLSv1.1\n tls1_2 03 TLSv1.2\n" | while read p proto_hex proto; do order=""; ciphers_found_with_sockets=false if [[ $p == ssl3 ]] && ! "$HAS_SSL3" && ! "$using_sockets"; then out "\n SSLv3: "; local_problem "$OPENSSL doesn't support \"s_client -ssl3\""; @@ -5363,7 +5366,7 @@ cipher_pref_check() { order="" $OPENSSL s_client $BUGS -nextprotoneg "$p" -connect $NODEIP:$PORT $SNI >$ERRFILE >$TMPFILE cipher=$(awk '/Cipher.*:/ { print $3 }' $TMPFILE) - printf " %-10s %s " "$p:" "$cipher" + out "$(printf " %-10s %s " "$p:" "$cipher")" tested_cipher="-"$cipher order="$cipher" if ! "$FAST"; then @@ -6583,7 +6586,7 @@ run_server_defaults() { i=1 newhostcert=$(cat $HOSTCERT) while [[ $i -le $certs_found ]]; do - if [ "$newhostcert" == "${previous_hostcert[i]}" ]; then + if [[ "$newhostcert" == "${previous_hostcert[i]}" ]]; then match_found=true break; fi @@ -9304,12 +9307,12 @@ run_heartbleed(){ if [[ "${saved_sockreply[1]}" == "${saved_sockreply[2]}" ]] && [[ "${saved_sockreply[2]}" == "${saved_sockreply[3]}" ]] \ && "$found_500_oops"; then pr_done_best "not vulnerable (OK)$append" - [[ $DEBUG -ge 1 ]] && out_term ", successful weeded out vsftpd false positive" + [[ $DEBUG -ge 1 ]] && out ", successful weeded out vsftpd false positive" fileout "heartbleed" "OK" "Heartbleed: not vulnerable $append" "$cve" "$cwe" else out "likely " pr_svrty_critical "VULNERABLE (NOT ok)" - [[ $DEBUG -ge 1 ]] && out_term " use debug >=2 to confirm" + [[ $DEBUG -ge 1 ]] && out " use debug >=2 to confirm" fileout "heartbleed" "CRITICAL" "Heartbleed: likely VULNERABLE $append" "$cve" "$cwe" "$hint" fi else @@ -9850,7 +9853,7 @@ run_tls_poodle() { pr_bold " POODLE, TLS"; out " ($cve), experimental " #FIXME - echo "#FIXME" + pr_warningln "#FIXME" fileout "poodle_tls" "WARN" "POODLE, TLS: Not tested. Not yet implemented #FIXME" "$cve" "$cwe" return 7 } @@ -10285,7 +10288,9 @@ run_drown() { if [[ "$DEBUG" -ge 1 ]] || "$SHOW_CENSYS_LINK"; then # not advertising it as it after 5 tries and account is needed cert_fingerprint_sha2=${cert_fingerprint_sha2/SHA256 /} - outln "$spaces https://censys.io/ipv4?q=$cert_fingerprint_sha2 could help you to find out" + out "$spaces " + pr_url "https://censys.io/ipv4?q=$cert_fingerprint_sha2" + outln " could help you to find out" fileout "drown" "INFO" "make sure you don't use this certificate elsewhere with SSLv2 enabled services, see https://censys.io/ipv4?q=$cert_fingerprint_sha2" fi else @@ -10889,9 +10894,11 @@ run_youknowwho() { old_fart() { - outln "Get precompiled bins or compile https://github.com/PeterMosmans/openssl ." + out "Get precompiled bins or compile " + pr_url "https://github.com/PeterMosmans/openssl" + outln "." fileout "old_fart" "WARN" "Your $OPENSSL $OSSL_VER version is an old fart... . It doesn\'t make much sense to proceed. Get precompiled bins or compile https://github.com/PeterMosmans/openssl ." - fatal "Your $OPENSSL $OSSL_VER version is an old fart... . It doesn\'t make much sense to proceed." -5 + fatal "Your $OPENSSL $OSSL_VER version is an old fart... . It doesn't make much sense to proceed." -5 } # try very hard to determine the install path to get ahold of the mapping file and the CA bundles @@ -10977,7 +10984,7 @@ find_openssl_binary() { # 0. check environment variable whether it's executable if [[ -n "$OPENSSL" ]] && [[ ! -x "$OPENSSL" ]]; then pr_warningln "\ncannot find specified (\$OPENSSL=$OPENSSL) binary." - outln " Looking some place else ..." + outln_term " Looking some place else ..." elif [[ -x "$OPENSSL" ]]; then : # 1. all ok supplied $OPENSSL was found and has excutable bit set -- testrun comes below elif [[ -e "/mnt/c/Windows/System32/bash.exe" ]] && test_openssl_suffix "$(dirname "$(which openssl)")"; then @@ -11087,10 +11094,12 @@ check4openssl_oldfarts() { pr_warningln " Your \"$OPENSSL\" is way too old (/dev/null)\" [~$OPENSSL_NR_CIPHERS ciphers]" out " on $HNAME:" @@ -11536,10 +11546,10 @@ prepare_logging() { : # just for clarity: a log file was specified, no need to do anything else fi >$LOGFILE - outln "## Scan started as: \"$PROG_NAME $CMDLINE\"" >>${LOGFILE} - outln "## at $HNAME:$OPENSSL_LOCATION" >>${LOGFILE} - outln "## version testssl: $VERSION ${GIT_REL_SHORT:-$CVS_REL_SHORT} from $REL_DATE" >>${LOGFILE} - outln "## version openssl: \"$OSSL_VER\" from \"$OSSL_BUILD_DATE\")\n" >>${LOGFILE} + outln_term "## Scan started as: \"$PROG_NAME $CMDLINE\"" >>${LOGFILE} + outln_term "## at $HNAME:$OPENSSL_LOCATION" >>${LOGFILE} + outln_term "## version testssl: $VERSION ${GIT_REL_SHORT:-$CVS_REL_SHORT} from $REL_DATE" >>${LOGFILE} + outln_term "## version openssl: \"$OSSL_VER\" from \"$OSSL_BUILD_DATE\")\n" >>${LOGFILE} exec > >(tee -a ${LOGFILE}) # not decided yet. Maybe good to have a separate file or none at all #exec 2> >(tee -a ${LOGFILE} >&2) @@ -12031,8 +12041,8 @@ determine_service() { grep -q '^Server Temp Key' $TMPFILE && HAS_DH_BITS=true # FIX #190 out " Service set:$CORRECT_SPACES STARTTLS via " fileout "service" "INFO" "$protocol" - toupper "$protocol" - [[ -n "$XMPP_HOST" ]] && echo -n " (XMPP domain=\'$XMPP_HOST\')" + out "$(toupper "$protocol")" + [[ -n "$XMPP_HOST" ]] && out " (XMPP domain=\'$XMPP_HOST\')" outln ;; *) outln @@ -12355,7 +12365,7 @@ parse_cmd_line() { case $STARTTLS_PROTOCOL in ftp|smtp|pop3|imap|xmpp|telnet|ldap|nntp|postgres) ;; ftps|smtps|pop3s|imaps|xmpps|telnets|ldaps|nntps|postgress) ;; - *) pr_magentaln "\nunrecognized STARTTLS protocol \"$1\", see help" 1>&2 + *) pr_magentaln_term "\nunrecognized STARTTLS protocol \"$1\", see help" 1>&2 help 1 ;; esac ;; @@ -12514,7 +12524,7 @@ parse_cmd_line() { [[ $? -eq 0 ]] && shift case "$WARNINGS" in batch|off|false) ;; - *) pr_magentaln "\nwarnings can be either \"batch\", \"off\" or \"false\"" + *) pr_magentaln_term "\nwarnings can be either \"batch\", \"off\" or \"false\"" help 1 esac ;; @@ -12532,7 +12542,7 @@ parse_cmd_line() { [[ $? -eq 0 ]] && shift case $DEBUG in [0-6]) ;; - *) pr_magentaln_term "\nunrecognized debug value \"$1\", must be between 0..6" 1>&2 + *) pr_magentaln_term_term "\nunrecognized debug value \"$1\", must be between 0..6" 1>&2 help 1 esac ;; @@ -12542,7 +12552,7 @@ parse_cmd_line() { case $COLOR in [0-2]) ;; *) COLOR=2 - pr_magentaln "\nunrecognized color: \"$1\", must be between 0..2" 1>&2 + pr_magentaln_term "\nunrecognized color: \"$1\", must be between 0..2" 1>&2 help 1 esac ;; @@ -12595,7 +12605,7 @@ parse_cmd_line() { HTMLFILE=$(parse_opt_equal_sign "$1" "$2") [[ $? -eq 0 ]] && shift if [[ -d "$HTMLFILE" ]]; then - pr_warningln_term "$HTMLFILE exists and is a directory" + pr_warningln_term_term "$HTMLFILE exists and is a directory" exit -6 fi do_html=true @@ -12620,7 +12630,7 @@ parse_cmd_line() { [[ $? -eq 0 ]] && shift case "$cipher_mapping" in no-rfc) unset ADD_RFC_STR;; - *) pr_magentaln "\nmapping can only be \"no-rfc\"" + *) pr_magentaln_term "\nmapping can only be \"no-rfc\"" help 1 ;; esac ;; @@ -12640,7 +12650,7 @@ parse_cmd_line() { (--) shift break ;; - (-*) pr_magentaln "0: unrecognized option \"$1\"" 1>&2; + (-*) pr_magentaln_term "0: unrecognized option \"$1\"" 1>&2; help 1 ;; (*) break @@ -12672,7 +12682,7 @@ nodeip_to_proper_ip6() { if is_ipv6addr $NODEIP; then ${UNBRACKTD_IPV6} || NODEIP="[$NODEIP]" len_nodeip=${#NODEIP} - CORRECT_SPACES="$(draw_line " " "$((len_nodeip - 17))" )" + CORRECT_SPACES="$(printf -- " "'%.s' $(eval "echo {1.."$((len_nodeip - 17))"}"))" # IPv6 addresses are longer, this varaible takes care that "further IP" and "Service" is properly aligned fi }