@blamejs/pki 0.5.37 → 0.5.38

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 CHANGED
@@ -4,7 +4,15 @@ 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.5.37 — 2026-08-30
7
+ ## v0.5.38 — 2026-08-30
8
+
9
+ Builder verbs reject a sparse or nullish array argument with a typed error instead of a native one.
10
+
11
+ ### Changed
12
+
13
+ - The array arguments of pki.pkcs12.build (SafeContents bags), pki.ocsp.buildRequest and pki.ocsp.sign (the query and response batches), pki.cmc.build (requests and the CMS and other-message sequences), pki.crl.sign (revoked entries and the issuing-distribution-point and freshest-CRL general names), pki.crmf.build (controls and registration info), and pki.cms.encrypt (authenticated attributes) are checked for holes and nullish entries up front. A sparse or nullish array is now the verb's own typed `<domain>/bad-input` error naming the index, in place of the native `TypeError` the hole previously produced at the encoder. A valid (dense) array is unaffected and its emitted structure is byte-for-byte identical.
14
+
15
+ ## v0.5.37 — 2026-08-29
8
16
 
9
17
  pki.cms.decrypt can return the recovered content as an async iterable of plaintext chunks.
10
18
 
package/lib/cmc-build.js CHANGED
@@ -27,6 +27,7 @@
27
27
 
28
28
  var nodeCrypto = require("node:crypto");
29
29
  var asn1 = require("./asn1-der");
30
+ var pkiBuild = require("./pki-build"); // reqDenseArray: reject a sparse/nullish caller array as a typed cmc/bad-input
30
31
  var csr = require("./schema-csr"); // to read the Subject Key Identifier a tcr request declares
31
32
  var crmf = require("./schema-crmf"); // ... and the one a crm request declares
32
33
  var cmcFmt = require("./schema-cmc"); // to read the assembled message back before signing it
@@ -510,7 +511,9 @@ function _build(spec, signer, opts) {
510
511
  // them has no replay defense, and pki.cmc.verify cannot enforce a binding the
511
512
  // client never sent, so the omission is invisible from both ends.
512
513
  guard.identifier.assertKnownKeys(spec, KNOWN_SPEC_KEYS, E, "cmc/bad-input", "unknown spec field ");
513
- var requests = spec.requests || [];
514
+ // Density up front: requests is iterated by both the forEach below and the map that encodes it, and a
515
+ // hole would survive either (map/forEach skip it) to reach b.sequence as a native error.
516
+ var requests = spec.requests != null ? pkiBuild.reqDenseArray(spec.requests, "requests", E, "cmc/bad-input") : [];
514
517
  if (!Array.isArray(requests)) throw E("cmc/bad-input", "spec.requests must be an array");
515
518
  var callerControls = spec.controls || [];
516
519
  if (!Array.isArray(callerControls)) throw E("cmc/bad-input", "spec.controls must be an array");
@@ -532,10 +535,10 @@ function _build(spec, signer, opts) {
532
535
  var fixed = fixedRequestId(r, i);
533
536
  if (fixed != null) ids.reserve(fixed, "request " + i);
534
537
  });
