Last active
January 29, 2025 12:25
-
-
Save joostd/40590010192b700f3358d72277fcba61 to your computer and use it in GitHub Desktop.
Check if a YubiHSM 2 FIPS key attestation and CSR meet CA/B forum requirements for code signing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# extend PATH with location of yubihsm-parse-attestation tool | |
PATH=$PATH:~/go/bin | |
# check for installed tools | |
command -v curl >/dev/null 2>&1 \ | |
|| { echo >&2 "please install curl - see https://github.com/curl/curl"; exit 1; } | |
command -v openssl >/dev/null 2>&1 \ | |
|| { echo >&2 "please install openssl - see https://github.com/openssl/openssl"; exit 1; } | |
command -v jq >/dev/null 2>&1 \ | |
|| { echo >&2 "please install jq - see https://github.com/jqlang/jq"; exit 1; } | |
command -v yubihsm-parse-attestation >/dev/null 2>&1 \ | |
|| { echo >&2 "please install yubihsm-parse-attestation - see https://github.com/YubicoLabs/yubihsm-parse-attestation"; exit 1; } | |
# command line arguments with defaults | |
CSR="${1:-csr.pem}" | |
ATTESTATION=${2:-attestation.pem} | |
PRELOADED=${3:-preloaded.pem} | |
# check file types | |
echo -n "input file type " | |
file -E $CSR | grep -e 'RFC1421' -e 'PEM certificate request' \ | |
|| { echo >&2 "❌ CSR expected as first argument"; exit 1 ; } | |
echo -n "input file type " | |
file -E $ATTESTATION | grep 'PEM certificate$' \ | |
|| { echo >&2 "❌ attestation certificate expected as second argument"; exit 1 ; } | |
echo -n "input file type " | |
file -E $PRELOADED | grep 'PEM certificate$' \ | |
|| { echo >&2 "❌ attestation issuer certificate expected as third argument"; exit 1 ; } | |
# Yubico YubiHSM CA certificates | |
SUBCA=E45DA5F361B091B30D8F2C6FA040DB6FEF57918E.pem | |
ROOTCA=yubihsm2-attest-ca-crt.pem | |
# download if missing | |
curl -s -o $SUBCA -z yubihsm-subca.pem https://developers.yubico.com/YubiHSM2/Concepts/E45DA5F361B091B30D8F2C6FA040DB6FEF57918E.pem | |
curl -s -o $ROOTCA -z yubihsm2-attest-ca-crt.pem https://developers.yubico.com/YubiHSM2/Concepts/yubihsm2-attest-ca-crt.pem | |
openssl x509 -noout -fingerprint -sha256 -in $ROOTCA | grep -q 09:4A:3A:C4:93:C2:BD:CD:65:A5:4B:DF:40:19:0F:52:BB:03:F7:15:63:97:A3:FC:69:D8:AA:9A:39:2F:B7:24$ \ | |
|| { echo >&2 "❌ YubiHSM 2 Root CA fingerprint mismatch"; exit 1; } | |
# 0. check if CSR parses and has a correct signature | |
openssl req -in $CSR -noout -verify \ | |
|| { echo >&2 "❌ cannot verify $CSR"; exit 1; } | |
# 1. check if public key in CSR matches public key in attestation certificate: | |
cmp -s \ | |
<(openssl req -noout -in $CSR -pubkey) \ | |
<(openssl x509 -noout -in $ATTESTATION -pubkey) \ | |
|| { echo >&2 "❌ public key in $CSR does not match public key in $ATTESTATION"; exit 1; } | |
# 2. Validate CA chain | |
echo -n "CA path validation for " | |
openssl verify \ | |
-untrusted $PRELOADED \ | |
-untrusted E45DA5F361B091B30D8F2C6FA040DB6FEF57918E.pem \ | |
-CAfile yubihsm2-attest-ca-crt.pem \ | |
$ATTESTATION \ | |
|| { echo >&2 "❌ cannot validate $ATTESTATION"; exit 1; } | |
# 3. Parse attestation certificate | |
json=$(yubihsm-parse-attestation --format json $ATTESTATION) \ | |
|| { echo >&2 "❌ cannot parse $ATTESTATION"; exit 1; } | |
echo Attestation: | |
echo $json | jq -c \ | |
|| { echo >&2 "❌ cannot parse JSON from attestation"; exit 1; } | |
# optional - check firmware | |
echo -n Checking firmware version... | |
FW=$(echo $json | jq -r '.device.firmware') | |
if [[ "$FW" > "2.4.1" ]]; then | |
echo >&2 "❗ this script is only tested with versions 2.2 and 2.4 of YubiHSM 2 FIPS firmware" | |
fi | |
echo -n Checking FIPS certificate... | |
openssl asn1parse -in preloaded.pem | grep 1.3.6.1.4.1.41482.4.10 -A1 | tail -1 | egrep -o 0201[0-9]+$ | |
# 020106 = https://csrc.nist.gov/projects/cryptographic-module-validation-program/certificate/3916 | |
# 020109 = pending, see https://csrc.nist.gov/projects/cryptographic-module-validation-program/modules-in-process/modules-in-process-list | |
# 4. check CA/B forum requirements for code signing | |
# FIPS approved mode is OID is available since fw 2.4.1 | |
if [[ "$FW" > "2.4.0" ]]; then | |
echo -n Checking FIPS status... | |
echo $json | jq -e .key.fips \ | |
|| { echo >&2 "❗ YubiHSM 2 not in FIPS approved mode"; } | |
fi | |
echo -n Checking origin... | |
echo $json | jq -e 'select(.key.origin == ["generated"]) | . != {}' \ | |
|| { echo >&2 "❌ signing key not generated on YubiHSM 2"; exit 1; } | |
echo -n Checking capabilities... | |
echo $json | jq -e '[.key.capabilities[]!="exportable_under_wrap"] | all' \ | |
|| { echo >&2 "❌ key is exportable"; exit 1; } | |
echo -n Checking signing key/algorithm... | |
echo $json | jq -e 'select(.key.algorithm == "RSA" and .key.size == (3072,4096) or .key.algorithm=="ECDSA" and .key.curve == ("P-256","P-384","P-521")) | . != {}' \ | |
|| { echo >&2 "❌ key/algorithm not allowed"; exit 1; } | |
echo "✅ CA/B forum code signing requirement checks passed" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment