@blamejs/pki 0.5.15 → 0.5.17
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 +42 -0
- package/lib/acme.js +1 -0
- package/lib/asn1-der.js +1 -0
- package/lib/attrcert-sign.js +1 -0
- package/lib/cbor-det.js +1 -0
- package/lib/cmc-verify.js +1 -0
- package/lib/cmp-build.js +1 -0
- package/lib/cmp-verify.js +425 -82
- package/lib/cms-decrypt.js +58 -29
- package/lib/cms-encrypt.js +45 -24
- package/lib/cms-sign.js +3 -3
- package/lib/cms-verify.js +5 -1
- package/lib/constants.js +1 -0
- package/lib/crl-sign.js +1 -0
- package/lib/crmf-sign.js +1 -0
- package/lib/csr-sign.js +1 -0
- package/lib/ct.js +1 -0
- package/lib/est.js +1 -0
- package/lib/framework-error.js +1 -0
- package/lib/guard-all.js +2 -0
- package/lib/guard-async.js +14 -2
- package/lib/guard-bytes.js +183 -93
- package/lib/guard-compress.js +32 -12
- package/lib/guard-der.js +30 -7
- package/lib/guard-encoding.js +28 -12
- package/lib/guard-header.js +18 -7
- package/lib/guard-identifier.js +146 -79
- package/lib/guard-intrinsic.js +318 -0
- package/lib/guard-json.js +39 -12
- package/lib/guard-limits.js +15 -6
- package/lib/guard-name.js +72 -23
- package/lib/guard-parsed.js +71 -34
- package/lib/guard-range.js +17 -4
- package/lib/guard-secret.js +60 -2
- package/lib/guard-text.js +35 -6
- package/lib/guard-time.js +13 -4
- package/lib/hpke.js +6 -2
- package/lib/http-transport.js +1 -0
- package/lib/inspect.js +1 -0
- package/lib/jose.js +1 -0
- package/lib/key.js +2 -1
- package/lib/lint.js +1 -0
- package/lib/merkle.js +1 -0
- package/lib/ocsp.js +1 -0
- package/lib/oid.js +1 -0
- package/lib/path-validate.js +1 -0
- package/lib/pbes2.js +16 -8
- package/lib/pkcs12-build.js +2 -1
- package/lib/schema-all.js +1 -0
- package/lib/schema-c509.js +1 -0
- package/lib/schema-csrattrs.js +1 -0
- package/lib/schema-engine.js +1 -0
- package/lib/schema-pkcs8.js +1 -0
- package/lib/schema-smime.js +1 -0
- package/lib/schema-tsp.js +1 -0
- package/lib/schema-x509.js +1 -0
- package/lib/shbs.js +1 -0
- package/lib/sigstore.js +1 -0
- package/lib/smime.js +1 -0
- package/lib/tls-cert-compress.js +1 -0
- package/lib/trust.js +1 -0
- package/lib/tsp-sign.js +1 -0
- package/lib/webauthn.js +1 -0
- package/lib/webcrypto.js +11 -8
- package/lib/x509-sign.js +1 -0
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
package/lib/pbes2.js
CHANGED
|
@@ -133,13 +133,21 @@ function parsePbkdf2Params(paramsDer, opts, E, prefix, strictPrf) {
|
|
|
133
133
|
|
|
134
134
|
// AES-CBC content encryption / decryption (PKCS#7 pad). decrypt's final() throws on bad pad, and the caller
|
|
135
135
|
// collapses that into its uniform decrypt-failed verdict.
|
|
136
|
-
|
|
136
|
+
// cbcEncrypt(key, iv, plaintext, keyBits, E, code) -> the ciphertext.
|
|
137
|
+
// Takes the caller's typed error for the same reason cbcDecrypt does: the cipher runs through the
|
|
138
|
+
// shared guard, whose one throw has to keep the calling domain's own code.
|
|
139
|
+
function cbcEncrypt(key, iv, plaintext, keyBits, E, code) {
|
|
137
140
|
var c = nodeCrypto.createCipheriv("aes-" + keyBits + "-cbc", key, iv);
|
|
138
|
-
return
|
|
141
|
+
return guard.secret.cipherFinish(c, plaintext, E, code, "a content-encryption intermediate");
|
|
139
142
|
}
|
|
140
|
-
|
|
143
|
+
// cbcDecrypt(key, iv, ct, keyBits, E, code) -> the recovered plaintext.
|
|
144
|
+
// Takes the caller's typed error the way rc2.cbcDecrypt does, so a refusal keeps its own domain.
|
|
145
|
+
function cbcDecrypt(key, iv, ct, keyBits, E, code) {
|
|
141
146
|
var d = nodeCrypto.createDecipheriv("aes-" + keyBits + "-cbc", key, iv);
|
|
142
|
-
|
|
147
|
+
// A wrong key fails inside final(), on the padding check, and update() has by then produced every
|
|
148
|
+
// block but the last. Through the guard so that partial plaintext is cleared on both exits rather
|
|
149
|
+
// than abandoned readable on exactly the path an attacker induces.
|
|
150
|
+
return guard.secret.cipherFinish(d, ct, E, code, "the partially recovered plaintext");
|
|
143
151
|
}
|
|
144
152
|
|
|
145
153
|
// Higher-level PBES2 AES-CBC encrypt: derive an AES key from PRE-FORMATTED password bytes (the caller owns
|
|
@@ -160,11 +168,11 @@ function pbes2Encrypt(pwBytes, plaintext, opts, E, prefix) {
|
|
|
160
168
|
// is not cleared: the caller formatted it and may still own the buffer.
|
|
161
169
|
var key = nodeCrypto.pbkdf2Sync(pwBytes, salt, iterations, keyBits / 8, prfNode);
|
|
162
170
|
try {
|
|
163
|
-
return { algId: pbes2AlgId(salt, iterations, prf, cipherName, iv), ct: cbcEncrypt(key, iv, plaintext, keyBits) };
|
|
171
|
+
return { algId: pbes2AlgId(salt, iterations, prf, cipherName, iv), ct: cbcEncrypt(key, iv, plaintext, keyBits, E, prefix + "/bad-input") };
|
|
164
172
|
} finally {
|
|
165
173
|
// E is the caller's error FACTORY, not a class; guard-secret delegates its only throw to
|
|
166
|
-
// guard-bytes, which constructs.
|
|
167
|
-
// currency is compatible -- and the throw is unreachable here regardless, because a freshly
|
|
174
|
+
// guard-bytes, which constructs. `new` on a factory yields the object the factory returns, so
|
|
175
|
+
// the currency is compatible -- and the throw is unreachable here regardless, because a freshly
|
|
168
176
|
// allocated pbkdf2 buffer cannot be detached.
|
|
169
177
|
guard.secret.zeroize(key, E, prefix + "/bad-input", "the password-derived encryption key");
|
|
170
178
|
}
|
|
@@ -208,7 +216,7 @@ function pbes2Decrypt(pwBytes, params, ciphertext, opts, E, prefix, budget) {
|
|
|
208
216
|
if (budget.rounds < 0) throw E(prefix + "/iteration-limit", "the aggregate PBKDF2 key-derivation work exceeds the budget (a hostile many-element input)");
|
|
209
217
|
}
|
|
210
218
|
var dk = nodeCrypto.pbkdf2Sync(pwBytes, pb.salt, pb.iterations, keyBits / 8, pb.prfNode);
|
|
211
|
-
try { return cbcDecrypt(dk, iv, ciphertext, keyBits); }
|
|
219
|
+
try { return cbcDecrypt(dk, iv, ciphertext, keyBits, E, prefix + "/decrypt-failed"); }
|
|
212
220
|
catch (_e) { throw E(prefix + "/decrypt-failed", "decryption failed"); }
|
|
213
221
|
finally { guard.secret.zeroize(dk, E, prefix + "/bad-input", "the password-derived decryption key"); }
|
|
214
222
|
}
|
package/lib/pkcs12-build.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* @module pki.pkcs12
|
|
6
6
|
* @nav Signing
|
|
7
7
|
* @title PKCS#12
|
|
8
|
+
* @fullname PKCS#12 keystores (.p12 and .pfx): build and open
|
|
8
9
|
* @intro The PKCS#12 (.p12 / .pfx) producing side (RFC 7292, RFC 9579). `pki.pkcs12.build` assembles a
|
|
9
10
|
* password-integrity PFX -- key, certificate, CRL, and secret bags (shrouded keys and cert safes encrypted
|
|
10
11
|
* under RFC 8018 PBES2) wrapped in an AuthenticatedSafe, protected by either a classic Appendix B HMAC or
|
|
@@ -848,7 +849,7 @@ function _decryptLegacyPbe(ea, ct, password, opts, budget) {
|
|
|
848
849
|
try {
|
|
849
850
|
if (scheme.rc2) return rc2.cbcDecrypt(keyM, scheme.rc2, iv, ct, _err, "pkcs12/decrypt-failed");
|
|
850
851
|
var d = nodeCrypto.createDecipheriv(scheme.cipher, keyM, iv);
|
|
851
|
-
return
|
|
852
|
+
return guard.secret.cipherFinish(d, ct, Pkcs12Error, "pkcs12/bad-input", "the recovered safe contents");
|
|
852
853
|
} catch (_e) { throw _err("pkcs12/decrypt-failed", "decryption failed"); }
|
|
853
854
|
finally { guard.secret.zeroize(keyM, Pkcs12Error, "pkcs12/bad-input", "the password-derived decryption key"); }
|
|
854
855
|
}
|
package/lib/schema-all.js
CHANGED
package/lib/schema-c509.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* @module pki.schema.c509
|
|
6
6
|
* @nav Schema
|
|
7
7
|
* @title C509
|
|
8
|
+
* @fullname C509 compact certificates (CBOR-encoded X.509)
|
|
8
9
|
* @intro C509 CBOR-encoded certificates (draft-ietf-cose-cbor-encoded-cert). A compact CBOR
|
|
9
10
|
* re-encoding of an X.509 v3 certificate: a deterministic-CBOR array of exactly 11 elements
|
|
10
11
|
* (10 TBS fields + the issuer signature). Two modes: c509CertificateType 2 is a natively-signed
|
package/lib/schema-csrattrs.js
CHANGED
package/lib/schema-engine.js
CHANGED
package/lib/schema-pkcs8.js
CHANGED
package/lib/schema-smime.js
CHANGED
package/lib/schema-tsp.js
CHANGED
package/lib/schema-x509.js
CHANGED
package/lib/shbs.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* @module pki.shbs
|
|
6
6
|
* @nav Signatures
|
|
7
7
|
* @title Stateful hash-based
|
|
8
|
+
* @fullname Stateful hash-based signatures: LMS and XMSS
|
|
8
9
|
* @intro Stateful hash-based signature VERIFICATION -- HSS/LMS (RFC 8554),
|
|
9
10
|
* carried in X.509 by RFC 9802 and in CMS by RFC 9708, profiled by NIST
|
|
10
11
|
* SP 800-208. Verify only, by deliberate design: stateful hash-based signing
|
package/lib/sigstore.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* @module pki.sigstore
|
|
6
6
|
* @nav Supply chain
|
|
7
7
|
* @title Sigstore
|
|
8
|
+
* @fullname Sigstore bundles: keyless signing and provenance
|
|
8
9
|
* @intro Zero-dependency verifier for a Sigstore bundle, the exact artifact
|
|
9
10
|
* `npm publish --provenance` produces and the npm registry serves at its
|
|
10
11
|
* attestations API. A bundle is a keyless (Fulcio) signature over a DSSE-wrapped
|
package/lib/smime.js
CHANGED
package/lib/tls-cert-compress.js
CHANGED
package/lib/trust.js
CHANGED
package/lib/tsp-sign.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* @module pki.tsp
|
|
6
6
|
* @nav Signing
|
|
7
7
|
* @title Timestamps
|
|
8
|
+
* @fullname RFC 3161 trusted timestamps: request, sign and verify
|
|
8
9
|
* @intro Create an RFC 3161 timestamp token. A TimeStampToken IS a CMS SignedData whose
|
|
9
10
|
* encapsulated content is a `TSTInfo` (the timestamped message imprint + trusted time), so
|
|
10
11
|
* `sign(messageImprint, tsa, opts)` builds the `TSTInfo`, attaches the RFC 3161 sec. 2.4.2
|
package/lib/webauthn.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* @module pki.webauthn
|
|
6
6
|
* @nav Validation
|
|
7
7
|
* @title WebAuthn
|
|
8
|
+
* @fullname WebAuthn: verify registration attestation and assertions
|
|
8
9
|
* @intro Trust evaluation of a W3C WebAuthn (Level 3) / passkey attestation: parse
|
|
9
10
|
* the attestation object + authenticatorData, decode the COSE credential public
|
|
10
11
|
* key, and verify each defined attestation-statement format (packed, tpm,
|
package/lib/webcrypto.js
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* @module pki.webcrypto
|
|
6
6
|
* @nav Core
|
|
7
7
|
* @title WebCrypto
|
|
8
|
+
* @fullname WebCrypto: a SubtleCrypto surface over node:crypto
|
|
8
9
|
* @order 50
|
|
9
10
|
* @featured true
|
|
10
11
|
* @slug webcrypto
|
|
@@ -470,7 +471,7 @@ SubtleCrypto.prototype.encrypt = async function encrypt(algorithm, key, data) {
|
|
|
470
471
|
return _withSecretBytes(key, function (kb) {
|
|
471
472
|
var cipher = nodeCrypto.createCipheriv("aes-" + key.algorithm.length + "-gcm", kb, iv, { authTagLength: (alg.tagLength || 128) / 8 });
|
|
472
473
|
if (aad) cipher.setAAD(aad);
|
|
473
|
-
var ct =
|
|
474
|
+
var ct = guard.secret.cipherFinish(cipher, buf, WebCryptoError, "webcrypto/operation", "an AES-GCM encrypt intermediate");
|
|
474
475
|
return Buffer.concat([ct, cipher.getAuthTag()]);
|
|
475
476
|
});
|
|
476
477
|
}, "encrypt"));
|
|
@@ -480,7 +481,7 @@ SubtleCrypto.prototype.encrypt = async function encrypt(algorithm, key, data) {
|
|
|
480
481
|
return _toArrayBuffer(_runCipher(function () {
|
|
481
482
|
return _withSecretBytes(key, function (kb) {
|
|
482
483
|
var c2 = nodeCrypto.createCipheriv("aes-" + key.algorithm.length + "-cbc", kb, cbcIv);
|
|
483
|
-
return
|
|
484
|
+
return guard.secret.cipherFinish(c2, buf, WebCryptoError, "webcrypto/operation", "an AES-CBC encrypt intermediate");
|
|
484
485
|
});
|
|
485
486
|
}, "encrypt"));
|
|
486
487
|
}
|
|
@@ -490,7 +491,7 @@ SubtleCrypto.prototype.encrypt = async function encrypt(algorithm, key, data) {
|
|
|
490
491
|
return _toArrayBuffer(_runCipher(function () {
|
|
491
492
|
return _withSecretBytes(key, function (kb) {
|
|
492
493
|
var c3 = nodeCrypto.createCipheriv("aes-" + key.algorithm.length + "-ctr", kb, ctrCounter);
|
|
493
|
-
return
|
|
494
|
+
return guard.secret.cipherFinish(c3, buf, WebCryptoError, "webcrypto/operation", "an AES-CTR encrypt intermediate");
|
|
494
495
|
});
|
|
495
496
|
}, "encrypt"));
|
|
496
497
|
}
|
|
@@ -528,7 +529,9 @@ SubtleCrypto.prototype.decrypt = async function decrypt(algorithm, key, data) {
|
|
|
528
529
|
var d = nodeCrypto.createDecipheriv("aes-" + key.algorithm.length + "-gcm", kb, iv, { authTagLength: tagLen });
|
|
529
530
|
if (gcmAad) d.setAAD(gcmAad);
|
|
530
531
|
d.setAuthTag(tag);
|
|
531
|
-
|
|
532
|
+
// The recovered plaintext exists in full before final() judges the tag, so a forged message
|
|
533
|
+
// would otherwise abandon a readable copy on the throw path.
|
|
534
|
+
return guard.secret.cipherFinish(d, ct, WebCryptoError, "webcrypto/operation", "the recovered AES-GCM plaintext");
|
|
532
535
|
});
|
|
533
536
|
}, "decrypt"));
|
|
534
537
|
}
|
|
@@ -537,7 +540,7 @@ SubtleCrypto.prototype.decrypt = async function decrypt(algorithm, key, data) {
|
|
|
537
540
|
return _toArrayBuffer(_runCipher(function () {
|
|
538
541
|
return _withSecretBytes(key, function (kb) {
|
|
539
542
|
var d2 = nodeCrypto.createDecipheriv("aes-" + key.algorithm.length + "-cbc", kb, cbcIv2);
|
|
540
|
-
return
|
|
543
|
+
return guard.secret.cipherFinish(d2, buf, WebCryptoError, "webcrypto/operation", "the recovered AES-CBC plaintext");
|
|
541
544
|
});
|
|
542
545
|
}, "decrypt"));
|
|
543
546
|
}
|
|
@@ -547,7 +550,7 @@ SubtleCrypto.prototype.decrypt = async function decrypt(algorithm, key, data) {
|
|
|
547
550
|
return _toArrayBuffer(_runCipher(function () {
|
|
548
551
|
return _withSecretBytes(key, function (kb) {
|
|
549
552
|
var d3 = nodeCrypto.createDecipheriv("aes-" + key.algorithm.length + "-ctr", kb, ctrCounter2);
|
|
550
|
-
return
|
|
553
|
+
return guard.secret.cipherFinish(d3, buf, WebCryptoError, "webcrypto/operation", "the recovered AES-CTR plaintext");
|
|
551
554
|
});
|
|
552
555
|
}, "decrypt"));
|
|
553
556
|
}
|
|
@@ -874,7 +877,7 @@ SubtleCrypto.prototype.wrapKey = async function wrapKey(format, key, wrappingKey
|
|
|
874
877
|
try {
|
|
875
878
|
return _withSecretBytes(wrappingKey, function (wkBytes) {
|
|
876
879
|
var c = nodeCrypto.createCipheriv("aes" + wrappingKey.algorithm.length + "-wrap", wkBytes, Buffer.from("A6A6A6A6A6A6A6A6", "hex"));
|
|
877
|
-
return _toArrayBuffer(
|
|
880
|
+
return _toArrayBuffer(guard.secret.cipherFinish(c, bytes, WebCryptoError, "webcrypto/operation", "an AES-KW wrap intermediate"));
|
|
878
881
|
});
|
|
879
882
|
} catch (e) { throw new WebCryptoError("webcrypto/operation", "wrapKey: AES-KW key wrap failed", e); }
|
|
880
883
|
}
|
|
@@ -919,7 +922,7 @@ SubtleCrypto.prototype.unwrapKey = async function unwrapKey(format, wrappedKey,
|
|
|
919
922
|
try {
|
|
920
923
|
bytes = _withSecretBytes(unwrappingKey, function (kwBytes) {
|
|
921
924
|
var d = nodeCrypto.createDecipheriv("aes" + unwrappingKey.algorithm.length + "-wrap", kwBytes, Buffer.from("A6A6A6A6A6A6A6A6", "hex"));
|
|
922
|
-
return
|
|
925
|
+
return guard.secret.cipherFinish(d, wrapped, WebCryptoError, "webcrypto/operation", "the unwrapped key material");
|
|
923
926
|
});
|
|
924
927
|
} catch (e) { throw new WebCryptoError("webcrypto/operation", "unwrapKey: AES-KW key unwrap failed (integrity or length)", e); }
|
|
925
928
|
} else {
|
package/lib/x509-sign.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* @module pki.x509
|
|
7
7
|
* @nav Signing
|
|
8
8
|
* @title Certificates
|
|
9
|
+
* @fullname X.509 certificates: parse, sign and inspect
|
|
9
10
|
* @intro The X.509 certificate-issuance producing side. `pki.x509.sign` builds a `TBSCertificate`,
|
|
10
11
|
* signs it, and emits a `Certificate` (RFC 5280 sec. 4) that `pki.schema.x509.parse`,
|
|
11
12
|
* `pki.path.validate`, and OpenSSL all accept, self-signed or CA-signed, over any signature
|
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:b8b3d2cf-001e-4a5b-8644-a627ed3ce3c5",
|
|
6
6
|
"version": 1,
|
|
7
7
|
"metadata": {
|
|
8
|
-
"timestamp": "2026-08-
|
|
8
|
+
"timestamp": "2026-08-20T14:50:41.972Z",
|
|
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.17",
|
|
23
23
|
"type": "application",
|
|
24
24
|
"name": "pki",
|
|
25
|
-
"version": "0.5.
|
|
25
|
+
"version": "0.5.17",
|
|
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.17",
|
|
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.17",
|
|
58
58
|
"dependsOn": []
|
|
59
59
|
}
|
|
60
60
|
]
|