@blamejs/pki 0.1.15 → 0.1.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/README.md +2 -1
- package/index.js +4 -0
- package/lib/constants.js +4 -0
- package/lib/framework-error.js +8 -0
- package/lib/oid.js +8 -3
- package/lib/path-validate.js +1393 -0
- package/lib/schema-pkix.js +316 -11
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,18 @@ All notable changes to `@blamejs/pki` are documented here. The format
|
|
|
4
4
|
follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); this
|
|
5
5
|
project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## v0.1.16 — 2026-07-06
|
|
8
|
+
|
|
9
|
+
Certification path validation joins the toolkit — RFC 5280 section 6, as a pure re-entrant algorithm.
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- pki.path.validate(path, opts) — RFC 5280 section 6 certification-path validation. It validates an ordered array of pki.schema.x509.parse certificates (or DER/PEM it parses) against a trust anchor, running the section 6.1 state machine: section 6.1.3(a)(1) signature chaining, the always-on section 6.1.3(a)(2) validity window with the check date an explicit input, section 6.1.3(a)(4) name chaining, section 6.1.3(b,c)/6.1.4(g) name constraints (directoryName, dNSName, rfc822Name including an emailAddress carried in the subject DN, uniformResourceIdentifier, and iPAddress with the address-and-mask subtree form), section 6.1.4(k) basic constraints as the single authoritative CA gate, section 6.1.4(l,m) path length, section 6.1.4(n) keyUsage keyCertSign, and the section 6.1.3(d)/6.1.4(a,b,i,j)/6.1.5 certificate-policy tree with its explicit-policy, policy-mapping, and inhibit-any-policy counters. It returns { valid, path, results, workingPublicKey, workingPublicKeyAlgorithm, workingPublicKeyParameters, validPolicyTree } where results[i].checks carries a stable path/* reason code per check. Validation is pure and re-entrant. An unrecognized critical extension, an undetermined revocation status, or a structural fault fails the path with a typed code.
|
|
14
|
+
- pki.path.crlChecker(crls) — a CRL-backed revocation checker for the validate revocationChecker option, composing pki.schema.crl.parse. For each certificate it consults every CRL issued by the certificate's issuer (so a clean CRL cannot shadow a revoking one), verifies each CRL signature over its tbsBytes, honors the issuing-distribution-point scope and reason coverage, checks thisUpdate/nextUpdate currency, and requires the CRL signer to assert keyUsage cRLSign; a certificate listed in any authoritative in-scope CRL is revoked, and an issuer with no authoritative in-scope CRL yields an undetermined status, which the validator fails closed unless softFail is set. An OCSP checker satisfies the same interface.
|
|
15
|
+
- pki.schema.pkix gains the ns-parameterized RFC 5280 section 4.2.1 extension-value decoders (pkix.certExtensionDecoders) — basicConstraints, keyUsage, nameConstraints, certificatePolicies, policyMappings, policyConstraints, inhibitAnyPolicy, subjectAltName / issuerAltName, extKeyUsage, and authorityKeyIdentifier / subjectKeyIdentifier — each turning a raw extension value into a validated structure or a typed error, fail-closed. The shared GeneralName validator gains a decoded-value mode (surfacing the IA5 text, the IP octets, or the directoryName as a structured name alongside the raw bytes) and an address-and-mask subtree-base mode for name-constraint bases; both are opt-in, so the existing callers are byte-identical.
|
|
16
|
+
- The OID registry gains the RFC 5280 policy and wildcard extension identifiers used by path validation: policyMappings, policyConstraints, and inhibitAnyPolicy, plus the anyPolicy and anyExtendedKeyUsage special-OID leaves.
|
|
17
|
+
- The error taxonomy gains PathError, carrying the per-check reason in its stable path/* code.
|
|
18
|
+
|
|
7
19
|
## v0.1.15 — 2026-07-06
|
|
8
20
|
|
|
9
21
|
CMS EnvelopedData and EncryptedData join the parser, and every documentation example is now executed as a test.
|
package/README.md
CHANGED
|
@@ -200,8 +200,9 @@ is callable today; nothing below is a stub.
|
|
|
200
200
|
| `pki.schema.tsp` | Parse DER / PEM RFC 3161 timestamp responses and tokens — the TSTInfo payload (imprint, genTime with sub-second precision, serial, nonce, accuracy), the status-to-token coupling, and the token wrapper composed over CMS with the single-signer rule, fail-closed — `parse`, `parseTstInfo`, `parseToken`, `pemDecode` |
|
|
201
201
|
| `pki.schema.attrcert` | Parse DER / PEM RFC 5755 attribute certificates — the holder and issuer identities (validated GeneralNames), the validity window (real `Date`s), the privilege attributes (role / group / clearance) and extensions, with the raw signed region for a verifier; the obsolete v1 form is recognized and deferred, fail-closed — `parse`, `pemDecode` |
|
|
202
202
|
| `pki.schema.engine` | The declarative ASN.1 structure-schema engine every format parser composes — `walk` plus the schema combinators |
|
|
203
|
+
| `pki.path` | RFC 5280 §6 certification-path validation — `validate` runs the §6.1 state machine (signature chaining, validity windows, name chaining, basic constraints and path length, key usage, name constraints, the certificate-policy tree) over an ordered path and a trust anchor, returning a structured verdict with per-check reason codes; `crlChecker` supplies CRL-based revocation. Pure and re-entrant, fail-closed — `validate`, `crlChecker` |
|
|
203
204
|
| `pki.C` / `pki.constants` | Version-stable constants — functional scale helpers (`C.TIME.*`, `C.BYTES.*`), codec `LIMITS`, `version` |
|
|
204
|
-
| `pki.errors` | The `PkiError` taxonomy — `defineClass` plus `ConstantsError` / `Asn1Error` / `OidError` / `PemError` / `CertificateError` / `CrlError` / `CsrError` / `Pkcs8Error` / `CmsError` / `OcspError` / `TspError`, each carrying a stable `code` in `domain/reason` form |
|
|
205
|
+
| `pki.errors` | The `PkiError` taxonomy — `defineClass` plus `ConstantsError` / `Asn1Error` / `OidError` / `PemError` / `CertificateError` / `CrlError` / `CsrError` / `Pkcs8Error` / `CmsError` / `OcspError` / `TspError` / `AttrCertError` / `PathError`, each carrying a stable `code` in `domain/reason` form |
|
|
205
206
|
| `pki` CLI | `pki version`, `pki oid <dotted\|name>`, `pki parse <cert>` |
|
|
206
207
|
|
|
207
208
|
### CLI
|
package/index.js
CHANGED
|
@@ -29,6 +29,7 @@ var asn1 = require("./lib/asn1-der");
|
|
|
29
29
|
var oid = require("./lib/oid");
|
|
30
30
|
var webcrypto = require("./lib/webcrypto");
|
|
31
31
|
var schema = require("./lib/schema-all");
|
|
32
|
+
var path = require("./lib/path-validate");
|
|
32
33
|
|
|
33
34
|
module.exports = {
|
|
34
35
|
version: constants.version,
|
|
@@ -42,6 +43,9 @@ module.exports = {
|
|
|
42
43
|
// `schema` is the family: the L2 structure-schema engine (schema.engine) and
|
|
43
44
|
// the per-format parsers (schema.x509, …) with detect-and-route schema.parse.
|
|
44
45
|
schema: schema,
|
|
46
|
+
// `path` is RFC 5280 §6 certification-path validation — pki.path.validate
|
|
47
|
+
// runs the §6.1 state machine over an already-parsed path + a trust anchor.
|
|
48
|
+
path: path,
|
|
45
49
|
// A ready W3C Crypto instance (globalThis.crypto shape) with the classes for
|
|
46
50
|
// constructing more attached under the same namespace (pki.webcrypto.CryptoKey,
|
|
47
51
|
// .SubtleCrypto, .Crypto, .WebCryptoError). PQC-first, classical-capable, zero-dep.
|
package/lib/constants.js
CHANGED
|
@@ -117,6 +117,10 @@ var LIMITS = {
|
|
|
117
117
|
PEM_MAX_BYTES: BYTES.mib(16),
|
|
118
118
|
DER_MAX_INTEGER_BYTES: BYTES.kib(16),
|
|
119
119
|
OID_MAX_SUBIDENTIFIER_BYTES: 32,
|
|
120
|
+
// Certification-path length ceiling: bounds the per-cert asymmetric verify
|
|
121
|
+
// work on an untrusted certificate bundle (a real chain is well under this;
|
|
122
|
+
// the operator may override via opts.maxPathCerts).
|
|
123
|
+
PATH_MAX_CERTS: 100,
|
|
120
124
|
};
|
|
121
125
|
|
|
122
126
|
// Single-sourced from the package manifest so the reported version can
|
package/lib/framework-error.js
CHANGED
|
@@ -155,6 +155,13 @@ var TspError = defineClass("TspError", { withCause: true });
|
|
|
155
155
|
// underlying leaf fault as `.cause`.
|
|
156
156
|
var AttrCertError = defineClass("AttrCertError", { withCause: true });
|
|
157
157
|
|
|
158
|
+
// PathError — a certification path that fails RFC 5280 §6 validation, or a
|
|
159
|
+
// malformed input handed to the validator (an extension value that does not
|
|
160
|
+
// decode, an empty path, an unsupported signature algorithm). Carries the
|
|
161
|
+
// per-check reason in `.code` (`path/*`) and the underlying leaf fault as
|
|
162
|
+
// `.cause`.
|
|
163
|
+
var PathError = defineClass("PathError", { withCause: true });
|
|
164
|
+
|
|
158
165
|
module.exports = {
|
|
159
166
|
PkiError: PkiError,
|
|
160
167
|
defineClass: defineClass,
|
|
@@ -171,4 +178,5 @@ module.exports = {
|
|
|
171
178
|
OcspError: OcspError,
|
|
172
179
|
TspError: TspError,
|
|
173
180
|
AttrCertError: AttrCertError,
|
|
181
|
+
PathError: PathError,
|
|
174
182
|
};
|
package/lib/oid.js
CHANGED
|
@@ -61,8 +61,12 @@ var FAMILIES = {
|
|
|
61
61
|
cRLNumber: 20, reasonCode: 21, invalidityDate: 24, deltaCRLIndicator: 27,
|
|
62
62
|
issuingDistributionPoint: 28, certificateIssuer: 29,
|
|
63
63
|
nameConstraints: 30, cRLDistributionPoints: 31,
|
|
64
|
-
certificatePolicies: 32,
|
|
65
|
-
freshestCRL: 46,
|
|
64
|
+
certificatePolicies: 32, policyMappings: 33, authorityKeyIdentifier: 35,
|
|
65
|
+
policyConstraints: 36, extKeyUsage: 37, freshestCRL: 46,
|
|
66
|
+
inhibitAnyPolicy: 54,
|
|
67
|
+
// The two special-OID leaves under extension arcs (RFC 5280 §4.2.1.4 /
|
|
68
|
+
// §4.2.1.12): the certificate-policies wildcard and the EKU wildcard.
|
|
69
|
+
anyPolicy: [32, 0], anyExtendedKeyUsage: [37, 0],
|
|
66
70
|
// RFC 5755 attribute-certificate extensions (§4.3.2, §4.3.6).
|
|
67
71
|
targetInformation: 55, noRevAvail: 56 } },
|
|
68
72
|
|
|
@@ -106,7 +110,8 @@ var FAMILIES = {
|
|
|
106
110
|
|
|
107
111
|
// PKCS#1 RSA public-key + RSASSA signature algorithms.
|
|
108
112
|
rsa: { base: [1, 2, 840, 113549, 1, 1], of: {
|
|
109
|
-
rsaEncryption: 1,
|
|
113
|
+
rsaEncryption: 1, rsaesOaep: 7, mgf1: 8, rsassaPss: 10,
|
|
114
|
+
sha256WithRSAEncryption: 11,
|
|
110
115
|
sha384WithRSAEncryption: 12, sha512WithRSAEncryption: 13 } },
|
|
111
116
|
|
|
112
117
|
// PKCS#7 / CMS content types (RFC 5652 §4, RFC 2315). id-signedData is the one
|