From f0c9875696b52fd6d52263e792a7db05c3068c6b Mon Sep 17 00:00:00 2001 From: David Cooper Date: Fri, 19 Jan 2018 11:31:45 -0500 Subject: [PATCH 1/2] Check keyUsage and extended key usage extensions This commit prints the contents of the keyUsage and extended key usage extensions in certificates and checks the public keys in the certificates are not being used in a manner that is inconsistent with these extensions. --- testssl.sh | 56 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 47 insertions(+), 9 deletions(-) diff --git a/testssl.sh b/testssl.sh index c955fe4..e56f4c4 100755 --- a/testssl.sh +++ b/testssl.sh @@ -6346,11 +6346,12 @@ certificate_info() { local -i number_of_certificates=$2 local cipher=$3 local cert_keysize=$4 - local ocsp_response=$5 - local ocsp_response_status=$6 - local sni_used=$7 - local ct="$8" - local cert_sig_algo cert_sig_hash_algo cert_key_algo + local cert_type="$5" + local ocsp_response=$6 + local ocsp_response_status=$7 + local sni_used=$8 + local ct="$9" + local cert_sig_algo cert_sig_hash_algo cert_key_algo cert_keyusage cert_ext_keyusage local expire days2expire secs2warn ocsp_uri crl local startdate enddate issuer_CN issuer_C issuer_O issuer sans san all_san="" cn local issuer_DC issuerfinding cn_nosni="" @@ -6568,6 +6569,36 @@ certificate_info() { fi fi + out "$indent"; pr_bold " Server key usage "; + cert_keyusage=$($OPENSSL x509 -text -noout -in $HOSTCERT 2>>$ERRFILE | grep -A 1 "X509v3 Key Usage:" | tail -n +2 | sed 's/^[ \t]*//') + if [[ -n "$cert_keyusage" ]]; then + outln "$cert_keyusage" + if ( [[ " $cert_type " =~ " RSASig " ]] || [[ " $cert_type " =~ " DSA " ]] || [[ " $cert_type " =~ " ECDSA " ]] ) && \ + [[ ! "$cert_keyusage" =~ "Digital Signature" ]]; then + prln_svrty_high "$indent -- certificate incorrectly used for digital signatures" + fi + if [[ " $cert_type " =~ " RSAKMK " ]] && [[ ! "$cert_keyusage" =~ "Key Encipherment" ]]; then + prln_svrty_high "$indent -- certificate incorrectly used for key encipherment" + fi + if ( [[ " $cert_type " =~ " DH " ]] || [[ " $cert_type " =~ " ECDH " ]] ) && \ + [[ ! "$cert_keyusage" =~ "Key Agreement" ]]; then + prln_svrty_high "$indent -- certificate incorrectly used for key agreement" + fi + else + outln "(absent)" + fi + + out "$indent"; pr_bold " Server extended key usage "; + cert_ext_keyusage="$($OPENSSL x509 -noout -text -in $HOSTCERT 2>>$ERRFILE | grep -A 1 "X509v3 Extended Key Usage: " | tail -1 | sed 's/^[ \t]*//')" + if [[ -n "$cert_ext_keyusage" ]]; then + outln "$cert_ext_keyusage" + if [[ ! "$cert_ext_keyusage" =~ "TLS Web Server Authentication" ]] && [[ ! "$cert_ext_keyusage" =~ "Any Extended Key Usage" ]]; then + prln_svrty_high "$indent -- certificate incorrectly used for TLS Web Server Authentication" + fi + else + outln "(absent)" + fi + out "$indent"; pr_bold " Fingerprint / Serial " cert_fingerprint_sha1="$($OPENSSL x509 -noout -in $HOSTCERT -fingerprint -sha1 2>>$ERRFILE | sed 's/Fingerprint=//' | sed 's/://g')" cert_fingerprint_serial="$($OPENSSL x509 -noout -in $HOSTCERT -serial 2>>$ERRFILE | sed 's/serial=//')" @@ -7005,9 +7036,9 @@ run_server_defaults() { local sessticket_lifetime_hint="" lifetime unit local -i i n local -i certs_found=0 - local -a previous_hostcert previous_intermediates keysize cipher + local -a previous_hostcert previous_hostcert_type previous_intermediates keysize cipher local -a ocsp_response ocsp_response_status sni_used tls_version ct - local -a ciphers_to_test + local -a ciphers_to_test certificate_type local -a -i success local cn_nosni cn_sni sans_nosni sans_sni san tls_extensions @@ -7035,6 +7066,10 @@ run_server_defaults() { ciphers_to_test[5]="aECDH" ciphers_to_test[6]="aECDSA" ciphers_to_test[7]="aGOST" + certificate_type[1]="RSASig" ; certificate_type[2]="RSAKMK" + certificate_type[3]="DSA"; certificate_type[4]="DH" + certificate_type[5]="ECDH" ; certificate_type[6]="ECDSA" + certificate_type[7]="GOST" for (( n=1; n <= 14 ; n++ )); do # Some servers use a different certificate if the ClientHello @@ -7043,7 +7078,7 @@ run_server_defaults() { # try again, but only with TLSv1.1 and without SNI. if [[ $n -ge 8 ]]; then ciphers_to_test[n]="" - [[ ${success[n-7]} -eq 0 ]] && ciphers_to_test[n]="${ciphers_to_test[n-7]}" + [[ ${success[n-7]} -eq 0 ]] && ciphers_to_test[n]="${ciphers_to_test[n-7]}" && certificate_type[n]="${certificate_type[n-7]}" fi if [[ -n "${ciphers_to_test[n]}" ]] && [[ $(count_ciphers $($OPENSSL ciphers "${ciphers_to_test[n]}" 2>>$ERRFILE)) -ge 1 ]]; then @@ -7129,6 +7164,9 @@ run_server_defaults() { previous_intermediates[certs_found]=$(cat $TEMPDIR/intermediatecerts.pem) [[ $n -ge 8 ]] && sni_used[certs_found]="" || sni_used[certs_found]="$SNI" tls_version[certs_found]="$DETECTED_TLS_VERSION" + previous_hostcert_type[certs_found]=" ${certificate_type[n]}" + else + previous_hostcert_type[i]+=" ${certificate_type[n]}" fi fi fi @@ -7260,7 +7298,7 @@ run_server_defaults() { for (( i=1; i <= certs_found; i++ )); do echo "${previous_hostcert[i]}" > $HOSTCERT echo "${previous_intermediates[i]}" > $TEMPDIR/intermediatecerts.pem - certificate_info "$i" "$certs_found" "${cipher[i]}" "${keysize[i]}" "${ocsp_response[i]}" "${ocsp_response_status[i]}" "${sni_used[i]}" "${ct[i]}" + certificate_info "$i" "$certs_found" "${cipher[i]}" "${keysize[i]}" "${previous_hostcert_type[i]}" "${ocsp_response[i]}" "${ocsp_response_status[i]}" "${sni_used[i]}" "${ct[i]}" done } From f5c2199369d53a8cda10657ede361c9bf097856e Mon Sep 17 00:00:00 2001 From: Dirk Date: Mon, 22 Jan 2018 19:50:50 +0100 Subject: [PATCH 2/2] Polishing #965 Add fileout() to #965. This commit also contains a change which needs to be commited before: separation of ``json_prefix`` from ``json_postfix``. Open issue: sed in openssl x509 statments look GNUish ([ \t]). Needs clarification. --- testssl.sh | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/testssl.sh b/testssl.sh index e56f4c4..4500863 100755 --- a/testssl.sh +++ b/testssl.sh @@ -6352,6 +6352,7 @@ certificate_info() { local sni_used=$8 local ct="$9" 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 local startdate enddate issuer_CN issuer_C issuer_O issuer sans san all_san="" cn local issuer_DC issuerfinding cn_nosni="" @@ -6570,33 +6571,55 @@ certificate_info() { fi out "$indent"; pr_bold " Server key usage "; + outok=true + json_prefix="cert_key_usage" cert_keyusage=$($OPENSSL x509 -text -noout -in $HOSTCERT 2>>$ERRFILE | grep -A 1 "X509v3 Key Usage:" | tail -n +2 | sed 's/^[ \t]*//') if [[ -n "$cert_keyusage" ]]; then outln "$cert_keyusage" if ( [[ " $cert_type " =~ " RSASig " ]] || [[ " $cert_type " =~ " DSA " ]] || [[ " $cert_type " =~ " ECDSA " ]] ) && \ [[ ! "$cert_keyusage" =~ "Digital Signature" ]]; then prln_svrty_high "$indent -- certificate incorrectly used for digital signatures" + fileout "${json_prefix}${json_postfix}" "HIGH" "Certificate incorrectly used for digital signatures: \"$cert_keyusage\"" + outok=false fi if [[ " $cert_type " =~ " RSAKMK " ]] && [[ ! "$cert_keyusage" =~ "Key Encipherment" ]]; then prln_svrty_high "$indent -- certificate incorrectly used for key encipherment" + fileout "${json_prefix}${json_postfix}" "HIGH" "Certificate incorrectly used for key encipherment: \"$cert_keyusage\"" + outok=false fi if ( [[ " $cert_type " =~ " DH " ]] || [[ " $cert_type " =~ " ECDH " ]] ) && \ [[ ! "$cert_keyusage" =~ "Key Agreement" ]]; then prln_svrty_high "$indent -- certificate incorrectly used for key agreement" + fileout "${json_prefix}${json_postfix}" "HIGH" "Certificate incorrectly used for key agreement: \"$cert_keyusage\"" + outok=false fi else - outln "(absent)" + outln "--" + fileout "${json_prefix}key_usage" "INFO" "No server key usage information" + outok=false + fi + if "$outok"; then + fileout "${json_prefix}key_usage" "INFO" "Server key usage information: $cert_keyusage" fi out "$indent"; pr_bold " Server extended key usage "; + json_prefix="cert_extended_key_usage" + outok=true cert_ext_keyusage="$($OPENSSL x509 -noout -text -in $HOSTCERT 2>>$ERRFILE | grep -A 1 "X509v3 Extended Key Usage: " | tail -1 | sed 's/^[ \t]*//')" if [[ -n "$cert_ext_keyusage" ]]; then outln "$cert_ext_keyusage" if [[ ! "$cert_ext_keyusage" =~ "TLS Web Server Authentication" ]] && [[ ! "$cert_ext_keyusage" =~ "Any Extended Key Usage" ]]; then prln_svrty_high "$indent -- certificate incorrectly used for TLS Web Server Authentication" + fileout "${json_prefix}${json_postfix}" "HIGH" "Certificate incorrectly used for TLS Web Server Authentication: \"$cert_ext_keyusage\"" + outok=false fi else - outln "(absent)" + outln "--" + fileout "${json_prefix}${json_postfix}" "INFO" "No server extended key usage information" + outok=false + fi + if "$outok"; then + fileout "${json_prefix}${json_postfix}" "INFO" "Server extended key usage: \"cert_ext_keyusage\"" fi out "$indent"; pr_bold " Fingerprint / Serial "