From a64847098861f7667a59ffc88a9e4b0ea0c2eb80 Mon Sep 17 00:00:00 2001 From: Frank Breedijk Date: Mon, 4 Jul 2016 17:21:24 +0200 Subject: [PATCH] Not done yet, but the basic code is working --- testssl.sh | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 83 insertions(+), 4 deletions(-) diff --git a/testssl.sh b/testssl.sh index 38eef5f..a290959 100755 --- a/testssl.sh +++ b/testssl.sh @@ -960,6 +960,7 @@ run_hpkp() { local i local hpkp_headers local first_hpkp_header + local ca_bundles="$INSTALL_DIR/etc/*.pem" if [[ ! -s $HEADERFILE ]]; then run_http_header "$1" || return 3 @@ -1029,21 +1030,99 @@ run_hpkp() { if [[ ! -s "$HOSTCERT" ]]; then get_host_cert || return 1 fi + + # Get the pins first + pins=$(tr ';' '\n' < $TMPFILE | tr -d ' ' | tr -d '\"' | awk -F'=' '/pin.*=/ { print $2 }') + # get the key fingerprint from the host certificate hpkp_key_hostcert="$($OPENSSL x509 -in $HOSTCERT -pubkey -noout | grep -v PUBLIC | \ $OPENSSL base64 -d | $OPENSSL dgst -sha256 -binary | $OPENSSL base64)" # compare it with the ones provided in the header - while read hpkp_key; do + for hpkp_key in $(echo "$pins"); do if [[ "$hpkp_key_hostcert" == "$hpkp_key" ]] || [[ "$hpkp_key_hostcert" == "$hpkp_key=" ]]; then out "\n$spaces matching host key: " pr_done_good "$hpkp_key" - fileout "hpkp_keymatch" "OK" "Key matches a key pinned in the HPKP header" + fileout "hpkp_keymatch" "OK" "Host certificate key matches a key pinned in the HPKP header" key_found=true fi debugme out "\n $hpkp_key | $hpkp_key_hostcert" - done < <(tr ';' '\n' < $TMPFILE | tr -d ' ' | tr -d '\"' | awk -F'=' '/pin.*=/ { print $2 }') + done + + if ! $key_found ; then + # Get keys from intermediate certificates + $OPENSSL s_client -showcerts $STARTTLS $BUGS $PROXY -showcerts -connect $NODEIP:$PORT ${sni[i]} $TMPFILE 2>$ERRFILE + # Place the server's certificate in $HOSTCERT and any intermediate + # certificates that were provided in $TEMPDIR/intermediatecerts.pem + # http://backreference.org/2010/05/09/ocsp-verification-with-openssl/ + awk -v n=-1 "/Certificate chain/ {start=1} + /-----BEGIN CERTIFICATE-----/{ if (start) {inc=1; n++} } + inc { print > (\"$TEMPDIR/level\" n \".crt\") } + /---END CERTIFICATE-----/{ inc=0 }" $TMPFILE + nrsaved=$(count_words "$(echo $TEMPDIR/level?.crt 2>/dev/null)") + rm $TEMPDIR/level0.crt + + # Compare them against the hashes found + if [[ nrsaved -ge 2 ]]; then + echo -n "" > "/tmp/hashes.intermediate" + for cert_fname in $TEMPDIR/level?.crt; do + hpkp_key_ca="$($OPENSSL x509 -in "$cert_fname" -pubkey -noout | grep -v PUBLIC|$OPENSSL dgst -sha256 -binary | $OPENSSL enc -base64)" + issuer="$(get_cn_from_cert $cert_fname)" + [[ -n $hpkp_name ]] || hpkp_name=$($OPENSSL x509 -in "$cert_fname" -subject -noout| sed "s/^subject= //") + echo "$hpkp_key_ca $bundle_name $issuer" >> "/tmp/hashes.intermediate" + done + for hpkp_key in $(echo $pins); do + hpkp_matches=$(grep "$hpkp_key" /tmp/hashes.intermediate) + if [[ -n $hpkp_matches ]]; then + # We have a winner! + key_found=true + out "\n$spaces Intermediate CA match : " + pr_done_good "$hpkp_matches" + fileout "hpkp_keymatch" "OK" "Intermediate CA key matches a key pinned in the HPKP header\nKey/CA: $hpkp_matches" + fi + done + fi + fi + + if ! $key_found ; then + # Get keys from Root CAs + for bundle_fname in $ca_bundles; do + local bundle_name=$(basename ${bundle_fname//.pem}) + if [[ ! -r $bundle_fname ]]; then + pr_warningln "\"$bundle_fname\" cannot be found / not readable" + return 7 + fi + debugme printf -- " %-12s" "${certificate_file[i]}" + # Split up the certificate bundle + awk -v n=-1 "BEGIN {start=1} + /-----BEGIN CERTIFICATE-----/{ if (start) {inc=1; n++} } + inc { print >> (\"/tmp/$bundle_name.\" n \".crt\") ; close (\"/tmp/$bundle_name.\" n \".crt\") } + /---END CERTIFICATE-----/{ inc=0 }" $bundle_fname + # Clear temp file + echo -n "" > "/tmp/hashes.$bundle_name" + for cert_fname in /tmp/$bundle_name.*.crt; do + hpkp_key_ca="$($OPENSSL x509 -in "$cert_fname" -pubkey -noout | grep -v PUBLIC|$OPENSSL dgst -sha256 -binary | $OPENSSL enc -base64)" + issuer="$(get_cn_from_cert $cert_fname)" + [[ -n $hpkp_name ]] || hpkp_name=$($OPENSSL x509 -in "$cert_fname" -subject -noout| sed "s/^subject= //") + echo "$hpkp_key_ca $bundle_name : $issuer" >> "/tmp/hashes.$bundle_name" + done + done + for hpkp_key in $(echo $pins); do + hpkp_matches=$(grep -h "$hpkp_key" /tmp/hashes.*) + if [[ -n $hpkp_matches ]]; then + # We have a winner! + key_found=true + out "\n$spaces Root CA match : " + pr_done_goodln "$hpkp_key" + out "$hpkp_matches" + + fileout "hpkp_keymatch" "OK" "Root CA key matches a key pinned in the HPKP header\nKey/OS/CA: $hpkp_matches" + fi + done + exit 99 + fi + + # If all else fails... if ! $key_found ; then - out "\n$spaces" pr_svrty_high " No matching key for pins found " out "(CAs pinned? -- not checked for yet)" fileout "hpkp_keymatch" "DEBUG" "The TLS key does not match any key pinned in the HPKP header. If you pinned a CA key you can ignore this"