@blamejs/pki 0.6.14 → 0.6.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.
Files changed (112) hide show
  1. package/CHANGELOG.md +27 -1
  2. package/lib/acme.js +59 -815
  3. package/lib/asn1-der.js +7 -245
  4. package/lib/attrcert-sign.js +12 -260
  5. package/lib/attrcert-verify.js +1 -7
  6. package/lib/byte-reader.js +0 -8
  7. package/lib/byte-writer.js +0 -11
  8. package/lib/cbor-det.js +0 -54
  9. package/lib/cmc-build.js +15 -357
  10. package/lib/cmc-verify.js +6 -239
  11. package/lib/cmp-build.js +41 -317
  12. package/lib/cmp-session.js +73 -760
  13. package/lib/cmp-verify.js +32 -488
  14. package/lib/cms-compress.js +3 -32
  15. package/lib/cms-decrypt.js +29 -294
  16. package/lib/cms-encrypt.js +14 -234
  17. package/lib/cms-sign.js +29 -324
  18. package/lib/cms-verify.js +9 -500
  19. package/lib/composite-kem.js +2 -102
  20. package/lib/composite-sig.js +1 -77
  21. package/lib/constants.js +0 -249
  22. package/lib/crl-sign.js +9 -237
  23. package/lib/crl-verify.js +1 -10
  24. package/lib/crmf-sign.js +19 -198
  25. package/lib/crmf-verify.js +1 -12
  26. package/lib/csr-sign.js +3 -34
  27. package/lib/csr-verify.js +1 -12
  28. package/lib/ct.js +28 -253
  29. package/lib/edwards-point.js +10 -44
  30. package/lib/est.js +28 -764
  31. package/lib/framework-error.js +4 -182
  32. package/lib/guard-all.js +1 -58
  33. package/lib/guard-async.js +1 -36
  34. package/lib/guard-bytes.js +6 -650
  35. package/lib/guard-compress.js +5 -102
  36. package/lib/guard-crypto.js +1 -40
  37. package/lib/guard-der.js +2 -93
  38. package/lib/guard-encoding.js +2 -60
  39. package/lib/guard-header.js +1 -36
  40. package/lib/guard-identifier.js +7 -531
  41. package/lib/guard-intrinsic.js +1 -150
  42. package/lib/guard-json.js +10 -73
  43. package/lib/guard-limits.js +1 -77
  44. package/lib/guard-list.js +1 -49
  45. package/lib/guard-name.js +3 -209
  46. package/lib/guard-parsed.js +7 -335
  47. package/lib/guard-range.js +1 -71
  48. package/lib/guard-secret.js +1 -102
  49. package/lib/guard-text.js +1 -64
  50. package/lib/guard-time.js +1 -97
  51. package/lib/hpke.js +3 -105
  52. package/lib/http-digest.js +14 -142
  53. package/lib/http-retry-after.js +1 -47
  54. package/lib/http-transport.js +21 -131
  55. package/lib/inspect.js +30 -284
  56. package/lib/ip-utils.js +6 -47
  57. package/lib/jose.js +7 -142
  58. package/lib/key.js +2 -67
  59. package/lib/lint.js +9 -194
  60. package/lib/merkle.js +1 -27
  61. package/lib/mime.js +9 -82
  62. package/lib/ocsp-request-verify.js +1 -14
  63. package/lib/ocsp-verify.js +1 -82
  64. package/lib/ocsp.js +11 -169
  65. package/lib/oid.js +5 -337
  66. package/lib/path-validate.js +103 -1492
  67. package/lib/pbes2.js +2 -89
  68. package/lib/pkcs12-build.js +31 -379
  69. package/lib/pki-build.js +64 -290
  70. package/lib/rc2.js +2 -18
  71. package/lib/rfc3339.js +4 -27
  72. package/lib/scep.js +140 -286
  73. package/lib/schema-all.js +0 -122
  74. package/lib/schema-attrcert.js +4 -146
  75. package/lib/schema-c509.js +153 -802
  76. package/lib/schema-cmc.js +5 -220
  77. package/lib/schema-cmp.js +2 -223
  78. package/lib/schema-cms.js +13 -427
  79. package/lib/schema-crl.js +5 -68
  80. package/lib/schema-crmf.js +6 -167
  81. package/lib/schema-csr.js +1 -54
  82. package/lib/schema-csrattrs.js +2 -87
  83. package/lib/schema-engine.js +0 -152
  84. package/lib/schema-ocsp.js +0 -117
  85. package/lib/schema-pkcs12.js +2 -93
  86. package/lib/schema-pkcs8.js +3 -35
  87. package/lib/schema-pkix.js +24 -655
  88. package/lib/schema-smime.js +0 -54
  89. package/lib/schema-tsp.js +3 -99
  90. package/lib/schema-x509.js +4 -63
  91. package/lib/shbs.js +11 -95
  92. package/lib/sign-scheme.js +2 -97
  93. package/lib/sigstore.js +9 -169
  94. package/lib/sleep.js +2 -8
  95. package/lib/smime.js +15 -408
  96. package/lib/tls-cert-compress.js +0 -62
  97. package/lib/trust.js +19 -185
  98. package/lib/tsp-sign.js +16 -270
  99. package/lib/validator-all.js +1 -30
  100. package/lib/validator-attcert.js +2 -46
  101. package/lib/validator-cose.js +2 -153
  102. package/lib/validator-keydesc.js +1 -37
  103. package/lib/validator-sig.js +1 -46
  104. package/lib/validator-tls.js +1 -88
  105. package/lib/validator-tpm.js +19 -122
  106. package/lib/verify-seam.js +1 -24
  107. package/lib/webauthn-mds.js +3 -400
  108. package/lib/webauthn.js +12 -833
  109. package/lib/webcrypto.js +5 -485
  110. package/lib/x509-sign.js +4 -108
  111. package/package.json +1 -1
  112. package/sbom.cdx.json +6 -6
