@blamejs/pki 0.8.59 → 0.8.61
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 +57 -0
- package/lib/acme.js +15 -7
- package/lib/alt-sig.js +3 -1
- package/lib/asn1-der.js +82 -34
- package/lib/attrcert-sign.js +19 -16
- package/lib/byte-writer.js +63 -13
- package/lib/cbor-det.js +9 -3
- package/lib/cmc-build.js +26 -18
- package/lib/cmp-build.js +35 -33
- package/lib/cmp-session.js +19 -9
- package/lib/cms-decrypt.js +37 -23
- package/lib/cms-digest.js +2 -3
- package/lib/cms-encrypt.js +38 -33
- package/lib/cms-sign.js +65 -43
- package/lib/cms-verify.js +8 -4
- package/lib/composite-kem.js +28 -29
- package/lib/crl-sign.js +24 -17
- package/lib/crmf-sign.js +11 -17
- package/lib/csr-sign.js +5 -2
- package/lib/ct.js +38 -25
- package/lib/est.js +12 -9
- package/lib/guard-bytes.js +5 -1
- package/lib/guard-crypto.js +506 -14
- package/lib/guard-der.js +6 -1
- package/lib/guard-intrinsic.js +12 -4
- package/lib/guard-list.js +64 -0
- package/lib/guard-name.js +1 -1
- package/lib/guard-secret.js +3 -2
- package/lib/hpke.js +34 -27
- package/lib/http-digest.js +5 -7
- package/lib/http-transport.js +12 -3
- package/lib/inspect.js +10 -2
- package/lib/jose.js +3 -1
- package/lib/key.js +41 -29
- package/lib/lint.js +236 -152
- package/lib/mime.js +9 -5
- package/lib/ocsp.js +26 -24
- package/lib/path-validate.js +43 -13
- package/lib/pbes2.js +12 -9
- package/lib/pkcs11-uri.js +3 -1
- package/lib/pkcs12-build.js +19 -17
- package/lib/pki-build.js +17 -13
- package/lib/possession.js +3 -1
- package/lib/rc2.js +6 -2
- package/lib/revocation-fetch.js +78 -19
- package/lib/scep.js +21 -14
- package/lib/schema-attrcert.js +4 -2
- package/lib/schema-c509.js +94 -78
- package/lib/schema-cmc.js +5 -2
- package/lib/schema-cmp.js +6 -3
- package/lib/schema-cms.js +7 -4
- package/lib/schema-crl.js +1 -1
- package/lib/schema-crmf.js +1 -1
- package/lib/schema-csr.js +3 -3
- package/lib/schema-engine.js +36 -18
- package/lib/schema-pkcs1.js +7 -3
- package/lib/schema-pkcs12.js +9 -6
- package/lib/schema-pkix.js +19 -3
- package/lib/schema-sec1.js +4 -1
- package/lib/schema-tsp.js +7 -4
- package/lib/shbs.js +10 -9
- package/lib/sign-scheme.js +2 -2
- package/lib/sigstore.js +9 -9
- package/lib/smime.js +19 -16
- package/lib/tlog.js +20 -13
- package/lib/tuf.js +7 -4
- package/lib/validator-cose.js +2 -2
- package/lib/validator-keydesc.js +4 -1
- package/lib/validator-tls.js +7 -2
- package/lib/webauthn-mds.js +3 -7
- package/lib/webauthn.js +4 -11
- package/lib/webcrypto.js +70 -49
- package/lib/x509-sign.js +20 -15
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
package/lib/guard-list.js
CHANGED
|
@@ -8,6 +8,7 @@ var _defineProperty = require("./guard-intrinsic").defineProperty;
|
|
|
8
8
|
var _isArray = require("./guard-intrinsic").isArray;
|
|
9
9
|
var _arrSort = require("./guard-intrinsic").sort;
|
|
10
10
|
var _isSafeInteger = require("./guard-intrinsic").isSafeInteger;
|
|
11
|
+
var _hasOwn = require("./guard-intrinsic").hasOwn;
|
|
11
12
|
|
|
12
13
|
var MAX_ARRAY_LENGTH = 4294967295;
|
|
13
14
|
|
|
@@ -76,6 +77,67 @@ function allMatch(list, predicate) {
|
|
|
76
77
|
return true;
|
|
77
78
|
}
|
|
78
79
|
|
|
80
|
+
/** @internal The first element a predicate selects, or null. Written as `list.filter(p)[0]`, the
|
|
81
|
+
* selection is a fresh array that is empty when nothing matched, and reading index 0 of an empty
|
|
82
|
+
* array answers from the array prototype: an accessor there becomes the selected element in a
|
|
83
|
+
* selection that selected nothing, which reads at every call site as "found one". `filter` also
|
|
84
|
+
* builds its result through the receiver's `Symbol.species`, so the array indexed is not necessarily
|
|
85
|
+
* one this toolkit made. This walks the own indexes and returns null when nothing matched, so a
|
|
86
|
+
* caller's `if (!found)` test answers for the list rather than for the prototype.
|
|
87
|
+
*
|
|
88
|
+
* @enforced-by behavioral -- `filter(...)[0]` has no rename-proof shape of its own beyond the method
|
|
89
|
+
* name, which the captured-operation budget already counts; the RED vectors are the empty-selection
|
|
90
|
+
* ones each consumer carries (a signedAttrs with no message-digest attribute, a certificate with no
|
|
91
|
+
* subject key identifier).
|
|
92
|
+
*/
|
|
93
|
+
function firstMatch(list, predicate) {
|
|
94
|
+
if (!list) return null;
|
|
95
|
+
for (var i = 0, n = _count(list, "firstMatch"); i < n; i++) {
|
|
96
|
+
if (!_hasOwn(list, i)) continue;
|
|
97
|
+
/** @internal One read of the element, tested and returned. Read again after the predicate, an
|
|
98
|
+
* own accessor at the index answers the test with one value and the caller with another, and a
|
|
99
|
+
* getter that deletes its own slot leaves the second read falling through to the prototype. */
|
|
100
|
+
var element = list[i];
|
|
101
|
+
if (predicate(element, i)) return element;
|
|
102
|
+
}
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** @internal Remove the element at `index`, shifting the ones after it down by defining each slot
|
|
107
|
+
* and then truncating through the array's own `length`. `splice` is the ordinary way to write this
|
|
108
|
+
* and it is not usable here: it returns the removed elements, so it builds that result through
|
|
109
|
+
* `ArraySpeciesCreate`, which reads the receiver's `constructor` and then its `Symbol.species`. A
|
|
110
|
+
* getter installed on `Array.prototype.constructor` receives the real array as its `this`, which
|
|
111
|
+
* hands caller code a reference to the list being edited and to every record in it, in the middle of
|
|
112
|
+
* the edit. Nothing is returned here, so nothing is constructed.
|
|
113
|
+
*
|
|
114
|
+
* @enforced-by behavioral -- `splice(i, 1)` has no rename-proof shape beyond the method name, which
|
|
115
|
+
* the captured-operation budget counts; the RED vector is the policy-node removal driven with a
|
|
116
|
+
* `constructor` getter installed.
|
|
117
|
+
*/
|
|
118
|
+
function removeAt(list, index) {
|
|
119
|
+
if (!_isArray(list)) throw new TypeError("guard.list.removeAt: the receiver must be an array");
|
|
120
|
+
var n = _count(list, "removeAt");
|
|
121
|
+
if (!_isSafeInteger(index) || index < 0 || index >= n) {
|
|
122
|
+
throw new RangeError("guard.list.removeAt: the index must be a position the array holds");
|
|
123
|
+
}
|
|
124
|
+
/** @internal A hole stays a hole, and is never read through. `splice` leaves an absent element
|
|
125
|
+
* absent, so a shift that defined every slot would turn one into an own `undefined`; and reading
|
|
126
|
+
* `list[i + 1]` at a hole answers from the prototype, which is the value this family exists to
|
|
127
|
+
* keep out. Each source slot is tested for own-ness once and read once. */
|
|
128
|
+
for (var i = index; i < n - 1; i++) {
|
|
129
|
+
if (_hasOwn(list, i + 1)) {
|
|
130
|
+
_defineProperty(list, i, { value: list[i + 1], writable: true, enumerable: true, configurable: true });
|
|
131
|
+
} else if (_hasOwn(list, i)) {
|
|
132
|
+
delete list[i];
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/** @internal `length` is an array's own writable property, so assigning it consults no prototype
|
|
136
|
+
* and the assignment deletes the tail slot the shift left behind. */
|
|
137
|
+
list.length = n - 1;
|
|
138
|
+
return list;
|
|
139
|
+
}
|
|
140
|
+
|
|
79
141
|
// @enforced-by caller-array-copied-live
|
|
80
142
|
function snapshot(list) {
|
|
81
143
|
if (!_isArray(list)) throw new TypeError("guard.list.snapshot: the receiver must be an array");
|
|
@@ -132,6 +194,8 @@ module.exports = _freeze({
|
|
|
132
194
|
containsAll: containsAll,
|
|
133
195
|
anyMatches: anyMatches,
|
|
134
196
|
allMatch: allMatch,
|
|
197
|
+
firstMatch: firstMatch,
|
|
198
|
+
removeAt: removeAt,
|
|
135
199
|
snapshot: snapshot,
|
|
136
200
|
copyMap: copyMap,
|
|
137
201
|
});
|
package/lib/guard-name.js
CHANGED
|
@@ -177,7 +177,7 @@ function _reduceDpn(d, E, code, label) {
|
|
|
177
177
|
for (var i = 0; i < len; i++) {
|
|
178
178
|
var n = ownValue(names, i);
|
|
179
179
|
if (!_isBuffer(n)) throw refuse("every fullName GeneralName must be its encoded bytes");
|
|
180
|
-
taken
|
|
180
|
+
_append(taken, n);
|
|
181
181
|
}
|
|
182
182
|
return { kind: kind, names: taken };
|
|
183
183
|
}
|
package/lib/guard-secret.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
|
|
6
6
|
var bytes = require("./guard-bytes");
|
|
7
7
|
var intrinsic = require("./guard-intrinsic");
|
|
8
|
+
var cryptoGuard = require("./guard-crypto");
|
|
8
9
|
|
|
9
10
|
var _fill = intrinsic.uncurry(Uint8Array.prototype.fill);
|
|
10
11
|
var _concat = intrinsic.bufferConcat;
|
|
@@ -30,8 +31,8 @@ function zeroizeAll(list, ErrorClass, code, label) {
|
|
|
30
31
|
function cipherFinish(transform, input, ErrorClass, code, label) {
|
|
31
32
|
var head = null, tail = null;
|
|
32
33
|
try {
|
|
33
|
-
head =
|
|
34
|
-
tail =
|
|
34
|
+
head = cryptoGuard.transformUpdate(transform, input);
|
|
35
|
+
tail = cryptoGuard.transformFinal(transform);
|
|
35
36
|
return _concat([head, tail]);
|
|
36
37
|
} finally {
|
|
37
38
|
zeroize(head, ErrorClass, code, label);
|
package/lib/hpke.js
CHANGED
|
@@ -47,7 +47,10 @@ var oid = require("./oid");
|
|
|
47
47
|
var _hasOwn = intrinsic.hasOwn;
|
|
48
48
|
var _isBuffer = intrinsic.isBuffer, _bufferFrom = intrinsic.bufferFrom, _bufferAlloc = intrinsic.bufferAlloc;
|
|
49
49
|
var _bufferConcat = intrinsic.bufferConcat, _bufferEquals = intrinsic.bufferEquals, _compare = intrinsic.compare;
|
|
50
|
-
|
|
50
|
+
/** @internal `append`, not a captured `push`: a store at an index walks the prototype chain for a
|
|
51
|
+
* setter, so an accessor there takes the element being appended. The lists here become the byte
|
|
52
|
+
* strings a KEM's key schedule is computed over. `append` defines the index. */
|
|
53
|
+
var _push = intrinsic.append;
|
|
51
54
|
var _subarray = intrinsic.subarray;
|
|
52
55
|
|
|
53
56
|
var HpkeError = frameworkError.HpkeError;
|
|
@@ -76,7 +79,10 @@ function _pushPrefixed(parts, b, what) {
|
|
|
76
79
|
throw _err("hpke/input-length", what + " is " + b.length + " bytes; a single-stage KDF accepts at " +
|
|
77
80
|
"most " + MAX_PREFIXED + " (draft-ietf-hpke-hpke-05 sec. 7.2.1)");
|
|
78
81
|
}
|
|
79
|
-
|
|
82
|
+
/** @internal Two appends, because `append` takes one value where `push` took many: the length
|
|
83
|
+
* prefix and the value it measures are both part of the byte string a KDF reads. */
|
|
84
|
+
_push(parts, i2osp(b.length, 2));
|
|
85
|
+
_push(parts, b);
|
|
80
86
|
return parts;
|
|
81
87
|
}
|
|
82
88
|
/** @internal Through the capture, which is the whole point of this helper existing: every
|
|
@@ -244,10 +250,10 @@ function _importPublic(kem, raw) {
|
|
|
244
250
|
if (raw[0] !== 0x04) throw _err("hpke/bad-key", "EC public key must be an uncompressed 0x04 point (RFC 9180 sec. 7.1.4)");
|
|
245
251
|
var half = (raw.length - 1) / 2;
|
|
246
252
|
var jwk = { kty: "EC", crv: kem.curve, x: raw.subarray(1, 1 + half).toString("base64url"), y: raw.subarray(1 + half).toString("base64url") };
|
|
247
|
-
return
|
|
253
|
+
return guard.crypto.publicKey({ key: jwk, format: "jwk" });
|
|
248
254
|
}
|
|
249
255
|
var prefix = kem.kind === "mlkem" ? ML_KEM_SPKI[kem.name] : OKP_SPKI[kem.curve];
|
|
250
|
-
return
|
|
256
|
+
return guard.crypto.publicKey({ key: _bufferConcat([_hex(prefix), raw]), format: "der", type: "spki" });
|
|
251
257
|
} catch (e) {
|
|
252
258
|
if (e instanceof HpkeError) throw e;
|
|
253
259
|
throw _err("hpke/bad-key", "invalid " + kem.name + " public key" +
|
|
@@ -255,15 +261,15 @@ function _importPublic(kem, raw) {
|
|
|
255
261
|
}
|
|
256
262
|
}
|
|
257
263
|
function _exportPublic(kem, keyObject) {
|
|
258
|
-
var pub = keyObject.type === "public" ? keyObject :
|
|
264
|
+
var pub = keyObject.type === "public" ? keyObject : guard.crypto.publicKey(keyObject);
|
|
259
265
|
if (kem.kind === "mlkem") {
|
|
260
|
-
var der =
|
|
266
|
+
var der = guard.crypto.exportKey(pub, { format: "der", type: "spki" }), prefix = _hex(ML_KEM_SPKI[kem.name]);
|
|
261
267
|
if (der.length !== prefix.length + kem.Npub || !_bufferEquals(_subarray(der, 0, prefix.length), prefix)) {
|
|
262
268
|
throw _err("hpke/bad-key", "the KeyObject is not an " + kem.name + " key");
|
|
263
269
|
}
|
|
264
270
|
return _subarray(der, prefix.length);
|
|
265
271
|
}
|
|
266
|
-
var jwk =
|
|
272
|
+
var jwk = guard.crypto.exportKey(pub, { format: "jwk" });
|
|
267
273
|
if (jwk.crv !== kem.curve) throw _err("hpke/bad-key", "the KeyObject is not a " + kem.name + " key");
|
|
268
274
|
if (kem.kind === "ec") return concat([Buffer.from([0x04]), _b64u(jwk.x), _b64u(jwk.y)]);
|
|
269
275
|
return _b64u(jwk.x);
|
|
@@ -287,7 +293,7 @@ function _importPrivate(kem, rawSk) {
|
|
|
287
293
|
der = _bufferConcat([_hex(kem.kind === "mlkem" ? ML_KEM_PKCS8[kem.name] : OKP_PKCS8[kem.curve]), rawSk]);
|
|
288
294
|
}
|
|
289
295
|
try {
|
|
290
|
-
return
|
|
296
|
+
return guard.crypto.privateKey({ key: der, format: "der", type: kem.kind === "ec" ? "sec1" : "pkcs8" });
|
|
291
297
|
} catch (e) {
|
|
292
298
|
throw _err("hpke/bad-key", "invalid " + kem.name + " private key", e);
|
|
293
299
|
} finally {
|
|
@@ -295,7 +301,7 @@ function _importPrivate(kem, rawSk) {
|
|
|
295
301
|
}
|
|
296
302
|
}
|
|
297
303
|
function _boundPublic(kem, privateKey, pkm) {
|
|
298
|
-
var derived = _exportPublic(kem,
|
|
304
|
+
var derived = _exportPublic(kem, guard.crypto.publicKey(privateKey));
|
|
299
305
|
if (pkm === undefined) return derived;
|
|
300
306
|
if (!_isBuffer(pkm) || !_bufferEquals(derived, pkm)) {
|
|
301
307
|
throw _err("hpke/bad-key", "pkm is not the " + kem.name + " public key derived from skm");
|
|
@@ -304,7 +310,7 @@ function _boundPublic(kem, privateKey, pkm) {
|
|
|
304
310
|
}
|
|
305
311
|
function _dh(privateKey, publicKey) {
|
|
306
312
|
try {
|
|
307
|
-
return
|
|
313
|
+
return guard.crypto.diffieHellman({ privateKey: privateKey, publicKey: publicKey });
|
|
308
314
|
} catch (e) {
|
|
309
315
|
throw _err("hpke/bad-key", "KEM Diffie-Hellman failed: invalid or low-order public key", e);
|
|
310
316
|
}
|
|
@@ -313,8 +319,8 @@ function _dh(privateKey, publicKey) {
|
|
|
313
319
|
* drawn and expanded by generateKeyPair, and an ML-KEM encapsulation takes its randomness from the
|
|
314
320
|
* runtime rather than from an ephemeral key pair. */
|
|
315
321
|
function _generate(kem) {
|
|
316
|
-
if (kem.kind === "ec") return
|
|
317
|
-
return
|
|
322
|
+
if (kem.kind === "ec") return guard.crypto.generateKeyPair("ec", { namedCurve: kem.nodeCurve });
|
|
323
|
+
return guard.crypto.generateKeyPair(intrinsic.toLowerCase(kem.curve));
|
|
318
324
|
}
|
|
319
325
|
|
|
320
326
|
|
|
@@ -346,7 +352,8 @@ function _derive(xof, input, outLen) {
|
|
|
346
352
|
function _labeledDerive(xof, suiteId, ikm, label, context, outLen) {
|
|
347
353
|
var lab = _bufferFrom(label, "latin1");
|
|
348
354
|
var parts = _pushPrefixed([ikm, HPKE_V1, suiteId], lab, "a derive label");
|
|
349
|
-
_push(parts, i2osp(outLen, 2)
|
|
355
|
+
_push(parts, i2osp(outLen, 2));
|
|
356
|
+
_push(parts, context);
|
|
350
357
|
var labeledIkm = concat(parts);
|
|
351
358
|
try { return _derive(xof, labeledIkm, outLen); }
|
|
352
359
|
finally { guard.secret.zeroize(labeledIkm, HpkeError, "hpke/bad-input", "the labeled derive input"); }
|
|
@@ -378,8 +385,8 @@ function _hybridExpand(kem, seed) {
|
|
|
378
385
|
var skT = _importPrivate(_groupRow(kem), _randomScalar(kem, _subarray(full, kem.pq.Nsk)));
|
|
379
386
|
return {
|
|
380
387
|
skPQ: skPQ, skT: skT,
|
|
381
|
-
ekPQ: _exportPublic(kem.pq,
|
|
382
|
-
ekT: _exportPublic(_groupRow(kem),
|
|
388
|
+
ekPQ: _exportPublic(kem.pq, guard.crypto.publicKey(skPQ)),
|
|
389
|
+
ekT: _exportPublic(_groupRow(kem), guard.crypto.publicKey(skT)),
|
|
383
390
|
};
|
|
384
391
|
} finally {
|
|
385
392
|
guard.secret.zeroize(full, HpkeError, "hpke/bad-input", "the hybrid seed expansion");
|
|
@@ -484,7 +491,7 @@ function _refuseEph(kem, eph) {
|
|
|
484
491
|
function _mlKemEncap(kem, pkR, eph) {
|
|
485
492
|
_refuseEph(kem, eph);
|
|
486
493
|
var r;
|
|
487
|
-
try { r =
|
|
494
|
+
try { r = guard.crypto.encapsulate(pkR); }
|
|
488
495
|
catch (e) { throw _err("hpke/bad-key", kem.name + " encapsulation failed", e); }
|
|
489
496
|
return { sharedSecret: r.sharedKey, enc: r.ciphertext };
|
|
490
497
|
}
|
|
@@ -492,7 +499,7 @@ function _mlKemDecap(kem, enc, skR) {
|
|
|
492
499
|
if (enc.length !== kem.Nenc) {
|
|
493
500
|
throw _err("hpke/bad-key", kem.name + " encapsulated key must be " + kem.Nenc + " bytes (FIPS 203 sec. 7.3 ciphertext check)");
|
|
494
501
|
}
|
|
495
|
-
try { return
|
|
502
|
+
try { return guard.crypto.decapsulate(skR, enc); }
|
|
496
503
|
catch (e) { throw _err("hpke/bad-key", kem.name + " decapsulation failed", e); }
|
|
497
504
|
}
|
|
498
505
|
function _encap(kem, pkR, pkRm, eph) {
|
|
@@ -641,10 +648,10 @@ Context.prototype.seal = function (aad, pt) {
|
|
|
641
648
|
* which is what RFC 9180 sec. 5.2 uses. */
|
|
642
649
|
var aadBytes = _buf(aad);
|
|
643
650
|
var nonce = this._nonce();
|
|
644
|
-
var c =
|
|
645
|
-
if (aadBytes.length)
|
|
651
|
+
var c = guard.crypto.cipher(aead.cipher, this._key, nonce, { authTagLength: aead.Nt });
|
|
652
|
+
if (aadBytes.length) guard.crypto.transformSetAAD(c, aadBytes);
|
|
646
653
|
var body = guard.secret.cipherFinish(c, _buf(pt), HpkeError, "hpke/bad-input", "a seal intermediate");
|
|
647
|
-
var ct = concat([body,
|
|
654
|
+
var ct = concat([body, guard.crypto.cipherAuthTag(c)]);
|
|
648
655
|
this._inc();
|
|
649
656
|
return ct;
|
|
650
657
|
};
|
|
@@ -658,9 +665,9 @@ Context.prototype.open = function (aad, ct) {
|
|
|
658
665
|
* so the AAD was dropped on this side too and the pair round-tripped with nothing bound. */
|
|
659
666
|
var aadBytes = _buf(aad);
|
|
660
667
|
var nonce = this._nonce();
|
|
661
|
-
var d =
|
|
662
|
-
if (aadBytes.length)
|
|
663
|
-
|
|
668
|
+
var d = guard.crypto.decipher(aead.cipher, this._key, nonce, { authTagLength: aead.Nt });
|
|
669
|
+
if (aadBytes.length) guard.crypto.transformSetAAD(d, aadBytes);
|
|
670
|
+
guard.crypto.decipherSetAuthTag(d, ct.subarray(ct.length - aead.Nt));
|
|
664
671
|
var pt;
|
|
665
672
|
try { pt = guard.secret.cipherFinish(d, ct.subarray(0, ct.length - aead.Nt), HpkeError, "hpke/bad-input", "the recovered plaintext"); }
|
|
666
673
|
catch (e) { throw _err("hpke/open-failed", "AEAD authentication failed (RFC 9180 sec. 5.2)", e); }
|
|
@@ -807,7 +814,7 @@ function _recipPrivate(suite, sk) {
|
|
|
807
814
|
}
|
|
808
815
|
try {
|
|
809
816
|
if (sk.type !== "private") throw _err("hpke/bad-key", "the private key must be a private KeyObject or { skm, pkm }, got a " + guard.text.showValue(sk.type) + " KeyObject");
|
|
810
|
-
var pkm = _exportPublic(kem,
|
|
817
|
+
var pkm = _exportPublic(kem, guard.crypto.publicKey(sk));
|
|
811
818
|
return { key: sk, pkm: pkm };
|
|
812
819
|
} catch (e) {
|
|
813
820
|
if (e instanceof HpkeError) throw e;
|
|
@@ -1111,11 +1118,11 @@ function deriveKeyPair(kemId, ikm) {
|
|
|
1111
1118
|
* and the decapsulation key returned is that 64-byte value. */
|
|
1112
1119
|
var dk = _labeledDerive("shake256", _kemSuiteId(_kemId(kem)), input, "DeriveKeyPair", _EMPTY, kem.Nsk);
|
|
1113
1120
|
var mlSk = _importPrivate(kem, dk);
|
|
1114
|
-
return { publicKey: _exportPublic(kem,
|
|
1121
|
+
return { publicKey: _exportPublic(kem, guard.crypto.publicKey(mlSk)), privateKey: dk };
|
|
1115
1122
|
}
|
|
1116
1123
|
var raw = _deriveKeyPairDhkem(kem, input);
|
|
1117
1124
|
var sk = _importPrivate(kem, raw);
|
|
1118
|
-
return { publicKey: _exportPublic(kem,
|
|
1125
|
+
return { publicKey: _exportPublic(kem, guard.crypto.publicKey(sk)), privateKey: raw };
|
|
1119
1126
|
}
|
|
1120
1127
|
|
|
1121
1128
|
/** @internal DeriveKeyPair for a DHKEM (RFC 9180 sec. 7.1.3). X25519 and X448 expand the extract output
|
|
@@ -1251,7 +1258,7 @@ function decap(kemId, enc, recipientPrivateKey) {
|
|
|
1251
1258
|
* Nsk rather than trusted. An ML-KEM or hybrid key never reaches here, its private half being a seed
|
|
1252
1259
|
* that generateKeyPair draws. */
|
|
1253
1260
|
function _exportPrivateRaw(kem, privateKey) {
|
|
1254
|
-
var raw = _b64u(
|
|
1261
|
+
var raw = _b64u(guard.crypto.exportKey(privateKey, { format: "jwk" }).d);
|
|
1255
1262
|
if (!_isBuffer(raw) || raw.length !== kem.Nsk) {
|
|
1256
1263
|
throw _err("hpke/bad-key", "the generated " + kem.name + " private key is not the " +
|
|
1257
1264
|
kem.Nsk + "-byte scalar this verb returns");
|
package/lib/http-digest.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
var crypto = require("crypto");
|
|
7
7
|
var constants = require("./constants");
|
|
8
8
|
var intrinsic = require("./guard-intrinsic");
|
|
9
|
+
var guard = require("./guard-all");
|
|
9
10
|
var guardIdentifier = require("./guard-identifier");
|
|
10
11
|
var _hasOwn = intrinsic.hasOwn;
|
|
11
12
|
/** @internal The URL parser, taken at load: the origin it reports is what a challenge is bound to.
|
|
@@ -46,14 +47,11 @@ var DEFAULT_CODES = intrinsic.assign(intrinsic.create(null), {
|
|
|
46
47
|
noQop: "digest/no-qop", badChallenge: "digest/bad-challenge",
|
|
47
48
|
});
|
|
48
49
|
|
|
49
|
-
/** @internal
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
var _createHash = crypto.createHash;
|
|
50
|
+
/** @internal Every Digest response value is this function's output, so whatever computes it chooses
|
|
51
|
+
* what is sent in place of the password-derived proof. RFC 7616 sec. 3 computes over the octets of
|
|
52
|
+
* the latin1 encoding, which is why the input encoding is named rather than defaulted. */
|
|
53
53
|
var _randomBytes = crypto.randomBytes;
|
|
54
|
-
|
|
55
|
-
var _hashDigest = intrinsic.uncurry(crypto.createHash("sha256").digest);
|
|
56
|
-
function H(hash, s) { return _hashDigest(_hashUpdate(_createHash(hash), s, "latin1"), "hex"); }
|
|
54
|
+
function H(hash, s) { return guard.crypto.digest(hash, s, { input: "latin1", output: "hex" }); }
|
|
57
55
|
function KD(hash, secret, data) { return H(hash, secret + ":" + data); }
|
|
58
56
|
function _qstr(v) {
|
|
59
57
|
var s = intrinsic.String(v), out = "";
|
package/lib/http-transport.js
CHANGED
|
@@ -128,7 +128,10 @@ var _toLowerCase = intrinsic.toLowerCase;
|
|
|
128
128
|
var _fromCharCode = intrinsic.fromCharCode;
|
|
129
129
|
var _isArray = intrinsic.isArray;
|
|
130
130
|
var _arrIndexOf = intrinsic.indexOf;
|
|
131
|
-
|
|
131
|
+
/** @internal `append`, not a captured `push`: a store at an index walks the prototype chain for a
|
|
132
|
+
* setter, so an accessor there takes the element being appended, and this list is the peer chain a
|
|
133
|
+
* caller reads. `append` defines the index. */
|
|
134
|
+
var _arrPush = intrinsic.append;
|
|
132
135
|
var _arrForEach = intrinsic.forEach;
|
|
133
136
|
var _isBuffer = intrinsic.isBuffer;
|
|
134
137
|
var _bufferFrom = intrinsic.bufferFrom;
|
|
@@ -348,7 +351,10 @@ function _makeGuardedLookup(lookupFn) {
|
|
|
348
351
|
var entry = address[i];
|
|
349
352
|
var one = { address: entry && entry.address, family: entry && entry.family };
|
|
350
353
|
if (_isBlockedIp(one.address)) return callback(_blockedAddrErr(hostname, one.address));
|
|
351
|
-
|
|
354
|
+
/** @internal Appended by defining the index. Stored at, the store walks the prototype chain
|
|
355
|
+
* for a setter, so an accessor there took the checked entry and node read the address it
|
|
356
|
+
* connects to back from the getter instead: an address this check never saw. */
|
|
357
|
+
_arrPush(checked, one);
|
|
352
358
|
}
|
|
353
359
|
return callback(null, checked);
|
|
354
360
|
}
|
|
@@ -448,7 +454,10 @@ function snapshotProxy(p) {
|
|
|
448
454
|
var a = p.tls.anchors;
|
|
449
455
|
if (_copyableArray(a)) {
|
|
450
456
|
var copied = [];
|
|
451
|
-
|
|
457
|
+
/** @internal Appended by defining the index, for the reason the address list above is: these
|
|
458
|
+
* are the trust anchors the handshake runs under, and a store consults a setter inherited at
|
|
459
|
+
* the index. */
|
|
460
|
+
for (var i = 0; i < a.length; i++) _arrPush(copied, _copyAnchor(a[i]));
|
|
452
461
|
out.tls.anchors = copied;
|
|
453
462
|
} else if (typeof a === "string") out.tls.anchors = a;
|
|
454
463
|
else if (a !== null && typeof a === "object" && !nodeUtil.types.isProxy(a) && _isBuffer(a)) out.tls.anchors = _bufferFrom(a);
|
package/lib/inspect.js
CHANGED
|
@@ -1158,7 +1158,11 @@ function _joinAnd(list) {
|
|
|
1158
1158
|
* door can validate to arbitrary depth, so a report must not fault on any shape it is handed. */
|
|
1159
1159
|
function _list(v) { return Array.isArray(v) ? v : []; }
|
|
1160
1160
|
/** @internal The same for a member a loop body dereferences. */
|
|
1161
|
-
|
|
1161
|
+
/** @internal The stand-in for a value that is not a record has NO PROTOTYPE. Written as `{}`, it
|
|
1162
|
+
* inherits `Object.prototype`, so a field read off it answers with whatever a name planted there
|
|
1163
|
+
* holds and a report prints a value its subject does not carry. */
|
|
1164
|
+
var _EMPTY_RECORD = Object.create(null);
|
|
1165
|
+
function _obj(v) { return (v !== null && typeof v === "object") ? v : _EMPTY_RECORD; }
|
|
1162
1166
|
|
|
1163
1167
|
/** @internal A serial reads the same wherever a report carries one, through the certificate report's own
|
|
1164
1168
|
* presentation: small values as decimal with the hex beside them, long ones as wrapped colon-hex. Printed
|
|
@@ -1327,7 +1331,11 @@ function _someSignerUnmatched(signed) {
|
|
|
1327
1331
|
}
|
|
1328
1332
|
function _certMatchesSid(cert, sid) {
|
|
1329
1333
|
if (Buffer.isBuffer(sid.subjectKeyIdentifier)) {
|
|
1330
|
-
|
|
1334
|
+
/** @internal The selection returns the first matching row or null. `filter(...)[0]` indexes a
|
|
1335
|
+
* result that is EMPTY when the certificate carries no key identifier, and index 0 of an empty
|
|
1336
|
+
* array answers from the array prototype, which would report a signer match for a certificate
|
|
1337
|
+
* that carries nothing to match on. */
|
|
1338
|
+
var ski = guard.list.firstMatch(_list(cert.extensions), function (e) { return _obj(e).oid === OID_SUBJECT_KEY_ID; });
|
|
1331
1339
|
if (!ski) return false;
|
|
1332
1340
|
// allow:swallow-unverified drop-silent display fallback: an unreadable key id matches nothing
|
|
1333
1341
|
try { return asn1.read.octetString(asn1.decode(_obj(ski).value)).equals(sid.subjectKeyIdentifier); }
|
package/lib/jose.js
CHANGED
|
@@ -54,7 +54,9 @@ var _isBuffer = intrinsic.isBuffer;
|
|
|
54
54
|
var _bufferFrom = intrinsic.bufferFrom;
|
|
55
55
|
var _stringify = intrinsic.stringify;
|
|
56
56
|
var _ObjectProto = intrinsic.ObjectProto;
|
|
57
|
-
|
|
57
|
+
/** @internal `append`, not a captured `push`: a store at an index walks the prototype chain for a
|
|
58
|
+
* setter, so an accessor there takes the element being appended. `append` defines it. */
|
|
59
|
+
var _push = intrinsic.append;
|
|
58
60
|
var _join = intrinsic.join;
|
|
59
61
|
var _map = intrinsic.map;
|
|
60
62
|
var _bufToString = intrinsic.uncurry(Buffer.prototype.toString);
|
package/lib/key.js
CHANGED
|
@@ -183,11 +183,11 @@ async function encrypt(privateKey, password, opts) {
|
|
|
183
183
|
var prf = opts.prf || "hmacWithSHA256";
|
|
184
184
|
var prfNode = pbes2.prfNodeByName(prf, _err, "key");
|
|
185
185
|
var iterations = pbes2.assertIterations(opts.iterations == null ? 600000 : opts.iterations, _err, "key");
|
|
186
|
-
var salt = opts.salt != null ? pbes2.assertSalt(guard.bytes.view(opts.salt, KeyError, "key/bad-input", "salt"), _err, "key") :
|
|
187
|
-
var iv =
|
|
186
|
+
var salt = opts.salt != null ? pbes2.assertSalt(guard.bytes.view(opts.salt, KeyError, "key/bad-input", "salt"), _err, "key") : guard.crypto.randomBytes(16);
|
|
187
|
+
var iv = guard.crypto.randomBytes(16);
|
|
188
188
|
var pwK = pbes2.passwordBytesOwned(password, _err, "key");
|
|
189
189
|
var dk;
|
|
190
|
-
try { dk =
|
|
190
|
+
try { dk = guard.crypto.pbkdf2(pwK.bytes, salt, iterations, keyBits / 8, prfNode); }
|
|
191
191
|
finally { if (pwK.owned) guard.secret.zeroize(pwK.bytes, KeyError, "key/bad-input", "the password encoding"); }
|
|
192
192
|
try {
|
|
193
193
|
var ciphertext = pbes2.cbcEncrypt(dk, iv, der, keyBits, KeyError, "key/bad-input");
|
|
@@ -290,6 +290,10 @@ function _decryptPbes2(encAlg, ciphertext, password, opts) {
|
|
|
290
290
|
* var spkiPem = await pki.key.export(pair.publicKey, { format: "pem" });
|
|
291
291
|
*/
|
|
292
292
|
var _EXPORT_OPTS = _assign(_create(null), { format: 1, label: 1 });
|
|
293
|
+
/** @internal The WebCrypto export format each key type calls for, named here so the ONE read of the
|
|
294
|
+
* key's type below settles the encoding as well as the PEM label. Passing the format explicitly is
|
|
295
|
+
* what keeps the engine from reading the type a second time. */
|
|
296
|
+
var _EXPORT_WANT_BY_TYPE = _assign(_create(null), { "private": "pkcs8", "public": "spki", "secret": "raw" });
|
|
293
297
|
|
|
294
298
|
async function export_(key, opts) {
|
|
295
299
|
opts = guard.identifier.optionsObject(opts, _err, "key/bad-input", "pki.key.export options");
|
|
@@ -297,9 +301,14 @@ async function export_(key, opts) {
|
|
|
297
301
|
"pki.key.export has an unknown option. It serializes only. To protect a private key, call " +
|
|
298
302
|
"pki.key.encrypt(key, password) first and export its result. The unknown option was: ");
|
|
299
303
|
if (!_isCryptoKey(key)) throw _err("key/bad-input", "export expects a WebCrypto CryptoKey");
|
|
304
|
+
/** @internal ONE read of the key's type, which both the PEM label and every encoding decision
|
|
305
|
+
* below come from. On node's own CryptoKey it is a getter, so reading it per question let a
|
|
306
|
+
* replacement answer "private" where the label was chosen and "public" where the bytes were, and
|
|
307
|
+
* a public key came back inside a `PRIVATE KEY` block. */
|
|
308
|
+
var keyType = key.type;
|
|
300
309
|
var defaultLabel;
|
|
301
|
-
if (
|
|
302
|
-
else if (
|
|
310
|
+
if (keyType === "private") defaultLabel = "PRIVATE KEY";
|
|
311
|
+
else if (keyType === "public") defaultLabel = "PUBLIC KEY";
|
|
303
312
|
else throw _err("key/bad-input", "export supports asymmetric (private / public) CryptoKeys only");
|
|
304
313
|
var fmt = opts.format || "der";
|
|
305
314
|
if (fmt === "jwk") {
|
|
@@ -310,11 +319,11 @@ async function export_(key, opts) {
|
|
|
310
319
|
throw _err("key/bad-input", "exporting the key as a JWK failed", e);
|
|
311
320
|
}
|
|
312
321
|
}
|
|
313
|
-
var der = await _exportAnyKey(key, _err, "key/bad-input");
|
|
322
|
+
var der = await _exportAnyKey(key, _err, "key/bad-input", _EXPORT_WANT_BY_TYPE[keyType]);
|
|
314
323
|
if (fmt === "der") return der;
|
|
315
324
|
if (fmt === "pem") return pkix.pemEncode(der, opts.label || defaultLabel, PemError);
|
|
316
|
-
if (fmt === "pkcs1") return _toPkcs1(der, key);
|
|
317
|
-
if (fmt === "sec1") return _toSec1(der, key);
|
|
325
|
+
if (fmt === "pkcs1") return _toPkcs1(der, key, keyType);
|
|
326
|
+
if (fmt === "sec1") return _toSec1(der, key, keyType);
|
|
318
327
|
throw _err("key/bad-input", "unsupported format " + guard.text.showValue(opts.format) + " (der / pem / pkcs1 / sec1 / jwk)");
|
|
319
328
|
}
|
|
320
329
|
|
|
@@ -923,18 +932,19 @@ var _PAIR_RSA = _assign(_create(null), { rsa: 1, "rsa-pss": 1 });
|
|
|
923
932
|
var _PAIR_PROBE = _bufferFrom("pki.js key pair correspondence", "utf8");
|
|
924
933
|
|
|
925
934
|
function _sameKeyFamily(priv, pub) {
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
935
|
+
var privType = guard.crypto.keyType(priv), pubType = guard.crypto.keyType(pub);
|
|
936
|
+
if (privType === pubType) return true;
|
|
937
|
+
return !!(_PAIR_RSA[guard.text.keyOf(privType)] && _PAIR_RSA[guard.text.keyOf(pubType)]);
|
|
929
938
|
}
|
|
930
939
|
|
|
931
940
|
/** @internal How to exercise a signing pair: the digest, and any padding the encoding requires. An
|
|
932
941
|
* `id-RSASSA-PSS` key may pin the hash and salt length it is usable with, and the engine refuses any
|
|
933
942
|
* other, so a pinned value from either half is what proves the pair. */
|
|
934
943
|
function _pairSignOptions(priv, pub) {
|
|
935
|
-
var
|
|
944
|
+
var privType = guard.crypto.keyType(priv);
|
|
945
|
+
var privPss = privType === "rsa-pss", pubPss = guard.crypto.keyType(pub) === "rsa-pss";
|
|
936
946
|
if (!privPss && !pubPss) {
|
|
937
|
-
return { digest: _PAIR_DIGEST[guard.text.keyOf(
|
|
947
|
+
return { digest: _PAIR_DIGEST[guard.text.keyOf(privType)] || null, options: null };
|
|
938
948
|
}
|
|
939
949
|
var privDetails = _pssRestrictionOf(priv, privPss);
|
|
940
950
|
var pubDetails = _pssRestrictionOf(pub, pubPss);
|
|
@@ -969,7 +979,7 @@ var _PSS_PINS = ["hashAlgorithm", "mgf1HashAlgorithm", "saltLength"];
|
|
|
969
979
|
* carried, and refuse a genuine pair. */
|
|
970
980
|
function _pssRestrictionOf(key, isPss) {
|
|
971
981
|
var out = _create(null);
|
|
972
|
-
var details = isPss ? key
|
|
982
|
+
var details = isPss ? guard.crypto.keyDetails(key) : null;
|
|
973
983
|
if (details == null) return out;
|
|
974
984
|
for (var i = 0; i < _PSS_PINS.length; i++) {
|
|
975
985
|
var name = _PSS_PINS[i];
|
|
@@ -1026,7 +1036,7 @@ async function correspondsTo(privateKey, spkiDer) {
|
|
|
1026
1036
|
try { pub = guard.crypto.publicKey({ key: pubAsPkcs3, format: "der", type: "spki" }); }
|
|
1027
1037
|
catch (e) { throw _err("key/bad-input", "the public key could not be read", e); }
|
|
1028
1038
|
if (!_sameKeyFamily(priv, pub)) return false;
|
|
1029
|
-
var kind = guard.text.keyOf(priv
|
|
1039
|
+
var kind = guard.text.keyOf(guard.crypto.keyType(priv));
|
|
1030
1040
|
/** @internal Every secret a probe makes, wiped once the verdict is decided, on every way out. */
|
|
1031
1041
|
var secrets = [];
|
|
1032
1042
|
try {
|
|
@@ -1041,17 +1051,17 @@ async function correspondsTo(privateKey, spkiDer) {
|
|
|
1041
1051
|
return _keyEquals(guard.crypto.publicKey(priv), pub) === true;
|
|
1042
1052
|
}
|
|
1043
1053
|
if (_PAIR_KEM[kind]) {
|
|
1044
|
-
var sealed =
|
|
1054
|
+
var sealed = guard.crypto.encapsulate(pub);
|
|
1045
1055
|
guard.list.append(secrets, sealed.sharedKey);
|
|
1046
|
-
var opened =
|
|
1056
|
+
var opened = guard.crypto.decapsulate(priv, sealed.ciphertext);
|
|
1047
1057
|
guard.list.append(secrets, opened);
|
|
1048
1058
|
return guard.crypto.constantTimeEqual(opened, sealed.sharedKey);
|
|
1049
1059
|
}
|
|
1050
1060
|
if (_PAIR_AGREE[kind]) {
|
|
1051
|
-
var ephemeral =
|
|
1052
|
-
var ours =
|
|
1061
|
+
var ephemeral = guard.crypto.generateKeyPair(guard.crypto.keyType(priv));
|
|
1062
|
+
var ours = guard.crypto.diffieHellman({ privateKey: priv, publicKey: ephemeral.publicKey });
|
|
1053
1063
|
guard.list.append(secrets, ours);
|
|
1054
|
-
var theirs =
|
|
1064
|
+
var theirs = guard.crypto.diffieHellman({ privateKey: ephemeral.privateKey, publicKey: pub });
|
|
1055
1065
|
guard.list.append(secrets, theirs);
|
|
1056
1066
|
if (!guard.crypto.constantTimeEqual(ours, theirs)) return false;
|
|
1057
1067
|
/** @internal The agreement proves the SCALAR, not the encoding it was handed. RFC 7748 masks the
|
|
@@ -1194,13 +1204,13 @@ async function _importNamedFormat(input, opts) {
|
|
|
1194
1204
|
/** @internal The inverse of the wrap: pull the inner key out of the PKCS#8 or SPKI the engine
|
|
1195
1205
|
* wrote. The bytes come back as they went in, since the engine carries the inner structure
|
|
1196
1206
|
* unchanged and this reads it rather than re-encoding it. */
|
|
1197
|
-
function _toPkcs1(der, key) {
|
|
1198
|
-
var algOid = _wrappedAlgorithmOid(der,
|
|
1207
|
+
function _toPkcs1(der, key, keyType) {
|
|
1208
|
+
var algOid = _wrappedAlgorithmOid(der, keyType);
|
|
1199
1209
|
if (algOid !== O("rsaEncryption")) {
|
|
1200
1210
|
throw _err("key/bad-input", "PKCS#1 is an RSA encoding (RFC 8017 App. A.1) and this key is " + _algName(key.algorithm));
|
|
1201
1211
|
}
|
|
1202
1212
|
var node = asn1.decode(der);
|
|
1203
|
-
if (
|
|
1213
|
+
if (keyType === "public") {
|
|
1204
1214
|
var bits = asn1.read.bitString(node.children[1]);
|
|
1205
1215
|
if (bits.unusedBits !== 0) throw _err("key/bad-input", "the exported public key does not hold whole octets");
|
|
1206
1216
|
schemaPkcs1.parsePublic(bits.bytes);
|
|
@@ -1210,12 +1220,12 @@ function _toPkcs1(der, key) {
|
|
|
1210
1220
|
schemaPkcs1.parse(inner);
|
|
1211
1221
|
return inner;
|
|
1212
1222
|
}
|
|
1213
|
-
function _toSec1(der, key) {
|
|
1214
|
-
var algOid = _wrappedAlgorithmOid(der,
|
|
1223
|
+
function _toSec1(der, key, keyType) {
|
|
1224
|
+
var algOid = _wrappedAlgorithmOid(der, keyType);
|
|
1215
1225
|
if (algOid !== O("ecPublicKey")) {
|
|
1216
1226
|
throw _err("key/bad-input", "SEC1 is an elliptic-curve private-key encoding (RFC 5915 sec. 3) and this key is " + _algName(key.algorithm));
|
|
1217
1227
|
}
|
|
1218
|
-
if (
|
|
1228
|
+
if (keyType !== "private") {
|
|
1219
1229
|
throw _err("key/bad-input", "SEC1 encodes a private key; export the public half as SubjectPublicKeyInfo");
|
|
1220
1230
|
}
|
|
1221
1231
|
var node = asn1.decode(der);
|
|
@@ -1248,11 +1258,13 @@ function _toSec1(der, key) {
|
|
|
1248
1258
|
}
|
|
1249
1259
|
|
|
1250
1260
|
/** @internal The algorithm the wrapper names, read from whichever wrapper the key type produced:
|
|
1251
|
-
* a PrivateKeyInfo names it second, a SubjectPublicKeyInfo first.
|
|
1252
|
-
|
|
1261
|
+
* a PrivateKeyInfo names it second, a SubjectPublicKeyInfo first. `keyType` is the one read the
|
|
1262
|
+
* caller took, rather than a fresh one off the key, so every decision in an export comes from the
|
|
1263
|
+
* same answer. */
|
|
1264
|
+
function _wrappedAlgorithmOid(der, keyType) {
|
|
1253
1265
|
var node;
|
|
1254
1266
|
try { node = asn1.decode(der); } catch (e) { throw _err("key/bad-input", "the exported key is not DER", e); }
|
|
1255
|
-
var algSeq =
|
|
1267
|
+
var algSeq = keyType === "public" ? node.children[0] : node.children[1];
|
|
1256
1268
|
if (!algSeq || !algSeq.children || algSeq.children.length === 0) {
|
|
1257
1269
|
throw _err("key/bad-input", "the exported key names no algorithm");
|
|
1258
1270
|
}
|