@blamejs/pki 0.8.60 → 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 +24 -0
- package/lib/cmc-build.js +14 -9
- package/lib/cms-decrypt.js +15 -15
- package/lib/cms-digest.js +2 -3
- package/lib/cms-encrypt.js +15 -16
- package/lib/composite-kem.js +28 -29
- package/lib/crmf-sign.js +11 -17
- package/lib/ct.js +11 -9
- package/lib/guard-crypto.js +506 -14
- package/lib/guard-secret.js +3 -2
- package/lib/hpke.js +24 -24
- package/lib/http-digest.js +5 -7
- package/lib/key.js +41 -29
- package/lib/ocsp.js +1 -2
- package/lib/pbes2.js +6 -7
- package/lib/pkcs12-build.js +5 -6
- package/lib/pki-build.js +3 -3
- package/lib/scep.js +7 -8
- package/lib/schema-tsp.js +3 -3
- package/lib/shbs.js +3 -6
- package/lib/sign-scheme.js +2 -2
- package/lib/sigstore.js +9 -9
- package/lib/smime.js +1 -2
- package/lib/tlog.js +3 -2
- package/lib/tuf.js +4 -3
- package/lib/validator-cose.js +2 -2
- package/lib/webauthn-mds.js +3 -7
- package/lib/webauthn.js +4 -11
- package/lib/webcrypto.js +61 -46
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
package/lib/sigstore.js
CHANGED
|
@@ -28,7 +28,6 @@
|
|
|
28
28
|
* @card Verify an npm --provenance Sigstore bundle offline (DSSE + Fulcio + Rekor + SLSA).
|
|
29
29
|
*/
|
|
30
30
|
|
|
31
|
-
var nodeCrypto = require("crypto");
|
|
32
31
|
var frameworkError = require("./framework-error");
|
|
33
32
|
var constants = require("./constants");
|
|
34
33
|
var asn1 = require("./asn1-der");
|
|
@@ -227,8 +226,8 @@ function _assertKeyDetailsParameters(want, leafSpki, declared) {
|
|
|
227
226
|
if (want.bits !== undefined) {
|
|
228
227
|
var bits;
|
|
229
228
|
try {
|
|
230
|
-
bits = guard.crypto.
|
|
231
|
-
.
|
|
229
|
+
bits = guard.crypto.keyDetails(
|
|
230
|
+
guard.crypto.publicKey({ key: leafSpki.bytes, format: "der", type: "spki" })).modulusLength;
|
|
232
231
|
} catch (_e) { bits = null; } // allow:swallow-unverified -- a key that will not import has no modulus size to match, and the mismatch below is the verdict
|
|
233
232
|
if (bits !== want.bits) {
|
|
234
233
|
throw _err("sigstore/entry-mismatch", "the Rekor entry states the signing key is " +
|
|
@@ -709,13 +708,14 @@ function _chainDers(vm) {
|
|
|
709
708
|
}
|
|
710
709
|
|
|
711
710
|
function _rawVerify(keyObj, data, derSig) {
|
|
712
|
-
var t = keyObj
|
|
711
|
+
var t = guard.crypto.keyType(keyObj);
|
|
713
712
|
if (t === "ed25519" || t === "ed448") {
|
|
714
713
|
var edSpki = guard.crypto.exportKey(keyObj, { type: "spki", format: "der" });
|
|
715
714
|
edwardsPoint.validateSpki(edSpki, t === "ed25519" ? 6 : 7, SigstoreError, "sigstore/bad-key");
|
|
716
715
|
return guard.crypto.verify(null, data, keyObj, derSig);
|
|
717
716
|
}
|
|
718
|
-
var
|
|
717
|
+
var keyObjDetails = guard.crypto.keyDetails(keyObj);
|
|
718
|
+
var crv = keyObjDetails && keyObjDetails.namedCurve;
|
|
719
719
|
var hash = crv === "secp384r1" ? "sha384" : (crv === "secp521r1" ? "sha512" : "sha256");
|
|
720
720
|
return guard.crypto.verify(hash, data, { key: keyObj, dsaEncoding: "der" }, derSig);
|
|
721
721
|
}
|
|
@@ -723,7 +723,7 @@ function _pubFromSpki(spkiDer, label) {
|
|
|
723
723
|
var key;
|
|
724
724
|
try { key = guard.crypto.publicKey({ key: spkiDer, format: "der", type: "spki" }); }
|
|
725
725
|
catch (e) { throw _err("sigstore/bad-key", "invalid " + label + " public key", e); }
|
|
726
|
-
var t = key
|
|
726
|
+
var t = guard.crypto.keyType(key);
|
|
727
727
|
if (t === "ed25519" || t === "ed448") {
|
|
728
728
|
edwardsPoint.validateSpki(spkiDer, t === "ed25519" ? 6 : 7, SigstoreError, "sigstore/bad-key");
|
|
729
729
|
}
|
|
@@ -735,7 +735,7 @@ function _parseCert(der, label) {
|
|
|
735
735
|
}
|
|
736
736
|
|
|
737
737
|
|
|
738
|
-
function _sha256(buf) { return
|
|
738
|
+
function _sha256(buf) { return guard.crypto.digest("sha256", buf); }
|
|
739
739
|
|
|
740
740
|
function _toMs(x) {
|
|
741
741
|
if (x == null) return null;
|
|
@@ -1109,7 +1109,7 @@ function _bindHashedRekordV002Entry(body, arm, leafDer, contentType, payloadType
|
|
|
1109
1109
|
}
|
|
1110
1110
|
var digest = _b64(data.digest, "hashedRekordV002.data.digest");
|
|
1111
1111
|
if (contentType === "dsseEnvelope") {
|
|
1112
|
-
var computed =
|
|
1112
|
+
var computed = guard.crypto.digest(alg.node, pae(payloadType, payload));
|
|
1113
1113
|
if (!guard.crypto.constantTimeEqual(computed, digest)) {
|
|
1114
1114
|
throw _err("sigstore/entry-mismatch", "the Rekor entry digest is not the hash of this envelope's " +
|
|
1115
1115
|
"signing preimage, so the entry records a different signature than the bundle carries");
|
|
@@ -1831,7 +1831,7 @@ async function verifyBundle(bundle, opts) {
|
|
|
1831
1831
|
var artifactDigests = intrinsic.create(null);
|
|
1832
1832
|
function _artifactDigest(nodeName) {
|
|
1833
1833
|
if (!intrinsic.hasOwn(artifactDigests, nodeName)) {
|
|
1834
|
-
artifactDigests[nodeName] =
|
|
1834
|
+
artifactDigests[nodeName] = guard.crypto.digest(nodeName, artifact);
|
|
1835
1835
|
}
|
|
1836
1836
|
return artifactDigests[nodeName];
|
|
1837
1837
|
}
|
package/lib/smime.js
CHANGED
|
@@ -48,7 +48,6 @@ var _push = guard.list.append;
|
|
|
48
48
|
var pkiBuild = require("./pki-build.js");
|
|
49
49
|
var C = require("./constants.js");
|
|
50
50
|
var nodeUtil = require("util");
|
|
51
|
-
var nodeCrypto = require("crypto");
|
|
52
51
|
|
|
53
52
|
var SmimeError = frameworkError.SmimeError;
|
|
54
53
|
|
|
@@ -591,7 +590,7 @@ function _micalgOf(p7Der) {
|
|
|
591
590
|
return out.length ? out.sort().join(",") : null;
|
|
592
591
|
}
|
|
593
592
|
|
|
594
|
-
function _boundary() { return "----=_pki_smime_" +
|
|
593
|
+
function _boundary() { return "----=_pki_smime_" + guard.crypto.randomBytes(18).toString("hex"); }
|
|
595
594
|
|
|
596
595
|
function _wrap64Crlf(s) {
|
|
597
596
|
var out = "";
|
package/lib/tlog.js
CHANGED
|
@@ -299,12 +299,13 @@ function _resolveKey(keyName, publicKey) {
|
|
|
299
299
|
throw _err("tlog/bad-input", "publicKey must be the raw " + ED25519_RAW_BYTES +
|
|
300
300
|
" Ed25519 bytes or a SubjectPublicKeyInfo, got " + bytes.length + " bytes", e);
|
|
301
301
|
}
|
|
302
|
-
var type = key
|
|
302
|
+
var type = guard.crypto.keyType(key);
|
|
303
303
|
if (type === "ed25519") {
|
|
304
304
|
return _edKey(name, bytes, _subarray(bytes, bytes.length - ED25519_RAW_BYTES));
|
|
305
305
|
}
|
|
306
306
|
if (type === "ec") {
|
|
307
|
-
var
|
|
307
|
+
var keyDetails = guard.crypto.keyDetails(key);
|
|
308
|
+
var curve = keyDetails && keyDetails.namedCurve;
|
|
308
309
|
if (EC_CURVES[curve] !== 1) {
|
|
309
310
|
throw _err("tlog/bad-input", "a signed note names no key-ID derivation for the elliptic curve " +
|
|
310
311
|
guard.text.showValue(_stringOf(curve)));
|
package/lib/tuf.js
CHANGED
|
@@ -798,12 +798,13 @@ function _declarationOf(key) {
|
|
|
798
798
|
function _checkedPublicKey(key, d) {
|
|
799
799
|
if (d.nodeType === "ed25519") return null;
|
|
800
800
|
var imported = _publicFromPem(key.keyval.public, "a " + key.keytype + " public key");
|
|
801
|
-
|
|
801
|
+
var importedType = guard.crypto.keyType(imported);
|
|
802
|
+
if (importedType !== d.nodeType) {
|
|
802
803
|
throw _err("tuf/bad-key", "the key declared as " + key.keytype + " holds a " +
|
|
803
|
-
guard.text.showValue(
|
|
804
|
+
guard.text.showValue(importedType) + " public key, so the signature would be checked " +
|
|
804
805
|
"under an algorithm the metadata does not name");
|
|
805
806
|
}
|
|
806
|
-
var details = imported
|
|
807
|
+
var details = guard.crypto.keyDetails(imported) || {};
|
|
807
808
|
if (d.curve !== null && details.namedCurve !== d.curve) {
|
|
808
809
|
throw _err("tuf/bad-key", "the scheme " + key.scheme + " names the " + d.curve +
|
|
809
810
|
" curve; the key is on " + guard.text.showValue(details.namedCurve));
|
package/lib/validator-cose.js
CHANGED
|
@@ -7,7 +7,7 @@ var cbor = require("./cbor-det");
|
|
|
7
7
|
var asn1 = require("./asn1-der");
|
|
8
8
|
var oid = require("./oid");
|
|
9
9
|
var edwardsPoint = require("./edwards-point");
|
|
10
|
-
var
|
|
10
|
+
var guard = require("./guard-all.js");
|
|
11
11
|
|
|
12
12
|
var EC2_CRV_LEN = Object.assign(Object.create(null), { 1: 32, 2: 48, 3: 66 });
|
|
13
13
|
var EC2_CRV_OID = Object.assign(Object.create(null), { 1: "prime256v1", 2: "secp384r1", 3: "secp521r1" });
|
|
@@ -114,7 +114,7 @@ function assertKeyMaterial(key, E, code, unsupportedCode) {
|
|
|
114
114
|
if (!prof) throw new E(unsupportedCode || code, "unsupported credential key algorithm " + key.alg);
|
|
115
115
|
if (prof.kty !== key.kty) throw bad("credential key algorithm " + key.alg + " is inconsistent with key type " + key.kty);
|
|
116
116
|
if (prof.crv != null && prof.crv !== key.crv) throw bad("credential key algorithm " + key.alg + " requires a different curve");
|
|
117
|
-
try {
|
|
117
|
+
try { guard.crypto.publicKey({ key: toSpki(key, E, code), format: "der", type: "spki" }); }
|
|
118
118
|
catch (e) { throw bad("the credential public key point is not valid for its curve", e); }
|
|
119
119
|
if (Number(key.kty) === 1 && !edwardsPoint.validate(key.x, key.crv)) throw bad("the OKP credential public key is not a valid, full-order Edwards point");
|
|
120
120
|
return key;
|
package/lib/webauthn-mds.js
CHANGED
|
@@ -26,12 +26,6 @@ var _charAt = intrinsic.uncurry(String.prototype.charAt);
|
|
|
26
26
|
var _strToLowerCase = intrinsic.toLowerCase;
|
|
27
27
|
var _strSlice = intrinsic.uncurry(String.prototype.slice);
|
|
28
28
|
var _strSplit = intrinsic.uncurry(String.prototype.split);
|
|
29
|
-
/** @internal The hash constructor and the methods of the object it returns. What a digest here
|
|
30
|
-
* produces is a metadata lookup key and the identity two certificates are told apart by, so a
|
|
31
|
-
* replaced constructor, update or digest decides which entry governs an attestation. */
|
|
32
|
-
var _createHash = _nodeCrypto.createHash;
|
|
33
|
-
var _hashUpdate = intrinsic.uncurry(_nodeCrypto.createHash("sha256").update);
|
|
34
|
-
var _hashDigest = intrinsic.uncurry(_nodeCrypto.createHash("sha256").digest);
|
|
35
29
|
var jose = require("./jose");
|
|
36
30
|
var rfc3339 = require("./rfc3339");
|
|
37
31
|
var constants = require("./constants");
|
|
@@ -702,7 +696,9 @@ function certKeyIdentifier(cert) {
|
|
|
702
696
|
if (!pk || !intrinsic.isBuffer(pk.bytes)) {
|
|
703
697
|
throw _err("webauthn/bad-input", "certKeyIdentifier expects a parsed certificate carrying a subject public key");
|
|
704
698
|
}
|
|
705
|
-
|
|
699
|
+
/** @internal A metadata lookup key, and the identity two certificates are told apart by, so
|
|
700
|
+
* whatever computes it decides which entry governs an attestation. */
|
|
701
|
+
return guard.crypto.digest("sha1", pk.bytes, { output: "hex" });
|
|
706
702
|
}
|
|
707
703
|
|
|
708
704
|
function metadataForKeyIdentifier(metadata, keyId) {
|
package/lib/webauthn.js
CHANGED
|
@@ -54,7 +54,6 @@ var _promiseResolve = intrinsic.uncurry(intrinsic.promiseResolve);
|
|
|
54
54
|
var _promiseReject = intrinsic.uncurry(intrinsic.promiseReject);
|
|
55
55
|
var jose = require("./jose");
|
|
56
56
|
var mds = require("./webauthn-mds");
|
|
57
|
-
var nodeCrypto = require("crypto");
|
|
58
57
|
|
|
59
58
|
var WebauthnError = frameworkError.WebauthnError;
|
|
60
59
|
function _err(code, message, cause) { return new WebauthnError(code, message, cause); }
|
|
@@ -76,16 +75,10 @@ var _subtleVerify = intrinsic.uncurry(subtle.verify);
|
|
|
76
75
|
* while the bytes handed in were never the credential's. */
|
|
77
76
|
var _subtleImportKey = intrinsic.uncurry(subtle.importKey);
|
|
78
77
|
|
|
79
|
-
/** @internal
|
|
80
|
-
*
|
|
81
|
-
*
|
|
82
|
-
|
|
83
|
-
function _sha(name, buf) {
|
|
84
|
-
var h = _createHash(name);
|
|
85
|
-
return _hashDigest(_hashUpdate(h, buf));
|
|
86
|
-
}
|
|
87
|
-
var _hashUpdate = intrinsic.uncurry(nodeCrypto.createHash("sha256").update);
|
|
88
|
-
var _hashDigest = intrinsic.uncurry(nodeCrypto.createHash("sha256").digest);
|
|
78
|
+
/** @internal Every attestation comparison in this module rests on a digest, so whatever computes one
|
|
79
|
+
* chooses what the comparison sees. The guard owns the hash construction and the methods of the
|
|
80
|
+
* object it returns. */
|
|
81
|
+
function _sha(name, buf) { return guard.crypto.digest(name, buf); }
|
|
89
82
|
/** @internal The comparison goes through the captured operation. This is what decides that an
|
|
90
83
|
* attestation statement's key is the credential's key, so a replacement answering zero makes a
|
|
91
84
|
* different key match. */
|
package/lib/webcrypto.js
CHANGED
|
@@ -261,10 +261,10 @@ SubtleCrypto.prototype.digest = async function digest(algorithm, data) {
|
|
|
261
261
|
var name = _normalizeAlg(algorithm, "digest").name;
|
|
262
262
|
var xof = XOF_NODE[_toUpperCase(_String(name))];
|
|
263
263
|
var h = xof
|
|
264
|
-
?
|
|
265
|
-
:
|
|
266
|
-
h
|
|
267
|
-
return _toArrayBuffer(h
|
|
264
|
+
? guard.crypto.hash(xof.node, xof.length)
|
|
265
|
+
: guard.crypto.hash(_hashNode(name, "digest"));
|
|
266
|
+
_hashUpdate(h, _toBuf(data, "digest"));
|
|
267
|
+
return _toArrayBuffer(_hashDigest(h));
|
|
268
268
|
};
|
|
269
269
|
|
|
270
270
|
SubtleCrypto.prototype.digestStream = async function digestStream(algorithms, source) {
|
|
@@ -276,8 +276,8 @@ SubtleCrypto.prototype.digestStream = async function digestStream(algorithms, so
|
|
|
276
276
|
var name = _normalizeAlg(algorithms[_h], "digestStream").name;
|
|
277
277
|
var xof = XOF_NODE[_toUpperCase(_String(name))];
|
|
278
278
|
hashes[_h] = xof
|
|
279
|
-
?
|
|
280
|
-
:
|
|
279
|
+
? guard.crypto.hash(xof.node, xof.length)
|
|
280
|
+
: guard.crypto.hash(_hashNode(name, "digestStream"));
|
|
281
281
|
}
|
|
282
282
|
var acquire = source == null ? undefined : source[_asyncIterator];
|
|
283
283
|
if (typeof acquire !== "function") {
|
|
@@ -307,8 +307,8 @@ SubtleCrypto.prototype.digestStream = async function digestStream(algorithms, so
|
|
|
307
307
|
|
|
308
308
|
SubtleCrypto.prototype.encryptStream = async function encryptStream(spec, source) {
|
|
309
309
|
var cipher = spec.authTagLength
|
|
310
|
-
?
|
|
311
|
-
:
|
|
310
|
+
? guard.crypto.cipher(spec.algNode, spec.key, spec.iv, { authTagLength: spec.authTagLength })
|
|
311
|
+
: guard.crypto.cipher(spec.algNode, spec.key, spec.iv);
|
|
312
312
|
if (spec.aad && spec.aad.length) _cipherSetAAD(cipher, spec.aad);
|
|
313
313
|
var acquire = source == null ? undefined : source[_asyncIterator];
|
|
314
314
|
if (typeof acquire !== "function") {
|
|
@@ -344,7 +344,7 @@ SubtleCrypto.prototype.encryptStream = async function encryptStream(spec, source
|
|
|
344
344
|
};
|
|
345
345
|
|
|
346
346
|
SubtleCrypto.prototype.decryptStream = function decryptStream(spec, ct) {
|
|
347
|
-
var decipher =
|
|
347
|
+
var decipher = guard.crypto.decipher(spec.algNode, spec.key, spec.iv);
|
|
348
348
|
return _decipherDrive(decipher, _bufferFrom(_toBuf(ct, "decryptStream ciphertext")), _STREAM_CHUNK);
|
|
349
349
|
};
|
|
350
350
|
async function* _decipherDrive(decipher, ct, chunkSize) {
|
|
@@ -368,12 +368,12 @@ SubtleCrypto.prototype.generateKey = async function generateKey(algorithm, extra
|
|
|
368
368
|
if (name === "AES-GCM" || name === "AES-CBC" || name === "AES-CTR" || name === "AES-KW") {
|
|
369
369
|
var bits = alg.length;
|
|
370
370
|
if (bits !== 128 && bits !== 192 && bits !== 256) throw new WebCryptoError("webcrypto/syntax", name + ": length must be 128/192/256");
|
|
371
|
-
var secret = guard.crypto.secretKey(
|
|
371
|
+
var secret = guard.crypto.secretKey(guard.crypto.randomBytes(bits / 8));
|
|
372
372
|
return new CryptoKey("secret", extractable, { name: name, length: bits }, usages, secret);
|
|
373
373
|
}
|
|
374
374
|
if (name === "HMAC") {
|
|
375
375
|
var lenBits = _hmacLengthBits(alg, "generateKey HMAC");
|
|
376
|
-
var hkey = guard.crypto.secretKey(
|
|
376
|
+
var hkey = guard.crypto.secretKey(guard.crypto.randomBytes(lenBits / 8));
|
|
377
377
|
return new CryptoKey("secret", extractable, { name: name, hash: { name: (typeof alg.hash === "string" ? alg.hash : alg.hash.name) }, length: lenBits }, usages, hkey);
|
|
378
378
|
}
|
|
379
379
|
|
|
@@ -391,7 +391,7 @@ function _generateKeyPair(alg) {
|
|
|
391
391
|
var name = alg.name, kp, algorithm;
|
|
392
392
|
if (name === "RSASSA-PKCS1-V1_5" || name === "RSA-PSS" || name === "RSA-OAEP") {
|
|
393
393
|
var rsaHash = _hashObj(alg.hash, "generateKey " + name);
|
|
394
|
-
kp =
|
|
394
|
+
kp = guard.crypto.generateKeyPair("rsa", {
|
|
395
395
|
modulusLength: alg.modulusLength || 2048,
|
|
396
396
|
publicExponent: alg.publicExponent ? _bufToBigIntNum(alg.publicExponent) : 65537,
|
|
397
397
|
});
|
|
@@ -399,19 +399,19 @@ function _generateKeyPair(alg) {
|
|
|
399
399
|
} else if (name === "ECDSA" || name === "ECDH") {
|
|
400
400
|
var curve = alg.namedCurve;
|
|
401
401
|
if (!CURVE_NODE[curve]) throw new WebCryptoError("webcrypto/not-supported", name + ": unsupported curve " + _stringify(curve));
|
|
402
|
-
kp =
|
|
402
|
+
kp = guard.crypto.generateKeyPair("ec", { namedCurve: CURVE_NODE[curve] });
|
|
403
403
|
algorithm = { name: name, namedCurve: curve };
|
|
404
404
|
} else if (name === "ED25519" || name === "ED448" || name === "X25519" || name === "X448") {
|
|
405
|
-
kp =
|
|
405
|
+
kp = guard.crypto.generateKeyPair(_toLowerCase(name));
|
|
406
406
|
algorithm = { name: _stdName(name) };
|
|
407
407
|
} else if (ML_DSA_NODE[name]) {
|
|
408
|
-
kp =
|
|
408
|
+
kp = guard.crypto.generateKeyPair(ML_DSA_NODE[name]);
|
|
409
409
|
algorithm = { name: name };
|
|
410
410
|
} else if (ML_KEM_NODE[name]) {
|
|
411
|
-
kp =
|
|
411
|
+
kp = guard.crypto.generateKeyPair(ML_KEM_NODE[name]);
|
|
412
412
|
algorithm = { name: name };
|
|
413
413
|
} else if (SLH_DSA_NODE[name]) {
|
|
414
|
-
kp =
|
|
414
|
+
kp = guard.crypto.generateKeyPair(SLH_DSA_NODE[name]);
|
|
415
415
|
algorithm = { name: name };
|
|
416
416
|
} else {
|
|
417
417
|
throw new WebCryptoError("webcrypto/not-supported", "generateKey: unsupported algorithm " + _stringify(name));
|
|
@@ -515,7 +515,7 @@ SubtleCrypto.prototype.encrypt = async function encrypt(algorithm, key, data) {
|
|
|
515
515
|
if (!ENCRYPT_DECRYPT_NAMES[name]) throw new WebCryptoError("webcrypto/not-supported", "encrypt: unsupported algorithm " + _stringify(name));
|
|
516
516
|
_requireAlgMatch(alg, key, "encrypt");
|
|
517
517
|
if (name === "RSA-OAEP") {
|
|
518
|
-
return _toArrayBuffer(
|
|
518
|
+
return _toArrayBuffer(guard.crypto.publicEncrypt({
|
|
519
519
|
key: key._handle, padding: guard.crypto.padding.RSA_PKCS1_OAEP,
|
|
520
520
|
oaepHash: _hashNode(key.algorithm.hash, "encrypt"),
|
|
521
521
|
oaepLabel: alg.label ? _toBuf(alg.label, "encrypt label") : undefined,
|
|
@@ -526,10 +526,10 @@ SubtleCrypto.prototype.encrypt = async function encrypt(algorithm, key, data) {
|
|
|
526
526
|
var aad = alg.additionalData ? _toBuf(alg.additionalData, "AES-GCM aad") : null;
|
|
527
527
|
return _toArrayBuffer(_runCipher(function () {
|
|
528
528
|
return _withSecretBytes(key, function (kb) {
|
|
529
|
-
var cipher =
|
|
530
|
-
if (aad)
|
|
529
|
+
var cipher = guard.crypto.cipher("aes-" + key.algorithm.length + "-gcm", kb, iv, { authTagLength: (alg.tagLength || 128) / 8 });
|
|
530
|
+
if (aad) guard.crypto.transformSetAAD(cipher, aad);
|
|
531
531
|
var ct = guard.secret.cipherFinish(cipher, buf, WebCryptoError, "webcrypto/operation", "an AES-GCM encrypt intermediate");
|
|
532
|
-
return _bufferConcat([ct,
|
|
532
|
+
return _bufferConcat([ct, guard.crypto.cipherAuthTag(cipher)]);
|
|
533
533
|
});
|
|
534
534
|
}, "encrypt"));
|
|
535
535
|
}
|
|
@@ -537,7 +537,7 @@ SubtleCrypto.prototype.encrypt = async function encrypt(algorithm, key, data) {
|
|
|
537
537
|
var cbcIv = _toBuf(alg.iv, "AES-CBC iv");
|
|
538
538
|
return _toArrayBuffer(_runCipher(function () {
|
|
539
539
|
return _withSecretBytes(key, function (kb) {
|
|
540
|
-
var c2 =
|
|
540
|
+
var c2 = guard.crypto.cipher("aes-" + key.algorithm.length + "-cbc", kb, cbcIv);
|
|
541
541
|
return guard.secret.cipherFinish(c2, buf, WebCryptoError, "webcrypto/operation", "an AES-CBC encrypt intermediate");
|
|
542
542
|
});
|
|
543
543
|
}, "encrypt"));
|
|
@@ -547,7 +547,7 @@ SubtleCrypto.prototype.encrypt = async function encrypt(algorithm, key, data) {
|
|
|
547
547
|
var ctrCounter = _toBuf(alg.counter, "AES-CTR counter");
|
|
548
548
|
return _toArrayBuffer(_runCipher(function () {
|
|
549
549
|
return _withSecretBytes(key, function (kb) {
|
|
550
|
-
var c3 =
|
|
550
|
+
var c3 = guard.crypto.cipher("aes-" + key.algorithm.length + "-ctr", kb, ctrCounter);
|
|
551
551
|
return guard.secret.cipherFinish(c3, buf, WebCryptoError, "webcrypto/operation", "an AES-CTR encrypt intermediate");
|
|
552
552
|
});
|
|
553
553
|
}, "encrypt"));
|
|
@@ -563,7 +563,7 @@ SubtleCrypto.prototype.decrypt = async function decrypt(algorithm, key, data) {
|
|
|
563
563
|
if (!ENCRYPT_DECRYPT_NAMES[name]) throw new WebCryptoError("webcrypto/not-supported", "decrypt: unsupported algorithm " + _stringify(name));
|
|
564
564
|
_requireAlgMatch(alg, key, "decrypt");
|
|
565
565
|
if (name === "RSA-OAEP") {
|
|
566
|
-
var oaepOut =
|
|
566
|
+
var oaepOut = guard.crypto.privateDecrypt({
|
|
567
567
|
key: key._handle, padding: guard.crypto.padding.RSA_PKCS1_OAEP,
|
|
568
568
|
oaepHash: _hashNode(key.algorithm.hash, "decrypt"),
|
|
569
569
|
oaepLabel: alg.label ? _toBuf(alg.label, "decrypt label") : undefined,
|
|
@@ -580,9 +580,9 @@ SubtleCrypto.prototype.decrypt = async function decrypt(algorithm, key, data) {
|
|
|
580
580
|
var gcmAad = alg.additionalData ? _toBuf(alg.additionalData, "AES-GCM aad") : null;
|
|
581
581
|
return _toArrayBuffer(_runCipher(function () {
|
|
582
582
|
return _withSecretBytes(key, function (kb) {
|
|
583
|
-
var d =
|
|
584
|
-
if (gcmAad)
|
|
585
|
-
|
|
583
|
+
var d = guard.crypto.decipher("aes-" + key.algorithm.length + "-gcm", kb, iv, { authTagLength: tagLen });
|
|
584
|
+
if (gcmAad) guard.crypto.transformSetAAD(d, gcmAad);
|
|
585
|
+
guard.crypto.decipherSetAuthTag(d, tag);
|
|
586
586
|
return guard.secret.cipherFinish(d, ct, WebCryptoError, "webcrypto/operation", "the recovered AES-GCM plaintext");
|
|
587
587
|
});
|
|
588
588
|
}, "decrypt"));
|
|
@@ -591,7 +591,7 @@ SubtleCrypto.prototype.decrypt = async function decrypt(algorithm, key, data) {
|
|
|
591
591
|
var cbcIv2 = _toBuf(alg.iv, "AES-CBC iv");
|
|
592
592
|
return _toArrayBuffer(_runCipher(function () {
|
|
593
593
|
return _withSecretBytes(key, function (kb) {
|
|
594
|
-
var d2 =
|
|
594
|
+
var d2 = guard.crypto.decipher("aes-" + key.algorithm.length + "-cbc", kb, cbcIv2);
|
|
595
595
|
return guard.secret.cipherFinish(d2, buf, WebCryptoError, "webcrypto/operation", "the recovered AES-CBC plaintext");
|
|
596
596
|
});
|
|
597
597
|
}, "decrypt"));
|
|
@@ -601,7 +601,7 @@ SubtleCrypto.prototype.decrypt = async function decrypt(algorithm, key, data) {
|
|
|
601
601
|
var ctrCounter2 = _toBuf(alg.counter, "AES-CTR counter");
|
|
602
602
|
return _toArrayBuffer(_runCipher(function () {
|
|
603
603
|
return _withSecretBytes(key, function (kb) {
|
|
604
|
-
var d3 =
|
|
604
|
+
var d3 = guard.crypto.decipher("aes-" + key.algorithm.length + "-ctr", kb, ctrCounter2);
|
|
605
605
|
return guard.secret.cipherFinish(d3, buf, WebCryptoError, "webcrypto/operation", "the recovered AES-CTR plaintext");
|
|
606
606
|
});
|
|
607
607
|
}, "decrypt"));
|
|
@@ -650,7 +650,7 @@ function _pbkdf2Async(pw, salt, iterations, keylen, digest) {
|
|
|
650
650
|
if (next) next();
|
|
651
651
|
if (err) reject(err); else resolve(derived);
|
|
652
652
|
}
|
|
653
|
-
try {
|
|
653
|
+
try { guard.crypto.pbkdf2Async(pw, salt, iterations, keylen, digest, done); }
|
|
654
654
|
catch (e) { done(e); }
|
|
655
655
|
}
|
|
656
656
|
if (_pbkdf2InFlight < _PBKDF2_MAX_CONCURRENT) start(); else _push(_pbkdf2Waiters,start);
|
|
@@ -662,7 +662,7 @@ async function _deriveBitsRaw(alg, key, length) {
|
|
|
662
662
|
if (name === "ECDH" || name === "X25519" || name === "X448") {
|
|
663
663
|
_requireAlgMatch(alg, alg.public, name + " public key");
|
|
664
664
|
_requireOwnKey(alg.public, "deriveBits public key");
|
|
665
|
-
var secret =
|
|
665
|
+
var secret = guard.crypto.diffieHellman({ privateKey: key._handle, publicKey: alg.public._handle });
|
|
666
666
|
try {
|
|
667
667
|
if (length == null) return _toArrayBuffer(secret);
|
|
668
668
|
_requireDeriveLength(length, name);
|
|
@@ -677,7 +677,7 @@ async function _deriveBitsRaw(alg, key, length) {
|
|
|
677
677
|
if (name === "HKDF") {
|
|
678
678
|
_requireDeriveLength(length, "HKDF");
|
|
679
679
|
return _withSecretBytes(key, function (ikm) {
|
|
680
|
-
var derived =
|
|
680
|
+
var derived = guard.crypto.hkdf(_hashNode(alg.hash, "HKDF"), ikm, _toBuf(alg.salt, "HKDF salt"), _toBuf(alg.info || _bufferAlloc(0), "HKDF info"), length / 8);
|
|
681
681
|
return _types.isArrayBuffer(derived) ? derived : _toArrayBuffer(_bufferFrom(derived));
|
|
682
682
|
});
|
|
683
683
|
}
|
|
@@ -710,7 +710,7 @@ function _x963Kdf(hashNode, z, sharedInfo, lenBytes) {
|
|
|
710
710
|
* hash of the shared secret with this counter in it, so a replaced write makes two blocks derive
|
|
711
711
|
* from the same input and the key material repeats. */
|
|
712
712
|
var ctr = _bufferAlloc(4); intrinsic.writeUInt32BE(ctr, counter, 0);
|
|
713
|
-
var h =
|
|
713
|
+
var h = guard.crypto.digestParts(hashNode, [z, ctr, sharedInfo]);
|
|
714
714
|
_push(blocks, h); got += h.length; counter += 1;
|
|
715
715
|
}
|
|
716
716
|
var joined = _bufferConcat(blocks);
|
|
@@ -758,7 +758,7 @@ SubtleCrypto.prototype.encapsulateBits = async function encapsulateBits(algorith
|
|
|
758
758
|
_requireAlgMatch(alg, encapsulationKey, "encapsulateBits");
|
|
759
759
|
if (encapsulationKey.type !== "public") throw new WebCryptoError("webcrypto/invalid-access", "encapsulateBits requires a public (encapsulation) key, got " + _stringify(encapsulationKey.type));
|
|
760
760
|
var r;
|
|
761
|
-
try { r =
|
|
761
|
+
try { r = guard.crypto.encapsulate(encapsulationKey._handle); }
|
|
762
762
|
catch (e) { throw new WebCryptoError("webcrypto/operation", "encapsulateBits: ML-KEM encapsulation failed", e); }
|
|
763
763
|
try {
|
|
764
764
|
return { sharedKey: _toArrayBuffer(r.sharedKey), ciphertext: _toArrayBuffer(r.ciphertext) };
|
|
@@ -780,7 +780,7 @@ SubtleCrypto.prototype.decapsulateBits = async function decapsulateBits(algorith
|
|
|
780
780
|
"decapsulateBits: " + alg.name + " expects a " + kemRow.ct + "-octet ciphertext, got " + ct.length + " (FIPS 203 sec. 7.3)");
|
|
781
781
|
}
|
|
782
782
|
var ss;
|
|
783
|
-
try { ss =
|
|
783
|
+
try { ss = guard.crypto.decapsulate(decapsulationKey._handle, ct); }
|
|
784
784
|
catch (e) { throw new WebCryptoError("webcrypto/operation", "decapsulateBits: ML-KEM decapsulation failed (malformed or wrong-length ciphertext)", e); }
|
|
785
785
|
try {
|
|
786
786
|
return _toArrayBuffer(ss);
|
|
@@ -803,7 +803,7 @@ SubtleCrypto.prototype.wrapKey = async function wrapKey(format, key, wrappingKey
|
|
|
803
803
|
}
|
|
804
804
|
try {
|
|
805
805
|
return _withSecretBytes(wrappingKey, function (wkBytes) {
|
|
806
|
-
var c =
|
|
806
|
+
var c = guard.crypto.cipher("aes" + wrappingKey.algorithm.length + "-wrap", wkBytes, _bufferFrom("A6A6A6A6A6A6A6A6", "hex"));
|
|
807
807
|
return _toArrayBuffer(guard.secret.cipherFinish(c, bytes, WebCryptoError, "webcrypto/operation", "an AES-KW wrap intermediate"));
|
|
808
808
|
});
|
|
809
809
|
} catch (e) { throw new WebCryptoError("webcrypto/operation", "wrapKey: AES-KW key wrap failed", e); }
|
|
@@ -828,7 +828,7 @@ SubtleCrypto.prototype.unwrapKey = async function unwrapKey(format, wrappedKey,
|
|
|
828
828
|
}
|
|
829
829
|
try {
|
|
830
830
|
bytes = _withSecretBytes(unwrappingKey, function (kwBytes) {
|
|
831
|
-
var d =
|
|
831
|
+
var d = guard.crypto.decipher("aes" + unwrappingKey.algorithm.length + "-wrap", kwBytes, _bufferFrom("A6A6A6A6A6A6A6A6", "hex"));
|
|
832
832
|
return guard.secret.cipherFinish(d, wrapped, WebCryptoError, "webcrypto/operation", "the unwrapped key material");
|
|
833
833
|
});
|
|
834
834
|
} catch (e) { throw new WebCryptoError("webcrypto/operation", "unwrapKey: AES-KW key unwrap failed (integrity or length)", e); }
|
|
@@ -1021,8 +1021,13 @@ _forEach([ML_DSA_NODE, ML_KEM_NODE, SLH_DSA_NODE], function (m) {
|
|
|
1021
1021
|
});
|
|
1022
1022
|
function _algFromImport(name, alg, keyObject) {
|
|
1023
1023
|
var wantType = IMPORT_KEY_TYPE[name];
|
|
1024
|
-
|
|
1025
|
-
|
|
1024
|
+
/** @internal The key's own family, read through the accessor captured at load. This is the check
|
|
1025
|
+
* that binds the algorithm a caller named to the key they supplied, so reading it off the live
|
|
1026
|
+
* prototype let a replaced accessor answer `"rsa"` for an Ed25519 key and the import accepted it
|
|
1027
|
+
* as RSA-PSS. */
|
|
1028
|
+
var actualType = guard.crypto.keyTypeOf(keyObject);
|
|
1029
|
+
if (wantType && actualType && !wantType[actualType]) {
|
|
1030
|
+
throw new WebCryptoError("webcrypto/data", name + ": the imported key is a " + actualType +
|
|
1026
1031
|
" key, which is not compatible with algorithm " + name);
|
|
1027
1032
|
}
|
|
1028
1033
|
if (name === "ECDSA" || name === "ECDH") {
|
|
@@ -1136,17 +1141,17 @@ Crypto.prototype.getRandomValues = function getRandomValues(typedArray) {
|
|
|
1136
1141
|
if (out.length > MAX_RANDOM_BYTES) {
|
|
1137
1142
|
throw new WebCryptoError("webcrypto/data", "getRandomValues: byteLength exceeds " + MAX_RANDOM_BYTES);
|
|
1138
1143
|
}
|
|
1139
|
-
|
|
1144
|
+
guard.crypto.randomFill(out);
|
|
1140
1145
|
return typedArray;
|
|
1141
1146
|
};
|
|
1142
1147
|
|
|
1143
|
-
Crypto.prototype.randomUUID = function randomUUID() { return
|
|
1148
|
+
Crypto.prototype.randomUUID = function randomUUID() { return guard.crypto.randomUUID(); };
|
|
1144
1149
|
|
|
1145
1150
|
function decompressEcPoint(sec1Compressed, nodeCurve, E, code) {
|
|
1146
1151
|
var head = sec1Compressed[0];
|
|
1147
1152
|
if (head !== 0x02 && head !== 0x03) throw E(code, "EC point de-compression expects a compressed SEC1 point (0x02/0x03)");
|
|
1148
1153
|
try {
|
|
1149
|
-
return
|
|
1154
|
+
return guard.crypto.ecConvertPoint(sec1Compressed, nodeCurve, "uncompressed");
|
|
1150
1155
|
} catch (e) {
|
|
1151
1156
|
throw E(code, "EC point is not on curve " + nodeCurve + " (de-compression failed)", e);
|
|
1152
1157
|
}
|
|
@@ -1170,9 +1175,19 @@ function isCryptoKeyLike(x) {
|
|
|
1170
1175
|
* key this engine did not make while the others returned it. A JWK is an object rather than
|
|
1171
1176
|
* bytes, so only the byte formats are wrapped. */
|
|
1172
1177
|
function exportAnyKey(key, E, code, want) {
|
|
1173
|
-
|
|
1178
|
+
/** @internal At most ONE read of the key's type, and none at all when the caller named the format
|
|
1179
|
+
* it wants. It is a getter on node's own CryptoKey, so each read is a call a replacement answers,
|
|
1180
|
+
* and reading it per decision let one answer "private" where a PEM label was chosen and "public"
|
|
1181
|
+
* where the bytes were, which put a public key inside a `PRIVATE KEY` block. */
|
|
1182
|
+
var keyType;
|
|
1183
|
+
var readType = false;
|
|
1184
|
+
function typeOnce() {
|
|
1185
|
+
if (!readType) { keyType = key == null ? undefined : key.type; readType = true; }
|
|
1186
|
+
return keyType;
|
|
1187
|
+
}
|
|
1188
|
+
var format = want || _EXPORT_FORMAT[typeOnce()];
|
|
1174
1189
|
if (!format) throw E(code, "a CryptoKey with a private, public, or secret type is required");
|
|
1175
|
-
if (want === "jwk" && !_EXPORT_FORMAT[
|
|
1190
|
+
if (want === "jwk" && !_EXPORT_FORMAT[typeOnce()]) {
|
|
1176
1191
|
throw E(code, "a CryptoKey with a private, public, or secret type is required");
|
|
1177
1192
|
}
|
|
1178
1193
|
var asJwk = format === "jwk";
|
|
@@ -1186,7 +1201,7 @@ function exportAnyKey(key, E, code, want) {
|
|
|
1186
1201
|
throw E(code, "the CryptoKey comes from a different WebCrypto implementation and is not extractable, so its key material cannot be reached; import it through pki.webcrypto.subtle, or pass the key as DER");
|
|
1187
1202
|
}
|
|
1188
1203
|
var handle = key._handle;
|
|
1189
|
-
if (handle
|
|
1204
|
+
if (guard.crypto.isKeyObject(handle) && guard.crypto.keyKind(handle) === key.type) {
|
|
1190
1205
|
return _resolve(_Promise).then(function () {
|
|
1191
1206
|
if (asJwk) return guard.crypto.exportKey(handle, { format: "jwk" });
|
|
1192
1207
|
return format === "raw" ? guard.crypto.exportKey(handle) : guard.crypto.exportKey(handle, { format: "der", type: format });
|
|
@@ -1195,7 +1210,7 @@ function exportAnyKey(key, E, code, want) {
|
|
|
1195
1210
|
});
|
|
1196
1211
|
}
|
|
1197
1212
|
return _resolve(_Promise)
|
|
1198
|
-
.then(function () { return
|
|
1213
|
+
.then(function () { return guard.crypto.nodeExportKey(format, key); })
|
|
1199
1214
|
.then(wrap, function (e) {
|
|
1200
1215
|
throw E(code, "the CryptoKey comes from a different WebCrypto implementation and could not be exported for re-import; import it through pki.webcrypto.subtle, or pass the key as DER", e);
|
|
1201
1216
|
});
|
package/package.json
CHANGED
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:dc638a09-3eb3-4620-b84b-f3edd3453ec6",
|
|
6
6
|
"version": 1,
|
|
7
7
|
"metadata": {
|
|
8
|
-
"timestamp": "2026-10-
|
|
8
|
+
"timestamp": "2026-10-07T23:02:52.146Z",
|
|
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.8.
|
|
22
|
+
"bom-ref": "@blamejs/pki@0.8.61",
|
|
23
23
|
"type": "application",
|
|
24
24
|
"name": "pki",
|
|
25
|
-
"version": "0.8.
|
|
25
|
+
"version": "0.8.61",
|
|
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.8.
|
|
29
|
+
"purl": "pkg:npm/%40blamejs/pki@0.8.61",
|
|
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.8.
|
|
57
|
+
"ref": "@blamejs/pki@0.8.61",
|
|
58
58
|
"dependsOn": []
|
|
59
59
|
}
|
|
60
60
|
]
|