From 1d4622ebab69e499f532d6217f699b7a37970068 Mon Sep 17 00:00:00 2001 From: David Cooper Date: Fri, 6 May 2016 15:12:53 -0400 Subject: [PATCH 1/8] Additional checks in run_protocols() One server I am testing responds to an SSLv3 ClientHello with TLSv1.2. If tls_sockets is being used, then testssl.sh responds with "#FIXME: downgraded. still missing a test case here." This PR fixes that, and in general checks the responses in run_protocols() more closely. If tls_sockets is being used and the connection fails even though the server supports an earlier version of SSL/TLS, then it flags an error. If tls_sockets returns 2, then it verifies that $DETECTED_TLS_VERSION is equal to the highest version number supported by the server (that is also less than the version number in the ClientHello). In addition, in order to test servers' support for version negotiation, it adds a new test that sends a TLSv1.4 ClientHello and verifies that the server responds with the highest version number that it supports. (This test only runs if both $using_sockets and $EXPERIMENTAL are true and server actually supports some version of SSL/TLS other than SSLv2.) --- testssl.sh | 195 +++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 161 insertions(+), 34 deletions(-) diff --git a/testssl.sh b/testssl.sh index 8d133d4..1869d06 100755 --- a/testssl.sh +++ b/testssl.sh @@ -2224,31 +2224,34 @@ run_protocols() { local using_sockets=true local supported_no_ciph1="supported but couldn't detect a cipher (may need debugging)" local supported_no_ciph2="supported but couldn't detect a cipher" - local via="" + local latest_supported="" # version.major and version.minor of highest version supported by the server. + local detected_version_string latest_supported_string + local extra_spaces="" outln; pr_headline " Testing protocols " - via="Protocol tested " #FIXME: use PROTOS_OFFERED here if $SSL_NATIVE; then using_sockets=false pr_headlineln "(via native openssl)" - via+="via native openssl" else if [[ -n "$STARTTLS" ]]; then pr_headlineln "(via openssl, SSLv2 via sockets) " - via+="via openssl, SSLv2 via sockets" using_sockets=false else using_sockets=true - pr_headlineln "(via sockets except TLS 1.2, SPDY+HTTP2) " - via+="via sockets except for TLS1.2, SPDY+HTTP2" + if $EXPERIMENTAL; then + pr_headlineln "(via sockets except SPDY+HTTP2) " + extra_spaces=" " + else + pr_headlineln "(via sockets except TLS 1.2, SPDY+HTTP2) " + fi fi fi outln - pr_bold " SSLv2 "; + pr_bold " SSLv2 $extra_spaces"; if ! $SSL_NATIVE; then sslv2_sockets #FIXME: messages need to be moved to this higher level else @@ -2272,7 +2275,7 @@ run_protocols() { esac fi - pr_bold " SSLv3 "; + pr_bold " SSLv3 $extra_spaces"; if $using_sockets; then tls_sockets "00" "$TLS_CIPHER" else @@ -2282,14 +2285,22 @@ run_protocols() { 0) pr_svrty_highln "offered (NOT ok)" fileout "sslv3" "NOT ok" "SSLv3 is offered (NOT ok)" + latest_supported="0300" + latest_supported_string="SSLv3" ;; 1) pr_done_bestln "not offered (OK)" fileout "sslv3" "OK" "SSLv3 is not offered (OK)" ;; 2) - pr_warningln "#FIXME: downgraded. still missing a test case here" - fileout "sslv3" "WARN" "SSLv3: #FIXME: downgraded. still missing a test case here" + if [[ "$DETECTED_TLS_VERSION" == 03* ]]; then + detected_version_string="TLSv1.$((0x$DETECTED_TLS_VERSION-0x0301))" + pr_svrty_criticalln "server responded with higher version number ($detected_version_string) than requested by client (NOT ok)" + fileout "sslv3" "NOT ok" "SSLv3: server responded with higher version number ($detected_version_string) than requested by client (NOT ok)" + else + pr_svrty_criticalln "server responded with version number ${DETECTED_TLS_VERSION:0:2}.${DETECTED_TLS_VERSION:2:2} (NOT ok)" + fileout "sslv3" "NOT ok" "SSLv3: server responded with version number ${DETECTED_TLS_VERSION:0:2}.${DETECTED_TLS_VERSION:2:2} (NOT ok)" + fi ;; 5) fileout "sslv3" "WARN" "SSLv3 is $supported_no_ciph1" @@ -2301,7 +2312,7 @@ run_protocols() { ;; # no local support esac - pr_bold " TLS 1 "; + pr_bold " TLS 1 $extra_spaces"; if $using_sockets; then tls_sockets "01" "$TLS_CIPHER" else @@ -2311,16 +2322,33 @@ run_protocols() { 0) outln "offered" fileout "tls1" "INFO" "TLSv1.0 is offered" + latest_supported="0301" + latest_supported_string="TLSv1.0" ;; # nothing wrong with it -- per se 1) - outln "not offered" - fileout "tls1" "INFO" "TLSv1.0 is not offered" - ;; # neither good or bad + out "not offered" + if ! $using_sockets || [[ -z $latest_supported ]]; then + outln + fileout "tls1" "INFO" "TLSv1.0 is not offered" # neither good or bad + else + pr_svrty_criticalln " -- connection failed rather than downgrading to $latest_supported_string (NOT ok)" + fileout "tls1" "NOT ok" "TLSv1.0: connection failed rather than downgrading to $latest_supported_string (NOT ok)" + fi + ;; 2) pr_svrty_medium "not offered (NOT ok)" - [[ $DEBUG -eq 1 ]] && out " -- downgraded" - outln - fileout "tls1" "NOT ok" "TLSv1.0 is not offered, and downgraded to SSL (NOT ok)" + if [[ "$DETECTED_TLS_VERSION" == "0300" ]]; then + [[ $DEBUG -eq 1 ]] && out " -- downgraded" + outln + fileout "tls1" "NOT ok" "TLSv1.0 is not offered, and downgraded to SSL (NOT ok)" + elif [[ "$DETECTED_TLS_VERSION" == 03* ]]; then + detected_version_string="TLSv1.$((0x$DETECTED_TLS_VERSION-0x0301))" + pr_svrty_criticalln " -- server responded with higher version number ($detected_version_string) than requested by client" + fileout "tls1" "NOT ok" "TLSv1.0: server responded with higher version number ($detected_version_string) than requested by client (NOT ok)" + else + pr_svrty_criticalln " -- server responded with version number ${DETECTED_TLS_VERSION:0:2}.${DETECTED_TLS_VERSION:2:2}" + fileout "tls1" "NOT ok" "TLSv1.0: server responded with version number ${DETECTED_TLS_VERSION:0:2}.${DETECTED_TLS_VERSION:2:2} (NOT ok)" + fi ;; 5) outln "$supported_no_ciph1" # protocol ok, but no cipher @@ -2331,7 +2359,7 @@ run_protocols() { ;; # no local support esac - pr_bold " TLS 1.1 "; + pr_bold " TLS 1.1 $extra_spaces"; if $using_sockets; then tls_sockets "02" "$TLS_CIPHER" else @@ -2341,16 +2369,36 @@ run_protocols() { 0) outln "offered" fileout "tls1_1" "INFO" "TLSv1.1 is offered" + latest_supported="0302" + latest_supported_string="TLSv1.1" ;; # nothing wrong with it 1) - outln "not offered" - fileout "tls1_1" "INFO" "TLSv1.1 is not offered" - ;; # neither good or bad + out "not offered" + if ! $using_sockets || [[ -z $latest_supported ]]; then + outln + fileout "tls1_1" "INFO" "TLSv1.1 is not offered" # neither good or bad + else + pr_svrty_criticalln " -- connection failed rather than downgrading to $latest_supported_string" + fileout "tls1_1" "NOT ok" "TLSv1.1: connection failed rather than downgrading to $latest_supported_string (NOT ok)" + fi + ;; 2) out "not offered" - [[ $DEBUG -eq 1 ]] && out " -- downgraded" - outln - fileout "tls1_1" "NOT ok" "TLSv1.1 is not offered, and downgraded to a weaker protocol (NOT ok)" + if [[ "$DETECTED_TLS_VERSION" == "$latest_supported" ]]; then + [[ $DEBUG -eq 1 ]] && out " -- downgraded" + outln + fileout "tls1_1" "NOT ok" "TLSv1.1 is not offered, and downgraded to a weaker protocol (NOT ok)" + elif [[ "$DETECTED_TLS_VERSION" == "0300" ]] && [[ "$latest_supported" == "0301" ]]; then + pr_svrty_criticalln " -- server supports TLSv1.0, but downgraded to SSLv3 (NOT ok)" + fileout "tls1_1" "NOT ok" "TLSv1.1 is not offered, and downgraded to SSLv3 rather than TLSv1.0 (NOT ok)" + elif [[ "$DETECTED_TLS_VERSION" == 03* ]] && [[ 0x$DETECTED_TLS_VERSION -gt 0x0302 ]]; then + detected_version_string="TLSv1.$((0x$DETECTED_TLS_VERSION-0x0301))" + pr_svrty_criticalln " -- server responded with higher version number ($detected_version_string) than requested by client (NOT ok)" + fileout "tls1_1" "NOT ok" "TLSv1.1 is not offered, server responded with higher version number ($detected_version_string) than requested by client (NOT ok)" + else + pr_svrty_criticalln " -- server responded with version number ${DETECTED_TLS_VERSION:0:2}.${DETECTED_TLS_VERSION:2:2} (NOT ok)" + fileout "tls1" "NOT ok" "TLSv1.1: server responded with version number ${DETECTED_TLS_VERSION:0:2}.${DETECTED_TLS_VERSION:2:2} (NOT ok)" + fi ;; 5) outln "$supported_no_ciph1" @@ -2361,7 +2409,7 @@ run_protocols() { ;; # no local support esac - pr_bold " TLS 1.2 "; + pr_bold " TLS 1.2 $extra_spaces"; if $using_sockets && $EXPERIMENTAL; then #TODO: IIS servers do have a problem here with our handshake tls_sockets "03" "$TLS12_CIPHER" else @@ -2371,16 +2419,40 @@ run_protocols() { 0) pr_done_bestln "offered (OK)" fileout "tls1_2" "OK" "TLSv1.2 is offered (OK)" + latest_supported="0303" + latest_supported_string="TLSv1.2" ;; # GCM cipher in TLS 1.2: very good! 1) - pr_svrty_mediumln "not offered (NOT ok)" - fileout "tls1_2" "NOT ok" "TLSv1.2 is not offered (NOT ok)" - ;; # no GCM, penalty + pr_svrty_medium "not offered (NOT ok)" + if ! $using_sockets || ! $EXPERIMENTAL || [[ -z $latest_supported ]]; then + outln + fileout "tls1_2" "NOT ok" "TLSv1.2 is not offered (NOT ok)" # no GCM, penalty + else + pr_svrty_criticalln " -- connection failed rather than downgrading to $latest_supported_string" + fileout "tls1_1" "NOT ok" "TLSv1.2: connection failed rather than downgrading to $latest_supported_string" + fi + ;; 2) - pr_svrty_medium "not offered (NOT ok)" - [[ $DEBUG -eq 1 ]] && out " -- downgraded" - outln - fileout "tls1_2" "NOT ok" "TLSv1.2 is not offered and downgraded to a weaker protocol (NOT ok)" + pr_svrty_medium "not offered (NOT ok)" + if [[ "$DETECTED_TLS_VERSION" == "0300" ]]; then + detected_version_string="SSLv3" + elif [[ "$DETECTED_TLS_VERSION" == 03* ]]; then + detected_version_string="TLSv1.$((0x$DETECTED_TLS_VERSION-0x0301))" + fi + if [[ "$DETECTED_TLS_VERSION" == "$latest_supported" ]]; then + [[ $DEBUG -eq 1 ]] && out " -- downgraded" + outln + fileout "tls1_2" "NOT ok" "TLSv1.2 is not offered and downgraded to a weaker protocol (NOT ok)" + elif [[ "$DETECTED_TLS_VERSION" == 03* ]] && [[ 0x$DETECTED_TLS_VERSION -lt 0x$latest_supported ]]; then + pr_svrty_criticalln " -- server supports $latest_supported_string, but downgraded to $detected_version_string" + fileout "tls1_2" "NOT ok" "TLSv1.2 is not offered, and downgraded to $detected_version_string rather than $latest_supported_string (NOT ok)" + elif [[ "$DETECTED_TLS_VERSION" == 03* ]] && [[ 0x$DETECTED_TLS_VERSION -gt 0x0303 ]]; then + pr_svrty_criticalln " -- server responded with higher version number ($detected_version_string) than requested by client" + fileout "tls1_2" "NOT ok" "TLSv1.2 is not offered, server responded with higher version number ($detected_version_string) than requested by client (NOT ok)" + else + pr_svrty_criticalln " -- server responded with version number ${DETECTED_TLS_VERSION:0:2}.${DETECTED_TLS_VERSION:2:2}" + fileout "tls1" "NOT ok" "TLSv1.2: server responded with version number ${DETECTED_TLS_VERSION:0:2}.${DETECTED_TLS_VERSION:2:2} (NOT ok)" + fi ;; 5) outln "$supported_no_ciph1" @@ -2390,6 +2462,55 @@ run_protocols() { fileout "tls1_2" "INFO" "TLSv1.2 is not tested due to lack of local support" ;; # no local support esac + + # Testing version negotiation. RFC 5246, Appendix E.1, states: + # + # If a TLS server receives a ClientHello containing a version number + # greater than the highest version supported by the server, it MUST + # reply according to the highest version supported by the server. + if [[ -n $latest_supported ]] && $using_sockets && $EXPERIMENTAL; then + pr_bold " Version Negotiation "; + tls_sockets "05" "$TLS12_CIPHER" + case $? in + 0) + pr_svrty_criticalln "server claims support for non-existent TLSv1.4" + fileout "TLS Version Negotiation" "NOT ok" "Server claims support for non-existent TLSv1.4 (NOT ok)" + ;; + 1) + pr_svrty_criticalln "version negotiation did not work -- connection failed rather than downgrading to $latest_supported_string (NOT ok)" + fileout "TLS Version Negotiation" "NOT ok" "Version negotiation did not work -- connection failed rather than downgrading to $latest_supported_string (NOT ok)" + ;; + 2) + case $DETECTED_TLS_VERSION in + 0304) + pr_svrty_criticalln "server claims support for TLSv1.3, which is still a working draft (NOT ok)" + fileout "TLS Version Negotiation" "NOT ok" "Server claims support for TLSv1.3, which is still a working draft (NOT ok)" + ;; + 0303|0302|0301|0300) + if [[ "$DETECTED_TLS_VERSION" == "0300" ]]; then + detected_version_string="SSLv3" + else + detected_version_string="TLSv1.$((0x$DETECTED_TLS_VERSION-0x0301))" + fi + if [[ 0x$DETECTED_TLS_VERSION -lt 0x$latest_supported ]]; then + pr_svrty_criticalln "server supports $latest_supported_string, but downgraded to $detected_version_string (NOT ok)" + fileout "TLS Version Negotiation" "NOT ok" "Downgraded to $detected_version_string rather than $latest_supported_string (NOT ok)" + else + pr_done_bestln "downgraded to $detected_version_string (OK)" + fileout "TLS Version Negotiation" "OK" "Downgraded to $detected_version_string" + fi + ;; + *) + pr_svrty_criticalln "server responded with version number ${DETECTED_TLS_VERSION:0:2}.${DETECTED_TLS_VERSION:2:2} (NOT ok)" + fileout "TLS Version Negotiation" "NOT ok" "TLSv1.4: server responded with version number ${DETECTED_TLS_VERSION:0:2}.${DETECTED_TLS_VERSION:2:2} (NOT ok)" + ;; + esac ;; + 5) + pr_svrty_criticalln "server claims support for non-existent TLSv1.4 (NOT ok)" + fileout "TLS Version Negotiation" "NOT ok" "Server claims support for non-existent TLSv1.4 (NOT ok)" + ;; + esac + fi return 0 } @@ -3689,8 +3810,11 @@ http2_pre(){ run_spdy() { local tmpstr local -i ret=0 + extra_spaces="" - pr_bold " SPDY/NPN " + ! $SSL_NATIVE && [[ -z "$STARTTLS" ]] && $EXPERIMENTAL && extra_spaces=" " + + pr_bold " SPDY/NPN $extra_spaces" if ! spdy_pre ; then outln return 0 @@ -3727,8 +3851,11 @@ run_http2() { local -i ret=0 local had_alpn_proto=false local alpn_finding="" + extra_spaces="" - pr_bold " HTTP2/ALPN " + ! $SSL_NATIVE && [[ -z "$STARTTLS" ]] && $EXPERIMENTAL && extra_spaces=" " + + pr_bold " HTTP2/ALPN $extra_spaces" if ! http2_pre ; then outln return 0 From 346c52dc7c65b87cce9881b5e045756ee1c26f7e Mon Sep 17 00:00:00 2001 From: David Cooper Date: Wed, 20 Jul 2016 11:37:51 -0400 Subject: [PATCH 2/8] CA names with domain component attributes `certificate_info()` does not correctly display the Issuer name for CAs that use domain component attributes. There is a server on the NIST intra-net that I test against that has a certificate issued by a NIST CA, and the issuer name in the certificate is of the form: `/DC=net/DC=example/DC=internal/CN=CAname` Since there is no organizational name, testssl.sh displays the name as: ``` Issuer "CAname" ("") ``` In this PR, if the Issuer name has 'DC=' attributes, but does not have an 'O=' attribute, the "DC=" attributes are combined into a DNS name that is used as if it were the organizational name: ``` Issuer "CAname" ("internal.example.net") ``` I should note, however, that I have not been able to find any other examples of TLS server certificates that have been issued by CAs that have domain components ("DC=") in their names. So, it may not be worthwhile to change the code to try to accommodate such CAs. --- testssl.sh | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/testssl.sh b/testssl.sh index e513d20..194b8df 100755 --- a/testssl.sh +++ b/testssl.sh @@ -3839,7 +3839,7 @@ certificate_info() { local ocsp_response=$5 local ocsp_response_status=$6 local cert_sig_algo cert_sig_hash_algo cert_key_algo - local expire days2expire secs2warn ocsp_uri crl startdate enddate issuer_CN issuer_C issuer_O issuer sans san cn cn_nosni + local expire days2expire secs2warn ocsp_uri crl startdate enddate issuer_CN issuer_C issuer_O issuer_DC issuer issuerfinding sans san cn cn_nosni local cert_fingerprint_sha1 cert_fingerprint_sha2 cert_fingerprint_serial local policy_oid local spaces="" @@ -4146,22 +4146,33 @@ certificate_info() { issuer_CN="$(awk -F'=' '/CN=/ { print $2 }' <<< "$issuer")" issuer_O="$(awk -F'=' '/O=/ { print $2 }' <<< "$issuer")" issuer_C="$(awk -F'=' '/ C=/ { print $2 }' <<< "$issuer")" + issuer_DC="$(awk -F'=' '/DC=/ { print $2 }' <<< "$issuer")" if [[ "$issuer_O" == "issuer=" ]] || [[ "$issuer_O" == "issuer= " ]] || [[ "$issuer_CN" == "$CN" ]]; then pr_svrty_criticalln "self-signed (NOT ok)" fileout "${json_prefix}issuer" "NOT ok" "Issuer: selfsigned (NOT ok)" else - pr_dquoted "$issuer_CN" - out " (" - pr_dquoted "$issuer_O" - if [[ -n "$issuer_C" ]]; then - out " from " - pr_dquoted "$issuer_C" - fileout "${json_prefix}issuer" "INFO" "Issuer: \"$issuer_CN\" ( \"$issuer_O\" from \"$issuer_C\")" - else - fileout "${json_prefix}issuer" "INFO" "Issuer: \"$issuer_CN\" ( \"$issuer_O\" )" + issuerfinding="$(pr_dquoted "$issuer_CN")" + if [[ -z "$issuer_O" ]] && [[ -n "$issuer_DC" ]]; then + for san in $issuer_DC; do + if [[ -z "$issuer_O" ]]; then + issuer_O="${san}" + else + issuer_O="${san}.${issuer_O}" + fi + done fi - outln ")" + if [[ -n "$issuer_O" ]]; then + issuerfinding+=" (" + issuerfinding+="$(pr_dquoted "$issuer_O")" + if [[ -n "$issuer_C" ]]; then + issuerfinding+=" from " + issuerfinding+="$(pr_dquoted "$issuer_C")" + fi + issuerfinding+=")" + fi + outln "$issuerfinding" + fileout "${json_prefix}issuer" "INFO" "Issuer: $issuerfinding" fi # http://events.ccc.de/congress/2010/Fahrplan/attachments/1777_is-the-SSLiverse-a-safe-place.pdf, see page 40pp From df64e47fb9c21efb98147fe64624b23e94d0baa1 Mon Sep 17 00:00:00 2001 From: David Cooper Date: Fri, 22 Jul 2016 11:31:52 -0400 Subject: [PATCH 3/8] CN <--> hostname match PR to address issue #94 (CN <--> hostname match) --- testssl.sh | 314 ++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 227 insertions(+), 87 deletions(-) diff --git a/testssl.sh b/testssl.sh index a857644..bd65d84 100755 --- a/testssl.sh +++ b/testssl.sh @@ -3586,7 +3586,7 @@ determine_trust() { if [[ $OSSL_VER_MAJOR.$OSSL_VER_MINOR != "1.0.2" ]] && [[ $OSSL_VER_MAJOR.$OSSL_VER_MINOR != "1.1.0" ]]; then addtl_warning="(Your openssl <= 1.0.2 might be too unreliable to determine trust)" - fileout "${json_prefix}trust_warn" "WARN" "$addtl_warning" + fileout "${json_prefix}chain_of_trust_warn" "WARN" "$addtl_warning" fi debugme outln for bundle_fname in $ca_bundles; do @@ -3624,7 +3624,7 @@ determine_trust() { # all stores ok pr_done_good "Ok "; pr_warning "$addtl_warning" # we did to stdout the warning above already, so we could stay here with INFO: - fileout "${json_prefix}trust" "OK" "All certificate trust checks passed. $addtl_warning" + fileout "${json_prefix}chain_of_trust" "OK" "All certificate trust checks passed. $addtl_warning" else # at least one failed pr_svrty_critical "NOT ok" @@ -3632,7 +3632,7 @@ determine_trust() { # all failed (we assume with the same issue), we're displaying the reason out " " verify_retcode_helper "${verify_retcode[2]}" - fileout "${json_prefix}trust" "NOT ok" "All certificate trust checks failed: $(verify_retcode_helper "${verify_retcode[2]}"). $addtl_warning" + fileout "${json_prefix}chain_of_trust" "NOT ok" "All certificate trust checks failed: $(verify_retcode_helper "${verify_retcode[2]}"). $addtl_warning" else # is one ok and the others not ==> display the culprit store if $some_ok ; then @@ -3655,7 +3655,7 @@ determine_trust() { [[ "$DEBUG" -eq 0 ]] && out "$spaces" pr_done_good "OK: $ok_was" fi - fileout "${json_prefix}trust" "NOT ok" "Some certificate trust checks failed : OK : $ok_was NOT ok: $notok_was $addtl_warning" + fileout "${json_prefix}chain_of_trust" "NOT ok" "Some certificate trust checks failed : OK : $ok_was NOT ok: $notok_was $addtl_warning" fi [[ -n "$addtl_warning" ]] && out "\n$spaces" && pr_warning "$addtl_warning" fi @@ -3792,42 +3792,128 @@ get_cn_from_cert() { return $? } -# Return 0 if the server name provided in arg1 matches the CN or SAN in arg2, otherwise return 1. +# Return 0 if the name provided in arg1 is a wildcard name +is_wildcard() +{ + local certname="$1" + + # If the first label in the DNS name begins "xn--", then assume it is an + # A-label and not a wildcard name (RFC 6125, Section 6.4.3). + [[ "${certname:0:4}" == "xn--" ]] && return 1 + + # Remove part of name preceding '*' or '.'. If no "*" appears in the + # left-most label, then it is not a wildcard name (RFC 6125, Section 6.4.3). + basename="$(echo -n "$certname" | sed 's/^[a-zA-Z0-9\-]*//')" + [[ "${basename:0:1}" != "*" ]] && return 1 # not a wildcard name + + # Check that there are no additional wildcard ('*') characters or any + # other characters that do not belong in a DNS name. + [[ -n $(echo -n "${basename:1}" | sed 's/^[\.a-zA-Z0-9\-]*//') ]] && return 1 + return 0 +} + +# Return 0 if the name provided in arg2 is a wildcard name and it matches the name provided in arg1. +wildcard_match() +{ + local servername="$1" + local certname="$2" + local basename + local -i basename_offset len_certname len_part1 len_basename + local -i len_servername len_wildcard + + len_servername=${#servername} + len_certname=${#certname} + + # Use rules from RFC 6125 to perform the match. + + # Assume the "*" in the wildcard needs to be replaced by one or more + # characters, although RFC 6125 is not clear about that. + [[ $len_servername -lt $len_certname ]] && return 1 + + is_wildcard "$certname" + [[ $? -ne 0 ]] && return 1 + + # Comparisons of DNS names are case insenstive, so convert both names to uppercase. + certname="$(toupper "$certname")" + servername="$(toupper "$servername")" + + # Extract part of name that comes after the "*" + basename="$(echo -n "$certname" | sed 's/^[A-Z0-9\-]*\*//')" + len_basename=${#basename} + len_part1=$len_certname-$len_basename-1 + len_wildcard=$len_servername-$len_certname+1 + basename_offset=$len_servername-$len_basename + + # Check that initial part of $servername matches initial part of $certname + # and that final part of $servername matches final part of $certname. + [[ "${servername:0:len_part1}" != "${certname:0:len_part1}" ]] && return 1 + [[ "${servername:basename_offset:len_basename}" != "$basename" ]] && return 1 + + # Check that part of $servername that matches "*" is all part of a single + # domain label. + [[ -n $(echo -n "${servername:len_part1:len_wildcard}" | sed 's/^[A-Z0-9\-]*//') ]] && return 1 + + return 0 +} + +# Compare the server name provided in arg1 to the CN and SAN in arg2 and return: +# 0, if server name provided does not match any of the names in the CN or SAN +# 1, if the server name provided matches a name in the SAN +# 2, if the server name provided is a wildcard match against a name in the SAN +# 4, if the server name provided matches the CN +# 5, if the server name provided matches the CN AND a name in the SAN +# 6, if the server name provided matches the CN AND is a wildcard match against a name in the SAN +# 8, if the server name provided is a wildcard match against the CN +# 9, if the server name provided matches a name in the SAN AND is a wildcard match against the CN +# 10, if the server name provided is a wildcard match against the CN AND a name in the SAN + compare_server_name_to_cert() { - local servername=$1 - local cert=$2 - local cn dns_sans ip_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 + local servername="$(toupper "$1")" + local cert="$2" + local cn dns_sans ip_sans san + local -i ret=0 # 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" | \ + 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') 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 - basename="$(echo -n "$san" | sed 's/^\*.//')" - [[ "$san" == "*.$basename" ]] && [[ "$servername" == *".$basename" ]] && return 0 - fi + [[ $(toupper "$san") == "$servername" ]] && ret=1 && break 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 -A2 "Subject Alternative Name" | \ - 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 - return 1 + if [[ $req -eq 0 ]]; then + # Check whether any of the IP addresses in the certificate match the servername + ip_sans=$($OPENSSL x509 -in "$cert" -noout -text 2>>$ERRFILE | grep -A2 "Subject Alternative Name" | \ + tr ',' '\n' | grep "IP Address:" | sed -e 's/IP Address://g' -e 's/ //g') + for san in $ip_sans; do + [[ "$san" == "$servername" ]] && ret=1 && break + done + fi + + # Check whether any of the DNS names in the certificate are wildcard names + # that match the servername + if [[ $req -eq 0 ]]; then + for san in $dns_sans; do + wildcard_match "$servername" "$san" + [[ $? -eq 0 ]] && ret=2 && break + done + fi + + cn="$(get_cn_from_cert "$cert")" + + # If the CN contains any characters that are not valid for a DNS name, + # then assume it does not contain a DNS name. + [[ -n $(echo -n "$cn" | sed 's/^[\.a-zA-Z0-9*\-]*//') ]] && return $ret + + # Check whether the CN in the certificate matches the servername + [[ $(toupper "$cn") == "$servername" ]] && ret+=4 && return $ret + + # Check whether the CN in the certificate is a wildcard name that matches + # the servername + wildcard_match "$servername" "$cn" + [[ $? -eq 0 ]] && ret+=8 + + return $ret } certificate_info() { @@ -3844,9 +3930,9 @@ certificate_info() { local cert_fingerprint_sha1 cert_fingerprint_sha2 cert_fingerprint_serial local policy_oid local spaces="" - local wildcard=false + local trust_sni=0 trust_nosni=0 has_dns_sans local -i certificates_provided - local cnfinding + local cnfinding trustfinding trustfinding_nosni local cnok="OK" local expfinding expok="OK" local json_prefix="" # string to place at beginng of JSON IDs when there is more than one certificate @@ -4058,19 +4144,6 @@ certificate_info() { if [[ -n "$cn" ]]; then pr_dquoted "$cn" cnfinding="$cn" - if echo -n "$cn" | grep -q '^*.' ; then - out " (wildcard certificate" - cnfinding+="(wildcard certificate " - if [[ "$cn" == "*.$(echo -n "$cn" | sed 's/^\*.//')" ]]; then - out " match)" - cnfinding+=" match)" - wildcard=true - else - cnfinding+=" NO match)" - cnok="INFO" - #FIXME: we need to test also the SANs as they can contain a wild card (google.de .e.g) ==> 2.7dev - fi - fi else cn="no CN field in subject" out "($cn)" @@ -4088,40 +4161,23 @@ certificate_info() { #FIXME: check for SSLv3/v2 and look whether it goes to a different CN (probably not polite) debugme out "\"$NODE\" | \"$cn\" | \"$cn_nosni\"" - if [[ "$cn_nosni" == "$cn" ]]; then - outln " (works w/o SNI)" - cnfinding+=" (works w/o SNI)" - elif [[ $NODE == "$cn_nosni" ]]; then - if [[ $SERVICE == "HTTP" ]] || $CLIENT_AUTH ; then - outln " (works w/o SNI)" - cnfinding+=" (works w/o SNI)" - else - outln " (matches certificate directly)" - cnfinding+=" (matches certificate directly)" - # for services != HTTP it depends on the protocol, server and client but it is not named "SNI" + if [[ "$(toupper "$cn_nosni")" == "$(toupper "$cn")" ]]; then + outln + elif [[ -z "$cn_nosni" ]]; then + out " (request w/o SNI didn't succeed"; + cnfinding+=" (request w/o SNI didn't succeed" + if [[ $cert_sig_algo =~ ecdsa ]]; then + out ", usual for EC certificates" + cnfinding+=", usual for EC certificates" fi + outln ")" + cnfinding+=")" + elif [[ "$cn_nosni" == *"no CN field"* ]]; then + outln ", (request w/o SNI: $cn_nosni)" + cnfinding+=", (request w/o SNI: $cn_nosni)" else - if [[ $SERVICE != "HTTP" ]]; then - outln - cnfinding+="\n" - #pr_svrty_mediumln " (non-SNI clients don't match CN but for non-HTTP services it might be ok)" - #FIXME: this is irritating and needs to be redone. Then also the wildcard match needs to be tested against "$cn_nosni" - elif [[ -z "$cn_nosni" ]]; then - out " (request w/o SNI didn't succeed"; - cnfinding+=" (request w/o SNI didn't succeed" - if [[ $cert_sig_algo =~ ecdsa ]]; then - out ", usual for EC certificates" - cnfinding+=", usual for EC certificates" - fi - outln ")" - cnfinding+=")" - elif [[ "$cn_nosni" == *"no CN field"* ]]; then - outln ", (request w/o SNI: $cn_nosni)" - cnfinding+=", (request w/o SNI: $cn_nosni)" - else - out " (CN in response to request w/o SNI: "; pr_dquoted "$cn_nosni"; outln ")" - cnfinding+=" (CN in response to request w/o SNI: \"$cn_nosni\")" - fi + out " (CN in response to request w/o SNI: "; pr_dquoted "$cn_nosni"; outln ")" + cnfinding+=" (CN in response to request w/o SNI: \"$cn_nosni\")" fi fileout "${json_prefix}cn" "$cnok" "$cnfinding" @@ -4178,6 +4234,90 @@ certificate_info() { fileout "${json_prefix}issuer" "INFO" "Issuer: $issuerfinding" fi + out "$indent"; pr_bold " Trust " + compare_server_name_to_cert "$NODE" "$HOSTCERT" + trust_sni=$? + + # Find out if the subjectAltName extension is present and contains + # a DNS name, since Section 6.3 of RFC 6125 says: + # Security Warning: A client MUST NOT seek a match for a reference + # identifier of CN-ID if the presented identifiers include a DNS-ID, + # SRV-ID, URI-ID, or any application-specific identifier types + # supported by the client. + $OPENSSL x509 -in $HOSTCERT -noout -text 2>>$ERRFILE | \ + grep -A2 "Subject Alternative Name" | grep -q "DNS:" && \ + has_dns_sans=true || has_dns_sans=false + + case $trust_sni in + 0) trustfinding="certificate does not match URI" ;; + 1) trustfinding="Ok via SAN" ;; + 2) trustfinding="Ok via SAN wildcard" ;; + 4) if $has_dns_sans; then + trustfinding="Ok via CN, but not SAN" + else + trustfinding="Ok via CN" + fi + ;; + 5) trustfinding="Ok via SAN and CN" ;; + 6) trustfinding="Ok via SAN wildcard and CN" + ;; + 8) if $has_dns_sans; then + trustfinding="Ok via CN wildcard, but not SAN" + else + trustfinding="Ok via CN wildcard" + fi + ;; + 9) trustfinding="Ok via CN wildcard and SAN" + ;; + 10) trustfinding="Ok via SAN wildcard and CN wildcard" + ;; + esac + + if [[ $trust_sni -eq 0 ]]; then + pr_svrty_medium "$trustfinding" + trust_sni="fail" + elif $has_dns_sans && ( [[ $trust_sni -eq 4 ]] || [[ $trust_sni -eq 8 ]] ); then + pr_svrty_medium "$trustfinding" + trust_sni="warn" + else + out "$trustfinding" + trust_sni="ok" + fi + + if [[ -n "$cn_nosni" ]]; then + compare_server_name_to_cert "$NODE" "$HOSTCERT.nosni" + trust_nosni=$? + $OPENSSL x509 -in "$HOSTCERT.nosni" -noout -text 2>>$ERRFILE | \ + grep -A2 "Subject Alternative Name" | grep -q "DNS:" && \ + has_dns_sans=true || has_dns_sans=false + fi + + if $has_dns_sans && [[ $trust_nosni -eq 4 ]]; then + trustfinding_nosni=" (w/o SNI: Ok via CN, but not SAN)" + elif $has_dns_sans && [[ $trust_nosni -eq 8 ]]; then + trustfinding_nosni=" (w/o SNI: Ok via CN wildcard, but not SAN)" + elif [[ $trust_nosni -eq 0 ]] && ( [[ "$trust_sni" == "ok" ]] || [[ "$trust_sni" == "warn" ]] ); then + trustfinding_nosni=" (SNI mandatory)" + elif [[ "$trust_sni" == "ok" ]] || [[ "$trust_sni" == "warn" ]]; then + trustfinding_nosni=" (works w/o SNI)" + elif [[ $trust_nosni -ne 0 ]]; then + trustfinding_nosni=" (however, works w/o SNI)" + else + trustfinding_nosni="" + outln + fi + if $has_dns_sans && ( [[ $trust_nosni -eq 4 ]] || [[ $trust_nosni -eq 8 ]] ); then + pr_svrty_mediumln "$trustfinding_nosni" + else + outln "$trustfinding_nosni" + fi + + if [[ "$trust_sni" == "ok" ]]; then + fileout "${json_prefix}trust" "INFO" "${trustfinding}${trustfinding_nosni}" + else + fileout "${json_prefix}trust" "WARN" "${trustfinding}${trustfinding_nosni}" + fi + # http://events.ccc.de/congress/2010/Fahrplan/attachments/1777_is-the-SSLiverse-a-safe-place.pdf, see page 40pp out "$indent"; pr_bold " EV cert"; out " (experimental) " # only the first one, seldom we have two @@ -4400,23 +4540,23 @@ run_server_defaults() { # $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]=$? + [[ $? -ne 0 ]] && success[n]=0 || success[n]=1 if [[ ${success[n]} -ne 0 ]]; then - cn_nosni="$(get_cn_from_cert $HOSTCERT)" - 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') + cn_nosni="$(toupper "$(get_cn_from_cert $HOSTCERT)")" + sans_nosni="$(toupper "$($OPENSSL x509 -in $HOSTCERT -noout -text 2>>$ERRFILE | grep -A2 "Subject Alternative Name" | \ + tr ',' '\n' | grep "DNS:" | sed -e 's/DNS://g' -e 's/ //g' | tr '\n' ' ')")" echo "${previous_hostcert[1]}" > $HOSTCERT - cn_sni="$(get_cn_from_cert $HOSTCERT)" - + cn_sni="$(toupper "$(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 (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 -A2 "Subject Alternative Name" | grep "DNS:" | \ - sed -e 's/DNS://g' -e 's/ //g' -e 's/,/ /g' -e 's/othername://g') + sans_sni="$(toupper "$($OPENSSL x509 -in $HOSTCERT -noout -text 2>>$ERRFILE | grep -A2 "Subject Alternative Name" | \ + tr ',' '\n' | grep "DNS:" | sed -e 's/DNS://g' -e 's/ //g' | tr '\n' ' ')")" if [[ "$sans_nosni" == "$sans_sni" ]]; then success[n]=0 else From 59002c1088e06287afd4fbbde5b2fa5c66540bd5 Mon Sep 17 00:00:00 2001 From: David Cooper Date: Fri, 22 Jul 2016 11:57:16 -0400 Subject: [PATCH 4/8] Update JSON id for chain-of-trust --- t/01_badssl.com.t | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/t/01_badssl.com.t b/t/01_badssl.com.t index 0c9cb3c..0812d34 100755 --- a/t/01_badssl.com.t +++ b/t/01_badssl.com.t @@ -53,7 +53,7 @@ is($found,1,"We had a finding for this in the JSON output"); $tests++; like($out, qr/Chain of trust.*?NOT ok.*\(self signed\)/,"Chain of trust should fail because of self signed"); $tests++; $found = 0; foreach my $f ( @$json ) { - if ( $f->{id} eq "trust" ) { + if ( $f->{id} eq "chain_of_trust" ) { $found = 1; like($f->{finding},qr/^All certificate trust checks failed/,"Finding says certificate cannot be trusted."); $tests++; is($f->{severity}, "NOT ok", "Severity should be NOT ok"); $tests++; @@ -65,7 +65,7 @@ is($found,1,"We had a finding for this in the JSON output"); $tests++; like($okout, qr/Chain of trust[^\n]*?Ok/,"Chain of trust should be ok"); $tests++; $found = 0; foreach my $f ( @$okjson ) { - if ( $f->{id} eq "trust" ) { + if ( $f->{id} eq "chain_of_trust" ) { $found = 1; is($f->{finding},"All certificate trust checks passed.","Finding says certificate can be trusted."); $tests++; is($f->{severity}, "OK", "Severity should be OK"); $tests++; @@ -97,7 +97,7 @@ like($out, qr/Chain of trust.*?NOT ok\s+\(chain incomplete\)/,"Chain of trust sh $json = json('tmp.json'); $found = 0; foreach my $f ( @$json ) { - if ( $f->{id} eq "trust" ) { + if ( $f->{id} eq "chain_of_trust" ) { $found = 1; like($f->{finding},qr/^All certificate trust checks failed.*incomplete/,"Finding says certificate cannot be trusted."); $tests++; is($f->{severity}, "NOT ok", "Severity should be NOT ok"); $tests++; @@ -115,7 +115,7 @@ is($found,1,"We had a finding for this in the JSON output"); $tests++; #$json = json('tmp.json'); #$found = 0; #foreach my $f ( @$json ) { -# if ( $f->{id} eq "trust" ) { +# if ( $f->{id} eq "chain_of_trust" ) { # $found = 1; # like($f->{finding},qr/^All certificate trust checks failed.*incomplete/,"Finding says certificate cannot be trusted."); $tests++; # is($f->{severity}, "NOT ok", "Severity should be NOT ok"); $tests++; @@ -132,4 +132,4 @@ sub json($) { $file = `cat $file`; unlink $file; return from_json($file); -} \ No newline at end of file +} From ae386700673f2e47b5cc70a7ee15055f65b5f173 Mon Sep 17 00:00:00 2001 From: David Cooper Date: Fri, 22 Jul 2016 12:06:52 -0400 Subject: [PATCH 5/8] Fix check for self-signed certificate The check for whether a certificate is self-signed was using the undefined variable $CN rather than $cn. --- testssl.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testssl.sh b/testssl.sh index a857644..989709a 100755 --- a/testssl.sh +++ b/testssl.sh @@ -4151,7 +4151,7 @@ certificate_info() { issuer_C="$(awk -F'=' '/ C=/ { print $2 }' <<< "$issuer")" issuer_DC="$(awk -F'=' '/DC=/ { print $2 }' <<< "$issuer")" - if [[ "$issuer_O" == "issuer=" ]] || [[ "$issuer_O" == "issuer= " ]] || [[ "$issuer_CN" == "$CN" ]]; then + if [[ "$issuer_O" == "issuer=" ]] || [[ "$issuer_O" == "issuer= " ]] || [[ "$issuer_CN" == "$cn" ]]; then pr_svrty_criticalln "self-signed (NOT ok)" fileout "${json_prefix}issuer" "NOT ok" "Issuer: selfsigned (NOT ok)" else From 1a099d35b7da8f97d991a02f7fb6fd6284f5c0b3 Mon Sep 17 00:00:00 2001 From: Dirk Date: Sat, 23 Jul 2016 11:17:49 +0200 Subject: [PATCH 6/8] - minor polishing #419 --- testssl.sh | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/testssl.sh b/testssl.sh index bd65d84..0dcbf63 100755 --- a/testssl.sh +++ b/testssl.sh @@ -4234,7 +4234,7 @@ certificate_info() { fileout "${json_prefix}issuer" "INFO" "Issuer: $issuerfinding" fi - out "$indent"; pr_bold " Trust " + out "$indent"; pr_bold " Trust (hostname) " compare_server_name_to_cert "$NODE" "$HOSTCERT" trust_sni=$? @@ -4249,7 +4249,7 @@ certificate_info() { has_dns_sans=true || has_dns_sans=false case $trust_sni in - 0) trustfinding="certificate does not match URI" ;; + 0) trustfinding="certificate does not match supplied URI" ;; 1) trustfinding="Ok via SAN" ;; 2) trustfinding="Ok via SAN wildcard" ;; 4) if $has_dns_sans; then @@ -4276,11 +4276,11 @@ certificate_info() { if [[ $trust_sni -eq 0 ]]; then pr_svrty_medium "$trustfinding" trust_sni="fail" - elif $has_dns_sans && ( [[ $trust_sni -eq 4 ]] || [[ $trust_sni -eq 8 ]] ); then + elif "$has_dns_sans" && ( [[ $trust_sni -eq 4 ]] || [[ $trust_sni -eq 8 ]] ); then pr_svrty_medium "$trustfinding" trust_sni="warn" else - out "$trustfinding" + pr_done_good "$trustfinding" trust_sni="ok" fi @@ -4292,9 +4292,9 @@ certificate_info() { has_dns_sans=true || has_dns_sans=false fi - if $has_dns_sans && [[ $trust_nosni -eq 4 ]]; then + if "$has_dns_sans" && [[ $trust_nosni -eq 4 ]]; then trustfinding_nosni=" (w/o SNI: Ok via CN, but not SAN)" - elif $has_dns_sans && [[ $trust_nosni -eq 8 ]]; then + elif "$has_dns_sans" && [[ $trust_nosni -eq 8 ]]; then trustfinding_nosni=" (w/o SNI: Ok via CN wildcard, but not SAN)" elif [[ $trust_nosni -eq 0 ]] && ( [[ "$trust_sni" == "ok" ]] || [[ "$trust_sni" == "warn" ]] ); then trustfinding_nosni=" (SNI mandatory)" @@ -4304,9 +4304,8 @@ certificate_info() { trustfinding_nosni=" (however, works w/o SNI)" else trustfinding_nosni="" - outln fi - if $has_dns_sans && ( [[ $trust_nosni -eq 4 ]] || [[ $trust_nosni -eq 8 ]] ); then + if "$has_dns_sans" && ( [[ $trust_nosni -eq 4 ]] || [[ $trust_nosni -eq 8 ]] ); then pr_svrty_mediumln "$trustfinding_nosni" else outln "$trustfinding_nosni" @@ -8489,4 +8488,4 @@ fi exit $? -# $Id: testssl.sh,v 1.527 2016/07/20 15:36:50 dirkw Exp $ +# $Id: testssl.sh,v 1.528 2016/07/23 09:16:12 dirkw Exp $ From 3d588ddb20ed61602799ea94648a8bf19b83b270 Mon Sep 17 00:00:00 2001 From: Dirk Date: Sat, 23 Jul 2016 14:52:26 +0200 Subject: [PATCH 7/8] change sequence of out output (trust checks together --- testssl.sh | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/testssl.sh b/testssl.sh index dfc1c24..4234f19 100755 --- a/testssl.sh +++ b/testssl.sh @@ -4317,6 +4317,9 @@ certificate_info() { fileout "${json_prefix}trust" "WARN" "${trustfinding}${trustfinding_nosni}" fi + out "$indent"; pr_bold " Chain of trust"; out " " + determine_trust "$json_prefix" # Also handles fileout + # http://events.ccc.de/congress/2010/Fahrplan/attachments/1777_is-the-SSLiverse-a-safe-place.pdf, see page 40pp out "$indent"; pr_bold " EV cert"; out " (experimental) " # only the first one, seldom we have two @@ -4386,10 +4389,6 @@ certificate_info() { out "$indent"; pr_bold " # of certificates provided"; outln " $certificates_provided" fileout "${json_prefix}certcount" "INFO" "# of certificates provided : $certificates_provided" - - out "$indent"; pr_bold " Chain of trust"; out " (experim.) " - determine_trust "$json_prefix" # Also handles fileout - out "$indent"; pr_bold " Certificate Revocation List " crl="$($OPENSSL x509 -in $HOSTCERT -noout -text 2>>$ERRFILE | grep -A 4 "CRL Distribution" | grep URI | sed 's/^.*URI://')" if [[ -z "$crl" ]]; then @@ -8488,4 +8487,4 @@ fi exit $? -# $Id: testssl.sh,v 1.528 2016/07/23 09:16:12 dirkw Exp $ +# $Id: testssl.sh,v 1.530 2016/07/23 12:52:24 dirkw Exp $ From 541690b46e1dfa78362fda1368cd3c818ab5fd5d Mon Sep 17 00:00:00 2001 From: Dirk Date: Sat, 23 Jul 2016 15:12:13 +0200 Subject: [PATCH 8/8] - enabled+renamed tolerance test per default - quoted some bool vars for faster execution --- testssl.sh | 45 ++++++++++++++++++++------------------------- 1 file changed, 20 insertions(+), 25 deletions(-) diff --git a/testssl.sh b/testssl.sh index afdf70a..7187daa 100755 --- a/testssl.sh +++ b/testssl.sh @@ -2016,7 +2016,7 @@ run_client_simulation() { local name tls proto cipher local using_sockets=true - if $SSL_NATIVE || [[ -n "$STARTTLS" ]]; then + if "$SSL_NATIVE" || [[ -n "$STARTTLS" ]]; then using_sockets=false fi @@ -2758,7 +2758,7 @@ run_client_simulation() { for name in "${short[@]}"; do #FIXME: printf formatting would look better, especially if we want a wide option here out " ${names[i]} " - if $using_sockets && [[ -n "${handshakebytes[i]}" ]]; then + if "$using_sockets" && [[ -n "${handshakebytes[i]}" ]]; then client_simulation_sockets "${handshakebytes[i]}" sclient_success=$? if [[ $sclient_success -eq 0 ]]; then @@ -2781,7 +2781,7 @@ run_client_simulation() { #FIXME: awk proto=$(grep -aw "Protocol" $TMPFILE | sed -e 's/^.*Protocol.*://' -e 's/ //g') [[ "$proto" == TLSv1 ]] && proto="TLSv1.0" - if [[ "$proto" == TLSv1.2 ]] && ( ! $using_sockets || [[ -z "${handshakebytes[i]}" ]] ); then + if [[ "$proto" == TLSv1.2 ]] && ( ! "$using_sockets" || [[ -z "${handshakebytes[i]}" ]] ); then # OpenSSL reports TLS1.2 even if the connection is TLS1.1 or TLS1.0. Need to figure out which one it is... for tls in ${tlsvers[i]}; do $OPENSSL s_client $tls -cipher ${ciphers[i]} ${protos[i]} $STARTTLS $BUGS $PROXY -connect $NODEIP:$PORT ${sni[i]} $TMPFILE 2>$ERRFILE @@ -2807,7 +2807,7 @@ run_client_simulation() { fi #FiXME: awk cipher=$(grep -wa Cipher $TMPFILE | egrep -avw "New|is" | sed -e 's/ //g' -e 's/^Cipher://') - $using_sockets && [[ -n "${handshakebytes[i]}" ]] && [[ -n "$MAPPING_FILE_RFC" ]] && cipher="$(rfc2openssl "$cipher")" + "$using_sockets" && [[ -n "${handshakebytes[i]}" ]] && [[ -n "$MAPPING_FILE_RFC" ]] && cipher="$(rfc2openssl "$cipher")" outln "$proto $cipher" if [[ -n "${warning[i]}" ]]; then out " " @@ -2893,11 +2893,11 @@ run_protocols() { local supported_no_ciph2="supported but couldn't detect a cipher" local latest_supported="" # version.major and version.minor of highest version supported by the server. local detected_version_string latest_supported_string - local extra_spaces="" + local extra_spaces=" " outln; pr_headline " Testing protocols " - if $SSL_NATIVE; then + if "$SSL_NATIVE"; then using_sockets=false pr_headlineln "(via native openssl)" else @@ -2906,9 +2906,8 @@ run_protocols() { using_sockets=false else using_sockets=true - if $EXPERIMENTAL; then + if "$EXPERIMENTAL"; then pr_headlineln "(via sockets except SPDY+HTTP2) " - extra_spaces=" " else pr_headlineln "(via sockets except TLS 1.2, SPDY+HTTP2) " fi @@ -2917,7 +2916,7 @@ run_protocols() { outln pr_bold " SSLv2 $extra_spaces"; - if ! $SSL_NATIVE; then + if ! "$SSL_NATIVE"; then sslv2_sockets #FIXME: messages/output need to be moved to this (higher) level else run_prototest_openssl "-ssl2" @@ -2943,7 +2942,7 @@ run_protocols() { fi pr_bold " SSLv3 $extra_spaces"; - if $using_sockets; then + if "$using_sockets"; then tls_sockets "00" "$TLS_CIPHER" else run_prototest_openssl "-ssl3" @@ -2982,7 +2981,7 @@ run_protocols() { esac pr_bold " TLS 1 $extra_spaces"; - if $using_sockets; then + if "$using_sockets"; then tls_sockets "01" "$TLS_CIPHER" else run_prototest_openssl "-tls1" @@ -2997,7 +2996,7 @@ run_protocols() { ;; # nothing wrong with it -- per se 1) out "not offered" - if ! $using_sockets || [[ -z $latest_supported ]]; then + if ! "$using_sockets" || [[ -z $latest_supported ]]; then outln fileout "tls1" "INFO" "TLSv1.0 is not offered" # neither good or bad else @@ -3031,7 +3030,7 @@ run_protocols() { esac pr_bold " TLS 1.1 $extra_spaces"; - if $using_sockets; then + if "$using_sockets"; then tls_sockets "02" "$TLS_CIPHER" else run_prototest_openssl "-tls1_1" @@ -3046,7 +3045,7 @@ run_protocols() { ;; # nothing wrong with it 1) out "not offered" - if ! $using_sockets || [[ -z $latest_supported ]]; then + if ! "$using_sockets" || [[ -z $latest_supported ]]; then outln fileout "tls1_1" "INFO" "TLSv1.1 is not offered" # neither good or bad else @@ -3083,7 +3082,7 @@ run_protocols() { esac pr_bold " TLS 1.2 $extra_spaces"; - if $using_sockets && $EXPERIMENTAL; then #TODO: IIS servers do have a problem here with our handshake + if "$using_sockets" && "$EXPERIMENTAL"; then #TODO: IIS servers do have a problem here with our handshake tls_sockets "03" "$TLS12_CIPHER" else run_prototest_openssl "-tls1_2" @@ -3098,7 +3097,7 @@ run_protocols() { ;; # GCM cipher in TLS 1.2: very good! 1) pr_svrty_mediumln "not offered" - if ! $using_sockets || ! $EXPERIMENTAL || [[ -z $latest_supported ]]; then + if ! "$using_sockets" || ! "$EXPERIMENTAL" || [[ -z $latest_supported ]]; then outln fileout "tls1_2" "MEDIUM" "TLSv1.2 is not offered" # no GCM, penalty else @@ -3143,8 +3142,8 @@ run_protocols() { # If a TLS server receives a ClientHello containing a version number # greater than the highest version supported by the server, it MUST # reply according to the highest version supported by the server. - if [[ -n $latest_supported ]] && $using_sockets && $EXPERIMENTAL; then - pr_bold " Version Negotiation "; + if [[ -n $latest_supported ]] && "$using_sockets"; then + pr_bold " Version tolerance " tls_sockets "05" "$TLS12_CIPHER" case $? in 0) @@ -4971,9 +4970,7 @@ http2_pre(){ run_spdy() { local tmpstr local -i ret=0 - extra_spaces="" - - ! $SSL_NATIVE && [[ -z "$STARTTLS" ]] && $EXPERIMENTAL && extra_spaces=" " + local extra_spaces=" " pr_bold " SPDY/NPN $extra_spaces" if ! spdy_pre ; then @@ -5012,9 +5009,7 @@ run_http2() { local -i ret=0 local had_alpn_proto=false local alpn_finding="" - extra_spaces="" - - ! $SSL_NATIVE && [[ -z "$STARTTLS" ]] && $EXPERIMENTAL && extra_spaces=" " + local extra_spaces=" " pr_bold " HTTP2/ALPN $extra_spaces" if ! http2_pre ; then @@ -8613,4 +8608,4 @@ fi exit $? -# $Id: testssl.sh,v 1.530 2016/07/23 12:52:24 dirkw Exp $ +# $Id: testssl.sh,v 1.531 2016/07/23 13:12:12 dirkw Exp $