@blamejs/pki 0.5.32 → 0.5.34
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 +17 -0
- package/README.md +1 -1
- package/lib/cms-sign.js +207 -86
- package/lib/cms-verify.js +360 -239
- package/lib/guard-bytes.js +32 -1
- package/lib/guard-intrinsic.js +13 -0
- package/lib/pki-build.js +29 -6
- package/lib/webcrypto.js +79 -0
- package/package.json +2 -2
- package/sbom.cdx.json +6 -6
package/lib/guard-bytes.js
CHANGED
|
@@ -27,6 +27,8 @@ var _bufferFrom = intrinsic.bufferFrom;
|
|
|
27
27
|
// question this guard asked on the caller's behalf. See guard-intrinsic for the whole set.
|
|
28
28
|
var _isView = intrinsic.isView;
|
|
29
29
|
var _isBuffer = intrinsic.isBuffer;
|
|
30
|
+
var _asyncIterator = intrinsic.asyncIterator;
|
|
31
|
+
var _NO_ARGS = intrinsic.freeze([]);
|
|
30
32
|
var _create = intrinsic.create;
|
|
31
33
|
var _getPrototypeOf = intrinsic.getPrototypeOf;
|
|
32
34
|
var _getOwnPropertyDescriptor = intrinsic.getOwnPropertyDescriptor;
|
|
@@ -80,6 +82,35 @@ function isByteSource(x) {
|
|
|
80
82
|
return _isBuffer(x) || _isView(x) || _isArrayBuffer(x);
|
|
81
83
|
}
|
|
82
84
|
|
|
85
|
+
// asyncStreamOf(x) -> a LAZY single-use async iterable of x's byte chunks, or null when x is not a
|
|
86
|
+
// byte stream.
|
|
87
|
+
//
|
|
88
|
+
// A door offering both a byte source and a streamed content (an async iterable of byte chunks) asks
|
|
89
|
+
// this ONE module which it has, instead of re-inlining the `for await` protocol test and drifting on
|
|
90
|
+
// what counts. It reads x's Symbol.asyncIterator EXACTLY ONCE, captures that method, and returns a
|
|
91
|
+
// thin iterable that CALLS it only when the consumer drives the stream. Deferring the call matters
|
|
92
|
+
// twice: the underlying iterator is acquired once, in the digest engine, so reading the protocol
|
|
93
|
+
// property a second time downstream cannot fire a one-shot or stateful accessor and refuse a stream a
|
|
94
|
+
// direct `for await` accepts; AND a caller whose iterator factory opens a file or socket has that
|
|
95
|
+
// resource opened only on a path that will actually consume it, never on a pre-hash rejection (a
|
|
96
|
+
// missing detached option, an empty signer list, a message needing no streamed digest) that would
|
|
97
|
+
// otherwise acquire and leak it. A byte source is bytes, never a stream, EVEN when a caller attached a
|
|
98
|
+
// Symbol.asyncIterator to it: the byte-source classification wins and is checked FIRST, so a Buffer /
|
|
99
|
+
// typed array / DataView goes down the byte path every time and its own accessors are never invoked
|
|
100
|
+
// here. A callable carrying the method is a valid async iterable that `for await` consumes, so it too
|
|
101
|
+
// yields a stream.
|
|
102
|
+
// @enforced-by behavioral -- a lazy stream wrapper has no rename-proof code shape; the RED vectors (a
|
|
103
|
+
// stream produced where a byte source is not, a one-shot-accessor stream still consumed, and the
|
|
104
|
+
// factory NOT invoked until the stream is driven) are the guard.
|
|
105
|
+
function asyncStreamOf(x) {
|
|
106
|
+
if (isByteSource(x) || x == null || (typeof x !== "object" && typeof x !== "function")) return null;
|
|
107
|
+
var acquire = x[_asyncIterator];
|
|
108
|
+
if (typeof acquire !== "function") return null;
|
|
109
|
+
var stream = {};
|
|
110
|
+
stream[_asyncIterator] = function () { return _apply(acquire, x, _NO_ARGS); };
|
|
111
|
+
return stream;
|
|
112
|
+
}
|
|
113
|
+
|
|
83
114
|
// Is this value a byte store, asked of the internal slot rather than the prototype?
|
|
84
115
|
//
|
|
85
116
|
// `v instanceof ArrayBuffer` answers what a value inherits from, which is a different question
|
|
@@ -1057,6 +1088,6 @@ function fixedCall(ErrorClass, code, args, body) {
|
|
|
1057
1088
|
// call, so a writable export would let a caller replace the check rather than pass it.
|
|
1058
1089
|
module.exports = intrinsic.freeze({
|
|
1059
1090
|
view: view, source: source, snapshot: snapshot, snapshotSource: snapshotSource,
|
|
1060
|
-
isByteSource: isByteSource, lengthOf: lengthOf, outputView: outputView,
|
|
1091
|
+
isByteSource: isByteSource, asyncStreamOf: asyncStreamOf, lengthOf: lengthOf, outputView: outputView,
|
|
1061
1092
|
snapshotDeep: snapshotDeep, fixArguments: fixArguments, fixedCall: fixedCall,
|
|
1062
1093
|
});
|
package/lib/guard-intrinsic.js
CHANGED
|
@@ -59,6 +59,10 @@ var _bufferCompare = Buffer.compare;
|
|
|
59
59
|
// response is about this issuer, a responder ID says this key signed it. Dispatched live, one
|
|
60
60
|
// answering true makes a response about a DIFFERENT certificate match the one being asked about.
|
|
61
61
|
var _bufferEquals = uncurry(Buffer.prototype.equals);
|
|
62
|
+
// Buffer#toString, uncurried at load. Used to build dedup keys (a hex string) from bytes the toolkit
|
|
63
|
+
// owns; dispatched live, a replaced toString could make two distinct values key alike or one value key
|
|
64
|
+
// differently on two reads, so a dedup over untrusted-adjacent bytes would merge or split wrongly.
|
|
65
|
+
var _bufferToString = uncurry(Buffer.prototype.toString);
|
|
62
66
|
|
|
63
67
|
// The rest of what a guard reads from the runtime while it is deciding something. These are
|
|
64
68
|
// grouped here rather than captured file by file so the set is enumerable in one place and a guard
|
|
@@ -94,6 +98,13 @@ var _mathMax = Math.max;
|
|
|
94
98
|
var _parseInt = parseInt;
|
|
95
99
|
var _promiseResolve = Promise.resolve;
|
|
96
100
|
var _promiseReject = Promise.reject;
|
|
101
|
+
// The well-known async-iteration symbol, captured at load. `for await` uses this symbol at the
|
|
102
|
+
// language level regardless of the global `Symbol` object, so a classifier that reads
|
|
103
|
+
// `Symbol.asyncIterator` live would disagree with the loop the moment a co-resident replaced the
|
|
104
|
+
// writable `Symbol` global: a real async iterable would be looked up under the wrong key, judged not
|
|
105
|
+
// iterable, and refused where the engine would have consumed it. Reading the captured symbol keeps
|
|
106
|
+
// the door's answer and the loop's behavior the same.
|
|
107
|
+
var _asyncIterator = Symbol.asyncIterator;
|
|
97
108
|
|
|
98
109
|
// The array operations, uncurried at load. These run on arrays the TOOLKIT owns -- an `ownKeys`
|
|
99
110
|
// result, a local accumulator -- so the receiver is never a caller's object; what is caller-
|
|
@@ -274,6 +285,7 @@ module.exports = Object.freeze({
|
|
|
274
285
|
bufferFrom: _bufferFrom,
|
|
275
286
|
bufferAlloc: _bufferAlloc,
|
|
276
287
|
bufferConcat: _bufferConcat,
|
|
288
|
+
bufToString: _bufferToString,
|
|
277
289
|
isBuffer: _bufferIsBuffer,
|
|
278
290
|
byteLength: _bufferByteLength,
|
|
279
291
|
compare: _bufferCompare,
|
|
@@ -309,6 +321,7 @@ module.exports = Object.freeze({
|
|
|
309
321
|
bigIntToString: _bigIntToString,
|
|
310
322
|
promiseResolve: _promiseResolve,
|
|
311
323
|
promiseReject: _promiseReject,
|
|
324
|
+
asyncIterator: _asyncIterator,
|
|
312
325
|
forEach: _arrForEach,
|
|
313
326
|
map: _arrMap,
|
|
314
327
|
filter: _arrFilter,
|
package/lib/pki-build.js
CHANGED
|
@@ -70,7 +70,8 @@ function _isSubDelim(c) {
|
|
|
70
70
|
function _isUserinfoByte(c) { return _isUnreserved(c) || _isSubDelim(c) || c === 58; }
|
|
71
71
|
// A path/query/fragment byte: unreserved / sub-delim / a non-bracket gen-delim (":" "/" "?" "#" "@").
|
|
72
72
|
// "%" is handled separately (it must open a "%HEXHEX" triplet); the IP-literal brackets "[" "]" are
|
|
73
|
-
// excluded
|
|
73
|
+
// excluded here because they are authority syntax -- a bracketed IPv6 host is validated in
|
|
74
|
+
// _validUriAuthority (RFC 3986 sec. 3.2.2), never in the path.
|
|
74
75
|
function _isUriByte(c) {
|
|
75
76
|
return _isUnreserved(c) || _isSubDelim(c) || c === 58 || c === 47 || c === 63 || c === 35 || c === 64;
|
|
76
77
|
}
|
|
@@ -122,8 +123,8 @@ function _componentBytesOk(s, from, to, byteOk) {
|
|
|
122
123
|
// or an FQDN of strict-LDH labels (the email-domain grammar: no underscore, no hyphen at a label edge) with
|
|
123
124
|
// at least one dot -- a single-label host such as "localhost" is not fully qualified and uses the object
|
|
124
125
|
// form, matching the email domain. An IPv4-SHAPED host that is not a valid address is refused as ambiguous
|
|
125
|
-
// (the same rule the top-level classifier uses)
|
|
126
|
-
//
|
|
126
|
+
// (the same rule the top-level classifier uses). An IPv6-literal host is written in "[" "]" and validated
|
|
127
|
+
// by _validUriIp6Host from _validUriAuthority, never reaching this unbracketed-host check.
|
|
127
128
|
function _validUriHost(s, from, to) {
|
|
128
129
|
if (to <= from) return false; // empty host
|
|
129
130
|
var host = _sliceStr(s, from, to), len = host.length;
|
|
@@ -135,10 +136,21 @@ function _validUriHost(s, from, to) {
|
|
|
135
136
|
return _labelsValid(host, 0, len, _isHostLabelRange, true); // strict-LDH FQDN, root "." allowed
|
|
136
137
|
}
|
|
137
138
|
|
|
139
|
+
// A bracketed IPv6-literal URI host (RFC 3986 sec. 3.2.2): the bytes between "[" and "]" must be a valid
|
|
140
|
+
// IPv6 address (16 packed octets), never an IPv4 literal (which uses the unbracketed IPv4address form). The
|
|
141
|
+
// bracket is the ONLY way to write an IPv6 host in a URI, and an IPv6 host is a valid iPAddress per RFC 5280
|
|
142
|
+
// sec. 4.2.1.6, so the shorthand accepts it rather than forcing the object form.
|
|
143
|
+
function _validUriIp6Host(s, from, to) {
|
|
144
|
+
if (to <= from) return false; // empty "[ ]"
|
|
145
|
+
var packed = _packIpLiteral(_sliceStr(s, from, to));
|
|
146
|
+
return packed !== null && intrinsic.sizeOf(packed) === 16; // IPv6 literal only (16 octets)
|
|
147
|
+
}
|
|
148
|
+
|
|
138
149
|
// The authority in [from,to) is "[ userinfo "@" ] host [ ":" port ]" (RFC 3986 sec. 3.2): at most one "@"
|
|
139
|
-
// (userinfo and reg-name each exclude it), a host
|
|
140
|
-
// an all-digit -- possibly empty -- port after the host's
|
|
141
|
-
//
|
|
150
|
+
// (userinfo and reg-name each exclude it), a host that is an RFC 5280 FQDN or IPv4 (_validUriHost) or a
|
|
151
|
+
// bracketed IPv6 literal (_validUriIp6Host), and an all-digit -- possibly empty -- port after the host's
|
|
152
|
+
// ":". A bracketed host is taken as ONE unit before the port, so a ":" inside the IPv6 literal is not read
|
|
153
|
+
// as the port separator. The userinfo bytes are validated against the RFC 3986 userinfo class.
|
|
142
154
|
function _validUriAuthority(s, from, to) {
|
|
143
155
|
var i, c, at = -1;
|
|
144
156
|
for (i = from; i < to; i += 1) {
|
|
@@ -147,6 +159,17 @@ function _validUriAuthority(s, from, to) {
|
|
|
147
159
|
}
|
|
148
160
|
var hostStart = at === -1 ? from : at + 1;
|
|
149
161
|
if (at !== -1 && !_componentBytesOk(s, from, at, _isUserinfoByte)) return false; // userinfo
|
|
162
|
+
if (hostStart < to && _charCodeAt(s, hostStart) === 91) { // "[" -> bracketed IPv6 host
|
|
163
|
+
var close = -1;
|
|
164
|
+
for (i = hostStart + 1; i < to; i += 1) { if (_charCodeAt(s, i) === 93) { close = i; break; } } // "]"
|
|
165
|
+
if (close === -1) return false; // unterminated "["
|
|
166
|
+
if (!_validUriIp6Host(s, hostStart + 1, close)) return false; // IPv6 literal in "[ ]"
|
|
167
|
+
var after = close + 1;
|
|
168
|
+
if (after === to) return true; // "[ ipv6 ]" with no port
|
|
169
|
+
if (_charCodeAt(s, after) !== 58) return false; // only a ":" port may follow "]"
|
|
170
|
+
for (i = after + 1; i < to; i += 1) { if (!_isDigitCode(_charCodeAt(s, i))) return false; } // port = *DIGIT
|
|
171
|
+
return true;
|
|
172
|
+
}
|
|
150
173
|
var colon = -1;
|
|
151
174
|
for (i = hostStart; i < to; i += 1) { if (_charCodeAt(s, i) === 58) { colon = i; break; } } // ":" -> port
|
|
152
175
|
var hostEnd = colon === -1 ? to : colon;
|
package/lib/webcrypto.js
CHANGED
|
@@ -54,6 +54,14 @@ var _hasOwn = intrinsic.hasOwn;
|
|
|
54
54
|
var _stringify = intrinsic.stringify;
|
|
55
55
|
var _bufferFrom = intrinsic.bufferFrom;
|
|
56
56
|
var _bufToString = intrinsic.uncurry(Buffer.prototype.toString);
|
|
57
|
+
// The node Hash instance methods, captured at load. digestStream feeds chunks across `await` points,
|
|
58
|
+
// and a co-resident that replaced Hash.prototype.update while the stream was suspended between chunks
|
|
59
|
+
// could drop or alter one -- making digest("ab") equal digest("a") -- and, because both streamed
|
|
60
|
+
// signing and verification trust this digest, forge a valid verdict over bytes the stream never
|
|
61
|
+
// yielded. Calling the captured update/digest keeps the hash bound to the bytes the stream saw. The
|
|
62
|
+
// one-shot digest needs no such capture: its single update and digest run with no suspension between.
|
|
63
|
+
var _hashUpdate = intrinsic.uncurry(nodeCrypto.Hash.prototype.update);
|
|
64
|
+
var _hashDigest = intrinsic.uncurry(nodeCrypto.Hash.prototype.digest);
|
|
57
65
|
var _bufferConcat = intrinsic.bufferConcat;
|
|
58
66
|
var _bufferAlloc = intrinsic.bufferAlloc;
|
|
59
67
|
var _isBuffer = intrinsic.isBuffer;
|
|
@@ -76,6 +84,9 @@ var _Uint8Array = intrinsic.Uint8Array;
|
|
|
76
84
|
var _assign = intrinsic.assign;
|
|
77
85
|
var _create = intrinsic.create;
|
|
78
86
|
var _isView = intrinsic.isView;
|
|
87
|
+
var _asyncIterator = intrinsic.asyncIterator;
|
|
88
|
+
var _apply = intrinsic.apply;
|
|
89
|
+
var _NO_ARGS = intrinsic.freeze([]);
|
|
79
90
|
var _toUpperCase = intrinsic.toUpperCase;
|
|
80
91
|
var _toLowerCase = intrinsic.toLowerCase;
|
|
81
92
|
var _stringIndexOf = intrinsic.stringIndexOf;
|
|
@@ -334,6 +345,74 @@ SubtleCrypto.prototype.digest = async function digest(algorithm, data) {
|
|
|
334
345
|
return _toArrayBuffer(h.digest());
|
|
335
346
|
};
|
|
336
347
|
|
|
348
|
+
// Digest an async iterable of byte chunks under several algorithms in ONE pass, returning one
|
|
349
|
+
// ArrayBuffer per algorithm in order. Each result is byte-identical to digest(algorithms[i], <the
|
|
350
|
+
// concatenated chunks>): the same createHash + XOF handling, fed incrementally so an arbitrarily
|
|
351
|
+
// large payload is never held whole. The single pass is what lets a multi-signer detached CMS sign
|
|
352
|
+
// hash a single-use stream once for every distinct digest algorithm. Which algorithm each Hash runs
|
|
353
|
+
// is fixed up front through the captured name resolution (_normalizeAlg / _toUpperCase / _hashNode),
|
|
354
|
+
// exactly as the one-shot digest resolves it, so a replaced toUpperCase cannot swap SHA-256 for SHA-1
|
|
355
|
+
// mid-stream. A chunk that is not a BufferSource throws webcrypto/data, before it reaches a hash.
|
|
356
|
+
SubtleCrypto.prototype.digestStream = async function digestStream(algorithms, source) {
|
|
357
|
+
if (!_isArray(algorithms) || !algorithms.length) {
|
|
358
|
+
throw new WebCryptoError("webcrypto/syntax", "digestStream: algorithms must be a non-empty array of digest algorithms");
|
|
359
|
+
}
|
|
360
|
+
// Follow the async-iteration protocol exactly as `for await` does: read the source's
|
|
361
|
+
// Symbol.asyncIterator ONCE, call it to obtain the iterator, then capture THAT iterator's `next` with
|
|
362
|
+
// a single read and drive it manually. Driving `source` by its own `next` would diverge from
|
|
363
|
+
// `for await` whenever Symbol.asyncIterator returns a distinct iterator, and an inherited `next` (say
|
|
364
|
+
// from a polluted prototype) would misclassify an ordinary iterable; going through the method avoids
|
|
365
|
+
// both. Native `for await` caches `next` after one read, so capturing each method once and reusing it
|
|
366
|
+
// -- rather than re-reading to drive the loop -- also consumes a one-shot or stateful accessor a
|
|
367
|
+
// direct `for await` accepts.
|
|
368
|
+
// Build (and thereby validate) the hashes BEFORE acquiring the iterator: an unsupported algorithm
|
|
369
|
+
// must reject before the iterator factory runs, so a factory that opens a file or socket is never
|
|
370
|
+
// invoked -- and never leaked outside the cleanup guard -- on a rejection, keeping the lazy-stream
|
|
371
|
+
// guarantee that a pre-hash rejection acquires no resource.
|
|
372
|
+
// A plain index loop, not `_map`: Array.prototype.map SKIPS holes, so a sparse list such as
|
|
373
|
+
// `[, "SHA-256"]` would leave a hole in `hashes` (later read as `undefined` and updated as a raw
|
|
374
|
+
// TypeError) or, if fully sparse, yield sparse output. Indexing every slot instead makes a hole read
|
|
375
|
+
// as `undefined`, which `_normalizeAlg` rejects with a typed webcrypto/syntax before any chunk is read.
|
|
376
|
+
var hashes = [];
|
|
377
|
+
for (var _h = 0; _h < algorithms.length; _h++) {
|
|
378
|
+
var name = _normalizeAlg(algorithms[_h], "digestStream").name;
|
|
379
|
+
var xof = XOF_NODE[_toUpperCase(_String(name))];
|
|
380
|
+
hashes[_h] = xof
|
|
381
|
+
? nodeCrypto.createHash(xof.node, { outputLength: xof.length })
|
|
382
|
+
: nodeCrypto.createHash(_hashNode(name, "digestStream"));
|
|
383
|
+
}
|
|
384
|
+
var acquire = source == null ? undefined : source[_asyncIterator];
|
|
385
|
+
if (typeof acquire !== "function") {
|
|
386
|
+
throw new WebCryptoError("webcrypto/syntax", "digestStream: source must be an async iterable of byte chunks");
|
|
387
|
+
}
|
|
388
|
+
var iterator = _apply(acquire, source, _NO_ARGS);
|
|
389
|
+
try {
|
|
390
|
+
// The `next` retrieval and its validation are INSIDE the guard: the factory above may have opened a
|
|
391
|
+
// resource, so a non-callable next (or a throwing next accessor) must still reach the cleanup below
|
|
392
|
+
// that calls the iterator's return(), rather than leak on a malformed iterator protocol.
|
|
393
|
+
var nextMethod = iterator == null ? undefined : iterator.next;
|
|
394
|
+
if (typeof nextMethod !== "function") {
|
|
395
|
+
throw new WebCryptoError("webcrypto/syntax", "digestStream: source must be an async iterable of byte chunks");
|
|
396
|
+
}
|
|
397
|
+
for (;;) {
|
|
398
|
+
var step = await _apply(nextMethod, iterator, _NO_ARGS);
|
|
399
|
+
if (step && step.done) break;
|
|
400
|
+
var buf = _toBuf(step == null ? undefined : step.value, "digestStream chunk");
|
|
401
|
+
for (var i = 0; i < hashes.length; i++) _hashUpdate(hashes[i], buf);
|
|
402
|
+
}
|
|
403
|
+
} catch (e) {
|
|
404
|
+
// Best-effort completion, as `for await` performs on an early exit or throw: let the source release.
|
|
405
|
+
// The retrieval of `return` is INSIDE the guard too, so a throwing `return` accessor cannot replace
|
|
406
|
+
// the original error -- the malformed-chunk verdict is what the caller must see, not a cleanup fault.
|
|
407
|
+
try {
|
|
408
|
+
var ret = iterator == null ? undefined : iterator.return;
|
|
409
|
+
if (typeof ret === "function") await _apply(ret, iterator, _NO_ARGS);
|
|
410
|
+
} catch (_r) { /* cleanup is best-effort */ }
|
|
411
|
+
throw e;
|
|
412
|
+
}
|
|
413
|
+
return _map(hashes, function (h) { return _toArrayBuffer(_hashDigest(h)); });
|
|
414
|
+
};
|
|
415
|
+
|
|
337
416
|
SubtleCrypto.prototype.generateKey = async function generateKey(algorithm, extractable, keyUsages) {
|
|
338
417
|
var alg = _normalizeAlg(algorithm, "generateKey");
|
|
339
418
|
// Before the partition below, not only in the CryptoKey constructor: the asymmetric branch splits
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blamejs/pki",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.34",
|
|
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",
|
|
@@ -83,6 +83,6 @@
|
|
|
83
83
|
"devDependencies": {
|
|
84
84
|
"c8": "12.0.0",
|
|
85
85
|
"esbuild": "0.28.2",
|
|
86
|
-
"eslint": "10.
|
|
86
|
+
"eslint": "10.9.1"
|
|
87
87
|
}
|
|
88
88
|
}
|
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:
|
|
5
|
+
"serialNumber": "urn:uuid:849173ca-4a17-451d-91be-1f2d75d83f00",
|
|
6
6
|
"version": 1,
|
|
7
7
|
"metadata": {
|
|
8
|
-
"timestamp": "2026-08-
|
|
8
|
+
"timestamp": "2026-08-29T10:04:44.768Z",
|
|
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.
|
|
22
|
+
"bom-ref": "@blamejs/pki@0.5.34",
|
|
23
23
|
"type": "application",
|
|
24
24
|
"name": "pki",
|
|
25
|
-
"version": "0.5.
|
|
25
|
+
"version": "0.5.34",
|
|
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.
|
|
29
|
+
"purl": "pkg:npm/%40blamejs/pki@0.5.34",
|
|
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.
|
|
57
|
+
"ref": "@blamejs/pki@0.5.34",
|
|
58
58
|
"dependsOn": []
|
|
59
59
|
}
|
|
60
60
|
]
|