diff --git a/CREDITS.md b/CREDITS.md index 967c0bb..cb857cd 100644 --- a/CREDITS.md +++ b/CREDITS.md @@ -20,10 +20,12 @@ - Detection of insecure redirects - JSON and CSV output - Client simulations + - CI integration, test cases for it * David Cooper - Detection + output of multiple certificates - several cleanups of server certificate related stuff + - several minor fixes - improved parsing of TLS ServerHello messages - speed improvements when testing all ciphers diff --git a/testssl.sh b/testssl.sh index f318ee6..84f6447 100755 --- a/testssl.sh +++ b/testssl.sh @@ -83,7 +83,7 @@ readonly PS4='${LINENO}> ${FUNCNAME[0]:+${FUNCNAME[0]}(): }' # make sure that temporary files are cleaned up after use in ANY case trap "cleanup" QUIT EXIT -readonly VERSION="2.8rc1" +readonly VERSION="2.8rc2" readonly SWCONTACT="dirk aet testssl dot sh" egrep -q "dev|rc" <<< "$VERSION" && \ SWURL="https://testssl.sh/dev/" || @@ -211,6 +211,7 @@ OSSL_VER_APPENDIX="none" HAS_DH_BITS=${HAS_DH_BITS:-false} # initialize openssl variables HAS_SSL2=false HAS_SSL3=false +HAS_NO_SSL2=false HAS_ALPN=false HAS_SPDY=false ADD_RFC_STR="rfc" # display RFC ciphernames @@ -2775,6 +2776,7 @@ 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]}")" $OPENSSL s_client -cipher ${ciphers[i]} ${protos[i]} $STARTTLS $BUGS $PROXY -connect $NODEIP:$PORT ${sni[i]} $TMPFILE 2>$ERRFILE debugme echo "$OPENSSL s_client -cipher ${ciphers[i]} ${protos[i]} $STARTTLS $BUGS $PROXY -connect $NODEIP:$PORT ${sni[i]} =2)" + [[ $DEBUG -ge 3 ]] && hexdump -C "$TEMPDIR/$NODEIP.sslv2_sockets.dd" | head -1 + fileout "sslv2" "WARN" "SSLv2: received a strange SSLv2 reply (rerun with DEBUG>=2)" + ;; + 1) # no sslv2 server hello returned, like in openlitespeed which returns HTTP! + pr_done_bestln "not offered (OK)" + fileout "sslv2" "OK" "SSLv2 not offered (OK)" + ;; + 0) # reset + pr_done_bestln "not offered (OK)" + fileout "sslv2" "OK" "SSLv2 not offered (OK)" + ;; + 3) # everything else + lines=$(count_lines "$(hexdump -C "$TEMPDIR/$NODEIP.sslv2_sockets.dd" 2>/dev/null)") + [[ "$DEBUG" -ge 2 ]] && out " ($lines lines) " + if [[ "$lines" -gt 1 ]]; then + nr_ciphers_detected=$((V2_HELLO_CIPHERSPEC_LENGTH / 3)) + add_tls_offered "ssl2" + if [[ 0 -eq "$nr_ciphers_detected" ]]; then + pr_svrty_highln "supported but couldn't detect a cipher and vulnerable to CVE-2015-3197 "; + fileout "sslv2" "NOT ok" "SSLv2 offered (NOT ok), vulnerable to CVE-2015-3197" + else + pr_svrty_critical "offered (NOT ok), also VULNERABLE to DROWN attack"; + outln " -- $nr_ciphers_detected ciphers" + fileout "sslv2" "NOT ok" "SSLv2 offered (NOT ok), vulnerable to DROWN attack. Detected ciphers: $nr_ciphers_detected" + fi + fi ;; + esac + pr_off + debugme outln else run_prototest_openssl "-ssl2" case $? in @@ -3104,7 +3140,6 @@ run_protocols() { 1) pr_svrty_mediumln "not offered" if ! "$using_sockets" || ! "$EXPERIMENTAL" || [[ -z $latest_supported ]]; then - outln fileout "tls1_2" "MEDIUM" "TLSv1.2 is not offered" # no GCM, penalty else pr_svrty_criticalln " -- connection failed rather than downgrading to $latest_supported_string" @@ -3433,7 +3468,11 @@ 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 + if [[ "$p" =~ ssl ]]; then + $OPENSSL s_client $STARTTLS -"$p" $BUGS -connect $NODEIP:$PORT $PROXY >$ERRFILE >$TMPFILE + else + $OPENSSL s_client $STARTTLS -"$p" $BUGS -connect $NODEIP:$PORT $PROXY $SNI >$ERRFILE >$TMPFILE + fi 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') @@ -3564,7 +3603,7 @@ check_tls12_pref() { cipher_pref_check() { - local p proto protos npn_protos + local p proto protos npn_protos sni local tested_cipher cipher order local overflow_probe_cipherlist="ALL:-ECDHE-RSA-AES256-GCM-SHA384:-AES128-SHA:-DES-CBC3-SHA" @@ -3581,11 +3620,12 @@ cipher_pref_check() { continue fi # with the supplied binaries SNI works also for SSLv2 (+ SSLv3) - $OPENSSL s_client $STARTTLS -"$p" $BUGS -connect $NODEIP:$PORT $PROXY $SNI $ERRFILE >$TMPFILE + [[ "$p" =~ ssl ]] && sni="" || sni=$SNI + $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) - cipher=$(awk '/Cipher.*:/ { print $3 }' $TMPFILE) + cipher=$(awk '/Cipher *:/ { print $3 }' $TMPFILE) [[ -z "$proto" ]] && continue # for early openssl versions sometimes needed outln printf " %-10s" "$proto: " @@ -3608,9 +3648,9 @@ 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 $SNI >$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) + cipher=$(awk '/Cipher *:/ { print $3 }' $TMPFILE) out " $cipher" order+=" $cipher" tested_cipher="$tested_cipher:-$cipher" @@ -4193,6 +4233,7 @@ certificate_info() { *DSA*|*dsa*) out "DSA ";; *ecdsa*|*ecPublicKey) out "ECDSA ";; *GOST*|*gost*) out "GOST ";; + *dh*|*DH*) out "DH " ;; *) pr_warning "fixme: $cert_key_algo " ;; esac # https://tools.ietf.org/html/rfc4492, http://www.keylength.com/en/compare/ @@ -4220,7 +4261,8 @@ certificate_info() { fileout "${json_prefix}key_size" "DEBUG" "Server keys $cert_keysize bits (not expected)" fi outln " bits" - elif [[ $cert_key_algo = *RSA* ]] || [[ $cert_key_algo = *rsa* ]] || [[ $cert_key_algo = *dsa* ]]; then + elif [[ $cert_key_algo = *RSA* ]] || [[ $cert_key_algo = *rsa* ]] || [[ $cert_key_algo = *dsa* ]] || \ + [[ $cert_key_algo =~ dhKeyAgreement ]] || [[ $cert_key_algo =~ "X9.42 DH" ]]; then if [[ "$cert_keysize" -le 512 ]]; then pr_svrty_critical "$cert_keysize" outln " bits" @@ -5583,7 +5625,7 @@ parse_tls_serverhello() { sslv2_sockets() { - local nr_ciphers_detected + local ret fd_socket 5 || return 6 debugme outln "sending client hello... " @@ -5597,43 +5639,7 @@ sslv2_sockets() { fi parse_sslv2_serverhello "$SOCK_REPLY_FILE" - case $? in - 7) # strange reply, couldn't convert the cipher spec length to a hex number - pr_cyan "strange v2 reply " - outln " (rerun with DEBUG >=2)" - [[ $DEBUG -ge 3 ]] && hexdump -C "$SOCK_REPLY_FILE" | head -1 - ret=7 - fileout "sslv2" "WARN" "SSLv2: received a strange SSLv2 reply (rerun with DEBUG>=2)" - ;; - 1) # no sslv2 server hello returned, like in openlitespeed which returns HTTP! - pr_done_bestln "not offered (OK)" - ret=0 - fileout "sslv2" "OK" "SSLv2 not offered (OK)" - ;; - 0) # reset - pr_done_bestln "not offered (OK)" - ret=0 - fileout "sslv2" "OK" "SSLv2 not offered (OK)" - ;; - 3) # everything else - lines=$(count_lines "$(hexdump -C "$SOCK_REPLY_FILE" 2>/dev/null)") - [[ "$DEBUG" -ge 2 ]] && out " ($lines lines) " - if [[ "$lines" -gt 1 ]]; then - nr_ciphers_detected=$((V2_HELLO_CIPHERSPEC_LENGTH / 3)) - add_tls_offered "ssl2" - if [[ 0 -eq "$nr_ciphers_detected" ]]; then - pr_svrty_highln "supported but couldn't detect a cipher and vulnerable to CVE-2015-3197 "; - fileout "sslv2" "NOT ok" "SSLv2 offered (NOT ok), vulnerable to CVE-2015-3197" - else - pr_svrty_critical "offered (NOT ok), also VULNERABLE to DROWN attack"; - outln " -- $nr_ciphers_detected ciphers" - fileout "sslv2" "NOT ok" "SSLv2 offered (NOT ok), vulnerable to DROWN attack. Detected ciphers: $nr_ciphers_detected" - fi - ret=1 - fi ;; - esac - pr_off - debugme outln + ret=$? close_socket TMPFILE=$SOCK_REPLY_FILE @@ -6435,10 +6441,11 @@ run_ssl_poodle() { [[ $VULN_COUNT -le $VULN_THRESHLD ]] && outln && pr_headlineln " Testing for SSLv3 POODLE (Padding Oracle On Downgraded Legacy Encryption) " && outln pr_bold " POODLE, SSL"; out " (CVE-2014-3566) " + locally_supported "-ssl3" || return 0 cbc_ciphers=$(actually_supported_ciphers $cbc_ciphers) debugme echo $cbc_ciphers - $OPENSSL s_client -ssl3 $STARTTLS $BUGS -cipher $cbc_ciphers -connect $NODEIP:$PORT $PROXY $SNI >$TMPFILE 2>$ERRFILE $TMPFILE 2>$ERRFILE =2)" - [[ $DEBUG -ge 3 ]] && hexdump -C "$SOCK_REPLY_FILE" | head -1 + [[ $DEBUG -ge 3 ]] && hexdump -C "$TEMPDIR/$NODEIP.sslv2_sockets.dd" | head -1 ret=7 fileout "drown" "MINOR_ERROR" "SSLv2: received a strange SSLv2 reply (rerun with DEBUG>=2)" ;; 3) # vulnerable - lines=$(count_lines "$(hexdump -C "$SOCK_REPLY_FILE" 2>/dev/null)") + lines=$(count_lines "$(hexdump -C "$TEMPDIR/$NODEIP.sslv2_sockets.dd" 2>/dev/null)") debugme out " ($lines lines) " if [[ "$lines" -gt 1 ]]; then nr_ciphers_detected=$((V2_HELLO_CIPHERSPEC_LENGTH / 3)) @@ -6666,8 +6674,8 @@ run_drown() { pr_svrty_highln "CVE-2015-3197: SSLv2 supported but couldn't detect a cipher (NOT ok)"; fileout "drown" "NOT ok" "SSLv2 offered (NOT ok), CVE-2015-3197: but could not detect a cipher" else - pr_svrty_criticalln "vulnerable (NOT ok), SSLv2 offered with $nr_ciphers_detected ciphers"; - fileout "drown" "NOT ok" "vulnerable (NOT ok), SSLv2 offered with $nr_ciphers_detected ciphers" + pr_svrty_criticalln "VULNERABLE (NOT ok), SSLv2 offered with $nr_ciphers_detected ciphers"; + fileout "drown" "NOT ok" "VULNERABLE (NOT ok), SSLv2 offered with $nr_ciphers_detected ciphers" fi fi ret=1 @@ -6730,11 +6738,21 @@ run_beast(){ done for proto in ssl3 tls1; do + if [[ "$proto" == "ssl3" ]] && ! locally_supported "-$proto"; then + continued=true + out " " + continue + fi $OPENSSL s_client -"$proto" $STARTTLS $BUGS -connect $NODEIP:$PORT $PROXY $SNI >$TMPFILE 2>>$ERRFILE &1 | grep -aq "unknown option" || \ HAS_SSL3=true + $OPENSSL s_client -no_ssl2 2>&1 | grep -aq "unknown option" || \ + HAS_NO_SSL2=true + $OPENSSL s_client -help 2>&1 | grep -qw '\-alpn' && \ HAS_ALPN=true @@ -7258,6 +7279,7 @@ OPENSSL_CONF: $OPENSSL_CONF HAS_IPv6: $HAS_IPv6 HAS_SSL2: $HAS_SSL2 HAS_SSL3: $HAS_SSL3 +HAS_NO_SSL2: $HAS_NO_SSL2 HAS_SPDY: $HAS_SPDY HAS_ALPN: $HAS_ALPN @@ -7816,6 +7838,7 @@ determine_optimal_proto() { fi all_failed=0 done + [[ $all_failed -eq 0 ]] && STARTTLS_OPTIMAL_PROTO="" debugme echo "STARTTLS_OPTIMAL_PROTO: $STARTTLS_OPTIMAL_PROTO" else for OPTIMAL_PROTO in '' -tls1_2 -tls1 -ssl3 -tls1_1 -ssl2; do @@ -7827,6 +7850,7 @@ determine_optimal_proto() { fi all_failed=0 done + [[ $all_failed -eq 0 ]] && OPTIMAL_PROTO="" debugme echo "OPTIMAL_PROTO: $OPTIMAL_PROTO" if [[ "$OPTIMAL_PROTO" == "-ssl2" ]]; then pr_magentaln "$NODEIP:$PORT appears to only support SSLv2." @@ -8328,7 +8352,7 @@ parse_cmd_line() { do_pfs=true ;; --devel) ### this development feature will soon disappear - HEX_CIPHER="" + HEX_CIPHER="$TLS12_CIPHER" # DEBUG=3 ./testssl.sh --devel 03 "cc, 13, c0, 13" google.de --> TLS 1.2, old CHACHA/POLY # DEBUG=3 ./testssl.sh --devel 03 "cc,a8, cc,a9, cc,aa, cc,ab, cc,ac" blog.cloudflare.com --> new CHACHA/POLY # DEBUG=3 ./testssl.sh --devel 01 yandex.ru --> TLS 1.0 @@ -8515,9 +8539,8 @@ lets_roll() { determine_rdns determine_service "$1" # any starttls service goes here - $do_tls_sockets && { [[ $TLS_LOW_BYTE -eq 22 ]] && \ - sslv2_sockets || \ - tls_sockets "$TLS_LOW_BYTE" "$HEX_CIPHER"; echo "$?" ; exit 0; } + $do_tls_sockets && [[ $TLS_LOW_BYTE -eq 22 ]] && { sslv2_sockets; echo "$?" ; exit 0; } + $do_tls_sockets && [[ $TLS_LOW_BYTE -ne 22 ]] && { tls_sockets "$TLS_LOW_BYTE" "$HEX_CIPHER"; echo "$?" ; exit 0; } $do_test_just_one && test_just_one ${single_cipher} # all top level functions now following have the prefix "run_" @@ -8644,4 +8667,4 @@ fi exit $? -# $Id: testssl.sh,v 1.531 2016/07/23 13:12:12 dirkw Exp $ +# $Id: testssl.sh,v 1.533 2016/08/28 19:41:29 dirkw Exp $