From 2edfa57eaaf12e65131d2a081ffd2382319c3c7f Mon Sep 17 00:00:00 2001 From: Dirk Wetter Date: Tue, 19 Oct 2021 19:42:12 +0200 Subject: [PATCH] Check cert serial len + fix output when too big OpenSSL shows certificate serial numbers >35 with a LF (0A). Testssl.sh just output that which makes JSON invalid and displays the LF in the terminal too. This commit fixes that (#2010) by adding filters so that the serialnumber is not a multiline string. Also this commit introduces a new function: a size check of the cert serial. Below 8 bytes the CAB Forum's lower limit is hit which says the *entropy* from a CSPRNG should be at least 64 bits. It is assumed that below 8 bytes length this requirement isn't possible to meet (needs to be clarified with Shannon, 8 bytes seems to low to me). The high threshold is according to RFC 5280, Section-4.1.2.2 . See also #2013. The output has changed, so that on the terminal the serial has one line, SHA1 and SHA256 each one line. The new json key is "cert_serialNumberLen". --- testssl.sh | 34 ++++++++++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/testssl.sh b/testssl.sh index 0b6e4fd..6f9e3c7 100755 --- a/testssl.sh +++ b/testssl.sh @@ -8429,8 +8429,10 @@ certificate_transparency() { return 0 } -# replacement for inline $OPENSSL x509 -noout -in $HOSTCERT -serial -# and $OPENSSL x509 -noout -in $HOSTCERT -fingerprint -sha256/-sha1 +# Shortcut for $OPENSSL x509 -noout -in $cert $ossl_command +# arg1 is the certificate +# arg2 is -serial | -fingerprint -sha1 | -fingerprint -sha256 +# returns the serial or fingerprint as ASCII # determine_cert_fingerprint_serial() { local cert="$1" @@ -8444,6 +8446,10 @@ determine_cert_fingerprint_serial() { result="${result//:/}" result="${result//SHA1 /}" result="${result//SHA256 /}" + # When the serial number is too large we'll get a 0x0a LF after 70 ASCII chars (see #2010). + # Thus we clean them here so that it is displayed correctly. + result="${result/[$'\n\r']/}" + result="${result//[\\]/}" safe_echo "$result" } @@ -8549,6 +8555,7 @@ certificate_info() { local -i secsaday=86400 local first=true local badocsp=1 + local len_cert_serial=0 if [[ $number_of_certificates -gt 1 ]]; then [[ $certificate_number -eq 1 ]] && outln @@ -8885,12 +8892,31 @@ certificate_info() { hostcert="$(<$HOSTCERT)" - out "$indent"; pr_bold " Serial / Fingerprints " + out "$indent"; pr_bold " Serial " cert_serial="$(determine_cert_fingerprint_serial "$hostcert" "-serial")" fileout "cert_serialNumber${json_postfix}" "INFO" "$cert_serial" + out "$cert_serial" + len_cert_serial=${#cert_serial} + len_cert_serial=$(( len_cert_serial / 2 )) + + if [[ $len_cert_serial -gt 20 ]]; then + # https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.2 + outln + prln_svrty_low "${spaces}NOT ok: length must not exceed 20 bytes (is: $len_cert_serial bytes)" + fileout "cert_serialNumberLen${json_postfix}" "LOW" "$len_cert_serial is too long" + elif [[ $len_cert_serial -lt 8 ]]; then + # Wording is from https://cabforum.org/wp-content/uploads/CA-Browser-Forum-BR-1.8.0.pdf + prln_svrty_low " NOT ok: length should be >= 64 bits entropy (is: $len_cert_serial bytes)" + fileout "cert_serialNumberLen${json_postfix}" "LOW" "$len_cert_serial is not enough entropy" + else + outln " (OK: length $len_cert_serial)" + fileout "cert_serialNumberLen${json_postfix}" "INFO" "$len_cert_serial" + fi + + out "$indent"; pr_bold " Fingerprints " cert_fingerprint_sha1="$(determine_cert_fingerprint_serial "$hostcert" "-fingerprint -sha1")" - outln "$cert_serial / SHA1 $cert_fingerprint_sha1" + outln "SHA1 $cert_fingerprint_sha1" fileout "cert_fingerprintSHA1${json_postfix}" "INFO" "${cert_fingerprint_sha1}" cert_fingerprint_sha2="$(determine_cert_fingerprint_serial "$hostcert" "-fingerprint -sha256")"