# PKIX validation scope and roadmap This file is the canonical support boundary, claim-language guide, and forward-work backlog for the PKIX-facing surface. ## Standards status | Area | Status | Notes | | -------------------------- | ---------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | RFC 5280 path validation | `complete` | core path validation, name constraints across all GeneralName forms (enforce or fail-closed), initial subtree inputs, RFC 9618 policy processing, and malformed-DER coverage ship; validated against the full NIST PKITS suite (224 test procedures, 249 runs incl. documented subtest variations; 4.1.4/4.1.5 DSA chains expected-fail per the WebCrypto algorithm boundary). Revocation is a separate API by design | | RFC 6960 OCSP | `complete` | the full validation surface ships: request/response parsing, signature checks, responder binding/authorization (incl. local trusted responders, `id-pkix-ocsp-nocheck`, and responder revocation policy), nonce/request matching, freshness checks, full request coverage, and chain-level revocation orchestration with freshest-evidence combination; HTTP transport is caller-provided by design (scope boundary, not a gap) | | RFC 6125 service identity | `complete` | `matchServiceIdentity()` and the verification helpers (`verifyCertificateChain`, `validateForTlsServer`, …) ship every RFC 6125/9525 identity type: DNS-ID, IP-ID, URI-ID, SRV-ID, wildcard, IDNA, and opt-in CN-compat checks | | RFC 9618 policy validation | `complete` | RFC 9618-style policy state, enforcement, and outputs ship; the full PKITS policy sections (4.8–4.12, every documented subtest variation) pass | Current conformance evidence: - [`test/pkits.test.ts`](../test/pkits.test.ts), - [`test/policy.test.ts`](../test/policy.test.ts), - [`test/name-constraints.test.ts`](../test/name-constraints.test.ts), - [`test/ocsp-fixtures.test.ts`](../test/ocsp-fixtures.test.ts), - [`test/identity-fixtures.test.ts`](../test/identity-fixtures.test.ts), - [`test/revocation.test.ts`](../test/revocation.test.ts), - [`test/chain-revocation.test.ts`](../test/chain-revocation.test.ts), - [`test/malformed-der.test.ts`](../test/malformed-der.test.ts), and - [`test/differential.test.ts`](../test/differential.test.ts). ## 1. Define the boundary up front - [x] Treat **certification path validation** as a function over a **prospective certification path** plus validation inputs, not as “build whatever chain you can find and hope for the best.”\ RFC 5280 Section 6.1.1 defines the algorithm in terms of a candidate path and nine inputs. (IETF Datatracker[^rfc5280]) - [x] Keep **path building/discovery** separate from **path validation**. - [x] Keep **service identity matching** separate from **path validation**. - [x] Keep **revocation** separate from **path validation**. ## 2. Required inputs for RFC 5280-style path validation - [x] Prospective certification path. - [x] Validation time. - [x] Trust anchor information: trusted issuer name, trusted public key algorithm, trusted public key, and optional trusted key parameters. - [x] User-initial-policy-set. - [x] Initial policy-mapping inhibit flag. - [x] Initial explicit-policy flag. - [x] Initial anyPolicy-inhibit flag. - [x] Initial permitted subtrees. - [x] Initial excluded subtrees. (IETF Datatracker[^rfc5280]) ## 3. Core certificate/path checks - [x] Parse DER strictly enough to reject malformed certificates. - [x] Verify issuer/subject chaining across the candidate path. - [x] Verify each certificate signature using the evolving working public key. - [x] Check validity time (`notBefore` / `notAfter`) against the chosen validation time. - [x] Enforce `basicConstraints` for CA certificates. - [x] Enforce `pathLenConstraint` where applicable. - [x] Enforce `keyUsage`, especially `keyCertSign` for CAs used to sign subordinate certs. - [x] Process self-issued vs non-self-issued certs correctly for path length and name constraints. - [x] Reject the path if any required path-processing step fails. (IETF Datatracker[^rfc5280]) ## 4. Extension handling - [x] Parse and preserve all extensions, including unknown ones. - [x] Reject certificates containing an **unsupported critical extension** or a critical extension whose contents cannot be processed. - [x] Process recognized non-critical extensions when relevant to path processing. - [x] Expose raw extension data so callers can layer application-specific policy on top. (IETF Datatracker[^rfc5280]) ## 5. Name constraints - [x] Support `nameConstraints` on CA certificates. - [x] Support initial permitted/excluded subtrees as validator inputs. - [x] Apply constraints across supported name forms, not just DNS SANs. - [x] Handle self-issued certificates correctly when evaluating constraints. - [x] Fail closed per RFC 5280 §4.2.1.10 when a **critical** nameConstraints extension imposes a form the validator cannot process (`otherName`, `x400Address`, `ediPartyName`, `registeredID`) **and** an instance of that form appears in a subsequent certificate's SANs; chains where the form never appears stay acceptable, and unsupported forms in non-critical extensions are ignored. (IETF Datatracker[^rfc5280]) Current GeneralName matrix for `nameConstraints`: | Form | Parser role | Validator role | Status | | --------------------------- | -------------------------------- | ------------------------------------------ | ---------- | | `rfc822Name` / `dNSName` | decode to typed email/DNS values | enforce | `complete` | | `uniformResourceIdentifier` | decode to typed URI values | enforce host-based matching | `complete` | | `iPAddress` | decode to address+mask bytes | enforce | `complete` | | `directoryName` | preserve structured DN payload | enforce with RFC 5280 semantic compare | `complete` | | `otherName` | preserved as raw payload | fail closed when critical and form appears | `complete` | | `x400Address` | preserved as raw payload | fail closed when critical and form appears | `complete` | | `ediPartyName` | preserved as raw payload | fail closed when critical and form appears | `complete` | | `registeredID` | decoded OID, preserved | fail closed when critical and form appears | `complete` | - Parser responsibility: preserve enough tag/type information that validation can make a deterministic supported-vs-unsupported decision. - Validator responsibility: enforce supported forms and reject critical under-enforced cases instead of silently widening trust. ## 6. Certificate policy processing - [x] Support `certificatePolicies`. - [x] Support `policyConstraints`. - [x] Support `policyMappings`. - [x] Support `inhibitAnyPolicy`. - [x] Use the **RFC 9618** update rather than the older RFC 5280 policy-tree algorithm, because RFC 9618 replaced it with an equivalent, more efficient algorithm to avoid worst-case exponential blowups and DoS risk. (IETF Datatracker[^rfc9618]) - [x] Conformance evidence landed: the full PKITS policy sections (4.8–4.12) pass, with every manifest expectation verified against the official PKITS document ([`docs/rfc/pkits.txt`](./rfc/pkits.txt)). ## 7. Trust-anchor model - [x] Accept trust anchors as structured input, not only as “root cert PEM”. - [x] Allow trust anchor info to come from a self-signed certificate as a convenience, but treat the trust anchor as out-of-band trust input. - [x] Do not assume every self-signed cert is a trust anchor. (IETF Datatracker[^rfc5280]) ## 8. Application/service identity checks - [x] Keep hostname/service-name matching in a separate API from path validation. - [x] For each supported identity type (`dNSName`, `iPAddress`, URI-ID, SRV-ID), match `subjectAltName` entries of the corresponding type first. - [x] `matchServiceIdentity()` supports `dNSName`, `iPAddress`, URI-ID, and SRV-ID matching with wildcard and IDNA coverage. - [x] Verification helpers (`verifyCertificateChain`, `validateForTlsServer`, …) accept the same identity union as `matchServiceIdentity()`. - [x] Only support CN fallback as an explicit compatibility mode, because RFC 6125 treats CN-ID usage as existing practice and prefers `subjectAltName`; CN comparison is deprecated. (IETF Datatracker[^rfc6125]) - [x] Make wildcard behavior explicit and test it hard. Focused RFC 6125 identity fixtures live in [`test/identity-fixtures.test.ts`](../test/identity-fixtures.test.ts). ## 9. EKU / purpose checks - [x] Keep EKU checks separate from raw path validity. - [x] Allow callers to request purposes such as `serverAuth`, `clientAuth`, etc. - [x] Distinguish “certificate is path-valid” from “certificate is acceptable for this application”. ## 10. OCSP support checklist - [x] Build `CertID` from issuer name hash, issuer key hash, serial number, and hash algorithm. - [x] Discover the responder from AIA `id-ad-ocsp` or let callers provide a responder URL explicitly. - [x] Parse and verify `BasicOCSPResponse`. - [x] Check that the response fully and correctly refers to the requested certificate set. - [x] Validate the OCSP response signature. - [x] Validate responder authorization exhaustively. - [x] Land RFC 6960 §4.2.2.2 criterion 1: explicit local signer acceptance scoped to the issuing CA (`trustedOcspResponders` on `validateOcspResponse()`, `trustedOcspResponders` on chain orchestration). - [x] Decide and enforce responder-certificate revocation policy — see §11 for the canonical breakdown. - [x] Add fixture coverage for configured-responder accept/reject and historical-time validation. - [x] Enforce response freshness using `thisUpdate` / `nextUpdate` and configurable clock skew. - [x] Return `good`, `revoked`, and `unknown` distinctly. - [x] Support optional nonce handling if you want replay binding between request and response. RFC 9654 defines the updated nonce extension details. (IETF Datatracker[^rfc6960]) - [x] Consume caller-supplied OCSP responses in chain-level revocation orchestration (`checkChainRevocation()` / `verifyCertificateChain()`), with fail-closed combination against CRL evidence: a validated `revoked` verdict from either source always wins; when both validate as `good`, the default `'best-available'` preference reports the source with the fresher `thisUpdate` (an applied delta CRL counts as its own `thisUpdate`; ties favor OCSP), surfaced as `source.thisUpdate` on the per-certificate status. ## 11. OCSP responder authorization rules - [x] Accept an OCSP response signer if it matches local responder configuration for the certificate in question. - [x] Add a validation input binding trusted responder certs to issuer CA scopes (`trustedOcspResponders` — per-call, and each call is scoped to one issuer). - [x] Thread local responder policy through `validateOcspResponse()` before falling back to issuer-cert or delegated-responder rules. - [x] Add positive and negative fixtures for locally authorized signer scope. - [x] Accept it if the signer is the issuing CA certificate itself. - [x] Accept it if the signer cert contains EKU `id-kp-OCSPSigning` **and** was issued directly by the CA that issued the target certificate. - [x] Reject the response if the signer certificate meets none of those conditions. - [x] Decide and document responder-certificate revocation policy (RFC 6960 §4.2.2.2.1). - [x] Parse and expose `id-pkix-ocsp-nocheck` (`hasOcspNoCheckExtension()`). - [x] Define validator policy knobs: `responderRevocationPolicy` = `'honor-nocheck'` (default) / `'require-evidence'` / `'skip'`, with `responderRevocationCrls` as evidence and `trustedOcspResponders` as the caller-local override. - [x] Add fixtures for each policy branch. - [x] Pass caller evaluation time through delegated responder chain validation. Focused OCSP auth/completeness/freshness fixtures live in [`test/ocsp-fixtures.test.ts`](../test/ocsp-fixtures.test.ts). ## 12. CRL support checklist - [x] Treat CRL validation as a separate revocation subsystem. - [x] Parse CRLs and CRL extensions. - [x] Verify CRL signatures and issuer linkage. - [x] Enforce CRL time/freshness semantics. - [x] Parse CRL distribution points and enforce distribution-point scope during CRL applicability; CRL discovery/fetch hooks are not shipped. - [x] Add delta CRL handling only if you actually want to live in that swamp. RFC 5280 defines CRL validation separately from path validation. (IETF Datatracker[^rfc5280]) ## 13. API design checklist - [x] Keep path building separate from path validation. - [x] Keep service identity matching in a separate API from path validation. - [x] Keep revocation checking separate from path validation. - [x] Expose structured validation inputs instead of hiding policy/name-constraint knobs. - [x] Return typed failure reasons for currently implemented path-validation, CRL, and OCSP checks. - [x] Distinguish hard validation failure from revocation status `unknown` in revocation orchestration; chain, CRL, and OCSP validators still return binary success/failure results. ## 14. Test/conformance checklist - [x] Add fixed RFC-style test vectors for builders, parsers, and validators. - [x] Add round-trip tests for certs, CSRs, names, and extensions. - [x] Run the full NIST PKITS suite: all 224 test procedures across sections 4.1–4.16, expanded to 249 runs including every documented subtest variation; manifest expectations verified against the official PKITS document ([`docs/rfc/pkits.txt`](./rfc/pkits.txt)). 4.1.4/4.1.5 (DSA) are expected-fail per the WebCrypto algorithm boundary and tracked with `it.failing`. See [`test/pkits.test.ts`](../test/pkits.test.ts). - [x] Add malformed DER / fuzz tests. - [x] Differential-test against at least one mature implementation. See [`test/differential.test.ts`](../test/differential.test.ts). - [x] Run the validator against **NIST PKITS** as a gap-report harness, which NIST describes as a comprehensive X.509 path validation test suite for relying parties. (NIST Computer Security Resource Center[^x-509-path-validation]) [^rfc5280]: https://datatracker.ietf.org/doc/html/rfc5280 "RFC 5280 - Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile" [^rfc9618]: https://datatracker.ietf.org/doc/html/rfc9618 "RFC 9618 - Updates to X.509 Policy Validation" [^rfc6125]: https://datatracker.ietf.org/doc/html/rfc6125 "RFC 6125 - Representation and Verification of Domain-Based Application Service Identity within Internet Public Key Infrastructure Using X.509 (PKIX) Certificates in the Context of Transport Layer Security (TLS)" [^rfc6960]: https://datatracker.ietf.org/doc/html/rfc6960 "RFC 6960 - X.509 Internet Public Key Infrastructure Online Certificate Status Protocol - OCSP" [^x-509-path-validation]: https://csrc.nist.gov/projects/pki-testing/x-509-path-validation-test-suite "X.509 Path Validation Test Suite - Public Key Infrastructure Testing | CSRC"