# 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

```text
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 key
```

| Certificate                                          | Held by                          | Constraints                                                                         |
| ---------------------------------------------------- | -------------------------------- | ----------------------------------------------------------------------------------- |
| AuthFI Root CA R1 (`C=IN, O=AuthFI Private Limited`) | An HSM. The key never leaves it. | Signs intermediate CAs only                                                         |
| Regional intermediate CA                             | An HSM in its region             | Name-constrained to the names that region serves                                    |
| Custody certificate                                  | The key service of the region    | `keyUsage` `digitalSignature`, `CA:FALSE`. Lives 90 days, renewed before it expires |

The 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](/security/keys) 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`.

| OID                     | Policy                                                                      |
| ----------------------- | --------------------------------------------------------------------------- |
| `1.3.6.1.4.1.67322.1.1` | Key held in AuthFI custody, certified under the HSM-rooted chain            |
| `1.3.6.1.4.1.67322.1.2` | Key resident in a hardware security module (the root and the intermediates) |
| `1.3.6.1.4.1.67322.1.3` | Key held by its subject                                                     |

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.

| JWK member | Value                                                                  |
| ---------- | ---------------------------------------------------------------------- |
| `x5c`      | `[custody certificate, regional intermediate]`, base64 DER, leaf first |
| `x5t#S256` | Base64url SHA-256 thumbprint of the first certificate in `x5c`         |

SAML metadata carries the same chain in the `X509Data` of its signing key.

### Check the chain

Save the root certificate from [below](#the-root-certificate) as `root.pem`. Then take a key's chain from the JWKS and verify it:

```bash
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.pem
```

```text
leaf.pem: OK
```

Replace `<kid of the key>` with the `kid` from the token header you are checking.

### Check the thumbprint and the policy

```bash
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.

| Field               | Value                                                                                             |
| ------------------- | ------------------------------------------------------------------------------------------------- |
| Subject and issuer  | `C=IN, O=AuthFI Private Limited, CN=AuthFI Root CA R1`                                            |
| Valid               | 24 October 2026 to 24 October 2051                                                                |
| SHA-256 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` |

```text
-----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:

```bash
openssl x509 -in root.pem -noout -fingerprint -sha256
```

```text
sha256 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
```

## Next steps

<Cards>
  <Card href="/security/keys" title="Keys and secrets">
    The keys a project has, and how to rotate or disable one.
  </Card>
  <Card href="/reference/tokens" title="Tokens and claims">
    Which key signs each kind of token.
  </Card>
</Cards>
