mirror of
				https://github.com/drwetter/testssl.sh.git
				synced 2025-11-03 23:35:26 +01:00 
			
		
		
		
	Certificate Transparency
This commit implements a check for Certificate Transparency support, as proposed in #771.
This commit is contained in:
		
							
								
								
									
										108
									
								
								testssl.sh
									
									
									
									
									
								
							
							
						
						
									
										108
									
								
								testssl.sh
									
									
									
									
									
								
							@@ -5348,6 +5348,12 @@ get_server_certificate() {
 | 
			
		||||
               GOST_STATUS_PROBLEM=true
 | 
			
		||||
          fi
 | 
			
		||||
     fi
 | 
			
		||||
     case "$proto" in
 | 
			
		||||
          "tls1_2") DETECTED_TLS_VERSION="0303" ;;
 | 
			
		||||
          "tls1_1") DETECTED_TLS_VERSION="0302" ;;
 | 
			
		||||
          "tls1") DETECTED_TLS_VERSION="0301" ;;
 | 
			
		||||
          "ssl3") DETECTED_TLS_VERSION="0300" ;;
 | 
			
		||||
     esac
 | 
			
		||||
     extract_new_tls_extensions $TMPFILE
 | 
			
		||||
 | 
			
		||||
     # Place the server's certificate in $HOSTCERT and any intermediate
 | 
			
		||||
