mirror of
https://github.com/drwetter/testssl.sh.git
synced 2025-01-01 06:19:44 +01:00
Check stapled OCSP response for revocation status
In cases in which the server offers a stapled OCSP response, this commit extracts the OCSP response and then checks the response for the status of the server's certificate. The check is performed in the same way as when the certificate includes an OCSP URI and the "--phone-out" option is set, except that the OCSP response is received from the TLS server rather than coming directly from the OCSP responder. Since this only involves additional processing of data that testssl.sh is already receiving, the check is performed whether or not the "--phone-out" flag is set.
This commit is contained in:
parent
4aabc3f999
commit
b5595a9205
119
testssl.sh
119
testssl.sh
@ -249,6 +249,7 @@ NO_ENGINE=${NO_ENGINE:-false} # if there are problems finding the (ext
|
||||
declare -r CLIENT_MIN_PFS=5 # number of ciphers needed to run a test for PFS
|
||||
CAPATH="${CAPATH:-/etc/ssl/certs/}" # Does nothing yet (FC has only a CA bundle per default, ==> openssl version -d)
|
||||
GOOD_CA_BUNDLE="" # A bundle of CA certificates that can be used to validate the server's certificate
|
||||
STAPLED_OCSP_RESPONSE=""
|
||||
MEASURE_TIME_FILE=${MEASURE_TIME_FILE:-""}
|
||||
if [[ -n "$MEASURE_TIME_FILE" ]] && [[ -z "$MEASURE_TIME" ]]; then
|
||||
MEASURE_TIME=true
|
||||
@ -1516,26 +1517,35 @@ check_revocation_crl() {
|
||||
|
||||
check_revocation_ocsp() {
|
||||
local uri="$1"
|
||||
local jsonID="$2"
|
||||
local stapled_response="$2"
|
||||
local jsonID="$3"
|
||||
local tmpfile=""
|
||||
local -i success
|
||||
local response=""
|
||||
local host_header=""
|
||||
|
||||
"$PHONE_OUT" || return 0
|
||||
"$PHONE_OUT" || [[ -n "$stapled_response" ]] || return 0
|
||||
[[ -n "$GOOD_CA_BUNDLE" ]] || return 0
|
||||
grep -q "\-\-\-\-\-BEGIN CERTIFICATE\-\-\-\-\-" $TEMPDIR/intermediatecerts.pem || return 0
|
||||
tmpfile=$TEMPDIR/${NODE}-${NODEIP}.${uri##*\/} || exit $ERR_FCREATE
|
||||
host_header=${uri##http://}
|
||||
host_header=${host_header%%/*}
|
||||
if [[ $OSSL_VER_MAJOR.$OSSL_VER_MINOR == "1.1.0"* ]] || [[ $OSSL_VER_MAJOR.$OSSL_VER_MINOR == "1.1.1"* ]]; then
|
||||
host_header="-header Host=${host_header}"
|
||||
if [[ -n "$stapled_response" ]]; then
|
||||
> "$TEMPDIR/stabled_ocsp_response.dd"
|
||||
asciihex_to_binary_file "$stapled_response" "$TEMPDIR/stabled_ocsp_response.dd"
|
||||
$OPENSSL ocsp -no_nonce -respin "$TEMPDIR/stabled_ocsp_response.dd" \
|
||||
-issuer $TEMPDIR/hostcert_issuer.pem -verify_other $TEMPDIR/intermediatecerts.pem \
|
||||
-CAfile <(cat $ADDITIONAL_CA_FILES "$GOOD_CA_BUNDLE") -cert $HOSTCERT -text &> "$tmpfile"
|
||||
else
|
||||
host_header="-header Host ${host_header}"
|
||||
host_header=${uri##http://}
|
||||
host_header=${host_header%%/*}
|
||||
if [[ $OSSL_VER_MAJOR.$OSSL_VER_MINOR == "1.1.0"* ]] || [[ $OSSL_VER_MAJOR.$OSSL_VER_MINOR == "1.1.1"* ]]; then
|
||||
host_header="-header Host=${host_header}"
|
||||
else
|
||||
host_header="-header Host ${host_header}"
|
||||
fi
|
||||
$OPENSSL ocsp -no_nonce ${host_header} -url "$uri" \
|
||||
-issuer $TEMPDIR/hostcert_issuer.pem -verify_other $TEMPDIR/intermediatecerts.pem \
|
||||
-CAfile <(cat $ADDITIONAL_CA_FILES "$GOOD_CA_BUNDLE") -cert $HOSTCERT -text &> "$tmpfile"
|
||||
fi
|
||||
$OPENSSL ocsp -no_nonce ${host_header} -url "$uri" \
|
||||
-issuer $TEMPDIR/hostcert_issuer.pem -verify_other $TEMPDIR/intermediatecerts.pem \
|
||||
-CAfile <(cat $ADDITIONAL_CA_FILES "$GOOD_CA_BUNDLE") -cert $HOSTCERT -text &> "$tmpfile"
|
||||
if [[ $? -eq 0 ]] && grep -Fq "Response verify OK" "$tmpfile"; then
|
||||
response="$(grep -F "$HOSTCERT: " "$tmpfile")"
|
||||
response="${response#$HOSTCERT: }"
|
||||
@ -6580,6 +6590,53 @@ extract_certificates() {
|
||||
return $success
|
||||
}
|
||||
|
||||
extract_stapled_ocsp() {
|
||||
local response="$(cat $TMPFILE)"
|
||||
local ocsp tmp
|
||||
local -i ocsp_len
|
||||
|
||||
STAPLED_OCSP_RESPONSE=""
|
||||
if [[ "$response" =~ "CertificateStatus" ]]; then
|
||||
# This is OpenSSL 1.1.0 or 1.1.1 and the response
|
||||
# is TLS 1.2 or earlier.
|
||||
ocsp="${response##*CertificateStatus}"
|
||||
ocsp="16${ocsp#*16}"
|
||||
ocsp="${ocsp%%<<<*}"
|
||||
ocsp="$(strip_spaces "$(newline_to_spaces "$ocsp")")"
|
||||
ocsp="${ocsp:8}"
|
||||
elif [[ "$response" =~ "TLS server extension \"status request\" (id=5), len=0" ]]; then
|
||||
# This is not OpenSSL 1.1.0 or 1.1.1, and the response
|
||||
# is TLS 1.2 or earlier.
|
||||
ocsp="${response%%OCSP response:*}"
|
||||
ocsp="${ocsp##*<<<}"
|
||||
ocsp="16${ocsp#*16}"
|
||||
ocsp="$(strip_spaces "$(newline_to_spaces "$ocsp")")"
|
||||
ocsp="${ocsp:8}"
|
||||
elif [[ "$response" =~ "TLS server extension \"status request\" (id=5), len=" ]]; then
|
||||
# This is OpenSSL 1.1.1 and the response is TLS 1.3.
|
||||
ocsp="${response##*TLS server extension \"status request\" (id=5), len=}"
|
||||
ocsp="${ocsp%%<<<*}"
|
||||
tmp="${ocsp%%[!0-9]*}"
|
||||
ocsp="${ocsp#$tmp}"
|
||||
ocsp_len=2*$tmp
|
||||
ocsp="$(awk ' { print $3 $4 $5 $6 $7 $8 $9 $10 $11 $12 $13 $14 $15 $16 $17 } ' <<< "$ocsp" | sed 's/-//')"
|
||||
ocsp="$(strip_spaces "$(newline_to_spaces "$ocsp")")"
|
||||
ocsp="${ocsp:0:ocsp_len}"
|
||||
else
|
||||
return 0
|
||||
fi
|
||||
# Determine whether this is a single OCSP response or a sequence of
|
||||
# responses and then extract just the response for the server's
|
||||
# certificate.
|
||||
if [[ "${ocsp:0:2}" == "01" ]]; then
|
||||
STAPLED_OCSP_RESPONSE="${ocsp:8}"
|
||||
elif [[ "${ocsp:0:2}" == "02" ]]; then
|
||||
ocsp_len=2*$(hex2dec "${tls_certificate_status_ascii:8:6}")
|
||||
STAPLED_OCSP_RESPONSE="${ocsp:14:ocsp_len}"
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# arg1 is "-cipher <OpenSSL cipher>" or empty
|
||||
# arg2 is a list of protocols to try (tls1_2, tls1_1, tls1, ssl3) or empty (if all should be tried)
|
||||
get_server_certificate() {
|
||||
@ -6591,15 +6648,16 @@ get_server_certificate() {
|
||||
[[ $(has_server_protocol "tls1_3") -eq 1 ]] && return 1
|
||||
if "$HAS_TLS13"; then
|
||||
if [[ "$1" =~ "-cipher tls1_3_RSA" ]]; then
|
||||
$OPENSSL s_client $(s_client_options "$STARTTLS $BUGS -showcerts -connect $NODEIP:$PORT $PROXY $SNI -tls1_3 -tlsextdebug -status -sigalgs PSS+SHA256:PSS+SHA384") </dev/null 2>$ERRFILE >$TMPFILE
|
||||
$OPENSSL s_client $(s_client_options "$STARTTLS $BUGS -showcerts -connect $NODEIP:$PORT $PROXY $SNI -tls1_3 -tlsextdebug -status -msg -sigalgs PSS+SHA256:PSS+SHA384") </dev/null 2>$ERRFILE >$TMPFILE
|
||||
elif [[ "$1" =~ "-cipher tls1_3_ECDSA" ]]; then
|
||||
$OPENSSL s_client $(s_client_options "$STARTTLS $BUGS -showcerts -connect $NODEIP:$PORT $PROXY $SNI -tls1_3 -tlsextdebug -status -sigalgs ECDSA+SHA256:ECDSA+SHA384") </dev/null 2>$ERRFILE >$TMPFILE
|
||||
$OPENSSL s_client $(s_client_options "$STARTTLS $BUGS -showcerts -connect $NODEIP:$PORT $PROXY $SNI -tls1_3 -tlsextdebug -status -msg -sigalgs ECDSA+SHA256:ECDSA+SHA384") </dev/null 2>$ERRFILE >$TMPFILE
|
||||
else
|
||||
return 1
|
||||
fi
|
||||
sclient_connect_successful $? $TMPFILE || return 1
|
||||
DETECTED_TLS_VERSION="0304"
|
||||
extract_certificates "tls1_3"
|
||||
extract_stapled_ocsp
|
||||
success=$?
|
||||
else
|
||||
if [[ "$1" =~ "-cipher tls1_3_RSA" ]]; then
|
||||
@ -6650,7 +6708,7 @@ get_server_certificate() {
|
||||
[[ 1 -eq $(has_server_protocol $proto) ]] && continue
|
||||
[[ "$proto" == "ssl3" ]] && ! "$HAS_SSL3" && continue
|
||||
addcmd=""
|
||||
$OPENSSL s_client $(s_client_options "$STARTTLS $BUGS $1 -showcerts -connect $NODEIP:$PORT $PROXY $SNI -$proto -tlsextdebug $npn_params -status") </dev/null 2>$ERRFILE >$TMPFILE
|
||||
$OPENSSL s_client $(s_client_options "$STARTTLS $BUGS $1 -showcerts -connect $NODEIP:$PORT $PROXY $SNI -$proto -tlsextdebug $npn_params -status -msg") </dev/null 2>$ERRFILE >$TMPFILE
|
||||
if sclient_connect_successful $? $TMPFILE; then
|
||||
success=0
|
||||
grep -a 'TLS server extension' $TMPFILE >>$TEMPDIR/tlsext.txt
|
||||
@ -6680,6 +6738,7 @@ get_server_certificate() {
|
||||
esac
|
||||
extract_new_tls_extensions $TMPFILE
|
||||
extract_certificates "$proto"
|
||||
extract_stapled_ocsp
|
||||
success=$?
|
||||
|
||||
tmpfile_handle ${FUNCNAME[0]}.txt
|
||||
@ -6960,10 +7019,11 @@ certificate_info() {
|
||||
local cipher=$4
|
||||
local cert_keysize=$5
|
||||
local cert_type="$6"
|
||||
local ocsp_response=$7
|
||||
local ocsp_response_status=$8
|
||||
local sni_used=$9
|
||||
local ct="${10}"
|
||||
local ocsp_response_binary="$7"
|
||||
local ocsp_response=$8
|
||||
local ocsp_response_status=$9
|
||||
local sni_used="${10}"
|
||||
local ct="${11}"
|
||||
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
|
||||
@ -7636,7 +7696,7 @@ certificate_info() {
|
||||
if [[ $(count_lines "$ocsp_uri") -eq 1 ]]; then
|
||||
out "$ocsp_uri"
|
||||
if [[ "$expfinding" != "expired" ]]; then
|
||||
check_revocation_ocsp "$ocsp_uri" "cert_ocspRevoked${json_postfix}"
|
||||
check_revocation_ocsp "$ocsp_uri" "" "cert_ocspRevoked${json_postfix}"
|
||||
fi
|
||||
ret=$((ret +$?))
|
||||
outln
|
||||
@ -7650,7 +7710,7 @@ certificate_info() {
|
||||
fi
|
||||
out "$line"
|
||||
if [[ "$expfinding" != "expired" ]]; then
|
||||
check_revocation_ocsp "$line" "cert_ocspRevoked${json_postfix}"
|
||||
check_revocation_ocsp "$line" "" "cert_ocspRevoked${json_postfix}"
|
||||
ret=$((ret +$?))
|
||||
fi
|
||||
outln
|
||||
@ -7680,6 +7740,7 @@ certificate_info() {
|
||||
pr_svrty_good "offered"
|
||||
fileout "${jsonID}${json_postfix}" "OK" "offered"
|
||||
provides_stapling=true
|
||||
check_revocation_ocsp "" "$ocsp_response_binary" "cert_ocspRevoked${json_postfix}"
|
||||
else
|
||||
if $GOST_STATUS_PROBLEM; then
|
||||
pr_warning "(GOST servers make problems here, sorry)"
|
||||
@ -7752,7 +7813,7 @@ run_server_defaults() {
|
||||
local -i certs_found=0
|
||||
local -i ret=0
|
||||
local -a previous_hostcert previous_hostcert_txt previous_hostcert_type previous_hostcert_issuer previous_intermediates keysize cipher
|
||||
local -a ocsp_response ocsp_response_status sni_used tls_version ct
|
||||
local -a ocsp_response_binary ocsp_response ocsp_response_status sni_used tls_version ct
|
||||
local -a ciphers_to_test certificate_type
|
||||
local -a -i success
|
||||
local cn_nosni cn_sni sans_nosni sans_sni san tls_extensions
|
||||
@ -7873,6 +7934,7 @@ run_server_defaults() {
|
||||
# If an OCSP response was sent, then get the full
|
||||
# response so that certificate_info() can determine
|
||||
# whether it includes a certificate transparency extension.
|
||||
ocsp_response_binary[certs_found]="$STAPLED_OCSP_RESPONSE"
|
||||
if grep -a "OCSP response:" $TMPFILE | grep -q "no response sent"; then
|
||||
ocsp_response[certs_found]="$(grep -a "OCSP response" $TMPFILE)"
|
||||
else
|
||||
@ -8056,7 +8118,8 @@ run_server_defaults() {
|
||||
echo "${previous_hostcert_issuer[i]}" > $TEMPDIR/hostcert_issuer.pem
|
||||
certificate_info "$i" "$certs_found" "${previous_hostcert_txt[i]}" \
|
||||
"${cipher[i]}" "${keysize[i]}" "${previous_hostcert_type[i]}" \
|
||||
"${ocsp_response[i]}" "${ocsp_response_status[i]}" "${sni_used[i]}" "${ct[i]}"
|
||||
"${ocsp_response_binary[i]}" "${ocsp_response[i]}" \
|
||||
"${ocsp_response_status[i]}" "${sni_used[i]}" "${ct[i]}"
|
||||
[[ $? -ne 0 ]] && ((ret++))
|
||||
done
|
||||
return $ret
|
||||
@ -11034,8 +11097,11 @@ parse_tls_serverhello() {
|
||||
echo " i:${CAissuerDN:8}" >> $TMPFILE
|
||||
echo "$pem_certificate" >> $TMPFILE
|
||||
echo "$pem_certificate" >> "$TEMPDIR/intermediatecerts.pem"
|
||||
if [[ -z "$hostcert_issuer" ]] && [[ $tls_certificate_status_ascii_len -ne 0 ]]; then
|
||||
hostcert_issuer=$(mktemp $TEMPDIR/pem_cert.XXXXXX) || return 1
|
||||
if [[ -z "$hostcert_issuer" ]]; then
|
||||
# The issuer's certificate is needed if there is a stapled OCSP response,
|
||||
# and it may be needed if check_revocation_ocsp() will later be called
|
||||
# with the OCSP URI in the server's certificate.
|
||||
hostcert_issuer="$TEMPDIR/hostcert_issuer.pem"
|
||||
echo "$pem_certificate" > "$hostcert_issuer"
|
||||
fi
|
||||
done
|
||||
@ -11077,15 +11143,16 @@ parse_tls_serverhello() {
|
||||
fi
|
||||
ocsp_resp_offset=14
|
||||
fi
|
||||
STAPLED_OCSP_RESPONSE=""
|
||||
if [[ $ocsp_response_len -ne 0 ]]; then
|
||||
STAPLED_OCSP_RESPONSE="${tls_certificate_status_ascii:ocsp_resp_offset:ocsp_response_len}"
|
||||
echo "OCSP response:" >> $TMPFILE
|
||||
echo "===============================================================================" >> $TMPFILE
|
||||
if [[ -n "$hostcert_issuer" ]]; then
|
||||
asciihex_to_binary_file "${tls_certificate_status_ascii:ocsp_resp_offset:ocsp_response_len}" "/dev/stdout" | \
|
||||
asciihex_to_binary_file "$STAPLED_OCSP_RESPONSE" "/dev/stdout" | \
|
||||
$OPENSSL ocsp -no_nonce -CAfile $TEMPDIR/intermediatecerts.pem -issuer $hostcert_issuer -cert $HOSTCERT -respin /dev/stdin -resp_text >> $TMPFILE 2>$ERRFILE
|
||||
rm "$hostcert_issuer"
|
||||
else
|
||||
asciihex_to_binary_file "${tls_certificate_status_ascii:ocsp_resp_offset:ocsp_response_len}" "/dev/stdout" | \
|
||||
asciihex_to_binary_file "$STAPLED_OCSP_RESPONSE" "/dev/stdout" | \
|
||||
$OPENSSL ocsp -respin /dev/stdin -resp_text >> $TMPFILE 2>$ERRFILE
|
||||
fi
|
||||
echo "===============================================================================" >> $TMPFILE
|
||||
|
Loading…
Reference in New Issue
Block a user