Merge pull request #3183 from testssl/fix_spki_hashgeneration

Fix spki hashgeneration check in t/05_ca_hashes_up_to_date.t
This commit is contained in:
Dirk Wetter
2026-10-17 18:04:35 +02:00
committed by GitHub
2 changed files with 32 additions and 9 deletions
+27 -5
View File
@@ -4,14 +4,36 @@ use strict;
use warnings; use warnings;
use Test::More; use Test::More;
printf "\n%s\n", "Make sure CA certificate stores are older than their SPKI hashes \"~/etc/ca_hashes.txt\" ..."; # Verify that etc/ca_hashes.txt is in sync with the CA bundles (etc/*.pem).
# Regenerates the hashes and compares content, rather than relying on
# file modification times (which git does not preserve).
my $newer_bundles=`find etc/*.pem -newer etc/ca_hashes.txt`; # Regenerate ca_hashes.txt from the .pem bundles
my $rc = system('./utils/create_ca_hashes.sh');
is($rc, 0, "create_ca_hashes.sh exited successfully");
#1 # Compare the set of SPKI hashes (field 1) between the committed file and
is($newer_bundles,"","Checking if there's an output with a *.pem file. If so: run \"~/utils/create_ca_hashes.sh\""); # the freshly regenerated one, order-independently. We do NOT compare the
# whole file byte-for-byte: the name column (field 2) and the line order
# are cosmetic and are not stable across platforms. The name comes from
# `openssl x509 -subject`, which formats differently between LibreSSL
# (macOS) and OpenSSL (Linux); the order comes from `sort`, whose collation
# differs between BSD libc and glibc even under an identically-named locale.
# Only the SPKI hash is deterministic, and it is the sole column testssl.sh
# consumes (grep -h "$hpkp_spki"), so that is what "up to date" means here.
# LC_ALL=C pins the collation so the set comparison is byte-order and
# platform-independent.
my $committed = `git show HEAD:etc/ca_hashes.txt 2>/dev/null | cut -d' ' -f1 | LC_ALL=C sort -u`;
my $regenerated = `cut -d' ' -f1 etc/ca_hashes.txt 2>/dev/null | LC_ALL=C sort -u`;
my $has_diff = ($committed eq $regenerated) ? "0" : "1";
# Restore the original file and remove the .bak the script creates
system('git checkout -- etc/ca_hashes.txt 2>/dev/null');
unlink 'etc/ca_hashes.txt.bak';
is($has_diff, "0",
"ca_hashes.txt is up to date with the .pem bundles (run ./utils/create_ca_hashes.sh if not)");
printf "\n";
done_testing; done_testing;
+5 -4
View File
@@ -6,7 +6,8 @@
# This file generates the file etc/ca_hashes.txt from the (root)certificate # This file generates the file etc/ca_hashes.txt from the (root)certificate
# Bundles in etc (etc/*.pem) # Bundles in etc (etc/*.pem)
TEMPDIR="/tmp" TEMPDIR=$(mktemp -d)
trap 'rm -rf "$TEMPDIR"' EXIT
# Check if we are in the right directory # Check if we are in the right directory
if [[ ! -e etc ]]; then if [[ ! -e etc ]]; then
@@ -14,7 +15,7 @@ if [[ ! -e etc ]]; then
exit 99 exit 99
fi fi
echo "Extracting private key hashes from CA bundles" echo "Extracting SPKI (public key) hashes from CA bundles"
echo -n > "$TEMPDIR/cahashes" echo -n > "$TEMPDIR/cahashes"
for bundle_fname in etc/*.pem; do for bundle_fname in etc/*.pem; do
if [[ ! -r $bundle_fname ]]; then if [[ ! -r $bundle_fname ]]; then
@@ -32,7 +33,7 @@ for bundle_fname in etc/*.pem; do
echo -n "." echo -n "."
hpkp_key_ca="$( ( openssl x509 -in "$cert_fname" -pubkey -noout | grep -v PUBLIC | openssl base64 -d | hpkp_key_ca="$( ( openssl x509 -in "$cert_fname" -pubkey -noout | grep -v PUBLIC | openssl base64 -d |
openssl dgst -sha256 -binary | openssl enc -base64 ) 2>/dev/null )" openssl dgst -sha256 -binary | openssl enc -base64 ) 2>/dev/null )"
hpkp_name=$( openssl x509 -in "$cert_fname" -subject -noout 2>/dev/null | sed "s/^subject= //") hpkp_name=$( openssl x509 -in "$cert_fname" -subject -noout -nameopt compat 2>/dev/null | sed "s/^subject= //")
if [[ $(echo $hpkp_name|grep 'CN='|wc -l) -eq 1 ]]; then if [[ $(echo $hpkp_name|grep 'CN='|wc -l) -eq 1 ]]; then
hpkp_name=$(echo -n $hpkp_name|sed 's/^.*CN=//'|sed 's/\/.*$//') hpkp_name=$(echo -n $hpkp_name|sed 's/^.*CN=//'|sed 's/\/.*$//')
fi fi
@@ -44,4 +45,4 @@ done
# Make a backup first # Make a backup first
cp etc/ca_hashes.txt etc/ca_hashes.txt.bak cp etc/ca_hashes.txt etc/ca_hashes.txt.bak
sort -u "$TEMPDIR/cahashes" > etc/ca_hashes.txt LC_ALL=C sort -u "$TEMPDIR/cahashes" > etc/ca_hashes.txt