package/lib/x509-sign.js CHANGED
@@ -15,12 +15,6 @@
15
15
  * @spec RFC 5280
16
16
  * @card Build and sign an X.509 certificate, self-signed or CA-signed, over any registry algorithm.
17
17
  */
18
- //
19
- // The whole algorithm matrix comes from the shared sign-scheme resolver (the same registry
20
- // pki.cms.sign / pki.tsp.sign drive), so a new algorithm is a registry row, never a branch here. The
21
- // TBS + extension DER is hand-assembled through the canonical asn1.build.* layer (the shipped
22
- // cms/tsp/ocsp producing pattern); the strict schema-x509 decoder round-trips it, and that round-trip
23
- // (plus OpenSSL interop) is the divergence guard.
24
18
 
25
19
  var asn1 = require("./asn1-der");
26
20
  var oid = require("./oid");
@@ -28,9 +22,6 @@ var x509 = require("./schema-x509");
28
22
  var signScheme = require("./sign-scheme");
29
23
  var guard = require("./guard-all");
30
24
  var intrinsic = require("./guard-intrinsic");
31
- // This test picks which FORM the caller's extension spec is in, so it decides which fields are read
32
- // and therefore what is signed into the certificate. Read live, a replacement answering true sends
33
- // an object down the list arm and the extensions it carries are never seen.
34
25
  var _isArray = intrinsic.isArray;
35
26
  var frameworkError = require("./framework-error");
36
27
  var schema = require("./schema-engine");
@@ -38,43 +29,20 @@ var pkix = require("./schema-pkix");
38
29
  var pkiBuild = require("./pki-build");
39
30
 
40
31
  var CertificateError = frameworkError.CertificateError;
41
- // The x509 schema namespace and Name parser: the same RDNSequence parser pki.schema.x509.parse uses, so
42
- // a raw Name DER is validated fully (structure, DirectoryString types) with the frozen x509/* codes.
43
32
  var NS = pkix.makeNS("x509", CertificateError, oid);
44
33
  var NAME_SCHEMA = pkix.name(NS);
45
34
  var SPKI_SCHEMA = pkix.spki(NS);
46
- // The same RFC 5280 sec. 4.2.1 extension value decoders pki.schema.x509.parse uses, so a recognized
47
- // pre-encoded (array-form) extension is fully validated with the frozen x509/* codes.
48
35
  var EXT_DECODERS = pkix.certExtensionDecoders(NS).byOid;
49
36
  var b = asn1.build;
