← Week 1: HSM fundamentals + PKCS#11

Day 5: Key Ceremony — Offline Root CA and Quorum Control

Phase 5 · August 30, 2026

← Week 1: HSM fundamentals + PKCS#11

Agenda (2–3 hours)

  • Read (45 min): Mozilla CA Certificate Policy §5; NIST SP 800-57 Part 1 §8 (key management)
  • Study (45 min): What a real CA key ceremony looks like
  • Build (60 min): hsm-demo key-ceremony subcommand — simulated offline root
← Week 1: HSM fundamentals + PKCS#11

What Is a Key Ceremony?

A key ceremony is the controlled, witnessed procedure for:

  1. Generating a CA root private key
  2. Activating the CA (installing the key into the HSM or signing a self-signed cert)
  3. Establishing quorum (m-of-n control — N key custodians, M required to operate)
  4. Documenting every step (audit log, video recording, witness signatures)
  5. Destroying the generation medium (if generating offline)

The ceremony creates the root of trust for your entire PKI.
If it is compromised, the entire hierarchy is compromised.

← Week 1: HSM fundamentals + PKCS#11

Why Offline Root?

A root CA should never be online. Reasons:

Online root Offline root
Network-accessible → can be attacked Air-gapped → physical access required
Issues certs directly → high exposure Only signs subordinate CA certs → low frequency
If compromised → all certs invalid immediately If compromised → time to respond before revocation cascades

The pattern:

[Offline Root CA]   ← never connects to a network; stored in vault
    │ signs once
[Online Subordinate CA]   ← connects to networks; issues certs
    │ signs frequently
[Issuance CA / ACM PCA]   ← issues leaf certs on demand

The offline root signs the subordinate CA cert once, then goes back in the vault.

← Week 1: HSM fundamentals + PKCS#11

m-of-n Quorum: Shamir's Secret Sharing

An HSM or offline root can require m-of-n key shares to activate:

The CA private key is split into 5 shares (n=5).
Any 3 shares (m=3) are sufficient to reconstruct the key.
Each share is held by a different key custodian (different people, different locations).

To perform a CA operation:
  - At least 3 custodians must be present
  - Each inserts their smart card / USB token
  - The HSM reconstructs the key internally and performs the operation

This prevents a single person from unilaterally operating the root CA.

For AWS CloudHSM: quorum authentication uses PKCS#11 + smart cards.
For ACM PCA root: AWS manages quorum internally (you don't hold shares).

← Week 1: HSM fundamentals + PKCS#11

Real Ceremony Procedure (Simplified)

1. Pre-ceremony:
   - Identify m-of-n custodians; distribute roles (CRO, key custodians, witnesses)
   - Prepare air-gapped laptop; verify OS image hash
   - Prepare HSM or smart cards; initialize tokens
   - Prepare ceremony script (step-by-step with expected outputs)

2. At ceremony:
   - All participants present; sign attendance sheet
   - Boot air-gapped machine; verify no network interfaces
   - Initialize PKCS#11 token; generate CA key (CKA_EXTRACTABLE = false)
   - Generate CA self-signed certificate; verify subject, validity, key usage
   - Export CA certificate (public only); sign with each custodian's key
   - Create quorum shares using Shamir's Secret Sharing (or HSM m-of-n auth)
   - Distribute shares to custodians; custodians sign receipt

3. Post-ceremony:
   - Store HSM in physical vault; log entry
   - Distribute signed CA certificate to downstream PKI components
   - Schedule next activation (e.g., to sign a new subordinate CA)
← Week 1: HSM fundamentals + PKCS#11

Simulating the Ceremony in hsm-demo

// src/ceremony.rs
// This is a SIMULATION — no real quorum, no real air-gap
// Purpose: understand the sequence of PKCS#11 calls a ceremony performs

pub async fn run_key_ceremony(
    pkcs11: &Pkcs11,
    slot: cryptoki::slot::Slot,
    pin: &str,
) -> anyhow::Result<()> {
    println!("=== SIMULATED ROOT CA KEY CEREMONY ===");
    println!("WARNING: This is a software simulation. Not for production use.");
    println!();

    // Step 1: Generate root CA key pair
    println!("[Step 1] Generating root CA key pair in token...");
    let (pub_handle, _priv_handle) = generate_ceremony_key(pkcs11, slot, pin)?;
    println!("  ✓ Key pair generated (CKA_EXTRACTABLE=false)");

    // Step 2: Export public key for certificate generation
    println!("[Step 2] Exporting public key for self-signed cert generation...");
    // ... export EC_POINT, build rcgen cert params, sign with HSM

    // Step 3: Simulate quorum share creation
    println!("[Step 3] Simulating m-of-n share creation (3-of-5)...");
    // ... in production: use shamir crate or HSM m-of-n auth

    println!("\n=== CEREMONY COMPLETE ===");
    Ok(())
}
← Week 1: HSM fundamentals + PKCS#11

Building the Ceremony Certificate

// Use rcgen to create the self-signed root cert, but sign with the HSM key
use rcgen::{Certificate, CertificateParams, DistinguishedName, DnType, IsCa};

let mut params = CertificateParams::default();
params.is_ca = IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
params.distinguished_name.push(DnType::CommonName, "Ceremony Root CA (Simulated)");
params.not_after = time::OffsetDateTime::now_utc() + time::Duration::days(3650);

// Problem: rcgen expects a KeyPair, but our key is in the HSM.
// Solution: use rcgen's custom signing support or sign externally.
// For this exercise: generate the TBSCertificate with rcgen,
// then call C_Sign via cryptoki to sign it, then assemble the cert.
// This mirrors what a real CA implementation does.

// Alternatively: use the `openssl` crate with the PKCS#11 engine
// (see Day 6 for the OpenSSL + CloudHSM pattern)

The asymmetry between "generate cert params" and "sign with HSM key" is
a real engineering challenge in CA software — Day 5 introduces it; Day 6
looks at how CloudHSM/ACM PCA solve it at scale.

← Week 1: HSM fundamentals + PKCS#11

Challenge Assignment

Build hsm-demo key-ceremony:

  1. Generate an ECDSA P-256 key pair in SoftHSM2 with label root-ca-key

    • CKA_EXTRACTABLE = false, CKA_SENSITIVE = true, CKA_TOKEN = true
  2. Export the public key (CKA_EC_POINT)

  3. Print a ceremony transcript to stdout:

    [Step 1] Key pair generated: label=root-ca-key, algo=EC/P-256
    [Step 2] Public key (hex): 04abcd...
    [Step 3] Simulated 3-of-5 quorum shares created (shares not real)
    [Step 4] Ceremony complete. Store HSM in vault.
    
  4. Verify with softhsm2-util --show-objects --pin 123456 that the key exists
    and has CKA_SENSITIVE = true

Bonus: read and document the softhsm2-util --export behavior — can you export
the private key? What attribute controls this?

← Week 1: HSM fundamentals + PKCS#11

Resources

  • Mozilla CA Certificate Policy §5: wiki.mozilla.org/CA/Root_Store_Policy
  • NIST SP 800-57 Part 1: doi.org/10.6028/NIST.SP.800-57pt1r5 — §8 "Key management"
  • Shamir's Secret Sharing: shamir Rust crate on crates.io
  • Real CA ceremony video: search "CA key ceremony" on YouTube — DigiCert and Let's Encrypt both publish theirs