mirror of
https://github.com/drwetter/testssl.sh.git
synced 2025-01-31 04:41:15 +01:00
Further improvements to intermediate certs
* reorder sequence of checks in certificate info so that the chain relevant points are closer together * determine_cert_fingerprint_serial() doesn't need fil input anymore, thus removed that part * cert_validityPeriod in JSON/CSV may lead to misunderstandings, thus renamed to cert_extlifeSpan * reorganized loop for the intermediate certificate checks, so that also i is used and not the variable which defines the number of certificates, i.e. certificates_provided. In addition made the counting more hiuma friendly, which starts now at 1 instead of 0
This commit is contained in:
parent
a7bcf9ec7f
commit
d5a64ff4b6
99
testssl.sh
99
testssl.sh
@ -8320,16 +8320,11 @@ certificate_transparency() {
|
|||||||
# and $OPENSSL x509 -noout -in $HOSTCERT -fingerprint -sha256/-sha1
|
# and $OPENSSL x509 -noout -in $HOSTCERT -fingerprint -sha256/-sha1
|
||||||
#
|
#
|
||||||
determine_cert_fingerprint_serial() {
|
determine_cert_fingerprint_serial() {
|
||||||
local cert_file="$1"
|
local cert="$1"
|
||||||
local ossl_command="$2"
|
local ossl_command="$2"
|
||||||
local result=""
|
local result=""
|
||||||
|
|
||||||
if [[ -r "$cert_file" ]]; then
|
result="$($OPENSSL x509 -noout $ossl_command 2>>$ERRFILE <<< "$cert")"
|
||||||
result="$($OPENSSL x509 -noout -in $cert_file $ossl_command 2>>$ERRFILE)"
|
|
||||||
else
|
|
||||||
# not really a file but the variable which holds the certificate
|
|
||||||
result="$($OPENSSL x509 -noout $ossl_command 2>>$ERRFILE <<< "$cert_file")"
|
|
||||||
fi
|
|
||||||
# remove strings in text output, colon only appear in fingerprints
|
# remove strings in text output, colon only appear in fingerprints
|
||||||
result="${result//Fingerprint=}"
|
result="${result//Fingerprint=}"
|
||||||
result="${result//serial=}"
|
result="${result//serial=}"
|
||||||
@ -9067,14 +9062,6 @@ certificate_info() {
|
|||||||
# https://certs.opera.com/03/ev-oids.xml
|
# https://certs.opera.com/03/ev-oids.xml
|
||||||
# see #967
|
# see #967
|
||||||
|
|
||||||
out "$indent"; pr_bold " ETS/\"eTLS\""
|
|
||||||
out ", visibility info "
|
|
||||||
jsonID="cert_eTLS"
|
|
||||||
etsi_ets_visibility_info "${jsonID}${json_postfix}" "$spaces" "$hostcert" "$cert_txt"
|
|
||||||
# *Currently* this is even listed as a vulnerability (CWE-310, CVE-2019-919), see
|
|
||||||
# https://nvd.nist.gov/vuln/detail/CVE-2019-9191, https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-9191
|
|
||||||
# For now we leave this here. We may want to change that later or add infos to other sections (FS & vulnerability)
|
|
||||||
|
|
||||||
out "$indent"; pr_bold " Certificate Validity (UTC) "
|
out "$indent"; pr_bold " Certificate Validity (UTC) "
|
||||||
IFS=',' read -r startdate enddate diffseconds days2expire yearstart < <(determine_dates_certificate "$cert_txt")
|
IFS=',' read -r startdate enddate diffseconds days2expire yearstart < <(determine_dates_certificate "$cert_txt")
|
||||||
|
|
||||||
@ -9119,11 +9106,11 @@ certificate_info() {
|
|||||||
if [[ $diffseconds -ge $((secsaday*365*10)) ]]; then
|
if [[ $diffseconds -ge $((secsaday*365*10)) ]]; then
|
||||||
out "$spaces"
|
out "$spaces"
|
||||||
prln_svrty_high ">= 10 years is way too long"
|
prln_svrty_high ">= 10 years is way too long"
|
||||||
fileout "cert_validityPeriod${json_postfix}" "HIGH" "$((diffseconds / secsaday)) days"
|
fileout "cert_extlifeSpan${json_postfix}" "HIGH" "$((diffseconds / secsaday)) days"
|
||||||
elif [[ $diffseconds -ge $((secsaday*365*5)) ]]; then
|
elif [[ $diffseconds -ge $((secsaday*365*5)) ]]; then
|
||||||
out "$spaces"
|
out "$spaces"
|
||||||
prln_svrty_medium ">= 5 years is too long"
|
prln_svrty_medium ">= 5 years is too long"
|
||||||
fileout "cert_validityPeriod${json_postfix}" "MEDIUM" "$((diffseconds / secsaday)) days"
|
fileout "cert_extlifeSpan${json_postfix}" "MEDIUM" "$((diffseconds / secsaday)) days"
|
||||||
elif [[ $diffseconds -ge $((secsaday*398 + 1)) ]]; then
|
elif [[ $diffseconds -ge $((secsaday*398 + 1)) ]]; then
|
||||||
# Also "official" certificates issued from september 1st 2020 (1598918400) aren't supposed
|
# Also "official" certificates issued from september 1st 2020 (1598918400) aren't supposed
|
||||||
# to be valid longer than 398 days which is 34387200 in epoch seconds
|
# to be valid longer than 398 days which is 34387200 in epoch seconds
|
||||||
@ -9139,10 +9126,10 @@ certificate_info() {
|
|||||||
out "$spaces"
|
out "$spaces"
|
||||||
if "$gt_398warn" && "$gt_398"; then
|
if "$gt_398warn" && "$gt_398"; then
|
||||||
prln_svrty_medium "> 398 days issued after 2020/09/01 is too long"
|
prln_svrty_medium "> 398 days issued after 2020/09/01 is too long"
|
||||||
fileout "cert_validityPeriod${json_postfix}" "MEDIUM" "$((diffseconds / secsaday)) > 398 days"
|
fileout "cert_extlifeSpan${json_postfix}" "MEDIUM" "$((diffseconds / secsaday)) > 398 days"
|
||||||
elif "$gt_398"; then
|
elif "$gt_398"; then
|
||||||
outln ">= 398 days certificate life time but issued before 2020/09/01"
|
outln ">= 398 days certificate life time but issued before 2020/09/01"
|
||||||
fileout "cert_validityPeriod${json_postfix}" "INFO" "$((diffseconds / secsaday)) =< 398 days"
|
fileout "cert_extlifeSpan${json_postfix}" "INFO" "$((diffseconds / secsaday)) =< 398 days"
|
||||||
fi
|
fi
|
||||||
elif [[ $diffseconds -ge $((secsaday*825 + 1)) ]]; then
|
elif [[ $diffseconds -ge $((secsaday*825 + 1)) ]]; then
|
||||||
# Also "official" certificates issued from March 1st, 2018 (1517353200) aren't supposed
|
# Also "official" certificates issued from March 1st, 2018 (1517353200) aren't supposed
|
||||||
@ -9159,30 +9146,25 @@ certificate_info() {
|
|||||||
out "$spaces"
|
out "$spaces"
|
||||||
if "$gt_825warn" && "$gt_825"; then
|
if "$gt_825warn" && "$gt_825"; then
|
||||||
prln_svrty_medium "> 825 days issued after 2018/03/01 is too long"
|
prln_svrty_medium "> 825 days issued after 2018/03/01 is too long"
|
||||||
fileout "cert_validityPeriod${json_postfix}" "MEDIUM" "$((diffseconds / secsaday)) > 825 days"
|
fileout "cert_extlifeSpan${json_postfix}" "MEDIUM" "$((diffseconds / secsaday)) > 825 days"
|
||||||
elif "$gt_825"; then
|
elif "$gt_825"; then
|
||||||
outln ">= 825 days certificate life time but issued before 2018/03/01"
|
outln ">= 825 days certificate life time but issued before 2018/03/01"
|
||||||
fileout "cert_validityPeriod${json_postfix}" "INFO" "$((diffseconds / secsaday)) =< 825 days"
|
fileout "cert_extlifeSpan${json_postfix}" "INFO" "$((diffseconds / secsaday)) =< 825 days"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
# All is fine with valididy period
|
# All is fine with validity period
|
||||||
# We ignore for now certificates < 2018/03/01. On the screen we only show debug info
|
# We ignore for now certificates < 2018/03/01. On the screen we only show debug info
|
||||||
[[ "$DEBUG" -ge 1 ]] && outln "${spaces}DEBUG: all is fine with total certificate life time"
|
debugme1 outln "${spaces}DEBUG: all is fine with total certificate life time"
|
||||||
fileout "cert_validityPeriod${json_postfix}" "INFO" "No finding"
|
fileout "cert_extlifeSpan${json_postfix}" "OK" "certificate has no extended life time according to browser forum"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
out "$indent"; pr_bold " Certificates provided"
|
out "$indent"; pr_bold " ETS/\"eTLS\""
|
||||||
certificates_provided="$(grep -ac '\-\-\-\-\-BEGIN\ CERTIFICATE\-\-\-\-\-' <<< "$intermediates")"
|
out ", visibility info "
|
||||||
((certificates_provided++)) # plus host certificate
|
jsonID="cert_eTLS"
|
||||||
out " $certificates_provided"
|
etsi_ets_visibility_info "${jsonID}${json_postfix}" "$spaces" "$hostcert" "$cert_txt"
|
||||||
fileout "certs_countServer${json_postfix}" "INFO" "${certificates_provided}"
|
# *Currently* this is even listed as a vulnerability (CWE-310, CVE-2019-919), see
|
||||||
if "$certificate_list_ordering_problem"; then
|
# https://nvd.nist.gov/vuln/detail/CVE-2019-9191, https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-9191
|
||||||
prln_svrty_low " (certificate list ordering problem)"
|
# For now we leave this here. We may want to change that later or add infos to other sections (FS & vulnerability)
|
||||||
fileout "certs_list_ordering_problem${json_postfix}" "LOW" "yes"
|
|
||||||
else
|
|
||||||
fileout "certs_list_ordering_problem${json_postfix}" "INFO" "no"
|
|
||||||
outln
|
|
||||||
fi
|
|
||||||
|
|
||||||
if "$PHONE_OUT"; then
|
if "$PHONE_OUT"; then
|
||||||
out "$indent"; pr_bold " In pwnedkeys.com DB "
|
out "$indent"; pr_bold " In pwnedkeys.com DB "
|
||||||
@ -9349,32 +9331,42 @@ certificate_info() {
|
|||||||
fileout "${jsonID}${json_postfix}" "INFO" "$ct"
|
fileout "${jsonID}${json_postfix}" "INFO" "$ct"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
out "$indent"; pr_bold " Certificates provided"
|
||||||
|
certificates_provided="$(grep -ac '\-\-\-\-\-BEGIN\ CERTIFICATE\-\-\-\-\-' <<< "$intermediates")"
|
||||||
|
((certificates_provided++)) # plus host certificate
|
||||||
|
out " $certificates_provided"
|
||||||
|
fileout "certs_countServer${json_postfix}" "INFO" "${certificates_provided}"
|
||||||
|
if "$certificate_list_ordering_problem"; then
|
||||||
|
prln_svrty_low " (certificate list ordering problem)"
|
||||||
|
fileout "certs_list_ordering_problem${json_postfix}" "LOW" "yes"
|
||||||
|
else
|
||||||
|
fileout "certs_list_ordering_problem${json_postfix}" "INFO" "no"
|
||||||
|
outln
|
||||||
|
fi
|
||||||
|
|
||||||
# Now we take care of the intermediate certificates. We basically (should) have them on disk
|
# Now we take care of the intermediate certificates. We basically (should) have them on disk
|
||||||
# as "intermediatecerts.pem" (which could be split into intermediatecert1.crt, intermediatecert2.crt, ..)
|
# as "intermediatecerts.pem" (which could be split into intermediatecert1.crt, intermediatecert2.crt, ..)
|
||||||
# However we do this in RAM which is better as it was passed to this function.
|
# However we do this in RAM which is better as it was passed to this function.
|
||||||
# We should keep in mind though this is somewhat redundant code. We do similar stuff elsewhere,
|
# We should keep in mind though this is somewhat redundant code. We do similar stuff elsewhere,
|
||||||
# e.g. in extract_certificates() and run_hpkp() but don't keep the certificates
|
# e.g. in extract_certificates() and run_hpkp() but don't keep the certificates
|
||||||
|
|
||||||
#FIXME: the numbering scheme of certificates_provided below: we start @ 0 and always add 1. Careful with Intermediate Bad OCSP
|
|
||||||
|
|
||||||
# Store all of the text output of the intermediate certificates in an array so that they can
|
# Store all of the text output of the intermediate certificates in an array so that they can
|
||||||
# be used later (e.g., to check their expiration dates).
|
# be used later (e.g., to check their expiration dates).
|
||||||
certificates_provided=0
|
for (( i=1; i < certificates_provided; i++ )); do
|
||||||
while true; do
|
|
||||||
[[ "$intermediates" =~ \-\-\-\-\-BEGIN\ CERTIFICATE\-\-\-\-\- ]] || break
|
[[ "$intermediates" =~ \-\-\-\-\-BEGIN\ CERTIFICATE\-\-\-\-\- ]] || break
|
||||||
intermediates="${intermediates#*-----BEGIN CERTIFICATE-----}"
|
intermediates="${intermediates#*-----BEGIN CERTIFICATE-----}"
|
||||||
cert="${intermediates%%-----END CERTIFICATE-----*}"
|
cert="${intermediates%%-----END CERTIFICATE-----*}"
|
||||||
intermediates="${intermediates#${cert}-----END CERTIFICATE-----}"
|
intermediates="${intermediates#${cert}-----END CERTIFICATE-----}"
|
||||||
cert="-----BEGIN CERTIFICATE-----${cert}-----END CERTIFICATE-----"
|
cert="-----BEGIN CERTIFICATE-----${cert}-----END CERTIFICATE-----"
|
||||||
|
|
||||||
fileout "intermediate_cert <#$((certificates_provided + 1))>${json_postfix}" "INFO" "$cert"
|
fileout "intermediate_cert <#${i}>${json_postfix}" "INFO" "$cert"
|
||||||
fileout "intermediate_cert_fingerprintSHA256 <#$((certificates_provided + 1))>${json_postfix}" "INFO" "$(determine_cert_fingerprint_serial "$cert" "-fingerprint -sha256")"
|
fileout "intermediate_cert_fingerprintSHA256 <#${i}>${json_postfix}" "INFO" "$(determine_cert_fingerprint_serial "$cert" "-fingerprint -sha256")"
|
||||||
|
|
||||||
intermediate_certs_txt[certificates_provided]="$($OPENSSL x509 -text -noout 2>/dev/null <<< "$cert")"
|
intermediate_certs_txt[i]="$($OPENSSL x509 -text -noout 2>/dev/null <<< "$cert")"
|
||||||
|
|
||||||
# We don't need every value here. For the sake of being consistent here we add the rest
|
# We don't need every value here. For the sake of being consistent here we add the rest
|
||||||
IFS=',' read -r startdate enddate diffseconds days2expire yearstart < <(determine_dates_certificate "${intermediate_certs_txt[certificates_provided]}")
|
IFS=',' read -r startdate enddate diffseconds days2expire yearstart < <(determine_dates_certificate "${intermediate_certs_txt[i]}")
|
||||||
fileout "intermediate_cert_notBefore <#$((certificates_provided + 1))>${json_postfix}" "INFO" "$startdate"
|
fileout "intermediate_cert_notBefore <#${i}>${json_postfix}" "INFO" "$startdate"
|
||||||
|
|
||||||
if $first; then
|
if $first; then
|
||||||
out "$indent"; pr_bold " Intermediate cert validity "
|
out "$indent"; pr_bold " Intermediate cert validity "
|
||||||
@ -9382,7 +9374,7 @@ certificate_info() {
|
|||||||
else
|
else
|
||||||
out "$indent$spaces"
|
out "$indent$spaces"
|
||||||
fi
|
fi
|
||||||
out "#$((certificates_provided+1)): "
|
out "#${i}: "
|
||||||
if ! [[ "$($OPENSSL x509 -checkend 1 2>>$ERRFILE <<< "$cert")" =~ \ not\ ]]; then
|
if ! [[ "$($OPENSSL x509 -checkend 1 2>>$ERRFILE <<< "$cert")" =~ \ not\ ]]; then
|
||||||
cn_finding="expired!"
|
cn_finding="expired!"
|
||||||
pr_svrty_critical "$cn_finding"
|
pr_svrty_critical "$cn_finding"
|
||||||
@ -9401,13 +9393,12 @@ certificate_info() {
|
|||||||
expok="OK"
|
expok="OK"
|
||||||
fi
|
fi
|
||||||
out " ($enddate). "
|
out " ($enddate). "
|
||||||
cn="$(awk -F= '/Subject:.*CN/ { print $NF }' <<< "${intermediate_certs_txt[certificates_provided]}")"
|
cn="$(awk -F= '/Subject:.*CN/ { print $NF }' <<< "${intermediate_certs_txt[i]}")"
|
||||||
issuer_CN="$(awk -F= '/Issuer:.*CN/ { print $NF }' <<< "${intermediate_certs_txt[certificates_provided]}")"
|
issuer_CN="$(awk -F= '/Issuer:.*CN/ { print $NF }' <<< "${intermediate_certs_txt[i]}")"
|
||||||
pr_italic "$cn"; out " <-- "; prln_italic "$issuer_CN"
|
pr_italic "$cn"; out " <-- "; prln_italic "$issuer_CN"
|
||||||
fileout "intermediate_cert_notAfter <#$((certificates_provided + 1))>${json_postfix}" "$expok" "$enddate"
|
fileout "intermediate_cert_notAfter <#${i}>${json_postfix}" "$expok" "$enddate"
|
||||||
fileout "intermediate_cert_expiration <#$((certificates_provided + 1))>${json_postfix}" "$expok" "$cn_finding"
|
fileout "intermediate_cert_expiration <#${i}>${json_postfix}" "$expok" "$cn_finding"
|
||||||
fileout "intermediate_cert_chain <#$((certificates_provided + 1))>${json_postfix}" "INFO" "$cn <-- $issuer_CN"
|
fileout "intermediate_cert_chain <#${i}>${json_postfix}" "INFO" "$cn <-- $issuer_CN"
|
||||||
certificates_provided+=1
|
|
||||||
done
|
done
|
||||||
|
|
||||||
# Courtesy Hanno Böck (see https://github.com/hannob/badocspcert)
|
# Courtesy Hanno Böck (see https://github.com/hannob/badocspcert)
|
||||||
@ -9419,11 +9410,9 @@ certificate_info() {
|
|||||||
cert_ext_keyusage="$(awk '/X509v3 Extended Key Usage:/ { getline; print $0 }' <<< "${intermediate_certs_txt[i]}")"
|
cert_ext_keyusage="$(awk '/X509v3 Extended Key Usage:/ { getline; print $0 }' <<< "${intermediate_certs_txt[i]}")"
|
||||||
[[ "$cert_ext_keyusage" =~ OCSP\ Signing ]] && badocsp=0 && break
|
[[ "$cert_ext_keyusage" =~ OCSP\ Signing ]] && badocsp=0 && break
|
||||||
done
|
done
|
||||||
|
|
||||||
#FIXME: We only raise the flag saying the chain is bad w/o naming the intermediate cert to blame.
|
|
||||||
if [[ $badocsp -eq 0 ]]; then
|
if [[ $badocsp -eq 0 ]]; then
|
||||||
prln_svrty_medium "NOT ok"
|
prln_svrty_medium "NOT ok"
|
||||||
fileout "${jsonID}${json_postfix}" "MEDIUM" "NOT ok is/are intermediate certificate(s)"
|
fileout "${jsonID}${json_postfix}" "MEDIUM" "NOT ok is intermediate certificate ${i}"
|
||||||
else
|
else
|
||||||
prln_svrty_good "Ok"
|
prln_svrty_good "Ok"
|
||||||
fileout "${jsonID}${json_postfix}" "OK" "intermediate certificate(s) is/are ok"
|
fileout "${jsonID}${json_postfix}" "OK" "intermediate certificate(s) is/are ok"
|
||||||
|
Loading…
Reference in New Issue
Block a user