50
- // Two error factories (cms-sign.js pattern): `_err` takes a full x509/* code; `_signE` prepends the
51
- // domain so the shared sign-scheme resolver/signer faults keep the x509/* codes. Both are FACTORIES
52
- // -- guard.time.assertValid and resolveSignScheme invoke them as `E(code, msg)` with no `new`.
53
37
  function _err(code, message, cause) { return new CertificateError(code, message, cause); }
54
38
  function _signE(kind, message, cause) { return new CertificateError("x509/" + kind, message, cause); }
55
39
  function O(n) { return oid.byName(n); }
56
40
 
57
41
  var OID_SKI = O("subjectKeyIdentifier");
58
42
 
59
- // The recognized keys of the `extensions` spec object; an unknown key is a typo and throws at
60
- // config-time (a custom extension is passed as pre-encoded DER via the array form).
61
- // The three caller-owned objects pki.x509.sign reads, each with its own door. A key nothing here
62
- // names is a typo or a misplaced argument, and the failure it causes is invisible: the certificate
63
- // builds, signs, and simply does not carry what was asked for. `spec.extension` (one letter short
64
- // of `extensions`) emitted a certificate with NO extensions at all -- no basicConstraints on an
65
- // intended CA, no keyUsage on an intended constrained leaf. `spec.issuer` is the other shape: the
66
- // issuer is argument TWO, and nesting it in the spec left the certificate SELF-SIGNED with nothing
67
- // to read as a failure.
68
- //
69
- // Every table is derived from what the function actually reads, not from the doc block, because a
70
- // table naming a key nothing reads reopens the hole it was added to close.
71
43
  var KNOWN_SPEC_KEYS = {
72
44
  subject: 1, subjectPublicKey: 1, notBefore: 1, notAfter: 1, serialNumber: 1, extensions: 1,
73
45
  };
74
- // The issuer names itself in one of two FORMS, and the cert form wins unconditionally: when
75
- // `issuer.cert` is present the builder takes the DN and the public key from it and never reads
76
- // `name` or `publicKey`. A union accepted `{ key, cert, name: "Different CA", publicKey }` and
77
- // signed under the certificate's identity while discarding the identity the caller wrote out.
78
46
  var KNOWN_ISSUER_CERT_KEYS = { key: 1, cert: 1 };
79
47
  var KNOWN_ISSUER_EXPLICIT_KEYS = { key: 1, name: 1, publicKey: 1 };
80
48
  var KNOWN_SIGN_OPTS = { digestAlgorithm: 1, pem: 1, pss: 1 };
@@ -85,9 +53,6 @@ var KNOWN_EXT_KEYS = {
85
53
  certificatePolicies: 1, certificatePoliciesCritical: 1,
86
54
  };
87
55
 
88
- // The shared PKIX producing primitives (lib/pki-build.js), bound to the x509 namespace so they keep the
89
- // frozen x509/* codes. Thin local aliases let the x509 call sites read unchanged. csr-sign binds the same
90
- // builder to its own namespace: one encode definition, no per-format hand-roll.
91
56
  var _b = pkiBuild.makeBuilder({ ErrorClass: CertificateError, prefix: "x509", O: O, NS: NS, NAME_SCHEMA: NAME_SCHEMA, SPKI_SCHEMA: SPKI_SCHEMA, EXT_DECODERS: EXT_DECODERS });
92
57
  var _encodeName = _b.encodeName, _isEmptyName = _b.isEmptyName, _reqDer = _b.reqDer,
93
58
  _assertValidSpki = _b.assertValidSpki, _assertValidExtension = _b.assertValidExtension,
@@ -97,11 +62,10 @@ var _encodeName = _b.encodeName, _isEmptyName = _b.isEmptyName, _reqDer = _b.req
97
62
  _extAki = _b.extAki, _extSan = _b.extSan, _extCertPolicies = _b.extCertPolicies,
98
63
  _skiKeyId = _b.skiKeyId, _spkiKeyId = _b.spkiKeyId, _serialInteger = _b.serialInteger;
99
64
 
100
- // ---- issuer-side extension helpers (subjectKeyIdentifier lookup + authorityKeyIdentifier) ----
101
65
 
102
66
  function _skiValueOf(caCert) {
103
67
  var ext = (caCert.extensions || []).filter(function (e) { return e.oid === OID_SKI; })[0];
104
- if (ext) { try { return asn1.read.octetString(asn1.decode(ext.value)); } catch (_e) { /* fall through to re-derive from the issuer SPKI */ } }
68
+ if (ext) { try { return asn1.read.octetString(asn1.decode(ext.value)); } catch (_e) { } } // allow:swallow-unverified -- a malformed CA SKI is read as absent; _akiKeyId then derives the authorityKeyIdentifier keyIdentifier from the issuer public key
105
69
  return null;
106
70
  }