535
- var cmsSequence = (spec.cmsSequence || []).map(function (el, i) {
538
+ var cmsSequence = (spec.cmsSequence != null ? pkiBuild.reqDenseArray(spec.cmsSequence, "cmsSequence", E, "cmc/bad-input") : []).map(function (el, i) {
536
539
  return _claimRawElement(el, ids, "a cmsSequence element (index " + i + ")");
537
540
  });
538
- var otherMsgSequence = (spec.otherMsgSequence || []).map(function (el, i) {
541
+ var otherMsgSequence = (spec.otherMsgSequence != null ? pkiBuild.reqDenseArray(spec.otherMsgSequence, "otherMsgSequence", E, "cmc/bad-input") : []).map(function (el, i) {
539
542
  return _claimRawElement(el, ids, "an otherMsgSequence element (index " + i + ")");
540
543
  });
541
544
 
@@ -17,6 +17,7 @@
17
17
 
18
18
  var nodeCrypto = require("crypto");
19
19
  var asn1 = require("./asn1-der");
20
+ var pkiBuild = require("./pki-build"); // reqDenseArray: reject a sparse/nullish caller array as a typed cms/bad-input
20
21
  var oid = require("./oid");
21
22
  var x509 = require("./schema-x509");
22
23
  var schemaCms = require("./schema-cms");
@@ -589,8 +590,14 @@ async function _envelopedData(contentBytes, contentStream, cek, ca, contentType,
589
590
  // design (RFC 5652 sec. 9.2), while for AuthEnvelopedData that value is the unencrypted hash of a
590
591
  // plaintext the message exists to conceal (RFC 5083 sec. 2.1 / sec. 5).
591
592
  function _assertAuthAttrs(pairs, forbidden) {
593
+ // Reject a sparse/nullish attribute array as a typed error before b.setOf reaches it as a native one.
594
+ // This gate runs before the setOf on both the AuthEnveloped and AuthenticatedData paths.
595
+ // Validate AND SNAPSHOT: reqDenseArray returns a fresh dense copy, and it is that copy the caller must
596
+ // iterate and encode. Iterating the original `pairs` would let an indexed getter that sparsified it
597
+ // during validation slip a hole into b.setOf as a native error; the returned snapshot cannot.
598
+ var dense = pkiBuild.reqDenseArray(pairs, "authAttrs", _err, "cms/bad-input");
592
599
  var seenTypes = {};
593
- pairs.forEach(function (p) {
600
+ dense.forEach(function (p) {
594
601
  var node;
595
602
  try { node = asn1.decode(p); } catch (e) { throw _err("cms/bad-input", "an authenticated attribute is not well-formed DER", e); }
596
603
  if (node.tagClass !== "universal" || node.tagNumber !== asn1.TAGS.SEQUENCE || !node.children || node.children.length !== 2 ||
@@ -604,6 +611,7 @@ function _assertAuthAttrs(pairs, forbidden) {
604
611
  seenTypes[t] = 1;
605
612
  if (forbidden && t === forbidden.oid) throw _err("cms/bad-input", forbidden.why);
606
613
  });
614
+ return dense;
607
615
  }
608
616
 
609
617
  // The one attribute AuthEnvelopedData declines to emit. Its value is the unencrypted one-way hash of
@@ -623,9 +631,9 @@ async function _authEnvelopedData(contentBytes, contentStream, cek, ca, contentT
623
631
  throw _err("cms/bad-input", "AuthEnvelopedData with a non-data contentType requires authAttrs (RFC 5083 sec. 2.1)");
624
632
  }
625
633
  if (opts.authAttrs && opts.authAttrs.length) {
626
- _assertAuthAttrs(opts.authAttrs, AUTH_ENVELOPED_FORBIDDEN);
634
+ var denseAttrs = _assertAuthAttrs(opts.authAttrs, AUTH_ENVELOPED_FORBIDDEN);
627
635
  // authAttrs are transmitted [1] IMPLICIT but MACed under the EXPLICIT SET OF tag (RFC 5083 sec. 2.2).
628
- var setOf = b.setOf(opts.authAttrs);
636
+ var setOf = b.setOf(denseAttrs);
629
637
  aad = setOf; authAttrsDer = b.contextConstructed(1, setOf.subarray(_tlvHeaderLen(setOf)));
630
638
  }
631
639
  // A 16-octet (128-bit) GCM tag, the strongest ICV and what OpenSSL emits, so the message
@@ -799,7 +807,7 @@ async function authenticate(content, recipients, opts) {
799
807
  b.sequence([b.oid(O("messageDigest")), b.setOf([b.octetString(mdDigest)])]),
800
808
  ];
801
809
  if (opts.authAttrs && opts.authAttrs.length) pairs = pairs.concat(opts.authAttrs);
802
- _assertAuthAttrs(pairs, null);
810
+ pairs = _assertAuthAttrs(pairs, null);
803
811
  var setOf = b.setOf(pairs);
804
812
  preimage = setOf; // MAC over the 0x31 SET OF
805
813
  authAttrsDer = b.contextConstructed(2, setOf.subarray(_tlvHeaderLen(setOf))); // [2] IMPLICIT on the wire
package/lib/crl-sign.js CHANGED
@@ -203,7 +203,7 @@ function _idpValue(idp) {
203
203
  if (idp.onlyContainsAttributeCerts === true) throw _err("crl/bad-idp", "onlyContainsAttributeCerts=TRUE is not permitted for a conforming CRL issuer (RFC 5280 sec. 5.2.5)");
204
204
  var children = [];
205
205
  if (idp.fullName != null) {
206
- var entries = Array.isArray(idp.fullName) ? idp.fullName : [idp.fullName];
206
+ var entries = Array.isArray(idp.fullName) ? pkiBuild.reqDenseArray(idp.fullName, "issuingDistributionPoint.fullName", _err, "crl/bad-idp") : [idp.fullName];
207
207
  if (!entries.length) throw _err("crl/bad-idp", "issuingDistributionPoint fullName must carry at least one GeneralName");
208
208
  // distributionPoint [0] { fullName [0] IMPLICIT GeneralNames }
209
209
  children.push(b.contextConstructed(0, b.contextConstructed(0, Buffer.concat(entries.map(_encodeGeneralName)))));
@@ -243,11 +243,12 @@ function _validatePreEncodedIdp(inner) {
243
243
  // fullName) or an array of { fullName } distribution points.
244
244
  function _freshestValue(spec) {
245
245
  if (!Array.isArray(spec) || !spec.length) throw _err("crl/bad-input", "freshestCRL must be a non-empty array of GeneralNames (or { fullName } distribution points)");
246
- var dps = spec.every(function (e) { return e && typeof e === "object" && !Buffer.isBuffer(e) && Object.keys(e).length === 1 && e.fullName != null; })
247
- ? spec.map(function (dp) { return dp.fullName; })
248
- : [spec];
246
+ var dense = _b.reqDenseArray(spec, "freshestCRL"); // density before every()/map() skip a hole into b.sequence
247
+ var dps = dense.every(function (e) { return e && typeof e === "object" && !Buffer.isBuffer(e) && Object.keys(e).length === 1 && e.fullName != null; })
248
+ ? dense.map(function (dp) { return dp.fullName; })
249
+ : [dense];
249
250
  return b.sequence(dps.map(function (fullName) {
250
- var entries = Array.isArray(fullName) ? fullName : [fullName];
251
+ var entries = Array.isArray(fullName) ? _b.reqDenseArray(fullName, "a freshestCRL distribution point fullName") : [fullName];
251
252
  if (!entries.length) throw _err("crl/bad-input", "a freshestCRL distribution point must carry at least one GeneralName (GeneralNames is SIZE(1..MAX), RFC 5280 sec. 4.2.1.13)");
252
253
  return b.sequence([b.contextConstructed(0, b.contextConstructed(0, Buffer.concat(entries.map(_encodeGeneralName))))]);
253
254
  }));
@@ -345,7 +346,8 @@ function _buildCrlExtensions(spec, ctx) {
345
346
  function _buildRevoked(entryList, isDelta) {
346
347
  if (!Array.isArray(entryList)) throw _err("crl/bad-input", "revoked must be an array of revoked-certificate entries");
347
348
  var anyExt = false, seenSerials = {};
348
- var entries = entryList.map(function (e, idx) {
349
+ // Density before the map, which would otherwise skip a hole into b.sequence as a native error.
350
+ var entries = _b.reqDenseArray(entryList, "revoked").map(function (e, idx) {
349
351
  if (!e || typeof e !== "object" || Buffer.isBuffer(e)) throw _err("crl/bad-input", "each revoked entry must be an object");
350
352
  // Before any field of the entry is encoded, so an unrecognized name is a refusal rather than an
351
353
  // entry signed without what it asked for.
package/lib/crmf-sign.js CHANGED
@@ -148,7 +148,8 @@ function _buildAttrTypeAndValues(spec, code, label, valueMap) {
148
148
  if (Array.isArray(spec)) {
149
149
  if (!spec.length) throw _err(code, label + " must carry at least one entry");
150
150
  var seenA = {};
151
- return b.sequence(spec.map(function (e, i) {
151
+ // Density before the map, which would otherwise skip a hole into b.sequence as a native error.
152
+ return b.sequence(pkiBuild.reqDenseArray(spec, label, _err, code).map(function (e, i) {
152
153
  var der = _b.reqDer(e, label + " [" + i + "]");
153
154
  var n;
154
155
  try { n = asn1.decode(der); } catch (err) { throw _err("crmf/bad-input", "pre-encoded " + label + " [" + i + "] is not valid DER", err); }
package/lib/ocsp.js CHANGED
@@ -25,6 +25,7 @@
25
25
 
26
26
  var nodeCrypto = require("crypto");
27
27
  var asn1 = require("./asn1-der");
28
+ var pkiBuild = require("./pki-build"); // reqDenseArray: reject a sparse/nullish caller array as a typed ocsp/bad-input
28
29
  var oid = require("./oid");
29
30
  var x509 = require("./schema-x509");
30
31
  var ocspSchema = require("./schema-ocsp");
@@ -176,7 +177,9 @@ function _buildRequest(query, opts) {
176
177
  var lightweight = opts.profile === "lightweight";
177
178
  var hashName = opts.hashAlgorithm || "sha1";
178
179
  if (lightweight && hashName !== "sha1") throw _err("ocsp/bad-input", "the lightweight profile requires a SHA-1 CertID (RFC 5019 sec. 2.1.1)");
179
- var queries = Array.isArray(query) ? query : [query];
180
+ // A batch array is density-checked before the map below (which would otherwise skip a hole and reach
181
+ // Promise.all/b.sequence with an undefined); a single {cert,issuer} wraps to a dense one-element array.
182
+ var queries = Array.isArray(query) ? pkiBuild.reqDenseArray(query, "queries", _err, "ocsp/bad-input") : [query];
180
183
  if (!queries.length) throw _err("ocsp/bad-input", "buildRequest needs at least one { cert, issuer } query");
181
184
  if (lightweight && queries.length !== 1) throw _err("ocsp/bad-input", "the lightweight profile permits exactly one Request (RFC 5019 sec. 2.1.1)");
182
185
  if (opts.signer && !opts.requestorName) throw _err("ocsp/bad-input", "a signed OCSP request MUST carry requestorName (RFC 6960 sec. 4.1.2)");
@@ -335,7 +338,7 @@ function _sign(responseData, responder, opts) {
335
338
  // exit -- sync throw and async rejection alike -- rather than each fallible step needing to
336
339
  // remember. `responderKey` is the private copy; it is never the caller's object.
337
340
  function _signResponse(responseData, responder, respCert, respCertDer, responderKey, opts) {
338
- var responses = responseData.responses || [];
341
+ var responses = responseData.responses != null ? pkiBuild.reqDenseArray(responseData.responses, "responses", _err, "ocsp/bad-input") : [];
339
342
  if (!responses.length) throw _err("ocsp/bad-input", "a response MUST include at least one SingleResponse (RFC 6960 sec. 4.2.1)");
340
343
 
341
344
  return _responderID(responseData.responderID, respCert).then(function (ridNode) {
@@ -47,6 +47,7 @@ var cmsSign = require("./cms-sign"); // the signer-descriptor field tables, fo
47
47
  var cmsDecrypt = require("./cms-decrypt"); // the @internal decryptEnvelopedData seam -- opens a privacy safe off the pkcs12 parser's already-walked (BER-capable) EnvelopedData node
48
48
  var schemaPkcs12 = require("./schema-pkcs12");
49
49
  var pkix = require("./schema-pkix");
50
+ var pkiBuild = require("./pki-build"); // reqDenseArray: reject a sparse/nullish caller array as a typed pkcs12/bad-input
50
51
  var guard = require("./guard-all");
51
52
  var intrinsic = require("./guard-intrinsic");
52
53
  var frameworkError = require("./framework-error");
@@ -463,9 +464,13 @@ function _pbeOpts(enc) {
463
464
 
464
465
  // SafeContents ::= SEQUENCE OF SafeBag (ordered, and not a SET OF).
465
466
  function _buildSafeContents(bags, opts, depth) {
466
- if (!Array.isArray(bags)) throw _err("pkcs12/bad-input", "bags must be an array");
467
- if (bags.length > C.LIMITS.PKCS12_MAX_ELEMENTS) throw _err("pkcs12/bad-input", "a SafeContents exceeds the element cap " + C.LIMITS.PKCS12_MAX_ELEMENTS);
468
- return b.sequence(bags.map(function (bag) { return _buildBag(bag, opts, depth); }));
467
+ // The element cap is enforced BEFORE the density scan, so a huge dense array is rejected in O(1) rather
468
+ // than walked. reqDenseArray then rejects a non-array, or a sparse hole / nullish entry that
469
+ // Array.prototype.map would skip into Buffer.concat as a native error, testing own-property presence
470
+ // and failing at the first bad index.
471
+ if (intrinsic.isArray(bags) && bags.length > C.LIMITS.PKCS12_MAX_ELEMENTS) throw _err("pkcs12/bad-input", "a SafeContents exceeds the element cap " + C.LIMITS.PKCS12_MAX_ELEMENTS);
472
+ var dense = pkiBuild.reqDenseArray(bags, "bags", _err, "pkcs12/bad-input");
473
+ return b.sequence(dense.map(function (bag) { return _buildBag(bag, opts, depth); }));
469
474
  }
470
475
 
471
476
  // One AuthenticatedSafe element: a plaintext id-data ContentInfo, an id-encryptedData ContentInfo whose
package/lib/pki-build.js CHANGED
@@ -329,6 +329,34 @@ var KU_BIT = {
329
329
  dataEncipherment: 3, keyAgreement: 4, keyCertSign: 5, cRLSign: 6, encipherOnly: 7, decipherOnly: 8,
330
330
  };
331
331
 
332
+ // A caller-supplied array a builder is about to map over: reject a sparse hole or a nullish entry as a
333
+ // typed error. Array.prototype.map SKIPS a hole, which would otherwise reach Buffer.concat as a native
334
+ // ERR_INVALID_ARG_TYPE and, on a huge sparse length, traverse the empty slots. Tests OWN-property presence
335
+ // (intrinsic.hasOwn) at each index BEFORE reading it, so a polluted Array.prototype[i] cannot slip a hole
336
+ // past the check, and fails fast at the first bad index so the length alone can never force a walk. Takes
337
+ // the caller's error factory E (invoked E(fullCode, msg)) so a builder WITHOUT a makeBuilder instance
338
+ // routes its caller arrays through the same choke point; makeBuilder's own reqDenseArray delegates here.
339
+ function reqDenseArrayImpl(list, what, E, code) {
340
+ if (!_isArray(list)) throw E(code, what + " must be an array");
341
+ var n = list.length;
342
+ // Snapshot each own index into a FRESH dense array and return THAT, never `list`. Reading list[i] can
343
+ // fire a caller-defined indexed accessor that mutates `list` (extending it with holes past the captured
344
+ // n, or deleting an already-checked index); returning `list` would then hand the caller's map a
345
+ // newly-sparse array and the native error this guard exists to prevent. The copy captures the value as
346
+ // read, so a later mutation of `list` cannot reintroduce a hole into what the caller iterates.
347
+ var out = [];
348
+ for (var i = 0; i < n; i++) {
349
+ if (!intrinsic.hasOwn(list, i)) throw E(code, what + "[" + i + "] is missing (a sparse array is not allowed)");
350
+ var v = list[i];
351
+ if (v === undefined || v === null) throw E(code, what + "[" + i + "] is missing (a nullish array entry is not allowed)");
352
+ // defineProperty, not `out[i] = v`: a plain assignment invokes an inherited Array.prototype[i] SETTER
353
+ // ([[Set]]) if one is polluted in, which could leave `out` sparse; [[DefineOwnProperty]] always makes
354
+ // an own data property, so the snapshot is dense regardless of prototype pollution.
355
+ intrinsic.defineProperty(out, i, { value: v, writable: true, enumerable: true, configurable: true });
356
+ }
357
+ return out;
358
+ }
359
+
332
360
  // makeBuilder(ctx) -> the bound producing primitives. ctx = { ErrorClass, prefix, O, NS, NAME_SCHEMA,
333
361
  // SPKI_SCHEMA, EXT_DECODERS }. `E(kind, msg, cause)` builds a `<prefix>/<kind>` typed error.
334
362
  function makeBuilder(ctx) {
@@ -593,23 +621,9 @@ function makeBuilder(ctx) {
593
621
  if (guard.bytes.isByteSource(v)) return guard.bytes.snapshotSource(v, ErrorClass, ctx.prefix + "/bad-input", what);
594
622
  throw E("bad-input", what + " must be a DER Buffer");
595
623
  }
596
- // A caller-supplied array a builder is about to map over: reject a sparse hole or a nullish entry HERE
597
- // as a typed error. Array.prototype.map SKIPS a hole, which would otherwise reach Buffer.concat as a
598
- // native ERR_INVALID_ARG_TYPE and, on a huge sparse length, traverse the empty slots. Test OWN-property
599
- // presence at each index BEFORE reading it: a bare `list[i]` on a hole walks the prototype chain, so a
600
- // polluted `Array.prototype[i]` would read as a value and slip a hole past the check while map still
601
- // skips it. Fails fast at the first bad index, so the length alone can never force a walk. Returns the
602
- // validated dense array for the caller to map normally.
603
- function reqDenseArray(list, what) {
604
- if (!_isArray(list)) throw E("bad-input", what + " must be an array");
605
- var n = list.length;
606
- for (var i = 0; i < n; i++) {
607
- if (!intrinsic.hasOwn(list, i)) throw E("bad-input", what + "[" + i + "] is missing (a sparse array is not allowed)");
608
- var v = list[i];
609
- if (v === undefined || v === null) throw E("bad-input", what + "[" + i + "] is missing (a nullish array entry is not allowed)");
610
- }
611
- return list;
612
- }
624
+ // The bound 2-arg form every makeBuilder consumer calls (`_b.reqDenseArray(list, what)`); it delegates
625
+ // to the standalone guard above with this builder's namespace, so the density rule lives in ONE place.
626
+ function reqDenseArray(list, what) { return reqDenseArrayImpl(list, what, rawErr, ctx.prefix + "/bad-input"); }
613
627
  // A caller-supplied DER a builder validates with a PEM-accepting parser and then embeds verbatim with
614
628
  // b.raw. Those parsers unwrap PEM from a byte source, so a PEM-armored input (a Buffer straight from
615
629
  // fs.readFileSync) passes the parse, but b.raw embeds the raw ASCII armor -- which the enclosing
@@ -817,4 +831,10 @@ function tbsSerialNumber(cert) {
817
831
  return asn1.read.integer(tbs.children[hasVersion ? 1 : 0]);
818
832
  }
819
833
 
820
- module.exports = { makeBuilder: makeBuilder, KU_BIT: KU_BIT, tbsNameField: tbsNameField, tbsSerialNumber: tbsSerialNumber };
834
+ // Frozen so a co-resident cannot reassign an exported guard (e.g. reqDenseArray) to bypass it: the
835
+ // standalone consumers read reqDenseArray off this object at call time, so the object holding it must be
836
+ // immutable, the way the guard-* modules freeze their surfaces.
837
+ // Frozen so a co-resident cannot reassign an exported guard (e.g. reqDenseArray) to bypass it: the
838
+ // standalone consumers read reqDenseArray off this object at call time, so the object holding it must be
839
+ // immutable, the way the guard-* modules freeze their surfaces.
840
+ module.exports = intrinsic.freeze({ makeBuilder: makeBuilder, reqDenseArray: reqDenseArrayImpl, KU_BIT: KU_BIT, tbsNameField: tbsNameField, tbsSerialNumber: tbsSerialNumber });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blamejs/pki",
3
- "version": "0.5.37",
3
+ "version": "0.5.38",
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:1796fef8-97af-4412-bcd2-31524856507a",
5
+ "serialNumber": "urn:uuid:fe024f86-e1b5-48d0-97ee-173c19cc63b0",
6
6
  "version": 1,
7
7
  "metadata": {
8
- "timestamp": "2026-08-30T00:38:29.705Z",
8
+ "timestamp": "2026-08-30T02:10:51.770Z",
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.5.37",
22
+ "bom-ref": "@blamejs/pki@0.5.38",
23
23
  "type": "application",
24
24
  "name": "pki",
25
- "version": "0.5.37",
25
+ "version": "0.5.38",
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.5.37",
29
+ "purl": "pkg:npm/%40blamejs/pki@0.5.38",
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.5.37",
57
+ "ref": "@blamejs/pki@0.5.38",
58
58
  "dependsOn": []
59
59
  }
60
60
  ]