From e79e9803364d7eb93afa18a181c4548cd4b9a21f Mon Sep 17 00:00:00 2001 From: David Cooper Date: Tue, 30 Aug 2016 15:22:46 -0400 Subject: [PATCH 1/2] Display SNI information in "Server Certificate" line This PR is an attempt to address issue #447. If more than one certificate is being displayed, then a parenthetical saying "(in response to request w/o SNI)" is added for any certificate that was obtained using `$SNI=""`. In addition, if the certificate was obtained without SNI, then `certificate_info()` doesn't call `$OPENSSL s_client` in order to obtain the non-SNI host certificate and it does not display a separate "Trust (hostname)" finding for the non-SNI certificate. --- testssl.sh | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/testssl.sh b/testssl.sh index 4013333..181e6d8 100755 --- a/testssl.sh +++ b/testssl.sh @@ -4113,6 +4113,7 @@ certificate_info() { local cert_keysize=$4 local ocsp_response=$5 local ocsp_response_status=$6 + local sni_used=$7 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 local issuer_DC issuerfinding cn_nosni="" @@ -4133,7 +4134,9 @@ certificate_info() { [[ $certificate_number -eq 1 ]] && outln indent=" " out "$indent" - pr_headlineln "Server Certificate #$certificate_number" + pr_headline "Server Certificate #$certificate_number" + [[ -z "$sni_used" ]] && pr_underline " (in response to request w/o SNI)" + outln json_prefix="Server Certificate #$certificate_number " spaces=" " else @@ -4342,17 +4345,21 @@ certificate_info() { cnok="INFO" fi - # no cipher suites specified here. We just want the default vhost subject - $OPENSSL s_client $STARTTLS $BUGS -connect $NODEIP:$PORT $PROXY $OPTIMAL_PROTO 2>>$ERRFILE $HOSTCERT.nosni - if grep -q "\-\-\-\-\-BEGIN" "$HOSTCERT.nosni"; then - cn_nosni="$(get_cn_from_cert "$HOSTCERT.nosni")" - [[ -z "$cn_nosni" ]] && cn_nosni="no CN field in subject" + if [[ -n "$sni_used" ]]; then + # no cipher suites specified here. We just want the default vhost subject + $OPENSSL s_client $STARTTLS $BUGS -connect $NODEIP:$PORT $PROXY $OPTIMAL_PROTO 2>>$ERRFILE $HOSTCERT.nosni + if grep -q "\-\-\-\-\-BEGIN" "$HOSTCERT.nosni"; then + cn_nosni="$(get_cn_from_cert "$HOSTCERT.nosni")" + [[ -z "$cn_nosni" ]] && cn_nosni="no CN field in subject" + fi + debugme out "\"$NODE\" | \"$cn\" | \"$cn_nosni\"" + else + debugme out "\"$NODE\" | \"$cn\"" fi #FIXME: check for SSLv3/v2 and look whether it goes to a different CN (probably not polite) - debugme out "\"$NODE\" | \"$cn\" | \"$cn_nosni\"" - if [[ "$(toupper "$cn_nosni")" == "$(toupper "$cn")" ]]; then + if [[ -z "$sni_used" ]] || [[ "$(toupper "$cn_nosni")" == "$(toupper "$cn")" ]]; then outln elif [[ -z "$cn_nosni" ]]; then out " (request w/o SNI didn't succeed"; @@ -4483,7 +4490,9 @@ certificate_info() { has_dns_sans=true || has_dns_sans=false fi - if "$has_dns_sans" && [[ $trust_nosni -eq 4 ]]; then + if [[ -z "$sni_used" ]]; then + trustfinding_nosni="" + elif "$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)" @@ -4647,7 +4656,8 @@ run_server_defaults() { local -i i n local all_tls_extensions="" local -i certs_found=0 - local -a previous_hostcert previous_intermediates keysize cipher ocsp_response ocsp_response_status + local -a previous_hostcert previous_intermediates keysize cipher + local -a ocsp_response ocsp_response_status sni_used local -a ciphers_to_test success local cn_nosni cn_sni sans_nosni sans_sni san @@ -4768,6 +4778,7 @@ run_server_defaults() { ocsp_response_status[certs_found]=$(grep -a "OCSP Response Status" $TMPFILE) previous_hostcert[certs_found]=$newhostcert previous_intermediates[certs_found]=$(cat $TEMPDIR/intermediatecerts.pem) + [[ $n -ge 8 ]] && sni_used[certs_found]="" || sni_used[certs_found]="$SNI" fi fi fi @@ -4825,7 +4836,7 @@ run_server_defaults() { while [[ $i -le $certs_found ]]; do echo "${previous_hostcert[i]}" > $HOSTCERT echo "${previous_intermediates[i]}" > $TEMPDIR/intermediatecerts.pem - certificate_info "$i" "$certs_found" "${cipher[i]}" "${keysize[i]}" "${ocsp_response[i]}" "${ocsp_response_status[i]}" + certificate_info "$i" "$certs_found" "${cipher[i]}" "${keysize[i]}" "${ocsp_response[i]}" "${ocsp_response_status[i]}" "${sni_used[i]}" i=$((i + 1)) done } From d665f69c72f99b3c6750755d4796a04b1b1322bd Mon Sep 17 00:00:00 2001 From: Dirk Date: Thu, 1 Sep 2016 12:42:56 +0200 Subject: [PATCH 2/2] fix #436 --- testssl.sh | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/testssl.sh b/testssl.sh index 181e6d8..0b2f446 100755 --- a/testssl.sh +++ b/testssl.sh @@ -170,7 +170,9 @@ FAST_STARTTLS=${FAST_STARTTLS:-true} #at the cost of reliabilty decrease the 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 + HSTS_MIN=$((HSTS_MIN * 86400)) # correct to seconds HPKP_MIN=${HPKP_MIN:-30} # >=30 days should be ok for HPKP_MIN, practical hints? + HPKP_MIN=$((HPKP_MIN * 86400)) # correct to seconds 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 @@ -912,6 +914,7 @@ run_hsts() { if [[ $? -eq 0 ]]; then grep -aciw '^Strict-Transport-Security' $HEADERFILE | egrep -waq "1" || out "(two HSTS header, using 1st one) " hsts_age_sec=$(sed -e 's/[^0-9]*//g' $TMPFILE | head -1) + debugme echo "hsts_age_sec: $hsts_age_sec" if [[ -n $hsts_age_sec ]]; then hsts_age_days=$(( hsts_age_sec / 86400)) else @@ -920,15 +923,14 @@ run_hsts() { if [[ $hsts_age_days -eq -1 ]]; then pr_svrty_medium "HSTS max-age is required but missing. Setting 15552000 s (180 days) or more is recommended" fileout "hsts_time" "MEDIUM" "HSTS max-age missing. 15552000 s (180 days) or more recommnded" - elif [[ $hsts_age_days -eq 0 ]]; then + elif [[ $hsts_age_sec -eq 0 ]]; then pr_svrty_medium "HSTS max-age is set to 0. HSTS is disabled" fileout "hsts_time" "MEDIUM" "HSTS max-age set to 0. HSTS is disabled" - elif [[ $hsts_age_days -gt $HSTS_MIN ]]; then + elif [[ $hsts_age_sec -gt $HSTS_MIN ]]; then pr_done_good "$hsts_age_days days" ; out "=$hsts_age_sec s" fileout "hsts_time" "OK" "HSTS timeout $hsts_age_days days (=$hsts_age_sec seconds) > $HSTS_MIN days" else - out "$hsts_age_sec s = " - pr_svrty_medium "$hsts_age_days days, <$HSTS_MIN days is too short" + pr_svrty_medium "$hsts_age_sec s = $hsts_age_days days is too short ( >=$HSTS_MIN s recommended)" fileout "hsts_time" "MEDIUM" "HSTS timeout too short. $hsts_age_days days (=$hsts_age_sec seconds) < $HSTS_MIN days" fi if includeSubDomains "$TMPFILE"; then @@ -8682,4 +8684,4 @@ fi exit $? -# $Id: testssl.sh,v 1.533 2016/08/28 19:41:29 dirkw Exp $ +# $Id: testssl.sh,v 1.535 2016/09/01 10:42:53 dirkw Exp $