107
71
  function _akiKeyId(val, ctx) {
@@ -113,14 +77,9 @@ function _akiKeyId(val, ctx) {
113
77
  throw _err("x509/bad-input", "authorityKeyIdentifier must be true (auto-derive from the issuer) or a Buffer key id");
114
78
  }
115
79
 
116
- // Build the extensions [3] block from the spec object (or pass through an array of pre-encoded
117
- // Extension DER buffers). Enforces the RFC 5280 CA cross-field gates, then emits a deterministic order.
118
80
  function _buildExtensions(extSpec, ctx) {
119
81
  if (extSpec == null) return [];
120
82
  if (_isArray(extSpec)) {
121
- // Validate each pre-encoded extension, reject a duplicate extnID (RFC 5280 sec. 4.2 allows at most one
122
- // instance of an extension), and decode basicConstraints + keyUsage to apply the same CA
123
- // cross-field rules the object form enforces (below), so the array escape hatch cannot bypass them.
124
83
  var seenExt = {}, arrCa = false, arrKeyCertSign = false, arrPathLen = false;
125
84
  var oidBc = O("basicConstraints"), oidKu = O("keyUsage");
126
85
  var arr = extSpec.map(function (e, i) {
@@ -130,9 +89,6 @@ function _buildExtensions(extSpec, ctx) {
130
89
  var extnId = asn1.read.oid(n.children[0]);
131
90
  if (seenExt[extnId]) throw _err("x509/bad-input", "duplicate extension " + extnId + " in the extensions array (RFC 5280 sec. 4.2 -- at most one instance of an extension)");
132
91
  seenExt[extnId] = true;
133
- // Fully validate a RECOGNIZED extension by running its real value decoder (which enforces the
134
- // RFC 5280 sec. 4.2.1 rules and throws a typed x509/* on malformed), and take the CA cross-field
135
- // inputs from the decoded value; an unrecognized extension is opaque (the caller's own concern).
136
92
  var dec = EXT_DECODERS[extnId];
137
93
  if (dec) {
138
94
  var decoded;
@@ -143,8 +99,6 @@ function _buildExtensions(extSpec, ctx) {
143
99
  }
144
100
  if (extnId === oidBc) {
145
101
  arrCa = decoded.cA === true; arrPathLen = decoded.pathLenConstraint != null;
146
- // RFC 5280 sec. 4.2.1.9 -- a CA's basicConstraints MUST be critical (3 children = an explicit
147
- // TRUE critical flag, since _assertValidExtension already rejects an explicit FALSE).
148
102
  if (arrCa && n.children.length !== 3) throw _err("x509/bad-input", "a CA certificate's basicConstraints MUST be critical (RFC 5280 sec. 4.2.1.9)");
149
103
  }
150
104
  else if (extnId === oidKu) { arrKeyCertSign = decoded.keyCertSign === true; }
@@ -156,8 +110,6 @@ function _buildExtensions(extSpec, ctx) {
156
110
  return arr;
157
111
  }
158
112
  if (typeof extSpec !== "object") throw _err("x509/bad-input", "extensions must be an object or an array of pre-encoded Extension DER");
159
- // Reject a typo'd or unsupported extension key at config-time instead of silently dropping it (a
160
- // misspelled `keyUsag` would otherwise omit keyUsage). A custom extension goes in the array form.
161
113
  guard.identifier.assertKnownKeys(extSpec, KNOWN_EXT_KEYS, _err, "x509/bad-input", function (k) {
162
114
  return "unknown extension " + JSON.stringify(k) + " in the extensions spec; pass a pre-encoded Extension DER via the array form for a custom extension";
163
115
  });
@@ -167,9 +119,7 @@ function _buildExtensions(extSpec, ctx) {
167
119
  var caTrue = !!(bc && bc.cA === true);
168
120
  var ku = extSpec.keyUsage;
169
121
  var assertsKeyCertSign = _isArray(ku) && ku.indexOf("keyCertSign") >= 0;
170
- // RFC 5280 sec. 4.2.1.3 -- keyCertSign requires basicConstraints cA=TRUE.
171
122
  if (assertsKeyCertSign && !caTrue) throw _err("x509/bad-input", "keyUsage keyCertSign requires basicConstraints cA=TRUE (RFC 5280 sec. 4.2.1.3)");
172
- // RFC 5280 sec. 4.2.1.9 -- pathLenConstraint requires cA=TRUE AND keyCertSign.
173
123
  if (bc && bc.pathLen != null) {
174
124
  if (!caTrue) throw _err("x509/bad-input", "basicConstraints pathLenConstraint requires cA=TRUE (RFC 5280 sec. 4.2.1.9)");
175
125
  if (!assertsKeyCertSign) throw _err("x509/bad-input", "basicConstraints pathLenConstraint requires keyUsage keyCertSign (RFC 5280 sec. 4.2.1.9)");
@@ -181,7 +131,6 @@ function _buildExtensions(extSpec, ctx) {
181
131
  if (ku != null) out.push(_ext(O("keyUsage"), extSpec.keyUsageCritical !== false, _extKeyUsage(ku)));
182
132
  if (extSpec.extendedKeyUsage != null) out.push(_ext(O("extKeyUsage"), !!extSpec.extendedKeyUsageCritical, _extExtKeyUsage(extSpec.extendedKeyUsage)));
183
133
  if (bc != null) {
184
- // RFC 5280 sec. 4.2.1.9 -- a CA certificate's basicConstraints MUST be critical.
185
134
  if (bc.cA === true && bc.critical === false) throw _err("x509/bad-input", "a CA certificate's basicConstraints MUST be critical (RFC 5280 sec. 4.2.1.9)");
186
135
  out.push(_ext(O("basicConstraints"), bc.critical !== false, _extBasicConstraints(bc)));
187
136
  }
@@ -190,15 +139,8 @@ function _buildExtensions(extSpec, ctx) {
190
139
  return out;
191
140
  }
192
141
 
193
- // ---- serial + validity + key plumbing --------------------------------------
194
142
 
195
- // RFC 5280 sec. 4.1.2.5 UTCTime/GeneralizedTime cutover -- the shared builder primitive (pki-build), a
196
- // thin wrapper here so the certificate validity label reads "certificate notBefore/notAfter".
197
143
  function _timeDer(date, which) { return _b.timeDer(date, "certificate " + which); }
198
- // A supplied issuer certificate MUST be a CA that may sign certificates: basicConstraints present AND
199
- // critical AND cA=TRUE (RFC 5280 sec. 4.2.1.9), plus, when a keyUsage extension is present, the
200
- // keyCertSign bit (sec. 4.2.1.3). Refuse a non-CA issuer instead of minting a certificate that will not
201
- // chain. Returns the issuer's pathLenConstraint (or null) so the caller can honor it.
202
144
  function _assertIssuerIsCa(issuerCert) {
203
145
  var exts = issuerCert.extensions || [];
204
146
  function ext(name) { return exts.filter(function (x) { return x.oid === O(name); })[0] || null; }
@@ -216,10 +158,8 @@ function _assertIssuerIsCa(issuerCert) {
216
158
  catch (e) { if (e instanceof CertificateError) throw e; throw _err("x509/bad-input", "the issuer certificate keyUsage is malformed", e); }
217
159
  if (ku.keyCertSign !== true) throw _err("x509/bad-input", "the issuer certificate keyUsage does not assert keyCertSign -- it cannot sign certificates (RFC 5280 sec. 4.2.1.3)");
218
160
  }
219
- return bc.pathLenConstraint; // BigInt-narrowed integer or null
161
+ return bc.pathLenConstraint;
220
162
  }
221
- // The cA flag + pathLenConstraint of the certificate being issued, from either the object or the
222
- // pre-encoded array extensions form (used to honor a supplied issuer's pathLenConstraint).
223
163
  function _issuedCaInfo(extSpec) {
224
164
  if (extSpec == null) return { cA: false, pathLen: null };
225
165
  if (!_isArray(extSpec)) {
@@ -234,9 +174,6 @@ function _issuedCaInfo(extSpec) {
234
174
  }
235
175
  return { cA: false, pathLen: null };
236
176
  }
237
- // Does the extensions spec carry a subjectAltName that will be emitted critical? The object form forces
238
- // SAN critical when the subject is empty (so any subjectAltName qualifies); the pre-encoded array form
239
- // is decoded to look for an Extension whose extnID is subjectAltName with a TRUE critical flag.
240
177
  function _hasCriticalSan(extSpec) {
241
178
  if (extSpec == null) return false;
242
179
  if (!_isArray(extSpec)) return !!extSpec.subjectAltName;
@@ -248,7 +185,6 @@ function _hasCriticalSan(extSpec) {
248
185
  return false;
249
186
  }
250
187
 
251
- // ---- the primitive ---------------------------------------------------------
252
188
 
253
189
  /**
254
190
  * @primitive pki.x509.sign
@@ -296,13 +232,6 @@ function _hasCriticalSan(extSpec) {
296
232
  * pki.schema.x509.parse(root).subject.dn; // "CN=Example Root CA"
297
233
  */
298
234
  function sign(spec, issuer, opts) {
299
- // EVERY caller-owned argument is copied before a field of any of them is read, and every copy is
300
- // cleared when the call settles. The checks below run NOW, and the values they approved are
301
- // encoded, signed and emitted several promise turns afterwards, while the caller still owns all
302
- // three objects -- so a spec, an option or a signer read again after the first turn need not be
303
- // the one that passed. Copying only some of them leaves the rest reachable; copying without the
304
- // release leaves a duplicate of whatever secret was nested in them. guard.bytes.fixArguments is
305
- // both halves, and is what every producing verb in the toolkit opens with.
306
235
  return guard.bytes.fixedCall(CertificateError, "x509/bad-input", [
307
236
  [spec, "the certificate spec"], [issuer, "the issuer"], [opts, "pki.x509.sign options"],
308
237
  ], _sign);
@@ -312,9 +241,6 @@ function _sign(spec, issuer, opts) {
312
241
  opts = opts || {};
313
242
  if (!spec || typeof spec !== "object" || Buffer.isBuffer(spec)) throw _err("x509/bad-input", "the certificate spec must be an object");
314
243
  issuer = issuer || {};
315
- // Before a single field is read, so a misspelling is a refusal rather than an omission carried
316
- // into a signed certificate. The issuer message names its own argument because the mistake this
317
- // catches most often is putting the issuer inside the spec, where it self-signed in silence.
318
244
  guard.identifier.assertKnownKeys(spec, KNOWN_SPEC_KEYS, _err, "x509/bad-input", function (k) {
319
245
  return "unknown certificate spec field " + JSON.stringify(k) +
320
246
  (k === "issuer" ? "; the issuer is the SECOND argument to pki.x509.sign, not a spec field" : "") +
@@ -335,18 +261,12 @@ function _sign(spec, issuer, opts) {
335
261
  var subjectDer = _encodeName(spec.subject == null ? [] : spec.subject);
336
262
  var subjectEmpty = _isEmptyName(subjectDer);
337
263
 
338
- // Resolve the issuer name + signing-key SPKI. `{ key }` alone -> self-signed.
339
264
  var issuerDer, issuerSpki, issuerCert = null, issuerPathLen = null;
340
265
  var selfSigned = issuer.name == null && issuer.cert == null && issuer.publicKey == null;
341
266
  if (selfSigned) {
342
267
  issuerDer = subjectDer;
343
268
  issuerSpki = spki;
344
269
  } else if (issuer.cert != null) {
345
- // The CA-ness gate, the issuer name and the signing key are all read off this object, so a
346
- // partial one decides them on fields that are not there.
347
- // Re-derived from the bytes its parser read. The issuer certificate's subject and key identifier
348
- // are copied into the certificate being signed, so they are a claim about who issued it -- an
349
- // assembled object could name an issuer whose bytes the signer never saw.
350
270
  issuerCert = guard.parsed.acceptDerived(issuer.cert, "certificate", x509.parse, _err, "x509/bad-input", "issuer.cert");
351
271
  issuerPathLen = _assertIssuerIsCa(issuerCert);
352
272
  issuerDer = pkiBuild.tbsNameField(issuerCert, "subject");
@@ -356,41 +276,24 @@ function _sign(spec, issuer, opts) {
356
276
  issuerSpki = _reqDer(issuer.publicKey, "issuer.publicKey (the issuer SPKI DER)");
357
277
  _assertValidSpki(issuerSpki, "issuer.publicKey");
358
278
  }
359
- // RFC 5280 sec. 4.1.2.4 -- the issuer MUST be a non-empty distinguished name.
360
279
  if (_isEmptyName(issuerDer)) throw _err("x509/bad-issuer", "issuer must be a non-empty distinguished name");
361
280
 
362
- // Resolve the signature scheme from the SIGNING key's SPKI algorithm (the whole registry, for free).
363
281
  var scheme = signScheme.resolveSignScheme(_certLikeFromSpki(issuerSpki), { combinedRsaSig: true, pss: opts.pss, digestAlgorithm: opts.digestAlgorithm }, true, _signE);
364
282
 
365
283
  var serialTlv = _serialInteger(spec.serialNumber);
366
- // Validate both instants, then reject an inverted window before encoding (a notBefore after notAfter
367
- // is a nonsensical validity period, RFC 5280 sec. 4.1.2.5).
368
284
  guard.time.assertValid(spec.notBefore, _err, "x509/bad-input", "notBefore");
369
285
  guard.time.assertValid(spec.notAfter, _err, "x509/bad-input", "notAfter");
370
286
  // allow:nan-date-comparison-unguarded -- both operands are guard.time.assertValid'd on the two lines above (an Invalid Date throws before this comparison).
371
287
  if (guard.time.instantOf(spec.notBefore) > guard.time.instantOf(spec.notAfter)) throw _err("x509/bad-input", "notBefore must not be after notAfter (RFC 5280 sec. 4.1.2.5)");
372
288
  var validityDer = b.sequence([_timeDer(spec.notBefore, "notBefore"), _timeDer(spec.notAfter, "notAfter")]);
373
289
 
374
- // Read ONCE. Three separate consumers test which form this spec is in -- the encoder, the
375
- // empty-subject rule below and the path-length rule under it -- and each answering for its own
376
- // read is three chances to answer differently about one certificate. The door deep-copies the
377
- // spec, so today they cannot disagree; taking the value once means they still cannot if the
378
- // shape of that door ever changes.
379
290
  var extSpec = spec.extensions;
380
291
  var exts = _buildExtensions(extSpec, { spki: spki, issuerSpki: issuerSpki, issuerCert: issuerCert, subjectEmpty: subjectEmpty });
381
- // RFC 5280 sec. 4.1.2.6 -- an empty subject requires a critical subjectAltName (recognized in both the
382
- // object form and a pre-encoded array-form extension).
383
292
  if (subjectEmpty && !_hasCriticalSan(extSpec)) {
384
293
  throw _err("x509/bad-input", "an empty subject requires a critical subjectAltName (RFC 5280 sec. 4.1.2.6)");
385
294
  }
386
- // Honor a supplied issuer's pathLenConstraint (RFC 5280 sec. 4.2.1.9): a CA certificate issued below
387
- // it consumes one unit of path length, so pathLen=0 forbids issuing a CA below it, and an issued CA's
388
- // own pathLenConstraint must leave room within the issuer's remaining depth.
389
295
  if (issuerPathLen != null) {
390
296
  var issued = _issuedCaInfo(extSpec);
391
- // A self-issued CA certificate (subject == issuer, e.g. a CA key rollover) does NOT consume path
392
- // length (RFC 5280 sec. 6.1 counts only non-self-issued intermediates), so it is permitted even at
393
- // pathLen 0. Compare canonically (sec. 7.1) via the parsed RDN sequences.
394
297
  var selfIssued = guard.name.dnEqual(
395
298
  schema.walk(NAME_SCHEMA, asn1.decode(subjectDer), NS).result.rdns,
396
299
  schema.walk(NAME_SCHEMA, asn1.decode(issuerDer), NS).result.rdns,
@@ -400,14 +303,12 @@ function _sign(spec, issuer, opts) {
400
303
  if (issued.pathLen != null && issued.pathLen > issuerPathLen - 1) throw _err("x509/bad-input", "the issued CA certificate pathLenConstraint exceeds the issuer's remaining path length (RFC 5280 sec. 4.2.1.9)");
401
304
  }
402
305
  }
403
- // Version is derived from the emitted field set (RFC 5280 sec. 4.1.2.1); the builder never emits
404
- // unique identifiers, so extensions => v3, otherwise v1 (the [0] tag is omitted under DER DEFAULT).
405
306
  var version = exts.length ? 3 : 1;
406
307
 
407
308
  var tbsChildren = [];
408
- if (version !== 1) tbsChildren.push(b.explicit(0, b.integer(BigInt(version - 1)))); // v2->INTEGER 1, v3->INTEGER 2
309
+ if (version !== 1) tbsChildren.push(b.explicit(0, b.integer(BigInt(version - 1))));
409
310
  tbsChildren.push(serialTlv);
410
- tbsChildren.push(scheme.sigAlgId); // signature == signatureAlgorithm (RFC 5280 sec. 4.1.1.2), single source
311
+ tbsChildren.push(scheme.sigAlgId);
411
312
  tbsChildren.push(issuerDer);
412
313
  tbsChildren.push(validityDer);
413
314
  tbsChildren.push(subjectDer);
@@ -416,16 +317,11 @@ function _sign(spec, issuer, opts) {
416
317
  var tbsDer = b.sequence(tbsChildren);
417
318
 
418
319
  return signScheme.signOverTbs(scheme, issuer.key, tbsDer, _signE).then(function (sig) {
419
- // The signature MUST verify under the issuer public key, or the certificate would not chain (the
420
- // composite arm returns a promise; the classical/PQC path throws synchronously on a mismatch).
421
320
  return Promise.resolve(_assertCertVerifies(tbsDer, sig, issuerSpki, scheme)).then(function () {
422
321
  var certDer = b.sequence([tbsDer, scheme.sigAlgId, b.bitString(sig, 0)]);
423
322
  return opts.pem ? x509.pemEncode(certDer, "CERTIFICATE") : certDer;
424
323
  });
425
324
  }, function (e) {
426
- // A signing failure at a well-formed tbs is a bad signing key or a key/algorithm mismatch; keep a
427
- // typed CertificateError (composite key-shape faults already are), and re-type a raw WebCrypto
428
- // rejection to x509/bad-input rather than leaking a DOMException from the boundary.
429
325
  if (e instanceof CertificateError) throw e;
430
326
  throw _err("x509/bad-input", "signing the certificate failed -- the signing key does not match the resolved algorithm or is invalid", e);
431
327
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blamejs/pki",
3
- "version": "0.6.14",
3
+ "version": "0.6.16",
4
4
  "description": "Pure-JavaScript PKI toolkit that owns its stack — X.509, ASN.1/DER, CMS, PQC-first.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "blamejs contributors",
package/sbom.cdx.json CHANGED
@@ -2,10 +2,10 @@
2
2
  "$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
3
3
  "bomFormat": "CycloneDX",
4
4
  "specVersion": "1.5",
5
- "serialNumber": "urn:uuid:427d5ce1-3756-4d29-ab2b-4e530ae0f322",
5
+ "serialNumber": "urn:uuid:e63bdf7d-807a-4e39-8cb7-7eb6a47b5808",
6
6
  "version": 1,
7
7
  "metadata": {
8
- "timestamp": "2026-09-01T03:46:40.994Z",
8
+ "timestamp": "2026-09-01T10:42:10.477Z",
9
9
  "lifecycles": [
10
10
  {
11
11
  "phase": "build"
@@ -19,14 +19,14 @@
19
19
  }
20
20
  ],
21
21
  "component": {
22
- "bom-ref": "@blamejs/pki@0.6.14",
22
+ "bom-ref": "@blamejs/pki@0.6.16",
23
23
  "type": "application",
24
24
  "name": "pki",
25
- "version": "0.6.14",
25
+ "version": "0.6.16",
26
26
  "scope": "required",
27
27
  "author": "blamejs contributors",
28
28
  "description": "Pure-JavaScript PKI toolkit that owns its stack — X.509, ASN.1/DER, CMS, PQC-first.",
29
- "purl": "pkg:npm/%40blamejs/pki@0.6.14",
29
+ "purl": "pkg:npm/%40blamejs/pki@0.6.16",
30
30
  "properties": [],
31
31
  "externalReferences": [
32
32
  {
@@ -54,7 +54,7 @@
54
54
  "components": [],
55
55
  "dependencies": [
56
56
  {
57
- "ref": "@blamejs/pki@0.6.14",
57
+ "ref": "@blamejs/pki@0.6.16",
58
58
  "dependsOn": []
59
59
  }
60
60
  ]