From a264898f779a655407a02c64049391180f778fb0 Mon Sep 17 00:00:00 2001 From: David Cooper Date: Mon, 3 Jul 2017 16:24:02 -0400 Subject: [PATCH] Initial fix for #772 This commit provides a partial fix for #772. --- testssl.sh | 85 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 51 insertions(+), 34 deletions(-) diff --git a/testssl.sh b/testssl.sh index 3efa97d..819412e 100755 --- a/testssl.sh +++ b/testssl.sh @@ -270,6 +270,7 @@ HAS_DH_BITS=${HAS_DH_BITS:-false} # initialize openssl variables HAS_SSL2=false HAS_SSL3=false HAS_NO_SSL2=false +HAS_NOSERVERNAME=false HAS_ALPN=false HAS_SPDY=false HAS_FALLBACK_SCSV=false @@ -1293,6 +1294,29 @@ string_to_asciihex() { } +# Adjust options to $OPENSSL s_client based on OpenSSL version and protocol version +s_client_options() { + local options="$1" + + # Don't include the -servername option for an SSLv2 or SSLv3 ClientHello. + [[ -n "$SNI" ]] && [[ " $options " =~ \ -ssl[2|3]\ ]] && options="$(sed "s/$SNI//" <<< "$options")" + + # The server_name extension should not be included in the ClientHello unless + # the -servername option is provided. However, OpenSSL 1.1.1 will include the + # server_name extension unless the -noservername option is provided. So, if + # the command line doesn't include -servername and the -noservername option is + # supported, then add -noservername to the options. + "$HAS_NOSERVERNAME" && [[ ! " $options " =~ " -servername " ]] && options+=" -noservername" + + # Newer versions of OpenSSL have dropped support for the -no_ssl2 option, so + # remove any -no_ssl2 option if the option isn't supported. (Since versions of + # OpenSSL that don't support -no_ssl2 also don't support SSLv2, the option + # isn't needed for these versions of OpenSSL.) + ! "$HAS_NO_SSL2" && options="$(sed 's/-no_ssl2//' <<< "$options")" + + tm_out "$options" +} + ###### check code starts here ###### # determines whether the port has an HTTP service running or not (plain TLS, no STARTTLS) @@ -1300,12 +1324,10 @@ string_to_asciihex() { service_detection() { local -i ret=0 local -i was_killed - local addcmd="" if ! "$CLIENT_AUTH"; then # SNI is not standardardized for !HTTPS but fortunately for other protocols s_client doesn't seem to care - [[ ! "$1" =~ ssl ]] && addcmd="$SNI" - printf "$GET_REQ11" | $OPENSSL s_client $1 -quiet $BUGS -connect $NODEIP:$PORT $PROXY $addcmd >$TMPFILE 2>$ERRFILE & + printf "$GET_REQ11" | $OPENSSL s_client $(s_client_options "$1 -quiet $BUGS -connect $NODEIP:$PORT $PROXY $SNI") >$TMPFILE 2>$ERRFILE & wait_kill $! $HEADER_MAXSLEEP was_killed=$? head $TMPFILE | grep -aq '^HTTP\/' && SERVICE=HTTP @@ -1358,7 +1380,7 @@ service_detection() { #problems not handled: chunked run_http_header() { - local header addcmd="" + local header local -i ret local referer useragent local url redirect @@ -1368,13 +1390,12 @@ run_http_header() { outln [[ -z "$1" ]] && url="/" || url="$1" - [[ ! "$OPTIMAL_PROTO" =~ ssl ]] && addcmd="$SNI" - printf "$GET_REQ11" | $OPENSSL s_client $OPTIMAL_PROTO $BUGS -quiet -ign_eof -connect $NODEIP:$PORT $PROXY $addcmd >$HEADERFILE 2>$ERRFILE & + printf "$GET_REQ11" | $OPENSSL s_client $(s_client_options "$OPTIMAL_PROTO $BUGS -quiet -ign_eof -connect $NODEIP:$PORT $PROXY $SNI") >$HEADERFILE 2>$ERRFILE & wait_kill $! $HEADER_MAXSLEEP if [[ $? -eq 0 ]]; then # we do the get command again as it terminated within $HEADER_MAXSLEEP. Thus it didn't hang, we do it # again in the foreground to get an accurate header time! - printf "$GET_REQ11" | $OPENSSL s_client $OPTIMAL_PROTO $BUGS -quiet -ign_eof -connect $NODEIP:$PORT $PROXY $addcmd >$HEADERFILE 2>$ERRFILE + printf "$GET_REQ11" | $OPENSSL s_client $(s_client_options "$OPTIMAL_PROTO $BUGS -quiet -ign_eof -connect $NODEIP:$PORT $PROXY $SNI") >$HEADERFILE 2>$ERRFILE NOW_TIME=$(date "+%s") HTTP_TIME=$(awk -F': ' '/^date:/ { print $2 } /^Date:/ { print $2 }' $HEADERFILE) HAD_SLEPT=0 @@ -2281,15 +2302,14 @@ std_cipherlists() { local -i i len sclient_success local sslv2_cipherlist detected_ssl2_ciphers local singlespaces - local proto="" addcmd="" + local proto="" local debugname="$(sed -e s'/\!/not/g' -e 's/\:/_/g' <<< "$1")" [[ "$OPTIMAL_PROTO" == "-ssl2" ]] && proto="$OPTIMAL_PROTO" pr_bold "$2 " # to be indented equal to server preferences if [[ -n "$5" ]] || listciphers "$1" $proto; then if [[ -z "$5" ]] || ( "$FAST" && listciphers "$1" -tls1 ); then - "$HAS_NO_SSL2" && addcmd="-no_ssl2" - $OPENSSL s_client -cipher "$1" $BUGS $STARTTLS -connect $NODEIP:$PORT $PROXY $SNI $addcmd 2>$ERRFILE >$TMPFILE $ERRFILE >$TMPFILE $TMPFILE 2>$ERRFILE $TMPFILE 2>$ERRFILE $TMPFILE 2>$ERRFILE $TMPFILE 2>$ERRFILE $TMPFILE 2>$ERRFILE $TMPFILE 2>$ERRFILE /dev/null @@ -3701,9 +3718,9 @@ run_client_simulation() { [[ $sclient_success -eq 0 ]] && cp "$TEMPDIR/$NODEIP.parse_tls_serverhello.txt" $TMPFILE >$ERRFILE fi else - "$HAS_NO_SSL2" || protos[i]="$(sed 's/-no_ssl2//' <<< "${protos[i]}")" - debugme echo "$OPENSSL s_client -cipher ${ciphers[i]} ${protos[i]} $STARTTLS $BUGS $PROXY -connect $NODEIP:$PORT ${sni[i]} $TMPFILE 2>$ERRFILE + options="$(s_client_options "-cipher ${ciphers[i]} ${protos[i]} $STARTTLS $BUGS $PROXY -connect $NODEIP:$PORT ${sni[i]}")" + debugme echo "$OPENSSL s_client $options $TMPFILE 2>$ERRFILE sclient_connect_successful $? $TMPFILE sclient_success=$? fi @@ -5335,7 +5352,7 @@ determine_tls_extensions() { # arg1 is "-cipher " or empty # arg2 is a list of protocols to try (tls1_2, tls1_1, tls1, ssl3) or empty (if all should be tried) get_server_certificate() { - local protocols_to_try proto addcmd + local protocols_to_try proto local success local npn_params="" line local savedir @@ -5391,8 +5408,7 @@ get_server_certificate() { for proto in $protocols_to_try; do # we could know here which protcols are supported addcmd="" - [[ ! "$proto" =~ ssl ]] && addcmd="$SNI" - $OPENSSL s_client $STARTTLS $BUGS $1 -showcerts -connect $NODEIP:$PORT $PROXY $addcmd -$proto -tlsextdebug $npn_params -status $ERRFILE >$TMPFILE + $OPENSSL s_client $(s_client_options "$STARTTLS $BUGS $1 -showcerts -connect $NODEIP:$PORT $PROXY $SNI -$proto -tlsextdebug $npn_params -status") $ERRFILE >$TMPFILE if sclient_connect_successful $? $TMPFILE; then success=0 grep -a 'TLS server extension' $TMPFILE >>$TEMPDIR/tlsext.txt @@ -5401,7 +5417,7 @@ get_server_certificate() { done # this loop is needed for IIS6 and others which have a handshake size limitations if [[ $success -eq 7 ]]; then # "-status" above doesn't work for GOST only servers, so we do another test without it and see whether that works then: - $OPENSSL s_client $STARTTLS $BUGS $1 -showcerts -connect $NODEIP:$PORT $PROXY $addcmd -$proto -tlsextdebug >$ERRFILE >$TMPFILE + $OPENSSL s_client $(s_client_options "$STARTTLS $BUGS $1 -showcerts -connect $NODEIP:$PORT $PROXY $SNI -$proto -tlsextdebug") >$ERRFILE >$TMPFILE if ! sclient_connect_successful $? $TMPFILE; then if [ -z "$1" ]; then prln_warning "Strange, no SSL/TLS protocol seems to be supported (error around line $((LINENO - 6)))" @@ -5951,7 +5967,7 @@ certificate_info() { if [[ -n "$sni_used" ]]; then # no cipher suites specified here. We just want the default vhost subject - $OPENSSL s_client $STARTTLS $BUGS -connect $NODEIP:$PORT $PROXY $OPTIMAL_PROTO 2>>$ERRFILE $HOSTCERT.nosni + $OPENSSL s_client $(s_client_options "$STARTTLS $BUGS -connect $NODEIP:$PORT $PROXY $OPTIMAL_PROTO") 2>>$ERRFILE $HOSTCERT.nosni if grep -q "\-\-\-\-\-BEGIN" "$HOSTCERT.nosni"; then cn_nosni="$(get_cn_from_cert "$HOSTCERT.nosni")" [[ -z "$cn_nosni" ]] && cn_nosni="no CN field in subject" @@ -10209,7 +10225,7 @@ run_freak() { local exportrsa_tls_cipher_list_hex="00,62, 00,61, 00,64, 00,60, 00,14, 00,0E, 00,08, 00,06, 00,03" local exportrsa_ssl2_cipher_list_hex="04,00,80, 02,00,80" local detected_ssl2_ciphers - local addcmd="" addtl_warning="" hexc + local addtl_warning="" hexc local cve="CVE-2015-0204" local cwe="CWE-310" local hint="" @@ -10254,8 +10270,7 @@ run_freak() { fi fi else - "$HAS_NO_SSL2" && addcmd="-no_ssl2" || addcmd="" - $OPENSSL s_client $STARTTLS $BUGS -cipher $exportrsa_cipher_list -connect $NODEIP:$PORT $PROXY $SNI $addcmd >$TMPFILE 2>$ERRFILE $TMPFILE 2>$ERRFILE $TMPFILE 2>$ERRFILE $TMPFILE 2>$ERRFILE &1 | grep -aq "unknown option" || \ HAS_NO_SSL2=true + $OPENSSL s_client -noservername -connect x 2>&1 | grep -aq "unknown option" || \ + HAS_NOSERVERNAME=true + $OPENSSL s_client -help 2>$s_client_has $OPENSSL s_client -starttls foo 2>$s_client_starttls_has