mirror of
				https://github.com/drwetter/testssl.sh.git
				synced 2025-11-04 07:45:27 +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
 | 
					               GOST_STATUS_PROBLEM=true
 | 
				
			||||||
          fi
 | 
					          fi
 | 
				
			||||||
     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
 | 
					     extract_new_tls_extensions $TMPFILE
 | 
				
			||||||
 | 
					
 | 
				
			||||||
     # Place the server's certificate in $HOSTCERT and any intermediate
 | 
					     # Place the server's certificate in $HOSTCERT and any intermediate
 | 
				
			||||||
@@ -5563,6 +5569,69 @@ must_staple() {
 | 
				
			|||||||
     fi
 | 
					     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() {
 | 
					certificate_info() {
 | 
				
			||||||
     local proto
 | 
					     local proto
 | 
				
			||||||
     local -i certificate_number=$1
 | 
					     local -i certificate_number=$1
 | 
				
			||||||
@@ -5572,6 +5641,7 @@ certificate_info() {
 | 
				
			|||||||
     local ocsp_response=$5
 | 
					     local ocsp_response=$5
 | 
				
			||||||
     local ocsp_response_status=$6
 | 
					     local ocsp_response_status=$6
 | 
				
			||||||
     local sni_used=$7
 | 
					     local sni_used=$7
 | 
				
			||||||
 | 
					     local ct="$8"
 | 
				
			||||||
     local cert_sig_algo cert_sig_hash_algo cert_key_algo
 | 
					     local cert_sig_algo cert_sig_hash_algo cert_key_algo
 | 
				
			||||||
     local expire days2expire secs2warn ocsp_uri crl
 | 
					     local expire days2expire secs2warn ocsp_uri crl
 | 
				
			||||||
     local startdate enddate issuer_CN issuer_C issuer_O issuer sans san all_san="" cn
 | 
					     local startdate enddate issuer_CN issuer_C issuer_O issuer sans san all_san="" cn
 | 
				
			||||||
@@ -6187,8 +6257,17 @@ certificate_info() {
 | 
				
			|||||||
          pr_svrty_low "--"
 | 
					          pr_svrty_low "--"
 | 
				
			||||||
          fileout "${json_prefix}CAA_record" "LOW" "DNS Certification Authority Authorization (CAA) Resource Record / RFC6844 : not offered"
 | 
					          fileout "${json_prefix}CAA_record" "LOW" "DNS Certification Authority Authorization (CAA) Resource Record / RFC6844 : not offered"
 | 
				
			||||||
     fi
 | 
					     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
 | 
					     return $ret
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -6199,7 +6278,7 @@ run_server_defaults() {
 | 
				
			|||||||
     local -i i n
 | 
					     local -i i n
 | 
				
			||||||
     local -i certs_found=0
 | 
					     local -i certs_found=0
 | 
				
			||||||
     local -a previous_hostcert previous_intermediates keysize cipher
 | 
					     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 ciphers_to_test
 | 
				
			||||||
     local -a -i success
 | 
					     local -a -i success
 | 
				
			||||||
     local cn_nosni cn_sni sans_nosni sans_sni san tls_extensions
 | 
					     local cn_nosni cn_sni sans_nosni sans_sni san tls_extensions
 | 
				
			||||||
@@ -6308,11 +6387,19 @@ run_server_defaults() {
 | 
				
			|||||||
                         certs_found=$(( certs_found + 1))
 | 
					                         certs_found=$(( certs_found + 1))
 | 
				
			||||||
                         cipher[certs_found]=${ciphers_to_test[n]}
 | 
					                         cipher[certs_found]=${ciphers_to_test[n]}
 | 
				
			||||||
                         keysize[certs_found]=$(awk '/Server public key/ { print $(NF-1) }' $TMPFILE)
 | 
					                         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)
 | 
					                         ocsp_response_status[certs_found]=$(grep -a "OCSP Response Status" $TMPFILE)
 | 
				
			||||||
                         previous_hostcert[certs_found]=$newhostcert
 | 
					                         previous_hostcert[certs_found]=$newhostcert
 | 
				
			||||||
                         previous_intermediates[certs_found]=$(cat $TEMPDIR/intermediatecerts.pem)
 | 
					                         previous_intermediates[certs_found]=$(cat $TEMPDIR/intermediatecerts.pem)
 | 
				
			||||||
                         [[ $n -ge 8 ]] && sni_used[certs_found]="" || sni_used[certs_found]="$SNI"
 | 
					                         [[ $n -ge 8 ]] && sni_used[certs_found]="" || sni_used[certs_found]="$SNI"
 | 
				
			||||||
 | 
					                         tls_version[certs_found]="$DETECTED_TLS_VERSION"
 | 
				
			||||||
                    fi
 | 
					                    fi
 | 
				
			||||||
               fi
 | 
					               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)
 | 
					          [[ -z "$sessticket_lifetime_hint" ]] && sessticket_lifetime_hint=$(grep -aw "session ticket" $TMPFILE | grep -a lifetime)
 | 
				
			||||||
     fi
 | 
					     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
 | 
					     outln
 | 
				
			||||||
     pr_headlineln " Testing server defaults (Server Hello) "
 | 
					     pr_headlineln " Testing server defaults (Server Hello) "
 | 
				
			||||||
     outln
 | 
					     outln
 | 
				
			||||||
@@ -6413,12 +6509,10 @@ run_server_defaults() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
     tls_time
 | 
					     tls_time
 | 
				
			||||||
 | 
					
 | 
				
			||||||
     i=1
 | 
					     for (( i=1; i <= certs_found; i++ )); do
 | 
				
			||||||
     while [[ $i -le $certs_found ]]; do
 | 
					 | 
				
			||||||
          echo "${previous_hostcert[i]}" > $HOSTCERT
 | 
					          echo "${previous_hostcert[i]}" > $HOSTCERT
 | 
				
			||||||
          echo "${previous_intermediates[i]}" > $TEMPDIR/intermediatecerts.pem
 | 
					          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]}"
 | 
					          certificate_info "$i" "$certs_found" "${cipher[i]}" "${keysize[i]}" "${ocsp_response[i]}" "${ocsp_response_status[i]}" "${sni_used[i]}" "${ct[i]}"
 | 
				
			||||||
          i=$((i + 1))
 | 
					 | 
				
			||||||
     done
 | 
					     done
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user