Skip to content

Commit a7bcf9e

Browse files
committed
Further improvements to certificate_info()
* add cn and issuer_CN to the output both on screen and file * the severity rating for intermediates are just a shot (20/40 days) and deserve a second thought * replace the expiry check by one test statement and make grep futile * replace at some places "$openssl x509 -in $filename" by "$openssl x509 <<< $var" * the thing with 25*60*60 was fie readability. When it's used >20 times it maybe is not (and maybe costs to much time) --> replaced by $secsaday * adjusted the loop for bad ocsp check for readability
1 parent 67afa6c commit a7bcf9e

1 file changed

Lines changed: 69 additions & 59 deletions

File tree

testssl.sh

Lines changed: 69 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -8043,7 +8043,7 @@ etsi_ets_visibility_info() {
80438043
# external functions to obtain the DER encoded certficate.
80448044
if [[ "$cert_txt" =~ X509v3\ Subject\ Alternative\ Name:.*othername:\<unsupported\> ]] || \
80458045
[[ "$cert_txt" =~ X509v3\ Subject\ Alternative\ Name:.*othername:\ 0.4.0.3523.3.1 ]]; then
8046-
dercert="$($OPENSSL x509 -in "$cert" -outform DER 2>>$ERRFILE | hexdump -v -e '16/1 "%02X"')"
8046+
dercert="$($OPENSSL x509 -outform DER 2>>$ERRFILE <<< "$cert" | hexdump -v -e '16/1 "%02X"')"
80478047
if [[ "$dercert" =~ 0603551D110101FF04[0-9A-F]*060604009B430301 ]] || \
80488048
[[ "$dercert" =~ 0603551D1104[0-9A-F]*060604009B430301 ]]; then
80498049
# Look for the beginning of the subjectAltName extension. It
@@ -8346,6 +8346,7 @@ determine_dates_certificate() {
83468346
local cert_txt="$1"
83478347
local startdate enddate yearnow y m d yearstart clockstart yearend clockend
83488348
local diffseconds=0 days2expire=0
8349+
local -i secsaday=86400
83498350

83508351
startdate="${cert_txt#*Validity*Not Before: }"
83518352
# FreeBSD + OSX can't swallow the leading blank:
@@ -8371,7 +8372,7 @@ determine_dates_certificate() {
83718372
# We take the year, month, days here as old OpenBSD's date is too difficult for real conversion
83728373
# see comment in parse_date(). In diffseconds then we have the estimated absolute validity period
83738374
diffseconds=$(( d + ((m*30)) + ((y*365)) ))
8374-
diffseconds=$((diffseconds * 3600 * 24))
8375+
diffseconds=$((diffseconds * secsaday))
83758376
# Now we estimate the days left plus length of month/year:
83768377
yearnow="$(date -juz GMT "+%Y-%m-%d %H:%M")"
83778378
y=$(( ${yearend:0:4} - ${yearnow:0:4} ))
@@ -8382,7 +8383,7 @@ determine_dates_certificate() {
83828383
startdate="$(parse_date "$startdate" +"%F %H:%M" "%b %d %T %Y %Z")"
83838384
enddate="$(parse_date "$enddate" +"%F %H:%M" "%b %d %T %Y %Z")"
83848385
days2expire=$(( $(parse_date "$enddate" "+%s" $'%F %H:%M') - $(LC_ALL=C date "+%s") )) # first in seconds
8385-
days2expire=$((days2expire / 3600 / 24 ))
8386+
days2expire=$((days2expire / secsaday))
83868387
diffseconds=$(( $(parse_date "$enddate" "+%s" $'%F %H:%M') - $(parse_date "$startdate" "+%s" $'%F %H:%M') ))
83878388
fi
83888389
safe_echo "$startdate,$enddate,$diffseconds,$days2expire,$yearstart"
@@ -8406,11 +8407,12 @@ certificate_info() {
84068407
local ct="${12}"
84078408
local certificate_list_ordering_problem="${13}"
84088409
local cert_sig_algo cert_sig_hash_algo cert_key_algo cert_spki_info
8410+
local hostcert=""
84098411
local common_primes_file="$TESTSSL_INSTALL_DIR/etc/common-primes.txt"
84108412
local -i lineno_matched=0
84118413
local cert_keyusage cert_ext_keyusage short_keyAlgo
84128414
local outok=true
8413-
local expire days2expire secs2warn ocsp_uri crl
8415+
local days2expire secs2warn ocsp_uri crl
84148416
local startdate enddate issuer_CN issuer_C issuer_O issuer sans san all_san="" cn
84158417
local issuer_DC issuerfinding cn_nosni=""
84168418
local cert_fingerprint_sha1 cert_fingerprint_sha2 cert_serial cert
@@ -8421,7 +8423,7 @@ certificate_info() {
84218423
local has_dns_sans has_dns_sans_nosni
84228424
local trust_sni_finding
84238425
local -i i certificates_provided=0
8424-
local cnfinding trustfinding trustfinding_nosni
8426+
local cn_finding trustfinding trustfinding_nosni
84258427
local cnok="OK"
84268428
local expfinding expok="OK"
84278429
local -i ret=0
@@ -8437,6 +8439,7 @@ certificate_info() {
84378439
local yearstart
84388440
local gt_398=false gt_398warn=false
84398441
local gt_825=false gt_825warn=false
8442+
local -i secsaday=86400
84408443
local first=true
84418444
local badocsp=1
84428445

@@ -8773,20 +8776,22 @@ certificate_info() {
87738776
fileout "${jsonID}${json_postfix}" "INFO" "$cert_ext_keyusage"
87748777
fi
87758778

8779+
hostcert="$(<$HOSTCERT)"
8780+
87768781
out "$indent"; pr_bold " Serial / Fingerprints "
8777-
cert_serial="$(determine_cert_fingerprint_serial "$HOSTCERT" "-serial")"
8782+
cert_serial="$(determine_cert_fingerprint_serial "$hostcert" "-serial")"
87788783
fileout "cert_serialNumber${json_postfix}" "INFO" "$cert_serial"
87798784

8780-
cert_fingerprint_sha1="$(determine_cert_fingerprint_serial "$HOSTCERT" "-fingerprint -sha1")"
8785+
cert_fingerprint_sha1="$(determine_cert_fingerprint_serial "$hostcert" "-fingerprint -sha1")"
87818786
outln "$cert_serial / SHA1 $cert_fingerprint_sha1"
87828787
fileout "cert_fingerprintSHA1${json_postfix}" "INFO" "${cert_fingerprint_sha1}"
87838788

8784-
cert_fingerprint_sha2="$(determine_cert_fingerprint_serial "$HOSTCERT" "-fingerprint -sha256")"
8789+
cert_fingerprint_sha2="$(determine_cert_fingerprint_serial "$hostcert" "-fingerprint -sha256")"
87858790
fileout "cert_fingerprintSHA256${json_postfix}" "INFO" "${cert_fingerprint_sha2}"
87868791
outln "${spaces}SHA256 ${cert_fingerprint_sha2}"
87878792

87888793
# " " needs to be converted back to lf in JSON/CSV output. watch out leading/ending line containting "CERTIFICATE"
8789-
fileout "cert${json_postfix}" "INFO" "$(< $HOSTCERT)"
8794+
fileout "cert${json_postfix}" "INFO" "$hostcert"
87908795

87918796
[[ -z $CERT_FINGERPRINT_SHA2 ]] && \
87928797
CERT_FINGERPRINT_SHA2="$cert_fingerprint_sha2" ||
@@ -8796,19 +8801,19 @@ certificate_info() {
87968801
RSA_CERT_FINGERPRINT_SHA2="$cert_fingerprint_sha2"
87978802

87988803
out "$indent"; pr_bold " Common Name (CN) "
8799-
cnfinding="Common Name (CN) : "
8804+
cn_finding="Common Name (CN) : "
88008805
cn="$(get_cn_from_cert $HOSTCERT)"
88018806
if [[ -n "$cn" ]]; then
88028807
pr_italic "$cn"
8803-
cnfinding="$cn"
8808+
cn_finding="$cn"
88048809
else
88058810
cn="no CN field in subject"
88068811
out "($cn)"
8807-
cnfinding="$cn"
8812+
cn_finding="$cn"
88088813
cnok="INFO"
88098814
fi
8810-
fileout "cert_commonName${json_postfix}" "$cnok" "$cnfinding"
8811-
cnfinding=""
8815+
fileout "cert_commonName${json_postfix}" "$cnok" "$cn_finding"
8816+
cn_finding=""
88128817

88138818
if [[ -n "$sni_used" ]]; then
88148819
if grep -q "\-\-\-\-\-BEGIN" "$HOSTCERT.nosni"; then
@@ -8822,24 +8827,24 @@ certificate_info() {
88228827

88238828
if [[ -z "$sni_used" ]] || [[ "$(toupper "$cn_nosni")" == "$(toupper "$cn")" ]]; then
88248829
outln
8825-
cnfinding="$cn"
8830+
cn_finding="$cn"
88268831
elif [[ -z "$cn_nosni" ]]; then
88278832
out " (request w/o SNI didn't succeed";
8828-
cnfinding+="request w/o SNI didn't succeed"
8833+
cn_finding+="request w/o SNI didn't succeed"
88298834
if [[ $cert_sig_algo =~ ecdsa ]]; then
88308835
out ", usual for EC certificates"
8831-
cnfinding+=", usual for EC certificates"
8836+
cn_finding+=", usual for EC certificates"
88328837
fi
88338838
outln ")"
8834-
cnfinding+=""
8839+
cn_finding+=""
88358840
elif [[ "$cn_nosni" == *"no CN field"* ]]; then
88368841
outln ", (request w/o SNI: $cn_nosni)"
8837-
cnfinding="$cn_nosni"
8842+
cn_finding="$cn_nosni"
88388843
else
88398844
out " (CN in response to request w/o SNI: "; pr_italic "$cn_nosni"; outln ")"
8840-
cnfinding="$cn_nosni"
8845+
cn_finding="$cn_nosni"
88418846
fi
8842-
fileout "cert_commonName_wo_SNI${json_postfix}" "INFO" "$cnfinding"
8847+
fileout "cert_commonName_wo_SNI${json_postfix}" "INFO" "$cn_finding"
88438848

88448849
sans=$(grep -A2 "Subject Alternative Name" <<< "$cert_txt" | \
88458850
grep -E "DNS:|IP Address:|email:|URI:|DirName:|Registered ID:" | tr ',' '\n' | \
@@ -8868,14 +8873,14 @@ certificate_info() {
88688873

88698874
out "$indent"; pr_bold " Issuer "
88708875
jsonID="cert_caIssuers"
8871-
#FIXME: oid would be better maybe (see above)
8872-
issuer="$($OPENSSL x509 -in $HOSTCERT -noout -issuer -nameopt multiline,-align,sname,-esc_msb,utf8,-space_eq 2>>$ERRFILE)"
8876+
#FIXME: oid would be better maybe (see above). And the line by line input could be done w/o awk
8877+
issuer="$($OPENSSL x509 -noout -issuer -nameopt multiline,-align,sname,-esc_msb,utf8,-space_eq 2>>$ERRFILE <<< "$hostcert")"
88738878
issuer_CN="$(awk -F'=' '/CN=/ { print $2 }' <<< "$issuer")"
88748879
issuer_O="$(awk -F'=' '/O=/ { print $2 }' <<< "$issuer")"
88758880
issuer_C="$(awk -F'=' '/ C=/ { print $2 }' <<< "$issuer")"
88768881
issuer_DC="$(awk -F'=' '/DC=/ { print $2 }' <<< "$issuer")"
88778882

8878-
if [[ "$issuer_O" == "issuer=" ]] || [[ "$issuer_O" == "issuer= " ]] || [[ "$issuer_CN" == "$cn" ]]; then
8883+
if [[ "$issuer_O" == issuer= ]] || [[ "$issuer_O" == issuer=\ ]] || [[ "$issuer_CN" == "$cn" ]]; then
88798884
prln_svrty_critical "self-signed (NOT ok)"
88808885
fileout "${jsonID}${json_postfix}" "CRITICAL" "selfsigned"
88818886
set_grade_cap "T" "Self-signed certificate"
@@ -9065,7 +9070,7 @@ certificate_info() {
90659070
out "$indent"; pr_bold " ETS/\"eTLS\""
90669071
out ", visibility info "
90679072
jsonID="cert_eTLS"
9068-
etsi_ets_visibility_info "${jsonID}${json_postfix}" "$spaces" "$HOSTCERT" "$cert_txt"
9073+
etsi_ets_visibility_info "${jsonID}${json_postfix}" "$spaces" "$hostcert" "$cert_txt"
90699074
# *Currently* this is even listed as a vulnerability (CWE-310, CVE-2019-919), see
90709075
# https://nvd.nist.gov/vuln/detail/CVE-2019-9191, https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-9191
90719076
# For now we leave this here. We may want to change that later or add infos to other sections (FS & vulnerability)
@@ -9081,19 +9086,16 @@ certificate_info() {
90819086
fi
90829087

90839088
debugme echo -n "diffseconds: $diffseconds"
9084-
expire=$($OPENSSL x509 -in $HOSTCERT -checkend 1 2>>$ERRFILE)
9085-
if ! grep -qw not <<< "$expire" ; then
9089+
if ! [[ "$($OPENSSL x509 -checkend 1 2>>$ERRFILE <<< "$hostcert")" =~ \ not\ ]]; then
90869090
pr_svrty_critical "expired"
90879091
expfinding="expired"
90889092
expok="CRITICAL"
90899093
set_grade_cap "T" "Certificate expired"
90909094
else
9091-
secs2warn=$((24 * 60 * 60 * days2warn2)) # low threshold first
9092-
expire=$($OPENSSL x509 -in $HOSTCERT -checkend $secs2warn 2>>$ERRFILE)
9093-
if grep -qw not <<< "$expire"; then
9094-
secs2warn=$((24 * 60 * 60 * days2warn1)) # high threshold
9095-
expire=$($OPENSSL x509 -in $HOSTCERT -checkend $secs2warn 2>>$ERRFILE)
9096-
if grep -qw not <<< "$expire"; then
9095+
# low threshold first
9096+
if ! [[ "$($OPENSSL x509 -checkend $((secsaday*days2warn2)) 2>>$ERRFILE <<< "$cert")" =~ \ not\ ]]; then
9097+
# high threshold
9098+
if ! [[ "$($OPENSSL x509 -checkend $((secsaday*days2warn1)) 2>>$ERRFILE <<< "$cert")" =~ \ not\ ]]; then
90979099
pr_svrty_good "$days2expire >= $days2warn1 days"
90989100
expfinding+="$days2expire >= $days2warn1 days"
90999101
else
@@ -9114,15 +9116,15 @@ certificate_info() {
91149116

91159117
# Internal certificates or those from appliances often have too high validity periods.
91169118
# We check for ~10 years and >~ 5 years
9117-
if [[ $diffseconds -ge $((3600 * 24 * 365 * 10)) ]]; then
9119+
if [[ $diffseconds -ge $((secsaday*365*10)) ]]; then
91189120
out "$spaces"
91199121
prln_svrty_high ">= 10 years is way too long"
9120-
fileout "cert_validityPeriod${json_postfix}" "HIGH" "$((diffseconds / (3600 * 24) )) days"
9121-
elif [[ $diffseconds -ge $((3600 * 24 * 365 * 5)) ]]; then
9122+
fileout "cert_validityPeriod${json_postfix}" "HIGH" "$((diffseconds / secsaday)) days"
9123+
elif [[ $diffseconds -ge $((secsaday*365*5)) ]]; then
91229124
out "$spaces"
91239125
prln_svrty_medium ">= 5 years is too long"
9124-
fileout "cert_validityPeriod${json_postfix}" "MEDIUM" "$((diffseconds / (3600 * 24) )) days"
9125-
elif [[ $diffseconds -ge $((3600 * 24 * 398 + 1)) ]]; then
9126+
fileout "cert_validityPeriod${json_postfix}" "MEDIUM" "$((diffseconds / secsaday)) days"
9127+
elif [[ $diffseconds -ge $((secsaday*398 + 1)) ]]; then
91269128
# Also "official" certificates issued from september 1st 2020 (1598918400) aren't supposed
91279129
# to be valid longer than 398 days which is 34387200 in epoch seconds
91289130
gt_398=true
@@ -9137,12 +9139,12 @@ certificate_info() {
91379139
out "$spaces"
91389140
if "$gt_398warn" && "$gt_398"; then
91399141
prln_svrty_medium "> 398 days issued after 2020/09/01 is too long"
9140-
fileout "cert_validityPeriod${json_postfix}" "MEDIUM" "$((diffseconds / (3600 * 24) )) > 398 days"
9142+
fileout "cert_validityPeriod${json_postfix}" "MEDIUM" "$((diffseconds / secsaday)) > 398 days"
91419143
elif "$gt_398"; then
91429144
outln ">= 398 days certificate life time but issued before 2020/09/01"
9143-
fileout "cert_validityPeriod${json_postfix}" "INFO" "$((diffseconds / (3600 * 24) )) =< 398 days"
9145+
fileout "cert_validityPeriod${json_postfix}" "INFO" "$((diffseconds / secsaday)) =< 398 days"
91449146
fi
9145-
elif [[ $diffseconds -ge $((3600 * 24 * 825 + 1)) ]]; then
9147+
elif [[ $diffseconds -ge $((secsaday*825 + 1)) ]]; then
91469148
# Also "official" certificates issued from March 1st, 2018 (1517353200) aren't supposed
91479149
# to be valid longer than 825 days which is 1517353200 in epoch seconds
91489150
gt_825=true
@@ -9157,10 +9159,10 @@ certificate_info() {
91579159
out "$spaces"
91589160
if "$gt_825warn" && "$gt_825"; then
91599161
prln_svrty_medium "> 825 days issued after 2018/03/01 is too long"
9160-
fileout "cert_validityPeriod${json_postfix}" "MEDIUM" "$((diffseconds / (3600 * 24) )) > 825 days"
9162+
fileout "cert_validityPeriod${json_postfix}" "MEDIUM" "$((diffseconds / secsaday)) > 825 days"
91619163
elif "$gt_825"; then
91629164
outln ">= 825 days certificate life time but issued before 2018/03/01"
9163-
fileout "cert_validityPeriod${json_postfix}" "INFO" "$((diffseconds / (3600 * 24) )) =< 825 days"
9165+
fileout "cert_validityPeriod${json_postfix}" "INFO" "$((diffseconds / secsaday)) =< 825 days"
91649166
fi
91659167
else
91669168
# All is fine with valididy period
@@ -9229,7 +9231,7 @@ certificate_info() {
92299231

92309232
out "$indent"; pr_bold " OCSP URI "
92319233
jsonID="cert_ocspURL"
9232-
ocsp_uri=$($OPENSSL x509 -in $HOSTCERT -noout -ocsp_uri 2>>$ERRFILE)
9234+
ocsp_uri="$($OPENSSL x509 -noout -ocsp_uri 2>>$ERRFILE <<< "$hostcert")"
92339235
if [[ -z "$ocsp_uri" ]]; then
92349236
outln "--"
92359237
fileout "${jsonID}${json_postfix}" "INFO" "--"
@@ -9353,9 +9355,7 @@ certificate_info() {
93539355
# We should keep in mind though this is somewhat redundant code. We do similar stuff elsewhere,
93549356
# e.g. in extract_certificates() and run_hpkp() but don't keep the certificates
93559357

9356-
#FIXME: output
9357-
# intermediate CN / (what about issuer. moving it?)
9358-
# fix the numbering schem of certificates_provided below
9358+
#FIXME: the numbering scheme of certificates_provided below: we start @ 0 and always add 1. Careful with Intermediate Bad OCSP
93599359

93609360
# Store all of the text output of the intermediate certificates in an array so that they can
93619361
# be used later (e.g., to check their expiration dates).
@@ -9367,9 +9367,7 @@ certificate_info() {
93679367
intermediates="${intermediates#${cert}-----END CERTIFICATE-----}"
93689368
cert="-----BEGIN CERTIFICATE-----${cert}-----END CERTIFICATE-----"
93699369

9370-
# we count as humans in the file output here. This needs later to be adjusted in the code
93719370
fileout "intermediate_cert <#$((certificates_provided + 1))>${json_postfix}" "INFO" "$cert"
9372-
93739371
fileout "intermediate_cert_fingerprintSHA256 <#$((certificates_provided + 1))>${json_postfix}" "INFO" "$(determine_cert_fingerprint_serial "$cert" "-fingerprint -sha256")"
93749372

93759373
intermediate_certs_txt[certificates_provided]="$($OPENSSL x509 -text -noout 2>/dev/null <<< "$cert")"
@@ -9384,18 +9382,31 @@ certificate_info() {
93849382
else
93859383
out "$indent$spaces"
93869384
fi
9387-
if ! $OPENSSL x509 -checkend $((24*3600*20)) 2>>$ERRFILE <<< "$cert" | grep -qw not; then
9388-
out "#$((certificates_provided+1)): less then "; pr_svrty_high "20 days"
9389-
outln " at $enddate"
9385+
out "#$((certificates_provided+1)): "
9386+
if ! [[ "$($OPENSSL x509 -checkend 1 2>>$ERRFILE <<< "$cert")" =~ \ not\ ]]; then
9387+
cn_finding="expired!"
9388+
pr_svrty_critical "$cn_finding"
9389+
expok="CRITICAL"
9390+
elif ! [[ "$($OPENSSL x509 -checkend $((secsaday*20)) 2>>$ERRFILE <<< "$cert")" =~ \ not\ ]]; then
9391+
cn_finding="expires <= 20 days"
9392+
pr_svrty_high "$cn_finding"
93909393
expok="HIGH"
9391-
elif ! $OPENSSL x509 -checkend $((24*3600*40)) 2>>$ERRFILE <<< "$cert" | grep -qw not; then
9392-
out "#$((certificates_provided+1)): less then "; pr_svrty_medium "40 days"
9393-
outln " at $enddate"
9394+
elif ! [[ "$($OPENSSL x509 -checkend $((secsaday*40)) 2>>$ERRFILE <<< "$cert")" =~ \ not\ ]]; then
9395+
cn_finding="expires <= 40 days"
9396+
pr_svrty_medium "$cn_finding"
93949397
expok="MEDIUM"
93959398
else
9396-
outln "#$((certificates_provided+1)): longer than 40 days ($enddate)"
9397-
fi
9399+
cn_finding="valid > 40 days"
9400+
pr_svrty_good "$cn_finding"
9401+
expok="OK"
9402+
fi
9403+
out " ($enddate). "
9404+
cn="$(awk -F= '/Subject:.*CN/ { print $NF }' <<< "${intermediate_certs_txt[certificates_provided]}")"
9405+
issuer_CN="$(awk -F= '/Issuer:.*CN/ { print $NF }' <<< "${intermediate_certs_txt[certificates_provided]}")"
9406+
pr_italic "$cn"; out " <-- "; prln_italic "$issuer_CN"
93989407
fileout "intermediate_cert_notAfter <#$((certificates_provided + 1))>${json_postfix}" "$expok" "$enddate"
9408+
fileout "intermediate_cert_expiration <#$((certificates_provided + 1))>${json_postfix}" "$expok" "$cn_finding"
9409+
fileout "intermediate_cert_chain <#$((certificates_provided + 1))>${json_postfix}" "INFO" "$cn <-- $issuer_CN"
93999410
certificates_provided+=1
94009411
done
94019412

@@ -9404,8 +9415,7 @@ certificate_info() {
94049415
out " (exp.) "
94059416
jsonID="intermediate_cert_badOCSP"
94069417

9407-
certificates_provided+=1
9408-
for (( i=0; i < certificates_provided-1; i++ )); do
9418+
for (( i=1; i < certificates_provided; i++ )); do
94099419
cert_ext_keyusage="$(awk '/X509v3 Extended Key Usage:/ { getline; print $0 }' <<< "${intermediate_certs_txt[i]}")"
94109420
[[ "$cert_ext_keyusage" =~ OCSP\ Signing ]] && badocsp=0 && break
94119421
done

0 commit comments

Comments
 (0)