@@ -5563,6 +5569,69 @@ must_staple() {
 | 
			
		||||
     fi
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# TODO: This function checks for Certificate Transparency support based on RFC 6962.
 | 
			
		||||
# It will need to be updated to add checks for Certificate Transparency support based on 6962bis.
 | 
			
		||||
certificate_transparency() {
 | 
			
		||||
     local cert="$1"
 | 
			
		||||
     local ocsp_response="$2"
 | 
			
		||||
     local -i number_of_certificates=$3
 | 
			
		||||
     local cipher="$4"
 | 
			
		||||
     local sni_used="$5"
 | 
			
		||||
     local tls_version="$6"
 | 
			
		||||
     local sni=""
 | 
			
		||||
     local ciphers=""
 | 
			
		||||
     local hexc n ciph sslver kx auth enc mac export
 | 
			
		||||
     local -i success
 | 
			
		||||
 | 
			
		||||
     # First check whether signed certificate timestamps (SCT) are included in the
 | 
			
		||||
     # server's certificate. If they aren't, check whether the server provided
 | 
			
		||||
     # a stapled OCSP response with SCTs. If no SCTs were found in the certificate
 | 
			
		||||
     # or OCSP response, check for an SCT TLS extension.
 | 
			
		||||
     if $OPENSSL x509 -noout -text 2>>$ERRFILE <<< "$cert" | egrep -q "CT Precertificate SCTs|1.3.6.1.4.1.11129.2.4.2" ; then
 | 
			
		||||
          tm_out "certificate extension"
 | 
			
		||||
          return 0
 | 
			
		||||
     fi
 | 
			
		||||
     if egrep -q "CT Certificate SCTs|1.3.6.1.4.1.11129.2.4.5" <<< "$ocsp_response"; then
 | 
			
		||||
          tm_out "OCSP extension"
 | 
			
		||||
          return 0
 | 
			
		||||
     fi
 | 
			
		||||
 | 
			
		||||
     # If the server only has one certificate, then it is sufficient to check whether
 | 
			
		||||
     # determine_tls_extensions() discovered an SCT TLS extension. If the server has more than
 | 
			
		||||
     # one certificate, then it is possible that an SCT TLS extension is returned for some
 | 
			
		||||
     # certificates, but not for all of them.
 | 
			
		||||
     if [[ $number_of_certificates -eq 1 ]] && [[ "$TLS_EXTENSIONS" =~ "signed certificate timestamps" ]]; then
 | 
			
		||||
          tm_out "TLS extension"
 | 
			
		||||
          return 0
 | 
			
		||||
     fi
 | 
			
		||||
 | 
			
		||||
     if [[ $number_of_certificates -gt 1 ]] && ! "$SSL_NATIVE"; then
 | 
			
		||||
          while read hexc n ciph sslver kx auth enc mac export; do
 | 
			
		||||
               if [[ ${#hexc} -eq 9 ]]; then
 | 
			
		||||
                    ciphers+=", ${hexc:2:2},${hexc:7:2}"
 | 
			
		||||
               fi
 | 
			
		||||
          done < <($OPENSSL ciphers -V $cipher 2>>$ERRFILE)
 | 
			
		||||
          [[ -z "$sni_used" ]] && sni="$SNI" && SNI=""
 | 
			
		||||
          tls_sockets "${tls_version:2:2}" "${ciphers:2}" "all" "00,12,00,00"
 | 
			
		||||
          success=$?
 | 
			
		||||
          [[ -z "$sni_used" ]] && SNI="$sni"
 | 
			
		||||
          if ( [[ $success -eq 0 ]] || [[ $success -eq 2 ]] ) && \
 | 
			
		||||
             grep -a 'TLS server extension ' "$TEMPDIR/$NODEIP.parse_tls_serverhello.txt" | \
 | 
			
		||||
             grep -aq "signed certificate timestamps"; then
 | 
			
		||||
               tm_out "TLS extension"
 | 
			
		||||
               return 0
 | 
			
		||||
          fi
 | 
			
		||||
     fi
 | 
			
		||||
 | 
			
		||||
     if [[ $SERVICE != "HTTP" ]]; then
 | 
			
		||||
          # At the moment Certificate Transparency only applies to HTTPS.
 | 
			
		||||
          tm_out "N/A"
 | 
			
		||||
     else
 | 
			
		||||
          tm_out "no"
 | 
			
		||||
     fi
 | 
			
		||||
     return 0
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
certificate_info() {
 | 
			
		||||
     local proto
 | 
			
		||||
     local -i certificate_number=$1
 | 
			
		||||
@@ -5572,6 +5641,7 @@ certificate_info() {
 | 
			
		||||
     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 expire days2expire secs2warn ocsp_uri crl
 | 
			
		||||
     local startdate enddate issuer_CN issuer_C issuer_O issuer sans san all_san="" cn
 | 
			
		||||
@@ -6187,8 +6257,17 @@ certificate_info() {
 | 
			
		||||
          pr_svrty_low "--"
 | 
			
		||||
          fileout "${json_prefix}CAA_record" "LOW" "DNS Certification Authority Authorization (CAA) Resource Record / RFC6844 : not offered"
 | 
			
		||||
     fi
 | 
			
		||||
     outln
 | 
			
		||||
 | 
			
		||||
     outln "\n"
 | 
			
		||||
     out "$indent"; pr_bold " Certificate Transparency     ";
 | 
			
		||||
     if [[ "$ct" =~ extension ]]; then
 | 
			
		||||
          pr_done_good "yes"; outln " ($ct)"
 | 
			
		||||
          fileout "${json_prefix}certificate_transparency" "OK" "Certificate Transparency: yes ($ct)"
 | 
			
		||||
     else
 | 
			
		||||
          outln "$ct"
 | 
			
		||||
          fileout "${json_prefix}certificate_transparency" "INFO" "Certificate Transparency: $ct"
 | 
			
		||||
     fi
 | 
			
		||||
     outln
 | 
			
		||||
     return $ret
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -6199,7 +6278,7 @@ run_server_defaults() {
 | 
			
		||||
     local -i i n
 | 
			
		||||
     local -i certs_found=0
 | 
			
		||||
     local -a previous_hostcert previous_intermediates keysize cipher
 | 
			
		||||
     local -a ocsp_response ocsp_response_status sni_used
 | 
			
		||||
     local -a ocsp_response ocsp_response_status sni_used tls_version ct
 | 
			
		||||
     local -a ciphers_to_test
 | 
			
		||||
     local -a -i success
 | 
			
		||||
     local cn_nosni cn_sni sans_nosni sans_sni san tls_extensions
 | 
			
		||||
@@ -6308,11 +6387,19 @@ run_server_defaults() {
 | 
			
		||||
                         certs_found=$(( certs_found + 1))
 | 
			
		||||
                         cipher[certs_found]=${ciphers_to_test[n]}
 | 
			
		||||
                         keysize[certs_found]=$(awk '/Server public key/ { print $(NF-1) }' $TMPFILE)
 | 
			
		||||
                         ocsp_response[certs_found]=$(grep -aA 20 "OCSP response" $TMPFILE)
 | 
			
		||||
                         # If an OCSP response was sent, then get the full
 | 
			
		||||
                         # response so that certificate_info() can determine
 | 
			
		||||
                         # whether it includes a certificate transparency extension.
 | 
			
		||||
                         if grep -a "OCSP response:" $TMPFILE | grep -q "no response sent"; then
 | 
			
		||||
                              ocsp_response[certs_found]="$(grep -a "OCSP response" $TMPFILE)"
 | 
			
		||||
                         else
 | 
			
		||||
                              ocsp_response[certs_found]="$(awk -v n=2 '/OCSP response:/ {start=1; inc=2} /======================================/ { if (start) {inc--} } inc' $TMPFILE)"
 | 
			
		||||
                         fi
 | 
			
		||||
                         ocsp_response_status[certs_found]=$(grep -a "OCSP Response Status" $TMPFILE)
 | 
			
		||||
                         previous_hostcert[certs_found]=$newhostcert
 | 
			
		||||
                         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"
 | 
			
		||||
                    fi
 | 
			
		||||
               fi
 | 
			
		||||
          fi
 | 
			
		||||
@@ -6325,6 +6412,15 @@ run_server_defaults() {
 | 
			
		||||
          [[ -z "$sessticket_lifetime_hint" ]] && sessticket_lifetime_hint=$(grep -aw "session ticket" $TMPFILE | grep -a lifetime)
 | 
			
		||||
     fi
 | 
			
		||||
 | 
			
		||||
     # Now that all of the server's certificates have been found, determine for
 | 
			
		||||
     # each certificate whether certificate transparency information is provided.
 | 
			
		||||
     for (( i=1; i <= certs_found; i++ )); do
 | 
			
		||||
          ct[i]="$(certificate_transparency "${previous_hostcert[i]}" "${ocsp_response[i]}" "$certs_found" "${cipher[i]}" "${sni_used[i]}" "${tls_version[i]}")"
 | 
			
		||||
          # If certificate_transparency() called tls_sockets() and found a "signed certificate timestamps" extension, then add it to $TLS_EXTENSIONS,
 | 
			
		||||
          # since it may not have been found by determine_tls_extensions().
 | 
			
		||||
          [[ $certs_found -gt 1 ]] && [[ "${ct[i]}" == "TLS extension" ]] && extract_new_tls_extensions "$TEMPDIR/$NODEIP.parse_tls_serverhello.txt"
 | 
			
		||||
     done
 | 
			
		||||
 | 
			
		||||
     outln
 | 
			
		||||
     pr_headlineln " Testing server defaults (Server Hello) "
 | 
			
		||||
     outln
 | 
			
		||||
@@ -6413,12 +6509,10 @@ run_server_defaults() {
 | 
			
		||||
 | 
			
		||||
     tls_time
 | 
			
		||||
 | 
			
		||||
     i=1
 | 
			
		||||
     while [[ $i -le $certs_found ]]; do
 | 
			
		||||
     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]}"
 | 
			
		||||
          i=$((i + 1))
 | 
			
		||||
          certificate_info "$i" "$certs_found" "${cipher[i]}" "${keysize[i]}" "${ocsp_response[i]}" "${ocsp_response_status[i]}" "${sni_used[i]}" "${ct[i]}"
 | 
			
		||||
     done
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user