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 + 9919 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; CertID hashing defaults to SHA-256 per RFC 9919 §3.1.1 with explicit SHA-1 interop; HTTP transport is caller-provided by design (scope boundary, not a gap) |
| RFC 9525 service identity | complete | matchServiceIdentity() and the verification helpers (verifyCertificateChain, validateForTlsServer, …) ship every RFC 9525 identity type: DNS-ID, IP-ID, URI-ID, SRV-ID, wildcard, IDNA, and opt-in RFC 6125 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 |
| RFC 7468 PEM textual encodings | complete | strict generator/parser conformance: strict-mode encapsulation, label handling, and base64 rules ship, with non-canonical final quanta rejected per RFC 4648 §3.5; RFC 1421 folded encapsulated headers unfold for legacy traditional PEM; section-complete executable suite |
| RFC 8410 + 9295 safe-curve profiles | complete | Ed25519 end-to-end (key import/export/generation, CSRs, certificates, signature verification); Ed448/X25519/X448 algorithm identifiers and subject keys parse, with RFC 9295 §3 key-usage enforcement for all four OIDs; Ed448/X25519/X448 key operations sit outside the WebCrypto algorithm boundary; section-complete executable suite |
| PKCS containers: RFC 5652, 7292, 8018 | partial | SignedData sign/parse/verify with per-signer certificate resolution and cert bags (RFC 5652 subset; no enveloped/encrypted content types); PFX create/parse with PKCS#12 MAC (RFC 7292 subset); PBES2 with PBKDF2 HMAC-SHA-1/256 and AES-CBC (RFC 8018 subset) |
Current conformance evidence:
test/pkits.test.ts,test/policy.test.ts,test/name-constraints.test.ts,test/ocsp-fixtures.test.ts,test/identity-fixtures.test.ts,test/revocation.test.ts,test/chain-revocation.test.ts,test/malformed-der.test.ts,test/rfc/rfc7468.test.ts,test/rfc/rfc8410.test.ts,test/pkcs7-signeddata.test.ts,test/pfx.test.ts, andtest/differential.test.ts.
1. Define the boundary up front
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])Keep path building/discovery separate from path validation.
Keep service identity matching separate from path validation.
Keep revocation separate from path validation.
2. Required inputs for RFC 5280-style path validation
- Prospective certification path.
- Validation time.
- Trust anchor information: trusted issuer name, trusted public key algorithm, trusted public key, and optional trusted key parameters.
- User-initial-policy-set.
- Initial policy-mapping inhibit flag.
- Initial explicit-policy flag.
- Initial anyPolicy-inhibit flag.
- Initial permitted subtrees.
- Initial excluded subtrees. (IETF Datatracker^rfc5280)
3. Core certificate/path checks
- Parse DER strictly enough to reject malformed certificates.
- Verify issuer/subject chaining across the candidate path.
- Verify each certificate signature using the evolving working public key.
- Check validity time (
notBefore/notAfter) against the chosen validation time. - Enforce
basicConstraintsfor CA certificates. - Enforce
pathLenConstraintwhere applicable. - Enforce
keyUsage, especiallykeyCertSignfor CAs used to sign subordinate certs. - Process self-issued vs non-self-issued certs correctly for path length and name constraints.
- Reject a certificate whose
id-ecPublicKeykey locates no namedCurve domain parameters. (IETF Datatracker^rfc5480) - Reject the path if any required path-processing step fails. (IETF Datatracker^rfc5280)
4. Extension handling
- Parse and preserve all extensions, including unknown ones.
- Reject certificates containing an unsupported critical extension or a critical extension whose contents cannot be processed.
- Process recognized non-critical extensions when relevant to path processing.
- Expose raw extension data so callers can layer application-specific policy on top. (IETF Datatracker^rfc5280)
5. Name constraints
- Support
nameConstraintson CA certificates. - Support initial permitted/excluded subtrees as validator inputs.
- Apply constraints across supported name forms, not just DNS SANs.
- Handle self-issued certificates correctly when evaluating constraints.
- 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
- Support
certificatePolicies. - Support
policyConstraints. - Support
policyMappings. - Support
inhibitAnyPolicy. - 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)
- 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).
7. Trust-anchor model
- Accept trust anchors as structured input, not only as “root cert PEM”.
- 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.
- Do not assume every self-signed cert is a trust anchor. (IETF Datatracker^rfc5280)
8. Application/service identity checks
- Keep hostname/service-name matching in a separate API from path validation.
- For each supported identity type (
dNSName,iPAddress, URI-ID, SRV-ID), matchsubjectAltNameentries of the corresponding type first. -
matchServiceIdentity()supportsdNSName,iPAddress, URI-ID, and SRV-ID matching with wildcard and IDNA coverage. - Verification helpers (
verifyCertificateChain,validateForTlsServer, …) accept the same identity union asmatchServiceIdentity(). - Only support CN fallback as an explicit RFC 6125 compatibility mode; RFC 9525 forbids using the Common Name RDN to identify a service. (IETF Datatracker^rfc6125, ^rfc9525)
- Make wildcard behavior explicit and test it hard.
Focused RFC 9525 identity fixtures live in test/identity-fixtures.test.ts.
9. EKU / purpose checks
- Keep EKU checks separate from raw path validity.
- Allow callers to request purposes such as
serverAuth,clientAuth, etc. - Distinguish “certificate is path-valid” from “certificate is acceptable for this application”.
10. OCSP support checklist
- Build
CertIDfrom issuer name hash, issuer key hash, serial number, and hash algorithm. - Discover the responder from AIA
id-ad-ocspor let callers provide a responder URL explicitly. - Parse and verify
BasicOCSPResponse. - Check that the response fully and correctly refers to the requested certificate set.
- Validate the OCSP response signature.
- Validate responder authorization exhaustively.
- Land RFC 6960 §4.2.2.2 criterion 1: explicit local signer acceptance scoped to the issuing CA (
trustedOcspRespondersonvalidateOcspResponse(),trustedOcspResponderson chain orchestration). - Decide and enforce responder-certificate revocation policy — see §11 for the canonical breakdown.
- Add fixture coverage for configured-responder accept/reject and historical-time validation.
- Land RFC 6960 §4.2.2.2 criterion 1: explicit local signer acceptance scoped to the issuing CA (
- Enforce response freshness using
thisUpdate/nextUpdateand configurable clock skew. - Return
good,revoked, andunknowndistinctly. - Support optional nonce handling if you want replay binding between request and response. RFC 9654 defines the updated nonce extension details. (IETF Datatracker^rfc6960)
- Consume caller-supplied OCSP responses in chain-level revocation orchestration (
checkChainRevocation()/verifyCertificateChain()), with fail-closed combination against CRL evidence: a validatedrevokedverdict from either source always wins; when both validate asgood, the default'best-available'preference reports the source with the fresherthisUpdate(an applied delta CRL counts as its ownthisUpdate; ties favor OCSP), surfaced assource.thisUpdateon the per-certificate status.
11. OCSP responder authorization rules
- Accept an OCSP response signer if it matches local responder configuration for the certificate in question.
- Add a validation input binding trusted responder certs to issuer CA scopes (
trustedOcspResponders— per-call, and each call is scoped to one issuer). - Thread local responder policy through
validateOcspResponse()before falling back to issuer-cert or delegated-responder rules. - Add positive and negative fixtures for locally authorized signer scope.
- Add a validation input binding trusted responder certs to issuer CA scopes (
- Accept it if the signer is the issuing CA certificate itself.
- Accept it if the signer cert contains EKU
id-kp-OCSPSigningand was issued directly by the CA that issued the target certificate. - Reject the response if the signer certificate meets none of those conditions.
- Decide and document responder-certificate revocation policy (RFC 6960 §4.2.2.2.1).
- Parse and expose
id-pkix-ocsp-nocheck(hasOcspNoCheckExtension()). - Define validator policy knobs:
responderRevocationPolicy='honor-nocheck'(default) /'require-evidence'/'skip', withresponderRevocationCrlsas evidence andtrustedOcspRespondersas the caller-local override. - Add fixtures for each policy branch.
- Pass caller evaluation time through delegated responder chain validation.
- Parse and expose
Focused OCSP auth/completeness/freshness fixtures live in test/ocsp-fixtures.test.ts.
12. CRL support checklist
- Treat CRL validation as a separate revocation subsystem.
- Parse CRLs and CRL extensions.
- Verify CRL signatures and issuer linkage.
- Enforce CRL time/freshness semantics.
- Parse CRL distribution points and enforce distribution-point scope during CRL applicability; CRL discovery/fetch hooks are not shipped.
- 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
- Keep path building separate from path validation.
- Keep service identity matching in a separate API from path validation.
- Keep revocation checking separate from path validation.
- Expose structured validation inputs instead of hiding policy/name-constraint knobs.
- Return typed failure reasons for currently implemented path-validation, CRL, and OCSP checks.
- Distinguish hard validation failure from revocation status
unknownin revocation orchestration; chain, CRL, and OCSP validators still return binary success/failure results.
14. Test/conformance checklist
- Add fixed RFC-style test vectors for builders, parsers, and validators.
- Add round-trip tests for certs, CSRs, names, and extensions.
- 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). 4.1.4/4.1.5 (DSA) are expected-fail per the WebCrypto algorithm boundary and tracked withit.failing. Seetest/pkits.test.ts. - Add malformed DER / fuzz tests.
- Differential-test against at least one mature implementation. See
test/differential.test.ts. - 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)