# Multi-CA Certificate Authority System: Architecture Modeled on the US DoD PKI and the Federal PKI. Every structural claim about how DoD does it is cited to a document in [source-documents.md](source-documents.md). --- ## 0. The idea worth copying The interesting thing about the DoD PKI is not its cryptography. It is that **policy is the product**. Concretely: 1. One **Certificate Policy (CP)** document defines *several named policies*, each with its own OID and its own set of requirements (identity proofing, key protection, module validation level). 2. Any CA, including CAs the DoD does not operate, is admitted to the trust fabric by writing a **Certification Practice Statement (CPS)**, having it approved, passing a compliance audit, and being issued a CA certificate that **carries the policy OIDs it is permitted to assert**. 3. Relying parties do not authorize on "did the chain validate." They authorize on **which policy OID survived path validation**. A signature made under `medium` is not accepted where `mediumHardware` is required, even though both chain to the same root. That third point is the whole design. RFC 5280 path validation computes a *valid policy tree*; the `requireExplicitPolicy` and `policyMappings` constraints in CA certificates are what make the tree meaningful across organizational boundaries. If you build multiple CAs without policy OIDs, you have built multiple CAs that are all equally trusted, which is usually worse than having one. Three separable layers follow, and this document is organized around them: | Layer | Question it answers | DoD instrument | |---|---|---| | **Governance** | Who is allowed to be a CA, and how do we throw one out? | PMA, CP, CPS, compliance audit | | **Topology** | How many roots and issuing CAs, split along what axes? | Root CA 3/5/6, IRCAs, ID/EMAIL/SW CAs | | **Enforcement** | How does a relying party actually get a different answer for different CAs? | Policy OIDs, name constraints, path length, EKU | --- ## 1. Governance ### 1.1 Policy Management Authority (PMA) A standing body, not a person, that: - owns the CP and approves changes to it via a consensus process across the organizations that consume the PKI; - reviews and approves each CA operator's CPS against the CP before that CA is issued a certificate; - reviews compliance-audit results and directs corrective action, up to and including revoking a CA's certificate; - decides whether an *external* policy is good enough to be mapped to one of ours (this is the cross-certification decision); - advises system owners on which policy OIDs are appropriate for which application. In DoD, decision authority sits with the DoD CIO's office and can be delegated (CP §1.3). Give yours a named accountable executive and a written charter; a PMA that cannot say "no" to a business unit is decorative. **Terminology worth stealing:** DoD calls CAs and RAs collectively **CMAs** (Certificate Management Authorities) so that requirements can be written once and apply to both (CP §1.3). Adopt this; it removes a lot of duplicated policy text. ### 1.2 Document set | Document | Count | Contents | |---|---|---| | Certificate Policy (CP) | **one** | RFC 3647 9-section outline. Defines every policy OID and its requirements. Public. | | Certification Practice Statement (CPS) | **one per CA operator** | How *this* operator meets the CP. May be sensitive; publish an abridged version (ECA CP §2.2 requires exactly this). | | Certificate & CRL Profiles | **one per network/domain** | Normative field-by-field tables. See [profiles.md](profiles.md). | | Interoperability Plan | one | Criteria and process for admitting an external PKI. | | Approved External PKI register | one, living | Which external PKIs are trusted, at what assurance, tested when. | | Key Recovery Policy / Practice Statement | one each | Only if you escrow encryption keys. | The CP/CPS split is the mechanism that lets you have many CAs run by *different organizations* without writing many policies. Do not let CA operators fork the CP. ### 1.3 Admission and expulsion A CA joins the fabric only after: CPS approved → key ceremony witnessed → initial compliance audit → CA certificate issued with a constrained policy OID set. It leaves by having that certificate revoked and the revocation propagated within the CRL latency budget in §8. Because expulsion is *just revocation of one intermediate*, keeping issuing CAs small and numerous (§3) is what makes expulsion survivable. --- ## 2. Trust anchor topology: why more than one root DoD runs **several unrelated self-signed roots simultaneously**. From the NIPRNet profiles doc §1.1, the current scope alone contains: - four DoD PKI roots split purely by algorithm: RSA-2048/SHA-256, EC P-256/SHA-256, EC P-384/SHA-384, and RSA-3072&4096/SHA-384; - a **Federal PKI Interoperability Root CA (IRCA)** whose only job is cross-certification with the Federal PKI; - a **CCEB IRCA** for allied-partner cross-certification; - an **NPE PKI** root for device certificates; - a **Special Devices Root CA** that issues to devices *directly*, with no intermediate; - a separate **Internal NPE root**, and, per CP §1.2, *a separate Internal NPE root per network classification level*; - the **ECA Root CA** (4 and 5), a sponsored program for external commercial issuance; - a Web Content Filtering PKI root (TLS interception), kept entirely separate. ### The rule behind that list > **A root is a blast-radius and trust-decision boundary, not an org chart node.** Split roots along axes where you would ever want to *distrust one and keep the others*, or where a relying party population differs: | Split axis | Why | DoD instance | |---|---|---| | **Cryptographic suite** | You cannot migrate algorithms inside one hierarchy without breaking path building. Stand up a parallel root, dual-issue, then retire. | RSA-2048 root vs. P-384 root vs. RSA-4096 root | | **Assurance floor** | Internal-NPE certs have *no* multi-person control and *no* activation data (CP §6.2.2, §6.4.1). Mixing them under a human-identity root would let a device CA mint person credentials. | Internal NPE root, mandated separate | | **Network / classification** | A SIPRNet compromise must not implicate NIPRNet. | Separate CP and roots for the SIPRNet interoperability domain | | **Interoperability** | Cross-certs are the highest-risk certificates you issue. Isolate them so your own subscribers' chains never traverse them. | FPKI IRCA, CCEB IRCA | | **Sponsored external issuance** | Vendors issuing under your policy, to your audit, but not your operations. | ECA Root CA 4 / 5 | | **Purpose that must never be conflated** | TLS-interception CAs must not be able to sign anything else. | Web Content Filtering PKI | ### Recommended starting root set For a greenfield build, four roots is a reasonable floor: ``` R1 Root CA - Human/Org, EC P-384 + SHA-384 (offline, 25y) R2 Root CA - Device/NPE, EC P-256 + SHA-256 (offline, 25y) R3 Interoperability Root CA (offline, 25y); cross-certs only, both directions R4 Root CA - Human/Org, ML-DSA-65 or hybrid (offline, 25y); the migration target, see §11 ``` `R1`/`R2` split by assurance floor; `R3` isolates federation; `R4` exists so that algorithm migration is a *distribution* problem (ship a new trust anchor) rather than a *reissuance* problem. Add a classification/network axis only if you actually operate separated networks. **Roots are offline.** Powered down, HSM in a safe, brought up only for a witnessed ceremony: issuing an intermediate, issuing a cross-certificate, or signing a CRL. DoD root CRLs are issued **at least every 28 days** (CP §4.9.7); that cadence is what makes an offline root operationally possible, and it is the number you should design your ceremony calendar around. --- ## 3. Issuing CA tier Under `R1`, DoD does not run one CA. It runs a numbered series, split by credential type: ``` DoD Root CA 3 ├── DOD ID CA-62 ┐ ├── DOD EMAIL CA-62 │ identity + email pair, per batch ├── DOD ID CA-63 │ ├── DOD EMAIL CA-63 ├─ ... through -65, -71 ├── DOD SW CA-66 │ software/code signing ├── DOD SW CA-67 │ ├── DOD SW CA-75 │ └── DOD DERILITY CA-1 ┘ derived credentials ``` (Names taken verbatim from the Approved External PKIs master document §2.) Three reasons to do this, in order of importance: 1. **Containment by capability.** The EMAIL CA's certificate does not carry the code-signing policy OID, and its profile does not permit the code-signing EKU. Compromising it does not yield a code-signing key. This is the *same* mechanism as the root split, one level down and finer-grained. 2. **Revocation-set partitioning.** A CRL is a single signed list. Ten million subscribers under one CA is a CRL nobody can fetch. Splitting into CA-62…CA-71 partitions the CRL by construction, with no need for `IssuingDistributionPoint` games. This is why the numbers increment: **you retire a full CA and stand up the next rather than growing one forever.** 3. **Cleaner key rollover.** Retiring CA-64 and starting CA-65 is a routine, rehearsed operation, so nobody is afraid of it when it is not routine. ### Parameters | | Root | Issuing CA | Cross-certificate | |---|---|---|---| | Validity | **≤ 25 y** (DoD permits ≤30 y, profile Table 1) | **≤ 6 y** (Table 5) | **≤ 3 y** (Table 2) | | `basicConstraints` | `cA=TRUE`, **pathLen absent** | `cA=TRUE`, **pathLen=0** | `cA=TRUE`, pathLen per agreement | | `keyUsage` (critical) | `keyCertSign, cRLSign` | `keyCertSign, cRLSign` | `keyCertSign, cRLSign` | | `policyConstraints` | - | `requireExplicitPolicy: skipCerts=0` | `requireExplicitPolicy: 0` (critical) + `inhibitPolicyMapping: 0` | | `nameConstraints` | - | optional | **critical, required** | | CRL cadence | ≥ every 28 days | **≥ daily** | per issuer | `pathLen=0` on every issuing CA is not decoration; it is the statement "this CA can issue end-entity certificates and nothing else," enforced by every RFC 5280 validator. Combined with `requireExplicitPolicy: skipCerts=0`, an issuing CA cannot silently widen the policy set below it. --- ## 4. Federation tier: the CAs you do not operate This is where "multiple certificate authorities" gets interesting, and DoD uses **three distinct patterns** for three distinct relationships. Do not collapse them. ### 4.1 Pattern A: Cross-certification via a dedicated Interoperability Root An IRCA is a root whose *only* function is to issue cross-certificates outward and hold them inward. Your own subscribers never chain through it. If a cross-certified partner turns out to be untrustworthy, you revoke one certificate at the IRCA and your internal trust fabric is untouched. Every cross-certificate you issue carries, per DoD profile Table 2: ``` Validity ≤ 3 years basicConstraints c=yes; cA=TRUE; pathLen per the cross-certification agreement certificatePolicies c=no; only the OIDs named in the agreement, nothing else policyMappings c=no; only the mappings named in the agreement policyConstraints c=YES; requireExplicitPolicy skipCerts=0 inhibitPolicyMapping skipCerts=0 (unless transitive trust is intended) nameConstraints c=YES; permitted/excluded subtrees for DN, rfc822Name, dNSName, URI, UPN AIA caIssuers HTTP + id-ad-ocsp HTTP CRLDP HTTP, full and complete CRL ``` Three of those lines carry almost all the risk reduction: - **`nameConstraints`, critical.** Without it, a cross-certified partner CA can issue a certificate for *your* names. Assert it for every name form you actually use: DN, email, DNS, UPN. The DoD profile requires it for exactly those four. - **`inhibitPolicyMapping: 0`.** By default, cross-certification is *transitive*: if you trust A and A cross-certifies B, you trust B. Setting `skipCerts=0` stops the mapping at A. Turn transitivity on only deliberately. - **`requireExplicitPolicy: 0`.** Forces every certificate below this point to assert an acceptable policy. Without it, `anyPolicy` leaks through and your policy tree collapses. A **bridge** (like the FBCA) is this pattern with a hub: rather than n² bilateral cross-certificates, everyone cross-certifies the bridge and policies are mapped through it. GSA's FPKI 101 is explicit that the bridge is *not* a root of trust; it creates transitive trust by policy mapping. Only worth it above roughly 5–6 peers. ### 4.2 Pattern B: Sponsored external CAs (the ECA model) The **External Certification Authority** program is the most directly reusable idea here for a commercial multi-CA build. Its shape: - **You own the root.** `ECA Root CA 4` and `ECA Root CA 5` are DoD-operated. - **Vendors operate the issuing CAs beneath it.** Currently two (IdenTrust and WidePoint) each with issuing CAs like `CN=WidePoint ECA 9` and `CN=IdenTrust ECA S24`. Two vendors, not one: competition, and survivable vendor failure. - **They operate under *your* CP,** not their own. The ECA CP is a DoD document. - **The hierarchy is flat and enforced:** "ECAs implementing this CP shall not certify other CAs with the exception of the ECA Root CA. The ECA Root CA shall only certify ECAs." (ECA CP §4.1.) Two levels, no surprises. - **Only the root cross-certifies outward** (to the FBCA), and only on PMA approval. Use this when you need issuance capacity or reach you do not want to operate (partner onboarding, a different geography, a different customer segment) but you refuse to outsource the trust decision. ### 4.3 Pattern C: Graded acceptance of foreign PKIs DoDI 8520.02 defines **six types** of approved external PKI, and the Approved External PKIs master document is the living register of who is in each: | Type | Population | Examples in the register | |---|---|---| | 1 | Federal Executive Branch department/agency PIV PKIs | Department of State PKI | | 2 | Federal Shared Service Provider PIV PKIs | Entrust Federal SSP, DigiCert Federal SSP, U.S. Treasury SSP, WidePoint SSP | | 3 | Commercial Medium Hardware PKIs | Boeing, Lockheed Martin, Raytheon, Exostar | | 4 | Commercial PIV-Interoperable PKIs | Northrop Grumman, Carillon, DigiCert NFI, Entrust NFI | | 5 | CCEB partner PKIs (allied militaries) | Australian Defence Organisation | | 6 | Other mission partner PKIs on unclassified networks | - | Admission requires cross-certification with the Federal PKI at **medium hardware assurance or higher** *and* passing interoperability testing at JITC. Every entry in the register carries a "date tested" and "date retested"; trust has an expiry and gets re-earned. The transferable pieces: (a) a **published taxonomy** of external trust tiers, so system owners choose a tier rather than negotiating per-partner; (b) a **register with retest dates**; (c) **independent interop testing** as an admission gate, separate from the paper audit. --- ## 5. Policy OID design DoD registers policies under `{joint-iso-ccitt(2) country(16) us(840) organization(1) gov(101) dod(2) infosec(1) certificate-policy(11)}` and assigns a leaf per policy (CP §1.2): ``` id-US-dod-medium-112 ::= {id-certificate-policy 39} id-US-dod-medium-128 ::= {id-certificate-policy 40} id-US-dod-medium-192 ::= {id-certificate-policy 41} id-US-dod-mediumHardware-112 ::= {id-certificate-policy 42} id-US-dod-mediumHardware-128 ::= {id-certificate-policy 43} id-US-dod-mediumHardware-192 ::= {id-certificate-policy 44} id-US-dod-mediumNPE-112/128/192 ::= {… 36, 37, 38} id-US-dod-internalNPE-112/128/192 ::= {… 60, 61, 62} id-US-dod-admin ::= {id-certificate-policy 59} id-US-dod-peerInterop ::= {id-certificate-policy 31} ``` Four design rules are visible in that list, and all four are worth copying. 1. **The OID encodes `(assurance level × cryptographic strength)`, as a flat product.** `medium-112`, `medium-128`, `medium-192` are three separate OIDs, not one OID plus a key-size field. A relying party that requires 128-bit security expresses that as a *policy OID set*, which path validation already computes for it. No custom certificate parsing. 2. **Never redefine an OID; deprecate it.** `{…5}` (`medium`) and `{…9}` (`mediumHardware`) are marked "included for historical purposes and no longer authorized for use in end-entity certificates," and the profiles doc lists them as *unacceptable* policies. Retiring an OID is a distribution problem you can solve. Silently changing what one means is not. 3. **Some OIDs are structurally reserved.** `peerInterop` appears *only* in cross-certificates, at PMA direction. `admin` goes only to designated system administrators. This gives you policy OIDs as a coarse authorization primitive. 4. **Foreign OIDs may be asserted directly.** DoD certificates assert Federal `id-fpki-common-authentication`, `id-fpki-common-cardAuth`, `id-fpki-common-piv-contentSigning` in the certificates that qualify; no policy mapping needed for those. And the cross-certificates issued to the ECA PKI assert ECA OIDs *directly* rather than mapping. Direct assertion is simpler than mapping; use mapping only when you cannot control the issuing side. ### Your arc Get an IANA Private Enterprise Number (free, ~2 weeks) and build under it: ``` 1.3.6.1.4.1..1 certificate policies .1.1 -medium-128 software key, remote proofing .1.2 -hardware-112 FIPS 140-3 L2 token, RSA-2048 (DoD CAC/ALT stock) .1.3 -hardware-128 FIPS 140-3 L2 token, EC P-256 .1.8 -hardware-192 FIPS 140-3 L2 token, EC P-384 .1.4 -device-128 NPE, sponsor-attested .1.5 -internal-device-128 NPE, no multi-person control, internal root only .1.6 -admin privileged operators .1.7 -peerInterop cross-certificates only 1.3.6.1.4.1..2 certificate extensions (if you must define any) 1.3.6.1.4.1..3 CPS qualifiers ``` Write the arc into the CP on day one, even if you launch with two policies. Adding OIDs is cheap; renumbering is not. ### Constraint that follows From the profiles doc §2.2: *an issuing CA shall not assert a policy in a subject certificate if the issuing CA's own certificate does not carry that OID.* Roots are exempt. Enforce this in your issuance software, not only in policy; it is the runtime check that makes §3's containment argument true. --- ## 6. Roles and separation of duties DoD's primary trusted roles are **CA**, **RA**, and **OCSP Responder**, plus mandated "other trusted roles": **System Administrator**, **Compliance Auditor**, **ISSO**, and **PKI Sponsor** (CP §5.2.1). | Role | Does | Must not | |---|---|---| | **CA** | Cert generation & revocation; publish certs and CRLs; DB backup; HSM management; escrow/recovery | Audit itself; hold ISSO or Auditor role | | **RA / LRA** | Verify identity; enter and check subscriber data; relay requests/responses; authorize key recovery | Be sysadmin/ISSO on any system where it holds RA authority | | **OCSP Responder** | Serve authenticated, current revocation status | - | | **PKI Sponsor** | Stand in as subscriber for a device, group, or role; carries subscriber obligations | - | | **System Administrator** | Install/configure; accounts; access control; backups; upgrades; recovery media | Audit | | **Compliance Auditor** | Run compliance audits | **Any other role, at all** | | **ISSO** | Archive/delete audit logs, review security audit log | **Any other role, at all** | Four rules from CP §5.2.4 that are cheap to implement and expensive to retrofit: - No one audits their own CMA. Ever. - Compliance Auditor and ISSO are **exclusive**: those people do nothing else on the CMA. - **"No individual shall have more than one identity on any CA, RA or OCSP Responder system."** This kills the usual dodge of holding a second account for the second role. - **"The CA, RA and OCSP Responder software and hardware shall enforce these role separations."** Not a checklist item but a product requirement. Pick a CA product that can actually express mutually exclusive roles, or you will be enforcing this with a spreadsheet. Trusted-role holders authenticate to PKI infrastructure with a certificate from the PKI itself (CP §5.2.3); remote administration *requires* it. Bootstrapping this is a real chicken-and-egg problem at launch; plan the sequence. --- ## 7. Key protection and ceremony From CP §6.1.5, §6.2.1, §6.2.2: **Modules.** | | Subscriber | RA / CA | OCSP Responder | |---|---|---|---| | Medium (software) | FIPS 140 **L1** | **L2 hardware** (L3 physical for CAs) | L2 hardware | | Medium Hardware | **L2 hardware** | **L2 hardware** (L3 physical for CAs) | L2 hardware | All certificate signing uses a hardware module validated at **overall Level 2 with Level 3 Physical Security**. Private asymmetric keys never leave a module in plaintext. Validate against **FIPS 140-3** for anything you procure now. **Multi-person control.** CA key *generation*, *activation*, and *backup* each require two trusted-role holders present. One must be a System Administrator; the other must **not** be the ISSO or Compliance Auditor. Two-person control also covers: access to disaster-recovery key backups, the CA/OCSP certificate request itself (key generation *and* delivery), and release of an escrowed key to a third party. The list of people used for two-person control is maintained and produced at audit. Note the deliberate carve-out: **Internal NPE CAs have no multi-person control requirement** (CP §6.2.2). That is the entire justification for giving them a separate root: the assurance floor is genuinely lower, so it is fenced off rather than allowed to dilute everything else. **Escrow.** CA private keys are never escrowed. Any key whose certificate asserts `digitalSignature` or `nonRepudiation` is never escrowed. *Encryption* keys are escrowed, to support data recovery, with two-person control on third-party release. Getting this distinction right is what lets you have both non-repudiation and data recovery; conflating signing and encryption into one key pair forfeits both. **Key sizes** (CP §6.1.5): certificates are signed with strength at least that of the highest policy OID asserted. | Policy strength | RSA | ECC | Hash | |---|---|---|---| | 112-bit | 2048 | P-256 | SHA-256 | | 128-bit | 3072 | P-256 | SHA-256 | | 192-bit | 7680 | P-384 | SHA-384 | **Ceremony.** Root operations are scripted, witnessed, video-recorded, and produce a signed ceremony log retained for the archive period. Write the script before you buy the HSM; it will tell you what the HSM has to be able to do. --- ## 8. Revocation and status ### CRL cadence (CP §4.9.7) | CA class | Normal periodicity | Max latency on key/CA compromise | |---|---|---| | Medium Assurance **Root CA** | at least every **28 days** | within **6 hours** of notification | | Medium Assurance **Signing CA** (≤128-bit) | at least **once a day** | within **18 hours** | | **Internal NPE** intermediate CA | at least every **90 days** | within **18 hours** | CRLs are issued on schedule *even when nothing changed*, so that a stale CRL is distinguishable from a current one. Superseded CRLs are removed on publication of the successor. A CRL is posted within **4 hours** of generation, and never later than the `nextUpdate` of the CRL it replaces (§4.9.8). Two policy choices worth noting. First, DoD **mandates CRL support** and makes OCSP optional, because parts of DoD operate disconnected: "the DoD operates in some environments that cannot accommodate on-line communications" (§4.9.9). Your disconnection profile is probably different; see §12. Second, on any CA revocation, the root notifies **every cross-certified and approved external PKI** within the latency budget above. Federation imposes an outbound notification obligation, not just an inbound checking one. ### OCSP - Responder certificates are valid **≤ 45 days** (profiles Table 6); the underlying private key ≤ 3 years. A *CA-hosted* responder (collocated in the CA enclave, key protected equivalently to the CA signing key) may be valid for the life of the CA (CP §6.3.2). - The responder certificate is **signed by the same CA key that signed the certificates it answers for**, with `keyUsage=digitalSignature` (critical) and `extendedKeyUsage=id-kp-OCSPSigning` (critical), all other EKUs prohibited. - Its `certificatePolicies` carries **every** policy OID the issuing CA issues under. - Relying parties use only responders approved through the CP's process; an unapproved responder is not merely unhelpful, it is out of policy. ### Distribution The **first** entry in both `AIA.caIssuers` and `CRLDistributionPoints` must be an HTTP URL reachable from the public Internet (profiles §2.5.2). Not LDAP, not an internal host. Path building fails in the field far more often than signature verification does, and this is the single rule that prevents most of it. --- ## 9. Naming Every DN in the DoD PKI starts with a fixed prefix (profiles §2.3.3): ``` C=US, O=U.S. Government, OU=DoD, OU=PKI CA: … , CN= OCSP: … , CN= End entity: … , OU=, CN= ``` Rules that matter operationally: - **One attribute value per RDN.** Multi-valued RDNs break comparison in real implementations. - **PrintableString** for directoryString attributes; UTF8String for CN only when PrintableString genuinely cannot encode it. - Human CN = `Last First MI [Generation] `. The identifier is what makes the name unique and stable across name changes; DoD uses the EDIPI. **Pick your equivalent before you issue certificate one.** A CN of just a display name is a uniqueness bug that surfaces years later. - Device CN = FQDN, IP, `model-serial`, or application name. Wildcards only in the least-significant label, only when the cert genuinely covers that whole namespace. - Subject and issuer DNs must match their directory entries exactly. - The CP must name who resolves name collisions (CP §3.1.5). --- ## 10. Audit, archive, compliance - **Security audit log**: generated by the CA/RA/OCSP software, reviewed by the ISSO, and the ISSO is the only role that can archive or delete it. Separating "who can act" from "who can erase the record of acting" is the point. - **Archive**: certificate applications, identity-proofing evidence, issued certificates, CRLs, ceremony logs, CPS versions. Retention is set by the highest assurance level served and, for non-repudiation, must outlive the longest plausible dispute. - **Compliance audit**: annual, by an auditor who holds no other role, against the CPS, with results to the PMA. WebTrust for CA or ETSI EN 319 411 are the commercial analogues. --- ## 11. Cryptographic agility DoD's approach is not in-place algorithm rotation. It is **parallel hierarchies**: RSA-2048 root, P-256 root, P-384 root, RSA-4096 root, all live at once, each internally consistent (profiles §1.1). Subscribers are migrated by *issuing them a second credential*, and old roots are retired once their population reaches zero. Hard deadline visible in the profiles doc §2.4: **no 2048-bit RSA certificate, CRL, or OCSP response may be valid beyond 2030-12-31**. Everything above (6-year issuing CAs, 3-year end-entity certs) is arithmetic backing away from that date. For a 2026 build: - Default to **EC P-384 + SHA-384** for new hierarchies. Use RSA only where a relying party genuinely cannot do ECC. - Stand up the **post-quantum root now**, even with no subscribers. NIST has standardized ML-DSA (FIPS 204) and SLH-DSA (FIPS 205); CNSA 2.0 sets DoD/NSS timelines. The expensive part of migration is trust-anchor distribution, and that is exactly the part you can start years early. - Never plan to "re-sign the root with a new algorithm." A trust anchor is identified by its key. New algorithm means new root means new distribution. - If you cross-certify with the Federal Bridge, note that **FBCA G4 is being replaced by FBCA G5 as of 2026-08-27** for cryptographic compliance. Build against G5. --- ## 12. Where to deviate from the DoD model The DoD design is shaped by constraints you very likely do not share. Deviate deliberately: | DoD does | Because | You should probably | |---|---|---| | CRLs mandatory, OCSP optional | Disconnected/tactical operation | **OCSP with stapling as primary**, CRL as fallback. Add CRLite/CRLSets if you have a browser-like population. | | 3-year TLS server certificates | Manual issuance at scale, air-gapped hosts | **90 days or less, fully automated (ACME)**. A 3-year server certificate in 2026 is a liability, and the public Web is heading to 47 days by 2029. | | 3-year human credentials on hardware | Physical card issuance is expensive | Keep 1–3 years for hardware tokens; that is genuinely fine. Consider WebAuthn/passkeys instead of X.509 for pure web authentication. | | Escrow of encryption keys | Statutory records requirements | Only if you have a real data-recovery requirement. Escrow is an attractive target; if you skip it, say so in the CP and mean it. | | RSA-2048 hierarchies still operating | Enormous installed base | Do not start one. | | Heavyweight in-person identity proofing | Adversary model | Match proofing to the policy OID. NIST SP 800-63A IAL2 is the civilian equivalent of DoD's medium-assurance proofing. | | Manual RA workflow | Human-credential-centric | Automate NPE/device issuance end to end (ACME, SPIFFE/SPIRE for workloads). Keep humans in the loop only for human and privileged credentials. | Two things to add that DoD's documents predate: - **Certificate Transparency.** Even for a private PKI, logging issuance to an append-only log (internal is fine) turns misissuance from undetectable into detectable. This is the single highest-value modern addition to the DoD design. - **Short-lived certificates as a revocation strategy.** For workloads, a 24-hour certificate makes revocation largely moot. Reserve the CRL/OCSP machinery for long-lived human and device credentials where it actually earns its cost. --- ## 13. Implementation stack **Chosen: Dogtag Certificate System** (upstream of Red Hat Certificate System) as the CA engine, with offline roots operated outside any CA product. ### 13.1 Engine decision record Not because DoD is publicly confirmed to run it; DISA does not disclose its CA software, and every vendor named in the source documents (Entrust, DigiCert, IdenTrust, WidePoint) is an *external* PKI in the approved-PKI register, not DISA's own stack. The DoD CP §1.1 is explicit that it "does not define a particular implementation of PKI." The reason is that **Dogtag's subsystems map 1:1 onto the components this CP requires**, and no other open-source option covers them: | Dogtag subsystem | Requirement it satisfies | Covered by EJBCA CE? | step-ca? | |---|---|---|---| | **CA** (Certificate Manager) | Issuance, revocation, CRL generation (CP §5.2.1.1) | yes | yes | | **KRA** (Key Recovery Authority) | Escrow and recovery of private **encryption** keys (CP §6.2.3, §4.12) | no | no | | **OCSP** (Online Certificate Status Manager) | Delegated responder as its own trusted role (CP §5.2.1.5) | yes | partial | | **TPS** (Token Processing System) | Card Management System / RA for smart-card enrollment (ECA CP §1.3.3) | no | no | | **TKS** (Token Key Service) | Master keys for the secure channel to the token | no | no | Key escrow and card management are not optional in this design; §7 requires escrow of encryption keys with two-person recovery, and the human tier requires hardware token issuance. With any other engine you build both yourself. The lineage is also the right one: Netscape Certificate Management System (1999) → Red Hat Certificate System → Dogtag. Netscape CMS was the dominant US-government CA platform during the period the CAC program stood up. **Re-evaluated 2026-08-28.** TPS formats tokens by installing the **CoolKey** applet and does not manage CACv2, so for this token TPS and TKS are out. Card personalization moves outside the PKI, which leaves **KRA the only Dogtag-only capability in the table**, and KRA is only needed if escrow is needed. That collapses to one question: | Is there a named data-recovery requirement? | Engine | Escrow | |---|---|---| | **No** (default) | **step-ca** | none: `nonRepudiation` keys are never escrowed anyway, and without a recovery requirement the encryption key needn't be either | | **Yes**, small scale | **step-ca** | wrap the encryption private key to a KMS key (Vault Transit, cloud KMS) at enrollment; recovery is a two-person-approved unwrap | | **Yes**, at fleet scale with an audit obligation | **Dogtag** CA + KRA | KRA's approval workflow, agent roles and archival schema are the thing you would otherwise build and have audited | **Default to row 1.** [components.md §7 item 5](components.md) counts the real price of escrow: the key escrow database, the KRA/KRO workflow, the requestor validation path, exposure-set reconstruction, a second retention clock, a separately committed RTO, and both the KRP and KRPS. It roughly doubles the audited surface of the CA core. Do not buy that to recover mail nobody will ask for. **Do not hand-roll escrow.** If row 2 is chosen, the private key is wrapped by a KMS that already exists and is already audited; no custom key-wrapping code. Escrow is a security boundary, and the ladder stops at "use the thing that already does it." **If Dogtag is chosen anyway, accept the cost honestly.** It is heavy: Java, Tomcat, a hard 389-DS dependency, fiddly PKCS#11 wiring, and a rough install. It is not easier to operate than EJBCA. It is chosen for coverage, not for comfort. ### 13.2 Stack **PROVISIONAL: engine choice is OPEN.** Escrow is required (confirmed). Scale is *not* settled, and the TPS/CACv2 finding that pushed toward step-ca is suggestive rather than proven: TPS's format operation injects the CoolKey applet into a blank token, but whether it can drive an already-personalized PIV applet is untested. The token exposes PIV, so this is decidable; see `lab/spike.sh` Phase −1.1. The table below is what step-ca looks like *if* that is the choice. It is not a decision. | Layer | Choice | Notes | |---|---|---| | **Roots `R1`–`R4`** | No CA product. Offline, scripted `openssl` + PKCS#11 against the root HSM | A root signs 2–6 objects a year. `lab/spike.sh` already drives this shape. | | **Issuing CAs** | **step-ca**, one instance per issuing CA | Matches §3's topology: one instance = one credential type = one policy OID set. | | **Conformance linter** | **MVP, load-bearing**: fails any certificate missing or mis-marking a profile field | Non-negotiable: step *silently drops* template keys it does not support (§13.3). Without the linter, `requireExplicitPolicy` can be absent and nothing tells you. | | **Escrow** | 9D key generated off-card, wrapped to a **KMS** key (Vault Transit or cloud KMS) at enrollment; recovery is a two-person-approved unwrap | No hand-rolled key wrapping. `lab/spike.sh` proves the CMS round-trip with a stand-in wrapping key. | | **Card personalization** | Outside the PKI: PIV applet, slots 9A/9C/9D, via OpenSC `piv-tool` | Dogtag TPS does not drive CACv2 (§13.1). Keeping issuance and personalization decoupled means the card can never block the CA. | | **9A / 9C keys** | Generated **on-card**, never exported | What makes `nonRepudiation` on 9C mean anything. | | **HSM** | Thales Luna / Entrust nShield, or Cloud HSM. SoftHSM for lab only | FIPS 140-3 L3 for roots. Confirm ML-DSA firmware before purchase (§11). | | **Status** | step-ca server for OCSP + CRL; publish CRLs to static HTTP/CDN | AIA/CRLDP first entry internet-reachable HTTP ([profiles.md §1.3](profiles.md)). Re-test AIA/CRLDP injection against the server; the offline gap in §13.2b is likely an artifact. | | **Cross-certification (`R3`)** | Manual ceremony, `openssl` + HSM | Phase 6. step cannot express `nameConstraints` reliably either; assume the linter gates this too. | | **Protocols** | ACME (RFC 8555) workloads · EST (RFC 7030) constrained devices · SCEP legacy only | | | **Path validation testing** | NIST PKITS, `openssl verify -policy_check` | Run PKITS before any cross-certificate goes live. | **What would settle it**, in order of cost: 1. **Plug in the reader**, `piv-tool -n` the token, and try a TPS enrollment against its actual applet. One afternoon, and it answers the only genuinely unknown question. 2. **Decide the escrow scale.** Row 2 (KMS-wrapped) vs row 3 (Dogtag KRA) turns on whether escrow carries an audit obligation and a fleet, not on how many cards exist today. That is a program decision, not a technical one. Nothing built so far depends on the answer; the engine matters at Phase 3, and `lab/spike.sh` is engine-agnostic. Leave it open. ### 13.3 Lab spike findings (2026-08-28) `lab/spike.sh`: **27/27 checks pass**, ~3s, no card required. It issues a root, an issuing CA and the human tier under *both* token capabilities (RSA-2048 and EC P-384), escrows and recovers the encryption key, emits a v2 CRL with `cRLNumber` and a `keyCompromise` `reasonCode`, and gates every certificate through `lab/lint.sh`. `lab/lint.sh` is the conformance linter [§13.2](#132-stack) calls load-bearing. It asserts a certificate against [profiles.md](profiles.md) using only `openssl` (no new dependency) and exits non-zero on deviation. Five profiles implemented (`root`, `issuing`, `auth`, `sign`, `enc`); add the rest when a certificate of that type first exists. **Three step-ca limits, established by test rather than assumption:** | Limit | Reality | Disposition | |---|---|---| | **`policyConstraints`** | step **silently drops** the template key. No error, certificate issued without it. Verified directly | **Closed.** CA certificates are signed by the offline root via `openssl`, which emits it `critical` correctly; that is already the ceremony path in §13.2. step issues **leaves only**, and leaves do not carry `policyConstraints`. The linter enforces it | | **AIA / CRLDP** | Expressible via `ocspServer`, `issuingCertificateURL`, `crlDistributionPoints`, but emitted **by default on neither** offline `certificate create` **nor** the running step-ca server. A server-issued certificate came back with no AIA and no CRLDP at all | **Closed, but note the shape:** the default is silently non-conformant. Every template must name them explicitly. This is the general hazard, not a one-off | | **CRL generation** | No offline CRL command. CRLs come from the step-ca server's DB, or `openssl ca -gencrl` | Fine. The root is offline and openssl-driven by design | **The general lesson, which outlives the product choice:** step fails **open**. An unsupported field is dropped without complaint and a missing field is simply absent. Nothing in the issuance path notices. That is why the linter runs on **every** issued certificate rather than on a sample, and why it ships with the first issuing CA rather than after it. ### 13.4 What this stack does not give you - **step silently drops profile fields it cannot express** (§13.3). The conformance linter is the only thing standing between that and a certificate missing `requireExplicitPolicy`. - **No WebTrust/ETSI audit artifacts.** The evidence pipeline (§10) is yours to build. - **Cross-certification is manual.** Deliberate. - **Certificate Transparency is not included.** If you adopt §12's CT recommendation, that is a separate log to run. - **Trust anchor distribution is not solved.** step-ca issues; getting `R1`–`R4` into every relying party's trust store is an MDM/config-management problem. - **Card personalization is out of scope.** By choice; see §13.2. --- ## 14. Build order 1. **Charter the PMA.** Name people. Write the charter. Nothing else matters until a body can say no. 2. **Register the OID arc** (IANA PEN) and write §5's policy table into a draft CP. 3. **Write the CP** against the RFC 3647 outline. Three policies to start: `hardware-112` (humans on DoD token stock), `hardware-192` (humans on ECC tokens) and `device-128` (workloads). Do not launch with more. 4. **Write the certificate profiles** ([profiles.md](profiles.md)): normative field tables, before any code. 5. **Lab first.** `lab/spike.sh`: done. Root → issuing CA → 9A/9C/9D, escrow round-trip, v2 CRL. Throw the keys away. 6. **Procure HSMs**; write and rehearse the root ceremony scripts on test units. Ceremony scripts are the first deliverable that touches a key. 7. **Ceremony: `R1` and `R2`.** Offline, witnessed, recorded, ceremony log retained. 8. **Stand up issuing CAs**: one step-ca instance per credential type, `pathLen=0`, correct policy OID sets, HSM-backed. **Ship the conformance linter with the first one**, not after. 9. **Stand up the repository before the first end-entity certificate exists**: HTTP/CDN for AIA and CRLDP, then the OCSP subsystem. Publish the root CRL first. 10. **Automate the device tier** (step-ca under `R2`, ACME) before onboarding humans. Higher volume, lower risk, and it shakes out the profile bugs cheaply. 11. **Human tier**: KMS-wrapped escrow for 9D, PIV personalization outside the PKI, RA workflow, identity proofing to the IAL you claimed in the CP. 12. **First compliance audit**, then **`R3` (IRCA)** and the first cross-certificate; name constraints asserted, validated against PKITS. 13. **`R4`**: the post-quantum root, and start distributing the anchor. Distribution lead time is the long pole; begin it before you need it. Do not build the federation tier first. It is the most interesting part and the one most likely to be wrong before the internal hierarchy has been operated in anger.