From 8842aeb2b93bef45dd432b198e75d087ad75bd18 Mon Sep 17 00:00:00 2001 From: AndreiD Date: Mon, 8 Feb 2016 12:51:54 +0100 Subject: [PATCH 01/10] Fix #289 - the grep that decides whether a domain is a local address doesn't consider the case when the full domain name is in the hosts file, but followed by .some.other.stuff. This PR addresses this case. --- testssl.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testssl.sh b/testssl.sh index f61b88d..5b55011 100755 --- a/testssl.sh +++ b/testssl.sh @@ -5715,7 +5715,7 @@ get_local_a() { local etchosts="/etc/hosts /c/Windows/System32/drivers/etc/hosts" # for security testing sometimes we have local entries. Getent is BS under Linux for localhost: No network, no resolution - ip4=$(grep -wh "$1" $etchosts 2>/dev/null | egrep -v ':|^#' | egrep "[[:space:]]$1" | awk '{ print $1 }') + ip4=$(grep -wh "$1[^\.]" $etchosts 2>/dev/null | egrep -v ':|^#' | egrep "[[:space:]]$1" | awk '{ print $1 }') if is_ipv4addr "$ip4"; then echo "$ip4" else From 9d1803d6eb6f7e92b4d74e53b57fc07a1e6b4f0c Mon Sep 17 00:00:00 2001 From: David Cooper Date: Fri, 29 Apr 2016 17:04:01 -0400 Subject: [PATCH 02/10] More SSLv2 (and SSLv3) related fixes In doing some work on cipher_pref_check() I noticed that it was failing on SSLv2 since the call to "$OPENSSL s_client" includes SNI. I've also noticed in my testing that "$OPENSSL s_client" will not connect to an SSLv2-only server unless the "-ssl2" flag is included. So, I carefully checked each call to "$OPENSSL s_client" in the program (other than in run_allciphers and run_cipher_per_proto, since those functions are already addresses in PR #341) to see whether they would inappropriate fail with an SSLv2-only (or SSLv3-only) server. As a general rule, if the call doesn't currently include the protocol, then I added "-ssl2" if $OPTIMAL_PROTO is "-ssl2", indicating that the server only supports SSLv2, and I removed any $SNI if a protocol is specified if a protocol is specified and it is either SSLv2 or SSLv3. I tested it on an SSLv2-only server, and the results are much better. I also tested it on a collection of other servers, none of which support SSLv2, and the results are the same as with the current code. The only thing I haven't been able to test is how the revised code works when the "--starttls" option is used. I don't believe the changes I made would cause anything to break in that case, but I also don't think code will work any better in that case, if the server only supports SSLv2. Of course, since no server should support SSLv2 (let alone only SSLv2), it shouldn't really be an issue. One thing that I did not change, but that I do not understand; why does determine_optimal_proto() try the protocols in the order "-tls1_2 -tls1 -ssl3 -tls1_1 -ssl2" rather than "-tls1_2 -tls1_1 -tls1 -ssl3 -ssl2"? Doesn't the current ordering imply that TLS v1.0 and SSLv3 are better than TLS v1.1? --- testssl.sh | 168 +++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 125 insertions(+), 43 deletions(-) diff --git a/testssl.sh b/testssl.sh index 8d133d4..786767a 100755 --- a/testssl.sh +++ b/testssl.sh @@ -617,10 +617,12 @@ wait_kill(){ runs_HTTP() { local -i ret=0 local -i was_killed + local addcmd="" if ! $CLIENT_AUTH; then # SNI is nonsense for !HTTPS but fortunately for other protocols s_client doesn't seem to care - printf "$GET_REQ11" | $OPENSSL s_client $1 -quiet $BUGS -connect $NODEIP:$PORT $PROXY $SNI >$TMPFILE 2>$ERRFILE & + [[ ! "$1" =~ ssl ]] && addcmd="$SNI" + printf "$GET_REQ11" | $OPENSSL s_client $1 -quiet $BUGS -connect $NODEIP:$PORT $PROXY $addcmd >$TMPFILE 2>$ERRFILE & wait_kill $! $HEADER_MAXSLEEP was_killed=$? head $TMPFILE | grep -aq ^HTTP && SERVICE=HTTP @@ -670,7 +672,7 @@ runs_HTTP() { #problems not handled: chunked run_http_header() { - local header + local header addcmd="" local -i ret local referer useragent local url redirect @@ -680,12 +682,13 @@ run_http_header() { outln [[ -z "$1" ]] && url="/" || url="$1" - printf "$GET_REQ11" | $OPENSSL s_client $OPTIMAL_PROTO $BUGS -quiet -ign_eof -connect $NODEIP:$PORT $PROXY $SNI >$HEADERFILE 2>$ERRFILE & + [[ ! "$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 & 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 ito get an ccurate header time! - printf "$GET_REQ11" | $OPENSSL s_client $OPTIMAL_PROTO $BUGS -quiet -ign_eof -connect $NODEIP:$PORT $PROXY $SNI >$HEADERFILE 2>$ERRFILE + # again in the foreground ito 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 NOW_TIME=$(date "+%s") HTTP_TIME=$(awk -F': ' '/^date:/ { print $2 } /^Date:/ { print $2 }' $HEADERFILE) HAD_SLEPT=0 @@ -1335,11 +1338,12 @@ prettyprint_local() { # list ciphers (and makes sure you have them locally configured) # arg[1]: cipher list (or anything else) +# arg[2]: protocol (e.g., -ssl2) listciphers() { local -i ret local debugname="$(sed -e s'/\!/not/g' -e 's/\:/_/g' <<< "$1")" - $OPENSSL ciphers "$1" &>$TMPFILE + $OPENSSL ciphers $2 "$1" &>$TMPFILE ret=$? debugme cat $TMPFILE @@ -1353,12 +1357,14 @@ listciphers() { # argv[3]: ok to offer? 0: yes, 1: no std_cipherlists() { local -i sclient_success - local singlespaces + local singlespaces proto="" addcmd="" local debugname="$(sed -e s'/\!/not/g' -e 's/\:/_/g' <<< "$1")" + [[ "$OPTIMAL_PROTO" == "-ssl2" ]] && addcmd="$OPTIMAL_PROTO" && proto="$OPTIMAL_PROTO" + [[ ! "$OPTIMAL_PROTO" =~ ssl ]] && addcmd="$SNI" pr_bold "$2 " # indent in order to be in the same row as server preferences - if listciphers "$1"; then # is that locally available?? - $OPENSSL s_client -cipher "$1" $BUGS $STARTTLS -connect $NODEIP:$PORT $PROXY $SNI 2>$ERRFILE >$TMPFILE $ERRFILE >$TMPFILE $ERRFILE >$TMPFILE $ERRFILE >$TMPFILE $ERRFILE >$TMPFILE $ERRFILE >$TMPFILE + [[ "$OPTIMAL_PROTO" == "-ssl2" ]] && addcmd="$OPTIMAL_PROTO" + [[ ! "$OPTIMAL_PROTO" =~ ssl ]] && addcmd="$SNI" && sni="$SNI" + $OPENSSL s_client $STARTTLS -cipher $list_fwd $BUGS -connect $NODEIP:$PORT $PROXY $addcmd $ERRFILE >$TMPFILE if ! sclient_connect_successful $? $TMPFILE && [[ -z "$STARTTLS_PROTOCOL" ]]; then pr_warning "no matching cipher in this list found (pls report this): " outln "$list_fwd . " @@ -2501,7 +2517,8 @@ run_server_preference() { # workaround is to connect with a protocol debugme out "(workaround #188) " determine_optimal_proto $STARTTLS_PROTOCOL - $OPENSSL s_client $STARTTLS $STARTTLS_OPTIMAL_PROTO -cipher $list_fwd $BUGS -connect $NODEIP:$PORT $PROXY $SNI $ERRFILE >$TMPFILE + [[ ! "$STARTTLS_OPTIMAL_PROTO" =~ ssl ]] && addcmd2="$SNI" + $OPENSSL s_client $STARTTLS $STARTTLS_OPTIMAL_PROTO -cipher $list_fwd $BUGS -connect $NODEIP:$PORT $PROXY $addcmd2 $ERRFILE >$TMPFILE if ! sclient_connect_successful $? $TMPFILE; then pr_warning "no matching cipher in this list found (pls report this): " outln "$list_fwd . " @@ -2513,7 +2530,15 @@ run_server_preference() { if $has_cipher_order; then cipher1=$(grep -wa Cipher $TMPFILE | egrep -avw "New|is" | sed -e 's/^ \+Cipher \+://' -e 's/ //g') - $OPENSSL s_client $STARTTLS $STARTTLS_OPTIMAL_PROTO -cipher $list_reverse $BUGS -connect $NODEIP:$PORT $PROXY $SNI >$ERRFILE >$TMPFILE + addcmd2="" + if [[ -n "$STARTTLS_OPTIMAL_PROTO" ]]; then + addcmd2="$STARTTLS_OPTIMAL_PROTO" + [[ ! "$STARTTLS_OPTIMAL_PROTO" =~ ssl ]] && addcmd2="$addcmd2 $SNI" + else + [[ "$OPTIMAL_PROTO" == "-ssl2" ]] && addcmd2="$OPTIMAL_PROTO" + [[ ! "$OPTIMAL_PROTO" =~ ssl ]] && addcmd2="$addcmd2 $SNI" + fi + $OPENSSL s_client $STARTTLS -cipher $list_reverse $BUGS -connect $NODEIP:$PORT $PROXY $addcmd2 >$ERRFILE >$TMPFILE # that worked above so no error handling here cipher2=$(grep -wa Cipher $TMPFILE | egrep -avw "New|is" | sed -e 's/^ \+Cipher \+://' -e 's/ //g') @@ -2530,10 +2555,10 @@ run_server_preference() { outln pr_bold " Negotiated protocol " - $OPENSSL s_client $STARTTLS $BUGS -connect $NODEIP:$PORT $PROXY $SNI >$ERRFILE >$TMPFILE + $OPENSSL s_client $STARTTLS $BUGS -connect $NODEIP:$PORT $PROXY $addcmd >$ERRFILE >$TMPFILE if ! sclient_connect_successful $? $TMPFILE; then # 2 second try with $OPTIMAL_PROTO especially for intolerant IIS6 servers: - $OPENSSL s_client $STARTTLS $OPTIMAL_PROTO $BUGS -connect $NODEIP:$PORT $PROXY $SNI >$ERRFILE >$TMPFILE + $OPENSSL s_client $STARTTLS $OPTIMAL_PROTO $BUGS -connect $NODEIP:$PORT $PROXY $sni >$ERRFILE >$TMPFILE sclient_connect_successful $? $TMPFILE || pr_warning "Handshake error!" fi default_proto=$(grep -aw "Protocol" $TMPFILE | sed -e 's/^.*Protocol.*://' -e 's/ //g') @@ -2627,7 +2652,9 @@ run_server_preference() { out " (SSLv3: "; local_problem "$OPENSSL doesn't support \"s_client -ssl3\"" ; outln ")"; continue fi - $OPENSSL s_client $STARTTLS -"$p" $BUGS -connect $NODEIP:$PORT $PROXY $SNI >$ERRFILE >$TMPFILE + addcmd="" + [[ ! "$p" =~ ssl ]] && addcmd="$SNI" + $OPENSSL s_client $STARTTLS -"$p" $BUGS -connect $NODEIP:$PORT $PROXY $addcmd >$ERRFILE >$TMPFILE if sclient_connect_successful $? $TMPFILE; then proto[i]=$(grep -aw "Protocol" $TMPFILE | sed -e 's/^.*Protocol.*://' -e 's/ //g') cipher[i]=$(grep -aw "Cipher" $TMPFILE | egrep -avw "New|is" | sed -e 's/^.*Cipher.*://' -e 's/ //g') @@ -2687,7 +2714,7 @@ run_server_preference() { } cipher_pref_check() { - local p proto protos npn_protos + local p proto protos npn_protos addcmd="" local tested_cipher cipher order pr_bold " Cipher order" @@ -2702,7 +2729,9 @@ cipher_pref_check() { out "\n SSLv3: "; local_problem "$OPENSSL doesn't support \"s_client -ssl3\""; continue fi - $OPENSSL s_client $STARTTLS -"$p" $BUGS -connect $NODEIP:$PORT $PROXY $SNI $ERRFILE >$TMPFILE + addcmd="" + [[ ! "$p" =~ ssl ]] && addcmd="$SNI" + $OPENSSL s_client $STARTTLS -"$p" $BUGS -connect $NODEIP:$PORT $PROXY $addcmd $ERRFILE >$TMPFILE if sclient_connect_successful $? $TMPFILE; then tested_cipher="" proto=$(grep -aw "Protocol" $TMPFILE | sed -e 's/^.*Protocol.*://' -e 's/ //g') @@ -2713,7 +2742,7 @@ cipher_pref_check() { tested_cipher="-"$cipher order="$cipher" while true; do - $OPENSSL s_client $STARTTLS -"$p" $BUGS -cipher "ALL:$tested_cipher" -connect $NODEIP:$PORT $PROXY $SNI >$ERRFILE >$TMPFILE + $OPENSSL s_client $STARTTLS -"$p" $BUGS -cipher "ALL:$tested_cipher" -connect $NODEIP:$PORT $PROXY $addcmd >$ERRFILE >$TMPFILE sclient_connect_successful $? $TMPFILE || break cipher=$(grep -aw "Cipher" $TMPFILE | egrep -avw "New|is" | sed -e 's/^.*Cipher.*://' -e 's/ //g') out "$cipher " @@ -2918,7 +2947,7 @@ tls_time() { debugme out "$TLS_TIME" outln else - pr_warning "SSLv3 through TLS 1.2 didn't return a timestamp" + pr_warningln "SSLv3 through TLS 1.2 didn't return a timestamp" fileout "tls_time" "INFO" "No TLS timestamp returned by SSLv3 through TLSv1.2" fi return 0 @@ -2936,7 +2965,7 @@ sclient_connect_successful() { # arg1 is "-cipher " or empty determine_tls_extensions() { - local proto + local proto addcmd local success local alpn="" local savedir @@ -2946,14 +2975,48 @@ determine_tls_extensions() { # throwing 1st every cipher/protocol at the server to know what works success=7 + + if [[ "$OPTIMAL_PROTO" == "-ssl2" ]]; then + $OPENSSL s_client $STARTTLS $BUGS $1 -showcerts -connect $NODEIP:$PORT $PROXY -ssl2 $ERRFILE >$TMPFILE + sclient_connect_successful $? $TMPFILE && success=0 + if [[ $success -eq 0 ]]; then + # Place the server's certificate in $HOSTCERT and any intermediate + # certificates that were provided in $TEMPDIR/intermediatecerts.pem + savedir=$(pwd); cd $TEMPDIR + # http://backreference.org/2010/05/09/ocsp-verification-with-openssl/ + awk -v n=-1 '/Server certificate/ {start=1} + /-----BEGIN CERTIFICATE-----/{ if (start) {inc=1; n++} } + inc { print > ("level" n ".crt") } + /---END CERTIFICATE-----/{ inc=0 }' $TMPFILE + nrsaved=$(count_words "$(echo level?.crt 2>/dev/null)") + if [[ $nrsaved -eq 0 ]]; then + success=1 + else + success=0 + mv level0.crt $HOSTCERT + if [[ $nrsaved -eq 1 ]]; then + echo "" > $TEMPDIR/intermediatecerts.pem + else + cat level?.crt > $TEMPDIR/intermediatecerts.pem + rm level?.crt + fi + fi + cd "$savedir" + fi + tmpfile_handle $FUNCNAME.txt + return $success + fi + for proto in tls1_2 tls1_1 tls1 ssl3; do # alpn: echo | openssl s_client -connect google.com:443 -tlsextdebug -alpn h2-14 -servername google.com <-- suport needs to be checked b4 -- see also: ssl/t1_trce.c - $OPENSSL s_client $STARTTLS $BUGS $1 -showcerts -connect $NODEIP:$PORT $PROXY $SNI -$proto -tlsextdebug -nextprotoneg $alpn -status $ERRFILE >$TMPFILE + addcmd="" + [[ ! "$proto" =~ ssl ]] && addcmd="$SNI" + $OPENSSL s_client $STARTTLS $BUGS $1 -showcerts -connect $NODEIP:$PORT $PROXY $addcmd -$proto -tlsextdebug -nextprotoneg $alpn -status $ERRFILE >$TMPFILE sclient_connect_successful $? $TMPFILE && success=0 && break 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 $SNI -$proto -tlsextdebug >$ERRFILE >$TMPFILE + $OPENSSL s_client $STARTTLS $BUGS $1 -showcerts -connect $NODEIP:$PORT $PROXY $addcmd -$proto -tlsextdebug >$ERRFILE >$TMPFILE if ! sclient_connect_successful $? $TMPFILE; then if [ -z "$1" ]; then pr_warningln "Strange, no SSL/TLS protocol seems to be supported (error around line $((LINENO - 6)))" @@ -4624,13 +4687,14 @@ run_renego() { # no SNI here. Not needed as there won't be two different SSL stacks for one IP local legacycmd="" local insecure_renogo_str="Secure Renegotiation IS NOT" - local sec_renego sec_client_renego + local sec_renego sec_client_renego addcmd="" [[ $VULN_COUNT -le $VULN_THRESHLD ]] && outln && pr_headlineln " Testing for Renegotiation vulnerabilities " && outln pr_bold " Secure Renegotiation "; out "(CVE-2009-3555) " # and RFC5746, OSVDB 59968-59974 # community.qualys.com/blogs/securitylabs/2009/11/05/ssl-and-tls-authentication-gap-vulnerability-discovered - $OPENSSL s_client $OPTIMAL_PROTO $STARTTLS $BUGS -connect $NODEIP:$PORT $SNI $PROXY 2>&1 $TMPFILE 2>$ERRFILE + [[ ! "$OPTIMAL_PROTO" =~ ssl ]] && addcmd="$SNI" + $OPENSSL s_client $OPTIMAL_PROTO $STARTTLS $BUGS -connect $NODEIP:$PORT $addcmd $PROXY 2>&1 $TMPFILE 2>$ERRFILE if sclient_connect_successful $? $TMPFILE; then grep -iaq "$insecure_renogo_str" $TMPFILE sec_renego=$? # 0= Secure Renegotiation IS NOT supported @@ -4683,7 +4747,7 @@ run_renego() { else # We need up to two tries here, as some LiteSpeed servers don't answer on "R" and block. Thus first try in the background # msg enables us to look deeper into it while debugging - echo R | $OPENSSL s_client $OPTIMAL_PROTO $BUGS $legacycmd $STARTTLS -msg -connect $NODEIP:$PORT $SNI $PROXY >$TMPFILE 2>>$ERRFILE & + echo R | $OPENSSL s_client $OPTIMAL_PROTO $BUGS $legacycmd $STARTTLS -msg -connect $NODEIP:$PORT $addcmd $PROXY >$TMPFILE 2>>$ERRFILE & wait_kill $! $HEADER_MAXSLEEP if [[ $? -eq 3 ]]; then pr_done_good "likely not vulnerable (OK)"; outln " (timed out)" # it hung @@ -4691,7 +4755,7 @@ run_renego() { sec_client_renego=1 else # second try in the foreground as we are sure now it won't hang - echo R | $OPENSSL s_client $legacycmd $STARTTLS $BUGS -msg -connect $NODEIP:$PORT $SNI $PROXY >$TMPFILE 2>>$ERRFILE + echo R | $OPENSSL s_client $legacycmd $STARTTLS $BUGS -msg -connect $NODEIP:$PORT $addcmd $PROXY >$TMPFILE 2>>$ERRFILE sec_client_renego=$? # 0=client is renegotiating & doesn't return an error --> vuln! case "$sec_client_renego" in 0) @@ -4803,7 +4867,7 @@ run_crime() { # to the version of TLS/SSL, more: http://www.breachattack.com/ . Foreign referrers are the important thing here! # Mitigation: see https://community.qualys.com/message/20360 run_breach() { - local header + local header addcmd="" local -i ret=0 local -i was_killed=0 local referer useragent @@ -4827,7 +4891,8 @@ run_breach() { useragent="$UA_STD" $SNEAKY && useragent="$UA_SNEAKY" - printf "GET $url HTTP/1.1\r\nHost: $NODE\r\nUser-Agent: $useragent\r\nReferer: $referer\r\nConnection: Close\r\nAccept-encoding: gzip,deflate,compress\r\nAccept: text/*\r\n\r\n" | $OPENSSL s_client $OPTIMAL_PROTO $BUGS -quiet -ign_eof -connect $NODEIP:$PORT $PROXY $SNI 1>$TMPFILE 2>$ERRFILE & + [[ ! "$OPTIMAL_PROTO" =~ ssl ]] && addcmd="$SNI" + printf "GET $url HTTP/1.1\r\nHost: $NODE\r\nUser-Agent: $useragent\r\nReferer: $referer\r\nConnection: Close\r\nAccept-encoding: gzip,deflate,compress\r\nAccept: text/*\r\n\r\n" | $OPENSSL s_client $OPTIMAL_PROTO $BUGS -quiet -ign_eof -connect $NODEIP:$PORT $PROXY $addcmd 1>$TMPFILE 2>$ERRFILE & wait_kill $! $HEADER_MAXSLEEP was_killed=$? # !=0 was killed result=$(awk '/^Content-Encoding/ { print $2 }' $TMPFILE) @@ -4874,7 +4939,7 @@ run_ssl_poodle() { cbc_ciphers=$($OPENSSL ciphers -v 'ALL:eNULL' 2>$ERRFILE | awk '/CBC/ { print $1 }' | tr '\n' ':') debugme echo $cbc_ciphers - $OPENSSL s_client -ssl3 $STARTTLS $BUGS -cipher $cbc_ciphers -connect $NODEIP:$PORT $PROXY $SNI >$TMPFILE 2>$ERRFILE $TMPFILE 2>$ERRFILE $TMPFILE 2>$ERRFILE $TMPFILE 2>$ERRFILE $TMPFILE 2>$ERRFILE $TMPFILE 2>>$ERRFILE $TMPFILE 2>>$ERRFILE $TMPFILE 2>>$ERRFILE $TMPFILE 2>>$ERRFILE >$ERRFILE) # -V doesn't work with openssl < 1.0 # ^^^^^ process substitution as shopt will either segfault or doesn't work with old bash versions - $OPENSSL s_client -cipher "$cbc_cipher" -"$proto" $STARTTLS $BUGS -connect $NODEIP:$PORT $PROXY $SNI >$TMPFILE 2>>$ERRFILE $TMPFILE 2>>$ERRFILE $TMPFILE 2>$ERRFILE $TMPFILE 2>$ERRFILE $TMPFILE 2>$ERRFILE + if [[ "$sslvers" == "SSLv2" ]]; then + $OPENSSL s_client -cipher $rc4_cipher $STARTTLS $BUGS -connect $NODEIP:$PORT $PROXY -ssl2 $TMPFILE 2>$ERRFILE + else + $OPENSSL s_client -cipher $rc4_cipher $STARTTLS $BUGS -connect $NODEIP:$PORT $PROXY $SNI $TMPFILE 2>$ERRFILE + fi sclient_connect_successful $? $TMPFILE sclient_success=$? # here we may have a fp with openssl < 1.0, TBC if [[ $sclient_success -ne 0 ]] && ! "$SHOW_EACH_C"; then @@ -6201,7 +6281,9 @@ determine_optimal_proto() { debugme echo "STARTTLS_OPTIMAL_PROTO: $STARTTLS_OPTIMAL_PROTO" else for OPTIMAL_PROTO in '' -tls1_2 -tls1 -ssl3 -tls1_1 -ssl2 ''; do - $OPENSSL s_client $OPTIMAL_PROTO $BUGS -connect "$NODEIP:$PORT" -msg $PROXY $SNI $TMPFILE 2>>$ERRFILE + addcmd="" + [[ ! "$OPTIMAL_PROTO" =~ ssl ]] && addcmd="$SNI" + $OPENSSL s_client $OPTIMAL_PROTO $BUGS -connect "$NODEIP:$PORT" -msg $PROXY $addcmd $TMPFILE 2>>$ERRFILE if sclient_auth $? $TMPFILE; then all_failed=1 break From d2f1e15243b8918aab2f82f666cc888b0b977178 Mon Sep 17 00:00:00 2001 From: David Cooper Date: Mon, 25 Jul 2016 16:30:30 -0400 Subject: [PATCH 03/10] Remove fixes for run_rc4() --- testssl.sh | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/testssl.sh b/testssl.sh index b189916..e272194 100755 --- a/testssl.sh +++ b/testssl.sh @@ -6951,7 +6951,7 @@ run_rc4() { local hexcode dash rc4_cipher sslvers kx auth enc mac export local rc4_ciphers_list="ECDHE-RSA-RC4-SHA:ECDHE-ECDSA-RC4-SHA:DHE-DSS-RC4-SHA:AECDH-RC4-SHA:ADH-RC4-MD5:ECDH-RSA-RC4-SHA:ECDH-ECDSA-RC4-SHA:RC4-SHA:RC4-MD5:RC4-MD5:RSA-PSK-RC4-SHA:PSK-RC4-SHA:KRB5-RC4-SHA:KRB5-RC4-MD5:RC4-64-MD5:EXP1024-DHE-DSS-RC4-SHA:EXP1024-RC4-SHA:EXP-ADH-RC4-MD5:EXP-RC4-MD5:EXP-RC4-MD5:EXP-KRB5-RC4-SHA:EXP-KRB5-RC4-MD5" local rc4_detected="" - local available="" addcmd="" + local available="" if [[ $VULN_COUNT -le $VULN_THRESHLD ]]; then outln @@ -6962,9 +6962,7 @@ run_rc4() { fi pr_bold " RC4"; out " (CVE-2013-2566, CVE-2015-2808) " - [[ "$OPTIMAL_PROTO" == "-ssl2" ]] && addcmd="$OPTIMAL_PROTO" - [[ ! "$OPTIMAL_PROTO" =~ ssl ]] && addcmd="$SNI" - $OPENSSL s_client -cipher $rc4_ciphers_list $STARTTLS $BUGS -connect $NODEIP:$PORT $PROXY $addcmd >$TMPFILE 2>$ERRFILE $TMPFILE 2>$ERRFILE $TMPFILE 2>$ERRFILE - else - $OPENSSL s_client -cipher $rc4_cipher $STARTTLS $BUGS -connect $NODEIP:$PORT $PROXY $SNI $TMPFILE 2>$ERRFILE - fi + $OPENSSL s_client -cipher $rc4_cipher $STARTTLS $BUGS -connect $NODEIP:$PORT $PROXY $SNI $TMPFILE 2>$ERRFILE sclient_connect_successful $? $TMPFILE sclient_success=$? # here we may have a fp with openssl < 1.0, TBC if [[ $sclient_success -ne 0 ]] && ! "$SHOW_EACH_C"; then From db0a6db620a24a4e8ff9d49152521db105b920a7 Mon Sep 17 00:00:00 2001 From: David Cooper Date: Mon, 25 Jul 2016 16:54:19 -0400 Subject: [PATCH 04/10] Remove fixes for test_just_one() --- testssl.sh | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/testssl.sh b/testssl.sh index e272194..9e7588e 100755 --- a/testssl.sh +++ b/testssl.sh @@ -1601,11 +1601,7 @@ test_just_one(){ neat_list $HEXC $ciph $kx $enc | grep -qwai "$arg" fi if [[ $? -eq 0 ]]; then # string matches, so we can ssl to it: - if [[ "$sslvers" == "SSLv2" ]]; then - $OPENSSL s_client -ssl2 -cipher $ciph $STARTTLS $BUGS -connect $NODEIP:$PORT $PROXY 2>$ERRFILE >$TMPFILE $ERRFILE >$TMPFILE $ERRFILE >$TMPFILE Date: Tue, 26 Jul 2016 10:11:22 -0400 Subject: [PATCH 05/10] Remove some server preference fixes --- testssl.sh | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/testssl.sh b/testssl.sh index 7d2881a..f0f5087 100755 --- a/testssl.sh +++ b/testssl.sh @@ -3477,9 +3477,7 @@ run_server_preference() { out " (SSLv3: "; local_problem "$OPENSSL doesn't support \"s_client -ssl3\"" ; outln ")"; continue fi - addcmd="" - [[ ! "$p" =~ ssl ]] && addcmd="$SNI" - $OPENSSL s_client $STARTTLS -"$p" $BUGS -connect $NODEIP:$PORT $PROXY $addcmd >$ERRFILE >$TMPFILE + $OPENSSL s_client $STARTTLS -"$p" $BUGS -connect $NODEIP:$PORT $PROXY $SNI >$ERRFILE >$TMPFILE if sclient_connect_successful $? $TMPFILE; then proto[i]=$(grep -aw "Protocol" $TMPFILE | sed -e 's/^.*Protocol.*://' -e 's/ //g') cipher[i]=$(grep -aw "Cipher" $TMPFILE | egrep -avw "New|is" | sed -e 's/^.*Cipher.*://' -e 's/ //g') @@ -3610,7 +3608,7 @@ check_tls12_pref() { cipher_pref_check() { - local p proto protos npn_protos addcmd="" + local p proto protos npn_protos local tested_cipher cipher order local overflow_probe_cipherlist="ALL:-ECDHE-RSA-AES256-GCM-SHA384:-AES128-SHA:-DES-CBC3-SHA" @@ -3626,10 +3624,8 @@ cipher_pref_check() { out "\n SSLv3: "; local_problem "$OPENSSL doesn't support \"s_client -ssl3\""; continue fi - addcmd="" - [[ ! "$p" =~ ssl ]] && addcmd="$SNI" # with the supplied binaries SNI works also for SSLv2 (+ SSLv3) - $OPENSSL s_client $STARTTLS -"$p" $BUGS -connect $NODEIP:$PORT $PROXY $addcmd $ERRFILE >$TMPFILE + $OPENSSL s_client $STARTTLS -"$p" $BUGS -connect $NODEIP:$PORT $PROXY $SNI $ERRFILE >$TMPFILE if sclient_connect_successful $? $TMPFILE; then tested_cipher="" proto=$(awk '/Protocol/ { print $3 }' $TMPFILE) @@ -3656,7 +3652,7 @@ cipher_pref_check() { else out " $cipher" # this is the first cipher for protocol while true; do - $OPENSSL s_client $STARTTLS -"$p" $BUGS -cipher "ALL:$tested_cipher" -connect $NODEIP:$PORT $PROXY $addcmd >$ERRFILE >$TMPFILE + $OPENSSL s_client $STARTTLS -"$p" $BUGS -cipher "ALL:$tested_cipher" -connect $NODEIP:$PORT $PROXY $SNI >$ERRFILE >$TMPFILE sclient_connect_successful $? $TMPFILE || break cipher=$(awk '/Cipher.*:/ { print $3 }' $TMPFILE) out " $cipher" From e9a2d27af39e417d4b063712a8768c382371005a Mon Sep 17 00:00:00 2001 From: David Cooper Date: Tue, 26 Jul 2016 11:04:43 -0400 Subject: [PATCH 06/10] Remove determine_optimal_proto() fix --- testssl.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/testssl.sh b/testssl.sh index f0f5087..0f60a2a 100755 --- a/testssl.sh +++ b/testssl.sh @@ -7896,9 +7896,7 @@ determine_optimal_proto() { debugme echo "STARTTLS_OPTIMAL_PROTO: $STARTTLS_OPTIMAL_PROTO" else for OPTIMAL_PROTO in '' -tls1_2 -tls1 -ssl3 -tls1_1 -ssl2 ''; do - addcmd="" - [[ ! "$OPTIMAL_PROTO" =~ ssl ]] && addcmd="$SNI" - $OPENSSL s_client $OPTIMAL_PROTO $BUGS -connect "$NODEIP:$PORT" -msg $PROXY $addcmd $TMPFILE 2>>$ERRFILE + $OPENSSL s_client $OPTIMAL_PROTO $BUGS -connect "$NODEIP:$PORT" -msg $PROXY $SNI $TMPFILE 2>>$ERRFILE if sclient_auth $? $TMPFILE; then all_failed=1 break From 72bbdbf49b0ad34966095dbcc9321ec1dd1fa36f Mon Sep 17 00:00:00 2001 From: David Cooper Date: Tue, 26 Jul 2016 12:00:46 -0400 Subject: [PATCH 07/10] Remove fixes for minor typos --- testssl.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testssl.sh b/testssl.sh index 0f60a2a..41683fd 100755 --- a/testssl.sh +++ b/testssl.sh @@ -717,7 +717,7 @@ run_http_header() { 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 ito get an accurate header time! + # again in the foreground ito get an ccurate header time! printf "$GET_REQ11" | $OPENSSL s_client $OPTIMAL_PROTO $BUGS -quiet -ign_eof -connect $NODEIP:$PORT $PROXY $addcmd >$HEADERFILE 2>$ERRFILE NOW_TIME=$(date "+%s") HTTP_TIME=$(awk -F': ' '/^date:/ { print $2 } /^Date:/ { print $2 }' $HEADERFILE) @@ -3858,7 +3858,7 @@ tls_time() { debugme out "$TLS_TIME" outln else - pr_warningln "SSLv3 through TLS 1.2 didn't return a timestamp" + pr_warning "SSLv3 through TLS 1.2 didn't return a timestamp" fileout "tls_time" "INFO" "No TLS timestamp returned by SSLv3 through TLSv1.2" fi return 0 From 1c531603489131dfe6a11990ad2fb4f6bc81c65e Mon Sep 17 00:00:00 2001 From: Dirk Date: Thu, 1 Sep 2016 19:04:47 +0200 Subject: [PATCH 08/10] ups ;-) --- testssl.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testssl.sh b/testssl.sh index 0b2f446..614a3e8 100755 --- a/testssl.sh +++ b/testssl.sh @@ -172,7 +172,7 @@ USLEEP_REC=${USLEEP_REC:-0.2} # sleep time for general socket receive HSTS_MIN=${HSTS_MIN:-179} # >179 days is ok for HSTS HSTS_MIN=$((HSTS_MIN * 86400)) # correct to seconds HPKP_MIN=${HPKP_MIN:-30} # >=30 days should be ok for HPKP_MIN, practical hints? - HPKP_MIN=$((HPKP_MIN * 86400)) # correct to seconds +# HPKP_MIN=$((HPKP_MIN * 86400)) # correct to seconds DAYS2WARN1=${DAYS2WARN1:-60} # days to warn before cert expires, threshold 1 DAYS2WARN2=${DAYS2WARN2:-30} # days to warn before cert expires, threshold 2 VULN_THRESHLD=${VULN_THRESHLD:-1} # if vulnerabilities to check >$VULN_THRESHLD we DON'T show a separate header line in the output each vuln. check @@ -8684,4 +8684,4 @@ fi exit $? -# $Id: testssl.sh,v 1.535 2016/09/01 10:42:53 dirkw Exp $ +# $Id: testssl.sh,v 1.536 2016/09/01 17:04:46 dirkw Exp $ From 2313aee22da0a7e6d2be56a759273e182d507b4c Mon Sep 17 00:00:00 2001 From: Dirk Date: Thu, 1 Sep 2016 19:09:12 +0200 Subject: [PATCH 09/10] fix for previously borken HPKP_MIN value --- testssl.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/testssl.sh b/testssl.sh index 614a3e8..d3b1e91 100755 --- a/testssl.sh +++ b/testssl.sh @@ -172,7 +172,7 @@ USLEEP_REC=${USLEEP_REC:-0.2} # sleep time for general socket receive HSTS_MIN=${HSTS_MIN:-179} # >179 days is ok for HSTS HSTS_MIN=$((HSTS_MIN * 86400)) # correct to seconds HPKP_MIN=${HPKP_MIN:-30} # >=30 days should be ok for HPKP_MIN, practical hints? -# HPKP_MIN=$((HPKP_MIN * 86400)) # correct to seconds + HPKP_MIN=$((HPKP_MIN * 86400)) # correct to seconds DAYS2WARN1=${DAYS2WARN1:-60} # days to warn before cert expires, threshold 1 DAYS2WARN2=${DAYS2WARN2:-30} # days to warn before cert expires, threshold 2 VULN_THRESHLD=${VULN_THRESHLD:-1} # if vulnerabilities to check >$VULN_THRESHLD we DON'T show a separate header line in the output each vuln. check @@ -1012,7 +1012,7 @@ run_hpkp() { # print key=value pair with awk, then strip non-numbers, to be improved with proper parsing of key-value with awk hpkp_age_sec=$(awk -F= '/max-age/{max_age=$2; print max_age}' $TMPFILE | sed -E 's/[^[:digit:]]//g') hpkp_age_days=$((hpkp_age_sec / 86400)) - if [[ $hpkp_age_days -ge $HPKP_MIN ]]; then + if [[ $hpkp_age_sec -ge $HPKP_MIN ]]; then pr_done_good "$hpkp_age_days days" ; out "=$hpkp_age_sec s" fileout "hpkp_age" "OK" "HPKP age is set to $hpkp_age_days days ($hpkp_age_sec sec)" else @@ -8684,4 +8684,4 @@ fi exit $? -# $Id: testssl.sh,v 1.536 2016/09/01 17:04:46 dirkw Exp $ +# $Id: testssl.sh,v 1.537 2016/09/01 17:09:11 dirkw Exp $ From a9002ba6e6522c26df4767de17c3608e87140115 Mon Sep 17 00:00:00 2001 From: David Cooper Date: Thu, 1 Sep 2016 13:22:39 -0400 Subject: [PATCH 10/10] Fix tls_sockets() when SNI empty `socksend_tls_clienthello()` always includes a server name extension in the ClientHello (for TLS 1.0 and above), even if `$SNI` is empty. If `$NODE` is an IP address, then the IP address is placed in the extension, even though RFC 6066 says that only DNS names are supported in the extension. This PR changes `socksend_tls_clienthello()` so that the server name extension is only included in the ClientHello is `$SNI` is not empty. --- testssl.sh | 48 +++++++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/testssl.sh b/testssl.sh index d3b1e91..10e2138 100755 --- a/testssl.sh +++ b/testssl.sh @@ -5747,20 +5747,22 @@ socksend_tls_clienthello() { fi done - #formatted example for SNI - #00 00 # extension server_name - #00 1a # length = the following +2 = server_name length + 5 - #00 18 # server_name list_length = server_name length +3 - #00 # server_name type (hostname) - #00 15 # server_name length - #66 66 66 66 66 66 2e 66 66 66 66 66 66 66 66 66 66 2e 66 66 66 target.mydomain1.tld # server_name target - len_servername=${#NODE} - hexdump_format_str="$len_servername/1 \"%02x,\"" - servername_hexstr=$(printf $NODE | hexdump -v -e "${hexdump_format_str}" | sed 's/,$//') - # convert lengths we need to fill in from dec to hex: - len_servername_hex=$(printf "%02x\n" $len_servername) - len_sni_listlen=$(printf "%02x\n" $((len_servername+3))) - len_sni_ext=$(printf "%02x\n" $((len_servername+5))) + if [[ -n "$SNI" ]]; then + #formatted example for SNI + #00 00 # extension server_name + #00 1a # length = the following +2 = server_name length + 5 + #00 18 # server_name list_length = server_name length +3 + #00 # server_name type (hostname) + #00 15 # server_name length + #66 66 66 66 66 66 2e 66 66 66 66 66 66 66 66 66 66 2e 66 66 66 target.mydomain1.tld # server_name target + len_servername=${#NODE} + hexdump_format_str="$len_servername/1 \"%02x,\"" + servername_hexstr=$(printf $NODE | hexdump -v -e "${hexdump_format_str}" | sed 's/,$//') + # convert lengths we need to fill in from dec to hex: + len_servername_hex=$(printf "%02x\n" $len_servername) + len_sni_listlen=$(printf "%02x\n" $((len_servername+3))) + len_sni_ext=$(printf "%02x\n" $((len_servername+5))) + fi extension_signature_algorithms=" 00, 0d, # Type: signature_algorithms , see RFC 5246 @@ -5790,16 +5792,20 @@ socksend_tls_clienthello() { 01, 00" all_extensions=" - 00, 00 # extension server_name - ,00, $len_sni_ext # length SNI EXT - ,00, $len_sni_listlen # server_name list_length - ,00 # server_name type (hostname) - ,00, $len_servername_hex # server_name length. We assume len(hostname) < FF - 9 - ,$servername_hexstr # server_name target - ,$extension_heartbeat + $extension_heartbeat ,$extension_session_ticket ,$extension_next_protocol" + if [[ -n "$SNI" ]]; then + all_extensions="$all_extensions + ,00, 00 # extension server_name + ,00, $len_sni_ext # length SNI EXT + ,00, $len_sni_listlen # server_name list_length + ,00 # server_name type (hostname) + ,00, $len_servername_hex # server_name length. We assume len(hostname) < FF - 9 + ,$servername_hexstr" # server_name target + fi + # RFC 5246 says that clients MUST NOT offer the signature algorithms # extension if they are offering TLS versions prior to 1.2. if [[ "0x$tls_low_byte" -ge "0x03" ]]; then