From 3bc0d6b45c7a1266a167e28e9bd267893e09a72b Mon Sep 17 00:00:00 2001 From: David Cooper Date: Wed, 1 Jun 2016 15:57:40 -0400 Subject: [PATCH 01/27] Fix issue #276 Here is my proposed change to fix issue #276. --- testssl.sh | 105 +++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 97 insertions(+), 8 deletions(-) diff --git a/testssl.sh b/testssl.sh index 7cc2e82..81c48c2 100755 --- a/testssl.sh +++ b/testssl.sh @@ -2937,6 +2937,7 @@ sclient_connect_successful() { } # 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) determine_tls_extensions() { local proto local success @@ -2946,9 +2947,15 @@ determine_tls_extensions() { "$HAS_ALPN" && alpn="h2-14,h2-15,h2" + if [[ -n "$2" ]]; then + protocols_to_try="$2" + else + protocols_to_try="tls1_2 tls1_1 tls1 ssl3" + fi + # throwing 1st every cipher/protocol at the server to know what works success=7 - for proto in tls1_2 tls1_1 tls1 ssl3; do + for proto in $protocols_to_try; 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 sclient_connect_successful $? $TMPFILE && success=0 && break @@ -3016,6 +3023,35 @@ get_cn_from_cert() { return $? } +# Return 0 if the server name provided in arg1 matches the CN or SAN in arg2, otherwise return 1. +compare_server_name_to_cert() +{ + local servername=$1 + local cert=$2 + local cn sans san basename + + cn="$(get_cn_from_cert $cert)" + if [[ -n "$cn" ]]; then + [[ "$cn" == "$servername" ]] && return 0 + # If the CN contains a wildcard name, then do a wildcard match + if echo -n "$cn" | grep -q '^*.'; then + basename="$(echo -n "$cn" | sed 's/^\*.//')" + [[ "$cn" == "*.$basename" ]] && [[ "$servername" == *".$basename" ]] && return 0 + fi + fi + + sans=$($OPENSSL x509 -in $cert -noout -text 2>>$ERRFILE | grep -A3 "Subject Alternative Name" | grep "DNS:" | \ + sed -e 's/DNS://g' -e 's/ //g' -e 's/,/ /g' -e 's/othername://g') + for san in $sans; do + [[ "$san" == "$servername" ]] && return 0 + # If $san is a wildcard name, then do a wildcard match + if echo -n "$san" | grep -q '^*.'; then + basename="$(echo -n "$san" | sed 's/^\*.//')" + [[ "$san" == "*.$basename" ]] && [[ "$servername" == *".$basename" ]] && return 0 + fi + done + return 1 +} certificate_info() { local proto @@ -3473,7 +3509,7 @@ certificate_info() { run_server_defaults() { - local ciph match_found newhostcert + local ciph match_found newhostcert sni local sessticket_str="" local lifetime unit local line @@ -3481,8 +3517,9 @@ run_server_defaults() { local all_tls_extensions="" local -i certs_found=0 local -a previous_hostcert previous_intermediates keysize cipher ocsp_response ocsp_response_status - local -a ciphers_to_test - + local -a ciphers_to_test success + local cn_nosni cn_sni sans_nosni sans_sni san + # Try each public key type once: # ciphers_to_test[1]: cipher suites using certificates with RSA signature public keys # ciphers_to_test[2]: cipher suites using certificates with RSA key encipherment public keys @@ -3507,11 +3544,29 @@ run_server_defaults() { ciphers_to_test[5]="aECDH" ciphers_to_test[6]="aECDSA" ciphers_to_test[7]="aGOST" - - for n in 1 2 3 4 5 6 7 ; do + + for (( n=1; n <= 14 ; n++ )); do + # Some servers use a different certificate if the ClientHello + # specifies TLSv1.1 and doesn't include a server name extension. + # So, for each public key type for which a certificate was found, + # try again, but only with TLSv1.1 and without SNI. + if [[ $n -ge 8 ]]; then + ciphers_to_test[n]="" + [[ ${success[n-7]} -eq 0 ]] && ciphers_to_test[n]="${ciphers_to_test[n-7]}" + fi + if [[ -n "${ciphers_to_test[n]}" ]] && [[ $(count_ciphers $($OPENSSL ciphers "${ciphers_to_test[n]}" 2>>$ERRFILE)) -ge 1 ]]; then - determine_tls_extensions "-cipher ${ciphers_to_test[n]}" - if [[ $? -eq 0 ]]; then + if [[ $n -ge 8 ]]; then + sni="$SNI" + SNI="" + determine_tls_extensions "-cipher ${ciphers_to_test[n]}" "tls1_1" + success[n]=$? + SNI="$sni" + else + determine_tls_extensions "-cipher ${ciphers_to_test[n]}" + success[n]=$? + fi + if [[ ${success[n]} -eq 0 ]]; then # check to see if any new TLS extensions were returned and add any new ones to all_tls_extensions while read -d "\"" -r line; do if [[ $line != "" ]] && ! grep -q "$line" <<< "$all_tls_extensions"; then @@ -3536,6 +3591,40 @@ run_server_defaults() { fi i=$((i + 1)) done + if ! $match_found && [[ $n -ge 8 ]] && [[ $certs_found -ne 0 ]]; then + # A new certificate was found using TLSv1.1 without SNI. + # Check to see if the new certificate should be displayed. + # It should be displayed if it is either a match for the + # $NODE being tested or if it has the same subject + # (CN and SAN) as other certificates for this host. + compare_server_name_to_cert "$NODE" "$HOSTCERT" + success[n]=$? + + if [[ ${success[n]} -ne 0 ]]; then + cn_nosni="$(get_cn_from_cert $HOSTCERT)" + sans_nosni=$($OPENSSL x509 -in $HOSTCERT -noout -text 2>>$ERRFILE | grep -A3 "Subject Alternative Name" | grep "DNS:" | \ + sed -e 's/DNS://g' -e 's/ //g' -e 's/,/ /g' -e 's/othername://g') + + echo "${previous_hostcert[1]}" > $HOSTCERT + cn_sni="$(get_cn_from_cert $HOSTCERT)" + + # FIXME: Not sure what the matching rule should be. At + # the moment, the no SNI certificate is considered a + # match if the CNs are the same and the SANs contain + # at least one DNS name in common. + if [[ "$cn_nosni" == "$cn_sni" ]]; then + sans_sni=$($OPENSSL x509 -in $HOSTCERT -noout -text 2>>$ERRFILE | grep -A3 "Subject Alternative Name" | grep "DNS:" | \ + sed -e 's/DNS://g' -e 's/ //g' -e 's/,/ /g' -e 's/othername://g') + for san in $sans_nosni; do + [[ " $sans_sni " =~ " $san " ]] && success[n]=0 && break + done + fi + fi + # If the certificate found for TLSv1.1 w/o SNI appears to + # be for a different host, then set match_found to true so + # that the new certificate will not be included in the output. + [[ ${success[n]} -ne 0 ]] && match_found=true + fi if ! $match_found ; then certs_found=$(($certs_found + 1)) cipher[certs_found]=${ciphers_to_test[n]} From 6825c0b363ebf77fb296f7f05e06f4f8244d07b4 Mon Sep 17 00:00:00 2001 From: David Cooper Date: Wed, 1 Jun 2016 16:20:10 -0400 Subject: [PATCH 02/27] Allow for certificates with no subjectAltName extension While it seems that almost all certificates include a subjectAltName extension, need to allow for the possibility that the two certificates being compared don't have subjectAltName extensions. --- testssl.sh | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/testssl.sh b/testssl.sh index 81c48c2..2828d8d 100755 --- a/testssl.sh +++ b/testssl.sh @@ -3610,14 +3610,18 @@ run_server_defaults() { # FIXME: Not sure what the matching rule should be. At # the moment, the no SNI certificate is considered a - # match if the CNs are the same and the SANs contain - # at least one DNS name in common. + # match if the CNs are the same and the SANs (if + # present) contain at least one DNS name in common. if [[ "$cn_nosni" == "$cn_sni" ]]; then sans_sni=$($OPENSSL x509 -in $HOSTCERT -noout -text 2>>$ERRFILE | grep -A3 "Subject Alternative Name" | grep "DNS:" | \ sed -e 's/DNS://g' -e 's/ //g' -e 's/,/ /g' -e 's/othername://g') - for san in $sans_nosni; do - [[ " $sans_sni " =~ " $san " ]] && success[n]=0 && break - done + if [[ "$sans_nosni" == "$sans_sni" ]]; then + success[n]=0 + else + for san in $sans_nosni; do + [[ " $sans_sni " =~ " $san " ]] && success[n]=0 && break + done + fi fi fi # If the certificate found for TLSv1.1 w/o SNI appears to From b264714fd9d464ea7cc5eac0053071c9a8cdf73a Mon Sep 17 00:00:00 2001 From: David Cooper Date: Mon, 13 Jun 2016 11:09:15 -0400 Subject: [PATCH 03/27] Add check of IP address compare_server_name_to_cert() now checks the DNS names and IP addresses in the subjectAltName extension for a match. --- testssl.sh | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/testssl.sh b/testssl.sh index 60d6c10..4656f4f 100755 --- a/testssl.sh +++ b/testssl.sh @@ -3161,7 +3161,7 @@ compare_server_name_to_cert() { local servername=$1 local cert=$2 - local cn sans san basename + local cn dns_sans ip_sans san basename cn="$(get_cn_from_cert $cert)" if [[ -n "$cn" ]]; then @@ -3173,9 +3173,10 @@ compare_server_name_to_cert() fi fi - sans=$($OPENSSL x509 -in $cert -noout -text 2>>$ERRFILE | grep -A3 "Subject Alternative Name" | grep "DNS:" | \ - sed -e 's/DNS://g' -e 's/ //g' -e 's/,/ /g' -e 's/othername://g') - for san in $sans; do + # Check whether any of the DNS names in the certificate match the servername + dns_sans=$($OPENSSL x509 -in $cert -noout -text 2>>$ERRFILE | grep -A3 "Subject Alternative Name" | \ + sed -e 's/,/\n/g' | grep "DNS:" | sed -e 's/DNS://g' -e 's/ //g') + for san in $dns_sans; do [[ "$san" == "$servername" ]] && return 0 # If $san is a wildcard name, then do a wildcard match if echo -n "$san" | grep -q '^*.'; then @@ -3183,6 +3184,13 @@ compare_server_name_to_cert() [[ "$san" == "*.$basename" ]] && [[ "$servername" == *".$basename" ]] && return 0 fi done + + # Check whether any of the IP addresses in the certificate match the serername + ip_sans=$($OPENSSL x509 -in $cert -noout -text 2>>$ERRFILE | grep -A3 "Subject Alternative Name" | \ + sed -e 's/,/\n/g' | grep "IP Address:" | sed -e 's/IP Address://g' -e 's/ //g') + for san in $ip_sans; do + [[ "$san" == "$servername" ]] && return 0 + done return 1 } From d5242c255e54a3bafe5a39f2aacc443b4260942d Mon Sep 17 00:00:00 2001 From: Dirk Date: Sun, 3 Jul 2016 21:45:49 +0200 Subject: [PATCH 04/27] FIX #384 --- testssl.sh | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/testssl.sh b/testssl.sh index 457cad3..36d2cad 100755 --- a/testssl.sh +++ b/testssl.sh @@ -170,10 +170,12 @@ USLEEP_SND=${USLEEP_SND:-0.1} # sleep time for general socket send USLEEP_REC=${USLEEP_REC:-0.2} # sleep time for general socket receive HSTS_MIN=${HSTS_MIN:-179} # >179 days is ok for HSTS HPKP_MIN=${HPKP_MIN:-30} # >=30 days should be ok for HPKP_MIN, practical hints? -readonly CLIENT_MIN_PFS=5 # number of ciphers needed to run a test for PFS 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 +readonly CLIENT_MIN_PFS=5 # number of ciphers needed to run a test for PFS + # generated from 'kEECDH:kEDH:!aNULL:!eNULL:!DES:!3DES:!RC4' with openssl 1.0.2i and openssl 1.1.0 +readonly ROBUST_PFS_CIPHERS="DHE-DSS-AES128-GCM-SHA256:DHE-DSS-AES128-SHA256:DHE-DSS-AES128-SHA:DHE-DSS-AES256-GCM-SHA384:DHE-DSS-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-DSS-CAMELLIA128-SHA256:DHE-DSS-CAMELLIA128-SHA:DHE-DSS-CAMELLIA256-SHA256:DHE-DSS-CAMELLIA256-SHA:DHE-DSS-SEED-SHA:DHE-RSA-AES128-CCM8:DHE-RSA-AES128-CCM:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-CCM8:DHE-RSA-AES256-CCM:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-CAMELLIA128-SHA256:DHE-RSA-CAMELLIA128-SHA:DHE-RSA-CAMELLIA256-SHA256:DHE-RSA-CAMELLIA256-SHA:DHE-RSA-CHACHA20-POLY1305-OLD:DHE-RSA-CHACHA20-POLY1305:DHE-RSA-SEED-SHA:ECDHE-ECDSA-AES128-CCM8:ECDHE-ECDSA-AES128-CCM:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-ECDSA-AES256-CCM8:ECDHE-ECDSA-AES256-CCM:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-ECDSA-CAMELLIA128-SHA256:ECDHE-ECDSA-CAMELLIA256-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305-OLD:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-RSA-CAMELLIA128-SHA256:ECDHE-RSA-CAMELLIA256-SHA384:ECDHE-RSA-CHACHA20-POLY1305-OLD:ECDHE-RSA-CHACHA20-POLY1305" HAD_SLEPT=0 CAPATH="${CAPATH:-/etc/ssl/certs/}" # Does nothing yet (FC has only a CA bundle per default, ==> openssl version -d) @@ -4379,18 +4381,13 @@ run_server_defaults() { done } -# http://www.heise.de/security/artikel/Forward-Secrecy-testen-und-einrichten-1932806.html run_pfs() { local -i sclient_success local pfs_offered=false local tmpfile local dhlen local hexcode dash pfs_cipher sslvers kx auth enc mac - # https://community.qualys.com/blogs/securitylabs/2013/08/05/configuring-apache-nginx-and-openssl-for-forward-secrecy -- but with RC4: - #local pfs_ciphers='EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA256 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EDH+aRSA EECDH RC4 !RC4-SHA !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS:@STRENGTH' - #w/o RC4: - #local pfs_ciphers='EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA256 EECDH+aRSA+SHA256 EDH+aRSA EECDH !RC4-SHA !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS:@STRENGTH' - local pfs_cipher_list="ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-CAMELLIA256-SHA256:DHE-RSA-CAMELLIA256-SHA:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-CAMELLIA256-SHA384:ECDHE-ECDSA-CAMELLIA256-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-ECDSA-CAMELLIA128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-CAMELLIA128-SHA256:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-CAMELLIA128-SHA256:DHE-RSA-SEED-SHA:DHE-RSA-CAMELLIA128-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA" + local pfs_cipher_list="$ROBUST_PFS_CIPHERS" local -i nr_supported_ciphers=0 local pfs_ciphers @@ -4410,7 +4407,7 @@ run_pfs() { return 1 fi - $OPENSSL s_client -cipher 'ECDH:DH' $STARTTLS $BUGS -connect $NODEIP:$PORT $PROXY $SNI >$TMPFILE 2>$ERRFILE $TMPFILE 2>$ERRFILE Date: Sun, 3 Jul 2016 22:35:21 +0200 Subject: [PATCH 05/27] updating neat_list() to be faster and more compatible to openssl 1.1.0 with new chacha/poly ciphers --- testssl.sh | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/testssl.sh b/testssl.sh index 36d2cad..2f8d0a8 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.7dev" +readonly VERSION="2.8rc1" readonly SWCONTACT="dirk aet testssl dot sh" egrep -q "dev|rc" <<< "$VERSION" && \ SWURL="https://testssl.sh/dev/" || @@ -1535,9 +1535,13 @@ neat_list(){ kx="${3//Kx=/}" enc="${4//Enc=/}" - strength=$(sed -e 's/.*(//' -e 's/)//' <<< "$enc") # strength = encryption bits - strength="${strength//ChaCha20-Poly1305/ly1305}" - enc=$(sed -e 's/(.*)//g' -e 's/ChaCha20-Poly1305/ChaCha20-Po/g' <<< "$enc") # workaround for empty bits ChaCha20-Poly1305 + strength="${enc//\)/}" # retrieve (). first remove traling ")" + strength="${strength#*\(}" # exfiltrate (VAL + enc="${enc%%\(*}" + + enc="${enc//POLY1305/}" # remove POLY1305 + enc="${enc//\//}" # remove "/" + echo "$export" | grep -iq export && strength="$strength,exp" #printf -- "%q" "$kx" | xxd | head -1 @@ -8145,4 +8149,4 @@ fi exit $? -# $Id: testssl.sh,v 1.512 2016/07/03 19:45:48 dirkw Exp $ +# $Id: testssl.sh,v 1.513 2016/07/03 20:35:20 dirkw Exp $ From f01bff973ae2474c6e6f749b22998b3ea3ca097b Mon Sep 17 00:00:00 2001 From: Dirk Date: Mon, 4 Jul 2016 13:59:39 +0200 Subject: [PATCH 06/27] renamed function, better banner for logging --- testssl.sh | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/testssl.sh b/testssl.sh index 2f8d0a8..5c09ad7 100755 --- a/testssl.sh +++ b/testssl.sh @@ -6620,7 +6620,7 @@ find_openssl_binary() { return 0 } -openssl_age() { +check4openssl_oldfarts() { case "$OSSL_VER" in 0.9.7*|0.9.6*|0.9.5*) # 0.9.5a was latest in 0.9.5 an released 2000/4/1, that'll NOT suffice for this test @@ -7006,7 +7006,9 @@ prepare_logging() { fi >$LOGFILE outln "## Scan started as: \"$PROG_NAME $CMDLINE\"" >>${LOGFILE} - outln "## ($VERSION ${GIT_REL_SHORT:-$CVS_REL_SHORT} from $REL_DATE, at $HNAME:$OPENSSL_LOCATION)\n" >>${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} exec > >(tee -a ${LOGFILE}) # not decided yet. Maybe good to have a separate file or none at all #exec 2> >(tee -a ${LOGFILE} >&2) @@ -8091,7 +8093,7 @@ find_openssl_binary maketempf mybanner check_proxy -openssl_age +check4openssl_oldfarts # TODO: it is ugly to have those two vars here --> main() ret=0 @@ -8149,4 +8151,4 @@ fi exit $? -# $Id: testssl.sh,v 1.513 2016/07/03 20:35:20 dirkw Exp $ +# $Id: testssl.sh,v 1.514 2016/07/04 11:59:38 dirkw Exp $ From 0b5705fff4e0b9dbb0acad03c0bcfc7fdab8cf2e Mon Sep 17 00:00:00 2001 From: Dirk Date: Mon, 4 Jul 2016 23:05:12 +0200 Subject: [PATCH 07/27] FIX #258, FIX #398 partly addressed: #246 --- testssl.sh | 54 ++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/testssl.sh b/testssl.sh index 5c09ad7..d15aa42 100755 --- a/testssl.sh +++ b/testssl.sh @@ -6497,7 +6497,7 @@ run_tls_truncation() { old_fart() { outln "Get precompiled bins or compile https://github.com/PeterMosmans/openssl ." fileout "old_fart" "ERROR" "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." -2 + 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 @@ -6580,7 +6580,7 @@ find_openssl_binary() { # no ERRFILE initialized yet, thus we use /dev/null for stderr directly $OPENSSL version -a 2>/dev/null >/dev/null if [[ $? -ne 0 ]] || [[ ! -x "$OPENSSL" ]]; then - fatal "\ncannot exec or find any openssl binary" -1 + fatal "\ncannot exec or find any openssl binary" -5 fi # http://www.openssl.org/news/openssl-notes.html @@ -6645,6 +6645,16 @@ check4openssl_oldfarts() { } +# FreeBSD needs to have /dev/fd mounted. This is a friendly hint, see #258 +check_bsd_mount() { + if [[ "$(uname)" == FreeBSD ]]; then + if ! mount | grep '/dev/fd' | grep -q fdescfs; then + fatal "You need to mount fdescfs on FreeBSD: \"mount -t fdescfs fdesc /dev/fd\"" -3 + fi + fi +} + + help() { cat << EOF @@ -6887,6 +6897,13 @@ cleanup () { fatal() { pr_magentaln "Fatal error: $1" >&2 exit $2 + # 1: cmd line error + # 2: secondary/other cmd line error + # -1: other user error + # -2: network problem + # -3: s.th. fatal is not supported in the client + # -4: s.th. is not supported yet + # -5: openssl problem } @@ -6935,9 +6952,9 @@ EOF ignore_no_or_lame() { local a - [[ "$WARNINGS" == "off" ]] && return 0 - [[ "$WARNINGS" == "false" ]] && return 0 - [[ "$WARNINGS" == "batch" ]] && return 1 + [[ "$WARNINGS" == off ]] && return 0 + [[ "$WARNINGS" == false ]] && return 0 + [[ "$WARNINGS" == batch ]] && return 1 pr_magenta "$1 " read a case $a in @@ -7112,7 +7129,7 @@ get_a_record() { elif which dig &>/dev/null; then ip4=$(filter_ip4_address $(dig @224.0.0.251 -p 5353 +short -t a +notcp "$1" 2>/dev/null | sed '/^;;/d')) else - fatal "Local hostname given but no 'avahi-resolve' or 'dig' avaliable." + fatal "Local hostname given but no 'avahi-resolve' or 'dig' avaliable." -3 fi fi if [[ -z "$ip4" ]]; then @@ -7149,7 +7166,7 @@ get_aaaa_record() { elif which dig &>/dev/null; then ip6=$(filter_ip6_address $(dig @ff02::fb -p 5353 -t aaaa +short +notcp "$NODE")) else - fatal "Local hostname given but no 'avahi-resolve' or 'dig' avaliable." + fatal "Local hostname given but no 'avahi-resolve' or 'dig' avaliable." -3 fi elif which host &> /dev/null ; then ip6=$(filter_ip6_address $(host -t aaaa "$NODE" | grep -v alias | grep -v "no AAAA record" | sed 's/^.*address //')) @@ -7263,11 +7280,11 @@ get_mx_record() { check_proxy() { if [[ -n "$PROXY" ]]; then if ! $OPENSSL s_client -help 2>&1 | grep -qw proxy; then - fatal "Your $OPENSSL is too old to support the \"--proxy\" option" -1 + fatal "Your $OPENSSL is too old to support the \"--proxy\" option" -5 fi PROXYNODE=${PROXY%:*} PROXYPORT=${PROXY#*:} - is_number "$PROXYPORT" || fatal "Proxy port cannot be determined from \"$PROXY\"" "-3" + is_number "$PROXYPORT" || fatal "Proxy port cannot be determined from \"$PROXY\"" "2" #if is_ipv4addr "$PROXYNODE" || is_ipv6addr "$PROXYNODE" ; then # IPv6 via openssl -proxy: that doesn't work. Sockets does @@ -7277,7 +7294,7 @@ check_proxy() { else check_resolver_bins PROXYIP=$(get_a_record $PROXYNODE 2>/dev/null | grep -v alias | sed 's/^.*address //') - [[ -z "$PROXYIP" ]] && fatal "Proxy IP cannot be determined from \"$PROXYNODE\"" "-3" + [[ -z "$PROXYIP" ]] && fatal "Proxy IP cannot be determined from \"$PROXYNODE\"" "2" fi PROXY="-proxy $PROXYIP:$PROXYPORT" fi @@ -7394,12 +7411,12 @@ determine_service() { ftp|smtp|pop3|imap|xmpp|telnet|ldap) STARTTLS="-starttls $protocol" SNI="" - if [[ $protocol == "xmpp" ]]; then + if [[ "$protocol" == xmpp ]]; then # for XMPP, openssl has a problem using -connect $NODEIP:$PORT. thus we use -connect $NODE:$PORT instead! NODEIP="$NODE" if [[ -n "$XMPP_HOST" ]]; then if ! $OPENSSL s_client --help 2>&1 | grep -q xmpphost; then - fatal "Your $OPENSSL does not support the \"-xmpphost\" option" -3 + fatal "Your $OPENSSL does not support the \"-xmpphost\" option" -5 fi STARTTLS="$STARTTLS -xmpphost $XMPP_HOST" # it's a hack -- instead of changing calls all over the place # see http://xmpp.org/rfcs/rfc3920.html @@ -7418,7 +7435,7 @@ determine_service() { outln ;; *) outln - fatal "momentarily only ftp, smtp, pop3, imap, xmpp, telnet and ldap allowed" -1 + fatal "momentarily only ftp, smtp, pop3, imap, xmpp, telnet and ldap allowed" -4 ;; esac fi @@ -7522,7 +7539,7 @@ run_mass_testing_parallel() { local global_cmdline=${CMDLINE%%--file*} if [[ ! -r "$FNAME" ]] && $IKNOW_FNAME; then - fatal "Can't read file \"$FNAME\"" "-1" + fatal "Can't read file \"$FNAME\"" "2" fi pr_reverse "====== Running in parallel file batch mode with file=\"$FNAME\" ======"; outln outln "(output is in ....\n)" @@ -7548,7 +7565,7 @@ run_mass_testing() { local global_cmdline=${CMDLINE%%--file*} if [[ ! -r "$FNAME" ]] && "$IKNOW_FNAME"; then - fatal "Can't read file \"$FNAME\"" "-1" + fatal "Can't read file \"$FNAME\"" "2" fi pr_reverse "====== Running in file batch mode with file=\"$FNAME\" ======"; outln "\n" @@ -8017,7 +8034,7 @@ reset_hostdepended_vars() { lets_roll() { local ret - [[ -z "$NODEIP" ]] && fatal "$NODE doesn't resolve to an IP address" -1 + [[ -z "$NODEIP" ]] && fatal "$NODE doesn't resolve to an IP address" 2 nodeip_to_proper_ip6 reset_hostdepended_vars determine_rdns @@ -8094,6 +8111,7 @@ maketempf mybanner check_proxy check4openssl_oldfarts +check_bsd_mount # TODO: it is ugly to have those two vars here --> main() ret=0 @@ -8119,7 +8137,7 @@ else parse_hn_port "${URI}" # NODE, URL_PATH, PORT, IPADDR and IP46ADDR is set now prepare_logging if ! determine_ip_addresses && [[ -z "$CMDLINE_IP" ]]; then - fatal "No IP address could be determined" + fatal "No IP address could be determined" 2 fi if [[ -n "$CMDLINE_IP" ]]; then [[ "$CMDLINE_IP" == "one" ]] && \ @@ -8151,4 +8169,4 @@ fi exit $? -# $Id: testssl.sh,v 1.514 2016/07/04 11:59:38 dirkw Exp $ +# $Id: testssl.sh,v 1.515 2016/07/04 21:05:11 dirkw Exp $ From 2bba19360fdef61a314c9528a0cccf1404e4642c Mon Sep 17 00:00:00 2001 From: Dirk Date: Mon, 4 Jul 2016 23:52:52 +0200 Subject: [PATCH 08/27] see #401, part 2 --- testssl.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/testssl.sh b/testssl.sh index b6a4dcd..3a18b87 100755 --- a/testssl.sh +++ b/testssl.sh @@ -4071,7 +4071,7 @@ certificate_info() { fi else cn="no CN field in subject" - pr_warning "($cn)" + outln "($cn)" cnfinding="$cn" cnok="INFO" fi @@ -4378,7 +4378,7 @@ run_server_defaults() { fi i=$((i + 1)) done - if ! $match_found && [[ $n -ge 8 ]] && [[ $certs_found -ne 0 ]]; then + if ! "$match_found" && [[ $n -ge 8 ]] && [[ $certs_found -ne 0 ]]; then # A new certificate was found using TLSv1.1 without SNI. # Check to see if the new certificate should be displayed. # It should be displayed if it is either a match for the @@ -4416,7 +4416,7 @@ run_server_defaults() { # that the new certificate will not be included in the output. [[ ${success[n]} -ne 0 ]] && match_found=true fi - if ! $match_found ; then + if ! "$match_found"; then certs_found=$(($certs_found + 1)) cipher[certs_found]=${ciphers_to_test[n]} keysize[certs_found]=$(grep -aw "^Server public key is" $TMPFILE | sed -e 's/^Server public key is //' -e 's/bit//' -e 's/ //') @@ -8270,4 +8270,4 @@ fi exit $? -# $Id: testssl.sh,v 1.515 2016/07/04 21:05:11 dirkw Exp $ +# $Id: testssl.sh,v 1.517 2016/07/04 21:52:51 dirkw Exp $ From d2f2dab7fb0a524904126303b12fe81b61485871 Mon Sep 17 00:00:00 2001 From: Dirk Date: Tue, 5 Jul 2016 00:02:34 +0200 Subject: [PATCH 09/27] fix regression lf in CN --- testssl.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testssl.sh b/testssl.sh index 3a18b87..4faf965 100755 --- a/testssl.sh +++ b/testssl.sh @@ -4071,7 +4071,7 @@ certificate_info() { fi else cn="no CN field in subject" - outln "($cn)" + out "($cn)" cnfinding="$cn" cnok="INFO" fi @@ -8270,4 +8270,4 @@ fi exit $? -# $Id: testssl.sh,v 1.517 2016/07/04 21:52:51 dirkw Exp $ +# $Id: testssl.sh,v 1.518 2016/07/04 22:02:33 dirkw Exp $ From 0217992553e513b62972e08badd6eb0516b55b87 Mon Sep 17 00:00:00 2001 From: Dirk Date: Tue, 5 Jul 2016 00:08:51 +0200 Subject: [PATCH 10/27] fixed error where an URI in X509v3 Issuer Alternative Name was displayed and an URI in SAN --- testssl.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/testssl.sh b/testssl.sh index 4faf965..e4cc6c9 100755 --- a/testssl.sh +++ b/testssl.sh @@ -3809,7 +3809,7 @@ compare_server_name_to_cert() fi # Check whether any of the DNS names in the certificate match the servername - dns_sans=$($OPENSSL x509 -in $cert -noout -text 2>>$ERRFILE | grep -A3 "Subject Alternative Name" | \ + dns_sans=$($OPENSSL x509 -in $cert -noout -text 2>>$ERRFILE | grep -A2 "Subject Alternative Name" | \ sed -e 's/,/\n/g' | grep "DNS:" | sed -e 's/DNS://g' -e 's/ //g') for san in $dns_sans; do [[ "$san" == "$servername" ]] && return 0 @@ -3821,7 +3821,7 @@ compare_server_name_to_cert() done # Check whether any of the IP addresses in the certificate match the serername - ip_sans=$($OPENSSL x509 -in $cert -noout -text 2>>$ERRFILE | grep -A3 "Subject Alternative Name" | \ + ip_sans=$($OPENSSL x509 -in $cert -noout -text 2>>$ERRFILE | grep -A2 "Subject Alternative Name" | \ sed -e 's/,/\n/g' | grep "IP Address:" | sed -e 's/IP Address://g' -e 's/ //g') for san in $ip_sans; do [[ "$san" == "$servername" ]] && return 0 @@ -4121,7 +4121,7 @@ certificate_info() { fi fileout "${json_prefix}cn" "$cnok" "$cnfinding" - sans=$($OPENSSL x509 -in $HOSTCERT -noout -text 2>>$ERRFILE | grep -A3 "Subject Alternative Name" | \ + sans=$($OPENSSL x509 -in $HOSTCERT -noout -text 2>>$ERRFILE | grep -A2 "Subject Alternative Name" | \ egrep "DNS:|IP Address:|email:|URI:|DirName:|Registered ID:" | \ sed -e 's/ *DNS://g' -e 's/ *IP Address://g' -e 's/ *email://g' -e 's/ *URI://g' -e 's/ *DirName://g' \ -e 's/ *Registered ID://g' -e 's/,/\n/g' \ @@ -4389,7 +4389,7 @@ run_server_defaults() { if [[ ${success[n]} -ne 0 ]]; then cn_nosni="$(get_cn_from_cert $HOSTCERT)" - sans_nosni=$($OPENSSL x509 -in $HOSTCERT -noout -text 2>>$ERRFILE | grep -A3 "Subject Alternative Name" | grep "DNS:" | \ + sans_nosni=$($OPENSSL x509 -in $HOSTCERT -noout -text 2>>$ERRFILE | grep -A2 "Subject Alternative Name" | grep "DNS:" | \ sed -e 's/DNS://g' -e 's/ //g' -e 's/,/ /g' -e 's/othername://g') echo "${previous_hostcert[1]}" > $HOSTCERT @@ -4400,7 +4400,7 @@ run_server_defaults() { # match if the CNs are the same and the SANs (if # present) contain at least one DNS name in common. if [[ "$cn_nosni" == "$cn_sni" ]]; then - sans_sni=$($OPENSSL x509 -in $HOSTCERT -noout -text 2>>$ERRFILE | grep -A3 "Subject Alternative Name" | grep "DNS:" | \ + sans_sni=$($OPENSSL x509 -in $HOSTCERT -noout -text 2>>$ERRFILE | grep -A2 "Subject Alternative Name" | grep "DNS:" | \ sed -e 's/DNS://g' -e 's/ //g' -e 's/,/ /g' -e 's/othername://g') if [[ "$sans_nosni" == "$sans_sni" ]]; then success[n]=0 @@ -8270,4 +8270,4 @@ fi exit $? -# $Id: testssl.sh,v 1.518 2016/07/04 22:02:33 dirkw Exp $ +# $Id: testssl.sh,v 1.519 2016/07/04 22:08:50 dirkw Exp $ From ec6c0ce605ba6eed8895f64eea46577f4a9f5beb Mon Sep 17 00:00:00 2001 From: David Cooper Date: Wed, 6 Jul 2016 10:52:54 -0400 Subject: [PATCH 11/27] Check for all CBC ciphers in Poodle test This PR should address issue #399. I created the list of ciphers using the CIPHERS_BY_STRENGTH file from PR #373, making a list of all ciphers that had "CBC" in the RFC name and for which I had been able to find a corresponding OpenSSL name. Then, since that list contained more than 128 ciphers, I removed any ciphers from the list where the name ended in "-SHA256" or "-SHA384", as it is my understanding that those ciphers can only be used with TLS 1.2. --- testssl.sh | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/testssl.sh b/testssl.sh index e4cc6c9..dd87303 100755 --- a/testssl.sh +++ b/testssl.sh @@ -6077,14 +6077,11 @@ run_breach() { # Padding Oracle On Downgraded Legacy Encryption, in a nutshell: don't use CBC Ciphers in SSLv3 run_ssl_poodle() { local -i sclient_success=0 - local cbc_ciphers - local cbc_ciphers="SRP-DSS-AES-256-CBC-SHA:SRP-RSA-AES-256-CBC-SHA:SRP-AES-256-CBC-SHA:RSA-PSK-AES256-CBC-SHA:PSK-AES256-CBC-SHA:SRP-DSS-AES-128-CBC-SHA:SRP-RSA-AES-128-CBC-SHA:SRP-AES-128-CBC-SHA:IDEA-CBC-SHA:IDEA-CBC-MD5:RC2-CBC-MD5:RSA-PSK-AES128-CBC-SHA:PSK-AES128-CBC-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:SRP-DSS-3DES-EDE-CBC-SHA:SRP-RSA-3DES-EDE-CBC-SHA:SRP-3DES-EDE-CBC-SHA:EDH-RSA-DES-CBC3-SHA:EDH-DSS-DES-CBC3-SHA:DH-RSA-DES-CBC3-SHA:DH-DSS-DES-CBC3-SHA:AECDH-DES-CBC3-SHA:ADH-DES-CBC3-SHA:ECDH-RSA-DES-CBC3-SHA:ECDH-ECDSA-DES-CBC3-SHA:DES-CBC3-SHA:DES-CBC3-MD5:RSA-PSK-3DES-EDE-CBC-SHA:PSK-3DES-EDE-CBC-SHA:EXP1024-DHE-DSS-DES-CBC-SHA:EDH-RSA-DES-CBC-SHA:EDH-DSS-DES-CBC-SHA:DH-RSA-DES-CBC-SHA:DH-DSS-DES-CBC-SHA:ADH-DES-CBC-SHA:EXP1024-DES-CBC-SHA:DES-CBC-SHA:EXP1024-RC2-CBC-MD5:DES-CBC-MD5:EXP-EDH-RSA-DES-CBC-SHA:EXP-EDH-DSS-DES-CBC-SHA:EXP-ADH-DES-CBC-SHA:EXP-DES-CBC-SHA:EXP-RC2-CBC-MD5:EXP-RC2-CBC-MD5" - local cbc_ciphers_krb="KRB5-IDEA-CBC-SHA:KRB5-IDEA-CBC-MD5:KRB5-DES-CBC3-SHA:KRB5-DES-CBC3-MD5:KRB5-DES-CBC-SHA:KRB5-DES-CBC-MD5:EXP-KRB5-RC2-CBC-SHA:EXP-KRB5-DES-CBC-SHA:EXP-KRB5-RC2-CBC-MD5:EXP-KRB5-DES-CBC-MD5" + local cbc_ciphers="ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:SRP-DSS-AES-256-CBC-SHA:SRP-RSA-AES-256-CBC-SHA:SRP-AES-256-CBC-SHA:DHE-PSK-AES256-CBC-SHA:DHE-RSA-AES256-SHA:DHE-DSS-AES256-SHA:DH-RSA-AES256-SHA:DH-DSS-AES256-SHA:DHE-RSA-CAMELLIA256-SHA:DHE-DSS-CAMELLIA256-SHA:DH-RSA-CAMELLIA256-SHA:DH-DSS-CAMELLIA256-SHA:AECDH-AES256-SHA:ADH-AES256-SHA:ADH-CAMELLIA256-SHA:ECDH-RSA-AES256-SHA:ECDH-ECDSA-AES256-SHA:AES256-SHA:ECDHE-PSK-AES256-CBC-SHA:CAMELLIA256-SHA:RSA-PSK-AES256-CBC-SHA:PSK-AES256-CBC-SHA:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:SRP-DSS-AES-128-CBC-SHA:SRP-RSA-AES-128-CBC-SHA:SRP-AES-128-CBC-SHA:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA:DH-RSA-AES128-SHA:DH-DSS-AES128-SHA:DHE-RSA-SEED-SHA:DHE-DSS-SEED-SHA:DH-RSA-SEED-SHA:DH-DSS-SEED-SHA:DHE-RSA-CAMELLIA128-SHA:DHE-DSS-CAMELLIA128-SHA:DH-RSA-CAMELLIA128-SHA:DH-DSS-CAMELLIA128-SHA:AECDH-AES128-SHA:ADH-AES128-SHA:ADH-SEED-SHA:ADH-CAMELLIA128-SHA:ECDH-RSA-AES128-SHA:ECDH-ECDSA-AES128-SHA:AES128-SHA:ECDHE-PSK-AES128-CBC-SHA:DHE-PSK-AES128-CBC-SHA:SEED-SHA:CAMELLIA128-SHA:IDEA-CBC-SHA:IDEA-CBC-MD5:RC2-CBC-MD5:RSA-PSK-AES128-CBC-SHA:PSK-AES128-CBC-SHA:KRB5-IDEA-CBC-SHA:KRB5-IDEA-CBC-MD5:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:SRP-DSS-3DES-EDE-CBC-SHA:SRP-RSA-3DES-EDE-CBC-SHA:SRP-3DES-EDE-CBC-SHA:EDH-RSA-DES-CBC3-SHA:EDH-DSS-DES-CBC3-SHA:DH-RSA-DES-CBC3-SHA:DH-DSS-DES-CBC3-SHA:AECDH-DES-CBC3-SHA:ADH-DES-CBC3-SHA:ECDH-RSA-DES-CBC3-SHA:ECDH-ECDSA-DES-CBC3-SHA:DES-CBC3-SHA:DES-CBC3-MD5:RSA-PSK-3DES-EDE-CBC-SHA:PSK-3DES-EDE-CBC-SHA:KRB5-DES-CBC3-SHA:KRB5-DES-CBC3-MD5:ECDHE-PSK-3DES-EDE-CBC-SHA:DHE-PSK-3DES-EDE-CBC-SHA:EXP1024-DHE-DSS-DES-CBC-SHA:EDH-RSA-DES-CBC-SHA:EDH-DSS-DES-CBC-SHA:DH-RSA-DES-CBC-SHA:DH-DSS-DES-CBC-SHA:ADH-DES-CBC-SHA:EXP1024-DES-CBC-SHA:DES-CBC-SHA:DES-CBC-MD5:KRB5-DES-CBC-SHA:KRB5-DES-CBC-MD5:EXP-EDH-RSA-DES-CBC-SHA:EXP-EDH-DSS-DES-CBC-SHA:EXP-ADH-DES-CBC-SHA:EXP-DES-CBC-SHA:EXP-RC2-CBC-MD5:EXP-RC2-CBC-MD5:EXP-KRB5-RC2-CBC-SHA:EXP-KRB5-DES-CBC-SHA:EXP-KRB5-RC2-CBC-MD5:EXP-KRB5-DES-CBC-MD5" [[ $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) " - #nr_supported_ciphers=$(count_ciphers $(actually_supported_ciphers $cbc_ciphers:cbc_ciphers_krb)) - cbc_ciphers=$($OPENSSL ciphers -v 'ALL:eNULL' 2>$ERRFILE | awk '/CBC/ { print $1 }' | tr '\n' ':') + 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 Date: Wed, 6 Jul 2016 14:23:32 -0400 Subject: [PATCH 12/27] Fix grammar issue in help output for --openssl Missing a closing parentheses `)`. --- testssl.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testssl.sh b/testssl.sh index e4cc6c9..b42a56f 100755 --- a/testssl.sh +++ b/testssl.sh @@ -6817,7 +6817,7 @@ tuning options (can also be preset via environment variables): --bugs enables the "-bugs" option of s_client, needed e.g. for some buggy F5s --assuming-http if protocol check fails it assumes HTTP protocol and enforces HTTP checks --ssl-native fallback to checks with OpenSSL where sockets are normally used - --openssl use this openssl binary (default: look in \$PATH, \$RUN_DIR of $PROG_NAME + --openssl use this openssl binary (default: look in \$PATH, \$RUN_DIR of $PROG_NAME) --proxy : connect via the specified HTTP proxy -6 use also IPv6. Works only with supporting OpenSSL version and IPv6 connectivity --sneaky leave less traces in target logs: user agent, referer From 9c92a866e09893d3af897403fac7f15902238f71 Mon Sep 17 00:00:00 2001 From: Dirk Wetter Date: Fri, 8 Jul 2016 08:04:58 +0200 Subject: [PATCH 13/27] Update Readme.md --- Readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Readme.md b/Readme.md index 3b16045..ed1eee6 100644 --- a/Readme.md +++ b/Readme.md @@ -11,7 +11,7 @@ cryptographic flaws. #### Key features * Clear output: you can tell easily whether anything is good or bad -* Ease of installation: It works for Linux, Darwin, FreeBSD and +* Ease of installation: It works for Linux, Darwin, FreeBSD, NetBSD and MSYS2/Cygwin out of the box: no need to install or configure something, no gems, CPAN, pip or the like. * Flexibility: You can test any SSL/TLS enabled and STARTTLS service, not @@ -64,7 +64,7 @@ Done so far: * Check for multiple server certificates * Browser cipher simulation * Assistance for color-blind users -* Even more compatibility improvements for FreeBSD, RH-ish, F5 and Cisco systems +* Even more compatibility improvements for FreeBSD, NetBSD, Gentoo, RH-ish, F5 and Cisco systems * Considerable speed improvements for each cipher runs (-e/-E) * More robust socket interface * OpenSSL 1.1.0 compliant From 8c113340306b2ba46a639d5aebeb8316eb80e3e6 Mon Sep 17 00:00:00 2001 From: Dirk Date: Fri, 8 Jul 2016 11:15:41 +0200 Subject: [PATCH 14/27] FIX #405 --- testssl.sh | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/testssl.sh b/testssl.sh index 6e03e77..3491c69 100755 --- a/testssl.sh +++ b/testssl.sh @@ -145,11 +145,13 @@ QUIET=${QUIET:-false} # don't output the banner. By doing this SSL_NATIVE=${SSL_NATIVE:-false} # we do per default bash sockets where possible "true": switch back to "openssl native" ASSUMING_HTTP=${ASSUMING_HTTP:-false} # in seldom cases (WAF, old servers, grumpy SSL) service detection fails. "True" enforces HTTP checks BUGS=${BUGS:-""} # -bugs option from openssl, needed for some BIG IP F5 -DEBUG=${DEBUG:-0} # 1.: the temp files won't be erased. - # 2: list more what's going on (formerly: eq VERBOSE=1, VERBERR=true), lists some errors of connections +DEBUG=${DEBUG:-0} # 1: normal putput the files in /tmp/ are kept for further debugging purposes + # 2: list more what's going on , also lists some errors of connections # 3: slight hexdumps + other info, - # 4: display bytes sent via sockets, 5: display bytes received via sockets, 6: whole 9 yards -WIDE=${WIDE:-false} # whether to display for some options the cipher or the table with hexcode/KX,Enc,strength etc. + # 4: display bytes sent via sockets + # 5: display bytes received via sockets + # 6: whole 9 yards +WIDE=${WIDE:-false} # whether to display for some options just ciphers or a table w hexcode/KX,Enc,strength etc. LOGFILE=${LOGFILE:-""} # logfile if used JSONFILE=${JSONFILE:-""} # jsonfile if used CSVFILE=${CSVFILE:-""} # csvfile if used @@ -6827,7 +6829,7 @@ output options (can also be preset via environment variables): --mapping don't display the RFC Cipher Suite Name --color <0|1|2> 0: no escape or other codes, 1: b/w escape codes, 2: color (default) --colorblind swap green and blue in the output - --debug <0-6> 1: screen output normal but debug output in temp files. 2-6: see line ~120 + --debug <0-6> 1: screen output normal but keeps debug output in /tmp/. 2-6: see "grep -A 5 '^DEBUG=' testssl.sh" file output options (can also be preset via environment variables): --log, --logging logs stdout to in current working directory @@ -8267,4 +8269,4 @@ fi exit $? -# $Id: testssl.sh,v 1.519 2016/07/04 22:08:50 dirkw Exp $ +# $Id: testssl.sh,v 1.521 2016/07/08 09:15:40 dirkw Exp $ From af4117aa7ae0aba04b3fb901ee60afc98fd690f2 Mon Sep 17 00:00:00 2001 From: Dirk Date: Fri, 8 Jul 2016 11:25:41 +0200 Subject: [PATCH 15/27] FIX #404 --- testssl.sh | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/testssl.sh b/testssl.sh index 3491c69..c2dd02c 100755 --- a/testssl.sh +++ b/testssl.sh @@ -132,8 +132,7 @@ fi TERM_CURRPOS=0 # custom line wrapping needs alter the current horizontal cursor pos # following variables make use of $ENV, e.g. OPENSSL= ./testssl.sh -# 0 means (normally) true here. Some of the variables are also accessible with a command line switch -# most of them can be set also by a cmd line switch +# 0 means (normally) true here. Some of the variables are also accessible with a command line switch, see --help declare -x OPENSSL COLOR=${COLOR:-2} # 2: Full color, 1: b/w+positioning, 0: no ESC at all @@ -8269,4 +8268,4 @@ fi exit $? -# $Id: testssl.sh,v 1.521 2016/07/08 09:15:40 dirkw Exp $ +# $Id: testssl.sh,v 1.522 2016/07/08 09:25:39 dirkw Exp $ From eb58598ca55d1123aa915e18765df9724646b564 Mon Sep 17 00:00:00 2001 From: Dirk Date: Fri, 8 Jul 2016 11:40:17 +0200 Subject: [PATCH 16/27] make it public, see #122 --- utils/curves.bash | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100755 utils/curves.bash diff --git a/utils/curves.bash b/utils/curves.bash new file mode 100755 index 0000000..6d62ad4 --- /dev/null +++ b/utils/curves.bash @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +# +# PoC for checking the ellipticale curves negotiated +# x448 and x25519 are missing, others are not supported +# License see testssl.sh + + +HN="$1" +[ -z "$HN" ] && HN=testssl.sh +for curve in $(bin/openssl.Linux.x86_64 ecparam -list_curves | awk -F':' '/:/ { print $1 }'); do + printf "$curve: " + #if bin/openssl.Linux.x86_64 s_client -curves $curve -connect $HN:443 -servername $HN /dev/null | grep -q "BEGIN CERTIFICATE" ; then + # echo 'YES' + #else + # echo '--' + #fi + if bin/openssl.Linux.x86_64 s_client -cipher ECDH -curves $curve -connect $HN:443 -servername $HN /dev/null | grep "Server Temp Key:" ; then + : + else + echo '--' + fi +done + +# vim:ts=5:sw=5:expandtab +# $Id: curves.bash,v 1.2 2016/07/08 09:39:27 dirkw Exp $ + From 018468a67013768407c80d7651c1790bdd8ab708 Mon Sep 17 00:00:00 2001 From: Dirk Wetter Date: Sat, 9 Jul 2016 14:24:38 +0200 Subject: [PATCH 17/27] more user friendly... --- utils/curves.bash | 82 +++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 75 insertions(+), 7 deletions(-) diff --git a/utils/curves.bash b/utils/curves.bash index 6d62ad4..4168c02 100755 --- a/utils/curves.bash +++ b/utils/curves.bash @@ -4,23 +4,91 @@ # x448 and x25519 are missing, others are not supported # License see testssl.sh +readonly RUN_DIR=$(dirname "$0") + +test_openssl_suffix() { + local naming_ext="$(uname).$(uname -m)" + local uname_arch="$(uname -m)" + local myarch_suffix="" + + [[ $uname_arch =~ 64 ]] && myarch_suffix=64 || myarch_suffix=32 + if [[ -f "$1/openssl" ]] && [[ -x "$1/openssl" ]]; then + OPENSSL="$1/openssl" + return 0 + elif [[ -f "$1/openssl.$naming_ext" ]] && [[ -x "$1/openssl.$naming_ext" ]]; then + OPENSSL="$1/openssl.$naming_ext" + return 0 + fi + return 1 +} + + +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 ..." + elif [[ -x "$OPENSSL" ]]; then + : # 1. all ok supplied $OPENSSL was found and has excutable bit set -- testrun comes below + elif test_openssl_suffix $RUN_DIR; then + : # 2. otherwise try openssl in path of testssl.sh + elif test_openssl_suffix ../$RUN_DIR; then + : # 2. otherwise try openssl in path of testssl.sh + elif test_openssl_suffix ../$RUN_DIR/bin; then + : # 3. otherwise here, this is supposed to be the standard --platform independed path in the future!!! + elif test_openssl_suffix "$(dirname "$(which openssl)")"; then + : # 5. we tried hard and failed, so now we use the system binaries + fi + + # no ERRFILE initialized yet, thus we use /dev/null for stderr directly + $OPENSSL version -a 2>/dev/null >/dev/null + if [[ $? -ne 0 ]] || [[ ! -x "$OPENSSL" ]]; then + echo "\ncannot exec or find any openssl binary" + exit 1 + fi + echo + echo "using $OPENSSL" + echo +} + + +VERBOSE=false +if [[ $1 == "-v" ]]; then + VERBOSE=true + shift +fi HN="$1" [ -z "$HN" ] && HN=testssl.sh -for curve in $(bin/openssl.Linux.x86_64 ecparam -list_curves | awk -F':' '/:/ { print $1 }'); do - printf "$curve: " +find_openssl_binary + +ERRFILE=$(mktemp /tmp/curve_tester.R.XXXXXX) || exit -6 +TMPFILE=$(mktemp /tmp/curve_tester.T.XXXXXX) || exit -6 + + +for curve in $($OPENSSL ecparam -list_curves | awk -F':' '/:/ { print $1 }'); do #if bin/openssl.Linux.x86_64 s_client -curves $curve -connect $HN:443 -servername $HN /dev/null | grep -q "BEGIN CERTIFICATE" ; then # echo 'YES' #else # echo '--' #fi - if bin/openssl.Linux.x86_64 s_client -cipher ECDH -curves $curve -connect $HN:443 -servername $HN /dev/null | grep "Server Temp Key:" ; then - : + $OPENSSL s_client -cipher ECDH -curves $curve -connect $HN:443 -servername $HN $ERRFILE | grep "Server Temp Key:" >$TMPFILE + if [[ $? -eq 0 ]]; then + printf "$curve: " + cat $TMPFILE | sed 's/^.*Server Temp Key: //' else - echo '--' + if grep -q 'Error with' $ERRFILE; then + if "$VERBOSE"; then + echo "$curve: no client support" + fi + else + echo "$curve: --" + fi fi done -# vim:ts=5:sw=5:expandtab -# $Id: curves.bash,v 1.2 2016/07/08 09:39:27 dirkw Exp $ +rm -f $ERRFILE $TMPFILE + +# vim:ts=5:sw=5:expandtab +# $Id: curves.bash,v 1.3 2016/07/09 12:22:13 dirkw Exp $ From 3c3939639189e5c86a739db98d506d4a48fc86b9 Mon Sep 17 00:00:00 2001 From: Will Elwood Date: Mon, 11 Jul 2016 13:35:55 +0100 Subject: [PATCH 18/27] Unreadable SAN list on FreeBSD On FreeBSD, sed does not support "\n" in the replacement string of a substitution. The SANs are currently output all together inside a single pair of quotes and each separated with an "n" character, needless to say this is very difficult to read. After a little digging, it seems this is a somewhat recent regression of the fix in #173. I believe `tr` would be a more cross-platform way to do this, and several sources (including the author of that PR) would seem to agree - assuming the newline is now necessary. It doesn't appear to matter what order the newline replacement happens amongst all the other replacements, so I have placed it first simply to avoid extending any already-long lines. Please correct me if this deduction is false. --- testssl.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testssl.sh b/testssl.sh index c2dd02c..085967a 100755 --- a/testssl.sh +++ b/testssl.sh @@ -4123,9 +4123,9 @@ certificate_info() { fileout "${json_prefix}cn" "$cnok" "$cnfinding" sans=$($OPENSSL x509 -in $HOSTCERT -noout -text 2>>$ERRFILE | grep -A2 "Subject Alternative Name" | \ - egrep "DNS:|IP Address:|email:|URI:|DirName:|Registered ID:" | \ + egrep "DNS:|IP Address:|email:|URI:|DirName:|Registered ID:" | tr ',' '\n' | \ sed -e 's/ *DNS://g' -e 's/ *IP Address://g' -e 's/ *email://g' -e 's/ *URI://g' -e 's/ *DirName://g' \ - -e 's/ *Registered ID://g' -e 's/,/\n/g' \ + -e 's/ *Registered ID://g' \ -e 's/ *othername://g' -e 's/ *X400Name://g' -e 's/ *EdiPartyName://g') # ^^^ CACert out "$indent"; pr_bold " subjectAltName (SAN) " From 382d22648aa36aeb2f2c6191fc7807432aebafc5 Mon Sep 17 00:00:00 2001 From: Will Elwood Date: Mon, 11 Jul 2016 14:15:50 +0100 Subject: [PATCH 19/27] Server cipher order NPN tests should use SNI I noticed the NPN parts of this test were not returning any ECDSA ciphers where I expected them to match the results of the immediately preceding TLS 1.2 test. Found it wasn't using SNI so my test server was using the default domain (snakeoil RSA certificate) instead of the tested domain (dual ECDSA/RSA certificates). --- testssl.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/testssl.sh b/testssl.sh index c2dd02c..90a5ad0 100755 --- a/testssl.sh +++ b/testssl.sh @@ -3499,16 +3499,16 @@ cipher_pref_check() { if ! spdy_pre " SPDY/NPN: "; then # is NPN/SPDY supported and is this no STARTTLS? outln else - npn_protos=$($OPENSSL s_client -host $NODE -port $PORT $BUGS -nextprotoneg \"\" >$ERRFILE | grep -a "^Protocols " | sed -e 's/^Protocols.*server: //' -e 's/,//g') + npn_protos=$($OPENSSL s_client $BUGS -nextprotoneg \"\" -connect $NODEIP:$PORT $PROXY $SNI >$ERRFILE | grep -a "^Protocols " | sed -e 's/^Protocols.*server: //' -e 's/,//g') for p in $npn_protos; do order="" - $OPENSSL s_client -host $NODE -port $PORT $BUGS -nextprotoneg "$p" $PROXY >$ERRFILE >$TMPFILE + $OPENSSL s_client $BUGS -nextprotoneg "$p" -connect $NODEIP:$PORT $PROXY $SNI >$ERRFILE >$TMPFILE cipher=$(awk '/Cipher.*:/ { print $3 }' $TMPFILE) printf " %-10s %s " "$p:" "$cipher" tested_cipher="-"$cipher order="$cipher" while true; do - $OPENSSL s_client -cipher "ALL:$tested_cipher" -host $NODE -port $PORT $BUGS -nextprotoneg "$p" $PROXY >$ERRFILE >$TMPFILE + $OPENSSL s_client -cipher "ALL:$tested_cipher" $BUGS -nextprotoneg "$p" -connect $NODEIP:$PORT $PROXY $SNI >$ERRFILE >$TMPFILE sclient_connect_successful $? $TMPFILE || break cipher=$(awk '/Cipher.*:/ { print $3 }' $TMPFILE) out "$cipher " From 2573a9b8b80caf841e676f3c61605c54cdc1ff6d Mon Sep 17 00:00:00 2001 From: Will Elwood Date: Mon, 11 Jul 2016 14:37:20 +0100 Subject: [PATCH 20/27] More SNI for NPN tests Found another NPN test (for the case where server doesn't specify cipher order?) that wasn't using SNI. Also found a comment saying proxies don't support NPN => removed `$PROXY` from all modified lines. --- testssl.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/testssl.sh b/testssl.sh index 90a5ad0..a54044d 100755 --- a/testssl.sh +++ b/testssl.sh @@ -3324,7 +3324,7 @@ run_server_preference() { [[ -n "$PROXY" ]] && arg=" SPDY/NPN is" [[ -n "$STARTTLS" ]] && arg=" " if spdy_pre " $arg" ; then # is NPN/SPDY supported and is this no STARTTLS? / no PROXY - $OPENSSL s_client -connect $NODEIP:$PORT $BUGS -nextprotoneg "$NPN_PROTOs" >$ERRFILE >$TMPFILE + $OPENSSL s_client -connect $NODEIP:$PORT $BUGS -nextprotoneg "$NPN_PROTOs" $SNI >$ERRFILE >$TMPFILE if sclient_connect_successful $? $TMPFILE; then proto[i]=$(grep -aw "Next protocol" $TMPFILE | sed -e 's/^Next protocol://' -e 's/(.)//' -e 's/ //g') if [[ -z "${proto[i]}" ]]; then @@ -3499,16 +3499,16 @@ cipher_pref_check() { if ! spdy_pre " SPDY/NPN: "; then # is NPN/SPDY supported and is this no STARTTLS? outln else - npn_protos=$($OPENSSL s_client $BUGS -nextprotoneg \"\" -connect $NODEIP:$PORT $PROXY $SNI >$ERRFILE | grep -a "^Protocols " | sed -e 's/^Protocols.*server: //' -e 's/,//g') + npn_protos=$($OPENSSL s_client $BUGS -nextprotoneg \"\" -connect $NODEIP:$PORT $SNI >$ERRFILE | grep -a "^Protocols " | sed -e 's/^Protocols.*server: //' -e 's/,//g') for p in $npn_protos; do order="" - $OPENSSL s_client $BUGS -nextprotoneg "$p" -connect $NODEIP:$PORT $PROXY $SNI >$ERRFILE >$TMPFILE + $OPENSSL s_client $BUGS -nextprotoneg "$p" -connect $NODEIP:$PORT $SNI >$ERRFILE >$TMPFILE cipher=$(awk '/Cipher.*:/ { print $3 }' $TMPFILE) printf " %-10s %s " "$p:" "$cipher" tested_cipher="-"$cipher order="$cipher" while true; do - $OPENSSL s_client -cipher "ALL:$tested_cipher" $BUGS -nextprotoneg "$p" -connect $NODEIP:$PORT $PROXY $SNI >$ERRFILE >$TMPFILE + $OPENSSL s_client -cipher "ALL:$tested_cipher" $BUGS -nextprotoneg "$p" -connect $NODEIP:$PORT $SNI >$ERRFILE >$TMPFILE sclient_connect_successful $? $TMPFILE || break cipher=$(awk '/Cipher.*:/ { print $3 }' $TMPFILE) out "$cipher " From 3e8d5208dc486846d01a51e551b9f7f13f0246b3 Mon Sep 17 00:00:00 2001 From: Dirk Date: Mon, 11 Jul 2016 16:20:36 +0200 Subject: [PATCH 21/27] further fix, see #410 --- testssl.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/testssl.sh b/testssl.sh index 085967a..1f3f079 100755 --- a/testssl.sh +++ b/testssl.sh @@ -3811,7 +3811,7 @@ compare_server_name_to_cert() # Check whether any of the DNS names in the certificate match the servername dns_sans=$($OPENSSL x509 -in $cert -noout -text 2>>$ERRFILE | grep -A2 "Subject Alternative Name" | \ - sed -e 's/,/\n/g' | grep "DNS:" | sed -e 's/DNS://g' -e 's/ //g') + tr '.' '\n' grep "DNS:" | sed -e 's/DNS://g' -e 's/ //g') for san in $dns_sans; do [[ "$san" == "$servername" ]] && return 0 # If $san is a wildcard name, then do a wildcard match @@ -3823,7 +3823,7 @@ compare_server_name_to_cert() # Check whether any of the IP addresses in the certificate match the serername ip_sans=$($OPENSSL x509 -in $cert -noout -text 2>>$ERRFILE | grep -A2 "Subject Alternative Name" | \ - sed -e 's/,/\n/g' | grep "IP Address:" | sed -e 's/IP Address://g' -e 's/ //g') + tr ',' '\n' | grep "IP Address:" | sed -e 's/IP Address://g' -e 's/ //g') for san in $ip_sans; do [[ "$san" == "$servername" ]] && return 0 done @@ -8268,4 +8268,4 @@ fi exit $? -# $Id: testssl.sh,v 1.522 2016/07/08 09:25:39 dirkw Exp $ +# $Id: testssl.sh,v 1.523 2016/07/11 14:20:35 dirkw Exp $ From fb94221ce0f9779a85ce66b925c87ef648d9d64e Mon Sep 17 00:00:00 2001 From: David Cooper Date: Mon, 11 Jul 2016 10:52:48 -0400 Subject: [PATCH 22/27] Reorder supported curves Reorder the supported curves sent by socksend_tls_clienthello() from strongest to weakest. --- testssl.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/testssl.sh b/testssl.sh index 76575b0..47fe1cf 100755 --- a/testssl.sh +++ b/testssl.sh @@ -5396,10 +5396,10 @@ socksend_tls_clienthello() { extensions_ecc=" 00, 0a, # Type: Supported Elliptic Curves , see RFC 4492 00, 3e, 00, 3c, # lengths - 00, 01, 00, 02, 00, 03, 00, 04, 00, 05, 00, 06, 00, 07, 00, 08, - 00, 09, 00, 0a, 00, 0b, 00, 0c, 00, 0d, 00, 0e, 00, 0f, 00, 10, - 00, 11, 00, 12, 00, 13, 00, 14, 00, 15, 00, 16, 00, 17, 00, 18, - 00, 19, 00, 1a, 00, 1b, 00, 1c, 00, 1d, 00, 1e, + 00, 0e, 00, 0d, 00, 19, 00, 1c, 00, 1e, 00, 0b, 00, 0c, 00, 1b, + 00, 18, 00, 09, 00, 0a, 00, 1a, 00, 16, 00, 17, 00, 1d, 00, 08, + 00, 06, 00, 07, 00, 14, 00, 15, 00, 04, 00, 05, 00, 12, 00, 13, + 00, 01, 00, 02, 00, 03, 00, 0f, 00, 10, 00, 11, 00, 0b, # Type: Supported Point Formats , see RFC 4492 00, 02, # len 01, 00" From 891c56f8bf328b3934264c1ab4c4a91b5cbdb9b6 Mon Sep 17 00:00:00 2001 From: David Cooper Date: Mon, 11 Jul 2016 11:00:56 -0400 Subject: [PATCH 23/27] Determine support elliptic curves for ECDHE- ciphers This PR extends run_pfs() to display the set of elliptic curves supported by the server, if the server supports any ECDHE- ciphers. --- testssl.sh | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/testssl.sh b/testssl.sh index 76575b0..2507488 100755 --- a/testssl.sh +++ b/testssl.sh @@ -4489,13 +4489,15 @@ run_server_defaults() { run_pfs() { local -i sclient_success - local pfs_offered=false + local pfs_offered=false ecdhe_offered=false local tmpfile local dhlen - local hexcode dash pfs_cipher sslvers kx auth enc mac + local hexcode dash pfs_cipher sslvers kx auth enc mac curve local pfs_cipher_list="$ROBUST_PFS_CIPHERS" + local ecdhe_cipher_list="" + local -a curves=("sect163k1" "sect163r1" "sect163r2" "sect193r1" "sect193r2" "sect233k1" "sect233r1" "sect239k1" "sect283k1" "sect283r1" "sect409k1" "sect409r1" "sect571k1" "sect571r1" "secp160k1" "secp160r1" "secp160r2" "secp192k1" "prime192v1" "secp224k1" "secp224r1" "secp256k1" "prime256v1" "secp384r1" "secp521r1" "brainpoolP256r1" "brainpoolP384r1" "brainpoolP512r1" "X25519" "X448") local -i nr_supported_ciphers=0 - local pfs_ciphers + local pfs_ciphers curves_offered outln pr_headlineln " Testing robust (perfect) forward secrecy, (P)FS -- omitting Null Authentication/Encryption as well as 3DES and RC4 here " @@ -4539,6 +4541,7 @@ run_pfs() { if [[ "$sclient_success" -ne 0 ]] && ! "$SHOW_EACH_C"; then continue # no successful connect AND not verbose displaying each cipher fi + [[ "$sclient_success" -eq 0 ]] && [[ $pfs_cipher == "ECDHE-"* ]] && ecdhe_offered=true && ecdhe_cipher_list+=":$pfs_cipher" if "$WIDE"; then normalize_ciphercode $hexcode @@ -4575,6 +4578,21 @@ run_pfs() { fileout "pfs_ciphers" "INFO" "(Perfect) Forward Secrecy Ciphers: $pfs_ciphers" fi fi + + if $ecdhe_offered; then + # find out what elliptic curves are supported. + curves_offered="" + for curve in "${curves[@]}"; do + $OPENSSL s_client -cipher "${ecdhe_cipher_list:1}" -curves $curve $STARTTLS $BUGS -connect $NODEIP:$PORT $PROXY $SNI &>$tmpfile Date: Mon, 11 Jul 2016 18:44:28 +0200 Subject: [PATCH 24/27] polishing output for #413 --- testssl.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/testssl.sh b/testssl.sh index 949454f..14f2d02 100755 --- a/testssl.sh +++ b/testssl.sh @@ -4519,13 +4519,13 @@ run_pfs() { sclient_connect_successful $? $TMPFILE if [[ $? -ne 0 ]] || [[ $(grep -ac "BEGIN CERTIFICATE" $TMPFILE) -eq 0 ]]; then outln - pr_svrty_mediumln "No ciphers supporting Forward Secrecy offered" + pr_svrty_mediumln " No ciphers supporting Forward Secrecy offered" fileout "pfs" "MEDIUM" "(Perfect) Forward Secrecy : No ciphers supporting Forward Secrecy offered" else outln pfs_offered=true pfs_ciphers="" - pr_done_good " PFS is offered (OK)" + pr_done_good " PFS is offered (OK) " fileout "pfs" "OK" "(Perfect) Forward Secrecy : PFS is offered (OK)" if "$WIDE"; then outln ", ciphers follow (client/browser support is important here) \n" @@ -4579,7 +4579,7 @@ run_pfs() { fi fi - if $ecdhe_offered; then + if "$ecdhe_offered"; then # find out what elliptic curves are supported. curves_offered="" for curve in "${curves[@]}"; do @@ -4589,8 +4589,8 @@ run_pfs() { [[ "$sclient_success" -eq 0 ]] && curves_offered+="$curve " done if [[ -n "$curves_offered" ]]; then - pr_bold " Elliptic curves offered: "; outln "$curves_offered" - fileout "ecdhe_curves" "INFO" "Elliptic curves offered: $curves_offered" + pr_bold " Elliptic curves offered: "; outln "$curves_offered" + fileout "ecdhe_curves" "INFO" "Elliptic curves offered $curves_offered" fi fi outln @@ -8286,4 +8286,4 @@ fi exit $? -# $Id: testssl.sh,v 1.523 2016/07/11 14:20:35 dirkw Exp $ +# $Id: testssl.sh,v 1.524 2016/07/11 16:44:27 dirkw Exp $ From bda62ec715c3e9245df2d2dea0c56efa355b3214 Mon Sep 17 00:00:00 2001 From: Dirk Date: Mon, 11 Jul 2016 19:41:32 +0200 Subject: [PATCH 25/27] no glasses needed, just need to look at the right spot ;- --- testssl.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testssl.sh b/testssl.sh index 14f2d02..ea85fae 100755 --- a/testssl.sh +++ b/testssl.sh @@ -3811,7 +3811,7 @@ compare_server_name_to_cert() # Check whether any of the DNS names in the certificate match the servername dns_sans=$($OPENSSL x509 -in $cert -noout -text 2>>$ERRFILE | grep -A2 "Subject Alternative Name" | \ - tr '.' '\n' grep "DNS:" | sed -e 's/DNS://g' -e 's/ //g') + tr ',' '\n' | grep "DNS:" | sed -e 's/DNS://g' -e 's/ //g') for san in $dns_sans; do [[ "$san" == "$servername" ]] && return 0 # If $san is a wildcard name, then do a wildcard match @@ -8286,4 +8286,4 @@ fi exit $? -# $Id: testssl.sh,v 1.524 2016/07/11 16:44:27 dirkw Exp $ +# $Id: testssl.sh,v 1.525 2016/07/11 17:41:32 dirkw Exp $ From a06ac81df3494ec97da7310d3a9f0dafcd7dc7a7 Mon Sep 17 00:00:00 2001 From: David Cooper Date: Thu, 14 Jul 2016 13:23:50 -0400 Subject: [PATCH 26/27] Speed up finding supported curves Rather than try each curve one at a time, follow model in `cipher_pref_check()`. First include all curves in ClientHello, then successively remove from the ClientHello those curves that have been offered by the server until the connection fails. This makes the number of calls to `$OPENSSL s_client` one more than the number of supported curves rather than the number of curves in NamedCurve supported by $OPENSSL. Note, however, that OpenSSL defines MAX_CURVELIST as 28 and fails if the `-curves` option includes more than 28 curves. Since OpenSSL 1.1.0 offers 29 curves from NamedCurve, this PR breaks the list of supported curves in 2. At the cost of one additional calls to `$OPENSSL s_client` it ensures that the number of curves provides to the `-curves` option is below the limit. --- testssl.sh | 66 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 55 insertions(+), 11 deletions(-) diff --git a/testssl.sh b/testssl.sh index ea85fae..622185a 100755 --- a/testssl.sh +++ b/testssl.sh @@ -4495,9 +4495,12 @@ run_pfs() { local hexcode dash pfs_cipher sslvers kx auth enc mac curve local pfs_cipher_list="$ROBUST_PFS_CIPHERS" local ecdhe_cipher_list="" - local -a curves=("sect163k1" "sect163r1" "sect163r2" "sect193r1" "sect193r2" "sect233k1" "sect233r1" "sect239k1" "sect283k1" "sect283r1" "sect409k1" "sect409r1" "sect571k1" "sect571r1" "secp160k1" "secp160r1" "secp160r2" "secp192k1" "prime192v1" "secp224k1" "secp224r1" "secp256k1" "prime256v1" "secp384r1" "secp521r1" "brainpoolP256r1" "brainpoolP384r1" "brainpoolP512r1" "X25519" "X448") - local -i nr_supported_ciphers=0 - local pfs_ciphers curves_offered + local -a curves_ossl=("sect163k1" "sect163r1" "sect163r2" "sect193r1" "sect193r2" "sect233k1" "sect233r1" "sect239k1" "sect283k1" "sect283r1" "sect409k1" "sect409r1" "sect571k1" "sect571r1" "secp160k1" "secp160r1" "secp160r2" "secp192k1" "prime192v1" "secp224k1" "secp224r1" "secp256k1" "prime256v1" "secp384r1" "secp521r1" "brainpoolP256r1" "brainpoolP384r1" "brainpoolP512r1" "X25519" "X448") + local -a curves_ossl_output=("K-163" "sect163r1" "B-163" "sect193r1" "sect193r2" "K-233" "B-233" "sect239k1" "K-283" "B-283" "K-409" "B-409" "K-571" "B-571" "secp160k1" "secp160r1" "secp160r2" "secp192k1" "P-192" "secp224k1" "P-224" "secp256k1" "P-256" "P-384" "P-521" "brainpoolP256r1" "brainpoolP384r1" "brainpoolP512r1" "X25519" "X448") + local -a supported_curves=() + local -i nr_supported_ciphers=0 nr_curves=0 i j low high + local pfs_ciphers curves_offered curves_to_test temp + local curve_found curve_used outln pr_headlineln " Testing robust (perfect) forward secrecy, (P)FS -- omitting Null Authentication/Encryption as well as 3DES and RC4 here " @@ -4582,15 +4585,56 @@ run_pfs() { if "$ecdhe_offered"; then # find out what elliptic curves are supported. curves_offered="" - for curve in "${curves[@]}"; do - $OPENSSL s_client -cipher "${ecdhe_cipher_list:1}" -curves $curve $STARTTLS $BUGS -connect $NODEIP:$PORT $PROXY $SNI &>$tmpfile $tmpfile Date: Sat, 16 Jul 2016 20:48:56 +0200 Subject: [PATCH 27/27] - output polising in curves - fix for jail #258 --- testssl.sh | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/testssl.sh b/testssl.sh index ea85fae..ee153a5 100755 --- a/testssl.sh +++ b/testssl.sh @@ -4525,13 +4525,13 @@ run_pfs() { outln pfs_offered=true pfs_ciphers="" - pr_done_good " PFS is offered (OK) " + pr_done_good " PFS is offered (OK)" fileout "pfs" "OK" "(Perfect) Forward Secrecy : PFS is offered (OK)" if "$WIDE"; then outln ", ciphers follow (client/browser support is important here) \n" neat_header else - out " " + out " " fi while read hexcode dash pfs_cipher sslvers kx auth enc mac; do tmpfile=$TMPFILE.$hexcode @@ -4589,6 +4589,7 @@ run_pfs() { [[ "$sclient_success" -eq 0 ]] && curves_offered+="$curve " done if [[ -n "$curves_offered" ]]; then + "$WIDE" && outln pr_bold " Elliptic curves offered: "; outln "$curves_offered" fileout "ecdhe_curves" "INFO" "Elliptic curves offered $curves_offered" fi @@ -6765,7 +6766,11 @@ check4openssl_oldfarts() { # FreeBSD needs to have /dev/fd mounted. This is a friendly hint, see #258 check_bsd_mount() { if [[ "$(uname)" == FreeBSD ]]; then - if ! mount | grep '/dev/fd' | grep -q fdescfs; then + if ! mount | grep -q "^devfs"; then + outln "you seem to run $PROG_NAME= in a jail. Hopefully you're did \"mount -t fdescfs fdesc /dev/fd\"" + elif mount | grep '/dev/fd' | grep -q fdescfs; then + : + else fatal "You need to mount fdescfs on FreeBSD: \"mount -t fdescfs fdesc /dev/fd\"" -3 fi fi @@ -8286,4 +8291,4 @@ fi exit $? -# $Id: testssl.sh,v 1.525 2016/07/11 17:41:32 dirkw Exp $ +# $Id: testssl.sh,v 1.526 2016/07/16 18:48:55 dirkw Exp $