@blamejs/pki 0.7.24 → 0.7.26

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/lib/ocsp.js CHANGED
@@ -222,6 +222,14 @@ function _normCertDer(cert, what) {
222
222
  * DER (RFC 6960 sec. 4.2.1: no CMS wrapper, no signed attributes). The responder certificate is
223
223
  * embedded in `certs [0]` so a relying party can find it. Returns the response DER, or PEM.
224
224
  *
225
+ * Each response may carry `singleExtensions`, as an object or as an array of pre-encoded Extension
226
+ * DER. The object form takes `archiveCutoff`, the Date before which the responder no longer holds
227
+ * status (RFC 6960 sec. 4.4.4), and `crlReferences`, a `{ crlUrl, crlNum, crlTime }` naming the CRL
228
+ * the status was drawn from (sec. 4.4.2), any subset of the three. A pre-encoded entry is read with
229
+ * the parser's own singleExtensions reader before it is emitted, so a response this verb signs is
230
+ * one `pki.schema.ocsp.parseResponse` reads back, and a malformed archiveCutoff or CrlID is refused
231
+ * here with the code the parser would have raised.
232
+ *
225
233
  * @opts
226
234
  * nonce a request nonce Buffer to echo back in responseExtensions (RFC 9654).
227
235
  * extendedRevoke emit the id-pkix-ocsp-extended-revoke extension (RFC 6960 sec. 4.4.8).
@@ -280,7 +288,7 @@ function _signResponse(responseData, responder, respCert, respCertDer, responder
280
288
 
281
289
  return _responderID(responseData.responderID, respCert).then(function (ridNode) {
282
290
  return Promise.all(responses.map(function (r) { return _buildSingleResponse(r, opts); })).then(function (srNodes) {
283
- var rdChildren = [ridNode, b.generalizedTime(_asDate(responseData.producedAt) || new Date()), b.sequence(srNodes)];
291
+ var rdChildren = [ridNode, b.generalizedTime(_asEncodableDate(responseData.producedAt, "producedAt") || new Date()), b.sequence(srNodes)];
284
292
  var respExts = [];
285
293
  if (opts.nonce != null) { _assertNonce(opts.nonce); respExts.push(_nonceExt(opts.nonce)); }
286
294
  if (opts.extendedRevoke) respExts.push(b.sequence([b.oid(OID_EXTENDED_REVOKE), b.octetString(b.nullValue())]));
@@ -303,6 +311,13 @@ function _asDate(d) {
303
311
  if (isNaN(guard.time.instantOf(dt))) throw _err("ocsp/bad-input", "an invalid date value " + guard.text.showValue(d));
304
312
  return dt;
305
313
  }
314
+ /** @internal `_asDate` for a Date this verb WRITES as a GeneralizedTime (producedAt, thisUpdate,
315
+ * nextUpdate, a revocation time): the encodable year range is held here so the fault stays in this
316
+ * verb's domain. The verify clock is only compared and stays on `_asDate`. */
317
+ function _asEncodableDate(d, which) {
318
+ var dt = _asDate(d);
319
+ return dt === null ? null : guard.time.assertEncodable(dt, _err, "ocsp/bad-input", which);
320
+ }
306
321
  function _snapshotSignerKey(key, owned) {
307
322
  if (Buffer.isBuffer(key) || key instanceof Uint8Array) { // allow:byte-source-narrow -- responder private key on the key-ownership contract (Buffer / Uint8Array / PEM / CryptoKey); widening keys is a separate root decision
308
323
  var copy = guard.bytes.snapshot(key, OcspError, "ocsp/bad-input", "the responder key");
@@ -331,8 +346,8 @@ function _buildSingleResponse(r, opts) {
331
346
  * attached handlers, and an earlier entry's rejection would be orphaned: the caller catches
332
347
  * sign()'s failure and the process still sees an unhandled rejection. */
333
348
  return certIdP.then(function (certID) {
334
- var thisUpdate = _asDate(r.thisUpdate) || new Date();
335
- var nextUpdate = r.nextUpdate === null ? null : (_asDate(r.nextUpdate) || _defaultNextUpdate());
349
+ var thisUpdate = _asEncodableDate(r.thisUpdate, "thisUpdate") || new Date();
350
+ var nextUpdate = r.nextUpdate === null ? null : (_asEncodableDate(r.nextUpdate, "nextUpdate") || _defaultNextUpdate());
336
351
  /** @internal RFC 6960 sec. 4.2.2.1 makes thisUpdate and nextUpdate a validity interval, and says
337
352
  * it corresponds to the {thisUpdate, nextUpdate} interval in CRLs. An interval whose end
338
353
  * precedes its start states a status window that closed before it opened, and pki.ocsp.verify
@@ -353,16 +368,76 @@ function _buildSingleResponse(r, opts) {
353
368
  var statusNode = _certStatusNode(r.status, opts);
354
369
  var srChildren = [certID, statusNode, b.generalizedTime(thisUpdate)];
355
370
  if (nextUpdate !== null) srChildren.push(b.explicit(0, b.generalizedTime(nextUpdate)));
356
- if (r.singleExtensions && r.singleExtensions.length) srChildren.push(b.explicit(1, b.sequence(r.singleExtensions)));
371
+ if (r.singleExtensions != null) {
372
+ var singleDer = _singleExtensionsDer(r.singleExtensions);
373
+ if (singleDer.length) srChildren.push(b.explicit(1, b.sequence(singleDer)));
374
+ }
357
375
  return b.sequence(srChildren);
358
376
  });
359
377
  }
360
378
  function _defaultNextUpdate() { return new Date(Date.now() + constants.TIME.days(7)); }
379
+ var _SINGLE_EXT_KEYS = Object.assign(Object.create(null), { archiveCutoff: 1, crlReferences: 1 });
380
+ var _CRL_ID_KEYS = Object.assign(Object.create(null), { crlUrl: 1, crlNum: 1, crlTime: 1 });
381
+
382
+ /** @internal RFC 6960 sec. 4.4.2 and sec. 4.4.4 put archiveCutoff and the CRL references in a
383
+ * SingleResponse's singleExtensions. The object form names them as fields; the array form carries
384
+ * pre-encoded Extension DER, and each entry is run through the parser's own singleExtensions reader
385
+ * first, so this verb never emits an entry pki.schema.ocsp.parseResponse would refuse. */
386
+ function _singleExtensionsDer(spec) {
387
+ if (Array.isArray(spec)) {
388
+ var dense = pkiBuild.reqDenseArray(spec, "singleExtensions", _err, "ocsp/bad-input");
389
+ var ders = dense.map(function (d, i) {
390
+ return guard.bytes.snapshotSource(d, OcspError, "ocsp/bad-input", "singleExtensions[" + i + "]");
391
+ });
392
+ if (ders.length) ocspSchema.readSingleExtensionsDer(ders);
393
+ return ders;
394
+ }
395
+ if (!spec || typeof spec !== "object" || Buffer.isBuffer(spec)) {
396
+ throw _err("ocsp/bad-input", "singleExtensions must be an object { archiveCutoff?, crlReferences? } or an array of pre-encoded Extension DER");
397
+ }
398
+ guard.identifier.assertKnownKeys(spec, _SINGLE_EXT_KEYS, _err, "ocsp/bad-input", function (k) {
399
+ return "unknown singleExtensions field " + guard.text.showValue(k) + " (accepted: archiveCutoff, crlReferences)";
400
+ });
401
+ var out = [];
402
+ if (spec.archiveCutoff != null) {
403
+ guard.time.assertEncodable(spec.archiveCutoff, _err, "ocsp/bad-input", "singleExtensions archiveCutoff");
404
+ out.push(b.sequence([b.oid(oid.byName("ocspArchiveCutoff")), b.octetString(b.generalizedTime(spec.archiveCutoff))]));
405
+ }
406
+ if (spec.crlReferences != null) {
407
+ var c = spec.crlReferences;
408
+ if (!c || typeof c !== "object" || Array.isArray(c) || Buffer.isBuffer(c)) {
409
+ throw _err("ocsp/bad-input", "singleExtensions crlReferences must be an object { crlUrl?, crlNum?, crlTime? }");
410
+ }
411
+ guard.identifier.assertKnownKeys(c, _CRL_ID_KEYS, _err, "ocsp/bad-input", function (k) {
412
+ return "unknown crlReferences field " + guard.text.showValue(k) + " (accepted: crlUrl, crlNum, crlTime)";
413
+ });
414
+ var fields = [];
415
+ if (c.crlUrl != null) {
416
+ if (typeof c.crlUrl !== "string" || !c.crlUrl.length) throw _err("ocsp/bad-input", "crlReferences crlUrl must be a non-empty string");
417
+ for (var j = 0; j < c.crlUrl.length; j++) {
418
+ if (c.crlUrl.charCodeAt(j) > 0x7f) throw _err("ocsp/bad-input", "crlReferences crlUrl must be 7-bit ASCII (an IA5String, RFC 6960 sec. 4.4.2)");
419
+ }
420
+ fields.push(b.explicit(0, b.ia5(c.crlUrl)));
421
+ }
422
+ if (c.crlNum != null) {
423
+ var num = guard.range.authoredInteger(c.crlNum, _err, "ocsp/bad-input", "crlReferences crlNum");
424
+ if (num < 0n) throw _err("ocsp/bad-input", "crlReferences crlNum must be non-negative (it is a cRLNumber, RFC 5280 sec. 5.2.3)");
425
+ fields.push(b.explicit(1, b.integer(num)));
426
+ }
427
+ if (c.crlTime != null) {
428
+ guard.time.assertEncodable(c.crlTime, _err, "ocsp/bad-input", "crlReferences crlTime");
429
+ fields.push(b.explicit(2, b.generalizedTime(c.crlTime)));
430
+ }
431
+ out.push(b.sequence([b.oid(oid.byName("ocspCrl")), b.octetString(b.sequence(fields))]));
432
+ }
433
+ return out;
434
+ }
435
+
361
436
  function _certStatusNode(status, opts) {
362
437
  if (status == null || status === "good") return b.contextPrimitive(0, Buffer.alloc(0));
363
438
  if (status === "unknown") return b.contextPrimitive(2, Buffer.alloc(0));
364
439
  if (typeof status === "object" && status.revoked != null) {
365
- var ri = [b.generalizedTime(_asDate(status.revoked))];
440
+ var ri = [b.generalizedTime(_asEncodableDate(status.revoked, "the revocation time"))];
366
441
  if (status.revocationReason != null) {
367
442
  var code = typeof status.revocationReason === "number" ? status.revocationReason : REASON_CODE[guard.text.keyOf(status.revocationReason)];
368
443
  if (code == null) throw _err("ocsp/bad-input", "unknown revocationReason " + guard.text.showValue(status.revocationReason));
package/lib/pki-build.js CHANGED
@@ -344,7 +344,7 @@ function makeBuilder(ctx) {
344
344
  function rawErr(fullCode, message, cause) { return new ErrorClass(fullCode, message, cause); }
345
345
 
346
346
  function timeDer(date, which) {
347
- guard.time.assertValid(date, rawErr, code("bad-input"), which);
347
+ guard.time.assertEncodable(date, rawErr, code("bad-input"), which);
348
348
  var y = date.getUTCFullYear();
349
349
  return (y >= 1950 && y <= 2049) ? b.utcTime(date) : b.generalizedTime(date);
350
350
  }
package/lib/schema-crl.js CHANGED
@@ -239,4 +239,9 @@ module.exports = {
239
239
  pemDecode: pemDecode,
240
240
  pemEncode: pemEncode,
241
241
  matches: matches,
242
+ /** @internal The reader this parser applies to a CRL entry extension (reasonCode, invalidityDate),
243
+ * for a consumer that meets the same extension elsewhere: RFC 6960 sec. 4.4.5 carries every CRL
244
+ * entry extension into an OCSP SingleResponse, and the linter reads it with this rather than a
245
+ * second one. Not on the curated `pki.schema.crl` surface. */
246
+ decodeExtension: decodeExt,
242
247
  };
@@ -41,6 +41,7 @@ var constants = require("./constants");
41
41
  var frameworkError = require("./framework-error");
42
42
  var intrinsic = require("./guard-intrinsic");
43
43
  var _hasOwn = intrinsic.hasOwn;
44
+ var _String = intrinsic.String;
44
45
 
45
46
  var OcspError = frameworkError.OcspError;
46
47
  var PemError = frameworkError.PemError;
@@ -56,6 +57,8 @@ var VERSION = pkix.versionReader(NS, {});
56
57
  var OID_OCSP_BASIC = oid.byName("ocspBasic");
57
58
 
58
59
  var OID_OCSP_NONCE = oid.byName("ocspNonce");
60
+ var OID_OCSP_ARCHIVE_CUTOFF = oid.byName("ocspArchiveCutoff");
61
+ var OID_OCSP_CRL = oid.byName("ocspCrl");
59
62
 
60
63
  var STATUS_NAMES = constants.NAMES.OCSP_STATUS;
61
64
 
@@ -92,10 +95,69 @@ function _rawSignature(field) {
92
95
 
93
96
  var CERTS = schema.seqOf(certificateBytes(), { assert: "sequence", code: "ocsp/bad-certs", what: "certs", max: constants.LIMITS.OCSP_MAX_CERTS, maxCode: "ocsp/too-many-certs" });
94
97
 
98
+ /** @internal RFC 6960 sec. 4.4.4: ArchiveCutoff ::= GeneralizedTime, carried as a singleExtension. */
99
+ function _readArchiveCutoff(ext) {
100
+ var node;
101
+ try { node = asn1.decode(ext.value); }
102
+ catch (e) { throw NS.E("ocsp/bad-archive-cutoff", "the archiveCutoff extension value did not decode: " + ((e && e.message) || _String(e)), e); }
103
+ if (!(node.tagClass === "universal" && node.tagNumber === asn1.TAGS.GENERALIZED_TIME)) {
104
+ throw NS.E("ocsp/bad-archive-cutoff", "the archiveCutoff extension value must be a GeneralizedTime (RFC 6960 sec. 4.4.4)");
105
+ }
106
+ try { return asn1.read.time(node); }
107
+ catch (e) { throw NS.E("ocsp/bad-archive-cutoff", "the archiveCutoff GeneralizedTime is malformed", e); }
108
+ }
109
+
110
+ /** @internal RFC 6960 sec. 4.4.2: CrlID ::= SEQUENCE { crlUrl [0] EXPLICIT IA5String OPTIONAL,
111
+ * crlNum [1] EXPLICIT INTEGER OPTIONAL, crlTime [2] EXPLICIT GeneralizedTime OPTIONAL }. Every
112
+ * field is optional and each may appear at most once, in tag order. */
113
+ function _readCrlId(ext) {
114
+ var C = "ocsp/bad-crl-id";
115
+ var node;
116
+ try { node = asn1.decode(ext.value); }
117
+ catch (e) { throw NS.E(C, "the CRL references extension value did not decode: " + ((e && e.message) || _String(e)), e); }
118
+ if (!(node.tagClass === "universal" && node.tagNumber === asn1.TAGS.SEQUENCE && node.children)) {
119
+ throw NS.E(C, "CrlID must be a SEQUENCE (RFC 6960 sec. 4.4.2)");
120
+ }
121
+ var out = { crlUrl: null, crlNum: null, crlTime: null }, last = -1;
122
+ for (var i = 0; i < node.children.length; i++) {
123
+ var k = node.children[i];
124
+ if (k.tagClass !== "context" || !k.constructed || !k.children || k.children.length !== 1) {
125
+ throw NS.E(C, "each CrlID member must be one EXPLICIT [0], [1] or [2] tag (RFC 6960 sec. 4.4.2)");
126
+ }
127
+ if (k.tagNumber <= last) throw NS.E(C, "CrlID members must appear at most once, in tag order");
128
+ last = k.tagNumber;
129
+ var inner = k.children[0];
130
+ try {
131
+ if (k.tagNumber === 0) {
132
+ if (inner.tagClass !== "universal" || inner.tagNumber !== asn1.TAGS.IA5_STRING) throw NS.E(C, "crlUrl must be an IA5String");
133
+ out.crlUrl = asn1.read.string(inner);
134
+ } else if (k.tagNumber === 1) {
135
+ if (inner.tagClass !== "universal" || inner.tagNumber !== asn1.TAGS.INTEGER) throw NS.E(C, "crlNum must be an INTEGER");
136
+ out.crlNum = asn1.read.integer(inner);
137
+ if (out.crlNum < 0n) throw NS.E(C, "crlNum must be non-negative (it is a cRLNumber, RFC 5280 sec. 5.2.3)");
138
+ } else if (k.tagNumber === 2) {
139
+ if (inner.tagClass !== "universal" || inner.tagNumber !== asn1.TAGS.GENERALIZED_TIME) throw NS.E(C, "crlTime must be a GeneralizedTime");
140
+ out.crlTime = asn1.read.time(inner);
141
+ } else {
142
+ throw NS.E(C, "CrlID has no member tagged [" + k.tagNumber + "] (RFC 6960 sec. 4.4.2)");
143
+ }
144
+ } catch (e) {
145
+ if (e && e.code === C) throw e;
146
+ throw NS.E(C, "CrlID member [" + k.tagNumber + "] is malformed", e);
147
+ }
148
+ }
149
+ return out;
150
+ }
151
+
152
+ /** @internal The extensions this profile reads are decoded onto their entry beside the raw value,
153
+ * so a consumer gets the value by name and a malformed one is refused here rather than passed
154
+ * through as opaque bytes. The nonce is RFC 9654; the other two are RFC 6960 sec. 4.4. */
95
155
  function _validateOcspExtensions(list) {
96
156
  if (!list) return list;
97
157
  for (var i = 0; i < list.length; i++) {
98
158
  var ext = list[i];
159
+ if (ext.oid === OID_OCSP_ARCHIVE_CUTOFF) { ext.archiveCutoff = _readArchiveCutoff(ext); continue; }
160
+ if (ext.oid === OID_OCSP_CRL) { ext.crlReferences = _readCrlId(ext); continue; }
99
161
  if (ext.oid !== OID_OCSP_NONCE) continue;
100
162
  var node;
101
163
  try { node = asn1.decode(ext.value); }
@@ -235,6 +297,7 @@ var BASIC_OCSP_RESPONSE = schema.seq([
235
297
  signatureAlgorithm: m.fields.signatureAlgorithm.value.result,
236
298
  signature: _rawSignature(m.fields.signature),
237
299
  certs: m.fields.certs.present ? m.fields.certs.value.items.map(function (it) { return it.value; }) : [],
300
+ certsPresent: m.fields.certs.present,
238
301
  };
239
302
  },
240
303
  });
@@ -397,8 +460,10 @@ var parseRequest = pkix.makeParser({ pemLabel: "OCSP REQUEST", PemError: PemErro
397
460
  * Parse a DER `Buffer` or a PEM (`OCSP RESPONSE`) string into a structured
398
461
  * OCSPResponse: `{ responseStatus, responseBytes, basicResponse }`. For a successful
399
462
  * basic response, `basicResponse` carries `{ tbsResponseDataBytes, responderID,
400
- * producedAt, responses, signatureAlgorithm, signature, certs }`; each
401
- * `responses[i].certStatus` is `{ type: "good" | "revoked" | "unknown" }`. A
463
+ * producedAt, responses, signatureAlgorithm, signature, certs, certsPresent }`; each
464
+ * `responses[i].certStatus` is `{ type: "good" | "revoked" | "unknown" }`. `certs` is the
465
+ * embedded certificate list, empty when the field is absent, and `certsPresent` says
466
+ * whether the response carried the field at all. A
402
467
  * non-successful status carries no `responseBytes`. A malformed structure throws a
403
468
  * typed `OcspError` (`ocsp/*`); an unsupported `responseType` throws
404
469
  * `ocsp/unsupported-response-type`.
@@ -500,4 +565,13 @@ module.exports = {
500
565
  pemEncode: pemEncode,
501
566
  matchesRequest: matchesRequest,
502
567
  matchesResponse: matchesResponse,
568
+ /** @internal Reads a list of pre-encoded Extension DER the way this parser reads a SingleResponse's
569
+ * singleExtensions, shared with pki.ocsp.sign so an entry the signer emits is one the parser
570
+ * reads. Throws the parser's own ocsp/* code for a malformed entry. */
571
+ readSingleExtensionsDer: function (derList) {
572
+ var node;
573
+ try { node = asn1.decode(asn1.build.sequence(intrinsic.map(derList, function (d) { return asn1.build.raw(d); }))); }
574
+ catch (e) { throw NS.E("ocsp/bad-single-response", "a pre-encoded singleExtension is not DER", e); }
575
+ return _validateOcspExtensions(schema.walk(EXTENSIONS, node, NS).result);
576
+ },
503
577
  };
package/lib/tsp-sign.js CHANGED
@@ -167,7 +167,7 @@ function _sign(messageImprint, tsa, opts) {
167
167
  if (!NODE_DIGEST[guard.text.keyOf(certHashAlg)]) throw _err("tsp/unsupported-algorithm", "unsupported certHashAlgorithm " + guard.text.showValue(certHashAlg));
168
168
 
169
169
  var imprint = b.sequence([_hashAlgId(mi.hashAlgorithm), b.octetString(guard.bytes.source(mi.hashedMessage, TspError, "tsp/bad-input", "messageImprint.hashedMessage"))]);
170
- if (opts.genTime != null) guard.time.assertValid(opts.genTime, _err, "tsp/bad-input", "genTime");
170
+ if (opts.genTime != null) guard.time.assertEncodable(opts.genTime, _err, "tsp/bad-input", "genTime");
171
171
  var genTime = guard.time.isDate(opts.genTime) ? opts.genTime : new Date();
172
172
  var serial = guard.range.authoredInteger(opts.serialNumber, _err, "tsp/bad-input", "serialNumber");
173
173
  var fields = [b.integer(1n), _policy(opts.policy), imprint, b.integer(serial), b.generalizedTime(genTime)];
package/lib/x509-sign.js CHANGED
@@ -504,9 +504,9 @@ function _sign(spec, issuer, opts) {
504
504
  var scheme = signScheme.resolveSignScheme(_certLikeFromSpki(issuerSpki), { combinedRsaSig: true, pss: opts.pss, digestAlgorithm: opts.digestAlgorithm }, true, _signE);
505
505
 
506
506
  var serialTlv = _serialInteger(spec.serialNumber);
507
- guard.time.assertValid(spec.notBefore, _err, "x509/bad-input", "notBefore");
508
- guard.time.assertValid(spec.notAfter, _err, "x509/bad-input", "notAfter");
509
- // allow:nan-date-comparison-unguarded -- both operands are guard.time.assertValid'd on the two lines above (an Invalid Date throws before this comparison).
507
+ guard.time.assertEncodable(spec.notBefore, _err, "x509/bad-input", "notBefore");
508
+ guard.time.assertEncodable(spec.notAfter, _err, "x509/bad-input", "notAfter");
509
+ // allow:nan-date-comparison-unguarded -- both operands are guard.time.assertEncodable'd on the two lines above (an Invalid Date throws before this comparison).
510
510
  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)");
511
511
  var validityDer = b.sequence([_timeDer(spec.notBefore, "notBefore"), _timeDer(spec.notAfter, "notAfter")]);
512
512
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blamejs/pki",
3
- "version": "0.7.24",
3
+ "version": "0.7.26",
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:afc45867-a237-46a4-91ea-4cb590b54d06",
5
+ "serialNumber": "urn:uuid:4d386905-4bf6-44a7-b504-c8e9fe74646d",
6
6
  "version": 1,
7
7
  "metadata": {
8
- "timestamp": "2026-09-12T00:45:51.621Z",
8
+ "timestamp": "2026-09-12T03:45:28.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.7.24",
22
+ "bom-ref": "@blamejs/pki@0.7.26",
23
23
  "type": "application",
24
24
  "name": "pki",
25
- "version": "0.7.24",
25
+ "version": "0.7.26",
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.7.24",
29
+ "purl": "pkg:npm/%40blamejs/pki@0.7.26",
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.7.24",
57
+ "ref": "@blamejs/pki@0.7.26",
58
58
  "dependsOn": []
59
59
  }
60
60
  ]