From 8c607d425e139c5bb23dccfbce75b519f2e1fc05 Mon Sep 17 00:00:00 2001 From: David Cooper Date: Fri, 17 Feb 2017 15:20:37 -0500 Subject: [PATCH] OCSP must staple RFC 7633 introduces the TLS Features certificate extension, which contains "Features: > The object member "Features" is a sequence of TLS extension identifiers (features, in this specification's terminology) as specified in the IANA Transport Layer Security (TLS) Extensions registry. If these features are requested by the client in its ClientHello message, then the server MUST return a ServerHello message that satisfies this request. The main purpose of this certificate extension is to implement "must staple." If the extension is present in a TLS server's certificate and it includes status_request, then the server MUST include a stapled OCSP response if the client requests one. (The same applies for the status_request_v2 extension.) This PR adds a check to `certificate_info()` of whether the server supports must staple (i.e., whether its certificate includes a TLS Features extension with "status_request"). It also changes the output for "OCSP stapling" in the case that the server did not staple an OCSP response. It indicates that: * it is a critical issue if the certificate specifies "must staple" * it is a low severity issue if the certificate does not specify "must staple," but the certificate does include an OCSP URI. * it is not an issue at all if the certificate does not specify "must staple" and certificate does not include an OCSP URI. --- testssl.sh | 63 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 60 insertions(+), 3 deletions(-) diff --git a/testssl.sh b/testssl.sh index f3da16e..301e830 100755 --- a/testssl.sh +++ b/testssl.sh @@ -5894,6 +5894,50 @@ compare_server_name_to_cert() return $ret } +must_staple() { + local json_prefix="$2" + local cert extn + local -i extn_len + local supported=false + + # Note this function is only looking for status_request (5) and not + # status_request_v2 (17), since OpenSSL seems to only include status_request (5) + # in its ClientHello when the "-status" option is used. + + # OpenSSL 1.1.0 supports pretty-printing the "TLS Feature extension." For any + # previous versions of OpenSSL, OpenSSL can only show if the extension OID is present. + if $OPENSSL x509 -in "$HOSTCERT" -noout -text 2>>$ERRFILE | grep -A 1 "TLS Feature:" | grep -q "status_request"; then + # FIXME: This will indicate that must staple is supported if the + # certificate indicates status_request or status_request_v2. This is + # probably okay, since it seems likely that any TLS Feature extension + # that includes status_request_v2 will also include status_request. + supported=true + elif $OPENSSL x509 -in "$HOSTCERT" -noout -text 2>>$ERRFILE | grep -q "1.3.6.1.5.5.7.1.24:"; then + cert="$($OPENSSL x509 -in "$HOSTCERT" -outform DER 2>>$ERRFILE | hexdump -v -e '16/1 "%02X"')" + extn="${cert##*06082B06010505070118}" + # Check for critical bit, and skip over it if present. + [[ "${extn:0:6}" == "0101FF" ]] && extn="${extn:6}" + # Next is tag and length of extnValue OCTET STRING. Assume it is less than 128 bytes. + extn="${extn:4}" + # The TLS Feature is a SEQUENCE of INTEGER. Get the length of the SEQUENCE + extn_len=2*$(hex2dec "${extn:2:2}") + # If the extension include the status_request (5), then it supports must staple. + if [[ "${extn:4:extn_len}" =~ "020105" ]]; then + supported=true + fi + fi + + if "$supported"; then + pr_done_bestln "Supported" + fileout "${json_prefix}ocsp_must_staple" "OK" "OCSP must staple : supported" + return 0 + else + outln "No" + fileout "${json_prefix}ocsp_must_staple" "INFO" "OCSP must staple : no" + return 1 + fi +} + certificate_info() { local proto local -i certificate_number=$1 @@ -5904,7 +5948,8 @@ certificate_info() { local ocsp_response_status=$6 local sni_used=$7 local cert_sig_algo cert_sig_hash_algo cert_key_algo - local expire days2expire secs2warn ocsp_uri crl startdate enddate issuer_CN issuer_C issuer_O issuer sans san all_san="" cn + local expire days2expire secs2warn ocsp_uri ocsp_must_staple 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 policy_oid @@ -6423,10 +6468,22 @@ certificate_info() { fileout "${json_prefix}ocsp_uri" "INFO" "OCSP URI : $ocsp_uri" fi + out "$indent"; pr_bold " OCSP must staple "; + must_staple "$json_prefix" + [[ $? -eq 0 ]] && ocsp_must_staple=true || ocsp_must_staple=false + out "$indent"; pr_bold " OCSP stapling " if grep -a "OCSP response" <<<"$ocsp_response" | grep -q "no response sent" ; then - pr_svrty_low "--" - fileout "${json_prefix}ocsp_stapling" "LOW" "OCSP stapling : not offered" + if "$ocsp_must_staple"; then + pr_svrty_critical "--" + fileout "${json_prefix}ocsp_stapling" "CRITICAL" "OCSP stapling : not offered" + elif [[ -n "$ocsp_uri" ]]; then + pr_svrty_low "--" + fileout "${json_prefix}ocsp_stapling" "LOW" "OCSP stapling : not offered" + else + out "--" + fileout "${json_prefix}ocsp_stapling" "INFO" "OCSP stapling : not offered" + fi else if grep -a "OCSP Response Status" <<<"$ocsp_response_status" | grep -q successful; then pr_done_good "offered"