HSM custody and certification practice
How AuthFI's hardware-rooted PKI certifies project signing keys, the policy OIDs it uses, and how to verify a key chains to AuthFI Root CA R1.
AuthFI certifies every signing key it holds for a project. Each key carries a custody certificate that chains to a root whose private key never leaves a hardware security module (HSM). A relying party can check the chain itself, with openssl and the root certificate on this page.
This page is the Certification Practice Statement (CPS) for that chain. It is the address named in the certificatePolicies extension of every custody certificate, under policy 1.3.6.1.4.1.67322.1.1.
The chain
AuthFI Root CA R1 offline root, key in an HSM
└── regional intermediate CA one per AuthFI region, key in an HSM
└── custody certificate one per project signing keyThe root signs an intermediate only in a recorded ceremony that needs approval before it runs. Each region has its own intermediate, so a region's certificates cannot vouch for names outside it.
Which keys are certified
Every signing key the key service holds for a project has a custody certificate issued by its region's intermediate:
- Token signing keys
- SAML signing keys
- AI agent token keys
- A project's own certificate authority
The certificate is signing-only. It cannot issue certificates and cannot be used for encryption. Project keys at rest are sealed under the region's HSM-held master key. See Keys and secrets for the keys a project has and how to rotate them.
Certificate policies
AuthFI's IANA Private Enterprise Number is 67322. Its certificate policies are defined under the arc 1.3.6.1.4.1.67322.1.
Custody certificates carry 1.3.6.1.4.1.67322.1.1, and a CPS qualifier that points to this page.
Verify a key
The JSON Web Key Set (JWKS) of a project at https://acme.authfi.io/.well-known/jwks.json publishes the chain with each key.
SAML metadata carries the same chain in the X509Data of its signing key.
Check the chain
Save the root certificate from below as root.pem. Then take a key's chain from the JWKS and verify it:
KID="<kid of the key>"
curl -s https://acme.authfi.io/.well-known/jwks.json > jwks.json
for i in 0 1; do
jq -r --arg kid "$KID" --argjson i "$i" \
'.keys[] | select(.kid==$kid) | .x5c[$i]' jwks.json \
| base64 -d | openssl x509 -inform der -out "cert$i.pem"
done
mv cert0.pem leaf.pem && mv cert1.pem intermediate.pem
openssl verify -x509_strict -CAfile root.pem -untrusted intermediate.pem leaf.pemleaf.pem: OKReplace <kid of the key> with the kid from the token header you are checking.
Check the thumbprint and the policy
openssl x509 -in leaf.pem -outform der | openssl dgst -sha256 -binary | openssl base64 -A | tr '+/' '-_' | tr -d '='
openssl x509 -in leaf.pem -noout -text | grep -A2 "Certificate Policies"The first command prints the value of x5t#S256 for that key. The second prints policy 1.3.6.1.4.1.67322.1.1 and the address of this page.
The root certificate
AuthFI Root CA R1 is a public trust anchor. Before you trust a copy, compare its SHA-256 fingerprint with the one below.
-----BEGIN CERTIFICATE-----
MIICGjCCAaCgAwIBAgIUE2P3qmlsWcUngRFGLj6BqKFRQzIwCgYIKoZIzj0EAwMw
SjELMAkGA1UEBhMCSU4xHzAdBgNVBAoTFkF1dGhGSSBQcml2YXRlIExpbWl0ZWQx
GjAYBgNVBAMTEUF1dGhGSSBSb290IENBIFIxMCAXDTI2MTAyNDEyNTMyNloYDzIw
NTExMDI0MTI1MzI2WjBKMQswCQYDVQQGEwJJTjEfMB0GA1UEChMWQXV0aEZJIFBy
aXZhdGUgTGltaXRlZDEaMBgGA1UEAxMRQXV0aEZJIFJvb3QgQ0EgUjEwdjAQBgcq
hkjOPQIBBgUrgQQAIgNiAATkjJGz3+80qIxSKrDy+r+dY+IOHW86ae42drb/SRI+
c3CetA/YLcHnc5jcnQz4ZEW/HtEhw7c3v27DyrN8bIhcZV4o/kNYH2lM+I9UVJV1
XN3B5m0mzzfAUr5wwGQCfZ+jRTBDMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8E
CDAGAQH/AgECMB0GA1UdDgQWBBSXy3ETwQDsWL3L3GCbnABT/SiqLTAKBggqhkjO
PQQDAwNoADBlAjBbXTVqVfSMVexqVgV7oIWwVp7AE2GqTOk0kH4UG/2ZPTEKcdrv
pBo27FMKva+QfgsCMQCFUAceFHpiuQd5BijHKgTtM5P+sfzLWOujBU05lHgvorDj
qLTdomlO6xF2s/+PAP4=
-----END CERTIFICATE-----Print the fingerprint of your copy:
openssl x509 -in root.pem -noout -fingerprint -sha256sha256 Fingerprint=D9:C2:A9:C7:0A:A8:53:AC:01:D3:B2:E3:D4:50:51:28:AB:28:E2:78:18:27:79:5D:25:C9:0A:CF:1D:BA:1B:54