From 01997b8b818d4b8b73154d462f368f14737b2a4f Mon Sep 17 00:00:00 2001 From: David Cooper Date: Tue, 29 Nov 2016 11:58:49 -0500 Subject: [PATCH 1/7] run_rc4() sockets implementation This PR implements `run_rc4()` in a similar manner to `run_allciphers()` and `run_cipher_per_proto()` (in PR #541). The change doesn't seem to have much of an impact on speed, but when sockets are used it can detect ciphers that aren't locally supported by OpenSSL. --- testssl.sh | 232 ++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 196 insertions(+), 36 deletions(-) diff --git a/testssl.sh b/testssl.sh index 884c143..223ab64 100755 --- a/testssl.sh +++ b/testssl.sh @@ -8822,12 +8822,19 @@ run_lucky13() { # http://blog.cryptographyengineering.com/2013/03/attack-of-week-rc4-is-kind-of-broken-in.html run_rc4() { local -i rc4_offered=0 - local -i sclient_success - 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_ssl2_ciphers_list="RC4-MD5:RC4-64-MD5:EXP-RC4-MD5" - local rc4_detected="" - local available="" + local -i nr_ciphers=0 nr_ossl_ciphers=0 nr_nonossl_ciphers=0 ret + local n auth mac export hexc sslv2_ciphers_hex="" sslv2_ciphers_ossl="" s + local -a normalized_hexcode hexcode ciph sslvers kx enc export2 sigalg ossl_supported + local -i i + local -a ciphers_found ciphers_found2 hexcode2 ciph2 sslvers2 rfc_ciph2 + local -i -a index + local dhlen available="" ciphers_to_test supported_sslv2_ciphers addcmd="" + local has_dh_bits="$HAS_DH_BITS" rc4_detected="" + local using_sockets=true + + "$SSL_NATIVE" && using_sockets=false + "$FAST" && using_sockets=false + [[ $TLS_NR_CIPHERS == 0 ]] && using_sockets=false if [[ $VULN_COUNT -le $VULN_THRESHLD ]]; then outln @@ -8838,62 +8845,215 @@ run_rc4() { fi pr_bold " RC4"; out " (CVE-2013-2566, CVE-2015-2808) " - $OPENSSL s_client -cipher $rc4_ciphers_list $STARTTLS $BUGS -connect $NODEIP:$PORT $PROXY $SNI >$TMPFILE 2>$ERRFILE $TMPFILE 2>$ERRFILE >$ERRFILE) fi - if [[ $sclient_success -eq 0 ]]; then + + if "$using_sockets" && [[ -n "$sslv2_ciphers_hex" ]]; then + sslv2_sockets "${sslv2_ciphers_hex:2}" "true" + if [[ $? -eq 3 ]] && [[ "$V2_HELLO_CIPHERSPEC_LENGTH" -ne 0 ]]; then + supported_sslv2_ciphers="$(grep "Supported cipher: " "$TEMPDIR/$NODEIP.parse_sslv2_serverhello.txt")" + "$WIDE" && "$SHOW_SIGALGO" && s="$($OPENSSL x509 -noout -text -in "$HOSTCERT" | awk -F':' '/Signature Algorithm/ { print $2 }' | head -1)" + for (( i=0 ; i$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 - 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 + for (( i=0 ; i Date: Tue, 6 Dec 2016 11:23:01 -0500 Subject: [PATCH 2/7] Don't parse SSLv2 ServerHello unless successful response This PR is a proposed alternative to #537. It only attempts to extract the certificate and list of ciphers from the SSLv2 ServerHello is `ret=3`. --- testssl.sh | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/testssl.sh b/testssl.sh index 883c267..d34a1fe 100755 --- a/testssl.sh +++ b/testssl.sh @@ -6514,20 +6514,21 @@ parse_sslv2_serverhello() { fi fi - certificate_len=2*$(hex2dec "$v2_hello_cert_length") - [[ -e $HOSTCERT ]] && rm $HOSTCERT - [[ -e $TEMPDIR/intermediatecerts.pem ]] && rm $TEMPDIR/intermediatecerts.pem - if [[ "$2" == "true" ]] && [[ "$v2_cert_type" == "01" ]] && [[ "$v2_hello_cert_length" != "00" ]]; then - tmp_der_certfile=$(mktemp $TEMPDIR/der_cert.XXXXXX) || return $ret - asciihex_to_binary_file "${v2_hello_ascii:26:certificate_len}" "$tmp_der_certfile" - $OPENSSL x509 -inform DER -in $tmp_der_certfile -outform PEM -out $HOSTCERT - rm $tmp_der_certfile - get_pub_key_size - echo "======================================" >> $TMPFILE - fi + [[ "$2" == "true" ]] && [[ -e $HOSTCERT ]] && rm $HOSTCERT + [[ "$2" == "true" ]] && [[ -e $TEMPDIR/intermediatecerts.pem ]] && rm $TEMPDIR/intermediatecerts.pem + if [[ "$2" == "true" ]] && [[ $ret -eq 3 ]]; then + certificate_len=2*$(hex2dec "$v2_hello_cert_length") + + if [[ "$v2_cert_type" == "01" ]] && [[ "$v2_hello_cert_length" != "00" ]]; then + tmp_der_certfile=$(mktemp $TEMPDIR/der_cert.XXXXXX) || return $ret + asciihex_to_binary_file "${v2_hello_ascii:26:certificate_len}" "$tmp_der_certfile" + $OPENSSL x509 -inform DER -in $tmp_der_certfile -outform PEM -out $HOSTCERT + rm $tmp_der_certfile + get_pub_key_size + echo "======================================" >> $TMPFILE + fi - # Output list of supported ciphers - if [[ "$2" == "true" ]]; then + # Output list of supported ciphers let offset=26+$certificate_len nr_ciphers_detected=$((V2_HELLO_CIPHERSPEC_LENGTH / 3)) for (( i=0 ; i Date: Tue, 6 Dec 2016 17:18:18 -0500 Subject: [PATCH 3/7] Fix bug in reading of cipher mapping file When the cipher-mapping.txt file is read, the contents of the "Mac=..." column is placed in `TLS_CIPHER_EXPORT` rather than the contents of the "export" column. This PR fixes that. --- testssl.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testssl.sh b/testssl.sh index 883c267..ef9c747 100755 --- a/testssl.sh +++ b/testssl.sh @@ -9405,7 +9405,7 @@ maketempf() { } prepare_debug() { - local hexc ossl_ciph ossl_supported_tls="" ossl_supported_sslv2="" + local hexc mac ossl_ciph ossl_supported_tls="" ossl_supported_sslv2="" if [[ $DEBUG -ne 0 ]]; then cat >$TEMPDIR/environment.txt << EOF @@ -9484,7 +9484,7 @@ EOF if [[ -e $CIPHERS_BY_STRENGTH_FILE ]]; then "$HAS_SSL2" && ossl_supported_sslv2="$($OPENSSL ciphers -ssl2 -V 'ALL:COMPLEMENTOFALL:@STRENGTH' 2>$ERRFILE)" ossl_supported_tls="$($OPENSSL ciphers -tls1 -V 'ALL:COMPLEMENTOFALL:@STRENGTH' 2>$ERRFILE)" - while read hexc n TLS_CIPHER_OSSL_NAME[TLS_NR_CIPHERS] TLS_CIPHER_RFC_NAME[TLS_NR_CIPHERS] TLS_CIPHER_SSLVERS[TLS_NR_CIPHERS] TLS_CIPHER_KX[TLS_NR_CIPHERS] TLS_CIPHER_AUTH[TLS_NR_CIPHERS] TLS_CIPHER_ENC[TLS_NR_CIPHERS] TLS_CIPHER_EXPORT[TLS_NR_CIPHERS]; do + while read hexc n TLS_CIPHER_OSSL_NAME[TLS_NR_CIPHERS] TLS_CIPHER_RFC_NAME[TLS_NR_CIPHERS] TLS_CIPHER_SSLVERS[TLS_NR_CIPHERS] TLS_CIPHER_KX[TLS_NR_CIPHERS] TLS_CIPHER_AUTH[TLS_NR_CIPHERS] TLS_CIPHER_ENC[TLS_NR_CIPHERS] mac TLS_CIPHER_EXPORT[TLS_NR_CIPHERS]; do TLS_CIPHER_HEXCODE[TLS_NR_CIPHERS]="$hexc" TLS_CIPHER_OSSL_SUPPORTED[TLS_NR_CIPHERS]=false if [[ ${#hexc} -eq 9 ]]; then From d14b24e832e3ee011777dfa0055f30ccafc9374a Mon Sep 17 00:00:00 2001 From: Dirk Date: Sun, 11 Dec 2016 18:15:36 +0100 Subject: [PATCH 4/7] regression fix #290, see #549 --- testssl.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testssl.sh b/testssl.sh index 7ee8573..9daa3fc 100755 --- a/testssl.sh +++ b/testssl.sh @@ -9922,7 +9922,7 @@ get_local_aaaa() { 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 - ip6=$(grep -wh "$NODE" $etchosts 2>/dev/null | grep ':' | grep -v '^#' | egrep "[[:space:]]$NODE" | awk '{ print $1 }') + ip6=$(grep -wh "$1" $etchosts 2>/dev/null | grep ':' | egrep -v '^#|\.local' | egrep "[[:space:]]$1" | awk '{ print $1 }') if is_ipv6addr "$ip6"; then echo "$ip6" else @@ -9935,7 +9935,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 ':|^#|\.local' | egrep "[[:space:]]$1" | awk '{ print $1 }') if is_ipv4addr "$ip4"; then echo "$ip4" else From 2a9668c000a0ab632b04ded42927b0ad8ac14015 Mon Sep 17 00:00:00 2001 From: David Cooper Date: Mon, 12 Dec 2016 09:38:20 -0500 Subject: [PATCH 5/7] Updated based on @typingArtist's suggesting --- testssl.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/testssl.sh b/testssl.sh index e45fb88..f6f385c 100755 --- a/testssl.sh +++ b/testssl.sh @@ -6514,9 +6514,9 @@ parse_sslv2_serverhello() { fi fi - [[ "$2" == "true" ]] && [[ -e $HOSTCERT ]] && rm $HOSTCERT - [[ "$2" == "true" ]] && [[ -e $TEMPDIR/intermediatecerts.pem ]] && rm $TEMPDIR/intermediatecerts.pem - if [[ "$2" == "true" ]] && [[ $ret -eq 3 ]]; then + [[ "$2" == "true" ]] || return $ret + rm -f $HOSTCERT $TEMPDIR/intermediatecerts.pem + if [[ $ret -eq 3 ]]; then certificate_len=2*$(hex2dec "$v2_hello_cert_length") if [[ "$v2_cert_type" == "01" ]] && [[ "$v2_hello_cert_length" != "00" ]]; then From 461f9566032a939804012b70abd3e83023ae7de0 Mon Sep 17 00:00:00 2001 From: Steven Danneman Date: Thu, 8 Dec 2016 10:54:44 -0800 Subject: [PATCH 6/7] Add support for testing postgres protocol over TLS/SSL The Postgres protocol uses STARTTLS with a custom start packet. This functionality is supported by openssl s_client in the current openssl master branch but not yet in any released version. This patch detects whether the given openssl binary supports postgres and runs the default tests against a postgres server. Example of no openssl support: ~/bin/testssl$ ./testssl.sh --quiet --openssl=/opt/openssl/openssl-1.1.0c/bin/openssl --starttls=postgres test.postgres.server.com:5432 Start 2016-12-07 18:03:24 -->> ip.add.re.ss:5432 (test.postgres.server.com:5432) <<-- Fatal error: Your /opt/openssl/openssl-1.1.0c/bin/openssl does not support the "-starttls postgres" option Example of openssl support: ~/bin/testssl$ ./testssl.sh --quiet --openssl=/opt/openssl/openssl-2016-12-07/bin/openssl --startt ls=postgres test.postgres.server.com:5432 Start 2016-12-07 18:06:03 -->> ip.add.re.ss:5432 (test.postgres.server.com:5432) <<-- Service set: STARTTLS via POSTGRES Testing protocols (via openssl, SSLv2 via sockets) SSLv2 not offered (OK) SSLv3 offered (NOT ok) TLS 1 offered TLS 1.1 offered TLS 1.2 offered (OK) SPDY/NPN (SPDY is an HTTP protocol and thus not tested here) HTTP2/ALPN (HTTP/2 is a HTTP protocol and thus not tested here) ... --- testssl.sh | 45 ++++++++++++++++++++++++++++++++++++++------- 1 file changed, 38 insertions(+), 7 deletions(-) diff --git a/testssl.sh b/testssl.sh index 883c267..66b7d81 100755 --- a/testssl.sh +++ b/testssl.sh @@ -226,6 +226,7 @@ HAS_SPDY=false HAS_FALLBACK_SCSV=false HAS_PROXY=false HAS_XMPP=false +HAS_POSTGRES=false ADD_RFC_STR="rfc" # display RFC ciphernames PORT=443 # unless otherwise auto-determined, see below NODE="" @@ -6227,6 +6228,16 @@ starttls_nntp_dialog() { return $ret } +starttls_postgres_dialog() { + debugme echo "=== starting postgres STARTTLS dialog ===" + local reINITTLS="\x00\x00\x00\x08\x04\xD2\x16\x2F" + starttls_just_send "${reINITTLS}" && debugme echo "initiated STARTTLS" && + starttls_full_read '' '' 'S' && debugme echo "received ack for STARTTLS" + local ret=$? + debugme echo "=== finished postgres STARTTLS dialog with ${ret} ===" + return $ret +} + # arg for a fd doesn't work here fd_socket() { local jabber="" @@ -6301,6 +6312,9 @@ EOF starttls_line "" "proceed" # BTW: https://xmpp.net ! ;; + postgres|postgress) # Postgres SQL, see http://www.postgresql.org/docs/devel/static/protocol-message-formats.html + starttls_postgres_dialog + ;; *) # we need to throw an error here -- otherwise testssl.sh treats the STARTTLS protocol as plain SSL/TLS which leads to FP fatal "FIXME: STARTTLS protocol $STARTTLS_PROTOCOL is not yet supported" -4 esac @@ -9155,6 +9169,7 @@ test_openssl_suffix() { find_openssl_binary() { local s_client_has=$TEMPDIR/s_client_has.txt + local s_client_starttls_has=$TEMPDIR/s_client_starttls_has.txt # 0. check environment variable whether it's executable if [[ -n "$OPENSSL" ]] && [[ ! -x "$OPENSSL" ]]; then @@ -9211,6 +9226,8 @@ find_openssl_binary() { $OPENSSL s_client -help 2>$s_client_has + $OPENSSL s_client -starttls foo 2>$s_client_starttls_has + grep -qw '\-alpn' $s_client_has && \ HAS_ALPN=true @@ -9226,6 +9243,9 @@ find_openssl_binary() { grep -q '\-xmpp' $s_client_has && \ HAS_XMPP=true + grep -q 'postgres' $s_client_starttls_has && \ + HAS_POSTGRES=true + if [[ "$OPENSSL_TIMEOUT" != "" ]]; then if which timeout >&2 2>/dev/null ; then # there are different "timeout". Check whether --preserve-status is supported @@ -9307,7 +9327,7 @@ help() { "$PROG_NAME URI", where is: -t, --starttls does a default run against a STARTTLS enabled (latter two require supplied openssl) + protocol is (latter three require supplied openssl) --xmpphost for STARTTLS enabled XMPP it supplies the XML stream to-'' domain -- sometimes needed --mx tests MX records from high to low priority (STARTTLS, port 25) --file mass testing option: Reads command lines from , one line per instance. @@ -9440,6 +9460,7 @@ HAS_ALPN: $HAS_ALPN HAS_FALLBACK_SCSV: $HAS_FALLBACK_SCSV HAS_PROXY: $HAS_PROXY HAS_XMPP: $HAS_XMPP +HAS_POSTGRES: $HAS_POSTGRES PATH: $PATH PROG_NAME: $PROG_NAME @@ -10070,7 +10091,7 @@ determine_optimal_proto() { } -# arg1: ftp smtp, pop3, imap, xmpp, telnet, ldap (maybe with trailing s) +# arg1: ftp smtp, pop3, imap, xmpp, telnet, ldap, postgres (maybe with trailing s) determine_service() { local ua local protocol @@ -10097,9 +10118,13 @@ determine_service() { service_detection $OPTIMAL_PROTO else # STARTTLS - protocol=${1%s} # strip trailing 's' in ftp(s), smtp(s), pop3(s), etc + if [[ "$1" == postgres ]]; then + protocol="postgres" + else + protocol=${1%s} # strip trailing 's' in ftp(s), smtp(s), pop3(s), etc + fi case "$protocol" in - ftp|smtp|pop3|imap|xmpp|telnet|ldap) + ftp|smtp|pop3|imap|xmpp|telnet|ldap|postgres) STARTTLS="-starttls $protocol" SNI="" if [[ "$protocol" == xmpp ]]; then @@ -10113,6 +10138,12 @@ determine_service() { # see http://xmpp.org/rfcs/rfc3920.html fi fi + if [[ "$protocol" == postgres ]]; then + # Check if openssl version supports postgres. + if ! "$HAS_POSTGRES"; then + fatal "Your $OPENSSL does not support the \"-starttls postgres\" option" -5 + fi + fi $OPENSSL s_client -connect $NODEIP:$PORT $PROXY $BUGS $STARTTLS 2>$ERRFILE >$TMPFILE &2 help 1 ;; esac From f30dab9e2f02b868849d9da9c2dfdb07eb99eafa Mon Sep 17 00:00:00 2001 From: Dirk Date: Tue, 13 Dec 2016 12:38:20 +0100 Subject: [PATCH 7/7] cosmetic improvement to #551 --- testssl.sh | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/testssl.sh b/testssl.sh index 8f47044..585e062 100755 --- a/testssl.sh +++ b/testssl.sh @@ -6490,14 +6490,17 @@ parse_sslv2_serverhello() { # [cipher spec length] ==> ciphers GOOD: HERE ARE ALL CIPHERS ALREADY! local ret=3 + local parse_complete="false" + if [[ "$2" == "true" ]]; then - echo "======================================" > $TMPFILE + parse_complete=true fi + "$parse_complete" && echo "======================================" > $TMPFILE v2_hello_ascii=$(hexdump -v -e '16/1 "%02X"' $1) [[ "$DEBUG" -ge 5 ]] && echo "$v2_hello_ascii" if [[ -z "$v2_hello_ascii" ]]; then - ret=0 # 1 line without any blanks: no server hello received + ret=0 # 1 line without any blanks: no server hello received debugme echo "server hello empty" else # now scrape two bytes out of the reply per byte @@ -6528,7 +6531,8 @@ parse_sslv2_serverhello() { fi fi - [[ "$2" == "true" ]] || return $ret + "$parse_complete" || return $ret + rm -f $HOSTCERT $TEMPDIR/intermediatecerts.pem if [[ $ret -eq 3 ]]; then certificate_len=2*$(hex2dec "$v2_hello_cert_length")