From f0c9875696b52fd6d52263e792a7db05c3068c6b Mon Sep 17 00:00:00 2001 From: David Cooper Date: Fri, 19 Jan 2018 11:31:45 -0500 Subject: [PATCH 1/6] Check keyUsage and extended key usage extensions This commit prints the contents of the keyUsage and extended key usage extensions in certificates and checks the public keys in the certificates are not being used in a manner that is inconsistent with these extensions. --- testssl.sh | 56 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 9 deletions(-) diff --git a/testssl.sh b/testssl.sh index c955fe4..e56f4c4 100755 --- a/testssl.sh +++ b/testssl.sh @@ -6346,11 +6346,12 @@ certificate_info() { local -i number_of_certificates=$2 local cipher=$3 local cert_keysize=$4 - local ocsp_response=$5 - local ocsp_response_status=$6 - local sni_used=$7 - local ct="$8" - local cert_sig_algo cert_sig_hash_algo cert_key_algo + local cert_type="$5" + local ocsp_response=$6 + local ocsp_response_status=$7 + local sni_used=$8 + local ct="$9" + local cert_sig_algo cert_sig_hash_algo cert_key_algo cert_keyusage cert_ext_keyusage local expire days2expire secs2warn ocsp_uri crl local startdate enddate issuer_CN issuer_C issuer_O issuer sans san all_san="" cn local issuer_DC issuerfinding cn_nosni="" @@ -6568,6 +6569,36 @@ certificate_info() { fi fi + out "$indent"; pr_bold " Server key usage "; + cert_keyusage=$($OPENSSL x509 -text -noout -in $HOSTCERT 2>>$ERRFILE | grep -A 1 "X509v3 Key Usage:" | tail -n +2 | sed 's/^[ \t]*//') + if [[ -n "$cert_keyusage" ]]; then + outln "$cert_keyusage" + if ( [[ " $cert_type " =~ " RSASig " ]] || [[ " $cert_type " =~ " DSA " ]] || [[ " $cert_type " =~ " ECDSA " ]] ) && \ + [[ ! "$cert_keyusage" =~ "Digital Signature" ]]; then + prln_svrty_high "$indent -- certificate incorrectly used for digital signatures" + fi + if [[ " $cert_type " =~ " RSAKMK " ]] && [[ ! "$cert_keyusage" =~ "Key Encipherment" ]]; then + prln_svrty_high "$indent -- certificate incorrectly used for key encipherment" + fi + if ( [[ " $cert_type " =~ " DH " ]] || [[ " $cert_type " =~ " ECDH " ]] ) && \ + [[ ! "$cert_keyusage" =~ "Key Agreement" ]]; then + prln_svrty_high "$indent -- certificate incorrectly used for key agreement" + fi + else + outln "(absent)" + fi + + out "$indent"; pr_bold " Server extended key usage "; + cert_ext_keyusage="$($OPENSSL x509 -noout -text -in $HOSTCERT 2>>$ERRFILE | grep -A 1 "X509v3 Extended Key Usage: " | tail -1 | sed 's/^[ \t]*//')" + if [[ -n "$cert_ext_keyusage" ]]; then + outln "$cert_ext_keyusage" + if [[ ! "$cert_ext_keyusage" =~ "TLS Web Server Authentication" ]] && [[ ! "$cert_ext_keyusage" =~ "Any Extended Key Usage" ]]; then + prln_svrty_high "$indent -- certificate incorrectly used for TLS Web Server Authentication" + fi + else + outln "(absent)" + fi + out "$indent"; pr_bold " Fingerprint / Serial " cert_fingerprint_sha1="$($OPENSSL x509 -noout -in $HOSTCERT -fingerprint -sha1 2>>$ERRFILE | sed 's/Fingerprint=//' | sed 's/://g')" cert_fingerprint_serial="$($OPENSSL x509 -noout -in $HOSTCERT -serial 2>>$ERRFILE | sed 's/serial=//')" @@ -7005,9 +7036,9 @@ run_server_defaults() { local sessticket_lifetime_hint="" lifetime unit local -i i n local -i certs_found=0 - local -a previous_hostcert previous_intermediates keysize cipher + local -a previous_hostcert previous_hostcert_type previous_intermediates keysize cipher local -a ocsp_response ocsp_response_status sni_used tls_version ct - local -a ciphers_to_test + local -a ciphers_to_test certificate_type local -a -i success local cn_nosni cn_sni sans_nosni sans_sni san tls_extensions @@ -7035,6 +7066,10 @@ run_server_defaults() { ciphers_to_test[5]="aECDH" ciphers_to_test[6]="aECDSA" ciphers_to_test[7]="aGOST" + certificate_type[1]="RSASig" ; certificate_type[2]="RSAKMK" + certificate_type[3]="DSA"; certificate_type[4]="DH" + certificate_type[5]="ECDH" ; certificate_type[6]="ECDSA" + certificate_type[7]="GOST" for (( n=1; n <= 14 ; n++ )); do # Some servers use a different certificate if the ClientHello @@ -7043,7 +7078,7 @@ run_server_defaults() { # 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]}" + [[ ${success[n-7]} -eq 0 ]] && ciphers_to_test[n]="${ciphers_to_test[n-7]}" && certificate_type[n]="${certificate_type[n-7]}" fi if [[ -n "${ciphers_to_test[n]}" ]] && [[ $(count_ciphers $($OPENSSL ciphers "${ciphers_to_test[n]}" 2>>$ERRFILE)) -ge 1 ]]; then @@ -7129,6 +7164,9 @@ run_server_defaults() { previous_intermediates[certs_found]=$(cat $TEMPDIR/intermediatecerts.pem) [[ $n -ge 8 ]] && sni_used[certs_found]="" || sni_used[certs_found]="$SNI" tls_version[certs_found]="$DETECTED_TLS_VERSION" + previous_hostcert_type[certs_found]=" ${certificate_type[n]}" + else + previous_hostcert_type[i]+=" ${certificate_type[n]}" fi fi fi @@ -7260,7 +7298,7 @@ run_server_defaults() { for (( i=1; i <= certs_found; i++ )); 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]}" "${sni_used[i]}" "${ct[i]}" + certificate_info "$i" "$certs_found" "${cipher[i]}" "${keysize[i]}" "${previous_hostcert_type[i]}" "${ocsp_response[i]}" "${ocsp_response_status[i]}" "${sni_used[i]}" "${ct[i]}" done } From f5c2199369d53a8cda10657ede361c9bf097856e Mon Sep 17 00:00:00 2001 From: Dirk Date: Mon, 22 Jan 2018 19:50:50 +0100 Subject: [PATCH 2/6] Polishing #965 Add fileout() to #965. This commit also contains a change which needs to be commited before: separation of ``json_prefix`` from ``json_postfix``. Open issue: sed in openssl x509 statments look GNUish ([ \t]). Needs clarification. --- testssl.sh | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/testssl.sh b/testssl.sh index e56f4c4..4500863 100755 --- a/testssl.sh +++ b/testssl.sh @@ -6352,6 +6352,7 @@ certificate_info() { local sni_used=$8 local ct="$9" local cert_sig_algo cert_sig_hash_algo cert_key_algo cert_keyusage cert_ext_keyusage + local outok=true local expire days2expire secs2warn ocsp_uri crl local startdate enddate issuer_CN issuer_C issuer_O issuer sans san all_san="" cn local issuer_DC issuerfinding cn_nosni="" @@ -6570,33 +6571,55 @@ certificate_info() { fi out "$indent"; pr_bold " Server key usage "; + outok=true + json_prefix="cert_key_usage" cert_keyusage=$($OPENSSL x509 -text -noout -in $HOSTCERT 2>>$ERRFILE | grep -A 1 "X509v3 Key Usage:" | tail -n +2 | sed 's/^[ \t]*//') if [[ -n "$cert_keyusage" ]]; then outln "$cert_keyusage" if ( [[ " $cert_type " =~ " RSASig " ]] || [[ " $cert_type " =~ " DSA " ]] || [[ " $cert_type " =~ " ECDSA " ]] ) && \ [[ ! "$cert_keyusage" =~ "Digital Signature" ]]; then prln_svrty_high "$indent -- certificate incorrectly used for digital signatures" + fileout "${json_prefix}${json_postfix}" "HIGH" "Certificate incorrectly used for digital signatures: \"$cert_keyusage\"" + outok=false fi if [[ " $cert_type " =~ " RSAKMK " ]] && [[ ! "$cert_keyusage" =~ "Key Encipherment" ]]; then prln_svrty_high "$indent -- certificate incorrectly used for key encipherment" + fileout "${json_prefix}${json_postfix}" "HIGH" "Certificate incorrectly used for key encipherment: \"$cert_keyusage\"" + outok=false fi if ( [[ " $cert_type " =~ " DH " ]] || [[ " $cert_type " =~ " ECDH " ]] ) && \ [[ ! "$cert_keyusage" =~ "Key Agreement" ]]; then prln_svrty_high "$indent -- certificate incorrectly used for key agreement" + fileout "${json_prefix}${json_postfix}" "HIGH" "Certificate incorrectly used for key agreement: \"$cert_keyusage\"" + outok=false fi else - outln "(absent)" + outln "--" + fileout "${json_prefix}key_usage" "INFO" "No server key usage information" + outok=false + fi + if "$outok"; then + fileout "${json_prefix}key_usage" "INFO" "Server key usage information: $cert_keyusage" fi out "$indent"; pr_bold " Server extended key usage "; + json_prefix="cert_extended_key_usage" + outok=true cert_ext_keyusage="$($OPENSSL x509 -noout -text -in $HOSTCERT 2>>$ERRFILE | grep -A 1 "X509v3 Extended Key Usage: " | tail -1 | sed 's/^[ \t]*//')" if [[ -n "$cert_ext_keyusage" ]]; then outln "$cert_ext_keyusage" if [[ ! "$cert_ext_keyusage" =~ "TLS Web Server Authentication" ]] && [[ ! "$cert_ext_keyusage" =~ "Any Extended Key Usage" ]]; then prln_svrty_high "$indent -- certificate incorrectly used for TLS Web Server Authentication" + fileout "${json_prefix}${json_postfix}" "HIGH" "Certificate incorrectly used for TLS Web Server Authentication: \"$cert_ext_keyusage\"" + outok=false fi else - outln "(absent)" + outln "--" + fileout "${json_prefix}${json_postfix}" "INFO" "No server extended key usage information" + outok=false + fi + if "$outok"; then + fileout "${json_prefix}${json_postfix}" "INFO" "Server extended key usage: \"cert_ext_keyusage\"" fi out "$indent"; pr_bold " Fingerprint / Serial " From 0ec5586dfb8c14ac112019cc0605d15169af0db4 Mon Sep 17 00:00:00 2001 From: Dirk Date: Mon, 22 Jan 2018 23:56:03 +0100 Subject: [PATCH 3/6] Changing JSON objects in server defaults ATTENTION: breaking change!! The server default run had several JSON objects which weren't, looking at just the ID, either clear or contained a redundant explanation in "finding". Purely certificate related JSON objects are now having the id "cert_" like cert_CN or cert_SAN. This commit changes all this, also it avoids another colon in finding (see #830). Also the implicit strategy "output for the screen s followed by only one output with fileout" has been relaxed -- which results on more, better parsable JSON objects. Some example of the changes: Old: ---- { "id" : "Server Certificate #1 fingerprint", "severity" : "INFO", "finding" : "Fingerprints / Serial: SHA1 2940BC13ECF7DAF30B9084CC734C3B971D73B3BB / 01BFD1DC15006E0ABBA7C670FF5E1101, SHA256 30BA61012FFE7CEAAF9A148A0CB0C5C852A9C04F4B1C27DB6 EFA9919C7F49CCF" } [..] { "id" : "Server Certificate #2 ocsp_stapling", "severity" : "OK", "finding" : "OCSP stapling : offered" } New: ---- { "id" : "cert_key_size ", "severity" : "INFO", "finding" : "Server keys 2048 bits" },{ "id" : "cert_fingerprint_SHA1 ", "severity" : "INFO", "finding" : "2940BC13ECF7DAF30B9084CC734C3B971D73B3BB" },{ "id" : "cert_fingerprint_SHA256 ", "severity" : "INFO", "finding" : "30BA61012FFE7CEAAF9A148A0CB0C5C852A9C04F4B1C27DB6EFA9919C7F49CCF" },{ "id" : "cert_serial ", "severity" : "INFO", "finding" : "01BFD1DC15006E0ABBA7C670FF5E1101" } [..] { "id" : "OCSP_stapling ", "severity" : "OK", "finding" : "offered" } This PR also fixes the JSON output where for "OCSP must staple" the id was just 'id" : "OCSP must staple: ocsp_must_staple",' for multiple server certificates without the certificate number. As far as the code is concerned: $json_prefix should be a variable which is used for the id object. If there was more then one certificates for a single host detected, $json_postfix carries the certificate number. Unit tests need to be fixed -- if possible. --- testssl.sh | 256 +++++++++++++++++++++++++++++------------------------ 1 file changed, 142 insertions(+), 114 deletions(-) diff --git a/testssl.sh b/testssl.sh index c955fe4..50db43d 100755 --- a/testssl.sh +++ b/testssl.sh @@ -1462,31 +1462,32 @@ service_detection() { fi out " Service detected: $CORRECT_SPACES" + json_prefix="service" case $SERVICE in HTTP) out " $SERVICE" - fileout "service" "INFO" "Service detected: $SERVICE" + fileout "${json_prefix}" "INFO" "$SERVICE" ret=0 ;; IMAP|POP|SMTP|NNTP|MongoDB) out " $SERVICE, thus skipping HTTP specific checks" - fileout "service" "INFO" "Service detected: $SERVICE, thus skipping HTTP specific checks" + fileout "${json_prefix}" "INFO" "$SERVICE, thus skipping HTTP specific checks" ret=0 ;; *) if "$CLIENT_AUTH"; then out " certificate-based authentication => skipping all HTTP checks" echo "certificate-based authentication => skipping all HTTP checks" >$TMPFILE - fileout "service" "INFO" "certificate-based authentication => skipping all HTTP checks" + fileout "${json_prefix}" "INFO" "certificate-based authentication => skipping all HTTP checks" else out " Couldn't determine what's running on port $PORT" if "$ASSUME_HTTP"; then SERVICE=HTTP out " -- ASSUME_HTTP set though" - fileout "service" "DEBUG" "Couldn't determine service, --ASSUME_HTTP set" + fileout "${json_prefix}" "DEBUG" "Couldn't determine service -- ASSUME_HTTP set" ret=0 else out ", assuming no HTTP service => skipping all HTTP checks" - fileout "service" "DEBUG" "Couldn't determine service, skipping all HTTP checks" + fileout "${json_prefix}" "DEBUG" "Couldn't determine service, skipping all HTTP checks" ret=1 fi fi @@ -5715,7 +5716,8 @@ verify_retcode_helper() { # arg1: number of certificate if provided >1 determine_trust() { - local json_prefix=$1 + local json_prefix="$1" + local json_postfix="$2" local -i i=1 local -i num_ca_bundles=0 local bundle_fname="" @@ -5730,16 +5732,17 @@ determine_trust() { local -i certificates_provided=1+$(grep -c "\-\-\-\-\-BEGIN CERTIFICATE\-\-\-\-\-" $TEMPDIR/intermediatecerts.pem) local addtl_warning - # If $json_prefix is not empty, then there is more than one certificate + # If $json_postfix is not empty, then there is more than one certificate # and the output should should be indented by two more spaces. - [[ -n $json_prefix ]] && spaces=" " + [[ -n $json_postfix ]] && spaces=" " case $OSSL_VER_MAJOR.$OSSL_VER_MINOR in 1.0.2|1.1.0|1.1.1|2.3.*|2.2.*|2.1.*) # 2.x is LibreSSL. 2.1.1 was tested to work, below is not sure : ;; - *) addtl_warning="(Your $OPENSSL <= 1.0.2 might be too unreliable to determine trust)" - fileout "${json_prefix}chain_of_trust_Problem" "WARN" "$addtl_warning" + *) addtl_warning="Your $OPENSSL <= 1.0.2 might be too unreliable to determine trust" + fileout "${json_prefix}${json_postfix}" "WARN" "$addtl_warning" + addtl_warning="(${addtl_warning})" ;; esac debugme tmln_out @@ -5784,8 +5787,11 @@ determine_trust() { if "$all_ok"; then # 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}chain_of_trust" "OK" "All certificate trust checks passed. $addtl_warning" + # we did to stdout the warning above already, so we could stay here with OK: + [[ -z "$addtl_warning" ]] && \ + fileout "${json_prefix}${json_postfix}" "OK" "All certificate trust checks passed" || \ + fileout "${json_prefix}${json_postfix}" "OK" "All certificate trust checks passed. $addtl_warning" + # The "." is otherwise confusing else # at least one failed pr_svrty_critical "NOT ok" @@ -5798,7 +5804,7 @@ determine_trust() { else out "$code" fi - fileout "${json_prefix}chain_of_trust" "CRITICAL" "All certificate trust checks failed: $code. $addtl_warning" + fileout "${json_prefix}${json_postfix}" "CRITICAL" "All certificate trust checks failed: $code. $addtl_warning" else # is one ok and the others not ==> display the culprit store if "$some_ok"; then @@ -5826,7 +5832,7 @@ determine_trust() { [[ "$DEBUG" -eq 0 ]] && tm_out "$spaces" pr_done_good "OK: $ok_was" fi - fileout "${json_prefix}chain_of_trust" "CRITICAL" "Some certificate trust checks failed : OK : $ok_was NOT ok: $notok_was $addtl_warning" + fileout "${json_prefix}${json_postfix}" "CRITICAL" "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 @@ -5834,11 +5840,12 @@ determine_trust() { return 0 } -# not handled: Root CA supplied (contains anchor) +# not handled: Root CA supplied ("contains anchor" in SSLlabs terminology) tls_time() { local now difftime local spaces=" " + local json_prefix="TLS_time" pr_bold " TLS clock skew" ; out "$spaces" TLS_DIFFTIME_SET=true # this is a switch whether we want to measure the remote TLS_TIME @@ -5852,17 +5859,17 @@ tls_time() { if [[ "${#difftime}" -gt 5 ]]; then # openssl >= 1.0.1f fills this field with random values! --> good for possible fingerprint out "Random values, no fingerprinting possible " - fileout "tls_time" "INFO" "Your TLS time seems to be filled with random values to prevent fingerprinting" + fileout "${json_prefix}" "INFO" "The server's TLS time seems to be filled with random values to prevent fingerprinting" else [[ $difftime != "-"* ]] && [[ $difftime != "0" ]] && difftime="+$difftime" out "$difftime"; out " sec from localtime"; - fileout "tls_time" "INFO" "Your TLS time is skewed from your localtime by $difftime seconds" + fileout "${json_prefix}" "INFO" "The server's TLS time is skewed from your localtime by $difftime seconds" fi debugme tm_out "$TLS_TIME" outln else outln "SSLv3 through TLS 1.2 didn't return a timestamp" - fileout "tls_time" "INFO" "No TLS timestamp returned by SSLv3 through TLSv1.2" + fileout "${json_prefix}" "INFO" "No TLS timestamp returned by SSLv3 through TLSv1.2" fi TLS_DIFFTIME_SET=false # reset the switch to save calls to date and friend in tls_sockets() return 0 @@ -6230,7 +6237,8 @@ compare_server_name_to_cert() } must_staple() { - local json_prefix="OCSP must staple: " + local json_prefix="OCSP_must_staple" + local json_postfix="$1" local provides_stapling="$2" local cert extn local -i extn_len @@ -6266,14 +6274,14 @@ must_staple() { if "$supported"; then if "$provides_stapling"; then prln_done_good "supported" - fileout "${json_prefix}ocsp_must_staple" "OK" "OCSP must staple : supported" + fileout "${json_prefix}${json_postfix}" "OK" "supported" else prln_svrty_high "requires OCSP stapling (NOT ok)" - fileout "${json_prefix}" "HIGH" "must staple extension detected but no OCSP stapling provided" + fileout "${json_prefix}${json_postfix}" "HIGH" "must staple extension detected but no OCSP stapling provided" fi else outln "no" - fileout "${json_prefix}ocsp_must_staple" "INFO" "OCSP must staple : no" + fileout "${json_prefix}${json_postfix}" "INFO" "no" fi } @@ -6354,7 +6362,7 @@ certificate_info() { local expire days2expire secs2warn ocsp_uri crl local startdate enddate issuer_CN issuer_C issuer_O issuer sans san all_san="" cn local issuer_DC issuerfinding cn_nosni="" - local cert_fingerprint_sha1 cert_fingerprint_sha2 cert_fingerprint_serial + local cert_fingerprint_sha1 cert_fingerprint_sha2 cert_serial local policy_oid local spaces="" local -i trust_sni=0 trust_nosni=0 @@ -6364,7 +6372,8 @@ certificate_info() { 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 + local json_postfix="" # string to place at the end of JSON IDs when there is more than one certificate + local json_prefix="" # string to place at beginning of JSON IDs local indent="" local days2warn2=$DAYS2WARN2 local days2warn1=$DAYS2WARN1 @@ -6378,7 +6387,7 @@ certificate_info() { 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 " + json_postfix=" " spaces=" " else spaces=" " @@ -6390,6 +6399,7 @@ certificate_info() { cert_key_algo="${cert_key_algo// /}" out "$indent" ; pr_bold " Signature Algorithm " + json_prefix="cert_sig_algorithm" case $cert_sig_algo in sha1WithRSAEncryption) pr_svrty_medium "SHA1 with RSA" @@ -6397,110 +6407,111 @@ certificate_info() { out " -- besides: users will receive a "; pr_svrty_high "strong browser WARNING" fi outln - fileout "${json_prefix}algorithm" "MEDIUM" "Signature Algorithm: SHA1 with RSA" + fileout "${json_prefix}${json_postfix}" "MEDIUM" "SHA1 with RSA" ;; sha224WithRSAEncryption) outln "SHA224 with RSA" - fileout "${json_prefix}algorithm" "INFO" "Signature Algorithm: SHA224 with RSA" + fileout "${json_prefix}${json_postfix}" "INFO" "SHA224 with RSA" ;; sha256WithRSAEncryption) prln_done_good "SHA256 with RSA" - fileout "${json_prefix}algorithm" "OK" "Signature Algorithm: SHA256 with RSA" + fileout "${json_prefix}${json_postfix}" "OK" "SHA256 with RSA" ;; sha384WithRSAEncryption) prln_done_good "SHA384 with RSA" - fileout "${json_prefix}algorithm" "OK" "Signature Algorithm: SHA384 with RSA" + fileout "${json_prefix}${json_postfix}" "OK" "SHA384 with RSA" ;; sha512WithRSAEncryption) prln_done_good "SHA512 with RSA" - fileout "${json_prefix}algorithm" "OK" "Signature Algorithm: SHA512 with RSA" + fileout "${json_prefix}${json_postfix}" "OK" "SHA512 with RSA" ;; ecdsa-with-SHA1) prln_svrty_medium "ECDSA with SHA1" - fileout "${json_prefix}algorithm" "MEDIUM" "Signature Algorithm: ECDSA with SHA1" + fileout "${json_prefix}${json_postfix}" "MEDIUM" "ECDSA with SHA1" ;; ecdsa-with-SHA224) outln "ECDSA with SHA224" - fileout "${json_prefix}algorithm" "INFO" "Signature Algorithm: ECDSA with SHA224" + fileout "${json_prefix}${json_postfix}" "INFO" "ECDSA with SHA224" ;; ecdsa-with-SHA256) prln_done_good "ECDSA with SHA256" - fileout "${json_prefix}algorithm" "OK" "Signature Algorithm: ECDSA with SHA256" + fileout "${json_prefix}${json_postfix}" "OK" "ECDSA with SHA256" ;; ecdsa-with-SHA384) prln_done_good "ECDSA with SHA384" - fileout "${json_prefix}algorithm" "OK" "Signature Algorithm: ECDSA with SHA384" + fileout "${json_prefix}${json_postfix}" "OK" "ECDSA with SHA384" ;; ecdsa-with-SHA512) prln_done_good "ECDSA with SHA512" - fileout "${json_prefix}algorithm" "OK" "Signature Algorithm: ECDSA with SHA512" + fileout "${json_prefix}${json_postfix}" "OK" "ECDSA with SHA512" ;; dsaWithSHA1) prln_svrty_medium "DSA with SHA1" - fileout "${json_prefix}algorithm" "MEDIUM" "Signature Algorithm: DSA with SHA1" + fileout "${json_prefix}${json_postfix}" "MEDIUM" "DSA with SHA1" ;; dsa_with_SHA224) outln "DSA with SHA224" - fileout "${json_prefix}algorithm" "INFO" "Signature Algorithm: DSA with SHA224" + fileout "${json_prefix}${json_postfix}" "INFO" "DSA with SHA224" ;; dsa_with_SHA256) prln_done_good "DSA with SHA256" - fileout "${json_prefix}algorithm" "OK" "Signature Algorithm: DSA with SHA256" + fileout "${json_prefix}${json_postfix}" "OK" "DSA with SHA256" ;; rsassaPss) cert_sig_hash_algo="$($OPENSSL x509 -in $HOSTCERT -noout -text 2>>$ERRFILE | grep -A 1 "Signature Algorithm" | head -2 | tail -1 | sed 's/^.*Hash Algorithm: //')" case $cert_sig_hash_algo in sha1) prln_svrty_medium "RSASSA-PSS with SHA1" - fileout "${json_prefix}algorithm" "MEDIUM" "Signature Algorithm: RSASSA-PSS with SHA1" + fileout "${json_prefix}${json_postfix}" "MEDIUM" "RSASSA-PSS with SHA1" ;; sha224) outln "RSASSA-PSS with SHA224" - fileout "${json_prefix}algorithm" "INFO" "Signature Algorithm: RSASSA-PSS with SHA224" + fileout "${json_prefix}${json_postfix}" "INFO" "RSASSA-PSS with SHA224" ;; sha256) prln_done_good "RSASSA-PSS with SHA256" - fileout "${json_prefix}algorithm" "OK" "Signature Algorithm: RSASSA-PSS with SHA256" + fileout "${json_prefix}${json_postfix}" "OK" "RSASSA-PSS with SHA256" ;; sha384) prln_done_good "RSASSA-PSS with SHA384" - fileout "${json_prefix}algorithm" "OK" "Signature Algorithm: RSASSA-PSS with SHA384" + fileout "${json_prefix}${json_postfix}" "OK" "RSASSA-PSS with SHA384" ;; sha512) prln_done_good "RSASSA-PSS with SHA512" - fileout "${json_prefix}algorithm" "OK" "Signature Algorithm: RSASSA-PSS with SHA512" + fileout "${json_prefix}${json_postfix}" "OK" "RSASSA-PSS with SHA512" ;; *) out "RSASSA-PSS with $cert_sig_hash_algo" prln_warning " (Unknown hash algorithm)" - fileout "${json_prefix}algorithm" "DEBUG" "Signature Algorithm: RSASSA-PSS with $cert_sig_hash_algo" + fileout "${json_prefix}${json_postfix}" "DEBUG" "RSASSA-PSS with $cert_sig_hash_algo" esac ;; md2*) prln_svrty_critical "MD2" - fileout "${json_prefix}algorithm" "CRITICAL" "Signature Algorithm: MD2" + fileout "${json_prefix}${json_postfix}" "CRITICAL" "MD2" ;; md4*) prln_svrty_critical "MD4" - fileout "${json_prefix}algorithm" "CRITICAL" "Signature Algorithm: MD4" + fileout "${json_prefix}${json_postfix}" "CRITICAL" "MD4" ;; md5*) prln_svrty_critical "MD5" - fileout "${json_prefix}algorithm" "CRITICAL" "Signature Algorithm: MD5" + fileout "${json_prefix}${json_postfix}" "CRITICAL" "MD5" ;; *) out "$cert_sig_algo (" pr_warning "FIXME: can't tell whether this is good or not" outln ")" - fileout "${json_prefix}algorithm" "DEBUG" "Signature Algorithm: $cert_sig_algo" + fileout "${json_prefix}${json_postfix}" "DEBUG" "$cert_sig_algo" ;; esac # old, but interesting: https://blog.hboeck.de/archives/754-Playing-with-the-EFF-SSL-Observatory.html out "$indent"; pr_bold " Server key size " + json_prefix="cert_key_size" if [[ -z "$cert_keysize" ]]; then outln "(couldn't determine)" - fileout "${json_prefix}key_size" "WARN" "Server keys size cannot be determined" + fileout "${json_prefix}${json_postfix}" "Server keys size cannot be determined" else case $cert_key_algo in *RSA*|*rsa*) out "RSA ";; @@ -6517,22 +6528,22 @@ certificate_info() { if [[ $cert_key_algo =~ ecdsa ]] || [[ $cert_key_algo =~ ecPublicKey ]]; then if [[ "$cert_keysize" -le 110 ]]; then # a guess pr_svrty_critical "$cert_keysize" - fileout "${json_prefix}key_size" "CRITICAL" "Server keys $cert_keysize EC bits" + fileout "${json_prefix}${json_postfix}" "CRITICAL" "Server keys $cert_keysize EC bits" elif [[ "$cert_keysize" -le 123 ]]; then # a guess pr_svrty_high "$cert_keysize" - fileout "${json_prefix}key_size" "HIGH" "Server keys $cert_keysize EC bits" + fileout "${json_prefix}${json_postfix}" "HIGH" "Server keys $cert_keysize EC bits" elif [[ "$cert_keysize" -le 163 ]]; then pr_svrty_medium "$cert_keysize" - fileout "${json_prefix}key_size" "MEDIUM" "Server keys $cert_keysize EC bits" + fileout "${json_prefix}${json_postfix}" "MEDIUM" "Server keys $cert_keysize EC bits" elif [[ "$cert_keysize" -le 224 ]]; then out "$cert_keysize" - fileout "${json_prefix}key_size" "INFO" "Server keys $cert_keysize EC bits" + fileout "${json_prefix}${json_postfix}" "INFO" "Server keys $cert_keysize EC bits" elif [[ "$cert_keysize" -le 533 ]]; then pr_done_good "$cert_keysize" - fileout "${json_prefix}key_size" "OK" "Server keys $cert_keysize EC bits" + fileout "${json_prefix}${json_postfix}" "OK" "Server keys $cert_keysize EC bits" else out "keysize: $cert_keysize (not expected, FIXME)" - fileout "${json_prefix}key_size" "DEBUG" "Server keys $cert_keysize bits (not expected)" + fileout "${json_prefix}${json_postfix}" "DEBUG" "Server keys $cert_keysize bits (not expected)" fi outln " bits" elif [[ $cert_key_algo = *RSA* ]] || [[ $cert_key_algo = *rsa* ]] || [[ $cert_key_algo = *dsa* ]] || \ @@ -6540,41 +6551,46 @@ certificate_info() { if [[ "$cert_keysize" -le 512 ]]; then pr_svrty_critical "$cert_keysize" outln " bits" - fileout "${json_prefix}key_size" "CRITICAL" "Server keys $cert_keysize bits" + fileout "${json_prefix}${json_postfix}" "CRITICAL" "Server keys $cert_keysize bits" elif [[ "$cert_keysize" -le 768 ]]; then pr_svrty_high "$cert_keysize" outln " bits" - fileout "${json_prefix}key_size" "HIGH" "Server keys $cert_keysize bits" + fileout "${json_prefix}${json_postfix}" "HIGH" "Server keys $cert_keysize bits" elif [[ "$cert_keysize" -le 1024 ]]; then pr_svrty_medium "$cert_keysize" outln " bits" - fileout "${json_prefix}key_size" "MEDIUM" "Server keys $cert_keysize bits" + fileout "${json_prefix}${json_postfix}" "MEDIUM" "Server keys $cert_keysize bits" elif [[ "$cert_keysize" -le 2048 ]]; then outln "$cert_keysize bits" - fileout "${json_prefix}key_size" "INFO" "Server keys $cert_keysize bits" + fileout "${json_prefix}${json_postfix}" "INFO" "Server keys $cert_keysize bits" elif [[ "$cert_keysize" -le 4096 ]]; then pr_done_good "$cert_keysize" - fileout "${json_prefix}key_size" "OK" "Server keys $cert_keysize bits" + fileout "${json_prefix}${json_postfix}" "OK" "Server keys $cert_keysize bits" outln " bits" else pr_warning "weird key size: $cert_keysize bits"; outln " (could cause compatibility problems)" - fileout "${json_prefix}key_size" "WARN" "Server keys $cert_keysize bits (Odd)" + fileout "${json_prefix}${json_postfix}" "WARN" "Server keys $cert_keysize bits (Odd)" fi else out "$cert_keysize bits (" pr_warning "FIXME: can't tell whether this is good or not" outln ")" - fileout "${json_prefix}key_size" "WARN" "Server keys $cert_keysize bits (unknown signature algorithm)" + fileout "${json_prefix}${json_postfix}" "WARN" "Server keys $cert_keysize bits (unknown signature algorithm)" fi fi out "$indent"; pr_bold " Fingerprint / Serial " cert_fingerprint_sha1="$($OPENSSL x509 -noout -in $HOSTCERT -fingerprint -sha1 2>>$ERRFILE | sed 's/Fingerprint=//' | sed 's/://g')" - cert_fingerprint_serial="$($OPENSSL x509 -noout -in $HOSTCERT -serial 2>>$ERRFILE | sed 's/serial=//')" + fileout "cert_fingerprint_SHA1${json_postfix}" "INFO" "${cert_fingerprint_sha1//SHA1 /}" + cert_fingerprint_sha2="$($OPENSSL x509 -noout -in $HOSTCERT -fingerprint -sha256 2>>$ERRFILE | sed 's/Fingerprint=//' | sed 's/://g' )" - outln "$cert_fingerprint_sha1 / $cert_fingerprint_serial" + fileout "cert_fingerprint_SHA256${json_postfix}" "INFO" "${cert_fingerprint_sha2//SHA256 /}" + + cert_serial="$($OPENSSL x509 -noout -in $HOSTCERT -serial 2>>$ERRFILE | sed 's/serial=//')" + outln "$cert_fingerprint_sha1 / $cert_serial" outln "$spaces$cert_fingerprint_sha2" - fileout "${json_prefix}fingerprint" "INFO" "Fingerprints / Serial: $cert_fingerprint_sha1 / $cert_fingerprint_serial, $cert_fingerprint_sha2" + + fileout "cert_serial${json_postfix}" "INFO" "$cert_serial" [[ -z $CERT_FINGERPRINT_SHA2 ]] && \ CERT_FINGERPRINT_SHA2="$cert_fingerprint_sha2" || CERT_FINGERPRINT_SHA2="$cert_fingerprint_sha2 $CERT_FINGERPRINT_SHA2" @@ -6594,6 +6610,8 @@ certificate_info() { cnfinding="$cn" cnok="INFO" fi + fileout "cert_CN${json_postfix}" "$cnok" "$cnfinding" + cnfinding="" if [[ -n "$sni_used" ]]; then if grep -q "\-\-\-\-\-BEGIN" "$HOSTCERT.nosni"; then @@ -6605,27 +6623,26 @@ certificate_info() { debugme tm_out "\"$NODE\" | \"$cn\"" fi -#FIXME: check for SSLv3/v2 and look whether it goes to a different CN (probably not polite) - if [[ -z "$sni_used" ]] || [[ "$(toupper "$cn_nosni")" == "$(toupper "$cn")" ]]; then outln + cnfinding="$cn" elif [[ -z "$cn_nosni" ]]; then out " (request w/o SNI didn't succeed"; - cnfinding+=" (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+=")" + cnfinding+="" elif [[ "$cn_nosni" == *"no CN field"* ]]; then outln ", (request w/o SNI: $cn_nosni)" - cnfinding+=", (request w/o SNI: $cn_nosni)" + cnfinding="$cn_nosni" else out " (CN in response to request w/o SNI: "; pr_italic "$cn_nosni"; outln ")" - cnfinding+=" (CN in response to request w/o SNI: \"$cn_nosni\")" + cnfinding="$cn_nosni" fi - fileout "${json_prefix}cn" "$cnok" "$cnfinding" + fileout "cert_CN_without_SNI${json_postfix}" "INFO" "$cnfinding" sans=$($OPENSSL x509 -in $HOSTCERT -noout -text 2>>$ERRFILE | grep -A2 "Subject Alternative Name" | \ egrep "DNS:|IP Address:|email:|URI:|DirName:|Registered ID:" | tr ',' '\n' | \ @@ -6633,23 +6650,27 @@ certificate_info() { -e 's/ *Registered ID://g' \ -e 's/ *othername://g' -e 's/ *X400Name://g' -e 's/ *EdiPartyName://g') # ^^^ CACert + out "$indent"; pr_bold " subjectAltName (SAN) " + json_prefix="cert_SAN" if [[ -n "$sans" ]]; then while read san; do [[ -n "$san" ]] && all_san+="$san " done <<< "$sans" prln_italic "$(out_row_aligned_max_width "$all_san" "$indent " $TERM_WIDTH)" - fileout "${json_prefix}san" "INFO" "subjectAltName (SAN) : $all_san" + fileout "${json_prefix}${json_postfix}" "INFO" "$all_san" else if [[ $SERVICE == "HTTP" ]] || "$ASSUME_HTTP"; then pr_svrty_high "missing (NOT ok)"; outln " -- Browsers are complaining" - fileout "${json_prefix}san" "HIGH" "subjectAltName (SAN) : -- Browsers are complaining" + fileout "${json_prefix}${json_postfix}" "HIGH" "No SAN, browsers are complaining" else pr_svrty_medium "missing"; outln " -- no SAN is deprecated" - fileout "${json_prefix}san" "MEDIUM" "subjectAltName (SAN) : -- no SAN is deprecated" + fileout "${json_prefix}${json_postfix}" "MEDIUM" "Providing no SAN is deprecated" fi fi + out "$indent"; pr_bold " Issuer " + json_prefix="cert_issuer" #FIXME: oid would be better maybe (see above) issuer="$($OPENSSL x509 -in $HOSTCERT -noout -issuer -nameopt multiline,-align,sname,-esc_msb,utf8,-space_eq 2>>$ERRFILE)" issuer_CN="$(awk -F'=' '/CN=/ { print $2 }' <<< "$issuer")" @@ -6659,7 +6680,7 @@ certificate_info() { if [[ "$issuer_O" == "issuer=" ]] || [[ "$issuer_O" == "issuer= " ]] || [[ "$issuer_CN" == "$cn" ]]; then prln_svrty_critical "self-signed (NOT ok)" - fileout "${json_prefix}issuer" "CRITICAL" "Issuer: selfsigned" + fileout "${json_prefix}${json_postfix}" "CRITICAL" "selfsigned" else issuerfinding="$issuer_CN" pr_italic "$issuer_CN" @@ -6687,7 +6708,7 @@ certificate_info() { out ")" fi outln - fileout "${json_prefix}issuer" "INFO" "Issuer: $issuerfinding" + fileout "${json_prefix}${json_postfix}" "INFO" "$issuerfinding" fi out "$indent"; pr_bold " Trust (hostname) " @@ -6804,19 +6825,21 @@ certificate_info() { prln_svrty_medium "$trustfinding_nosni" fi - fileout "${json_prefix}trust" "$trust_sni_finding" "${trustfinding}${trustfinding_nosni}" + fileout "cert_trust${json_postfix}" "$trust_sni_finding" "${trustfinding}${trustfinding_nosni}" out "$indent"; pr_bold " Chain of trust"; out " " + json_prefix="cert_chain_of_trust" if [[ "$issuer_O" =~ StartCom ]] || [[ "$issuer_O" =~ WoSign ]] || [[ "$issuer_CN" =~ StartCom ]] || [[ "$issuer_CN" =~ WoSign ]]; then # Shortcut for this special case here. pr_italic "WoSign/StartCom"; out " are " ; prln_svrty_critical "not trusted anymore (NOT ok)" - fileout "${json_prefix}issuer" "CRITICAL" "Issuer: not trusted anymore (WoSign/StartCom)" + fileout "${json_prefix}${json_postfix}" "CRITICAL" "Issuer not trusted anymore (WoSign/StartCom)" else - determine_trust "$json_prefix" # Also handles fileout + determine_trust "$json_prefix" "$json_postfix" # Also handles fileout 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) " + json_prefix="cert_EV" # only the first one, seldom we have two policy_oid=$($OPENSSL x509 -in $HOSTCERT -text 2>>$ERRFILE | awk '/ .Policy: / { print $2 }' | awk 'NR < 2') if echo "$issuer" | egrep -q 'Extended Validation|Extended Validated|EV SSL|EV CA' || \ @@ -6828,17 +6851,18 @@ certificate_info() { [[ 1.3.6.1.4.1.17326.10.8.12.1.2 == "$policy_oid" ]] || \ [[ 1.3.6.1.4.1.13177.10.1.3.10 == "$policy_oid" ]] ; then out "yes " - fileout "${json_prefix}ev" "OK" "Extended Validation (EV) (experimental) : yes" + fileout "${json_prefix}${json_postfix}" "OK" "yes" else out "no " - fileout "${json_prefix}ev" "INFO" "Extended Validation (EV) (experimental) : no" + fileout "${json_prefix}${json_postfix}" "INFO" "no" fi debugme echo "($(newline_to_spaces "$policy_oid"))" outln -#TODO: use browser OIDs: +#TODO: check browser OIDs: # https://mxr.mozilla.org/mozilla-central/source/security/certverifier/ExtendedValidation.cpp # http://src.chromium.org/chrome/trunk/src/net/cert/ev_root_ca_metadata.cc # https://certs.opera.com/03/ev-oids.xml +# see #967 out "$indent"; pr_bold " Certificate Expiration " @@ -6854,8 +6878,8 @@ certificate_info() { expire=$($OPENSSL x509 -in $HOSTCERT -checkend 1 2>>$ERRFILE) if ! grep -qw not <<< "$expire" ; then - pr_svrty_critical "expired!" - expfinding="expired!" + pr_svrty_critical "expired" + expfinding="expired" expok="CRITICAL" else secs2warn=$((24 * 60 * 60 * days2warn2)) # low threshold first @@ -6872,17 +6896,18 @@ certificate_info() { expok="MEDIUM" fi else - pr_svrty_high "expires < $days2warn2 days ($days2expire) !" - expfinding+="expires < $days2warn2 days ($days2expire) !" + pr_svrty_high "expires < $days2warn2 days ($days2expire)" + expfinding+="expires < $days2warn2 days ($days2expire)" expok="HIGH" fi fi outln " ($startdate --> $enddate)" - fileout "${json_prefix}expiration" "$expok" "Certificate Expiration : $expfinding ($startdate --> $enddate)" + fileout "cert_expiration_status${json_postfix}" "$expok" "$expfinding" + fileout "cert_expiration_startend${json_postfix}" "$expok" "$startdate --> $enddate" certificates_provided=1+$(grep -c "\-\-\-\-\-BEGIN CERTIFICATE\-\-\-\-\-" $TEMPDIR/intermediatecerts.pem) out "$indent"; pr_bold " # of certificates provided"; outln " $certificates_provided" - fileout "${json_prefix}certcount" "INFO" "# of certificates provided : $certificates_provided" + fileout "certchain_count${json_postfix}" "INFO" "${certificates_provided} certificates provided" # Get both CRL and OCSP URI upfront. If there's none, this is not good. And we need to penalize this in the output crl="$($OPENSSL x509 -in $HOSTCERT -noout -text 2>>$ERRFILE | \ @@ -6890,60 +6915,62 @@ certificate_info() { ocsp_uri=$($OPENSSL x509 -in $HOSTCERT -noout -ocsp_uri 2>>$ERRFILE) out "$indent"; pr_bold " Certificate Revocation List " + json_prefix="cert_CRL" if [[ -z "$crl" ]] ; then if [[ -n "$ocsp_uri" ]]; then outln "--" - fileout "${json_prefix}crl" "INFO" "No CRL provided" + fileout "${json_prefix}${json_postfix}" "INFO" "none" else pr_svrty_high "NOT ok --" outln " neither CRL nor OCSP URI provided" - fileout "${json_prefix}crl" "HIGH" "Neither CRL nor OCSP URI provided" + fileout "${json_prefix}${json_postfix}" "HIGH" "Neither CRL nor OCSP URI provided" fi else if [[ $(count_lines "$crl") -eq 1 ]]; then outln "$crl" - fileout "${json_prefix}crl" "INFO" "Certificate Revocation List : $crl" else # more than one CRL out_row_aligned "$crl" "$spaces" - fileout "${json_prefix}crl" "INFO" "Certificate Revocation List : $crl" fi + fileout "${json_prefix}${json_postfix}" "INFO" "$crl" fi out "$indent"; pr_bold " OCSP URI " + json_prefix="cert_OCSP_URI" if [[ -z "$ocsp_uri" ]]; then outln "--" - fileout "${json_prefix}ocsp_uri" "INFO" "OCSP URI : --" + fileout "${json_prefix}${json_postfix}" "INFO" "--" else if [[ $(count_lines "$ocsp_uri") -eq 1 ]]; then outln "$ocsp_uri" else out_row_aligned "$ocsp_uri" "$spaces" fi - fileout "${json_prefix}ocsp_uri" "INFO" "OCSP URI : $ocsp_uri" + fileout "${json_prefix}${json_postfix}" "INFO" "$ocsp_uri" fi out "$indent"; pr_bold " OCSP stapling " + json_prefix="OCSP_stapling" if grep -a "OCSP response" <<< "$ocsp_response" | grep -q "no response sent" ; then if [[ -n "$ocsp_uri" ]]; then pr_svrty_low "not offered" - fileout "${json_prefix}ocsp_stapling" "LOW" "OCSP stapling : not offered" + fileout "${json_prefix}${json_postfix}" "LOW" "not offered" else out "not offered" - fileout "${json_prefix}ocsp_stapling" "INFO" "OCSP stapling : not offered" + fileout "${json_prefix}${json_postfix}" "INFO" "not offered" fi else if grep -a "OCSP Response Status" <<<"$ocsp_response_status" | grep -q successful; then pr_done_good "offered" - fileout "${json_prefix}ocsp_stapling" "OK" "OCSP stapling : offered" + fileout "${json_prefix}${json_postfix}" "OK" "offered" provides_stapling=true else if $GOST_STATUS_PROBLEM; then pr_warning "(GOST servers make problems here, sorry)" - fileout "${json_prefix}ocsp_stapling" "WARN" "OCSP stapling : (GOST servers make problems here, sorry)" + fileout "${json_prefix}${json_postfix}" "WARN" "(The GOST server made a problem here, sorry)" ret=0 else out "(response status unknown)" - fileout "${json_prefix}ocsp_stapling" "OK" "OCSP stapling : not sure what's going on here, debug: $ocsp_response" + fileout "${json_prefix}${json_postfix}" "OK" " not sure what's going on here, \'$ocsp_response\'" debugme grep -a -A20 -B2 "OCSP response" <<<"$ocsp_response" ret=2 fi @@ -6952,10 +6979,10 @@ certificate_info() { outln out "$indent"; pr_bold " OCSP must staple "; - must_staple "$json_prefix" "$provides_stapling" + must_staple "$json_postfix" "$provides_stapling" out "$indent"; pr_bold " DNS CAA RR"; out " (experimental) " - + json_prefix="CAA_record" caa_node="$NODE" caa="" while ( [[ -z "$caa" ]] && [[ ! -z "$caa_node" ]] ); do @@ -6977,23 +7004,23 @@ certificate_info() { done <<< "$caa" all_caa=${all_caa%, } # strip trailing comma pr_italic "$(out_row_aligned_max_width "$all_caa" "$indent " $TERM_WIDTH)" - fileout "${json_prefix}CAA_record" "OK" "DNS Certification Authority Authorization (CAA) Resource Record / RFC6844 (check for match): \"$all_caa\" " + fileout "${json_prefix}${json_postfix}" "OK" "'DNS Certification Authority Authorization (CAA) Resource Record / RFC6844' \'$all_caa\' " elif "$NODNS"; then pr_warning "(was instructed to not use DNS)" - fileout "${json_prefix}CAA_record" "WARN" "DNS Certification Authority Authorization (CAA) Resource Record / RFC6844 : test skipped as instructed" + fileout "${json_prefix}${json_postfix}" "WARN" "check skipped as instructed" else pr_svrty_low "not offered" - fileout "${json_prefix}CAA_record" "LOW" "DNS Certification Authority Authorization (CAA) Resource Record / RFC6844 : not offered" + fileout "${json_prefix}${json_postfix}" "LOW" "'DNS Certification Authority Authorization (CAA) Resource Record / RFC6844' not offered" fi outln out "$indent"; pr_bold " Certificate Transparency "; if [[ "$ct" =~ extension ]]; then pr_done_good "yes"; outln " ($ct)" - fileout "${json_prefix}certificate_transparency" "OK" "Certificate Transparency: yes ($ct)" + fileout "certificate_transparency${json_postfix}" "OK" "yes ($ct)" else outln "$ct" - fileout "${json_prefix}certificate_transparency" "INFO" "Certificate Transparency: $ct" + fileout "certificate_transparency${json_postfix}" "INFO" "$ct" fi outln return $ret @@ -7157,7 +7184,7 @@ run_server_defaults() { pr_bold " TLS extensions (standard) " if [[ -z "$TLS_EXTENSIONS" ]]; then outln "(none)" - fileout "tls_extensions" "INFO" "TLS server extensions (std): (none)" + fileout "TLS_extensions" "INFO" "(none)" else #FIXME: we rather want to have the chance to print each ext in italics or another format. # Atm is a string of quoted strings -- that needs to be fixed at the root then @@ -7171,13 +7198,14 @@ run_server_defaults() { tls_extensions="$(out_row_aligned_max_width "$tls_extensions" " " $TERM_WIDTH)" tls_extensions="${tls_extensions//{/ }" outln "$tls_extensions" - fileout "tls_extensions" "INFO" "TLS server extensions (std): $TLS_EXTENSIONS" + fileout "TLS_extensions" "INFO" "$TLS_EXTENSIONS" fi pr_bold " Session Ticket RFC 5077 hint " + json_prefix="session_ticket" if [[ -z "$sessticket_lifetime_hint" ]]; then outln "(no lifetime advertised)" - fileout "session_ticket" "INFO" "TLS session ticket RFC 5077 lifetime: none advertised" + fileout "${json_prefix}" "INFO" "No TLS session ticket RFC 5077 lifetime advertised" # it MAY be given a hint of the lifetime of the ticket, see https://tools.ietf.org/html/rfc5077#section-5.6 . # Sometimes it just does not -- but it then may also support TLS session tickets reuse else @@ -7186,20 +7214,20 @@ run_server_defaults() { out "$lifetime $unit" if [[ $((3600 * 24)) -lt $lifetime ]]; then prln_svrty_low " but: PFS requires session ticket keys to be rotated < daily !" - fileout "session_ticket" "LOW" "TLS session ticket RFC 5077 valid for $lifetime $unit but PFS requires session ticket keys to be rotated at least daily!" + fileout "${json_prefix}" "LOW" "TLS session ticket RFC 5077 valid for $lifetime $unit but PFS requires session ticket keys to be rotated at least daily!" else outln ", session tickets keys seems to be rotated < daily" - fileout "session_ticket" "INFO" "TLS session ticket RFC 5077 valid for $lifetime $unit only (PFS requires session ticket keys are rotated at least daily)" + fileout "${json_prefix}" "INFO" "TLS session ticket RFC 5077 valid for $lifetime $unit only (PFS requires session ticket keys are rotated at least daily)" fi fi pr_bold " SSL Session ID support " if "$NO_SSL_SESSIONID"; then outln "no" - fileout "session_id" "INFO" "SSL session ID support: no" + fileout "SSL_session_id_support" "INFO" "no" else outln "yes" - fileout "session_id" "INFO" "SSL session ID support: yes" + fileout "SSL_session_id_support" "INFO" "yes" fi pr_bold " Session Resumption " From 83271719358789ab57bc65ee985bd2b82ed15a76 Mon Sep 17 00:00:00 2001 From: Dirk Date: Tue, 23 Jan 2018 11:46:24 +0100 Subject: [PATCH 4/6] simplify few cert checks messages + hopefullt make Travis work again --- t/31_badssl.com.t | 28 +++++++++++++++------------- testssl.sh | 9 +++------ 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/t/31_badssl.com.t b/t/31_badssl.com.t index 01ca476..ad60255 100755 --- a/t/31_badssl.com.t +++ b/t/31_badssl.com.t @@ -14,7 +14,7 @@ my ( ); # OK pass("Running testssl.sh against badssl.com to create a baseline (may take 2~3 minutes)"); $tests++; -my $okout = `./testssl.sh -S -e -U --jsonfile tmp.json --color 0 badssl.com`; +my $okout = `./testssl.sh -S -e --freak --logjam --drown --rc4 --sweet32 --breach --crime --jsonfile tmp.json --color 0 badssl.com`; my $okjson = json('tmp.json'); unlink 'tmp.json'; cmp_ok(@$okjson,'>',10,"We have more then 10 findings"); $tests++; @@ -22,14 +22,14 @@ cmp_ok(@$okjson,'>',10,"We have more then 10 findings"); $tests++; # Expiration pass("Running testssl against expired.badssl.com"); $tests++; $out = `./testssl.sh -S --jsonfile tmp.json --color 0 expired.badssl.com`; -like($out, qr/Certificate Expiration\s+expired\!/,"The certificate should be expired"); $tests++; +like($out, qr/Certificate Expiration\s+expired/,"The certificate should be expired"); $tests++; $json = json('tmp.json'); unlink 'tmp.json'; $found = 0; foreach my $f ( @$json ) { - if ( $f->{id} eq "expiration" ) { + if ( $f->{id} eq "cert_expiration_status" ) { $found = 1; - like($f->{finding},qr/^Certificate Expiration.*expired\!/,"Finding reads expired."); $tests++; + like($f->{finding},qr/^expired/,"Finding reads expired."); $tests++; is($f->{severity}, "CRITICAL", "Severity should be CRITICAL"); $tests++; last; } @@ -44,9 +44,10 @@ $json = json('tmp.json'); unlink 'tmp.json'; $found = 0; foreach my $f ( @$json ) { - if ( $f->{id} eq "expiration" ) { + if ( $f->{id} eq "cert_expiration_status" ) { $found = 1; - like($f->{finding},qr/^Certificate Expiration \: \d+/,"Finding doesn't read expired."); $tests++; + like($f->{finding},qr/days/,"Finding doesn't read expired."); $tests++; +# hope they don't come below 60days: is($f->{severity}, "OK", "Severity should be ok"); $tests++; last; } @@ -56,9 +57,9 @@ 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 "chain_of_trust" ) { + if ( $f->{id} eq "cert_chain_of_trust" ) { $found = 1; - like($f->{finding},qr/^All certificate trust checks failed/,"Finding says certificate cannot be trusted."); $tests++; + like($f->{finding},qr/^.*self signed/,"Finding says certificate cannot be trusted."); $tests++; is($f->{severity}, "CRITICAL", "Severity should be CRITICAL"); $tests++; last; } @@ -68,9 +69,10 @@ 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 "chain_of_trust" ) { + if ( $f->{id} eq "cert_chain_of_trust" ) { $found = 1; - is($f->{finding},"All certificate trust checks passed.","Finding says certificate can be trusted."); $tests++; + like($f->{finding},qr/passed/,"Finding says certificate can be trusted."); $tests++; + # is($f->{finding},"^.*passed.*","Finding says certificate can be trusted."); $tests++; is($f->{severity}, "OK", "Severity should be OK"); $tests++; last; } @@ -102,9 +104,9 @@ $json = json('tmp.json'); unlink 'tmp.json'; $found = 0; foreach my $f ( @$json ) { - if ( $f->{id} eq "chain_of_trust" ) { + if ( $f->{id} eq "cert_chain_of_trust" ) { $found = 1; - like($f->{finding},qr/^All certificate trust checks failed.*incomplete/,"Finding says certificate cannot be trusted."); $tests++; + like($f->{finding},qr/^.*chain incomplete/,"Finding says certificate cannot be trusted."); $tests++; is($f->{severity}, "CRITICAL", "Severity should be CRITICAL"); $tests++; last; } @@ -121,7 +123,7 @@ is($found,1,"We had a finding for this in the JSON output"); $tests++; #unlink 'tmp.json'; #$found = 0; #foreach my $f ( @$json ) { -# if ( $f->{id} eq "chain_of_trust" ) { +# if ( $f->{id} eq "cert_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}, "CRITICAL", "Severity should be CRITICAL"); $tests++; diff --git a/testssl.sh b/testssl.sh index 50db43d..467eed7 100755 --- a/testssl.sh +++ b/testssl.sh @@ -5788,10 +5788,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 OK: - [[ -z "$addtl_warning" ]] && \ - fileout "${json_prefix}${json_postfix}" "OK" "All certificate trust checks passed" || \ - fileout "${json_prefix}${json_postfix}" "OK" "All certificate trust checks passed. $addtl_warning" - # The "." is otherwise confusing + fileout "${json_prefix}${json_postfix}" "OK" "passed. $addtl_warning" else # at least one failed pr_svrty_critical "NOT ok" @@ -5804,7 +5801,7 @@ determine_trust() { else out "$code" fi - fileout "${json_prefix}${json_postfix}" "CRITICAL" "All certificate trust checks failed: $code. $addtl_warning" + fileout "${json_prefix}${json_postfix}" "CRITICAL" "failed $code. $addtl_warning" else # is one ok and the others not ==> display the culprit store if "$some_ok"; then @@ -5832,7 +5829,7 @@ determine_trust() { [[ "$DEBUG" -eq 0 ]] && tm_out "$spaces" pr_done_good "OK: $ok_was" fi - fileout "${json_prefix}${json_postfix}" "CRITICAL" "Some certificate trust checks failed : OK : $ok_was NOT ok: $notok_was $addtl_warning" + fileout "${json_prefix}${json_postfix}" "CRITICAL" "Some certificate trust checks failed -> $notok_was $addtl_warning, OK -> $ok_was" fi [[ -n "$addtl_warning" ]] && out "\n$spaces" && pr_warning "$addtl_warning" fi From 1cec0181af78985b289e4ccf4833353e1d4150cf Mon Sep 17 00:00:00 2001 From: Dirk Date: Tue, 23 Jan 2018 15:16:05 +0100 Subject: [PATCH 5/6] More changes ID + Finding for JSON outside server defaults This commit just adds more changes to those two parameters. It is not completely done yet (see downgrade protection via SCSV). Also json_prefix was changed to jsonID. The complete change of the fist fileout field is pending. --- testssl.sh | 708 +++++++++++++++++++++++++++-------------------------- 1 file changed, 358 insertions(+), 350 deletions(-) diff --git a/testssl.sh b/testssl.sh index 1b3d10b..b4e9650 100755 --- a/testssl.sh +++ b/testssl.sh @@ -1462,32 +1462,32 @@ service_detection() { fi out " Service detected: $CORRECT_SPACES" - json_prefix="service" + jsonID="service" case $SERVICE in HTTP) out " $SERVICE" - fileout "${json_prefix}" "INFO" "$SERVICE" + fileout "${jsonID}" "INFO" "$SERVICE" ret=0 ;; IMAP|POP|SMTP|NNTP|MongoDB) out " $SERVICE, thus skipping HTTP specific checks" - fileout "${json_prefix}" "INFO" "$SERVICE, thus skipping HTTP specific checks" + fileout "${jsonID}" "INFO" "$SERVICE, thus skipping HTTP specific checks" ret=0 ;; *) if "$CLIENT_AUTH"; then out " certificate-based authentication => skipping all HTTP checks" echo "certificate-based authentication => skipping all HTTP checks" >$TMPFILE - fileout "${json_prefix}" "INFO" "certificate-based authentication => skipping all HTTP checks" + fileout "${jsonID}" "INFO" "certificate-based authentication => skipping all HTTP checks" else out " Couldn't determine what's running on port $PORT" if "$ASSUME_HTTP"; then SERVICE=HTTP out " -- ASSUME_HTTP set though" - fileout "${json_prefix}" "DEBUG" "Couldn't determine service -- ASSUME_HTTP set" + fileout "${jsonID}" "DEBUG" "Couldn't determine service -- ASSUME_HTTP set" ret=0 else out ", assuming no HTTP service => skipping all HTTP checks" - fileout "${json_prefix}" "DEBUG" "Couldn't determine service, skipping all HTTP checks" + fileout "${jsonID}" "DEBUG" "Couldn't determine service, skipping all HTTP checks" ret=1 fi fi @@ -1561,31 +1561,31 @@ run_http_header() { pr_svrty_high " -- Redirect to insecure URL (NOT ok)" fileout "insecure_redirect" "HIGH" "Redirect to insecure URL: \"$redirect\"" fi - fileout "HTTP_STATUS_CODE" "INFO" "$HTTP_STATUS_CODE$msg_thereafter (\"$URL_PATH\" tested)" + fileout "HTTP_status_code" "INFO" "$HTTP_STATUS_CODE$msg_thereafter (\"$URL_PATH\" tested)" ;; 200|204|403|405) - fileout "HTTP_STATUS_CODE" "INFO" "$HTTP_STATUS_CODE$msg_thereafter (\"$URL_PATH\" tested)" + fileout "HTTP_status_code" "INFO" "$HTTP_STATUS_CODE$msg_thereafter (\"$URL_PATH\" tested)" ;; 206) out " -- WHAT?" - fileout "HTTP_STATUS_CODE" "INFO" "$HTTP_STATUS_CODE$msg_thereafter (\"$URL_PATH\" tested) -- WHAT?" + fileout "HTTP_status_code" "INFO" "$HTTP_STATUS_CODE$msg_thereafter (\"$URL_PATH\" tested) -- WHAT?" # partial content shouldn't happen ;; 400) pr_cyan " (Hint: better try another URL)" - fileout "HTTP_STATUS_CODE" "INFO" "$HTTP_STATUS_CODE$msg_thereafter (\"$URL_PATH\" tested) -- better try another URL" + fileout "HTTP_status_code" "INFO" "$HTTP_STATUS_CODE$msg_thereafter (\"$URL_PATH\" tested) -- better try another URL" ;; 401) grep -aq "^WWW-Authenticate" $HEADERFILE && out " "; out "$(strip_lf "$(grep -a "^WWW-Authenticate" $HEADERFILE)")" - fileout "HTTP_STATUS_CODE" "INFO" "$HTTP_STATUS_CODE$msg_thereafter (\"$URL_PATH\" tested) -- $(grep -a "^WWW-Authenticate" $HEADERFILE)" + fileout "HTTP_status_code" "INFO" "$HTTP_STATUS_CODE$msg_thereafter (\"$URL_PATH\" tested) -- $(grep -a "^WWW-Authenticate" $HEADERFILE)" ;; 404) out " (Hint: supply a path which doesn't give a \"$HTTP_STATUS_CODE$msg_thereafter\")" - fileout "HTTP_STATUS_CODE" "INFO" "$HTTP_STATUS_CODE$msg_thereafter (\"$URL_PATH\" tested) -- better supply a path which doesn't give a \"$HTTP_STATUS_CODE$msg_thereafter\"" + fileout "HTTP_status_code" "INFO" "$HTTP_STATUS_CODE$msg_thereafter (\"$URL_PATH\" tested) -- better supply a path which doesn't give a \"$HTTP_STATUS_CODE$msg_thereafter\"" ;; *) pr_warning ". Oh, didn't expect \"$HTTP_STATUS_CODE$msg_thereafter\"" - fileout "HTTP_STATUS_CODE" "WARN" "$HTTP_STATUS_CODE$msg_thereafter (\"$URL_PATH\" tested) -- Oops, didn't expect a \"$HTTP_STATUS_CODE$msg_thereafter\"" + fileout "HTTP_status_code" "WARN" "$HTTP_STATUS_CODE$msg_thereafter (\"$URL_PATH\" tested) -- Oops, didn't expect a \"$HTTP_STATUS_CODE$msg_thereafter\"" ;; esac outln @@ -1651,10 +1651,10 @@ run_http_date() { # process was killed, so we need to add an error: [[ $HAD_SLEPT -ne 0 ]] && difftime="$difftime (± 1.5)" out "$difftime sec from localtime"; - fileout "http_clock_skew" "INFO" "HTTP clock skew $difftime sec from localtime" + fileout "HTTP_clock_skew" "INFO" "HTTP clock skew $difftime sec from localtime" else out "Got no HTTP time, maybe try different URL?"; - fileout "http_clock_skew" "INFO" "HTTP clock skew not measured. Got no HTTP time, maybe try different URL?" + fileout "HTTP_clock_skew" "INFO" "HTTP clock skew not measured. Got no HTTP time, maybe try different URL?" fi debugme tm_out ", epoch: $HTTP_TIME" fi @@ -1742,33 +1742,33 @@ run_hsts() { fi 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" + fileout "HSTS_time" "MEDIUM" "HSTS max-age missing. 15552000 s (180 days) or more recommnded" 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" + fileout "HSTS_time" "MEDIUM" "HSTS max-age set to 0. HSTS is disabled" 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" + fileout "HSTS_time" "OK" "HSTS timeout $hsts_age_days days (=$hsts_age_sec seconds) > $HSTS_MIN days" else 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" + fileou t "HSTS_time" "MEDIUM" "HSTS timeout too short. $hsts_age_days days (=$hsts_age_sec seconds) < $HSTS_MIN days" fi if includeSubDomains "$TMPFILE"; then - fileout "hsts_subdomains" "OK" "HSTS includes subdomains" + fileout "HSTS_subdomains" "OK" "HSTS includes subdomains" else - fileout "hsts_subdomains" "INFO" "HSTS only for this domain" + fileout "HSTS_subdomains" "INFO" "HSTS only for this domain" fi if preload "$TMPFILE"; then - fileout "hsts_preload" "OK" "HSTS domain is marked for preloading" + fileout "HSTS_preload" "OK" "HSTS domain is marked for preloading" else - fileout "hsts_preload" "INFO" "HSTS domain is NOT marked for preloading" + fileout "HSTS_preload" "INFO" "HSTS domain is NOT marked for preloading" #FIXME: To be checked against preloading lists, # e.g. https://dxr.mozilla.org/mozilla-central/source/security/manager/boot/src/nsSTSPreloadList.inc # https://chromium.googlesource.com/chromium/src/+/master/net/http/transport_security_state_static.json fi else out "--" - fileout "hsts" "HIGH" "No support for HTTP Strict Transport Security" + fileout "HSTS" "HIGH" "No support for HTTP Strict Transport Security" fi outln @@ -1813,7 +1813,7 @@ run_hpkp() { out "\n$spaces Examining first: " first_hpkp_header=$(awk -F':' '/Public-Key-Pins/ { print $1 }' $HEADERFILE | head -1) pr_italic "$first_hpkp_header, " - fileout "hpkp_multiple" "WARN" "Multiple HPKP headers $hpkp_headers. Using first header: $first_hpkp_header" + fileout "HPKP_multiple" "WARN" "Multiple HPKP headers $hpkp_headers. Using first header: $first_hpkp_header" fi # remove leading Public-Key-Pins*, any colons, double quotes and trailing spaces and taking the first -- whatever that is @@ -1826,11 +1826,11 @@ run_hpkp() { hpkp_nr_keys=$(grep -ac pin-sha $TMPFILE) if [[ $hpkp_nr_keys -eq 1 ]]; then pr_svrty_high "1 key (NOT ok), " - fileout "hpkp_spkis" "HIGH" "Only one key pinned in HPKP header, this means the site may become unavailable if the key is revoked" + fileout "HPKP_SPKIs" "HIGH" "Only one key pinned in HPKP header, this means the site may become unavailable if the key is revoked" else pr_done_good "$hpkp_nr_keys" out " keys, " - fileout "hpkp_spkis" "OK" "$hpkp_nr_keys keys pinned in HPKP header, additional keys are available if the current key is revoked" + fileout "HPKP_SPKIs" "OK" "$hpkp_nr_keys keys pinned in HPKP header, additional keys are available if the current key is revoked" fi # print key=value pair with awk, then strip non-numbers, to be improved with proper parsing of key-value with awk @@ -1842,22 +1842,22 @@ run_hpkp() { hpkp_age_days=$((hpkp_age_sec / 86400)) if [[ $hpkp_age_sec -ge $HPKP_MIN ]]; then pr_done_good "$hpkp_age_days days" ; out "=$hpkp_age_sec s" - fileout "hpkp_age" "OK" "HPKP age is set to $hpkp_age_days days ($hpkp_age_sec sec)" + fileout "HPKP_age" "OK" "HPKP age is set to $hpkp_age_days days ($hpkp_age_sec sec)" else out "$hpkp_age_sec s = " pr_svrty_medium "$hpkp_age_days days (< $HPKP_MIN s = $((HPKP_MIN / 86400)) days is not good enough)" - fileout "hpkp_age" "MEDIUM" "HPKP age is set to $hpkp_age_days days ($hpkp_age_sec sec) < $HPKP_MIN s = $((HPKP_MIN / 86400)) days is not good enough." + fileout "HPKP_age" "MEDIUM" "HPKP age is set to $hpkp_age_days days ($hpkp_age_sec sec) < $HPKP_MIN s = $((HPKP_MIN / 86400)) days is not good enough." fi if includeSubDomains "$TMPFILE"; then - fileout "hpkp_subdomains" "INFO" "HPKP header is valid for subdomains as well" + fileout "HPKP_subdomains" "INFO" "HPKP header is valid for subdomains as well" else - fileout "hpkp_subdomains" "INFO" "HPKP header is valid for this domain only" + fileout "HPKP_subdomains" "INFO" "HPKP header is valid for this domain only" fi if preload "$TMPFILE"; then - fileout "hpkp_preload" "INFO" "HPKP header is marked for browser preloading" + fileout "HPKP_preload" "INFO" "HPKP header is marked for browser preloading" else - fileout "hpkp_preload" "INFO" "HPKP header is NOT marked for browser preloading" + fileout "HPKP_preload" "INFO" "HPKP header is NOT marked for browser preloading" fi # Get the SPKIs first @@ -1910,7 +1910,7 @@ run_hpkp() { spki_match=true out "\n$spaces_indented Host cert: " pr_done_good "$hpkp_spki" - fileout "hpkp_$hpkp_spki" "OK" "SPKI $hpkp_spki matches the host certificate" + fileout "HPKP_$hpkp_spki" "OK" "SPKI $hpkp_spki matches the host certificate" fi debugme tm_out "\n $hpkp_spki | $hpkp_spki_hostcert" @@ -1925,7 +1925,7 @@ run_hpkp() { pr_done_good "$hpkp_spki" ca_cn="$(sed "s/^[a-zA-Z0-9\+\/]*=* *//" <<< $"$hpkp_matches" )" pr_italic " $ca_cn" - fileout "hpkp_$hpkp_spki" "OK" "SPKI $hpkp_spki matches Intermediate CA \"$ca_cn\" pinned in the HPKP header" + fileout "HPKP_$hpkp_spki" "OK" "SPKI $hpkp_spki matches Intermediate CA \"$ca_cn\" pinned in the HPKP header" fi fi @@ -1947,11 +1947,11 @@ run_hpkp() { out "\n$spaces_indented Root CA: " pr_done_good "$hpkp_spki" pr_italic " $ca_cn" - fileout "hpkp_$hpkp_spki" "INFO" "SPKI $hpkp_spki matches Root CA \"$ca_cn\" pinned in the HPKP header. (Root CA part of the chain)" + fileout "HPKP_$hpkp_spki" "INFO" "SPKI $hpkp_spki matches Root CA \"$ca_cn\" pinned in the HPKP header. (Root CA part of the chain)" else # not part of chain match_ca="" has_backup_spki=true # Root CA outside the chain --> we save it for unmatched - fileout "hpkp_$hpkp_spki" "INFO" "SPKI $hpkp_spki matches Root CA \"$ca_cn\" pinned in the HPKP header. (Root backup SPKI)" + fileout "HPKP_$hpkp_spki" "INFO" "SPKI $hpkp_spki matches Root CA \"$ca_cn\" pinned in the HPKP header. (Root backup SPKI)" backup_spki[i]="$(strip_lf "$hpkp_spki")" # save it for later backup_spki_str[i]="$ca_cn" # also the name=CN of the root CA i=$((i + 1)) @@ -1966,7 +1966,7 @@ run_hpkp() { backup_spki[i]="$(strip_lf "$hpkp_spki")" # save it for later backup_spki_str[i]="" # no root ca i=$((i + 1)) - fileout "hpkp_$hpkp_spki" "INFO" "SPKI $hpkp_spki doesn't match anything. This is ok for a backup for any certificate" + fileout "HPKP_$hpkp_spki" "INFO" "SPKI $hpkp_spki doesn't match anything. This is ok for a backup for any certificate" # CSV/JSON output here for the sake of simplicity, rest we do en bloc below fi done @@ -1996,23 +1996,23 @@ run_hpkp() { if [[ ! -f "$ca_hashes" ]] && "$spki_match"; then out "$spaces " prln_warning "Attribution of further hashes couldn't be done as $ca_hashes could not be found" - fileout "hpkp_spkimatch" "WARN" "Attribution of further hashes couldn't be done as $ca_hashes could not be found" + fileout "HPKP_spkimatch" "WARN" "Attribution of further hashes couldn't be done as $ca_hashes could not be found" fi # If all else fails... if ! "$spki_match"; then "$has_backup_spki" && out "$spaces" # we had a few lines with backup SPKIs already prln_svrty_high " No matching key for SPKI found " - fileout "hpkp_spkimatch" "HIGH" "None of the SPKI match your host certificate, intermediate CA or known root CAs. You may have bricked this site" + fileout "HPKP_spkimatch" "HIGH" "None of the SPKI match your host certificate, intermediate CA or known root CAs. You may have bricked this site" fi if ! "$has_backup_spki"; then prln_svrty_high " No backup keys found. Loss/compromise of the currently pinned key(s) will lead to bricked site. " - fileout "hpkp_backup" "HIGH" "No backup keys found. Loss/compromise of the currently pinned key(s) will lead to bricked site." + fileout "HPKP_backup" "HIGH" "No backup keys found. Loss/compromise of the currently pinned key(s) will lead to bricked site." fi else outln "--" - fileout "hpkp" "INFO" "No support for HTTP Public Key Pinning" + fileout "HPKP" "INFO" "No support for HTTP Public Key Pinning" fi tmpfile_handle $FUNCNAME.txt @@ -2130,10 +2130,10 @@ run_server_banner() { serverbanner=$(sed -e 's/^Server: //' -e 's/^server: //' $TMPFILE) if [[ x"$serverbanner" == "x\n" ]] || [[ x"$serverbanner" == "x\n\r" ]] || [[ -z "$serverbanner" ]]; then outln "banner exists but empty string" - fileout "serverbanner" "INFO" "Server banner exists but empty string" + fileout "server_banner" "INFO" "Server banner is empty" else emphasize_stuff_in_headers "$serverbanner" - fileout "serverbanner" "INFO" "Server banner identified: $serverbanner" + fileout "server_banner" "INFO" "$serverbanner" if [[ "$serverbanner" = *Microsoft-IIS/6.* ]] && [[ $OSSL_VER == 1.0.2* ]]; then prln_warning " It's recommended to run another test w/ OpenSSL 1.0.1 !" # see https://github.com/PeterMosmans/openssl/issues/19#issuecomment-100897892 @@ -2144,7 +2144,7 @@ run_server_banner() { # https://support.microsoft.com/en-us/kb/245030 else outln "(no \"Server\" line in header, interesting!)" - fileout "serverbanner" "INFO" "No Server banner in header, interesting!" + fileout "server_banner" "INFO" "No Server banner line in header, interesting!" fi tmpfile_handle $FUNCNAME.txt @@ -2164,7 +2164,7 @@ run_rp_banner() { egrep -ai '^Via:|^X-Cache|^X-Squid|^X-Varnish:|^X-Server-Name:|^X-Server-Port:|^x-forwarded|^Forwarded' $HEADERFILE >$TMPFILE if [[ $? -ne 0 ]]; then outln "--" - fileout "rp_header" "INFO" "No reverse proxy banner found" + fileout "rp_banner" "INFO" "No reverse proxy banner found" else while read line; do line=$(strip_lf "$line") @@ -2176,7 +2176,7 @@ run_rp_banner() { emphasize_stuff_in_headers "$line" rp_banners="${rp_banners}${line}" done < $TMPFILE - fileout "rp_header" "INFO" "Reverse proxy banner(s) found: $rp_banners" + fileout "rp_banner" "INFO" "Reverse proxy banner(s) found: $rp_banners" fi outln @@ -2198,19 +2198,20 @@ run_application_banner() { egrep -ai '^X-Powered-By|^X-AspNet-Version|^X-Version|^Liferay-Portal|^X-OWA-Version^|^MicrosoftSharePointTeamServices' $HEADERFILE >$TMPFILE if [[ $? -ne 0 ]]; then outln "--" - fileout "app_banner" "INFO" "No Application Banners found" + fileout "app_banner" "INFO" "No application banner found" else while IFS='' read -r line; do line=$(strip_lf "$line") if ! $first; then out "$spaces" + app_banners="${app_banners}, ${line}" else + app_banners="${line}" first=false fi emphasize_stuff_in_headers "$line" - app_banners="${app_banners}${line}" done < "$TMPFILE" - fileout "app_banner" "INFO" "Application Banners found: $app_banners" + fileout "app_banner" "INFO" "$app_banners" fi tmpfile_handle $FUNCNAME.txt return 0 @@ -3997,7 +3998,7 @@ run_client_simulation() { else pr_headline " Running client simulations via openssl " prln_warning " -- you shouldn't run this with \"--ssl-native\" as you will get false results" - fileout "client_simulation_Problem" "WARN" "You shouldn't run this with \"--ssl-native\" as you will get false results" + fileout "client_simulation" "WARN" "You shouldn't run this with \"--ssl-native\" as you will get false results" fi outln debugme echo @@ -4065,6 +4066,7 @@ run_client_simulation() { if [[ $sclient_success -ne 0 ]]; then outln "No connection" fileout "client_${short[i]}" "INFO" "$(strip_spaces "${names[i]}") client simulation: No connection" +#FIXME: here probably either the id has to be changed or the finding, id seems not verbose enough else proto=$(get_protocol $TMPFILE) # hack: @@ -4275,26 +4277,26 @@ run_protocols() { case $? in 6) # couldn't open socket prln_fixme "couldn't open socket" - fileout "sslv2" "WARN" "SSLv2 couldn't be tested, socket problem" + fileout "SSLv2" "WARN" "couldn't be tested, socket problem" ;; 7) # strange reply, couldn't convert the cipher spec length to a hex number pr_cyan "strange v2 reply " outln "$debug_recomm" [[ $DEBUG -ge 3 ]] && hexdump -C "$TEMPDIR/$NODEIP.sslv2_sockets.dd" | head -1 - fileout "sslv2" "WARN" "SSLv2: received a strange SSLv2 reply (rerun with DEBUG>=2)" + fileout "SSLv2" "WARN" "received a strange SSLv2 reply (rerun with DEBUG>=2)" ;; 1) # no sslv2 server hello returned, like in openlitespeed which returns HTTP! prln_done_best "not offered (OK)" - fileout "sslv2" "OK" "SSLv2 is not offered" + fileout "SSLv2" "OK" "not offered" add_tls_offered ssl2 no ;; 0) # reset prln_done_best "not offered (OK)" - fileout "sslv2" "OK" "SSLv2 is not offered" + fileout "SSLv2" "OK" "not offered" add_tls_offered ssl2 no ;; 4) pr_fixme "signalled a 5xx after STARTTLS handshake"; outln "$debug_recomm" - fileout "sslv2" "WARN" "SSLv2: received 5xx after STARTTLS handshake reply (rerun with DEBUG>=2)" + fileout "SSLv2" "WARN" "received 5xx after STARTTLS handshake reply (rerun with DEBUG>=2)" ;; 3) lines=$(count_lines "$(hexdump -C "$TEMPDIR/$NODEIP.sslv2_sockets.dd" 2>/dev/null)") [[ "$DEBUG" -ge 2 ]] && tm_out " ($lines lines) " @@ -4303,11 +4305,11 @@ run_protocols() { add_tls_offered ssl2 yes if [[ 0 -eq "$nr_ciphers_detected" ]]; then prln_svrty_high "supported but couldn't detect a cipher and vulnerable to CVE-2015-3197 "; - fileout "sslv2" "HIGH" "SSLv2 is offered, vulnerable to CVE-2015-3197" + fileout "SSLv2" "HIGH" "offered, vulnerable to CVE-2015-3197" else pr_svrty_critical "offered (NOT ok), also VULNERABLE to DROWN attack"; outln " -- $nr_ciphers_detected ciphers" - fileout "sslv2" "CRITICAL" "SSLv2 offered, vulnerable to DROWN attack. Detected ciphers: $nr_ciphers_detected" + fileout "SSLv2" "CRITICAL" "offered, vulnerable to DROWN attack. Detected ciphers: $nr_ciphers_detected" fi fi ;; @@ -4319,18 +4321,18 @@ run_protocols() { run_prototest_openssl "-ssl2" case $? in 0) prln_svrty_critical "offered (NOT ok)" - fileout "sslv2" "CRITICAL" "SSLv2 is offered" + fileout "SSLv2" "CRITICAL" "offered" add_tls_offered ssl2 yes ;; 1) prln_done_best "not offered (OK)" - fileout "sslv2" "OK" "SSLv2 is not offered" + fileout "SSLv2" "OK" "not offered" add_tls_offered ssl2 no ;; 5) pr_svrty_high "CVE-2015-3197: $supported_no_ciph2"; - fileout "sslv2" "HIGH" "CVE-2015-3197: SSLv2 is $supported_no_ciph2" + fileout "SSLv2" "HIGH" "CVE-2015-3197: SSLv2 is $supported_no_ciph2" add_tls_offered ssl2 yes ;; - 7) fileout "sslv2" "INFO" "SSLv2 is not tested due to lack of local support" + 7) fileout "SSLv2" "INFO" "not tested due to lack of local support" ;; # no local support esac fi @@ -4343,34 +4345,34 @@ run_protocols() { fi case $? in 0) prln_svrty_high "offered (NOT ok)" - fileout "sslv3" "HIGH" "SSLv3 is offered" + fileout "SSLv3" "HIGH" "offered" latest_supported="0300" latest_supported_string="SSLv3" add_tls_offered ssl3 yes ;; 1) prln_done_best "not offered (OK)" - fileout "sslv3" "OK" "SSLv3 is not offered" + fileout "SSLv3" "OK" "not offered" add_tls_offered ssl3 no ;; 2) if [[ "$DETECTED_TLS_VERSION" == 03* ]]; then detected_version_string="TLSv1.$((0x$DETECTED_TLS_VERSION-0x0301))" prln_svrty_critical "server responded with higher version number ($detected_version_string) than requested by client (NOT ok)" - fileout "sslv3" "CRITICAL" "SSLv3: server responded with higher version number ($detected_version_string) than requested by client" + fileout "SSLv3" "CRITICAL" "server responded with higher version number ($detected_version_string) than requested by client" else if [[ ${#DETECTED_TLS_VERSION} -eq 4 ]]; then prln_svrty_critical "server responded with version number ${DETECTED_TLS_VERSION:0:2}.${DETECTED_TLS_VERSION:2:2} (NOT ok)" - fileout "sslv3" "CRITICAL" "SSLv3: server responded with version number ${DETECTED_TLS_VERSION:0:2}.${DETECTED_TLS_VERSION:2:2}" + fileout "SSLv3" "CRITICAL" "server responded with version number ${DETECTED_TLS_VERSION:0:2}.${DETECTED_TLS_VERSION:2:2}" else prln_svrty_medium "strange, server ${DETECTED_TLS_VERSION}" - fileout "sslv3" "MEDIUM" "SSLv3: strange, server ${DETECTED_TLS_VERSION}" + fileout "SSLv3" "MEDIUM" "strange, server ${DETECTED_TLS_VERSION}" fi fi ;; 4) pr_fixme "signalled a 5xx after STARTTLS handshake"; outln "$debug_recomm" - fileout "sslv3" "WARN" "SSLv3: received 5xx after STARTTLS handshake reply (rerun with DEBUG>=2)" + fileout "SSLv3" "WARN" "received 5xx after STARTTLS handshake reply (rerun with DEBUG>=2)" ;; 5) pr_svrty_high "$supported_no_ciph2" - fileout "sslv3" "HIGH" "SSLv3 is $supported_no_ciph1" + fileout "SSLv3" "HIGH" "$supported_no_ciph1" outln "(may need debugging)" add_tls_offered ssl3 yes ;; @@ -4379,7 +4381,7 @@ run_protocols() { pr_warning "strange reply, maybe a client side problem with SSLv3"; outln "$debug_recomm" else # warning on screen came already from locally_supported() - fileout "sslv3" "WARN" "SSLv3 is not tested due to lack of local support" + fileout "SSLv3" "WARN" "not tested due to lack of local support" fi ;; *) pr_fixme "unexpected value around line $((LINENO))"; outln "$debug_recomm" @@ -4394,7 +4396,7 @@ run_protocols() { fi case $? in 0) outln "offered" - fileout "tls1" "INFO" "TLSv1.0 is offered" + fileout "TLS1" "INFO" "offered" latest_supported="0301" latest_supported_string="TLSv1.0" add_tls_offered tls1 yes @@ -4403,10 +4405,10 @@ run_protocols() { add_tls_offered tls1 no if ! "$using_sockets" || [[ -z $latest_supported ]]; then outln - fileout "tls1" "INFO" "TLSv1.0 is not offered" # neither good or bad + fileout "TLS1" "INFO" "not offered" # neither good or bad else prln_svrty_critical " -- connection failed rather than downgrading to $latest_supported_string (NOT ok)" - fileout "tls1" "CRITICAL" "TLSv1.0: connection failed rather than downgrading to $latest_supported_string" + fileout "TLS1" "CRITICAL" "connection failed rather than downgrading to $latest_supported_string" fi ;; 2) pr_svrty_medium "not offered" @@ -4414,26 +4416,26 @@ run_protocols() { if [[ "$DETECTED_TLS_VERSION" == "0300" ]]; then [[ $DEBUG -ge 1 ]] && tm_out " -- downgraded" outln - fileout "tls1" "MEDIUM" "TLSv1.0 is not offered, and downgraded to SSL" + fileout "TLS1" "MEDIUM" "not offered, and downgraded to SSL" elif [[ "$DETECTED_TLS_VERSION" == 03* ]]; then detected_version_string="TLSv1.$((0x$DETECTED_TLS_VERSION-0x0301))" prln_svrty_critical " -- server responded with higher version number ($detected_version_string) than requested by client" - fileout "tls1" "CRITICAL" "TLSv1.0: server responded with higher version number ($detected_version_string) than requested by client" + fileout "TLS1" "CRITICAL" "server responded with higher version number ($detected_version_string) than requested by client" else if [[ ${#DETECTED_TLS_VERSION} -eq 4 ]]; then prln_svrty_critical "server responded with version number ${DETECTED_TLS_VERSION:0:2}.${DETECTED_TLS_VERSION:2:2} (NOT ok)" - fileout "tls1" "CRITICAL" "TLSv1.0: server responded with version number ${DETECTED_TLS_VERSION:0:2}.${DETECTED_TLS_VERSION:2:2}" + fileout "TLS1" "CRITICAL" "server responded with version number ${DETECTED_TLS_VERSION:0:2}.${DETECTED_TLS_VERSION:2:2}" else prln_svrty_medium " -- strange, server ${DETECTED_TLS_VERSION}" - fileout "tls1" "MEDIUM" "TLSv1.0: server ${DETECTED_TLS_VERSION}" + fileout "TLS1" "MEDIUM" "strange, server ${DETECTED_TLS_VERSION}" fi fi ;; 4) pr_fixme "signalled a 5xx after STARTTLS handshake"; outln "$debug_recomm" - fileout "tls1" "WARN" "TLSv1.0: received 5xx after STARTTLS handshake reply (rerun with DEBUG>=2)" + fileout "TLS1" "WARN" "received 5xx after STARTTLS handshake reply (rerun with DEBUG>=2)" ;; 5) outln "$supported_no_ciph1" # protocol ok, but no cipher - fileout "tls1" "INFO" "TLSv1.0 is $supported_no_ciph1" + fileout "TLS1" "INFO" "$supported_no_ciph1" add_tls_offered tls1 yes ;; 7) if "$using_sockets" ; then @@ -4441,7 +4443,7 @@ run_protocols() { pr_warning "strange reply, maybe a client side problem with TLS 1.0"; outln "$debug_recomm" else # warning on screen came already from locally_supported() - fileout "tls1" "WARN" "TLSv1.0 is not tested due to lack of local support" + fileout "TLS1" "WARN" "not tested due to lack of local support" fi ;; *) pr_fixme "unexpected value around line $((LINENO))"; outln "$debug_recomm" @@ -4456,7 +4458,7 @@ run_protocols() { fi case $? in 0) outln "offered" - fileout "tls1_1" "INFO" "TLSv1.1 is offered" + fileout "TLS1_1" "INFO" "offered" latest_supported="0302" latest_supported_string="TLSv1.1" add_tls_offered tls1_1 yes @@ -4465,10 +4467,10 @@ run_protocols() { add_tls_offered tls1_1 no if ! "$using_sockets" || [[ -z $latest_supported ]]; then outln - fileout "tls1_1" "INFO" "TLSv1.1 is not offered" # neither good or bad + fileout "TLS1_1" "INFO" "is not offered" # neither good or bad else prln_svrty_critical " -- connection failed rather than downgrading to $latest_supported_string" - fileout "tls1_1" "CRITICAL" "TLSv1.1: connection failed rather than downgrading to $latest_supported_string" + fileout "TLS1_1" "CRITICAL" "connection failed rather than downgrading to $latest_supported_string" fi ;; 2) out "not offered" @@ -4476,29 +4478,29 @@ run_protocols() { if [[ "$DETECTED_TLS_VERSION" == "$latest_supported" ]]; then [[ $DEBUG -ge 1 ]] && tm_out " -- downgraded" outln - fileout "tls1_1" "CRITICAL" "TLSv1.1 is not offered, and downgraded to a weaker protocol" + fileout "TLS1_1" "CRITICAL" "TLSv1.1 is not offered, and downgraded to a weaker protocol" elif [[ "$DETECTED_TLS_VERSION" == "0300" ]] && [[ "$latest_supported" == "0301" ]]; then prln_svrty_critical " -- server supports TLSv1.0, but downgraded to SSLv3 (NOT ok)" - fileout "tls1_1" "CRITICAL" "TLSv1.1 is not offered, and downgraded to SSLv3 rather than TLSv1.0" + fileout "TLS1_1" "CRITICAL" "not offered, and downgraded to SSLv3 rather than TLSv1.0" elif [[ "$DETECTED_TLS_VERSION" == 03* ]] && [[ 0x$DETECTED_TLS_VERSION -gt 0x0302 ]]; then detected_version_string="TLSv1.$((0x$DETECTED_TLS_VERSION-0x0301))" prln_svrty_critical " -- server responded with higher version number ($detected_version_string) than requested by client (NOT ok)" - fileout "tls1_1" "CRITICAL" "TLSv1.1 is not offered, server responded with higher version number ($detected_version_string) than requested by client" + fileout "TLS1_1" "CRITICAL" "not offered, server responded with higher version number ($detected_version_string) than requested by client" else if [[ ${#DETECTED_TLS_VERSION} -eq 4 ]]; then prln_svrty_critical "server responded with version number ${DETECTED_TLS_VERSION:0:2}.${DETECTED_TLS_VERSION:2:2} (NOT ok)" - fileout "tls1_1" "CRITICAL" "TLSv1.1: server responded with version number ${DETECTED_TLS_VERSION:0:2}.${DETECTED_TLS_VERSION:2:2}" + fileout "TLS1_1" "CRITICAL" "server responded with version number ${DETECTED_TLS_VERSION:0:2}.${DETECTED_TLS_VERSION:2:2}" else prln_svrty_medium " -- strange, server ${DETECTED_TLS_VERSION}" - fileout "tls1_1" "MEDIUM" "TLSv1.1: server ${DETECTED_TLS_VERSION}" + fileout "TLS1_1" "MEDIUM" "strange, server ${DETECTED_TLS_VERSION}" fi fi ;; 4) pr_fixme "signalled a 5xx after STARTTLS handshake"; outln "$debug_recomm" - fileout "tls1_1" "WARN" "TLSv1.1: received 5xx after STARTTLS handshake reply (rerun with DEBUG>=2)" + fileout "TLS1_1" "WARN" "received 5xx after STARTTLS handshake reply (rerun with DEBUG>=2)" ;; 5) outln "$supported_no_ciph1" - fileout "tls1_1" "INFO" "TLSv1.1 is $supported_no_ciph1" + fileout "TLS1_1" "INFO" "TLSv1.1 is $supported_no_ciph1" add_tls_offered tls1_1 yes ;; # protocol ok, but no cipher 7) if "$using_sockets" ; then @@ -4506,7 +4508,7 @@ run_protocols() { pr_warning "strange reply, maybe a client side problem with TLS 1.1"; outln "$debug_recomm" else # warning on screen came already from locally_supported() - fileout "tls1_1" "WARN" "TLSv1.1 is not tested due to lack of local support" + fileout "TLS1_1" "WARN" "not tested due to lack of local support" fi ;; *) pr_fixme "unexpected value around line $((LINENO))"; outln "$debug_recomm" @@ -4528,7 +4530,7 @@ run_protocols() { fi case $ret in 0) prln_done_best "offered (OK)" - fileout "tls1_2" "OK" "TLSv1.2 is offered" + fileout "TLS1_2" "OK" "offered" latest_supported="0303" latest_supported_string="TLSv1.2" add_tls_offered tls1_2 yes @@ -4537,10 +4539,10 @@ run_protocols() { add_tls_offered tls1_2 no if ! "$using_sockets" || [[ -z $latest_supported ]]; then outln - fileout "tls1_2" "MEDIUM" "TLSv1.2 is not offered" # no GCM, penalty + fileout "TLS1_2" "MEDIUM" "not offered" # no GCM, penalty else prln_svrty_critical " -- connection failed rather than downgrading to $latest_supported_string" - fileout "tls1_2" "CRITICAL" "TLSv1.2: connection failed rather than downgrading to $latest_supported_string" + fileout "TLS1_2" "CRITICAL" "connection failed rather than downgrading to $latest_supported_string" fi ;; 2) pr_svrty_medium "not offered" @@ -4553,28 +4555,28 @@ run_protocols() { if [[ "$DETECTED_TLS_VERSION" == "$latest_supported" ]]; then [[ $DEBUG -ge 1 ]] && tm_out " -- downgraded" outln - fileout "tls1_2" "MEDIUM" "TLSv1.2 is not offered and downgraded to a weaker protocol" + fileout "TLS1_2" "MEDIUM" "not offered and downgraded to a weaker protocol" elif [[ "$DETECTED_TLS_VERSION" == 03* ]] && [[ 0x$DETECTED_TLS_VERSION -lt 0x$latest_supported ]]; then prln_svrty_critical " -- server supports $latest_supported_string, but downgraded to $detected_version_string" - fileout "tls1_2" "CRITICAL" "TLSv1.2 is not offered, and downgraded to $detected_version_string rather than $latest_supported_string" + fileout "TLS1_2" "CRITICAL" "not offered, and downgraded to $detected_version_string rather than $latest_supported_string" elif [[ "$DETECTED_TLS_VERSION" == 03* ]] && [[ 0x$DETECTED_TLS_VERSION -gt 0x0303 ]]; then prln_svrty_critical " -- server responded with higher version number ($detected_version_string) than requested by client" - fileout "tls1_2" "CRITICAL" "TLSv1.2 is not offered, server responded with higher version number ($detected_version_string) than requested by client" + fileout "TLS1_2" "CRITICAL" "not offered, server responded with higher version number ($detected_version_string) than requested by client" else if [[ ${#DETECTED_TLS_VERSION} -eq 4 ]]; then prln_svrty_critical "server responded with version number ${DETECTED_TLS_VERSION:0:2}.${DETECTED_TLS_VERSION:2:2} (NOT ok)" - fileout "tls1_2" "CRITICAL" "TLSv1.2: server responded with version number ${DETECTED_TLS_VERSION:0:2}.${DETECTED_TLS_VERSION:2:2}" + fileout "TLS1_2" "CRITICAL" "server responded with version number ${DETECTED_TLS_VERSION:0:2}.${DETECTED_TLS_VERSION:2:2}" else prln_svrty_medium " -- strange, server ${DETECTED_TLS_VERSION}" - fileout "tls1_2" "MEDIUM" "TLSv1.2: server ${DETECTED_TLS_VERSION}" + fileout "TLS1_2" "MEDIUM" "strange, server ${DETECTED_TLS_VERSION}" fi fi ;; 4) pr_fixme "signalled a 5xx after STARTTLS handshake"; outln "$debug_recomm" - fileout "tls1_2" "WARN" "TLSv1.2: received 5xx after STARTTLS handshake reply (rerun with DEBUG>=2)" + fileout "TLS1_2" "WARN" "received 5xx after STARTTLS handshake reply (rerun with DEBUG>=2)" ;; 5) outln "$supported_no_ciph1" - fileout "tls1_2" "INFO" "TLSv1.2 is $supported_no_ciph1" + fileout "TLS1_2" "INFO" "is $supported_no_ciph1" add_tls_offered tls1_2 yes ;; # protocol ok, but no cipher 7) if "$using_sockets" ; then @@ -4582,7 +4584,7 @@ run_protocols() { pr_warning "strange reply, maybe a client side problem with TLS 1.2"; outln "$debug_recomm" else # warning on screen came already from locally_supported() - fileout "tls1_2" "WARN" "TLSv1.2 is not tested due to lack of local support" + fileout "TLS1_2" "WARN" "not tested due to lack of local support" fi ;; *) pr_fixme "unexpected value around line $((LINENO))"; outln "$debug_recomm" @@ -4616,7 +4618,7 @@ run_protocols() { case $? in 0) if ! "$using_sockets"; then outln "offered (OK)" - fileout "tls1_3" "OK" "TLSv1.3 is offered" + fileout "TLS1_3" "OK" "offered" else KEY_SHARE_EXTN_NR="28" tls_sockets "04" "$TLS13_CIPHER" "" "00, 2b, 00, 03, 02, 7f, 12" @@ -4655,10 +4657,10 @@ run_protocols() { KEY_SHARE_EXTN_NR="$key_share_extn_nr" if [[ -n "$drafts_offered" ]]; then pr_done_best "offered (OK)"; outln ": $drafts_offered" - fileout "tls1_3" "OK" "TLSv1.3 offered: $drafts_offered" + fileout "TLS1_3" "OK" "offered with $drafts_offered" else pr_warning "Unexpected results"; outln "$debug_recomm" - fileout "tls1_3" "WARN" "TLSv1.3 unexpected results" + fileout "TLS1_3" "WARN" "unexpected results" fi fi latest_supported="0304" @@ -4668,10 +4670,10 @@ run_protocols() { 1) out "not offered" if ! "$using_sockets" || [[ -z $latest_supported ]]; then outln - fileout "tls1_3" "INFO" "TLSv1.3 is not offered" + fileout "TLS1_3" "INFO" "not offered" else prln_svrty_critical " -- connection failed rather than downgrading to $latest_supported_string" - fileout "tls1_3" "CRITICAL" "TLSv1.3: connection failed rather than downgrading to $latest_supported_string" + fileout "TLS1_3" "CRITICAL" "connection failed rather than downgrading to $latest_supported_string" fi add_tls_offered tls1_3 no ;; @@ -4684,24 +4686,24 @@ run_protocols() { if [[ "$DETECTED_TLS_VERSION" == "$latest_supported" ]]; then [[ $DEBUG -eq 1 ]] && out " -- downgraded" outln - fileout "tls1_3" "INFO" "TLSv1.3 is not offered and downgraded to a weaker protocol" + fileout "TLS1_3" "INFO" "not offered and downgraded to a weaker protocol" elif [[ "$DETECTED_TLS_VERSION" == 03* ]] && [[ 0x$DETECTED_TLS_VERSION -lt 0x$latest_supported ]]; then prln_svrty_critical " -- server supports $latest_supported_string, but downgraded to $detected_version_string" - fileout "tls1_3" "CRITICAL" "TLSv1.3 is not offered, and downgraded to $detected_version_string rather than $latest_supported_string" + fileout "TLS1_3" "CRITICAL" "not offered, and downgraded to $detected_version_string rather than $latest_supported_string" elif [[ "$DETECTED_TLS_VERSION" == 03* ]] && [[ 0x$DETECTED_TLS_VERSION -gt 0x0304 ]]; then prln_svrty_critical " -- server responded with higher version number ($detected_version_string) than requested by client" - fileout "tls1_3" "CRITICAL" "TLSv1.3 is not offered, server responded with higher version number ($detected_version_string) than requested by client" + fileout "TLS1_3" "CRITICAL" "not offered, server responded with higher version number ($detected_version_string) than requested by client" else prln_svrty_critical " -- server responded with version number ${DETECTED_TLS_VERSION:0:2}.${DETECTED_TLS_VERSION:2:2}" - fileout "tls1_3" "CRITICAL" "TLSv1.3: server responded with version number ${DETECTED_TLS_VERSION:0:2}.${DETECTED_TLS_VERSION:2:2}" + fileout "TLS1_3" "CRITICAL" "server responded with version number ${DETECTED_TLS_VERSION:0:2}.${DETECTED_TLS_VERSION:2:2}" fi add_tls_offered tls1_3 no ;; 4) pr_fixme "signalled a 5xx after STARTTLS handshake"; outln "$debug_recomm" - fileout "tls1_3" "WARN" "TLSv1.3: received 5xx after STARTTLS handshake reply (rerun with DEBUG>=2)" + fileout "TLS1_3" "WARN" "received 5xx after STARTTLS handshake reply (rerun with DEBUG>=2)" ;; 5) outln "$supported_no_ciph1" - fileout "tls1_3" "INFO" "TLSv1.3 is $supported_no_ciph1" + fileout "TLS1_3" "INFO" "is $supported_no_ciph1" add_tls_offered tls1_3 yes ;; # protocol ok, but no cipher 7) if "$using_sockets" ; then @@ -4709,7 +4711,7 @@ run_protocols() { prln_warning "strange reply, maybe a client side problem with TLS 1.3"; outln "$debug_recomm" else # warning on screen came already from locally_supported() - fileout "tls1_3" "WARN" "TLSv1.3 is not tested due to lack of local support" + fileout "TLS1_3" "WARN" "not tested due to lack of local support" fi ;; *) pr_fixme "unexpected value around line $((LINENO))"; outln "$debug_recomm" @@ -5134,7 +5136,7 @@ run_server_preference() { outln "$list_fwd . " tmpfile_handle $FUNCNAME.txt return 6 - fileout "order_bug" "WARN" "Could not determine server cipher order, no matching cipher in this list found (pls report this): $list_fwd" + fileout "cipher_order" "WARN" "Could not determine server cipher order, no matching cipher in this list found (pls report this): $list_fwd" elif [[ -n "$STARTTLS_PROTOCOL" ]]; then # now it still could be that we hit this bug: https://github.com/drwetter/testssl.sh/issues/188 # workaround is to connect with a protocol @@ -5144,7 +5146,7 @@ run_server_preference() { if ! sclient_connect_successful $? $TMPFILE; then pr_warning "no matching cipher in this list found (pls report this): " outln "$list_fwd . " - fileout "order_bug" "WARN" "Could not determine server cipher order, no matching cipher in this list found (pls report this): $list_fwd" + fileout "cipher_order" "WARN" "Could not determine server cipher order, no matching cipher in this list found (pls report this): $list_fwd" tmpfile_handle $FUNCNAME.txt return 6 fi @@ -5170,12 +5172,12 @@ run_server_preference() { # server used the different ends (ciphers) from the client hello pr_svrty_high "nope (NOT ok)" limitedsense=" (limited sense as client will pick)" - fileout "order" "HIGH" "Server does NOT set a cipher order" + fileout "cipher_order" "HIGH" "Server does NOT set a cipher order" else pr_done_best "yes (OK)" has_cipher_order=true limitedsense="" - fileout "order" "OK" "Server sets a cipher order" + fileout "cipher_order" "OK" "Server sets a cipher order" fi debugme tm_out " $cipher1 | $cipher2" outln @@ -5207,40 +5209,40 @@ run_server_preference() { case "$default_proto" in *TLSv1.3) prln_done_best $default_proto - fileout "order_proto" "OK" "Default protocol TLS1.3" + fileout "protocol_negotiated" "OK" "Default protocol TLS1.3" ;; *TLSv1.2) prln_done_best $default_proto - fileout "order_proto" "OK" "Default protocol TLS1.2" + fileout "protocol_negotiated" "OK" "Default protocol TLS1.2" ;; *TLSv1.1) prln_done_good $default_proto - fileout "order_proto" "OK" "Default protocol TLS1.1" + fileout "protocol_negotiated" "OK" "Default protocol TLS1.1" ;; *TLSv1) outln $default_proto - fileout "order_proto" "INFO" "Default protocol TLS1.0" + fileout "protocol_negotiated" "INFO" "Default protocol TLS1.0" ;; *SSLv2) prln_svrty_critical $default_proto - fileout "order_proto" "CRITICAL" "Default protocol SSLv2" + fileout "protocol_negotiated" "CRITICAL" "Default protocol SSLv2" ;; *SSLv3) prln_svrty_critical $default_proto - fileout "order_proto" "CRITICAL" "Default protocol SSLv3" + fileout "protocol_negotiated" "CRITICAL" "Default protocol SSLv3" ;; "") pr_warning "default proto empty" if [[ $OSSL_VER == 1.0.2* ]]; then outln " (Hint: if IIS6 give OpenSSL 1.0.1 a try)" - fileout "order_proto" "WARN" "Default protocol empty (Hint: if IIS6 give OpenSSL 1.0.1 a try)" + fileout "protocol_negotiated" "WARN" "Default protocol empty (Hint: if IIS6 give OpenSSL 1.0.1 a try)" else - fileout "order_proto" "WARN" "Default protocol empty" + fileout "protocol_negotiated" "WARN" "Default protocol empty" fi ;; *) pr_warning "FIXME line $LINENO: $default_proto" - fileout "order_proto" "WARN" "FIXME line $LINENO: $default_proto" + fileout "protocol_negotiated" "WARN" "FIXME line $LINENO: $default_proto" ;; esac @@ -5254,25 +5256,25 @@ run_server_preference() { [[ -z "$default_cipher" ]] && default_cipher="$cipher1" pr_cipher_quality "$default_cipher" case $? in - 1) fileout "order_cipher" "CRITICAL" "Default cipher: $default_cipher$(read_dhbits_from_file "$TMPFILE" "string") $limitedsense" + 1) fileout "cipher_negotiated" "CRITICAL" "$default_cipher$(read_dhbits_from_file "$TMPFILE" "string") $limitedsense" ;; - 2) fileout "order_cipher" "HIGH" "Default cipher: $default_cipher$(read_dhbits_from_file "$TMPFILE" "string") $limitedsense" + 2) fileout "cipher_negotiated" "HIGH" "$default_cipher$(read_dhbits_from_file "$TMPFILE" "string") $limitedsense" ;; - 3) fileout "order_cipher" "MEDIUM" "Default cipher: $default_cipher$(read_dhbits_from_file "$TMPFILE" "string") $limitedsense" + 3) fileout "cipher_negotiated" "MEDIUM" "$default_cipher$(read_dhbits_from_file "$TMPFILE" "string") $limitedsense" ;; - 6|7) fileout "order_cipher" "OK" "Default cipher: $default_cipher$(read_dhbits_from_file "$TMPFILE" "string") $limitedsense" + 6|7) fileout "cipher_negotiated" "OK" "$default_cipher$(read_dhbits_from_file "$TMPFILE" "string") $limitedsense" ;; # best ones - 4) fileout "order_cipher" "LOW" "Default cipher: $default_cipher$(read_dhbits_from_file "$TMPFILE" "string") (cbc) $limitedsense" + 4) fileout "cipher_negotiated" "LOW" "$default_cipher$(read_dhbits_from_file "$TMPFILE" "string") (cbc) $limitedsense" ;; # it's CBC. --> lucky13 0) pr_warning "default cipher empty" ; if [[ $OSSL_VER == 1.0.2* ]]; then out " (Hint: if IIS6 give OpenSSL 1.0.1 a try)" - fileout "order_cipher" "WARN" "Default cipher empty (Hint: if IIS6 give OpenSSL 1.0.1 a try) $limitedsense" + fileout "cipher_negotiated" "WARN" "Default cipher empty (if IIS6 give OpenSSL 1.0.1 a try) $limitedsense" else - fileout "order_cipher" "WARN" "Default cipher empty $limitedsense" + fileout "cipher_negotiated" "WARN" "Default cipher empty $limitedsense" fi ;; - *) fileout "order_cipher" "INFO" "Default cipher: $default_cipher$(read_dhbits_from_file "$TMPFILE" "string") $limitedsense" + *) fileout "cipher_negotiated" "INFO" "$default_cipher$(read_dhbits_from_file "$TMPFILE" "string") $limitedsense" ;; esac read_dhbits_from_file "$TMPFILE" @@ -5388,7 +5390,7 @@ run_server_preference() { out "${proto[i]}" prev_cipher="${cipher[i]}" fi - fileout "order_${proto[i]}_cipher" "INFO" "Default cipher on ${proto[i]}: ${cipher[i]} $limitedsense" + fileout "cipher_order_${proto[i]}" "INFO" "${cipher[i]} at ${proto[i]} $limitedsense" done outln "\n No further cipher order check has been done as order is determined by the client" outln @@ -5663,7 +5665,7 @@ cipher_pref_check() { else out_row_aligned_max_width_by_entry "$order" " " $TERM_WIDTH pr_cipher_quality fi - fileout "order_$p" "INFO" "Default cipher order for protocol $p: $order" + fileout "cipher_order_${proto//./_}" "INFO" "$order" fi done <<< "$(tm_out " ssl3 00 SSLv3\n tls1 01 TLSv1\n tls1_1 02 TLSv1.1\n tls1_2 03 TLSv1.2\n tls1_3 04 TLSv1.3\n")" outln @@ -5716,7 +5718,7 @@ verify_retcode_helper() { # arg1: number of certificate if provided >1 determine_trust() { - local json_prefix="$1" + local jsonID="$1" local json_postfix="$2" local -i i=1 local -i num_ca_bundles=0 @@ -5741,7 +5743,7 @@ determine_trust() { : ;; *) addtl_warning="Your $OPENSSL <= 1.0.2 might be too unreliable to determine trust" - fileout "${json_prefix}${json_postfix}" "WARN" "$addtl_warning" + fileout "${jsonID}${json_postfix}" "WARN" "$addtl_warning" addtl_warning="(${addtl_warning})" ;; esac @@ -5788,7 +5790,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 OK: - fileout "${json_prefix}${json_postfix}" "OK" "passed. $addtl_warning" + fileout "${jsonID}${json_postfix}" "OK" "passed. $addtl_warning" else # at least one failed pr_svrty_critical "NOT ok" @@ -5801,7 +5803,7 @@ determine_trust() { else out "$code" fi - fileout "${json_prefix}${json_postfix}" "CRITICAL" "failed $code. $addtl_warning" + fileout "${jsonID}${json_postfix}" "CRITICAL" "failed $code. $addtl_warning" else # is one ok and the others not ==> display the culprit store if "$some_ok"; then @@ -5829,7 +5831,7 @@ determine_trust() { [[ "$DEBUG" -eq 0 ]] && tm_out "$spaces" pr_done_good "OK: $ok_was" fi - fileout "${json_prefix}${json_postfix}" "CRITICAL" "Some certificate trust checks failed -> $notok_was $addtl_warning, OK -> $ok_was" + fileout "${jsonID}${json_postfix}" "CRITICAL" "Some certificate trust checks failed -> $notok_was $addtl_warning, OK -> $ok_was" fi [[ -n "$addtl_warning" ]] && out "\n$spaces" && pr_warning "$addtl_warning" fi @@ -5842,7 +5844,7 @@ determine_trust() { tls_time() { local now difftime local spaces=" " - local json_prefix="TLS_time" + local jsonID="TLS_time" pr_bold " TLS clock skew" ; out "$spaces" TLS_DIFFTIME_SET=true # this is a switch whether we want to measure the remote TLS_TIME @@ -5856,17 +5858,17 @@ tls_time() { if [[ "${#difftime}" -gt 5 ]]; then # openssl >= 1.0.1f fills this field with random values! --> good for possible fingerprint out "Random values, no fingerprinting possible " - fileout "${json_prefix}" "INFO" "The server's TLS time seems to be filled with random values to prevent fingerprinting" + fileout "${jsonID}" "INFO" "The server's TLS time seems to be filled with random values to prevent fingerprinting" else [[ $difftime != "-"* ]] && [[ $difftime != "0" ]] && difftime="+$difftime" out "$difftime"; out " sec from localtime"; - fileout "${json_prefix}" "INFO" "The server's TLS time is skewed from your localtime by $difftime seconds" + fileout "${jsonID}" "INFO" "The server's TLS time is skewed from your localtime by $difftime seconds" fi debugme tm_out "$TLS_TIME" outln else outln "SSLv3 through TLS 1.2 didn't return a timestamp" - fileout "${json_prefix}" "INFO" "No TLS timestamp returned by SSLv3 through TLSv1.2" + fileout "${jsonID}" "INFO" "No TLS timestamp returned by SSLv3 through TLSv1.2" fi TLS_DIFFTIME_SET=false # reset the switch to save calls to date and friend in tls_sockets() return 0 @@ -6234,7 +6236,7 @@ compare_server_name_to_cert() } must_staple() { - local json_prefix="OCSP_must_staple" + local jsonID="OCSP_must_staple" local json_postfix="$1" local provides_stapling="$2" local cert extn @@ -6271,14 +6273,14 @@ must_staple() { if "$supported"; then if "$provides_stapling"; then prln_done_good "supported" - fileout "${json_prefix}${json_postfix}" "OK" "supported" + fileout "${jsonID}${json_postfix}" "OK" "supported" else prln_svrty_high "requires OCSP stapling (NOT ok)" - fileout "${json_prefix}${json_postfix}" "HIGH" "must staple extension detected but no OCSP stapling provided" + fileout "${jsonID}${json_postfix}" "HIGH" "must staple extension detected but no OCSP stapling provided" fi else outln "no" - fileout "${json_prefix}${json_postfix}" "INFO" "no" + fileout "${jsonID}${json_postfix}" "INFO" "no" fi } @@ -6372,7 +6374,7 @@ certificate_info() { local cnok="OK" local expfinding expok="OK" local json_postfix="" # string to place at the end of JSON IDs when there is more than one certificate - local json_prefix="" # string to place at beginning of JSON IDs + local jsonID="" # string to place at beginning of JSON IDs local indent="" local days2warn2=$DAYS2WARN2 local days2warn1=$DAYS2WARN1 @@ -6398,7 +6400,7 @@ certificate_info() { cert_key_algo="${cert_key_algo// /}" out "$indent" ; pr_bold " Signature Algorithm " - json_prefix="cert_sig_algorithm" + jsonID="cert_sig_algorithm" case $cert_sig_algo in sha1WithRSAEncryption) pr_svrty_medium "SHA1 with RSA" @@ -6406,111 +6408,111 @@ certificate_info() { out " -- besides: users will receive a "; pr_svrty_high "strong browser WARNING" fi outln - fileout "${json_prefix}${json_postfix}" "MEDIUM" "SHA1 with RSA" + fileout "${jsonID}${json_postfix}" "MEDIUM" "SHA1 with RSA" ;; sha224WithRSAEncryption) outln "SHA224 with RSA" - fileout "${json_prefix}${json_postfix}" "INFO" "SHA224 with RSA" + fileout "${jsonID}${json_postfix}" "INFO" "SHA224 with RSA" ;; sha256WithRSAEncryption) prln_done_good "SHA256 with RSA" - fileout "${json_prefix}${json_postfix}" "OK" "SHA256 with RSA" + fileout "${jsonID}${json_postfix}" "OK" "SHA256 with RSA" ;; sha384WithRSAEncryption) prln_done_good "SHA384 with RSA" - fileout "${json_prefix}${json_postfix}" "OK" "SHA384 with RSA" + fileout "${jsonID}${json_postfix}" "OK" "SHA384 with RSA" ;; sha512WithRSAEncryption) prln_done_good "SHA512 with RSA" - fileout "${json_prefix}${json_postfix}" "OK" "SHA512 with RSA" + fileout "${jsonID}${json_postfix}" "OK" "SHA512 with RSA" ;; ecdsa-with-SHA1) prln_svrty_medium "ECDSA with SHA1" - fileout "${json_prefix}${json_postfix}" "MEDIUM" "ECDSA with SHA1" + fileout "${jsonID}${json_postfix}" "MEDIUM" "ECDSA with SHA1" ;; ecdsa-with-SHA224) outln "ECDSA with SHA224" - fileout "${json_prefix}${json_postfix}" "INFO" "ECDSA with SHA224" + fileout "${jsonID}${json_postfix}" "INFO" "ECDSA with SHA224" ;; ecdsa-with-SHA256) prln_done_good "ECDSA with SHA256" - fileout "${json_prefix}${json_postfix}" "OK" "ECDSA with SHA256" + fileout "${jsonID}${json_postfix}" "OK" "ECDSA with SHA256" ;; ecdsa-with-SHA384) prln_done_good "ECDSA with SHA384" - fileout "${json_prefix}${json_postfix}" "OK" "ECDSA with SHA384" + fileout "${jsonID}${json_postfix}" "OK" "ECDSA with SHA384" ;; ecdsa-with-SHA512) prln_done_good "ECDSA with SHA512" - fileout "${json_prefix}${json_postfix}" "OK" "ECDSA with SHA512" + fileout "${jsonID}${json_postfix}" "OK" "ECDSA with SHA512" ;; dsaWithSHA1) prln_svrty_medium "DSA with SHA1" - fileout "${json_prefix}${json_postfix}" "MEDIUM" "DSA with SHA1" + fileout "${jsonID}${json_postfix}" "MEDIUM" "DSA with SHA1" ;; dsa_with_SHA224) outln "DSA with SHA224" - fileout "${json_prefix}${json_postfix}" "INFO" "DSA with SHA224" + fileout "${jsonID}${json_postfix}" "INFO" "DSA with SHA224" ;; dsa_with_SHA256) prln_done_good "DSA with SHA256" - fileout "${json_prefix}${json_postfix}" "OK" "DSA with SHA256" + fileout "${jsonID}${json_postfix}" "OK" "DSA with SHA256" ;; rsassaPss) cert_sig_hash_algo="$($OPENSSL x509 -in $HOSTCERT -noout -text 2>>$ERRFILE | grep -A 1 "Signature Algorithm" | head -2 | tail -1 | sed 's/^.*Hash Algorithm: //')" case $cert_sig_hash_algo in sha1) prln_svrty_medium "RSASSA-PSS with SHA1" - fileout "${json_prefix}${json_postfix}" "MEDIUM" "RSASSA-PSS with SHA1" + fileout "${jsonID}${json_postfix}" "MEDIUM" "RSASSA-PSS with SHA1" ;; sha224) outln "RSASSA-PSS with SHA224" - fileout "${json_prefix}${json_postfix}" "INFO" "RSASSA-PSS with SHA224" + fileout "${jsonID}${json_postfix}" "INFO" "RSASSA-PSS with SHA224" ;; sha256) prln_done_good "RSASSA-PSS with SHA256" - fileout "${json_prefix}${json_postfix}" "OK" "RSASSA-PSS with SHA256" + fileout "${jsonID}${json_postfix}" "OK" "RSASSA-PSS with SHA256" ;; sha384) prln_done_good "RSASSA-PSS with SHA384" - fileout "${json_prefix}${json_postfix}" "OK" "RSASSA-PSS with SHA384" + fileout "${jsonID}${json_postfix}" "OK" "RSASSA-PSS with SHA384" ;; sha512) prln_done_good "RSASSA-PSS with SHA512" - fileout "${json_prefix}${json_postfix}" "OK" "RSASSA-PSS with SHA512" + fileout "${jsonID}${json_postfix}" "OK" "RSASSA-PSS with SHA512" ;; *) out "RSASSA-PSS with $cert_sig_hash_algo" prln_warning " (Unknown hash algorithm)" - fileout "${json_prefix}${json_postfix}" "DEBUG" "RSASSA-PSS with $cert_sig_hash_algo" + fileout "${jsonID}${json_postfix}" "DEBUG" "RSASSA-PSS with $cert_sig_hash_algo" esac ;; md2*) prln_svrty_critical "MD2" - fileout "${json_prefix}${json_postfix}" "CRITICAL" "MD2" + fileout "${jsonID}${json_postfix}" "CRITICAL" "MD2" ;; md4*) prln_svrty_critical "MD4" - fileout "${json_prefix}${json_postfix}" "CRITICAL" "MD4" + fileout "${jsonID}${json_postfix}" "CRITICAL" "MD4" ;; md5*) prln_svrty_critical "MD5" - fileout "${json_prefix}${json_postfix}" "CRITICAL" "MD5" + fileout "${jsonID}${json_postfix}" "CRITICAL" "MD5" ;; *) out "$cert_sig_algo (" pr_warning "FIXME: can't tell whether this is good or not" outln ")" - fileout "${json_prefix}${json_postfix}" "DEBUG" "$cert_sig_algo" + fileout "${jsonID}${json_postfix}" "DEBUG" "$cert_sig_algo" ;; esac # old, but interesting: https://blog.hboeck.de/archives/754-Playing-with-the-EFF-SSL-Observatory.html out "$indent"; pr_bold " Server key size " - json_prefix="cert_key_size" + jsonID="cert_key_size" if [[ -z "$cert_keysize" ]]; then outln "(couldn't determine)" - fileout "${json_prefix}${json_postfix}" "Server keys size cannot be determined" + fileout "${jsonID}${json_postfix}" "Server keys size cannot be determined" else case $cert_key_algo in *RSA*|*rsa*) out "RSA ";; @@ -6527,22 +6529,22 @@ certificate_info() { if [[ $cert_key_algo =~ ecdsa ]] || [[ $cert_key_algo =~ ecPublicKey ]]; then if [[ "$cert_keysize" -le 110 ]]; then # a guess pr_svrty_critical "$cert_keysize" - fileout "${json_prefix}${json_postfix}" "CRITICAL" "Server keys $cert_keysize EC bits" + fileout "${jsonID}${json_postfix}" "CRITICAL" "Server keys $cert_keysize EC bits" elif [[ "$cert_keysize" -le 123 ]]; then # a guess pr_svrty_high "$cert_keysize" - fileout "${json_prefix}${json_postfix}" "HIGH" "Server keys $cert_keysize EC bits" + fileout "${jsonID}${json_postfix}" "HIGH" "Server keys $cert_keysize EC bits" elif [[ "$cert_keysize" -le 163 ]]; then pr_svrty_medium "$cert_keysize" - fileout "${json_prefix}${json_postfix}" "MEDIUM" "Server keys $cert_keysize EC bits" + fileout "${jsonID}${json_postfix}" "MEDIUM" "Server keys $cert_keysize EC bits" elif [[ "$cert_keysize" -le 224 ]]; then out "$cert_keysize" - fileout "${json_prefix}${json_postfix}" "INFO" "Server keys $cert_keysize EC bits" + fileout "${jsonID}${json_postfix}" "INFO" "Server keys $cert_keysize EC bits" elif [[ "$cert_keysize" -le 533 ]]; then pr_done_good "$cert_keysize" - fileout "${json_prefix}${json_postfix}" "OK" "Server keys $cert_keysize EC bits" + fileout "${jsonID}${json_postfix}" "OK" "Server keys $cert_keysize EC bits" else out "keysize: $cert_keysize (not expected, FIXME)" - fileout "${json_prefix}${json_postfix}" "DEBUG" "Server keys $cert_keysize bits (not expected)" + fileout "${jsonID}${json_postfix}" "DEBUG" "Server keys $cert_keysize bits (not expected)" fi outln " bits" elif [[ $cert_key_algo = *RSA* ]] || [[ $cert_key_algo = *rsa* ]] || [[ $cert_key_algo = *dsa* ]] || \ @@ -6550,84 +6552,84 @@ certificate_info() { if [[ "$cert_keysize" -le 512 ]]; then pr_svrty_critical "$cert_keysize" outln " bits" - fileout "${json_prefix}${json_postfix}" "CRITICAL" "Server keys $cert_keysize bits" + fileout "${jsonID}${json_postfix}" "CRITICAL" "Server keys $cert_keysize bits" elif [[ "$cert_keysize" -le 768 ]]; then pr_svrty_high "$cert_keysize" outln " bits" - fileout "${json_prefix}${json_postfix}" "HIGH" "Server keys $cert_keysize bits" + fileout "${jsonID}${json_postfix}" "HIGH" "Server keys $cert_keysize bits" elif [[ "$cert_keysize" -le 1024 ]]; then pr_svrty_medium "$cert_keysize" outln " bits" - fileout "${json_prefix}${json_postfix}" "MEDIUM" "Server keys $cert_keysize bits" + fileout "${jsonID}${json_postfix}" "MEDIUM" "Server keys $cert_keysize bits" elif [[ "$cert_keysize" -le 2048 ]]; then outln "$cert_keysize bits" - fileout "${json_prefix}${json_postfix}" "INFO" "Server keys $cert_keysize bits" + fileout "${jsonID}${json_postfix}" "INFO" "Server keys $cert_keysize bits" elif [[ "$cert_keysize" -le 4096 ]]; then pr_done_good "$cert_keysize" - fileout "${json_prefix}${json_postfix}" "OK" "Server keys $cert_keysize bits" + fileout "${jsonID}${json_postfix}" "OK" "Server keys $cert_keysize bits" outln " bits" else pr_warning "weird key size: $cert_keysize bits"; outln " (could cause compatibility problems)" - fileout "${json_prefix}${json_postfix}" "WARN" "Server keys $cert_keysize bits (Odd)" + fileout "${jsonID}${json_postfix}" "WARN" "Server keys $cert_keysize bits (Odd)" fi else out "$cert_keysize bits (" pr_warning "FIXME: can't tell whether this is good or not" outln ")" - fileout "${json_prefix}${json_postfix}" "WARN" "Server keys $cert_keysize bits (unknown signature algorithm)" + fileout "${jsonID}${json_postfix}" "WARN" "Server keys $cert_keysize bits (unknown signature algorithm)" fi fi out "$indent"; pr_bold " Server key usage "; outok=true - json_prefix="cert_key_usage" + jsonID="cert_key_usage" cert_keyusage=$($OPENSSL x509 -text -noout -in $HOSTCERT 2>>$ERRFILE | grep -A 1 "X509v3 Key Usage:" | tail -n +2 | sed 's/^[ \t]*//') if [[ -n "$cert_keyusage" ]]; then outln "$cert_keyusage" if ( [[ " $cert_type " =~ " RSASig " ]] || [[ " $cert_type " =~ " DSA " ]] || [[ " $cert_type " =~ " ECDSA " ]] ) && \ [[ ! "$cert_keyusage" =~ "Digital Signature" ]]; then prln_svrty_high "$indent -- certificate incorrectly used for digital signatures" - fileout "${json_prefix}${json_postfix}" "HIGH" "Certificate incorrectly used for digital signatures: \"$cert_keyusage\"" + fileout "${jsonID}${json_postfix}" "HIGH" "Certificate incorrectly used for digital signatures: \"$cert_keyusage\"" outok=false fi if [[ " $cert_type " =~ " RSAKMK " ]] && [[ ! "$cert_keyusage" =~ "Key Encipherment" ]]; then prln_svrty_high "$indent -- certificate incorrectly used for key encipherment" - fileout "${json_prefix}${json_postfix}" "HIGH" "Certificate incorrectly used for key encipherment: \"$cert_keyusage\"" + fileout "${jsonID}${json_postfix}" "HIGH" "Certificate incorrectly used for key encipherment: \"$cert_keyusage\"" outok=false fi if ( [[ " $cert_type " =~ " DH " ]] || [[ " $cert_type " =~ " ECDH " ]] ) && \ [[ ! "$cert_keyusage" =~ "Key Agreement" ]]; then prln_svrty_high "$indent -- certificate incorrectly used for key agreement" - fileout "${json_prefix}${json_postfix}" "HIGH" "Certificate incorrectly used for key agreement: \"$cert_keyusage\"" + fileout "${jsonID}${json_postfix}" "HIGH" "Certificate incorrectly used for key agreement: \"$cert_keyusage\"" outok=false fi else outln "--" - fileout "${json_prefix}key_usage" "INFO" "No server key usage information" + fileout "${jsonID}key_usage" "INFO" "No server key usage information" outok=false fi if "$outok"; then - fileout "${json_prefix}key_usage" "INFO" "Server key usage information: $cert_keyusage" + fileout "${jsonID}key_usage" "INFO" "$cert_keyusage" fi out "$indent"; pr_bold " Server extended key usage "; - json_prefix="cert_extended_key_usage" + jsonID="cert_extended_key_usage" outok=true cert_ext_keyusage="$($OPENSSL x509 -noout -text -in $HOSTCERT 2>>$ERRFILE | grep -A 1 "X509v3 Extended Key Usage: " | tail -1 | sed 's/^[ \t]*//')" if [[ -n "$cert_ext_keyusage" ]]; then outln "$cert_ext_keyusage" if [[ ! "$cert_ext_keyusage" =~ "TLS Web Server Authentication" ]] && [[ ! "$cert_ext_keyusage" =~ "Any Extended Key Usage" ]]; then prln_svrty_high "$indent -- certificate incorrectly used for TLS Web Server Authentication" - fileout "${json_prefix}${json_postfix}" "HIGH" "Certificate incorrectly used for TLS Web Server Authentication: \"$cert_ext_keyusage\"" + fileout "${jsonID}${json_postfix}" "HIGH" "Certificate incorrectly used for TLS Web Server Authentication: \"$cert_ext_keyusage\"" outok=false fi else outln "--" - fileout "${json_prefix}${json_postfix}" "INFO" "No server extended key usage information" + fileout "${jsonID}${json_postfix}" "INFO" "No server extended key usage information" outok=false fi if "$outok"; then - fileout "${json_prefix}${json_postfix}" "INFO" "Server extended key usage: \"cert_ext_keyusage\"" + fileout "${jsonID}${json_postfix}" "INFO" "cert_ext_keyusage" fi out "$indent"; pr_bold " Fingerprint / Serial " @@ -6703,25 +6705,25 @@ certificate_info() { # ^^^ CACert out "$indent"; pr_bold " subjectAltName (SAN) " - json_prefix="cert_SAN" + jsonID="cert_SAN" if [[ -n "$sans" ]]; then while read san; do [[ -n "$san" ]] && all_san+="$san " done <<< "$sans" prln_italic "$(out_row_aligned_max_width "$all_san" "$indent " $TERM_WIDTH)" - fileout "${json_prefix}${json_postfix}" "INFO" "$all_san" + fileout "${jsonID}${json_postfix}" "INFO" "$all_san" else if [[ $SERVICE == "HTTP" ]] || "$ASSUME_HTTP"; then pr_svrty_high "missing (NOT ok)"; outln " -- Browsers are complaining" - fileout "${json_prefix}${json_postfix}" "HIGH" "No SAN, browsers are complaining" + fileout "${jsonID}${json_postfix}" "HIGH" "No SAN, browsers are complaining" else pr_svrty_medium "missing"; outln " -- no SAN is deprecated" - fileout "${json_prefix}${json_postfix}" "MEDIUM" "Providing no SAN is deprecated" + fileout "${jsonID}${json_postfix}" "MEDIUM" "Providing no SAN is deprecated" fi fi out "$indent"; pr_bold " Issuer " - json_prefix="cert_issuer" + jsonID="cert_issuer" #FIXME: oid would be better maybe (see above) issuer="$($OPENSSL x509 -in $HOSTCERT -noout -issuer -nameopt multiline,-align,sname,-esc_msb,utf8,-space_eq 2>>$ERRFILE)" issuer_CN="$(awk -F'=' '/CN=/ { print $2 }' <<< "$issuer")" @@ -6731,7 +6733,7 @@ certificate_info() { if [[ "$issuer_O" == "issuer=" ]] || [[ "$issuer_O" == "issuer= " ]] || [[ "$issuer_CN" == "$cn" ]]; then prln_svrty_critical "self-signed (NOT ok)" - fileout "${json_prefix}${json_postfix}" "CRITICAL" "selfsigned" + fileout "${jsonID}${json_postfix}" "CRITICAL" "selfsigned" else issuerfinding="$issuer_CN" pr_italic "$issuer_CN" @@ -6759,7 +6761,7 @@ certificate_info() { out ")" fi outln - fileout "${json_prefix}${json_postfix}" "INFO" "$issuerfinding" + fileout "${jsonID}${json_postfix}" "INFO" "$issuerfinding" fi out "$indent"; pr_bold " Trust (hostname) " @@ -6879,18 +6881,18 @@ certificate_info() { fileout "cert_trust${json_postfix}" "$trust_sni_finding" "${trustfinding}${trustfinding_nosni}" out "$indent"; pr_bold " Chain of trust"; out " " - json_prefix="cert_chain_of_trust" + jsonID="cert_chain_of_trust" if [[ "$issuer_O" =~ StartCom ]] || [[ "$issuer_O" =~ WoSign ]] || [[ "$issuer_CN" =~ StartCom ]] || [[ "$issuer_CN" =~ WoSign ]]; then # Shortcut for this special case here. pr_italic "WoSign/StartCom"; out " are " ; prln_svrty_critical "not trusted anymore (NOT ok)" - fileout "${json_prefix}${json_postfix}" "CRITICAL" "Issuer not trusted anymore (WoSign/StartCom)" + fileout "${jsonID}${json_postfix}" "CRITICAL" "Issuer not trusted anymore (WoSign/StartCom)" else - determine_trust "$json_prefix" "$json_postfix" # Also handles fileout + determine_trust "$jsonID" "$json_postfix" # Also handles fileout 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) " - json_prefix="cert_EV" + jsonID="cert_EV" # only the first one, seldom we have two policy_oid=$($OPENSSL x509 -in $HOSTCERT -text 2>>$ERRFILE | awk '/ .Policy: / { print $2 }' | awk 'NR < 2') if echo "$issuer" | egrep -q 'Extended Validation|Extended Validated|EV SSL|EV CA' || \ @@ -6902,10 +6904,10 @@ certificate_info() { [[ 1.3.6.1.4.1.17326.10.8.12.1.2 == "$policy_oid" ]] || \ [[ 1.3.6.1.4.1.13177.10.1.3.10 == "$policy_oid" ]] ; then out "yes " - fileout "${json_prefix}${json_postfix}" "OK" "yes" + fileout "${jsonID}${json_postfix}" "OK" "yes" else out "no " - fileout "${json_prefix}${json_postfix}" "INFO" "no" + fileout "${jsonID}${json_postfix}" "INFO" "no" fi debugme echo "($(newline_to_spaces "$policy_oid"))" outln @@ -6966,15 +6968,15 @@ certificate_info() { ocsp_uri=$($OPENSSL x509 -in $HOSTCERT -noout -ocsp_uri 2>>$ERRFILE) out "$indent"; pr_bold " Certificate Revocation List " - json_prefix="cert_CRL" + jsonID="cert_CRL" if [[ -z "$crl" ]] ; then if [[ -n "$ocsp_uri" ]]; then outln "--" - fileout "${json_prefix}${json_postfix}" "INFO" "none" + fileout "${jsonID}${json_postfix}" "INFO" "none" else pr_svrty_high "NOT ok --" outln " neither CRL nor OCSP URI provided" - fileout "${json_prefix}${json_postfix}" "HIGH" "Neither CRL nor OCSP URI provided" + fileout "${jsonID}${json_postfix}" "HIGH" "Neither CRL nor OCSP URI provided" fi else if [[ $(count_lines "$crl") -eq 1 ]]; then @@ -6982,46 +6984,46 @@ certificate_info() { else # more than one CRL out_row_aligned "$crl" "$spaces" fi - fileout "${json_prefix}${json_postfix}" "INFO" "$crl" + fileout "${jsonID}${json_postfix}" "INFO" "$crl" fi out "$indent"; pr_bold " OCSP URI " - json_prefix="cert_OCSP_URI" + jsonID="cert_OCSP_URI" if [[ -z "$ocsp_uri" ]]; then outln "--" - fileout "${json_prefix}${json_postfix}" "INFO" "--" + fileout "${jsonID}${json_postfix}" "INFO" "--" else if [[ $(count_lines "$ocsp_uri") -eq 1 ]]; then outln "$ocsp_uri" else out_row_aligned "$ocsp_uri" "$spaces" fi - fileout "${json_prefix}${json_postfix}" "INFO" "$ocsp_uri" + fileout "${jsonID}${json_postfix}" "INFO" "$ocsp_uri" fi out "$indent"; pr_bold " OCSP stapling " - json_prefix="OCSP_stapling" + jsonID="OCSP_stapling" if grep -a "OCSP response" <<< "$ocsp_response" | grep -q "no response sent" ; then if [[ -n "$ocsp_uri" ]]; then pr_svrty_low "not offered" - fileout "${json_prefix}${json_postfix}" "LOW" "not offered" + fileout "${jsonID}${json_postfix}" "LOW" "not offered" else out "not offered" - fileout "${json_prefix}${json_postfix}" "INFO" "not offered" + fileout "${jsonID}${json_postfix}" "INFO" "not offered" fi else if grep -a "OCSP Response Status" <<<"$ocsp_response_status" | grep -q successful; then pr_done_good "offered" - fileout "${json_prefix}${json_postfix}" "OK" "offered" + fileout "${jsonID}${json_postfix}" "OK" "offered" provides_stapling=true else if $GOST_STATUS_PROBLEM; then pr_warning "(GOST servers make problems here, sorry)" - fileout "${json_prefix}${json_postfix}" "WARN" "(The GOST server made a problem here, sorry)" + fileout "${jsonID}${json_postfix}" "WARN" "(The GOST server made a problem here, sorry)" ret=0 else out "(response status unknown)" - fileout "${json_prefix}${json_postfix}" "OK" " not sure what's going on here, \'$ocsp_response\'" + fileout "${jsonID}${json_postfix}" "OK" " not sure what's going on here, \'$ocsp_response\'" debugme grep -a -A20 -B2 "OCSP response" <<<"$ocsp_response" ret=2 fi @@ -7033,7 +7035,7 @@ certificate_info() { must_staple "$json_postfix" "$provides_stapling" out "$indent"; pr_bold " DNS CAA RR"; out " (experimental) " - json_prefix="CAA_record" + jsonID="CAA_record" caa_node="$NODE" caa="" while ( [[ -z "$caa" ]] && [[ ! -z "$caa_node" ]] ); do @@ -7055,13 +7057,13 @@ certificate_info() { done <<< "$caa" all_caa=${all_caa%, } # strip trailing comma pr_italic "$(out_row_aligned_max_width "$all_caa" "$indent " $TERM_WIDTH)" - fileout "${json_prefix}${json_postfix}" "OK" "'DNS Certification Authority Authorization (CAA) Resource Record / RFC6844' \'$all_caa\' " + fileout "${jsonID}${json_postfix}" "OK" "'DNS Certification Authority Authorization (CAA) Resource Record / RFC6844' \'$all_caa\' " elif "$NODNS"; then pr_warning "(was instructed to not use DNS)" - fileout "${json_prefix}${json_postfix}" "WARN" "check skipped as instructed" + fileout "${jsonID}${json_postfix}" "WARN" "check skipped as instructed" else pr_svrty_low "not offered" - fileout "${json_prefix}${json_postfix}" "LOW" "'DNS Certification Authority Authorization (CAA) Resource Record / RFC6844' not offered" + fileout "${jsonID}${json_postfix}" "LOW" "'DNS Certification Authority Authorization (CAA) Resource Record / RFC6844' not offered" fi outln @@ -7260,10 +7262,10 @@ run_server_defaults() { fi pr_bold " Session Ticket RFC 5077 hint " - json_prefix="session_ticket" + jsonID="TLS_session_ticket" if [[ -z "$sessticket_lifetime_hint" ]]; then outln "(no lifetime advertised)" - fileout "${json_prefix}" "INFO" "No TLS session ticket RFC 5077 lifetime advertised" + fileout "${jsonID}" "INFO" "No TLS session ticket RFC 5077 lifetime advertised" # it MAY be given a hint of the lifetime of the ticket, see https://tools.ietf.org/html/rfc5077#section-5.6 . # Sometimes it just does not -- but it then may also support TLS session tickets reuse else @@ -7272,10 +7274,10 @@ run_server_defaults() { out "$lifetime $unit" if [[ $((3600 * 24)) -lt $lifetime ]]; then prln_svrty_low " but: PFS requires session ticket keys to be rotated < daily !" - fileout "${json_prefix}" "LOW" "TLS session ticket RFC 5077 valid for $lifetime $unit but PFS requires session ticket keys to be rotated at least daily!" + fileout "${jsonID}" "LOW" "TLS session ticket RFC 5077 valid for $lifetime $unit but PFS requires session ticket keys to be rotated at least daily!" else outln ", session tickets keys seems to be rotated < daily" - fileout "${json_prefix}" "INFO" "TLS session ticket RFC 5077 valid for $lifetime $unit only (PFS requires session ticket keys are rotated at least daily)" + fileout "${jsonID}" "INFO" "TLS session ticket RFC 5077 valid for $lifetime $unit only (PFS requires session ticket keys are rotated at least daily)" fi fi @@ -7453,7 +7455,7 @@ run_pfs() { if [[ "$nr_supported_ciphers" -le "$CLIENT_MIN_PFS" ]]; then outln prln_local_problem "You only have $nr_supported_ciphers PFS ciphers on the client side " - fileout "pfs" "WARN" "(Perfect) Forward Secrecy tests: Skipped. You only have $nr_supported_ciphers PFS ciphers on the client site. ($CLIENT_MIN_PFS are required)" + fileout "pfs" "WARN" "(P)FS tests skipped as you only have $nr_supported_ciphers PFS ciphers on the client site. ($CLIENT_MIN_PFS are required)" return 1 fi $OPENSSL s_client $(s_client_options "-cipher $pfs_cipher_list $STARTTLS $BUGS -connect $NODEIP:$PORT $PROXY $SNI") >$TMPFILE 2>$ERRFILE =3 to confirm" - fileout "heartbleed" "CRITICAL" "Heartbleed: VULNERABLE $cve" "$cwe" "$hint" + fileout "$jsonID" "CRITICAL" "VULNERABLE $cve" "$cwe" "$hint" ret=1 fi else pr_svrty_critical "VULNERABLE (NOT ok)" - fileout "heartbleed" "CRITICAL" "Heartbleed: VULNERABLE $cve" "$cwe" "$hint" + fileout "$jsonID" "CRITICAL" "VULNERABLE $cve" "$cwe" "$hint" ret=1 fi else pr_done_best "not vulnerable (OK)" - fileout "heartbleed" "OK" "Heartbleed: not vulnerable $cve" "$cwe" + fileout "$jsonID" "OK" "not vulnerable $cve" "$cwe" ret=0 fi fi @@ -11525,6 +11528,7 @@ run_ccs_injection(){ local cve="CVE-2014-0224" local cwe="CWE-310" local hint="" + local jsonID="CCS" # see https://www.openssl.org/news/secadv_20140605.txt # mainly adapted from Ramon de C Valle's C code from https://gist.github.com/rcvalle/71f4b027d61a78c42607 @@ -11636,15 +11640,15 @@ run_ccs_injection(){ # empty reply pr_done_best "not vulnerable (OK)" if [[ $retval -eq 3 ]]; then - fileout "ccs" "OK" "CCS: not vulnerable (timed out)" "$cve" "$cwe" + fileout "$jsonID" "OK" "not vulnerable (timed out)" "$cve" "$cwe" else - fileout "ccs" "OK" "CCS: not vulnerable" "$cve" "$cwe" + fileout "$jsonID" "OK" "not vulnerable" "$cve" "$cwe" fi ret=0 elif [[ "$byte6" == "15" ]] && [[ "${tls_hello_ascii:0:4}" == "1503" ]]; then # decryption failed received pr_svrty_critical "VULNERABLE (NOT ok)" - fileout "ccs" "CRITICAL" "CCS: VULNERABLE" "$cve" "$cwe" "$hint" + fileout "$jsonID" "CRITICAL" "VULNERABLE" "$cve" "$cwe" "$hint" ret=1 elif [[ "${tls_hello_ascii:0:4}" == "1503" ]]; then if [[ "$byte6" == "0A" ]] || [[ "$byte6" == "28" ]]; then @@ -11652,23 +11656,23 @@ run_ccs_injection(){ pr_warning "likely " out "not vulnerable (OK)" out " - alert description type: $byte6" - fileout "ccs" "WARN" "CCS: probably not vulnerable but received 0x${byte6} instead of 0x15" "$cve" "$cwe" "$hint" + fileout "$jsonID" "WARN" "probably not vulnerable but received 0x${byte6} instead of 0x15" "$cve" "$cwe" "$hint" fi elif [[ $STARTTLS_PROTOCOL == "mysql" ]] && [[ "${tls_hello_ascii:14:12}" == "233038533031" ]]; then # MySQL community edition (yaSSL) returns a MySQL error instead of a TLS Alert # Error: #08S01 Bad handshake pr_done_best "not vulnerable (OK)" out ", looks like MySQL community edition (yaSSL)" - fileout "ccs" "OK" "CCS: not vulnerable (MySQL community edition (yaSSL) detected)" "$cve" "$cwe" + fileout "$jsonID" "OK" "not vulnerable (MySQL community edition (yaSSL) detected)" "$cve" "$cwe" elif [[ "$byte6" == [0-9a-f][0-9a-f] ]] && [[ "${tls_hello_ascii:2:2}" != "03" ]]; then pr_warning "test failed" out ", probably read buffer too small (${tls_hello_ascii:0:14})" - fileout "ccs" "DEBUG" "CCS: test failed, probably read buffer too small (${tls_hello_ascii:0:14})" "$cve" "$cwe" "$hint" + fileout "$jsonID" "DEBUG" "test failed, probably read buffer too small (${tls_hello_ascii:0:14})" "$cve" "$cwe" "$hint" ret=7 else pr_warning "test failed " out "around line $LINENO (debug info: ${tls_hello_ascii:0:12},$byte6)" - fileout "ccs" "DEBUG" "CCS: test failed, around line $LINENO, debug info (${tls_hello_ascii:0:12},$byte6)" "$cve" "$cwe" "$hint" + fileout "$jsonID" "DEBUG" "test failed, around line $LINENO, debug info (${tls_hello_ascii:0:12},$byte6)" "$cve" "$cwe" "$hint" ret=7 fi outln @@ -11708,6 +11712,7 @@ run_ticketbleed() { local -a memory sid_detected local early_exit=true local ret=0 + local jsonID="ticketbleed" [[ -n "$STARTTLS" ]] && return 0 [[ $VULN_COUNT -le $VULN_THRESHLD ]] && outln && pr_headlineln " Testing for Ticketbleed vulnerability " && outln @@ -11715,7 +11720,7 @@ run_ticketbleed() { if [[ "$SERVICE" != HTTP ]] && ! "$CLIENT_AUTH"; then outln "-- (applicable only for HTTPS)" - fileout "ticketbleed" "INFO" "Ticketbleed: not applicable, not HTTP" "$cve" "$cwe" + fileout "$jsonID" "INFO" "Ticketbleed: not applicable, not HTTP" "$cve" "$cwe" return 0 fi @@ -11724,7 +11729,7 @@ run_ticketbleed() { if [[ ! "${TLS_EXTENSIONS}" =~ "session ticket" ]]; then pr_done_best "not vulnerable (OK)" outln ", no session ticket extension" - fileout "ticketbleed" "OK" "Ticketbleed: no session ticket extension" "$cve" "$cwe" + fileout "$jsonID" "OK" "Ticketbleed: no session ticket extension" "$cve" "$cwe" return 0 fi @@ -11751,7 +11756,7 @@ run_ticketbleed() { if [[ "$session_tckt_tls" == "," ]]; then pr_done_best "not vulnerable (OK)" outln ", no session tickets" - fileout "ticketbleed" "OK" "Ticketbleed: not vulnerable" "$cve" "$cwe" + fileout "$jsonID" "OK" "Ticketbleed: not vulnerable" "$cve" "$cwe" debugme echo " session ticket TLS \"$session_tckt_tls\"" return 0 fi @@ -11874,12 +11879,12 @@ run_ticketbleed() { if [[ "${tls_hello_ascii:0:2}" == "15" ]]; then debugme echo -n "TLS Alert ${tls_hello_ascii:10:4} (TLS version: ${tls_hello_ascii:2:4}) -- " pr_done_best "not vulnerable (OK)" - fileout "ticketbleed" "OK" "Ticketbleed: not vulnerable" "$cve" "$cwe" + fileout "$jsonID" "OK" "not vulnerable" "$cve" "$cwe" break elif [[ -z "${tls_hello_ascii:0:2}" ]]; then pr_done_best "not vulnerable (OK)" out ", reply empty" - fileout "ticketbleed" "OK" "Ticketbleed: not vulnerable" "$cve" "$cwe" + fileout "$jsonID" "OK" "not vulnerable" "$cve" "$cwe" break elif [[ "${tls_hello_ascii:0:2}" == "16" ]]; then early_exit=false @@ -11905,7 +11910,7 @@ run_ticketbleed() { ret=7 pr_warning "test failed" out " around line $LINENO (debug info: ${tls_hello_ascii:0:2}, ${tls_hello_ascii:2:10})" - fileout "ticketbleed" "DEBUG" "Ticketbleed: test failed, around $LINENO (debug info: ${tls_hello_ascii:0:2}, ${tls_hello_ascii:2:10})" "$cve" "$cwe" + fileout "$jsonID" "DEBUG" "test failed, around $LINENO (debug info: ${tls_hello_ascii:0:2}, ${tls_hello_ascii:2:10})" "$cve" "$cwe" break fi debugme echo "sending close_notify..." @@ -11928,11 +11933,11 @@ run_ticketbleed() { if [[ $nr_sid_detected -eq 3 ]]; then if [[ ${memory[1]} != ${memory[2]} ]] && [[ ${memory[2]} != ${memory[3]} ]]; then pr_svrty_critical "VULNERABLE (NOT ok)" - fileout "ticketbleed" "CRITICAL" "Ticketbleed: VULNERABLE" "$cve" "$cwe" "$hint" + fileout "$jsonID" "CRITICAL" "VULNERABLE" "$cve" "$cwe" "$hint" else pr_done_best "not vulnerable (OK)" out ", memory fragments do not differ" - fileout "ticketbleed" "OK" "Ticketbleed: not vulnerable, session IDs were returned but memory fragments do not differ" "$cve" "$cwe" + fileout "$jsonID" "OK" "not vulnerable, session IDs were returned but memory fragments do not differ" "$cve" "$cwe" fi else if [[ "$DEBUG" -ge 2 ]]; then @@ -11942,7 +11947,7 @@ run_ticketbleed() { pr_warning "test failed, non reproducible results!" out " Please run again w \"--debug=2\" (# of faked TLS SIDs detected: $nr_sid_detected)" fi - fileout "ticketbleed" "DEBUG" "Ticketbleed: # of TLS Session IDs detected: $nr_sid_detected, ${sid_detected[1]},${sid_detected[2]},${sid_detected[3]}" "$cve" "$cwe" + fileout "$jsonID" "DEBUG" "# of TLS Session IDs detected: $nr_sid_detected, ${sid_detected[1]},${sid_detected[2]},${sid_detected[3]}" "$cve" "$cwe" ret=7 fi fi @@ -11959,13 +11964,14 @@ run_renego() { local cve="CVE-2009-3555" local cwe="CWE-310" local hint="" + local jsonID="" "$HAS_TLS13" && [[ -z "$proto" ]] && proto="-no_tls1_3" [[ $VULN_COUNT -le $VULN_THRESHLD ]] && outln && pr_headlineln " Testing for Renegotiation vulnerabilities " && outln pr_bold " Secure Renegotiation "; out "($cve) " # and RFC 5746, OSVDB 59968-59974 - # community.qualys.com/blogs/securitylabs/2009/11/05/ssl-and-tls-authentication-gap-vulnerability-discovered + jsonID="secure_renego" # community.qualys.com/blogs/securitylabs/2009/11/05/ssl-and-tls-authentication-gap-vulnerability-discovered $OPENSSL s_client $(s_client_options "$proto $STARTTLS $BUGS -connect $NODEIP:$PORT $SNI $PROXY") 2>&1 $TMPFILE 2>$ERRFILE if sclient_connect_successful $? $TMPFILE; then grep -iaq "$insecure_renogo_str" $TMPFILE @@ -11973,29 +11979,30 @@ run_renego() { #FIXME: didn't occur to me yet but why not also to check on "Secure Renegotiation IS supported" case $sec_renego in 0) prln_svrty_critical "VULNERABLE (NOT ok)" - fileout "secure_renego" "CRITICAL" "Secure Renegotiation: VULNERABLE" "$cve" "$cwe" "$hint" + fileout "$jsonID" "CRITICAL" "VULNERABLE" "$cve" "$cwe" "$hint" ;; 1) prln_done_best "not vulnerable (OK)" - fileout "secure_renego" "OK" "Secure Renegotiation: not vulnerable" "$cve" "$cwe" + fileout "$jsonID" "OK" "not vulnerable" "$cve" "$cwe" ;; *) prln_warning "FIXME (bug): $sec_renego" - fileout "secure_renego" "WARN" "Secure Renegotiation: FIXME (bug) $sec_renego" "$cve" "$cwe" + fileout "$jsonID" "WARN" "FIXME (bug) $sec_renego" "$cve" "$cwe" ;; esac else prln_warning "handshake didn't succeed" - fileout "secure_renego" "WARN" "Secure Renegotiation: handshake didn't succeed" "$cve" "$cwe" + fileout "$jsonID" "WARN" "handshake didn't succeed" "$cve" "$cwe" fi - pr_bold " Secure Client-Initiated Renegotiation " # RFC 5746 # see: https://community.qualys.com/blogs/securitylabs/2011/10/31/tls-renegotiation-and-denial-of-service-attacks # http://blog.ivanristic.com/2009/12/testing-for-ssl-renegotiation.html -- head/get doesn't seem to be needed though + pr_bold " Secure Client-Initiated Renegotiation " # RFC 5746 + jsonID="secure_client_renego" case "$OSSL_VER" in 0.9.8*) # we need this for Mac OSX unfortunately case "$OSSL_VER_APPENDIX" in [a-l]) prln_local_problem " Your $OPENSSL cannot test this secure renegotiation vulnerability" - fileout "sec_client_renego" "WARN" "Secure Client-Initiated Renegotiation: your $OPENSSL cannot test this secure renegotiation vulnerability" "$cve" "$cwe" + fileout "$jsonID" "WARN" "your $OPENSSL cannot test this secure renegotiation vulnerability" "$cve" "$cwe" return 3 ;; [m-z]) @@ -12011,7 +12018,7 @@ run_renego() { if "$CLIENT_AUTH"; then prln_warning "client x509-based authentication prevents this from being tested" - fileout "sec_client_renego" "WARN" "Secure Client-Initiated Renegotiation : client x509-based authentication prevents this from being tested" + fileout "$jsonID" "WARN" "client x509-based authentication prevents this from being tested" sec_client_renego=1 else # We need up to two tries here, as some LiteSpeed servers don't answer on "R" and block. Thus first try in the background @@ -12020,7 +12027,7 @@ run_renego() { wait_kill $! $HEADER_MAXSLEEP if [[ $? -eq 3 ]]; then pr_done_good "likely not vulnerable (OK)"; outln ", timed out" # it hung - fileout "sec_client_renego" "OK" "Secure Client-Initiated Renegotiation : likely not vulnerable (timed out)" "$cve" "$cwe" + fileout "$jsonID" "OK" "likely not vulnerable (timed out)" "$cve" "$cwe" sec_client_renego=1 else # second try in the foreground as we are sure now it won't hang @@ -12029,19 +12036,19 @@ run_renego() { case "$sec_client_renego" in 0) if [[ $SERVICE == "HTTP" ]]; then pr_svrty_high "VULNERABLE (NOT ok)"; outln ", DoS threat" - fileout "sec_client_renego" "HIGH" "Secure Client-Initiated Renegotiation : VULNERABLE, DoS threat" "$cve" "$cwe" "$hint" + fileout "$jsonID" "HIGH" "VULNERABLE, DoS threat" "$cve" "$cwe" "$hint" else pr_svrty_medium "VULNERABLE (NOT ok)"; outln ", potential DoS threat" - fileout "sec_client_renego" "MEDIUM" "Secure Client-Initiated Renegotiation : VULNERABLE, potential DoS threat" "$cve" "$cwe" "$hint" + fileout "$jsonID" "MEDIUM" "VULNERABLE, potential DoS threat" "$cve" "$cwe" "$hint" fi ;; 1) prln_done_good "not vulnerable (OK)" - fileout "sec_client_renego" "OK" "Secure Client-Initiated Renegotiation : not vulnerable" "$cve" "$cwe" + fileout "$jsonID" "OK" "not vulnerable" "$cve" "$cwe" ;; *) prln_warning "FIXME (bug): $sec_client_renego" - fileout "sec_client_renego" "DEBUG" "Secure Client-Initiated Renegotiation : FIXME (bug) $sec_client_renego - Please report" "$cve" "$cwe" + fileout "$jsonID" "DEBUG" "FIXME (bug) $sec_client_renego - Please report" "$cve" "$cwe" ;; esac fi @@ -12075,7 +12082,7 @@ run_crime() { if [[ $? -eq 0 ]]; then if "$SSL_NATIVE"; then prln_local_problem "$OPENSSL lacks zlib support" - fileout "crime" "WARN" "CRIME, TLS: Not tested. $OPENSSL lacks zlib support" "$cve" "$cwe" + fileout "CRIME_TLS" "WARN" "CRIME, TLS: Not tested. $OPENSSL lacks zlib support" "$cve" "$cwe" return 7 else tls_sockets "03" "$TLS12_CIPHER" "" "" "true" @@ -12095,24 +12102,24 @@ run_crime() { fi if [[ $sclient_success -ne 0 ]]; then pr_warning "test failed (couldn't connect)" - fileout "crime" "WARN" "CRIME, TLS: Check failed. (couldn't connect)" "$cve" "$cwe" + fileout "CRIME_TLS" "WARN" "Check failed, couldn't connect" "$cve" "$cwe" ret=7 elif grep -a Compression $TMPFILE | grep -aq NONE >/dev/null; then pr_done_good "not vulnerable (OK)" if [[ $SERVICE != "HTTP" ]] && ! "$CLIENT_AUTH"; then out " (not using HTTP anyway)" - fileout "crime" "OK" "CRIME, TLS: Not vulnerable (not using HTTP anyway)" "$cve" "$cwe" + fileout "CRIME_TLS" "OK" "Not vulnerable (not using HTTP anyway)" "$cve" "$cwe" else - fileout "crime" "OK" "CRIME, TLS: Not vulnerable" "$cve" "$cwe" + fileout "CRIME_TLS" "OK" "Not vulnerable" "$cve" "$cwe" fi ret=0 else if [[ $SERVICE == "HTTP" ]] || "$CLIENT_AUTH"; then pr_svrty_high "VULNERABLE (NOT ok)" - fileout "crime" "HIGH" "CRIME, TLS: VULNERABLE" "$cve" "$cwe" "$hint" + fileout "CRIME_TLS" "HIGH" "VULNERABLE" "$cve" "$cwe" "$hint" else pr_svrty_medium "VULNERABLE but not using HTTP: probably no exploit known" - fileout "crime" "MEDIUM" "CRIME, TLS: VULNERABLE, but not using HTTP: probably no exploit known" "$cve" "$cwe" "$hint" + fileout "CRIME_TLS" "MEDIUM" "VULNERABLE, but not using HTTP. Probably no exploit known" "$cve" "$cwe" "$hint" fi ret=1 fi @@ -12178,7 +12185,7 @@ run_breach() { pr_bold " BREACH"; out " ($cve) " if "$CLIENT_AUTH"; then outln "cannot be tested (server side requires x509 authentication)" - fileout "breach" "INFO" "BREACH: cannot be tested (server side requires x509 authentication)" "$cve" "$cwe" + fileout "BREACH" "INFO" "cannot be tested, server side requires x509 authentication" "$cve" "$cwe" return 7 fi @@ -12202,22 +12209,22 @@ run_breach() { pr_warning "failed (HTTP header request stalled" if [[ $was_killed -ne 0 ]]; then pr_warning " and was terminated" - fileout "breach" "WARN" "BREACH: Test failed (HTTP request stalled and was terminated)" "$cve" "$cwe" + fileout "BREACH" "WARN" "Test failed (HTTP request stalled and was terminated)" "$cve" "$cwe" else - fileout "breach" "WARN" "BREACH: Test failed (HTTP request stalled)" "$cve" "$cwe" + fileout "BREACH" "WARN" "Test failed (HTTP request stalled)" "$cve" "$cwe" fi prln_warning ") " ret=3 elif [[ -z $result ]]; then pr_done_best "no HTTP compression (OK) " outln "$disclaimer" - fileout "breach" "OK" "BREACH: no HTTP compression $disclaimer" "$cve" "$cwe" + fileout "BREACH" "OK" "no HTTP compression $disclaimer" "$cve" "$cwe" ret=0 else pr_svrty_high "potentially NOT ok, uses $result HTTP compression." outln "$disclaimer" outln "$spaces$when_makesense" - fileout "breach" "HIGH" "BREACH: potentially VULNERABLE, uses $result HTTP compression. $disclaimer ($when_makesense)" "$cve" "$cwe" "$hint" + fileout "BREACH" "HIGH" "potentially VULNERABLE, uses $result HTTP compression. $disclaimer ($when_makesense)" "$cve" "$cwe" "$hint" ret=1 fi # Any URL can be vulnerable. I am testing now only the given URL! @@ -12275,11 +12282,11 @@ run_sweet32() { fi if [[ $sclient_success -eq 0 ]]; then pr_svrty_low "VULNERABLE"; out ", uses 64 bit block ciphers" - fileout "sweet32" "LOW" "SWEET32, uses 64 bit block ciphers" "$cve" "$cwe" "$hint" + fileout "SWEET32" "LOW" "uses 64 bit block ciphers" "$cve" "$cwe" "$hint" else pr_done_best "not vulnerable (OK)"; if "$using_sockets"; then - fileout "sweet32" "OK" "SWEET32: not vulnerable" "$cve" "$cwe" + fileout "SWEET32" "OK" "not vulnerable" "$cve" "$cwe" else if [[ "$nr_supported_ciphers" -ge 17 ]]; then # Likely only PSK/KRB5 ciphers are missing: display discrepancy but no warning @@ -12287,7 +12294,7 @@ run_sweet32() { else pr_warning ", $nr_supported_ciphers/$nr_sweet32_ciphers local ciphers" fi - fileout "sweet32" "OK" "SWEET32: not vulnerable ($nr_supported_ciphers of $nr_sweet32_ciphers local ciphers" "$cve" "$cwe" + fileout "SWEET32" "OK" "not vulnerable ($nr_supported_ciphers of $nr_sweet32_ciphers local ciphers" "$cve" "$cwe" fi fi outln @@ -12332,12 +12339,12 @@ run_ssl_poodle() { if [[ $sclient_success -eq 0 ]]; then POODLE=0 pr_svrty_high "VULNERABLE (NOT ok)"; out ", uses SSLv3+CBC (check TLS_FALLBACK_SCSV mitigation below)" - fileout "poodle_ssl" "HIGH" "POODLE, SSL: VULNERABLE, uses SSLv3+CBC" "$cve" "$cwe" "$hint" + fileout "POODLE_SSL" "HIGH" "VULNERABLE, uses SSLv3+CBC" "$cve" "$cwe" "$hint" else POODLE=1 pr_done_best "not vulnerable (OK)"; if "$using_sockets"; then - fileout "poodle_ssl" "OK" "POODLE, SSL: not vulnerable" "$cve" "$cwe" + fileout "POODLE_SSL" "OK" "not vulnerable" "$cve" "$cwe" else if [[ "$nr_supported_ciphers" -ge 83 ]]; then # Likely only KRB and PSK cipher are missing: display discrepancy but no warning @@ -12345,7 +12352,7 @@ run_ssl_poodle() { else pr_warning ", $nr_supported_ciphers/$nr_cbc_ciphers local ciphers" fi - fileout "poodle_ssl" "OK" "POODLE, SSL: not vulnerable ($nr_supported_ciphers of $nr_cbc_ciphers local ciphers" "$cve" "$cwe" + fileout "POODLE_SSL" "OK" "not vulnerable ($nr_supported_ciphers of $nr_cbc_ciphers local ciphers" "$cve" "$cwe" fi fi outln @@ -12361,10 +12368,11 @@ run_tls_poodle() { pr_bold " POODLE, TLS"; out " ($cve), experimental " #FIXME prln_warning "#FIXME" - fileout "poodle_tls" "WARN" "POODLE, TLS: Not tested. Not yet implemented #FIXME" "$cve" "$cwe" + fileout "POODLE_TLS" "WARN" "POODLE, TLS: Not tested. Not yet implemented #FIXME" "$cve" "$cwe" return 7 } +#FIXME: fileout needs to be patched according to new scheme. Postponed as otherwise merge fails run_tls_fallback_scsv() { local -i ret=0 @@ -12474,7 +12482,7 @@ run_freak() { case $nr_supported_ciphers in 0) prln_local_problem "$OPENSSL doesn't have any EXPORT RSA ciphers configured" - fileout "freak" "WARN" "FREAK: Not tested. $OPENSSL doesn't have any EXPORT RSA ciphers configured" "$cve" "$cwe" + fileout "FREAK" "WARN" "Not tested. $OPENSSL doesn't have any EXPORT RSA ciphers configured" "$cve" "$cwe" return 7 ;; 1|2|3) @@ -12512,10 +12520,10 @@ run_freak() { fi if [[ $sclient_success -eq 0 ]]; then pr_svrty_critical "VULNERABLE (NOT ok)"; out ", uses EXPORT RSA ciphers" - fileout "freak" "CRITICAL" "FREAK: VULNERABLE, uses EXPORT RSA ciphers" "$cve" "$cwe" "$hint" + fileout "FREAK" "CRITICAL" "VULNERABLE, uses EXPORT RSA ciphers" "$cve" "$cwe" "$hint" else pr_done_best "not vulnerable (OK)"; out "$addtl_warning" - fileout "freak" "OK" "FREAK: not vulnerable $addtl_warning" "$cve" "$cwe" + fileout "FREAK" "OK" "not vulnerable $addtl_warning" "$cve" "$cwe" fi outln @@ -12576,7 +12584,7 @@ run_logjam() { debugme echo $nr_supported_ciphers case $nr_supported_ciphers in 0) prln_local_problem "$OPENSSL doesn't have any DH EXPORT ciphers configured" - fileout "logjam" "WARN" "LOGJAM: Not tested. $OPENSSL doesn't have any DH EXPORT ciphers configured" "$cve" "$cwe" + fileout "LOGJAM" "WARN" "Not tested. $OPENSSL doesn't have any DH EXPORT ciphers configured" "$cve" "$cwe" return 1 # we could continue here testing common primes but the logjam test would be not complete and it's misleading/hard to code+display ;; 1|2|3) addtl_warning=" ($magenta""tested w/ $nr_supported_ciphers/4 ciphers only!$off)" ;; @@ -12657,7 +12665,7 @@ run_logjam() { if [[ ! -s "$common_primes_file" ]]; then prln_local_problem "couldn't read common primes file $common_primes_file" out "${spaces}" - fileout "LOGJAM_common primes_Problem" "WARN" "couldn't read common primes file $common_primes_file" + fileout "LOGJAM_common_primes" "WARN" "couldn't read common primes file $common_primes_file" ret=7 else dh_p="$(toupper "$dh_p")" @@ -12679,7 +12687,7 @@ run_logjam() { # we only use once the color here on the screen, so screen and fileout SEEM to be inconsistent if "$vuln_exportdh_ciphers"; then pr_svrty_high "VULNERABLE (NOT ok):"; out " uses DH EXPORT ciphers" - fileout "logjam" "HIGH" "LOGJAM: VULNERABLE, uses DH EXPORT ciphers" "$cve" "$cwe" "$hint" + fileout "LOGJAM" "HIGH" "VULNERABLE, uses DH EXPORT ciphers" "$cve" "$cwe" "$hint" if [[ $ret -eq 3 ]]; then out ", no DH key detected" fileout "LOGJAM_common primes" "OK" "no DH key detected" @@ -12729,20 +12737,20 @@ run_logjam() { fi outln "," out "${spaces}but no DH EXPORT ciphers${addtl_warning}" - fileout "logjam" "OK" "LOGJAM: not vulnerable, no DH EXPORT ciphers, $addtl_warning" "$cve" "$cwe" + fileout "LOGJAM" "OK" "not vulnerable, no DH EXPORT ciphers, $addtl_warning" "$cve" "$cwe" elif [[ $ret -eq 3 ]]; then pr_done_good "not vulnerable (OK):"; out " no DH EXPORT ciphers${addtl_warning}" - fileout "logjam" "OK" "LOGJAM: not vulnerable, no DH EXPORT ciphers, $addtl_warning" "$cve" "$cwe" + fileout "LOGJAM" "OK" "not vulnerable, no DH EXPORT ciphers, $addtl_warning" "$cve" "$cwe" out ", no DH key detected" fileout "LOGJAM_common primes" "OK" "no DH key detected" elif [[ $ret -eq 0 ]]; then pr_done_good "not vulnerable (OK):"; out " no DH EXPORT ciphers${ddtl_warning}" - fileout "logjam" "OK" "LOGJAM: not vulnerable, no DH EXPORT ciphers, $addtl_warning" "$cve" "$cwe" + fileout "LOGJAM" "OK" "not vulnerable, no DH EXPORT ciphers, $addtl_warning" "$cve" "$cwe" out ", no common primes detected" fileout "LOGJAM_common primes" "OK" "no common primes detected" elif [[ $ret -eq 7 ]]; then pr_done_good "partly not vulnerable:"; out " no DH EXPORT ciphers${ddtl_warning}" - fileout "logjam" "OK" "LOGJAM: not vulnerable, no DH EXPORT ciphers, $addtl_warning" "$cve" "$cwe" + fileout "LOGJAM" "OK" "not vulnerable, no DH EXPORT ciphers, $addtl_warning" "$cve" "$cwe" fi fi outln @@ -12785,7 +12793,7 @@ run_drown() { outln " (rerun with DEBUG >=2)" [[ $DEBUG -ge 3 ]] && hexdump -C "$TEMPDIR/$NODEIP.sslv2_sockets.dd" | head -1 ret=7 - fileout "drown" "WARN" "SSLv2: received a strange SSLv2 reply (rerun with DEBUG>=2)" "$cve" "$cwe" + fileout "DROWN" "WARN" "received a strange SSLv2 reply (rerun with DEBUG>=2)" "$cve" "$cwe" ;; 3) # vulnerable, [[ -n "$cert_fingerprint_sha2" ]] test is not needed as we should have RSA certificate here lines=$(count_lines "$(hexdump -C "$TEMPDIR/$NODEIP.sslv2_sockets.dd" 2>/dev/null)") @@ -12794,10 +12802,10 @@ run_drown() { nr_ciphers_detected=$((V2_HELLO_CIPHERSPEC_LENGTH / 3)) if [[ 0 -eq "$nr_ciphers_detected" ]]; then prln_svrty_high "CVE-2015-3197: SSLv2 supported but couldn't detect a cipher (NOT ok)"; - fileout "drown" "HIGH" "SSLv2 offered, but could not detect a cipher (CVE-2015-3197. Make sure you don't use this certificate elsewhere, see https://censys.io/ipv4?q=$cert_fingerprint_sha2" "$cve" "$cwe" "$hint" + fileout "DROWN" "HIGH" "SSLv2 offered, but could not detect a cipher (CVE-2015-3197. Make sure you don't use this certificate elsewhere, see https://censys.io/ipv4?q=$cert_fingerprint_sha2" "$cve" "$cwe" "$hint" else prln_svrty_critical "VULNERABLE (NOT ok), SSLv2 offered with $nr_ciphers_detected ciphers"; - fileout "drown" "CRITICAL" "VULNERABLE, SSLv2 offered with $nr_ciphers_detected ciphers. Make sure you don't use this certificate elsewhere, see https://censys.io/ipv4?q=$cert_fingerprint_sha2" "$cve" "$cwe" "$hint" + fileout "DROWN" "CRITICAL" "VULNERABLE, SSLv2 offered with $nr_ciphers_detected ciphers. Make sure you don't use this certificate elsewhere, see https://censys.io/ipv4?q=$cert_fingerprint_sha2" "$cve" "$cwe" "$hint" fi outln "$spaces Make sure you don't use this certificate elsewhere, see:" out "$spaces " @@ -12807,16 +12815,16 @@ run_drown() { ret=1 ;; *) prln_done_best "not vulnerable on this host and port (OK)" - fileout "drown" "OK" "not vulnerable to DROWN on this host and port" "$cve" "$cwe" + fileout "DROWN" "OK" "not vulnerable to DROWN on this host and port" "$cve" "$cwe" if [[ -n "$cert_fingerprint_sha2" ]]; then outln "$spaces make sure you don't use this certificate elsewhere with SSLv2 enabled services" out "$spaces " pr_url "https://censys.io/ipv4?q=$cert_fingerprint_sha2" outln " could help you to find out" - fileout "drown" "INFO" "make sure you don't use this certificate elsewhere with SSLv2 enabled services, see https://censys.io/ipv4?q=$cert_fingerprint_sha2" + fileout "DROWN" "INFO" "make sure you don't use this certificate elsewhere with SSLv2 enabled services, see https://censys.io/ipv4?q=$cert_fingerprint_sha2" else outln "$spaces no RSA certificate, thus certificate can't be used with SSLv2 elsewhere" - fileout "drown" "INFO" "no RSA certificate, thus certificate can't be used with SSLv2 elsewhere" + fileout "DROWN" "INFO" "no RSA certificate, thus certificate can't be used with SSLv2 elsewhere" fi ret=0 ;; @@ -12937,10 +12945,10 @@ run_beast(){ if "$continued"; then # second round: we hit TLS1 if "$HAS_SSL3" || "$using_sockets"; then prln_done_good "no SSL3 or TLS1 (OK)" - fileout "beast" "OK" "BEAST: not vulnerable, no SSL3 or TLS1" "$cve" "$cwe" + fileout "BEAST" "OK" "not vulnerable, no SSL3 or TLS1" "$cve" "$cwe" else prln_done_good "no TLS1 (OK)" - fileout "beast" "OK" "BEAST: not vulnerable, no TLS1" "$cve" "$cwe" + fileout "BEAST" "OK" "not vulnerable, no TLS1" "$cve" "$cwe" fi return 0 else # protocol not succeeded but it's the first time @@ -13056,7 +13064,7 @@ run_beast(){ if ! "$WIDE"; then if [[ -n "$detected_cbc_ciphers" ]]; then - fileout "cbc_$proto" "MEDIUM" "BEAST: CBC ciphers for $(toupper $proto): $detected_cbc_ciphers" "$cve" "$cwe" "$hint" + fileout "BEAST_CBC_$(toupper $proto)" "MEDIUM" "CBC ciphers for $(toupper $proto): $detected_cbc_ciphers" "$cve" "$cwe" "$hint" ! "$first" && out "$spaces" out "$(toupper $proto): " [[ -n "$higher_proto_supported" ]] && \ @@ -13073,7 +13081,7 @@ run_beast(){ else if ! "$vuln_beast" ; then prln_done_good "no CBC ciphers for $(toupper $proto) (OK)" - fileout "cbc_$proto" "OK" "BEAST: No CBC ciphers for $(toupper $proto)" "$cve" "$cwe" + fileout "BEAST_CBC_$(toupper $proto)" "OK" "No CBC ciphers for $(toupper $proto)" "$cve" "$cwe" fi fi done # for proto in ssl3 tls1 @@ -13084,13 +13092,13 @@ run_beast(){ outln # NOT ok seems too harsh for me if we have TLS >1.0 pr_svrty_low "VULNERABLE" - outln " -- but also supports higher protocols (possible mitigation):$higher_proto_supported" + outln " -- but also supports higher protocols (possible mitigation) $higher_proto_supported" else out "$spaces" pr_svrty_low "VULNERABLE" - outln " -- but also supports higher protocols (possible mitigation):$higher_proto_supported" + outln " -- but also supports higher protocols $higher_proto_supported (likely mitigated)" fi - fileout "beast" "LOW" "BEAST: VULNERABLE -- but also supports higher protocols (possible mitigation):$higher_proto_supported" "$cve" "$cwe" "$hint" + fileout "BEAST" "LOW" "VULNERABLE -- but also supports higher protocols $higher_proto_supported (likely mitigated)" "$cve" "$cwe" "$hint" else if "$WIDE"; then outln @@ -13099,7 +13107,7 @@ run_beast(){ fi pr_svrty_medium "VULNERABLE" outln " -- and no higher protocols as mitigation supported" - fileout "beast" "MEDIUM" "BEAST: VULNERABLE -- and no higher protocols as mitigation supported" "$cve" "$cwe" "$hint" + fileout "BEAST" "MEDIUM" "VULNERABLE -- and no higher protocols as mitigation supported" "$cve" "$cwe" "$hint" fi fi "$first" && ! "$vuln_beast" && prln_done_good "no CBC ciphers found for any protocol (OK)" @@ -13149,13 +13157,13 @@ run_lucky13() { if [[ $sclient_success -eq 0 ]]; then out "potentially " pr_svrty_low "VULNERABLE"; out ", uses cipher block chaining (CBC) ciphers with TLS" - fileout "lucky13" "LOW" "potentially vulnerable to LUCKY13, uses cipher block chaining (CBC) ciphers with TLS. Check patches" "$cve" "$cwe" "$hint" + fileout "LUCKY13" "LOW" "potentially vulnerable to LUCKY13, uses cipher block chaining (CBC) ciphers with TLS. Check patches" "$cve" "$cwe" "$hint" # the CBC padding which led to timing differences during MAC processing has been solved in openssl (https://www.openssl.org/news/secadv/20130205.txt) # and other software. However we can't tell with reasonable effort from the outside. Thus we still issue a warning and label it experimental else pr_done_best "not vulnerable (OK)"; if "$using_sockets"; then - fileout "lucky13" "OK" "LUCKY13: not vulnerable" "$cve" "$cwe" + fileout "lucky13" "OK" "not vulnerable" "$cve" "$cwe" else if [[ "$nr_supported_ciphers" -ge 133 ]]; then # Likely only PSK/KRB5 ciphers are missing: display discrepancy but no warning @@ -13163,7 +13171,7 @@ run_lucky13() { else pr_warning ", $nr_supported_ciphers/$nr_cbc_ciphers local ciphers" fi - fileout "lucky13" "OK" "LUCKY13: not vulnerable ($nr_supported_ciphers of $nr_cbc_ciphers local ciphers" "$cve" "$cwe" + fileout "LUCKY13" "OK" "not vulnerable ($nr_supported_ciphers of $nr_cbc_ciphers local ciphers" "$cve" "$cwe" fi fi outln @@ -13405,13 +13413,13 @@ run_rc4() { ! "$WIDE" && pr_svrty_high "$(out_row_aligned_max_width "$rc4_detected" " " $TERM_WIDTH)" outln "$WIDE" && pr_svrty_high "VULNERABLE (NOT ok)" - fileout "rc4" "HIGH" "RC4: VULNERABLE, Detected ciphers: $rc4_detected" "$cve" "$cwe" "$hint" + fileout "RC4" "HIGH" "VULNERABLE, Detected ciphers: $rc4_detected" "$cve" "$cwe" "$hint" elif [[ $nr_ciphers -eq 0 ]]; then prln_local_problem "No RC4 Ciphers configured in $OPENSSL" - fileout "rc4" "WARN" "RC4 ciphers not supported by local OpenSSL ($OPENSSL)" + fileout "RC4" "WARN" "RC4 ciphers not supported by local OpenSSL ($OPENSSL)" else prln_done_good "no RC4 ciphers detected (OK)" - fileout "rc4" "OK" "RC4: not vulnerable" "$cve" "$cwe" + fileout "RC4" "OK" "not vulnerable" "$cve" "$cwe" fi outln @@ -13513,11 +13521,11 @@ run_grease() { success=$? if [[ $success -eq 0 ]] || [[ $success -eq 2 ]]; then prln_svrty_medium " Server claims to support non-existent cipher suite." - fileout "grease" "CRITICAL" "Server claims to support non-existent cipher suite." + fileout "GREASE" "CRITICAL" "Server claims to support non-existent cipher suite." bug_found=true elif grep -q "The ServerHello specifies a cipher suite that wasn't included in the ClientHello" "$TEMPDIR/$NODEIP.parse_tls_serverhello.txt" ; then prln_svrty_medium " Server responded with a ServerHello rather than an alert even though it doesn't support any of the client-offered cipher suites." - fileout "grease" "CRITICAL" "Server responded with a ServerHello rather than an alert even though it doesn't support any of the client-offered cipher suites." + fileout "GREASE" "CRITICAL" "Server responded with a ServerHello rather than an alert even though it doesn't support any of the client-offered cipher suites." bug_found=true else # Send a list of non-existent ciphers such that for each cipher that @@ -13528,11 +13536,11 @@ run_grease() { success=$? if [[ $success -eq 0 ]] || [[ $success -eq 2 ]]; then prln_svrty_medium " Server claims to support non-existent cipher suite." - fileout "grease" "CRITICAL" "Server claims to support non-existent cipher suite." + fileout "GREASE" "CRITICAL" "Server claims to support non-existent cipher suite." bug_found=true elif grep -q " The ServerHello specifies a cipher suite that wasn't included in the ClientHello" "$TEMPDIR/$NODEIP.parse_tls_serverhello.txt" ; then prln_svrty_medium " Server only compares against second byte in each cipher suite in ClientHello." - fileout "grease" "CRITICAL" "Server only compares against second byte in each cipher suite in ClientHello." + fileout "GREASE" "CRITICAL" "Server only compares against second byte in each cipher suite in ClientHello." bug_found=true fi fi @@ -13580,7 +13588,7 @@ run_grease() { if [[ $success -ne 0 ]] && [[ $success -ne 2 ]]; then prln_svrty_medium " Server fails if ClientHello contains an unrecognized extension." outln " extension used in failed test: $extn" - fileout "grease" "CRITICAL" "Server fails if ClientHello contains an unrecognized extension: $extn" + fileout "GREASE" "CRITICAL" "Server fails if ClientHello contains an unrecognized extension: $extn" bug_found=true else # Check for inability to handle empty last extension (see PR #792 and @@ -13605,7 +13613,7 @@ run_grease() { success=$? if [[ $success -ne 0 ]] && [[ $success -ne 2 ]]; then prln_svrty_medium " Server fails if last extension in ClientHello is empty." - fileout "grease" "CRITICAL" "Server fails if last extension in ClientHello is empty." + fileout "GREASE" "CRITICAL" "Server fails if last extension in ClientHello is empty." bug_found=true fi fi @@ -13620,7 +13628,7 @@ run_grease() { success=$? if [[ $success -ne 0 ]] && [[ $success -ne 2 ]]; then prln_svrty_medium " Server fails if ClientHello includes more than 128 cipher suites." - fileout "grease" "CRITICAL" "Server fails if ClientHello includes more than 128 cipher suites." + fileout "GREASE" "CRITICAL" "Server fails if ClientHello includes more than 128 cipher suites." SERVER_SIZE_LIMIT_BUG=true bug_found=true fi @@ -13643,7 +13651,7 @@ run_grease() { success=$? if [[ $success -ne 0 ]] && [[ $success -ne 2 ]]; then prln_svrty_medium " Server fails if ClientHello is between 256 and 511 bytes in length." - fileout "grease" "CRITICAL" "Server fails if ClientHello is between 256 and 511 bytes in length." + fileout "GREASE" "CRITICAL" "Server fails if ClientHello is between 256 and 511 bytes in length." bug_found=true fi fi @@ -13660,7 +13668,7 @@ run_grease() { success=$? if [[ $success -ne 0 ]] && [[ $success -ne 2 ]]; then prln_svrty_medium " Server fails if ClientHello contains unrecognized cipher suite values." - fileout "grease" "CRITICAL" "Server fails if ClientHello contains unrecognized cipher suite values." + fileout "GREASE" "CRITICAL" "Server fails if ClientHello contains unrecognized cipher suite values." bug_found=true fi fi @@ -13706,7 +13714,7 @@ run_grease() { success=$? if [[ $success -ne 0 ]] && [[ $success -ne 2 ]]; then prln_svrty_medium " Server fails if ClientHello contains a supported_groups extension with an unrecognized named group value (${grease_supported_groups[rnd]})." - fileout "grease" "CRITICAL" "Server fails if ClientHello contains a supported_groups extension with an unrecognized named group value (${grease_supported_groups[rnd]})." + fileout "GREASE" "CRITICAL" "Server fails if ClientHello contains a supported_groups extension with an unrecognized named group value (${grease_supported_groups[rnd]})." bug_found=true fi fi @@ -13727,7 +13735,7 @@ run_grease() { success=$? if [[ $success -ne 0 ]] && [[ $success -ne 2 ]]; then prln_svrty_medium " Server fails if ClientHello contains an application_layer_protocol_negotiation extension." - fileout "grease" "CRITICAL" "Server fails if ClientHello contains an application_layer_protocol_negotiation extension." + fileout "GREASE" "CRITICAL" "Server fails if ClientHello contains an application_layer_protocol_negotiation extension." bug_found=true else selected_alpn_protocol="$(grep "ALPN protocol:" "$TEMPDIR/$NODEIP.parse_tls_serverhello.txt" | sed 's/ALPN protocol: //')" @@ -13744,17 +13752,17 @@ run_grease() { success=$? if [[ $success -ne 0 ]] && [[ $success -ne 2 ]]; then prln_svrty_medium " Server fails if ClientHello contains an application_layer_protocol_negotiation extension with an unrecognized ALPN value." - fileout "grease" "CRITICAL" "erver fails if ClientHello contains an application_layer_protocol_negotiation extension with an unrecognized ALPN value." + fileout "GREASE" "CRITICAL" "erver fails if ClientHello contains an application_layer_protocol_negotiation extension with an unrecognized ALPN value." bug_found=true else grease_selected_alpn_protocol="$(grep "ALPN protocol:" "$TEMPDIR/$NODEIP.parse_tls_serverhello.txt" | sed 's/ALPN protocol: //')" if [[ -z "$grease_selected_alpn_protocol" ]] && [[ -n "$selected_alpn_protocol" ]]; then prln_svrty_medium " Server did not ignore unrecognized ALPN value in the application_layer_protocol_negotiation extension." - fileout "grease" "CRITICAL" "Server did not ignore unrecognized ALPN value in the application_layer_protocol_negotiation extension." + fileout "GREASE" "CRITICAL" "Server did not ignore unrecognized ALPN value in the application_layer_protocol_negotiation extension." bug_found=true elif [[ "$grease_selected_alpn_protocol" =~ ignore/ ]]; then prln_svrty_medium " Server selected \"ignore/\" ALPN value in the application_layer_protocol_negotiation extension." - fileout "grease" "CRITICAL" "Server selected \"ignore/\" ALPN value in the application_layer_protocol_negotiation extension." + fileout "GREASE" "CRITICAL" "Server selected \"ignore/\" ALPN value in the application_layer_protocol_negotiation extension." bug_found=true fi fi @@ -13773,7 +13781,7 @@ run_grease() { if ! "$bug_found"; then outln " No bugs found." - fileout "grease" "OK" "No bugs found." + fileout "GREASE" "OK" "No bugs found." return 0 else return 1 @@ -13845,7 +13853,7 @@ run_robot() { cipherlist="${cipherlist:2}" elif [[ $ret -ne 0 ]]; then prln_done_best "Server does not support any cipher suites that use RSA key transport" - fileout "ROBOT" "OK" "ROBOT: not vulnerable (server does not support any cipher suites that use RSA key transport)" + fileout "ROBOT" "OK" "not vulnerable (server does not support any cipher suites that use RSA key transport)" return 0 fi fi @@ -14024,14 +14032,14 @@ run_robot() { if "$vulnerable"; then if [[ "${response[1]}" == "${response[2]}" ]] && [[ "${response[2]}" == "${response[3]}" ]]; then pr_svrty_medium "VULNERABLE (NOT ok)"; outln " - weakly vulnerable as the attack would take too long" - fileout "ROBOT" "MEDIUM" "ROBOT: VULNERABLE, but the attack would take too long" + fileout "ROBOT" "MEDIUM" "VULNERABLE, but the attack would take too long" else prln_svrty_critical "VULNERABLE (NOT ok)" - fileout "ROBOT" "CRITICAL" "ROBOT: VULNERABLE" + fileout "ROBOT" "CRITICAL" "VULNERABLE" fi else prln_done_best "not vulnerable (OK)" - fileout "ROBOT" "OK" "ROBOT: not vulnerable" + fileout "ROBOT" "OK" "not vulnerable" fi return 0 } From ed4262f74f77ce54e350d862cd82ac2dfdac6d41 Mon Sep 17 00:00:00 2001 From: Dirk Date: Thu, 25 Jan 2018 15:05:57 +0100 Subject: [PATCH 6/6] Further changes to JSON ID + finding for JSON, std cipherlists In the sense of the previous commits this one adds further changes to the JSON output parameters ID and findings. Findings in JSON are now more crunchy and don't repeat parts of ID. Also ID changed so that it is more reflecting what has been tested. As the cipherlist checks in the beginning have been less and less to do with the OPsnSSL standard lists a change to remove the word "standard" was long overdue. That has been addressed now alos in the code and in the JSON/CSV output. $HOSTCERT has now an .pem file extension. $HOSTCERT_TXT will contain the text putput of the x509 openssl operation on the certificate which enables testssl.sh to remove some of the redundant "openssl x509 -in $HOSTCERT -text" calls. fileout has not been consistently replaced by fileout $jsonID yet. --- testssl.sh | 411 ++++++++++++++++++++++++++++------------------------- 1 file changed, 216 insertions(+), 195 deletions(-) diff --git a/testssl.sh b/testssl.sh index b4e9650..9fa810b 100755 --- a/testssl.sh +++ b/testssl.sh @@ -250,7 +250,8 @@ TMPFILE="" ERRFILE="" CLIENT_AUTH=false NO_SSL_SESSIONID=false -HOSTCERT="" +HOSTCERT="" # File with host certificate, without intermediate certificate +HOSTCERT_TXT="" # Text output of that HEADERFILE="" HEADERVALUE="" HTTP_STATUS_CODE="" @@ -1635,29 +1636,30 @@ detect_ipv4() { run_http_date() { local now difftime + jsonID="HTTP_clock_skew" + + if [[ $SERVICE != "HTTP" ]] || "$CLIENT_AUTH"; then + return 7 + fi if [[ ! -s $HEADERFILE ]]; then run_http_header "$1" || return 3 # this is just for the line "Testing HTTP header response" fi pr_bold " HTTP clock skew " - if [[ $SERVICE != "HTTP" ]]; then - out "not tested as we're not targeting HTTP" - else - if [[ -n "$HTTP_TIME" ]]; then - HTTP_TIME=$(parse_date "$HTTP_TIME" "+%s" "%a, %d %b %Y %T %Z" 2>>$ERRFILE) # the trailing \r confuses BSD flavors otherwise + if [[ -n "$HTTP_TIME" ]]; then + HTTP_TIME=$(parse_date "$HTTP_TIME" "+%s" "%a, %d %b %Y %T %Z" 2>>$ERRFILE) # the trailing \r confuses BSD flavors otherwise - difftime=$((HTTP_TIME - NOW_TIME)) - [[ $difftime != "-"* ]] && [[ $difftime != "0" ]] && difftime="+$difftime" - # process was killed, so we need to add an error: - [[ $HAD_SLEPT -ne 0 ]] && difftime="$difftime (± 1.5)" - out "$difftime sec from localtime"; - fileout "HTTP_clock_skew" "INFO" "HTTP clock skew $difftime sec from localtime" - else - out "Got no HTTP time, maybe try different URL?"; - fileout "HTTP_clock_skew" "INFO" "HTTP clock skew not measured. Got no HTTP time, maybe try different URL?" - fi - debugme tm_out ", epoch: $HTTP_TIME" + difftime=$((HTTP_TIME - NOW_TIME)) + [[ $difftime != "-"* ]] && [[ $difftime != "0" ]] && difftime="+$difftime" + # process was killed, so we need to add an error: + [[ $HAD_SLEPT -ne 0 ]] && difftime="$difftime (± 1.5)" + out "$difftime sec from localtime"; + fileout "$jsonID" "INFO" "$difftime seconds from localtime" + else + out "Got no HTTP time, maybe try different URL?"; + fileout "$jsonID" "INFO" "Got no HTTP time, maybe try different URL?" fi + debugme tm_out ", epoch: $HTTP_TIME" outln detect_ipv4 } @@ -1754,21 +1756,21 @@ run_hsts() { fileou t "HSTS_time" "MEDIUM" "HSTS timeout too short. $hsts_age_days days (=$hsts_age_sec seconds) < $HSTS_MIN days" fi if includeSubDomains "$TMPFILE"; then - fileout "HSTS_subdomains" "OK" "HSTS includes subdomains" + fileout "HSTS_subdomains" "OK" "includes subdomains" else - fileout "HSTS_subdomains" "INFO" "HSTS only for this domain" + fileout "HSTS_subdomains" "INFO" "only for this domain" fi if preload "$TMPFILE"; then - fileout "HSTS_preload" "OK" "HSTS domain is marked for preloading" + fileout "HSTS_preload" "OK" "domain IS marked for preloading" else - fileout "HSTS_preload" "INFO" "HSTS domain is NOT marked for preloading" + fileout "HSTS_preload" "INFO" "domain is NOT marked for preloading" #FIXME: To be checked against preloading lists, # e.g. https://dxr.mozilla.org/mozilla-central/source/security/manager/boot/src/nsSTSPreloadList.inc # https://chromium.googlesource.com/chromium/src/+/master/net/http/transport_security_state_static.json fi else out "--" - fileout "HSTS" "HIGH" "No support for HTTP Strict Transport Security" + fileout "HSTS" "HIGH" "not offered" fi outln @@ -1813,7 +1815,7 @@ run_hpkp() { out "\n$spaces Examining first: " first_hpkp_header=$(awk -F':' '/Public-Key-Pins/ { print $1 }' $HEADERFILE | head -1) pr_italic "$first_hpkp_header, " - fileout "HPKP_multiple" "WARN" "Multiple HPKP headers $hpkp_headers. Using first header: $first_hpkp_header" + fileout "HPKP_multiple" "WARN" "Multiple HPKP headers $hpkp_headers. Using first header \'$first_hpkp_header\'" fi # remove leading Public-Key-Pins*, any colons, double quotes and trailing spaces and taking the first -- whatever that is @@ -1825,12 +1827,12 @@ run_hpkp() { hpkp_nr_keys=$(grep -ac pin-sha $TMPFILE) if [[ $hpkp_nr_keys -eq 1 ]]; then - pr_svrty_high "1 key (NOT ok), " - fileout "HPKP_SPKIs" "HIGH" "Only one key pinned in HPKP header, this means the site may become unavailable if the key is revoked" + pr_svrty_high "Only one key pinned (NOT ok), means the site may become unavailable in the future, " + fileout "HPKP_SPKIs" "HIGH" "Only one key pinned" else pr_done_good "$hpkp_nr_keys" out " keys, " - fileout "HPKP_SPKIs" "OK" "$hpkp_nr_keys keys pinned in HPKP header, additional keys are available if the current key is revoked" + fileout "HPKP_SPKIs" "OK" "$hpkp_nr_keys keys pinned in header" fi # print key=value pair with awk, then strip non-numbers, to be improved with proper parsing of key-value with awk @@ -1846,18 +1848,18 @@ run_hpkp() { else out "$hpkp_age_sec s = " pr_svrty_medium "$hpkp_age_days days (< $HPKP_MIN s = $((HPKP_MIN / 86400)) days is not good enough)" - fileout "HPKP_age" "MEDIUM" "HPKP age is set to $hpkp_age_days days ($hpkp_age_sec sec) < $HPKP_MIN s = $((HPKP_MIN / 86400)) days is not good enough." + fileout "HPKP_age" "MEDIUM" "age is set to $hpkp_age_days days ($hpkp_age_sec sec) < $HPKP_MIN s = $((HPKP_MIN / 86400)) days is not good enough." fi if includeSubDomains "$TMPFILE"; then - fileout "HPKP_subdomains" "INFO" "HPKP header is valid for subdomains as well" + fileout "HPKP_subdomains" "INFO" "is valid for subdomains as well" else - fileout "HPKP_subdomains" "INFO" "HPKP header is valid for this domain only" + fileout "HPKP_subdomains" "INFO" "is valid for this domain only" fi if preload "$TMPFILE"; then - fileout "HPKP_preload" "INFO" "HPKP header is marked for browser preloading" + fileout "HPKP_preload" "INFO" "IS marked for browser preloading" else - fileout "HPKP_preload" "INFO" "HPKP header is NOT marked for browser preloading" + fileout "HPKP_preload" "INFO" "NOT marked for browser preloading" fi # Get the SPKIs first @@ -1947,11 +1949,11 @@ run_hpkp() { out "\n$spaces_indented Root CA: " pr_done_good "$hpkp_spki" pr_italic " $ca_cn" - fileout "HPKP_$hpkp_spki" "INFO" "SPKI $hpkp_spki matches Root CA \"$ca_cn\" pinned in the HPKP header. (Root CA part of the chain)" + fileout "HPKP_$hpkp_spki" "INFO" "SPKI $hpkp_spki matches Root CA \"$ca_cn\" pinned. (Root CA part of the chain)" else # not part of chain match_ca="" has_backup_spki=true # Root CA outside the chain --> we save it for unmatched - fileout "HPKP_$hpkp_spki" "INFO" "SPKI $hpkp_spki matches Root CA \"$ca_cn\" pinned in the HPKP header. (Root backup SPKI)" + fileout "HPKP_$hpkp_spki" "INFO" "SPKI $hpkp_spki matches Root CA \"$ca_cn\" pinned. (Root backup SPKI)" backup_spki[i]="$(strip_lf "$hpkp_spki")" # save it for later backup_spki_str[i]="$ca_cn" # also the name=CN of the root CA i=$((i + 1)) @@ -1996,14 +1998,14 @@ run_hpkp() { if [[ ! -f "$ca_hashes" ]] && "$spki_match"; then out "$spaces " prln_warning "Attribution of further hashes couldn't be done as $ca_hashes could not be found" - fileout "HPKP_spkimatch" "WARN" "Attribution of further hashes couldn't be done as $ca_hashes could not be found" + fileout "HPKP_SPKImatch" "WARN" "Attribution of further hashes possible as $ca_hashes could not be found" fi # If all else fails... if ! "$spki_match"; then "$has_backup_spki" && out "$spaces" # we had a few lines with backup SPKIs already prln_svrty_high " No matching key for SPKI found " - fileout "HPKP_spkimatch" "HIGH" "None of the SPKI match your host certificate, intermediate CA or known root CAs. You may have bricked this site" + fileout "HPKP_SPKImatch" "HIGH" "None of the SPKI match your host certificate, intermediate CA or known root CAs. Bricked site?" fi if ! "$has_backup_spki"; then @@ -2360,7 +2362,7 @@ run_more_flags() { fi pr_done_good "$f2t" outln " $(out_row_aligned_max_width "$HEADERVALUE" "$spaces" $TERM_WIDTH)" - fileout "$f2t" "OK" "$f2t: $HEADERVALUE" + fileout "$f2t" "OK" "$HEADERVALUE" fi done @@ -2469,12 +2471,13 @@ listciphers() { # argv[4]: string to be appended for fileout # argv[5]: non-SSLv2 cipher list to test (hexcodes), if using sockets # argv[6]: SSLv2 cipher list to test (hexcodes), if using sockets -std_cipherlists() { +sub_cipherlists() { local -i i len sclient_success=1 local cipherlist sslv2_cipherlist detected_ssl2_ciphers local singlespaces local proto="" local debugname="$(sed -e s'/\!/not/g' -e 's/\:/_/g' <<< "$1")" + local jsonID="cipherlist" [[ "$OPTIMAL_PROTO" == "-ssl2" ]] && proto="$OPTIMAL_PROTO" pr_bold "$2 " # to be indented equal to server preferences @@ -2537,10 +2540,10 @@ std_cipherlists() { # If server failed with a known error, raise it to the user. if [[ $STARTTLS_PROTOCOL == "mysql" ]]; then pr_warning "SERVER_ERROR: test inconclusive due to MySQL Community Edition (yaSSL) bug." - fileout "std_$4" "WARN" "SERVER_ERROR: test inconclusive due to MySQL Community Edition (yaSSL) bug." + fileout "${jsonID}_$4" "WARN" "SERVER_ERROR, test inconclusive due to MySQL Community Edition (yaSSL) bug." else pr_warning "SERVER_ERROR: test inconclusive." - fileout "std_$4" "WARN" "SERVER_ERROR: test inconclusive." + fileout "${jsonID}_$4" "WARN" "SERVER_ERROR, test inconclusive." fi else # Otherwise the error means the server doesn't support that cipher list. @@ -2548,54 +2551,54 @@ std_cipherlists() { 2) if [[ $sclient_success -eq 0 ]]; then # Strong is excellent to offer pr_done_best "offered (OK)" - fileout "std_$4" "OK" "$2 offered" + fileout "${jsonID}_$4" "OK" "offered" else pr_svrty_medium "not offered" - fileout "std_$4" "MEDIUM" "$2 not offered" + fileout "${jsonID}_$4" "MEDIUM" "not offered" fi ;; 1) if [[ $sclient_success -eq 0 ]]; then # High is good to offer pr_done_good "offered (OK)" - fileout "std_$4" "OK" "$2 offered" + fileout "${jsonID}_$4" "OK" "offered" else # FIXME: the rating could be readjusted if we knew the result of STRONG before pr_svrty_medium "not offered" - fileout "std_$4" "MEDIUM" "$2 not offered" + fileout "${jsonID}_$4" "MEDIUM" "not offered" fi ;; 0) if [[ $sclient_success -eq 0 ]]; then # medium is not that bad pr_svrty_medium "offered" - fileout "std_$4" "MEDIUM" "$2 offered - not too bad" + fileout "${jsonID}_$4" "MEDIUM" "offered" else out "not offered (OK)" - fileout "std_$4" "OK" "$2 not offered" + fileout "${jsonID}_$4" "OK" "not offered" fi ;; -1) if [[ $sclient_success -eq 0 ]]; then # bad but there is worse pr_svrty_high "offered (NOT ok)" - fileout "std_$4" "HIGH" "$2 offered - bad" + fileout "${jsonID}_$4" "HIGH" "offered" else # need a check for -eq 1 here pr_done_good "not offered (OK)" - fileout "std_$4" "OK" "$2 not offered" + fileout "${jsonID}_$4" "OK" "not offered" fi ;; -2) if [[ $sclient_success -eq 0 ]]; then # the ugly ones pr_svrty_critical "offered (NOT ok)" - fileout "std_$4" "CRITICAL" "$2 offered - ugly" + fileout "${jsonID}_$4" "CRITICAL" "offered" else pr_done_best "not offered (OK)" - fileout "std_$4" "OK" "$2 not offered" + fileout "${jsonID}_$4" "OK" "not offered" fi ;; *) # we shouldn't reach this pr_warning "?: $3 (please report this)" - fileout "std_$4" "WARN" "return condition $3 unclear" + fileout "${jsonID}_$4" "WARN" "return condition $3 unclear" ;; esac fi @@ -2609,7 +2612,7 @@ std_cipherlists() { else prln_local_problem "No $singlespaces configured in $OPENSSL" fi - fileout "std_$4" "WARN" "Cipher $2 ($1) not supported by local OpenSSL ($OPENSSL)" + fileout "${jsonID}_$4" "WARN" "Cipher $2 ($1) not supported by local OpenSSL ($OPENSSL)" fi } @@ -3970,6 +3973,7 @@ run_client_simulation() { local has_dh_bits using_sockets=true local client_service local options + local jsonID="clientsimulation" # source the external file . "$TESTSSL_INSTALL_DIR/etc/client-simulation.txt" 2>/dev/null @@ -3998,7 +4002,7 @@ run_client_simulation() { else pr_headline " Running client simulations via openssl " prln_warning " -- you shouldn't run this with \"--ssl-native\" as you will get false results" - fileout "client_simulation" "WARN" "You shouldn't run this with \"--ssl-native\" as you will get false results" + fileout "$jsonID" "WARN" "You shouldn't run this with \"--ssl-native\" as you will get false results" fi outln debugme echo @@ -4065,8 +4069,7 @@ run_client_simulation() { fi if [[ $sclient_success -ne 0 ]]; then outln "No connection" - fileout "client_${short[i]}" "INFO" "$(strip_spaces "${names[i]}") client simulation: No connection" -#FIXME: here probably either the id has to be changed or the finding, id seems not verbose enough + fileout "${jsonID}-${short[i]}" "INFO" "No connection" else proto=$(get_protocol $TMPFILE) # hack: @@ -4136,8 +4139,7 @@ run_client_simulation() { out " " outln "${warning[i]}" fi - fileout "client_${short[i]}" "INFO" \ - "$(strip_spaces "${names[i]}") client simulation: $proto $cipher ${warning[i]}" + fileout "${jsonID}-${short[i]}" "INFO" "$proto $cipher ${warning[i]}" debugme cat $TMPFILE fi fi # correct service? @@ -4728,7 +4730,7 @@ run_protocols() { } #TODO: work with fixed lists here --> atm ok, as sockets are preferred. If there would be a single function for testing: yes. -run_std_cipherlists() { +run_cipherlists() { local hexc hexcode strength local using_sockets=true local -i i @@ -4767,7 +4769,7 @@ run_std_cipherlists() { fi outln - pr_headlineln " Testing ~standard cipher categories " + pr_headlineln " Testing cipher categories " outln # argv[1]: cipher list to test in OpenSSL syntax (see ciphers(1ssl) or run 'openssl ciphers -v/-V)' # argv[2]: string on console / HTML or "finding" @@ -4775,17 +4777,17 @@ run_std_cipherlists() { # argv[4]: string to be appended for fileout # argv[5]: non-SSLv2 cipher list to test (hexcodes), if using sockets # argv[6]: SSLv2 cipher list to test (hexcodes), if using sockets - std_cipherlists 'NULL:eNULL' " NULL ciphers (no encryption) " -2 "NULL" "$null_ciphers" "$sslv2_null_ciphers" - std_cipherlists 'aNULL:ADH' " Anonymous NULL Ciphers (no authentication)" -2 "aNULL" "$anon_ciphers" "$sslv2_anon_ciphers" - std_cipherlists 'EXPORT:!ADH:!NULL' " Export ciphers (w/o ADH+NULL) " -2 "EXPORT" "$exp_ciphers" "$sslv2_exp_ciphers" - std_cipherlists 'LOW:DES:!ADH:!EXP:!NULL' " LOW: 64 Bit + DES encryption (w/o export) " -2 "DES+64Bit" "$low_ciphers" "$sslv2_low_ciphers" + sub_cipherlists 'NULL:eNULL' " NULL ciphers (no encryption) " -2 "NULL" "$null_ciphers" "$sslv2_null_ciphers" + sub_cipherlists 'aNULL:ADH' " Anonymous NULL Ciphers (no authentication)" -2 "aNULL" "$anon_ciphers" "$sslv2_anon_ciphers" + sub_cipherlists 'EXPORT:!ADH:!NULL' " Export ciphers (w/o ADH+NULL) " -2 "EXPORT" "$exp_ciphers" "$sslv2_exp_ciphers" + sub_cipherlists 'LOW:DES:!ADH:!EXP:!NULL' " LOW: 64 Bit + DES encryption (w/o export) " -2 "DES+64Bit" "$low_ciphers" "$sslv2_low_ciphers" - std_cipherlists 'MEDIUM:!aNULL:!AES:!CAMELLIA:!ARIA:!CHACHA20:!3DES' \ + sub_cipherlists 'MEDIUM:!aNULL:!AES:!CAMELLIA:!ARIA:!CHACHA20:!3DES' \ " Weak 128 Bit ciphers (SEED, IDEA, RC[2,4])" -1 "128Bit" "$medium_ciphers" "$sslv2_medium_ciphers" - std_cipherlists '3DES:!aNULL:!ADH' " Triple DES Ciphers (Medium) " 0 "3DES" "$tdes_ciphers" "$sslv2_tdes_ciphers" - std_cipherlists 'HIGH:!NULL:!aNULL:!DES:!3DES:!AESGCM:!CHACHA20:!AESGCM:!CamelliaGCM:!AESCCM8:!AESCCM'\ + sub_cipherlists '3DES:!aNULL:!ADH' " Triple DES Ciphers (Medium) " 0 "3DES" "$tdes_ciphers" "$sslv2_tdes_ciphers" + sub_cipherlists 'HIGH:!NULL:!aNULL:!DES:!3DES:!AESGCM:!CHACHA20:!AESGCM:!CamelliaGCM:!AESCCM8:!AESCCM'\ " High encryption (AES+Camellia, no AEAD) " 1 "HIGH" "$high_ciphers" "" - std_cipherlists 'AESGCM:CHACHA20:AESGCM:CamelliaGCM:AESCCM8:AESCCM' \ + sub_cipherlists 'AESGCM:CHACHA20:AESGCM:CamelliaGCM:AESCCM8:AESCCM' \ " Strong encryption (AEAD ciphers) " 2 "STRONG" "$strong_ciphers" "" outln return 0 @@ -5115,6 +5117,7 @@ run_server_preference() { local has_cipher_order=false local addcmd="" addcmd2="" local using_sockets=true + local jsonID="cipher_order" "$SSL_NATIVE" && using_sockets=false @@ -5136,7 +5139,7 @@ run_server_preference() { outln "$list_fwd . " tmpfile_handle $FUNCNAME.txt return 6 - fileout "cipher_order" "WARN" "Could not determine server cipher order, no matching cipher in this list found (pls report this): $list_fwd" + fileout "$jsonID" "WARN" "Could not determine server cipher order, no matching cipher in list found (pls report this): $list_fwd" elif [[ -n "$STARTTLS_PROTOCOL" ]]; then # now it still could be that we hit this bug: https://github.com/drwetter/testssl.sh/issues/188 # workaround is to connect with a protocol @@ -5146,7 +5149,7 @@ run_server_preference() { if ! sclient_connect_successful $? $TMPFILE; then pr_warning "no matching cipher in this list found (pls report this): " outln "$list_fwd . " - fileout "cipher_order" "WARN" "Could not determine server cipher order, no matching cipher in this list found (pls report this): $list_fwd" + fileout "$jsonID" "WARN" "Could not determine cipher order, no matching cipher in list found (pls report this): $list_fwd" tmpfile_handle $FUNCNAME.txt return 6 fi @@ -5172,17 +5175,18 @@ run_server_preference() { # server used the different ends (ciphers) from the client hello pr_svrty_high "nope (NOT ok)" limitedsense=" (limited sense as client will pick)" - fileout "cipher_order" "HIGH" "Server does NOT set a cipher order" + fileout "$jsonID" "HIGH" "NOT cipher order configured" else pr_done_best "yes (OK)" has_cipher_order=true limitedsense="" - fileout "cipher_order" "OK" "Server sets a cipher order" + fileout "$jsonID" "OK" "sets cipher order" fi debugme tm_out " $cipher1 | $cipher2" outln pr_bold " Negotiated protocol " + jsonID="protocol_negotiated" sclient_success=1 if "$using_sockets" && ! "$HAS_TLS13" && [[ $(has_server_protocol "tls1_3") -ne 1 ]]; then # Send same list of cipher suites as OpenSSL 1.1.1 sends. @@ -5209,44 +5213,45 @@ run_server_preference() { case "$default_proto" in *TLSv1.3) prln_done_best $default_proto - fileout "protocol_negotiated" "OK" "Default protocol TLS1.3" + fileout "$jsonID" "OK" "Default protocol TLS1.3" ;; *TLSv1.2) prln_done_best $default_proto - fileout "protocol_negotiated" "OK" "Default protocol TLS1.2" + fileout "$jsonID" "OK" "Default protocol TLS1.2" ;; *TLSv1.1) prln_done_good $default_proto - fileout "protocol_negotiated" "OK" "Default protocol TLS1.1" + fileout "$jsonID" "OK" "Default protocol TLS1.1" ;; *TLSv1) outln $default_proto - fileout "protocol_negotiated" "INFO" "Default protocol TLS1.0" + fileout "$jsonID" "INFO" "Default protocol TLS1.0" ;; *SSLv2) prln_svrty_critical $default_proto - fileout "protocol_negotiated" "CRITICAL" "Default protocol SSLv2" + fileout "$jsonID" "CRITICAL" "Default protocol SSLv2" ;; *SSLv3) prln_svrty_critical $default_proto - fileout "protocol_negotiated" "CRITICAL" "Default protocol SSLv3" + fileout "$jsonID" "CRITICAL" "Default protocol SSLv3" ;; "") pr_warning "default proto empty" if [[ $OSSL_VER == 1.0.2* ]]; then outln " (Hint: if IIS6 give OpenSSL 1.0.1 a try)" - fileout "protocol_negotiated" "WARN" "Default protocol empty (Hint: if IIS6 give OpenSSL 1.0.1 a try)" + fileout "$jsonID" "WARN" "Default protocol empty (Hint: if IIS6 give OpenSSL 1.0.1 a try)" else - fileout "protocol_negotiated" "WARN" "Default protocol empty" + fileout "$jsonID" "WARN" "Default protocol empty" fi ;; *) pr_warning "FIXME line $LINENO: $default_proto" - fileout "protocol_negotiated" "WARN" "FIXME line $LINENO: $default_proto" + fileout "$jsonID" "WARN" "FIXME line $LINENO: $default_proto" ;; esac pr_bold " Negotiated cipher " + jsonID="cipher_negotiated" cipher1=$(get_cipher $TMPFILE) if [[ "$DISPLAY_CIPHERNAMES" =~ openssl ]] && ( [[ "$cipher1" == TLS_* ]] || [[ "$cipher1" == SSL_* ]] ); then default_cipher="$(rfc2openssl "$cipher1")" @@ -5256,25 +5261,25 @@ run_server_preference() { [[ -z "$default_cipher" ]] && default_cipher="$cipher1" pr_cipher_quality "$default_cipher" case $? in - 1) fileout "cipher_negotiated" "CRITICAL" "$default_cipher$(read_dhbits_from_file "$TMPFILE" "string") $limitedsense" + 1) fileout "$jsonID" "CRITICAL" "$default_cipher$(read_dhbits_from_file "$TMPFILE" "string") $limitedsense" ;; - 2) fileout "cipher_negotiated" "HIGH" "$default_cipher$(read_dhbits_from_file "$TMPFILE" "string") $limitedsense" + 2) fileout "$jsonID" "HIGH" "$default_cipher$(read_dhbits_from_file "$TMPFILE" "string") $limitedsense" ;; - 3) fileout "cipher_negotiated" "MEDIUM" "$default_cipher$(read_dhbits_from_file "$TMPFILE" "string") $limitedsense" + 3) fileout "$jsonID" "MEDIUM" "$default_cipher$(read_dhbits_from_file "$TMPFILE" "string") $limitedsense" ;; - 6|7) fileout "cipher_negotiated" "OK" "$default_cipher$(read_dhbits_from_file "$TMPFILE" "string") $limitedsense" + 6|7) fileout "$jsonID" "OK" "$default_cipher$(read_dhbits_from_file "$TMPFILE" "string") $limitedsense" ;; # best ones - 4) fileout "cipher_negotiated" "LOW" "$default_cipher$(read_dhbits_from_file "$TMPFILE" "string") (cbc) $limitedsense" + 4) fileout "$jsonID" "LOW" "$default_cipher$(read_dhbits_from_file "$TMPFILE" "string") (cbc) $limitedsense" ;; # it's CBC. --> lucky13 0) pr_warning "default cipher empty" ; if [[ $OSSL_VER == 1.0.2* ]]; then out " (Hint: if IIS6 give OpenSSL 1.0.1 a try)" - fileout "cipher_negotiated" "WARN" "Default cipher empty (if IIS6 give OpenSSL 1.0.1 a try) $limitedsense" + fileout "$jsonID" "WARN" "Default cipher empty (if IIS6 give OpenSSL 1.0.1 a try) $limitedsense" else - fileout "cipher_negotiated" "WARN" "Default cipher empty $limitedsense" + fileout "$jsonID" "WARN" "Default cipher empty $limitedsense" fi ;; - *) fileout "cipher_negotiated" "INFO" "$default_cipher$(read_dhbits_from_file "$TMPFILE" "string") $limitedsense" + *) fileout "$jsonID" "INFO" "$default_cipher$(read_dhbits_from_file "$TMPFILE" "string") $limitedsense" ;; esac read_dhbits_from_file "$TMPFILE" @@ -5665,7 +5670,7 @@ cipher_pref_check() { else out_row_aligned_max_width_by_entry "$order" " " $TERM_WIDTH pr_cipher_quality fi - fileout "cipher_order_${proto//./_}" "INFO" "$order" + fileout "cipherorder_${proto//./_}" "INFO" "$order" fi done <<< "$(tm_out " ssl3 00 SSLv3\n tls1 01 TLSv1\n tls1_1 02 TLSv1.1\n tls1_2 03 TLSv1.2\n tls1_3 04 TLSv1.3\n")" outln @@ -5858,17 +5863,17 @@ tls_time() { if [[ "${#difftime}" -gt 5 ]]; then # openssl >= 1.0.1f fills this field with random values! --> good for possible fingerprint out "Random values, no fingerprinting possible " - fileout "${jsonID}" "INFO" "The server's TLS time seems to be filled with random values to prevent fingerprinting" + fileout "$jsonID" "INFO" "TLS timestamp is random" else [[ $difftime != "-"* ]] && [[ $difftime != "0" ]] && difftime="+$difftime" out "$difftime"; out " sec from localtime"; - fileout "${jsonID}" "INFO" "The server's TLS time is skewed from your localtime by $difftime seconds" + fileout "$jsonID" "INFO" "TLS timestamp is off from your localtime by $difftime seconds" fi debugme tm_out "$TLS_TIME" outln else outln "SSLv3 through TLS 1.2 didn't return a timestamp" - fileout "${jsonID}" "INFO" "No TLS timestamp returned by SSLv3 through TLSv1.2" + fileout "$jsonID" "INFO" "No TLS timestamp returned by SSLv3 through TLSv1.2" fi TLS_DIFFTIME_SET=false # reset the switch to save calls to date and friend in tls_sockets() return 0 @@ -6026,6 +6031,8 @@ get_server_certificate() { cat level?.crt > $TEMPDIR/intermediatecerts.pem rm level?.crt fi + # generate file with text output -- we need that at several occasions later + $OPENSSL x509 -noout -text -in $HOSTCERT 2>>$ERRFILE >$HOSTCERT_TXT fi cd "$savedir" fi @@ -6394,7 +6401,7 @@ certificate_info() { spaces=" " fi - cert_sig_algo="$($OPENSSL x509 -in $HOSTCERT -noout -text 2>>$ERRFILE | awk -F':' '/Signature Algorithm/ { print $2; if (++Match >= 1) exit; }')" + cert_sig_algo="$($OPENSSL x509 -in $HOSTCERT -noout -text 2>>$ERRFILE| awk -F':' '/Signature Algorithm/ { print $2; if (++Match >= 1) exit; }')" cert_sig_algo="${cert_sig_algo// /}" cert_key_algo="$($OPENSSL x509 -in $HOSTCERT -noout -text 2>>$ERRFILE | awk -F':' '/Public Key Algorithm:/ { print $2; if (++Match >= 1) exit; }')" cert_key_algo="${cert_key_algo// /}" @@ -6512,7 +6519,7 @@ certificate_info() { jsonID="cert_key_size" if [[ -z "$cert_keysize" ]]; then outln "(couldn't determine)" - fileout "${jsonID}${json_postfix}" "Server keys size cannot be determined" + fileout "${jsonID}${json_postfix}" "cannot be determined" else case $cert_key_algo in *RSA*|*rsa*) out "RSA ";; @@ -6529,22 +6536,22 @@ certificate_info() { if [[ $cert_key_algo =~ ecdsa ]] || [[ $cert_key_algo =~ ecPublicKey ]]; then if [[ "$cert_keysize" -le 110 ]]; then # a guess pr_svrty_critical "$cert_keysize" - fileout "${jsonID}${json_postfix}" "CRITICAL" "Server keys $cert_keysize EC bits" + fileout "${jsonID}${json_postfix}" "CRITICAL" "$cert_keysize EC bits" elif [[ "$cert_keysize" -le 123 ]]; then # a guess pr_svrty_high "$cert_keysize" - fileout "${jsonID}${json_postfix}" "HIGH" "Server keys $cert_keysize EC bits" + fileout "${jsonID}${json_postfix}" "HIGH" "$cert_keysize EC bits" elif [[ "$cert_keysize" -le 163 ]]; then pr_svrty_medium "$cert_keysize" - fileout "${jsonID}${json_postfix}" "MEDIUM" "Server keys $cert_keysize EC bits" + fileout "${jsonID}${json_postfix}" "MEDIUM" "$cert_keysize EC bits" elif [[ "$cert_keysize" -le 224 ]]; then out "$cert_keysize" - fileout "${jsonID}${json_postfix}" "INFO" "Server keys $cert_keysize EC bits" + fileout "${jsonID}${json_postfix}" "INFO" "$cert_keysize EC bits" elif [[ "$cert_keysize" -le 533 ]]; then pr_done_good "$cert_keysize" - fileout "${jsonID}${json_postfix}" "OK" "Server keys $cert_keysize EC bits" + fileout "${jsonID}${json_postfix}" "OK" "$cert_keysize EC bits" else out "keysize: $cert_keysize (not expected, FIXME)" - fileout "${jsonID}${json_postfix}" "DEBUG" "Server keys $cert_keysize bits (not expected)" + fileout "${jsonID}${json_postfix}" "DEBUG" " $cert_keysize bits (not expected)" fi outln " bits" elif [[ $cert_key_algo = *RSA* ]] || [[ $cert_key_algo = *rsa* ]] || [[ $cert_key_algo = *dsa* ]] || \ @@ -6552,25 +6559,25 @@ certificate_info() { if [[ "$cert_keysize" -le 512 ]]; then pr_svrty_critical "$cert_keysize" outln " bits" - fileout "${jsonID}${json_postfix}" "CRITICAL" "Server keys $cert_keysize bits" + fileout "${jsonID}${json_postfix}" "CRITICAL" "$cert_keysize bits" elif [[ "$cert_keysize" -le 768 ]]; then pr_svrty_high "$cert_keysize" outln " bits" - fileout "${jsonID}${json_postfix}" "HIGH" "Server keys $cert_keysize bits" + fileout "${jsonID}${json_postfix}" "HIGH" "$cert_keysize bits" elif [[ "$cert_keysize" -le 1024 ]]; then pr_svrty_medium "$cert_keysize" outln " bits" - fileout "${jsonID}${json_postfix}" "MEDIUM" "Server keys $cert_keysize bits" + fileout "${jsonID}${json_postfix}" "MEDIUM" "$cert_keysize bits" elif [[ "$cert_keysize" -le 2048 ]]; then outln "$cert_keysize bits" - fileout "${jsonID}${json_postfix}" "INFO" "Server keys $cert_keysize bits" + fileout "${jsonID}${json_postfix}" "INFO" "$cert_keysize bits" elif [[ "$cert_keysize" -le 4096 ]]; then pr_done_good "$cert_keysize" - fileout "${jsonID}${json_postfix}" "OK" "Server keys $cert_keysize bits" + fileout "${jsonID}${json_postfix}" "OK" "$cert_keysize bits" outln " bits" else pr_warning "weird key size: $cert_keysize bits"; outln " (could cause compatibility problems)" - fileout "${jsonID}${json_postfix}" "WARN" "Server keys $cert_keysize bits (Odd)" + fileout "${jsonID}${json_postfix}" "WARN" "$cert_keysize bits (Odd)" fi else out "$cert_keysize bits (" @@ -6583,7 +6590,7 @@ certificate_info() { out "$indent"; pr_bold " Server key usage "; outok=true jsonID="cert_key_usage" - cert_keyusage=$($OPENSSL x509 -text -noout -in $HOSTCERT 2>>$ERRFILE | grep -A 1 "X509v3 Key Usage:" | tail -n +2 | sed 's/^[ \t]*//') + cert_keyusage="$(strip_leading_space "$($OPENSSL x509 -noout -text -in $HOSTCERT 2>>$ERRFILE | awk '/X509v3 Key Usage:/ { getline; print $0 }')")" if [[ -n "$cert_keyusage" ]]; then outln "$cert_keyusage" if ( [[ " $cert_type " =~ " RSASig " ]] || [[ " $cert_type " =~ " DSA " ]] || [[ " $cert_type " =~ " ECDSA " ]] ) && \ @@ -6605,17 +6612,18 @@ certificate_info() { fi else outln "--" - fileout "${jsonID}key_usage" "INFO" "No server key usage information" + fileout "${jsonID}${json_postfix}" "INFO" "No server key usage information" outok=false fi if "$outok"; then - fileout "${jsonID}key_usage" "INFO" "$cert_keyusage" + fileout "${jsonID}${json_postfix}" "INFO" "$cert_keyusage" fi out "$indent"; pr_bold " Server extended key usage "; jsonID="cert_extended_key_usage" outok=true - cert_ext_keyusage="$($OPENSSL x509 -noout -text -in $HOSTCERT 2>>$ERRFILE | grep -A 1 "X509v3 Extended Key Usage: " | tail -1 | sed 's/^[ \t]*//')" + cert_ext_keyusage="$(strip_leading_space "$($OPENSSL x509 -noout -text -in $HOSTCERT 2>>$ERRFILE | awk '/X509v3 Extended Key Usage:/ { getline; print $0 }')")" + $OPENSSL x509 -noout -text -in $HOSTCERT 2>>$ERRFILE | awk '/X509v3 Extended Key Usage:/ { getline; print $0 }' | read cert_ext_keyusage if [[ -n "$cert_ext_keyusage" ]]; then outln "$cert_ext_keyusage" if [[ ! "$cert_ext_keyusage" =~ "TLS Web Server Authentication" ]] && [[ ! "$cert_ext_keyusage" =~ "Any Extended Key Usage" ]]; then @@ -6754,7 +6762,7 @@ certificate_info() { if [[ -n "$issuer_C" ]]; then issuerfinding+=" from " out " from " - issuerfinding+="$issuer_C" + # issuerfinding+="$issuer_C" pr_italic "$issuer_C" fi issuerfinding+=")" @@ -6960,7 +6968,7 @@ certificate_info() { certificates_provided=1+$(grep -c "\-\-\-\-\-BEGIN CERTIFICATE\-\-\-\-\-" $TEMPDIR/intermediatecerts.pem) out "$indent"; pr_bold " # of certificates provided"; outln " $certificates_provided" - fileout "certchain_count${json_postfix}" "INFO" "${certificates_provided} certificates provided" + fileout "certchain_count${json_postfix}" "INFO" "${certificates_provided} certificates" # Get both CRL and OCSP URI upfront. If there's none, this is not good. And we need to penalize this in the output crl="$($OPENSSL x509 -in $HOSTCERT -noout -text 2>>$ERRFILE | \ @@ -7057,23 +7065,24 @@ certificate_info() { done <<< "$caa" all_caa=${all_caa%, } # strip trailing comma pr_italic "$(out_row_aligned_max_width "$all_caa" "$indent " $TERM_WIDTH)" - fileout "${jsonID}${json_postfix}" "OK" "'DNS Certification Authority Authorization (CAA) Resource Record / RFC6844' \'$all_caa\' " + fileout "${jsonID}${json_postfix}" "OK" "$all_caa" elif "$NODNS"; then pr_warning "(was instructed to not use DNS)" fileout "${jsonID}${json_postfix}" "WARN" "check skipped as instructed" else pr_svrty_low "not offered" - fileout "${jsonID}${json_postfix}" "LOW" "'DNS Certification Authority Authorization (CAA) Resource Record / RFC6844' not offered" + fileout "${jsonID}${json_postfix}" "LOW" "not offered" fi outln out "$indent"; pr_bold " Certificate Transparency "; + jsonID="certificate_transparency" if [[ "$ct" =~ extension ]]; then pr_done_good "yes"; outln " ($ct)" - fileout "certificate_transparency${json_postfix}" "OK" "yes ($ct)" + fileout "${jsonID}${json_postfix}" "OK" "yes ($ct)" else outln "$ct" - fileout "certificate_transparency${json_postfix}" "INFO" "$ct" + fileout "${jsonID}${json_postfix}" "INFO" "$ct" fi outln return $ret @@ -7265,7 +7274,7 @@ run_server_defaults() { jsonID="TLS_session_ticket" if [[ -z "$sessticket_lifetime_hint" ]]; then outln "(no lifetime advertised)" - fileout "${jsonID}" "INFO" "No TLS session ticket RFC 5077 lifetime advertised" + fileout "${jsonID}" "INFO" "No lifetime advertised" # it MAY be given a hint of the lifetime of the ticket, see https://tools.ietf.org/html/rfc5077#section-5.6 . # Sometimes it just does not -- but it then may also support TLS session tickets reuse else @@ -7274,66 +7283,69 @@ run_server_defaults() { out "$lifetime $unit" if [[ $((3600 * 24)) -lt $lifetime ]]; then prln_svrty_low " but: PFS requires session ticket keys to be rotated < daily !" - fileout "${jsonID}" "LOW" "TLS session ticket RFC 5077 valid for $lifetime $unit but PFS requires session ticket keys to be rotated at least daily!" + fileout "$jsonID" "LOW" "valid for $lifetime $unit (>daily)" else outln ", session tickets keys seems to be rotated < daily" - fileout "${jsonID}" "INFO" "TLS session ticket RFC 5077 valid for $lifetime $unit only (PFS requires session ticket keys are rotated at least daily)" + fileout "$jsonID" "INFO" "valid for $lifetime $unit only ($TMPFILE 2>$ERRFILE =2)" [[ $DEBUG -ge 3 ]] && hexdump -C "$TEMPDIR/$NODEIP.sslv2_sockets.dd" | head -1 ret=7 - fileout "DROWN" "WARN" "received a strange SSLv2 reply (rerun with DEBUG>=2)" "$cve" "$cwe" + fileout "$jsonID" "WARN" "received a strange SSLv2 reply (rerun with DEBUG>=2)" "$cve" "$cwe" ;; 3) # vulnerable, [[ -n "$cert_fingerprint_sha2" ]] test is not needed as we should have RSA certificate here lines=$(count_lines "$(hexdump -C "$TEMPDIR/$NODEIP.sslv2_sockets.dd" 2>/dev/null)") @@ -12802,10 +12821,10 @@ run_drown() { nr_ciphers_detected=$((V2_HELLO_CIPHERSPEC_LENGTH / 3)) if [[ 0 -eq "$nr_ciphers_detected" ]]; then prln_svrty_high "CVE-2015-3197: SSLv2 supported but couldn't detect a cipher (NOT ok)"; - fileout "DROWN" "HIGH" "SSLv2 offered, but could not detect a cipher (CVE-2015-3197. Make sure you don't use this certificate elsewhere, see https://censys.io/ipv4?q=$cert_fingerprint_sha2" "$cve" "$cwe" "$hint" + fileout "$jsonID" "HIGH" "SSLv2 offered, but could not detect a cipher (CVE-2015-3197). Make sure you don't use this certificate elsewhere, see https://censys.io/ipv4?q=$cert_fingerprint_sha2" "$cve" "$cwe" "$hint" else prln_svrty_critical "VULNERABLE (NOT ok), SSLv2 offered with $nr_ciphers_detected ciphers"; - fileout "DROWN" "CRITICAL" "VULNERABLE, SSLv2 offered with $nr_ciphers_detected ciphers. Make sure you don't use this certificate elsewhere, see https://censys.io/ipv4?q=$cert_fingerprint_sha2" "$cve" "$cwe" "$hint" + fileout "$jsonID" "CRITICAL" "VULNERABLE, SSLv2 offered with $nr_ciphers_detected ciphers. Make sure you don't use this certificate elsewhere, see https://censys.io/ipv4?q=$cert_fingerprint_sha2" "$cve" "$cwe" "$hint" fi outln "$spaces Make sure you don't use this certificate elsewhere, see:" out "$spaces " @@ -12821,10 +12840,10 @@ run_drown() { out "$spaces " pr_url "https://censys.io/ipv4?q=$cert_fingerprint_sha2" outln " could help you to find out" - fileout "DROWN" "INFO" "make sure you don't use this certificate elsewhere with SSLv2 enabled services, see https://censys.io/ipv4?q=$cert_fingerprint_sha2" + fileout "$jsonID" "INFO" "Make sure you don't use this certificate elsewhere with SSLv2 enabled services, see https://censys.io/ipv4?q=$cert_fingerprint_sha2" else outln "$spaces no RSA certificate, thus certificate can't be used with SSLv2 elsewhere" - fileout "DROWN" "INFO" "no RSA certificate, thus certificate can't be used with SSLv2 elsewhere" + fileout "$jsonID" "INFO" "no RSA certificate, can't be used with SSLv2 elsewhere" fi ret=0 ;; @@ -13064,7 +13083,7 @@ run_beast(){ if ! "$WIDE"; then if [[ -n "$detected_cbc_ciphers" ]]; then - fileout "BEAST_CBC_$(toupper $proto)" "MEDIUM" "CBC ciphers for $(toupper $proto): $detected_cbc_ciphers" "$cve" "$cwe" "$hint" + fileout "BEAST_CBC_$(toupper $proto)" "MEDIUM" "$detected_cbc_ciphers" "$cve" "$cwe" "$hint" ! "$first" && out "$spaces" out "$(toupper $proto): " [[ -n "$higher_proto_supported" ]] && \ @@ -13156,8 +13175,8 @@ run_lucky13() { fi if [[ $sclient_success -eq 0 ]]; then out "potentially " - pr_svrty_low "VULNERABLE"; out ", uses cipher block chaining (CBC) ciphers with TLS" - fileout "LUCKY13" "LOW" "potentially vulnerable to LUCKY13, uses cipher block chaining (CBC) ciphers with TLS. Check patches" "$cve" "$cwe" "$hint" + pr_svrty_low "VULNERABLE"; out ", uses cipher block chaining (CBC) ciphers with TLS. Check patches" + fileout "LUCKY13" "LOW" "potentially vulnerable to LUCKY13, uses TLS CBC ciphers" "$cve" "$cwe" "$hint" # the CBC padding which led to timing differences during MAC processing has been solved in openssl (https://www.openssl.org/news/secadv/20130205.txt) # and other software. However we can't tell with reasonable effort from the outside. Thus we still issue a warning and label it experimental else @@ -13807,17 +13826,18 @@ run_robot() { local -i start_time end_time timeout=$MAX_WAITSOCK local cve="CVE-2017-17382 CVE-2017-17427 CVE-2017-17428 CVE-2017-13098 CVE-2017-1000385 CVE-2017-13099 CVE-2016-6883 CVE-2012-5081" local cwe="" + local jsonID="ROBOT" [[ $VULN_COUNT -le $VULN_THRESHLD ]] && outln && pr_headlineln " Testing for Return of Bleichenbacher's Oracle Threat (ROBOT) vulnerability " && outln pr_bold " ROBOT " if [[ ! "$HAS_PKUTIL" ]]; then prln_local_problem "Your $OPENSSL does not support the pkeyutl utility." - fileout "ROBOT" "WARN" "Your $OPENSSL does not support the pkeyutl utility." + fileout "$jsonID" "WARN" "$OPENSSL does not support the pkeyutl utility." return 7 elif ! "$HAS_PKEY"; then prln_local_problem "Your $OPENSSL does not support the pkey utility." - fileout "ROBOT" "WARN" "Your $OPENSSL does not support the pkey utility." + fileout "$jsonID" "WARN" "$OPENSSL does not support the pkey utility." return 7 fi @@ -13853,7 +13873,7 @@ run_robot() { cipherlist="${cipherlist:2}" elif [[ $ret -ne 0 ]]; then prln_done_best "Server does not support any cipher suites that use RSA key transport" - fileout "ROBOT" "OK" "not vulnerable (server does not support any cipher suites that use RSA key transport)" + fileout "$jsonID" "OK" "not vulnerable, no RSA key transport cipher" return 0 fi fi @@ -13929,7 +13949,7 @@ run_robot() { fi close_socket prln_fixme "Conversion of public key failed around line $((LINENO - 9))" - fileout "ROBOT" "WARN" "Conversion of public key failed around line $((LINENO - 10)) " + fileout "$jsonID" "WARN" "Conversion of public key failed around line $((LINENO - 10)) " return 1 fi @@ -14032,14 +14052,14 @@ run_robot() { if "$vulnerable"; then if [[ "${response[1]}" == "${response[2]}" ]] && [[ "${response[2]}" == "${response[3]}" ]]; then pr_svrty_medium "VULNERABLE (NOT ok)"; outln " - weakly vulnerable as the attack would take too long" - fileout "ROBOT" "MEDIUM" "VULNERABLE, but the attack would take too long" + fileout "$jsonID" "MEDIUM" "VULNERABLE, but the attack would take too long" else prln_svrty_critical "VULNERABLE (NOT ok)" - fileout "ROBOT" "CRITICAL" "VULNERABLE" + fileout "$jsonID" "CRITICAL" "VULNERABLE" fi else prln_done_best "not vulnerable (OK)" - fileout "ROBOT" "OK" "not vulnerable" + fileout "$jsonID" "OK" "not vulnerable" fi return 0 } @@ -14459,7 +14479,8 @@ maketempf() { else ERRFILE=$TEMPDIR/errorfile.txt || exit -6 fi - HOSTCERT=$TEMPDIR/host_certificate.txt + HOSTCERT=$TEMPDIR/host_certificate.pem + HOSTCERT_TXT=$TEMPDIR/host_certificate.txt #FIXME: needs to be used later } prepare_debug() { @@ -16149,7 +16170,7 @@ parse_cmd_line() { do_protocols=true ;; -s|--std|--standard) - do_std_cipherlists=true + do_cipherlists=true ;; -S|--server[-_]defaults) do_server_defaults=true @@ -16572,7 +16593,7 @@ lets_roll() { "$do_grease" && { run_grease; ret=$(($? + ret)); time_right_align run_grease; } fileout_section_header $section_number true && ((section_number++)) - $do_std_cipherlists && { run_std_cipherlists; ret=$(($? + ret)); time_right_align run_std_cipherlists; } + $do_cipherlists && { run_cipherlists; ret=$(($? + ret)); time_right_align run_cipherlists; } fileout_section_header $section_number true && ((section_number++)) $do_pfs && { run_pfs; ret=$(($? + ret)); time_right_align run_pfs; }