@blamejs/pki 0.6.13 → 0.6.15
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 +22 -1
- package/README.md +1 -1
- package/index.js +1 -1
- package/lib/acme.js +59 -815
- package/lib/asn1-der.js +7 -245
- package/lib/attrcert-sign.js +12 -260
- package/lib/attrcert-verify.js +1 -7
- package/lib/byte-reader.js +0 -8
- package/lib/byte-writer.js +0 -11
- package/lib/cbor-det.js +0 -54
- package/lib/cmc-build.js +15 -357
- package/lib/cmc-verify.js +6 -239
- package/lib/cmp-build.js +41 -317
- package/lib/cmp-session.js +73 -760
- package/lib/cmp-verify.js +32 -488
- package/lib/cms-compress.js +3 -32
- package/lib/cms-decrypt.js +29 -294
- package/lib/cms-encrypt.js +14 -234
- package/lib/cms-sign.js +29 -324
- package/lib/cms-verify.js +9 -500
- package/lib/composite-kem.js +2 -102
- package/lib/composite-sig.js +1 -77
- package/lib/constants.js +0 -249
- package/lib/crl-sign.js +9 -237
- package/lib/crl-verify.js +1 -10
- package/lib/crmf-sign.js +19 -198
- package/lib/crmf-verify.js +1 -12
- package/lib/csr-sign.js +3 -34
- package/lib/csr-verify.js +1 -12
- package/lib/ct.js +28 -253
- package/lib/edwards-point.js +10 -44
- package/lib/est.js +28 -764
- package/lib/framework-error.js +4 -182
- package/lib/guard-all.js +1 -58
- package/lib/guard-async.js +1 -36
- package/lib/guard-bytes.js +6 -650
- package/lib/guard-compress.js +5 -102
- package/lib/guard-crypto.js +1 -40
- package/lib/guard-der.js +2 -93
- package/lib/guard-encoding.js +2 -60
- package/lib/guard-header.js +1 -36
- package/lib/guard-identifier.js +7 -531
- package/lib/guard-intrinsic.js +1 -150
- package/lib/guard-json.js +10 -73
- package/lib/guard-limits.js +1 -77
- package/lib/guard-list.js +1 -49
- package/lib/guard-name.js +3 -209
- package/lib/guard-parsed.js +7 -335
- package/lib/guard-range.js +1 -71
- package/lib/guard-secret.js +1 -102
- package/lib/guard-text.js +1 -64
- package/lib/guard-time.js +1 -97
- package/lib/hpke.js +3 -105
- package/lib/http-digest.js +14 -142
- package/lib/http-retry-after.js +1 -47
- package/lib/http-transport.js +21 -131
- package/lib/inspect.js +30 -284
- package/lib/ip-utils.js +6 -47
- package/lib/jose.js +7 -142
- package/lib/key.js +2 -67
- package/lib/lint.js +9 -194
- package/lib/merkle.js +1 -27
- package/lib/mime.js +9 -82
- package/lib/ocsp-request-verify.js +1 -14
- package/lib/ocsp-verify.js +1 -82
- package/lib/ocsp.js +11 -169
- package/lib/oid.js +5 -337
- package/lib/path-validate.js +103 -1492
- package/lib/pbes2.js +2 -89
- package/lib/pkcs12-build.js +31 -379
- package/lib/pki-build.js +64 -290
- package/lib/rc2.js +2 -18
- package/lib/rfc3339.js +4 -27
- package/lib/scep.js +59 -233
- package/lib/schema-all.js +0 -122
- package/lib/schema-attrcert.js +4 -146
- package/lib/schema-c509.js +153 -802
- package/lib/schema-cmc.js +5 -220
- package/lib/schema-cmp.js +2 -223
- package/lib/schema-cms.js +13 -427
- package/lib/schema-crl.js +5 -68
- package/lib/schema-crmf.js +6 -167
- package/lib/schema-csr.js +1 -54
- package/lib/schema-csrattrs.js +2 -87
- package/lib/schema-engine.js +0 -152
- package/lib/schema-ocsp.js +0 -117
- package/lib/schema-pkcs12.js +2 -93
- package/lib/schema-pkcs8.js +3 -35
- package/lib/schema-pkix.js +24 -655
- package/lib/schema-smime.js +0 -54
- package/lib/schema-tsp.js +3 -99
- package/lib/schema-x509.js +4 -63
- package/lib/shbs.js +11 -95
- package/lib/sign-scheme.js +2 -97
- package/lib/sigstore.js +9 -169
- package/lib/sleep.js +2 -8
- package/lib/smime.js +15 -408
- package/lib/tls-cert-compress.js +0 -62
- package/lib/trust.js +19 -185
- package/lib/tsp-sign.js +16 -270
- package/lib/validator-all.js +1 -30
- package/lib/validator-attcert.js +2 -46
- package/lib/validator-cose.js +2 -153
- package/lib/validator-keydesc.js +1 -37
- package/lib/validator-sig.js +1 -46
- package/lib/validator-tls.js +1 -88
- package/lib/validator-tpm.js +19 -122
- package/lib/verify-seam.js +1 -24
- package/lib/webauthn-mds.js +3 -400
- package/lib/webauthn.js +12 -833
- package/lib/webcrypto.js +5 -485
- package/lib/x509-sign.js +4 -108
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
package/lib/pbes2.js
CHANGED
|
@@ -1,14 +1,7 @@
|
|
|
1
1
|
// SPDX-License-Identifier: Apache-2.0
|
|
2
2
|
// Copyright (c) blamejs contributors
|
|
3
3
|
"use strict";
|
|
4
|
-
//
|
|
5
|
-
// @internal -- the RFC 8018 PBES2 / PBKDF2 primitives, the single home shared by pki.cms EncryptedData / PWRI
|
|
6
|
-
// password encryption and pki.key EncryptedPrivateKeyInfo (RFC 5958). Error-factory-parameterized like the
|
|
7
|
-
// guard family: every reject goes through the caller's `E(code, msg, cause)` full-code factory plus a domain
|
|
8
|
-
// `prefix`, so pki.cms keeps cms/* codes and pki.key keeps key/* codes off one implementation. Extracted
|
|
9
|
-
// behavior-preservingly from cms-encrypt.js and cms-decrypt.js; the shipped CMS PBES2 tests are the guard.
|
|
10
|
-
// A shape here that cannot route through a guard stays with its caller; the reusable PBES2 shape lives here
|
|
11
|
-
// so a fourth copy (the drift a reviewer flags) cannot re-accrete.
|
|
4
|
+
// @internal
|
|
12
5
|
|
|
13
6
|
var nodeCrypto = require("crypto");
|
|
14
7
|
var asn1 = require("./asn1-der");
|
|
@@ -20,15 +13,9 @@ var C = require("./constants");
|
|
|
20
13
|
var b = asn1.build;
|
|
21
14
|
function O(n) { return oid.byName(n); }
|
|
22
15
|
|
|
23
|
-
// PBKDF2 prf tables: the OID name -> node digest (encrypt names the prf) and the OID -> node digest (decrypt
|
|
24
|
-
// reads the OID). One source, both directions.
|
|
25
16
|
var PRF_NODE_BY_NAME = { hmacWithSHA1: "sha1", hmacWithSHA256: "sha256", hmacWithSHA384: "sha384", hmacWithSHA512: "sha512" };
|
|
26
17
|
var PRF_NODE_BY_OID = {}; Object.keys(PRF_NODE_BY_NAME).forEach(function (n) { PRF_NODE_BY_OID[O(n)] = PRF_NODE_BY_NAME[n]; });
|
|
27
18
|
|
|
28
|
-
// content-encryption OID -> AES key bits (CBC + GCM). The PBES2 encryptionScheme + CMS content cipher table.
|
|
29
|
-
// CONTENT_MODE rides the same rows so a cipher can never be present for its key length but absent for its
|
|
30
|
-
// mode: key length alone does not distinguish an AEAD cipher from a plain one, and a consumer that resolves
|
|
31
|
-
// only the length would open content in the wrong mode whenever the two happen to share a key size.
|
|
32
19
|
var CONTENT_KEYBITS = {}, CONTENT_MODE = {};
|
|
33
20
|
[["aes128-CBC", 128, "cbc"], ["aes192-CBC", 192, "cbc"], ["aes256-CBC", 256, "cbc"],
|
|
34
21
|
["aes128-GCM", 128, "gcm"], ["aes192-GCM", 192, "gcm"], ["aes256-GCM", 256, "gcm"]].forEach(function (r) {
|
|
@@ -36,15 +23,8 @@ var CONTENT_KEYBITS = {}, CONTENT_MODE = {};
|
|
|
36
23
|
CONTENT_MODE[O(r[0])] = r[2];
|
|
37
24
|
});
|
|
38
25
|
|
|
39
|
-
// A password is an octet string (RFC 8018 sec. 2): a string is UTF-8-encoded deterministically (correct for
|
|
40
|
-
// non-ASCII, and byte-identical to OpenSSL), a Buffer/Uint8Array used verbatim.
|
|
41
26
|
function passwordBytes(p, E, prefix) { return passwordBytesOwned(p, E, prefix).bytes; }
|
|
42
27
|
|
|
43
|
-
// The same conversion, reporting OWNERSHIP. A string or Uint8Array password is encoded into a fresh
|
|
44
|
-
// Buffer this toolkit allocated -- a credential copy that must be cleared once the derivation has
|
|
45
|
-
// consumed it -- while a caller-supplied Buffer is BORROWED and must be left intact. Without this
|
|
46
|
-
// distinction a call site can only be safe by leaving every password encoding readable, which is
|
|
47
|
-
// the common case, since a password arrives as a string far more often than as a Buffer.
|
|
48
28
|
function passwordBytesOwned(p, E, prefix) {
|
|
49
29
|
if (Buffer.isBuffer(p)) return { bytes: p, owned: false };
|
|
50
30
|
if (p instanceof Uint8Array) return { bytes: Buffer.from(p), owned: true };
|
|
@@ -52,15 +32,12 @@ function passwordBytesOwned(p, E, prefix) {
|
|
|
52
32
|
throw E(prefix + "/bad-input", "a password must be a string, Buffer, or Uint8Array");
|
|
53
33
|
}
|
|
54
34
|
|
|
55
|
-
// iterationCount for a PRODUCED PBES2/PWRI structure: a positive integer at or below the cap the decryptor
|
|
56
|
-
// enforces, so a structure we emit is always one we can read back (config-time throw on a bad value).
|
|
57
35
|
function assertIterations(n, E, prefix) {
|
|
58
36
|
if (typeof n !== "number" || !isFinite(n) || n < 1 || Math.floor(n) !== n) throw E(prefix + "/bad-input", "iterations must be a positive integer");
|
|
59
37
|
if (n > C.LIMITS.PBKDF2_MAX_ITERATIONS) throw E(prefix + "/bad-input", "iterations exceeds the " + C.LIMITS.PBKDF2_MAX_ITERATIONS + " cap");
|
|
60
38
|
return n;
|
|
61
39
|
}
|
|
62
40
|
|
|
63
|
-
// Bound a PRODUCED salt to the same cap the decryptor enforces.
|
|
64
41
|
function assertSalt(salt, E, prefix) {
|
|
65
42
|
guard.limits.byteCap(salt, C.LIMITS.PBKDF2_MAX_SALT, E, prefix + "/bad-input", "salt");
|
|
66
43
|
return salt;
|
|
@@ -69,28 +46,18 @@ function assertSalt(salt, E, prefix) {
|
|
|
69
46
|
function prfNodeByName(prf, E, prefix) { if (!PRF_NODE_BY_NAME[prf]) throw E(prefix + "/bad-input", "unsupported prf " + JSON.stringify(prf)); return PRF_NODE_BY_NAME[prf]; }
|
|
70
47
|
function prfNodeByOid(oidStr, E, prefix) { if (!PRF_NODE_BY_OID[oidStr]) throw E(prefix + "/unsupported-algorithm", "unsupported PBKDF2 prf " + oidStr); return PRF_NODE_BY_OID[oidStr]; }
|
|
71
48
|
|
|
72
|
-
// PBKDF2-params { salt OCTET STRING, iterationCount INTEGER, prf DEFAULT hmacWithSHA1 }. prf equal to the
|
|
73
|
-
// DEFAULT (hmacWithSHA1) MUST be omitted on encode (X.690 sec. 11.5 / RFC 8018 App. A.2); every other prf is
|
|
74
|
-
// an hmacWithSHA_n AlgorithmIdentifier carrying NULL parameters.
|
|
75
49
|
function pbkdf2ParamsSeq(salt, iterations, prf) {
|
|
76
50
|
var kids = [b.octetString(salt), b.integer(BigInt(iterations))];
|
|
77
51
|
if (prf !== "hmacWithSHA1") kids.push(b.sequence([b.oid(O(prf)), b.nullValue()]));
|
|
78
52
|
return b.sequence(kids);
|
|
79
53
|
}
|
|
80
54
|
|
|
81
|
-
// The PBES2 AlgorithmIdentifier: SEQUENCE { id-PBES2, SEQUENCE { keyDerivationFunc PBKDF2, encryptionScheme } }.
|
|
82
|
-
// The single home for the CMS EncryptedData contentEncryptionAlgorithm and the RFC 5958 EncryptedPrivateKeyInfo
|
|
83
|
-
// encryptionAlgorithm: both wrap the same PBES2 structure around a PBKDF2 KDF plus an AES-CBC scheme whose
|
|
84
|
-
// IV rides in the encryptionScheme parameter. `cipherName` is a registry NAME (an AES-CBC OID name).
|
|
85
55
|
function pbes2AlgId(salt, iterations, prf, cipherName, iv) {
|
|
86
56
|
var kdf = b.sequence([b.oid(O("pbkdf2")), pbkdf2ParamsSeq(salt, iterations, prf)]);
|
|
87
57
|
var encScheme = b.sequence([b.oid(O(cipherName)), b.octetString(iv)]);
|
|
88
58
|
return b.sequence([b.oid(O("pbes2")), b.sequence([kdf, encScheme])]);
|
|
89
59
|
}
|
|
90
60
|
|
|
91
|
-
// SEQUENCE structural guards -- a malformed (primitive / too-short) attacker-controlled parameter SEQUENCE is
|
|
92
|
-
// a typed E(prefix + "/bad-input"), never a raw `.children` dereference fault (a PBES2 structure is public,
|
|
93
|
-
// not a decrypt oracle).
|
|
94
61
|
function requireChildren(node, minLen, what, E, prefix) {
|
|
95
62
|
if (!node || !node.children || node.children.length < minLen) throw E(prefix + "/bad-input", "malformed " + what);
|
|
96
63
|
return node.children;
|
|
@@ -100,9 +67,6 @@ function seqChildren(paramsDer, minLen, what, E, prefix) {
|
|
|
100
67
|
return requireChildren(asn1.decode(paramsDer), minLen, what, E, prefix);
|
|
101
68
|
}
|
|
102
69
|
|
|
103
|
-
// Strict PBKDF2-params decode: salt (capped before derivation), iterationCount (positiveInt31 + cap, downward-
|
|
104
|
-
// overridable via a validated-positive-int opts.maxIterations so Math.min(NaN, cap) cannot silently disable
|
|
105
|
-
// the DoS cap), prf. Returns { salt, iterations, prfNode }.
|
|
106
70
|
function parsePbkdf2Params(paramsDer, opts, E, prefix, strictPrf) {
|
|
107
71
|
var node = Buffer.isBuffer(paramsDer) ? asn1.decode(paramsDer) : paramsDer;
|
|
108
72
|
var kids = requireChildren(node, 2, "PBKDF2 parameters", E, prefix);
|
|
@@ -120,8 +84,6 @@ function parsePbkdf2Params(paramsDer, opts, E, prefix, strictPrf) {
|
|
|
120
84
|
var ch = node.children[i];
|
|
121
85
|
if (ch.tagClass === "universal" && ch.tagNumber === asn1.TAGS.SEQUENCE) {
|
|
122
86
|
var prfOid = asn1.read.oid(ch.children[0]);
|
|
123
|
-
// X.690 sec. 11.5 / RFC 8018 App. A.2: a prf equal to the DEFAULT (hmacWithSHA1 with NULL parameters)
|
|
124
|
-
// MUST be omitted -- an explicit encoding of it is non-canonical. A strictPrf caller rejects it.
|
|
125
87
|
if (strictPrf && prfOid === O("hmacWithSHA1") && ch.children.length > 1 && ch.children[1].tagClass === "universal" && ch.children[1].tagNumber === asn1.TAGS.NULL) {
|
|
126
88
|
throw E(prefix + "/bad-input", "a PBKDF2 prf equal to the default hmacWithSHA1 must be omitted (X.690 sec. 11.5)");
|
|
127
89
|
}
|
|
@@ -131,28 +93,15 @@ function parsePbkdf2Params(paramsDer, opts, E, prefix, strictPrf) {
|
|
|
131
93
|
return { salt: salt, iterations: iterations, prfNode: prfNode };
|
|
132
94
|
}
|
|
133
95
|
|
|
134
|
-
// AES-CBC content encryption / decryption (PKCS#7 pad). decrypt's final() throws on bad pad, and the caller
|
|
135
|
-
// collapses that into its uniform decrypt-failed verdict.
|
|
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
96
|
function cbcEncrypt(key, iv, plaintext, keyBits, E, code) {
|
|
140
97
|
var c = nodeCrypto.createCipheriv("aes-" + keyBits + "-cbc", key, iv);
|
|
141
98
|
return guard.secret.cipherFinish(c, plaintext, E, code, "a content-encryption intermediate");
|
|
142
99
|
}
|
|
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
100
|
function cbcDecrypt(key, iv, ct, keyBits, E, code) {
|
|
146
101
|
var d = nodeCrypto.createDecipheriv("aes-" + keyBits + "-cbc", key, iv);
|
|
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
102
|
return guard.secret.cipherFinish(d, ct, E, code, "the partially recovered plaintext");
|
|
151
103
|
}
|
|
152
104
|
|
|
153
|
-
// Higher-level PBES2 AES-CBC encrypt: derive an AES key from PRE-FORMATTED password bytes (the caller owns
|
|
154
|
-
// the encoding -- CMS UTF-8 vs PKCS#12 App. B.1) and encrypt the plaintext, returning the PBES2
|
|
155
|
-
// AlgorithmIdentifier + ciphertext. `cipherName` is an AES-CBC registry name (aes128/192/256-CBC).
|
|
156
105
|
function pbes2Encrypt(pwBytes, plaintext, opts, E, prefix) {
|
|
157
106
|
opts = opts || {};
|
|
158
107
|
var cipherName = opts.cipher || "aes256-CBC";
|
|
@@ -163,33 +112,14 @@ function pbes2Encrypt(pwBytes, plaintext, opts, E, prefix) {
|
|
|
163
112
|
var iterations = assertIterations(opts.iterations == null ? 2048 : opts.iterations, E, prefix);
|
|
164
113
|
var salt = opts.salt != null ? assertSalt(opts.salt, E, prefix) : nodeCrypto.randomBytes(16);
|
|
165
114
|
var iv = opts.iv != null ? opts.iv : nodeCrypto.randomBytes(16);
|
|
166
|
-
// The derived key is this module's allocation and protects the caller's plaintext (a private key
|
|
167
|
-
// in the pkcs8 and pkcs12 callers), so it is cleared once the encryption has consumed it. pwBytes
|
|
168
|
-
// is not cleared: the caller formatted it and may still own the buffer.
|
|
169
115
|
var key = nodeCrypto.pbkdf2Sync(pwBytes, salt, iterations, keyBits / 8, prfNode);
|
|
170
116
|
try {
|
|
171
117
|
return { algId: pbes2AlgId(salt, iterations, prf, cipherName, iv), ct: cbcEncrypt(key, iv, plaintext, keyBits, E, prefix + "/bad-input") };
|
|
172
118
|
} finally {
|
|
173
|
-
// E is the caller's error FACTORY, not a class; guard-secret delegates its only throw to
|
|
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
|
|
176
|
-
// allocated pbkdf2 buffer cannot be detached.
|
|
177
119
|
guard.secret.zeroize(key, E, prefix + "/bad-input", "the password-derived encryption key");
|
|
178
120
|
}
|
|
179
121
|
}
|
|
180
122
|
|
|
181
|
-
// PBES2 AES-CBC DECRYPT: parse the PBES2 params (PBKDF2 kdf + AES-CBC scheme), derive the key from
|
|
182
|
-
// PRE-FORMATTED password bytes (the caller owns UTF-8 vs BMPString), and AES-CBC-decrypt. Structural faults
|
|
183
|
-
// (a non-PBKDF2 KDF, a non-AES-CBC scheme, an over-cap salt/iteration, a wrong-length IV, a malformed param
|
|
184
|
-
// SEQUENCE) are typed pre-derivation and password-independent, so they leak no oracle; the generic
|
|
185
|
-
// <prefix>/bad-input a param guard raises is normalized to the structural <prefix>/bad-algorithm-parameters.
|
|
186
|
-
// A wrong key / bad PKCS#7 pad collapses to the UNIFORM <prefix>/decrypt-failed (RFC 8018 sec. 8). The
|
|
187
|
-
// plaintext integrity re-check (re-parse as a PrivateKeyInfo / SafeContents) is the CALLER's step.
|
|
188
|
-
// `budget` (optional) is a shared { rounds } tally a caller decrypting MANY structures under one
|
|
189
|
-
// call charges against, so the per-structure iteration cap cannot simply reset each time: PBKDF2
|
|
190
|
-
// runs on the event loop, and a store that repeats a costly bag up to the parser's element limit
|
|
191
|
-
// otherwise multiplies the cap by that limit. A caller decrypting exactly one structure passes
|
|
192
|
-
// nothing and is bounded by the cap alone.
|
|
193
123
|
function pbes2Decrypt(pwBytes, params, ciphertext, opts, E, prefix, budget) {
|
|
194
124
|
var keyBits, iv, pb;
|
|
195
125
|
try {
|
|
@@ -197,7 +127,7 @@ function pbes2Decrypt(pwBytes, params, ciphertext, opts, E, prefix, budget) {
|
|
|
197
127
|
var kdf = requireChildren(p[0], 2, "PBES2 keyDerivationFunc", E, prefix);
|
|
198
128
|
var encScheme = requireChildren(p[1], 2, "PBES2 encryptionScheme", E, prefix);
|
|
199
129
|
if (asn1.read.oid(kdf[0]) !== O("pbkdf2")) throw E(prefix + "/unsupported-algorithm", "the PBES2 keyDerivationFunc must be PBKDF2 (RFC 8018 sec. 6.2)");
|
|
200
|
-
pb = parsePbkdf2Params(kdf[1].bytes, opts, E, prefix, true);
|
|
130
|
+
pb = parsePbkdf2Params(kdf[1].bytes, opts, E, prefix, true);
|
|
201
131
|
var encOid = asn1.read.oid(encScheme[0]);
|
|
202
132
|
keyBits = CONTENT_KEYBITS[encOid];
|
|
203
133
|
if (!keyBits || (oid.name(encOid) || "").indexOf("CBC") === -1) throw E(prefix + "/unsupported-algorithm", "unsupported PBES2 encryptionScheme " + (oid.name(encOid) || encOid) + " (AES-CBC only)");
|
|
@@ -210,7 +140,6 @@ function pbes2Decrypt(pwBytes, params, ciphertext, opts, E, prefix, budget) {
|
|
|
210
140
|
}
|
|
211
141
|
throw E(prefix + "/bad-algorithm-parameters", "malformed PBES2 parameters", e);
|
|
212
142
|
}
|
|
213
|
-
// Charge the shared budget before deriving, so the work is refused instead of performed.
|
|
214
143
|
if (budget) {
|
|
215
144
|
budget.rounds -= pb.iterations;
|
|
216
145
|
if (budget.rounds < 0) throw E(prefix + "/iteration-limit", "the aggregate PBKDF2 key-derivation work exceeds the budget (a hostile many-element input)");
|
|
@@ -221,13 +150,8 @@ function pbes2Decrypt(pwBytes, params, ciphertext, opts, E, prefix, budget) {
|
|
|
221
150
|
finally { guard.secret.zeroize(dk, E, prefix + "/bad-input", "the password-derived decryption key"); }
|
|
222
151
|
}
|
|
223
152
|
|
|
224
|
-
// ---- PBMAC1 (RFC 9579 / RFC 8018 App. A.5) : PBKDF2 -> HMAC over a message --
|
|
225
|
-
// An hmacWithSHA_n AlgorithmIdentifier carries NULL parameters (RFC 8018 B.1.1).
|
|
226
153
|
function _hmacAlgId(name) { return b.sequence([b.oid(O(name)), b.nullValue()]); }
|
|
227
154
|
|
|
228
|
-
// The id-PBMAC1 AlgorithmIdentifier: id-PBMAC1 + PBMAC1-params { keyDerivationFunc PBKDF2, messageAuthScheme
|
|
229
|
-
// HMAC }, the byte-exact inverse of schema-pkcs12 / schema-cmp's PBMAC1_PARAMS. `desc` = { salt,
|
|
230
|
-
// iterationCount, keyLength, prfName, macName }. The prf is omitted iff it equals the default hmacWithSHA1.
|
|
231
155
|
function pbmac1AlgId(desc) {
|
|
232
156
|
var pbkdf2Params = [b.octetString(desc.salt), b.integer(BigInt(desc.iterationCount)), b.integer(BigInt(desc.keyLength))];
|
|
233
157
|
if (desc.prfName !== "hmacWithSHA1") pbkdf2Params.push(_hmacAlgId(desc.prfName));
|
|
@@ -235,26 +159,15 @@ function pbmac1AlgId(desc) {
|
|
|
235
159
|
return b.sequence([b.oid(O("pbmac1")), b.sequence([pbkdf2AlgId, _hmacAlgId(desc.macName)])]);
|
|
236
160
|
}
|
|
237
161
|
|
|
238
|
-
// Compute PBMAC1 = HMAC_macHash(PBKDF2(pwBytes, salt, iter, keyLength, prfHash), message). The PBKDF2 prf
|
|
239
|
-
// and the HMAC messageAuthScheme are INDEPENDENT (RFC 9579 sec. 4 / RFC 8018 App. A.5) -- e.g. a SHA-512 PRF
|
|
240
|
-
// with a SHA-256 HMAC -- so both are passed explicitly. `prfHash` / `macHash` are WebCrypto hash names
|
|
241
|
-
// ("SHA-256"); pwBytes is pre-formatted (the caller owns the encoding).
|
|
242
162
|
function pbmac1(pwBytes, salt, iterationCount, keyLength, prfHash, macHash, message) {
|
|
243
163
|
var subtle = webcrypto.webcrypto.subtle;
|
|
244
164
|
return subtle.importKey("raw", pwBytes, { name: "PBKDF2" }, false, ["deriveBits"]).then(function (baseKey) {
|
|
245
165
|
return subtle.deriveBits({ name: "PBKDF2", salt: salt, iterations: iterationCount, hash: prfHash }, baseKey, keyLength * 8);
|
|
246
166
|
}).then(function (bits) {
|
|
247
|
-
// The derived MAC key is this function's allocation, in two forms: the ArrayBuffer deriveBits
|
|
248
|
-
// returned and the Buffer view over it that is imported. Clearing the view clears both, and it
|
|
249
|
-
// runs whether the signing succeeds or throws. The sibling PBES2 encrypt/decrypt above clear
|
|
250
|
-
// their derived keys, and every PBMAC1 consumer (PKCS#12 build and verification) inherits this.
|
|
251
167
|
var mk = Buffer.from(bits);
|
|
252
168
|
return subtle.importKey("raw", mk, { name: "HMAC", hash: macHash }, false, ["sign"]).then(function (hmacKey) {
|
|
253
169
|
return subtle.sign({ name: "HMAC" }, hmacKey, message);
|
|
254
170
|
}).finally(function () {
|
|
255
|
-
// pbmac1 takes no caller error factory, and this key is engine-adjacent, so the engine's
|
|
256
|
-
// typed class is the right currency -- a raw TypeError must never escape a lib boundary.
|
|
257
|
-
// Unreachable in practice: a freshly allocated Buffer cannot be detached.
|
|
258
171
|
guard.secret.zeroize(mk, webcrypto.WebCryptoError, "webcrypto/operation", "the PBMAC1 key");
|
|
259
172
|
});
|
|
260
173
|
}).then(function (sig) { return Buffer.from(sig); });
|