output + code polishing, phrasing. lf still has space for improvements
This commit is contained in:
parent
364bea1da0
commit
d786a94a8c
86
testssl.sh
86
testssl.sh
|
@ -513,6 +513,7 @@ hex2dec() {
|
|||
count_lines() {
|
||||
wc -l <<<"$1" | sed 's/ //g'
|
||||
}
|
||||
|
||||
count_words() {
|
||||
wc -w <<<"$1" | sed 's/ //g'
|
||||
}
|
||||
|
@ -541,6 +542,10 @@ strip_spaces() {
|
|||
echo "${1// /}"
|
||||
}
|
||||
|
||||
trim_trailing_space() {
|
||||
echo "${1%%*( )}"
|
||||
}
|
||||
|
||||
toupper() {
|
||||
echo -n "$1" | tr 'a-z' 'A-Z'
|
||||
}
|
||||
|
@ -958,6 +963,7 @@ run_hpkp() {
|
|||
local -i hpkp_age_days
|
||||
local -i hpkp_nr_keys
|
||||
local hpkp_key hpkp_key_hostcert
|
||||
local -a backup_keys
|
||||
local spaces=" "
|
||||
local key_found=false
|
||||
local i
|
||||
|
@ -968,7 +974,6 @@ run_hpkp() {
|
|||
if [[ ! -s $HEADERFILE ]]; then
|
||||
run_http_header "$1" || return 3
|
||||
fi
|
||||
#pr_bold " HPKP "
|
||||
pr_bold " Public Key Pinning "
|
||||
egrep -aiw '^Public-Key-Pins|Public-Key-Pins-Report-Only' $HEADERFILE >$TMPFILE
|
||||
if [[ $? -eq 0 ]]; then
|
||||
|
@ -1001,7 +1006,7 @@ run_hpkp() {
|
|||
out "# of keys: "
|
||||
if [[ $hpkp_nr_keys -eq 1 ]]; then
|
||||
pr_svrty_high "1 (NOT ok), "
|
||||
fileout "hpkp_keys" "NOT ok" "Only one key pinned in HPKP header, this means the site may become unavailable if the key is revoked"
|
||||
fileout "hpkp_keys" "HIGH" "Only one key pinned in HPKP header, this means the site may become unavailable if the key is revoked"
|
||||
else
|
||||
out "$hpkp_nr_keys, "
|
||||
fileout "hpkp_keys" "OK" "$hpkp_nr_keys keys pinned in HPKP header, additional keys are available if the current key is revoked"
|
||||
|
@ -1030,8 +1035,8 @@ run_hpkp() {
|
|||
fileout "hpkp_preload" "INFO" "HPKP header is NOT marked for browser preloading"
|
||||
fi
|
||||
|
||||
# Get the pins first
|
||||
pins=$(tr ';' '\n' < $TMPFILE | tr -d ' ' | tr -d '\"' | awk -F'=' '/pin.*=/ { print $2 }')
|
||||
# Get the spki first
|
||||
spki=$(tr ';' '\n' < $TMPFILE | tr -d ' ' | tr -d '\"' | awk -F'=' '/pin.*=/ { print $2 }')
|
||||
|
||||
|
||||
# Look at the host certificate first
|
||||
|
@ -1069,18 +1074,19 @@ run_hpkp() {
|
|||
fi
|
||||
|
||||
# This is where the matching magic happens...
|
||||
pins_match=false
|
||||
has_backup_pin=false
|
||||
for hpkp_key in $pins; do
|
||||
spki_match=false
|
||||
has_backup_spki=false
|
||||
i=0
|
||||
for hpkp_key in $spki; do
|
||||
key_found=false
|
||||
# compare pin against the host certificate
|
||||
# compare spki against the host certificate
|
||||
if [[ "$hpkp_key_hostcert" == "$hpkp_key" ]] || [[ "$hpkp_key_hostcert" == "$hpkp_key=" ]]; then
|
||||
# We have a match
|
||||
key_found=true
|
||||
pins_match=true
|
||||
spki_match=true
|
||||
out "\n$spaces Host cert match: "
|
||||
pr_done_good "$hpkp_key"
|
||||
fileout "hpkp_$hpkp_key" "OK" "PIN $hpkp_key matches the host certificate"
|
||||
fileout "hpkp_$hpkp_key" "OK" "SPKI $hpkp_key matches the host certificate"
|
||||
fi
|
||||
debugme out "\n $hpkp_key | $hpkp_key_hostcert"
|
||||
|
||||
|
@ -1090,66 +1096,78 @@ run_hpkp() {
|
|||
if [[ -n $hpkp_matches ]]; then
|
||||
# We have a match
|
||||
key_found=true
|
||||
pins_match=true
|
||||
spki_match=true
|
||||
out "\n$spaces Sub CA match: "
|
||||
pr_done_good "$hpkp_key"
|
||||
out "\n$spaces $(echo $hpkp_matches|sed "s/^[a-zA-Z0-9\+\/]*=* *//")"
|
||||
out "\n$spaces \"$(sed "s/^[a-zA-Z0-9\+\/]*=* *//" <<< $"$hpkp_matches" )\""
|
||||
fileout "hpkp_$hpkp_key" "OK" "Intermediate CA key matches a key pinned in the HPKP header. Key/CA: $hpkp_matches"
|
||||
fi
|
||||
fi
|
||||
|
||||
if ! $key_found; then
|
||||
# we compare now against a precompiled list of SPKIs against the ROOT CAs we have!
|
||||
hpkp_matches=$(grep -h "$hpkp_key" $ca_hashes | sort -u)
|
||||
if [[ -n $hpkp_matches ]]; then
|
||||
# We have a match
|
||||
key_found=true
|
||||
pins_match=true
|
||||
spki_match=true
|
||||
if [[ $(count_lines "$hpkp_matches") -eq 1 ]]; then
|
||||
match_ca=$(echo "$hpkp_matches" | sed "s/[a-zA-Z0-9\+\/]*=* *//")
|
||||
match_ca=$(sed "s/[a-zA-Z0-9\+\/]*=* *//" <<< "$hpkp_matches")
|
||||
else
|
||||
match_ca=""
|
||||
fi
|
||||
out "\n\n$spaces Root CA match: "
|
||||
pr_done_good "$hpkp_key"
|
||||
echo "$hpkp_matches"|sort -u|while read line; do
|
||||
out "\n$spaces $(echo $line |sed "s/^[a-zA-Z0-9\+\/]*=* *//")"
|
||||
out "\n$spaces \"$(sed "s/^[a-zA-Z0-9\+\/]*=* *//" <<< "$line")\""
|
||||
done
|
||||
if [[ $match_ca == $hpkp_ca ]]; then
|
||||
out " (part of the chain)"
|
||||
fileout "hpkp_$hpkp_key" "INFO" "Root CA key matches a key pinned in the HPKP header. Key/OS/CA: $hpkp_matches. The CA is part of the chain"
|
||||
fileout "hpkp_$hpkp_key" "INFO" "Root CA matches a key pinned in the HPKP header. Key/OS/CA: $hpkp_matches. The CA is part of the chain"
|
||||
else
|
||||
has_backup_pin=true
|
||||
out "\n$spaces This CA is not part of the chain and likely a backup PIN"
|
||||
fileout "hpkp_$hpkp_key" "INFO" "Root CA key matches a key pinned in the HPKP header. Key/OS/CA: $hpkp_matches. The CA is not part of the chain, this is a backup PIN"
|
||||
has_backup_spki=true
|
||||
out " -- not part of chain, probable backup key"
|
||||
fileout "hpkp_$hpkp_key" "INFO" "Root CA matches a key pinned in the HPKP header. Key/OS/CA: $hpkp_matches. The CA is not part of the chain, this is a backup SPKI"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if ! $key_found; then
|
||||
# Most likely a backup pin
|
||||
has_backup_pin=true
|
||||
out "\n\n$spaces Unmatched key: "
|
||||
out "$hpkp_key"
|
||||
out "\n$spaces (This is OK for a backup pin of a host cert)"
|
||||
fileout "hpkp_$hpkp_key" "INFO" "PIN $hpkp_key doesn't match anything. This could be ok if it is a backup pin for a host certificate"
|
||||
# Most likely a backup SPKI, unfortunately we can't tell for what it is: host, intermediates
|
||||
has_backup_spki=true
|
||||
backup_keys[i]="$hpkp_key"
|
||||
i=$((i + 1))
|
||||
fileout "hpkp_$hpkp_key" "INFO" "SPKI $hpkp_key doesn't match anything. This is ok for a backup for any certificate"
|
||||
# CVS/JSON output here for the sake of simplicity, rest we do en bloc below
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ $i -eq 1 ]]; then
|
||||
out "\n$spaces Unmatched SPKI: "
|
||||
outln "${backup_keys[0]}"
|
||||
else
|
||||
out "\n\n$spaces Unmatched SPKIs: "
|
||||
outln "${backup_keys[0]}"
|
||||
for ((i=1; i <= ${#backup_keys[@]} ;i++ )); do
|
||||
outln "$spaces ${backup_keys[i]}"
|
||||
done
|
||||
fi
|
||||
# OK for SPKI backup of host or different intermediate certificate is ok!
|
||||
|
||||
# If all else fails...
|
||||
if ! $pins_match; then
|
||||
pr_svrty_high " No matching key for pins found "
|
||||
fileout "hpkp_keymatch" "NOT ok" "None of the HPKP PINS match your host certificate, intermediate CA or known root CAs. You may have bricked this site"
|
||||
if ! $spki_match; then
|
||||
"$has_backup_spki" && out "$spaces" # we had a few lines with backup SPKIs already
|
||||
pr_svrty_highln " No matching key for SPKI found "
|
||||
fileout "hpkp_keymatch" "HIGH" "None of the HPKP SPKI match your host certificate, intermediate CA or known root CAs. You may have bricked this site"
|
||||
fi
|
||||
|
||||
if ! $has_backup_pin; then
|
||||
pr_svrty_high " No backup pins found. Loss/compromise of the currently pinned key(s) will lead to bricked site. "
|
||||
fileout "hpkp_backup" "NOT ok" "No backup pins found. Loss/compromise of the currently pinned key(s) will lead to bricked site."
|
||||
if ! $has_backup_spki; then
|
||||
pr_svrty_highln " No backup keys found. Loss/compromise of the currently pinned key(s) will lead to bricked site. "
|
||||
fileout "hpkp_backup" "HIGH" "No backup keys found. Loss/compromise of the currently pinned key(s) will lead to bricked site."
|
||||
fi
|
||||
else
|
||||
out "--"
|
||||
outln "--"
|
||||
fileout "hpkp" "INFO" "No support for HTTP Public Key Pinning"
|
||||
fi
|
||||
outln
|
||||
|
||||
tmpfile_handle $FUNCNAME.txt
|
||||
return $?
|
||||
|
|
Loading…
Reference in New Issue