Skip to content

feat(pki): HSM-backed sub-CA - CSR generation and oracle signing of certificates, CRLs and OCSP - #1328

Open
Manuthor wants to merge 8 commits into
developfrom
fix/csr_gen
Open

Manuthor wants to merge 8 commits into
developfrom
fix/csr_gen

Conversation

@Manuthor

Copy link
Copy Markdown
Contributor

Summary

Lets an online KMS run a delegated (sub) CA whose private key never leaves the HSM, with an offline root signing the sub-CA CSR using its own HSM key. Full rationale: documentation/adr/2026-10-23-hsm-backed-sub-ca-csr-and-oracle-signing.md.

Server

  • CSR generation: new POST /certificates/csr. The CSR is signed by the HSM through the crypto oracle and needs only the Sign permission on the key. An extractable HSM key is refused.
  • Oracle signing: Certify/ReCertify, GenerateCrl and the OCSP responder sign HSM CA keys through the crypto oracle. The structure is built with a placeholder key, re-signed by the HSM, and verified against the real public key before use.
    • Algorithms: RSA and EC (SHA-256) and, in non-FIPS builds, Ed25519/Ed448 (raw TBS).
    • ML-DSA/SLH-DSA HSM CA keys remain unsupported (no PQC key types in the HSM layer).
  • CRL regeneration: CrlRequester::{User, Server}. Post-Revoke and cron regeneration reads the issuer certificate directly, and the signing key is authorized as the issuer certificate's owner (never the caller). For hsm:: keys that owner still needs a grant or HSM-admin rights (documented as NEG-002).
  • Self-signed HSM root: certifying an HSM public key <sk>_pk derives <sk> as the private-key link, for both issuer lookup and the certificate's PrivateKeyLink.
  • OCSP fix: verify_issuer_hashes_match_ca answered unauthorized for every non-self-signed CA, because it hashed the CA's issuer name. It now hashes the CA's own subject, so OCSP works for sub-CAs (HSM or not).
  • _serial=<HEX> tag: added to every stored certificate (Certify, ReCertify, Import, Register, PKCS#12). Existing certificates are backfilled once at startup on SQLite, PostgreSQL, MySQL/MariaDB and Redis-Findex, gated by a marker. The SQL inserts are conflict-tolerant so multi-node starts are safe.
  • SCEP still returns NotSupported for a sensitive HSM CA key; EST works.

CLI

  • ckms certificates generate-csr (+ regenerated CLI docs).

UI

  • Certificates > Generate CSR page, with en/fr/zh-CN translations and a Playwright spec.
  • Includes a prettier reformat of ui/src/utils/utils.ts required by the format hook.

Docs

  • ADR, use-case guide use_cases/pki-sub-ca-csr.md, changelog entry, log reference.

Behaviour changes

  • Every hsm:: issuer key (including non-sensitive ones that used to be exported) now signs through the oracle for Certify, ReCertify, CRL and OCSP. HSM CA keys other than RSA/EC/Ed25519/Ed448 are rejected with NotSupported; a P-384 HSM CA signs ecdsa-with-SHA256.
  • One-time _serial= tag write on the first start after upgrade.

Verification

  • Unit and server tests (FIPS and non-FIPS): oracle_signing, sub_ca_tests, crl_tests, revoke_tests, enrollment_tests, certify, OCSP, test_validate, plus a crypto unit test for the sub-CA OCSP hash fix.
  • HSM scenario test_hsm_all on SoftHSM2 (FIPS and non-FIPS): HSM root, sub-CA CSR, leaf, CRL, Ed25519 sub-CA, and OCSP good/revoked signed by the HSM.
  • Database tests on live PostgreSQL, MySQL and Redis containers: test_db_postgresql (+ multihost, failover), test_db_mysql, test_db_redis_with_findex.
  • Clippy clean in both modes.

Not covered

  • Only SoftHSM2 was run, not the other HSM vendors.
  • The serial-tag backfill is tested with a seeded legacy certificate on SQLite and Redis only; on PostgreSQL and MySQL it ran against an empty certificate set.
  • pgsql::tests::test_db_postgresql_tls_sslmode_matrix was not run successfully (needs a TLS server).

@Manuthor
Manuthor deployed to xks-remote-approval October 23, 2026 08:00 — with GitHub Actions Active
…A keys

- add POST /certificates/csr: PKCS#10 CSR signed by the HSM through the crypto
  oracle (Sign permission only, non-extractable key)
- Certify/ReCertify, GenerateCrl and the OCSP responder sign HSM CA keys through
  the oracle (RSA, EC, Ed25519/Ed448 non-FIPS) and verify the signature
- CrlRequester: server-triggered CRL regeneration reads the issuer certificate
  directly and authorizes the key as the certificate owner
- self-signed HSM public key keeps its private key link
- fix OCSP issuer hash check for sub-CAs
- add _serial=<HEX> certificate tag, backfilled once at startup on all backends
- ADR, use-case doc and changelog
Generate a PKCS#10 CSR for a private key held by the KMS through
POST /certificates/csr; HSM keys sign inside the HSM.
Generate a PKCS#10 CSR for a KMS-held private key (HSM keys sign inside the
HSM), with en, fr and zh-CN translations and a Playwright spec. Includes the
prettier reformatting of ui/src/utils/utils.ts required by the format hook.
ctutils 0.4.2 (via crypto-bigint -> k256 -> cosmian_kms_crypto) may compile
const-fn mask generation to a branch; fixed in 0.4.4. Lock-only bump, new
cargo-vet exemption for 0.4.5 (the 0.4.2 one is pruned).
POST /certificates/csr signed with Deactivated or not-yet-active keys, while
Sign and Certify refuse them. Also correct the changelog (EST is unaffected,
Ed448 supported), the openapi error codes and a revoke.rs comment.
…icKeyLink

Adversarial review: the user-settable PublicKeyLink of the private key was
followed without an access check and leaked another user's object attributes
in the error; a key without the Sign usage could still sign; KEM keys
(X25519, ML-KEM) returned a 5xx. Database keys now derive the public key from
the private key, HSM keys use <id>_pk.
…tion

Other OpenSSL signing failures are server faults and propagate unchanged.
Adds the X25519 regression test.
@Manuthor
Manuthor deployed to xks-remote-approval October 23, 2026 20:20 — with GitHub Actions Active

This branch was successfully deployed

1 active deployment
xks-remote-approval — a26130de Deployed Oct 23, 2026 by Manuthor via main / test / AWS XKS — remote server #9371
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant