Not done yet, but the basic code is working

This commit is contained in:
Frank Breedijk 2016-07-04 17:21:24 +02:00
parent 946506f3ac
commit a648470988
1 changed files with 83 additions and 4 deletions

View File

@ -960,6 +960,7 @@ run_hpkp() {
local i local i
local hpkp_headers local hpkp_headers
local first_hpkp_header local first_hpkp_header
local ca_bundles="$INSTALL_DIR/etc/*.pem"
if [[ ! -s $HEADERFILE ]]; then if [[ ! -s $HEADERFILE ]]; then
run_http_header "$1" || return 3 run_http_header "$1" || return 3
@ -1029,21 +1030,99 @@ run_hpkp() {
if [[ ! -s "$HOSTCERT" ]]; then if [[ ! -s "$HOSTCERT" ]]; then
get_host_cert || return 1 get_host_cert || return 1
fi 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 # get the key fingerprint from the host certificate
hpkp_key_hostcert="$($OPENSSL x509 -in $HOSTCERT -pubkey -noout | grep -v PUBLIC | \ hpkp_key_hostcert="$($OPENSSL x509 -in $HOSTCERT -pubkey -noout | grep -v PUBLIC | \
$OPENSSL base64 -d | $OPENSSL dgst -sha256 -binary | $OPENSSL base64)" $OPENSSL base64 -d | $OPENSSL dgst -sha256 -binary | $OPENSSL base64)"
# compare it with the ones provided in the header # 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 if [[ "$hpkp_key_hostcert" == "$hpkp_key" ]] || [[ "$hpkp_key_hostcert" == "$hpkp_key=" ]]; then
out "\n$spaces matching host key: " out "\n$spaces matching host key: "
pr_done_good "$hpkp_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 key_found=true
fi fi
debugme out "\n $hpkp_key | $hpkp_key_hostcert" 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]} </dev/null >$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 if ! $key_found ; then
out "\n$spaces"
pr_svrty_high " No matching key for pins found " pr_svrty_high " No matching key for pins found "
out "(CAs pinned? -- not checked for yet)" 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" 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"