@@ -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