@blamejs/pki 0.5.7 → 0.5.8

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.
Files changed (104) hide show
  1. package/CHANGELOG.md +405 -386
  2. package/MIGRATING.md +43 -0
  3. package/README.md +12 -12
  4. package/lib/acme.js +31 -31
  5. package/lib/asn1-der.js +10 -10
  6. package/lib/attrcert-sign.js +19 -19
  7. package/lib/byte-reader.js +6 -6
  8. package/lib/byte-writer.js +5 -5
  9. package/lib/cbor-det.js +27 -24
  10. package/lib/cmc-build.js +97 -92
  11. package/lib/cmc-verify.js +106 -30
  12. package/lib/cmp-build.js +25 -25
  13. package/lib/cmp-session.js +70 -70
  14. package/lib/cmp-verify.js +71 -57
  15. package/lib/cms-compress.js +7 -7
  16. package/lib/cms-decrypt.js +90 -72
  17. package/lib/cms-encrypt.js +32 -32
  18. package/lib/cms-sign.js +74 -55
  19. package/lib/cms-verify.js +97 -75
  20. package/lib/composite-sig.js +13 -13
  21. package/lib/constants.js +4 -4
  22. package/lib/crl-sign.js +22 -22
  23. package/lib/crl-verify.js +7 -6
  24. package/lib/crmf-sign.js +14 -14
  25. package/lib/csr-sign.js +8 -8
  26. package/lib/ct.js +37 -37
  27. package/lib/edwards-point.js +7 -7
  28. package/lib/est.js +98 -55
  29. package/lib/framework-error.js +5 -5
  30. package/lib/guard-all.js +3 -3
  31. package/lib/guard-async.js +4 -4
  32. package/lib/guard-bytes.js +79 -79
  33. package/lib/guard-compress.js +17 -17
  34. package/lib/guard-crypto.js +1 -1
  35. package/lib/guard-encoding.js +15 -15
  36. package/lib/guard-header.js +3 -3
  37. package/lib/guard-identifier.js +16 -16
  38. package/lib/guard-json.js +15 -15
  39. package/lib/guard-limits.js +7 -7
  40. package/lib/guard-name.js +81 -16
  41. package/lib/guard-parsed.js +80 -80
  42. package/lib/guard-range.js +19 -19
  43. package/lib/guard-secret.js +11 -10
  44. package/lib/guard-text.js +6 -6
  45. package/lib/guard-time.js +10 -10
  46. package/lib/hpke.js +18 -17
  47. package/lib/http-digest.js +35 -35
  48. package/lib/http-retry-after.js +13 -13
  49. package/lib/http-transport.js +20 -19
  50. package/lib/inspect.js +53 -53
  51. package/lib/ip-utils.js +2 -2
  52. package/lib/jose.js +13 -13
  53. package/lib/key.js +16 -16
  54. package/lib/lint.js +51 -51
  55. package/lib/merkle.js +51 -36
  56. package/lib/mime.js +18 -18
  57. package/lib/ocsp-verify.js +10 -10
  58. package/lib/ocsp.js +13 -13
  59. package/lib/oid.js +29 -29
  60. package/lib/path-validate.js +114 -113
  61. package/lib/pbes2.js +16 -16
  62. package/lib/pkcs12-build.js +53 -53
  63. package/lib/pki-build.js +21 -19
  64. package/lib/rc2.js +1 -1
  65. package/lib/rfc3339.js +5 -5
  66. package/lib/schema-all.js +31 -31
  67. package/lib/schema-attrcert.js +12 -12
  68. package/lib/schema-c509.js +144 -142
  69. package/lib/schema-cmc.js +58 -58
  70. package/lib/schema-cmp.js +43 -43
  71. package/lib/schema-cms.js +45 -45
  72. package/lib/schema-crl.js +7 -7
  73. package/lib/schema-crmf.js +28 -28
  74. package/lib/schema-csr.js +12 -12
  75. package/lib/schema-csrattrs.js +16 -16
  76. package/lib/schema-engine.js +18 -18
  77. package/lib/schema-ocsp.js +15 -15
  78. package/lib/schema-pkcs12.js +20 -20
  79. package/lib/schema-pkcs8.js +2 -2
  80. package/lib/schema-pkix.js +131 -126
  81. package/lib/schema-smime.js +19 -19
  82. package/lib/schema-tsp.js +12 -12
  83. package/lib/schema-x509.js +3 -3
  84. package/lib/shbs.js +18 -18
  85. package/lib/sign-scheme.js +13 -13
  86. package/lib/sigstore.js +10 -11
  87. package/lib/sleep.js +1 -1
  88. package/lib/smime.js +308 -96
  89. package/lib/tls-cert-compress.js +18 -18
  90. package/lib/trust.js +27 -27
  91. package/lib/tsp-sign.js +17 -17
  92. package/lib/validator-all.js +1 -1
  93. package/lib/validator-attcert.js +1 -1
  94. package/lib/validator-cose.js +43 -44
  95. package/lib/validator-keydesc.js +3 -3
  96. package/lib/validator-sig.js +13 -13
  97. package/lib/validator-tls.js +11 -11
  98. package/lib/validator-tpm.js +20 -19
  99. package/lib/webauthn-mds.js +66 -66
  100. package/lib/webauthn.js +33 -33
  101. package/lib/webcrypto.js +15 -15
  102. package/lib/x509-sign.js +13 -13
  103. package/package.json +3 -2
  104. package/sbom.cdx.json +6 -6
package/lib/pbes2.js CHANGED
@@ -2,12 +2,12 @@
2
2
  // Copyright (c) blamejs contributors
3
3
  "use strict";
4
4
  //
5
- // @internal -- the RFC 8018 PBES2 / PBKDF2 primitives, the ONE home shared by pki.cms EncryptedData / PWRI
5
+ // @internal -- the RFC 8018 PBES2 / PBKDF2 primitives, the single home shared by pki.cms EncryptedData / PWRI
6
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 + 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
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
11
  // so a fourth copy (the drift a reviewer flags) cannot re-accrete.
12
12
 
13
13
  var nodeCrypto = require("crypto");
@@ -26,7 +26,7 @@ var PRF_NODE_BY_NAME = { hmacWithSHA1: "sha1", hmacWithSHA256: "sha256", hmacWit
26
26
  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
27
 
28
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
29
+ // CONTENT_MODE rides the same rows so a cipher can never be present for its key length but absent for its
30
30
  // mode: key length alone does not distinguish an AEAD cipher from a plain one, and a consumer that resolves
31
31
  // only the length would open content in the wrong mode whenever the two happen to share a key size.
32
32
  var CONTENT_KEYBITS = {}, CONTENT_MODE = {};
@@ -79,8 +79,8 @@ function pbkdf2ParamsSeq(salt, iterations, prf) {
79
79
  }
80
80
 
81
81
  // The PBES2 AlgorithmIdentifier: SEQUENCE { id-PBES2, SEQUENCE { keyDerivationFunc PBKDF2, encryptionScheme } }.
82
- // The ONE 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
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
84
  // IV rides in the encryptionScheme parameter. `cipherName` is a registry NAME (an AES-CBC OID name).
85
85
  function pbes2AlgId(salt, iterations, prf, cipherName, iv) {
86
86
  var kdf = b.sequence([b.oid(O("pbkdf2")), pbkdf2ParamsSeq(salt, iterations, prf)]);
@@ -100,7 +100,7 @@ function seqChildren(paramsDer, minLen, what, E, prefix) {
100
100
  return requireChildren(asn1.decode(paramsDer), minLen, what, E, prefix);
101
101
  }
102
102
 
103
- // Strict PBKDF2-params decode: salt (capped BEFORE derivation), iterationCount (positiveInt31 + cap, downward-
103
+ // Strict PBKDF2-params decode: salt (capped before derivation), iterationCount (positiveInt31 + cap, downward-
104
104
  // overridable via a validated-positive-int opts.maxIterations so Math.min(NaN, cap) cannot silently disable
105
105
  // the DoS cap), prf. Returns { salt, iterations, prfNode }.
106
106
  function parsePbkdf2Params(paramsDer, opts, E, prefix, strictPrf) {
@@ -131,7 +131,7 @@ function parsePbkdf2Params(paramsDer, opts, E, prefix, strictPrf) {
131
131
  return { salt: salt, iterations: iterations, prfNode: prfNode };
132
132
  }
133
133
 
134
- // AES-CBC content encryption / decryption (PKCS#7 pad). decrypt's final() throws on bad pad -- the caller
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
  function cbcEncrypt(key, iv, plaintext, keyBits) {
137
137
  var c = nodeCrypto.createCipheriv("aes-" + keyBits + "-cbc", key, iv);
@@ -155,9 +155,9 @@ function pbes2Encrypt(pwBytes, plaintext, opts, E, prefix) {
155
155
  var iterations = assertIterations(opts.iterations == null ? 2048 : opts.iterations, E, prefix);
156
156
  var salt = opts.salt != null ? assertSalt(opts.salt, E, prefix) : nodeCrypto.randomBytes(16);
157
157
  var iv = opts.iv != null ? opts.iv : nodeCrypto.randomBytes(16);
158
- // The derived key is this module's allocation and protects the caller's plaintext -- a private key
159
- // in the pkcs8 / pkcs12 callers -- so it is cleared once the encryption has consumed it. pwBytes is
160
- // NOT: the caller formatted it and may still own the buffer.
158
+ // The derived key is this module's allocation and protects the caller's plaintext (a private key
159
+ // in the pkcs8 and pkcs12 callers), so it is cleared once the encryption has consumed it. pwBytes
160
+ // is not cleared: the caller formatted it and may still own the buffer.
161
161
  var key = nodeCrypto.pbkdf2Sync(pwBytes, salt, iterations, keyBits / 8, prfNode);
162
162
  try {
163
163
  return { algId: pbes2AlgId(salt, iterations, prf, cipherName, iv), ct: cbcEncrypt(key, iv, plaintext, keyBits) };
@@ -202,7 +202,7 @@ function pbes2Decrypt(pwBytes, params, ciphertext, opts, E, prefix, budget) {
202
202
  }
203
203
  throw E(prefix + "/bad-algorithm-parameters", "malformed PBES2 parameters", e);
204
204
  }
205
- // Charge the shared budget BEFORE deriving, so the work is refused rather than performed.
205
+ // Charge the shared budget before deriving, so the work is refused instead of performed.
206
206
  if (budget) {
207
207
  budget.rounds -= pb.iterations;
208
208
  if (budget.rounds < 0) throw E(prefix + "/iteration-limit", "the aggregate PBKDF2 key-derivation work exceeds the budget (a hostile many-element input)");
@@ -218,7 +218,7 @@ function pbes2Decrypt(pwBytes, params, ciphertext, opts, E, prefix, budget) {
218
218
  function _hmacAlgId(name) { return b.sequence([b.oid(O(name)), b.nullValue()]); }
219
219
 
220
220
  // The id-PBMAC1 AlgorithmIdentifier: id-PBMAC1 + PBMAC1-params { keyDerivationFunc PBKDF2, messageAuthScheme
221
- // HMAC } -- the byte-exact inverse of schema-pkcs12 / schema-cmp's PBMAC1_PARAMS. `desc` = { salt,
221
+ // HMAC }, the byte-exact inverse of schema-pkcs12 / schema-cmp's PBMAC1_PARAMS. `desc` = { salt,
222
222
  // iterationCount, keyLength, prfName, macName }. The prf is omitted iff it equals the default hmacWithSHA1.
223
223
  function pbmac1AlgId(desc) {
224
224
  var pbkdf2Params = [b.octetString(desc.salt), b.integer(BigInt(desc.iterationCount)), b.integer(BigInt(desc.keyLength))];
@@ -238,7 +238,7 @@ function pbmac1(pwBytes, salt, iterationCount, keyLength, prfHash, macHash, mess
238
238
  }).then(function (bits) {
239
239
  // The derived MAC key is this function's allocation, in two forms: the ArrayBuffer deriveBits
240
240
  // returned and the Buffer view over it that is imported. Clearing the view clears both, and it
241
- // runs whether the signing succeeds or throws -- the sibling PBES2 encrypt/decrypt above clear
241
+ // runs whether the signing succeeds or throws. The sibling PBES2 encrypt/decrypt above clear
242
242
  // their derived keys, and every PBMAC1 consumer (PKCS#12 build and verification) inherits this.
243
243
  var mk = Buffer.from(bits);
244
244
  return subtle.importKey("raw", mk, { name: "HMAC", hash: macHash }, false, ["sign"]).then(function (hmacKey) {
@@ -17,20 +17,20 @@
17
17
  */
18
18
  //
19
19
  // The PBES2 bag encryption and the PBMAC1 MAC compose the shared lib/pbes2.js home (the same PBKDF2 + AES-CBC
20
- // + HMAC primitives pki.cms and pki.key use), fed PKCS#12 App. B.1-formatted password bytes -- NOT the CMS
20
+ // + HMAC primitives pki.cms and pki.key use), fed PKCS#12 App. B.1-formatted password bytes, never the CMS
21
21
  // UTF-8 encoding, the single most common PKCS#12 interop failure. The classic Appendix B.2 KDF (ID=3, the MAC
22
22
  // integrity purpose) is bespoke PKCS#12 crypto with no in-tree equivalent, built here as one primitive and
23
- // cross-checked against OpenSSL. The MAC is computed over the CONTENT octets of the id-data authSafe OCTET
24
- // STRING (excluding its TLV header) -- exactly the parser's `macedBytes`, the canonical off-by-the-header
25
- // trap designed out. Public-key integrity (an id-signedData authSafe -- a CMS SignedData over the exact
23
+ // cross-checked against OpenSSL. The MAC is computed over the content octets of the id-data authSafe OCTET
24
+ // STRING (excluding its TLV header), exactly the parser's `macedBytes`, the canonical off-by-the-header
25
+ // trap designed out. Public-key integrity (an id-signedData authSafe, a CMS SignedData over the exact
26
26
  // AuthenticatedSafe, no MacData) is produced by composing pki.cms.sign and verified on open by pki.cms.verify
27
27
  // as the integrity gate before any bag is trusted; the signer is surfaced, never trust-chained (the caller's
28
28
  // pki.path.validate step). Public-key PRIVACY (an id-envelopedData safe encrypting the SafeContents to a
29
29
  // recipient public key, RFC 7292 sec. 3.1) is produced by composing pki.cms.encrypt (AES-CBC EnvelopedData,
30
- // never GCM/AuthEnvelopedData) and opened by composing pki.cms.decrypt with the recipient key -- AFTER the
30
+ // never GCM/AuthEnvelopedData) and opened by composing pki.cms.decrypt with the recipient key, after the
31
31
  // integrity gate, with every recipient-side fault collapsed to the uniform pkcs12/decrypt-failed. Privacy is
32
32
  // independent of integrity: all four combinations (password/public-key integrity x password/public-key privacy)
33
- // are permitted, and the recipient key is a privacy credential only -- never a MAC key, signer, or PBES2 password.
33
+ // are permitted, and the recipient key is a privacy credential only: never a MAC key, signer, or PBES2 password.
34
34
 
35
35
  var nodeCrypto = require("crypto");
36
36
  var asn1 = require("./asn1-der");
@@ -55,13 +55,13 @@ var PemError = frameworkError.PemError;
55
55
  function O(n) { return oid.byName(n); }
56
56
  function _err(code, msg, cause) { return new Pkcs12Error(code, msg, cause); }
57
57
 
58
- // PKCS#12 integrity/privacy defaults (named, not call-site literals -- rule 12).
58
+ // PKCS#12 integrity/privacy defaults, named here so no call site writes them as literals (rule 12).
59
59
  var DEFAULT_MAC_ITER = 2048;
60
60
  var DEFAULT_PBMAC1_ITER = 2048;
61
61
  var MAC_SALT_BYTES = 8;
62
- var MAX_PBMAC1_KEYLEN = 1024; // an HMAC key beyond a hash block is pointless -- bound the derived length
63
- // Both MAC paths cap iterations to bound the SYNCHRONOUS derivation that blocks the event loop, but at
64
- // different counts BECAUSE the per-iteration cost differs by ~5x -- the two ceilings target a comparable
62
+ var MAX_PBMAC1_KEYLEN = 1024; // an HMAC key beyond a hash block is pointless, so bound the derived length
63
+ // Both MAC paths cap iterations to bound the synchronous derivation that blocks the event loop, but at
64
+ // different counts, because the per-iteration cost differs by ~5x: the two ceilings target a comparable
65
65
  // ~1-2 second wall-clock budget, not inconsistent DoS budgets. The classic Appendix B KDF is a hand-rolled
66
66
  // JS hash loop (a createHash per iteration, ~1.1us each, so 1e6 ~= 1s); PBMAC1 derives via native
67
67
  // crypto.pbkdf2Sync (one FFI call, ~0.2us per iteration, so the shared C.LIMITS.PBKDF2_MAX_ITERATIONS of 1e7
@@ -69,12 +69,12 @@ var MAX_PBMAC1_KEYLEN = 1024; // an HMAC key beyond a hash block is pointless
69
69
  // pkcs12-local (its KDF is bespoke here) while PBMAC1 reuses the toolkit-wide PBKDF2 ceiling. 1e6 is ~500x
70
70
  // the OpenSSL default (2048) yet still bounds the loop to ~1 second.
71
71
  var CLASSIC_MAC_MAX_ITERATIONS = 1000000;
72
- // The AGGREGATE cap on synchronous KDF work across a single open() -- rounds summed over every encrypted
72
+ // The aggregate cap on synchronous KDF work across a single open(): rounds summed over every encrypted
73
73
  // bag and safe, whichever scheme it uses: the legacy App. B KDF (its block count x iterations) and PBKDF2
74
74
  // alike. The per-bag iteration cap resets per bag, so a hostile store that duplicates a costly bag up to the
75
75
  // parser's 1024-element limit would otherwise block the event loop for minutes; this bounds the total to
76
- // ~the classic MAC ceiling. It covers BOTH schemes because covering only the legacy one left the modern
77
- // path -- the one every current producer emits -- free to multiply its cap by the element limit.
76
+ // ~the classic MAC ceiling. It covers both schemes because covering only the legacy one left the modern
77
+ // path (the one every current producer emits) free to multiply its cap by the element limit.
78
78
  // A conforming store runs only a few thousand rounds (its handful of bags at ~2048 iterations).
79
79
  var KDF_MAX_ROUNDS = CLASSIC_MAC_MAX_ITERATIONS;
80
80
 
@@ -104,10 +104,10 @@ var DIGEST_NAME = { sha1: "sha1", sha256: "sha256", sha384: "sha384", sha512: "s
104
104
  // is taken verbatim as already-formatted bytes (an escape hatch for a caller that pre-encodes).
105
105
  function _p12Password(pw) { return _p12PasswordOwned(pw).bytes; }
106
106
 
107
- // An ABSENT password is refused rather than encoded as the empty one. The two are not the same
107
+ // An absent password is refused, never encoded as the empty one. The two are not the same
108
108
  // credential, and the difference is invisible at the call site: a caller who misspells the option,
109
109
  // or threads it through a layer that drops it, otherwise gets a store whose private key is
110
- // protected by nothing and no error anywhere saying so. The empty password remains available --
110
+ // protected by nothing and no error anywhere saying so. The empty password remains available:
111
111
  // it just has to be asked for, as "".
112
112
  var _MISSING_PASSWORD = "a password must be a string, Buffer, or Uint8Array -- an omitted password " +
113
113
  "is not the empty password; pass \"\" to use the empty one deliberately";
@@ -116,8 +116,8 @@ var _MISSING_PASSWORD = "a password must be a string, Buffer, or Uint8Array -- a
116
116
  // capability cannot arrive with its option silently ignored at this boundary.
117
117
  var _INTEGRITY_OPTS = { mode: 1, signer: 1, signers: 1, certificates: 1, sid: 1, signingTime: 1 };
118
118
 
119
- // The same encoding, reporting OWNERSHIP -- mirroring pbes2.passwordBytesOwned. A caller-supplied
120
- // Buffer is returned AS-IS and is BORROWED: clearing it would destroy the caller's own credential,
119
+ // The same encoding, reporting ownership, mirroring pbes2.passwordBytesOwned. A caller-supplied
120
+ // Buffer is returned as-is and is borrowed: clearing it would destroy the caller's own credential,
121
121
  // which is a worse defect than leaving a copy readable. Every other input is re-encoded into a
122
122
  // buffer this module allocated, which it must clear once a derivation has consumed it.
123
123
  function _p12PasswordOwned(pw) {
@@ -125,9 +125,9 @@ function _p12PasswordOwned(pw) {
125
125
  return { bytes: _p12Encode(pw), owned: true };
126
126
  }
127
127
  function _p12Encode(pw) {
128
- // A view first, so a detached backing store is a reject rather than an empty password; then a COPY,
129
- // because everything this function returns is reported OWNED and gets zeroized after derivation --
130
- // handing back a view of a caller's Uint8Array would wipe the caller's own credential.
128
+ // A view first, so a detached backing store is a reject and never an empty password; then a copy,
129
+ // because everything this function returns is reported owned and gets zeroized after derivation,
130
+ // and handing back a view of a caller's Uint8Array would wipe the caller's own credential.
131
131
  if (Buffer.isBuffer(pw) || pw instanceof Uint8Array) return guard.bytes.snapshot(pw, Pkcs12Error, "pkcs12/bad-input", "the password");
132
132
  if (typeof pw !== "string") throw _err("pkcs12/bad-input", _MISSING_PASSWORD);
133
133
  var out = Buffer.alloc(pw.length * 2 + 2); // + the 2-byte NULL terminator
@@ -141,12 +141,12 @@ function _p12Encode(pw) {
141
141
  }
142
142
 
143
143
  // The password bytes for the RFC 8018 PBES2 bag ciphers and the RFC 9579 PBMAC1 MAC. Although RFC 9579 sec. 6
144
- // specifies the BMPString encoding here too, OpenSSL and NSS -- and thus the interoperable ecosystem -- feed
144
+ // specifies the BMPString encoding here too, OpenSSL and NSS (and thus the interoperable ecosystem) feed
145
145
  // PBKDF2 the raw UTF-8 password for these modern schemes (confirmed byte-for-byte against `openssl pkcs12`),
146
146
  // reserving the BMPString+NULL form for the bespoke Appendix B KDF only. A file we emit must open in OpenSSL,
147
147
  // so the modern schemes use UTF-8 here; only the classic Appendix B MAC uses `_p12Password`.
148
- // The UTF-8 encoding, reporting OWNERSHIP -- the sibling of _p12PasswordOwned, and it exists
149
- // for the same reason. A caller-supplied Buffer is BORROWED and left alone; every other input is
148
+ // The UTF-8 encoding, reporting ownership: the sibling of _p12PasswordOwned, and it exists
149
+ // for the same reason. A caller-supplied Buffer is borrowed and left alone; every other input is
150
150
  // re-encoded into a buffer this module allocated, and a plaintext password copy this module made
151
151
  // is cleared once the derivation has consumed it. Without it the App. B.1 copy taken from the same
152
152
  // argument in the same call was wiped while this one was not.
@@ -171,7 +171,7 @@ function _blockFill(src, blockSize) {
171
171
  }
172
172
 
173
173
  // RFC 7292 Appendix B.2 KDF: derive `nBytes` of key material for purpose `id` (1 = cipher key, 2 = IV,
174
- // 3 = MAC) from the App. B.1 password bytes + salt over `iterations` rounds of `hashName`. NOT PBKDF2. The
174
+ // 3 = MAC) from the App. B.1 password bytes + salt over `iterations` rounds of `hashName`. This is not PBKDF2. The
175
175
  // block count c = ceil(nBytes/u): the MAC always requests exactly the hash output u (c = 1, one diversified,
176
176
  // salted, iterated hash), while a legacy-PBE cipher key wider than u (e.g. 24-byte 3-key-3DES from SHA-1's
177
177
  // 20-byte output, c = 2) exercises the multi-block feedback (step 6C: I = (I + B + 1) mod 2^(8v) between
@@ -181,7 +181,7 @@ function _p12Kdf(hashName, id, pwBytes, salt, iterations, nBytes) {
181
181
  var uv = P12_KDF_UV[hashName], u = uv.u, v = uv.v;
182
182
  var D = Buffer.alloc(v, id); // step 1: v copies of the ID diversifier
183
183
  // Each fill is a full block-repeated copy of the salt / password; only their concatenation is
184
- // used, so the sources are cleared rather than abandoned.
184
+ // used, so the sources are cleared and never abandoned.
185
185
  var sFill = _blockFill(salt, v), pFill = _blockFill(pwBytes, v);
186
186
  var I = Buffer.concat([sFill, pFill]); // steps 2-4: I = S || P
187
187
  guard.secret.zeroizeAll([sFill, pFill], Pkcs12Error, "pkcs12/bad-input", "a key-derivation fill");
@@ -206,7 +206,7 @@ function _p12Kdf(hashName, id, pwBytes, salt, iterations, nBytes) {
206
206
  }
207
207
  guard.secret.zeroize(A, Pkcs12Error, "pkcs12/bad-input", "a key-derivation block");
208
208
  }
209
- // I is S || P -- it carries the password bytes -- and is finished with here.
209
+ // I is S || P, so it carries the password bytes, and is finished with here.
210
210
  guard.secret.zeroize(I, Pkcs12Error, "pkcs12/bad-input", "the key-derivation input block");
211
211
  // Step 8 is "the first nBytes of A", but returning a SUBARRAY would hand back a view over a
212
212
  // larger allocation: a caller clearing what it received would leave the rest of the final digest
@@ -358,7 +358,7 @@ function _pbeOpts(enc) {
358
358
  };
359
359
  }
360
360
 
361
- // SafeContents ::= SEQUENCE OF SafeBag (ordered, NOT a SET OF).
361
+ // SafeContents ::= SEQUENCE OF SafeBag (ordered, and not a SET OF).
362
362
  function _buildSafeContents(bags, opts, depth) {
363
363
  if (!Array.isArray(bags)) throw _err("pkcs12/bad-input", "bags must be an array");
364
364
  if (bags.length > C.LIMITS.PKCS12_MAX_ELEMENTS) throw _err("pkcs12/bad-input", "a SafeContents exceeds the element cap " + C.LIMITS.PKCS12_MAX_ELEMENTS);
@@ -366,13 +366,13 @@ function _buildSafeContents(bags, opts, depth) {
366
366
  }
367
367
 
368
368
  // One AuthenticatedSafe element: a plaintext id-data ContentInfo, an id-encryptedData ContentInfo whose
369
- // EncryptedData is the PBES2 encryption of the SafeContents (RFC 7292 sec. 5.1 step 2A/2B), or -- for
370
- // PUBLIC-KEY privacy (sec. 3.1) -- an id-envelopedData ContentInfo whose CMS EnvelopedData encrypts the
369
+ // EncryptedData is the PBES2 encryption of the SafeContents (RFC 7292 sec. 5.1 step 2A/2B), or, for
370
+ // public-key privacy (sec. 3.1), an id-envelopedData ContentInfo whose CMS EnvelopedData encrypts the
371
371
  // SafeContents to one or more recipient public keys. Async because the envelope path awaits pki.cms.encrypt.
372
372
  async function _buildAuthSafeElement(sc, opts) {
373
373
  if (!sc || typeof sc !== "object") throw _err("pkcs12/bad-input", "each safeContents entry must be an object");
374
- // A privacy directive is honored whenever its field is PRESENT (even if falsy). A present-but-falsy `recipients`
375
- // or `encrypt` (null / false / "") is a configuration error that intended privacy -- it must fail closed, NEVER
374
+ // A privacy directive is honored whenever its field is present (even if falsy). A present-but-falsy `recipients`
375
+ // or `encrypt` (null / false / "") is a configuration error that intended privacy, so it must fail closed and never
376
376
  // silently fall through to a plaintext id-data safe that would emit the bags in cleartext (privacy downgraded to
377
377
  // none while still producing a valid MAC-protected PFX). Omit the field entirely for a genuinely plaintext safe.
378
378
  var hasRecipients = sc.recipients !== undefined;
@@ -381,10 +381,10 @@ async function _buildAuthSafeElement(sc, opts) {
381
381
  var safeContentsDer = _buildSafeContents(sc.bags || [], opts, 0);
382
382
  if (hasRecipients) {
383
383
  if (!Array.isArray(sc.recipients) || !sc.recipients.length) throw _err("pkcs12/bad-input", "safeContents.recipients must be a non-empty array of recipient descriptors (RFC 5652 sec. 6.1)");
384
- // Public-key privacy admits only CERTIFICATE recipients (ktri / kari / kemri -- RSA / ECDH / X25519 / X448 /
385
- // ML-KEM, dispatched off the cert key). A password (pwri) or KEK (kekri) recipient is NOT public-key privacy
386
- // and pki.pkcs12.open (which forwards only { recipientKey, recipientCert } to cms.decrypt) cannot reopen it --
387
- // so reject it here rather than emit a store the toolkit's own reader cannot process. (Re-open: pwri/kekri
384
+ // Public-key privacy admits only certificate recipients (ktri / kari / kemri: RSA / ECDH / X25519 / X448 /
385
+ // ML-KEM, dispatched off the cert key). A password (pwri) or KEK (kekri) recipient is not public-key privacy
386
+ // and pki.pkcs12.open (which forwards only { recipientKey, recipientCert } to cms.decrypt) cannot reopen it,
387
+ // so reject it here and never emit a store the toolkit's own reader cannot process. (Re-open: pwri/kekri
388
388
  // privacy when open forwards the full cms.decrypt key-material model.)
389
389
  sc.recipients.forEach(function (r) {
390
390
  if (!r || typeof r !== "object" || r.cert == null) throw _err("pkcs12/bad-input", "a public-key privacy recipient must be a certificate recipient { cert } (a password or KEK recipient is not public-key privacy and cannot be reopened by pkcs12.open)");
@@ -474,9 +474,9 @@ function _normalizeSpec(spec, opts) {
474
474
  (spec.ca || []).forEach(function (ca) { certBags.push({ type: "cert", cert: ca }); });
475
475
  var sc = [];
476
476
  if (enveloped) {
477
- // Public-key-privacy convenience: the cert bags + a PLAINTEXT keyBag in ONE recipient-enveloped safe (the
477
+ // Public-key-privacy convenience: the cert bags plus a plaintext keyBag in one recipient-enveloped safe (the
478
478
  // envelope supplies confidentiality; there is no recipient-encrypted key-bag type, RFC 7292 sec. 4.2). The
479
- // caller password, if any, remains the MAC (integrity) password -- privacy and integrity are independent.
479
+ // caller password, if any, remains the MAC (integrity) password; privacy and integrity are independent.
480
480
  var bags = certBags.slice();
481
481
  if (spec.key != null) bags.push({ type: "key", key: spec.key, friendlyName: spec.friendlyName, localKeyId: spec.localKeyId });
482
482
  sc.push({ recipients: opts.recipientCerts.map(function (c) { return { cert: c }; }), bags: bags });
@@ -505,7 +505,7 @@ function _normalizeSpec(spec, opts) {
505
505
  * plaintext or PBES2-encrypted `SafeContents` of key / shroudedKey / cert / crl / secret / nested
506
506
  * safeContents bags. Keys and certs are validated before wrapping. Password integrity (the default) MACs the
507
507
  * AuthenticatedSafe with a classic Appendix B HMAC or an RFC 9579 PBMAC1. Public-key integrity
508
- * (`opts.integrity.mode: "public-key"`) instead wraps the AuthenticatedSafe in a CMS SignedData -- a
508
+ * (`opts.integrity.mode: "public-key"`) instead wraps the AuthenticatedSafe in a CMS SignedData: a
509
509
  * signature from a keypair, no MacData (RFC 7292 sec. 4). Privacy (PBES2 bag encryption via `password`) is
510
510
  * independent of the integrity mode. The store is re-parsed before return.
511
511
  *
@@ -675,33 +675,33 @@ function _capWork(iterations, salt, opts, keyLength, hardCap) {
675
675
  * @defends pkcs12-unauthenticated-decrypt (CWE-347), pbes2-padding-oracle (CWE-208)
676
676
  * @related pki.pkcs12.build, pki.pkcs12.verifyMac, pki.schema.pkcs12.parse
677
677
  *
678
- * Read a PKCS#12 store: verify its integrity FIRST -- a password store's MAC, or a public-key store's CMS
679
- * SignedData signature (RFC 7292 sec. 4 / 5.1 -- never trust a bag from a store whose integrity check fails) --
680
- * then decrypt every PBES2 privacy safe and pkcs8ShroudedKeyBag with the password -- and every id-envelopedData
681
- * (public-key privacy) safe with `opts.recipientKey` (RFC 7292 sec. 3.1, via `pki.cms.decrypt`) -- returning a
682
- * structured bundle `{ integrityMode, macVerified, signers, keys, certs, crls, secrets }` -- each private key as PKCS#8
678
+ * Read a PKCS#12 store: verify its integrity first (a password store's MAC, or a public-key store's CMS
679
+ * SignedData signature, per RFC 7292 sec. 4 / 5.1, so no bag from a store whose integrity check fails is trusted),
680
+ * then decrypt every PBES2 privacy safe and pkcs8ShroudedKeyBag with the password, and every id-envelopedData
681
+ * (public-key privacy) safe with `opts.recipientKey` (RFC 7292 sec. 3.1, via `pki.cms.decrypt`), returning a
682
+ * structured bundle `{ integrityMode, macVerified, signers, keys, certs, crls, secrets }` with each private key as PKCS#8
683
683
  * `PrivateKeyInfo` DER (re-validated), each certificate / CRL / secret as raw DER, all carrying their
684
684
  * `friendlyName` / `localKeyId` for pairing. `pfx` is the store's DER `Buffer`, a PEM string, or an
685
- * unmodified `pki.schema.pkcs12.parse` result; a REBUILT parsed store is refused, since the bytes whose
685
+ * unmodified `pki.schema.pkcs12.parse` result; a rebuilt parsed store is refused, since the bytes whose
686
686
  * integrity is checked and the bags returned as checked are separate properties of it.
687
687
  *
688
688
  * A MAC-less store is refused (`pkcs12/no-integrity`) unless `opts.allowUnauthenticated` is set. A public-key
689
689
  * integrity store is verified through `pki.cms.verify` before any bag is trusted; a signature failure is
690
690
  * `pkcs12/signature-invalid`, and `signers` carries the per-signer verdict `[{ ok, sid, cert }]` (`null` in
691
- * password / MAC-less mode). The signer is surfaced, NEVER trust-chained -- anchoring `signers[i].cert` to a
691
+ * password / MAC-less mode). The signer is surfaced, never trust-chained: anchoring `signers[i].cert` to a
692
692
  * trust root is the caller's `pki.path.validate` step (the out-of-path signer contract). Privacy is
693
693
  * independent of integrity, so the bag `password` still decrypts a public-key store's bags; a wrong bag
694
694
  * password there is the uniform `pkcs12/decrypt-failed` (no MAC to catch it first). Bags encrypted under
695
- * PBES2 (AES-CBC), or the RFC 7292 App. C legacy schemes an `openssl pkcs12 -legacy` store uses -- 3-key /
696
- * 2-key Triple-DES-CBC and 40-/128-bit RC2-CBC (the App. B KDF over the BMPString password, RC2 via an in-tree
697
- * RFC 2268 cipher) -- are decrypted; the legacy RC4 schemes are named and refused.
695
+ * PBES2 (AES-CBC), or the RFC 7292 App. C legacy schemes an `openssl pkcs12 -legacy` store uses (3-key /
696
+ * 2-key Triple-DES-CBC and 40-/128-bit RC2-CBC, the App. B KDF over the BMPString password, RC2 via an in-tree
697
+ * RFC 2268 cipher), are decrypted; the legacy RC4 schemes are named and refused.
698
698
  *
699
699
  * @opts
700
- * - `allowUnauthenticated` (boolean) -- open a MAC-less store anyway (result carries `macVerified: false`).
701
- * - `signerCerts` (array of cert DER) -- signer certificate(s) for a public-key store built with `certificates: false` (forwarded to `pki.cms.verify`).
702
- * - `recipientKey` (PKCS#8 DER|PEM) + `recipientCert` (cert DER|PEM, or `recipientIndex`) -- decrypt an id-envelopedData (public-key privacy) safe. The recipient key is a privacy credential only; a wrong key / tampered envelope is the uniform `pkcs12/decrypt-failed`, and an enveloped safe with no `recipientKey` is `pkcs12/no-recipient-key`.
703
- * - `maxIterations` (number) -- lower the PBKDF2 / MAC iteration cap for this call (downward-only).
704
- * - `keys` (string) -- `der` (default) or `crypto` (also `pki.key.import` each private key to a CryptoKey).
700
+ * - `allowUnauthenticated` (boolean): open a MAC-less store anyway (result carries `macVerified: false`).
701
+ * - `signerCerts` (array of cert DER): signer certificate(s) for a public-key store built with `certificates: false` (forwarded to `pki.cms.verify`).
702
+ * - `recipientKey` (PKCS#8 DER|PEM) + `recipientCert` (cert DER|PEM, or `recipientIndex`): decrypt an id-envelopedData (public-key privacy) safe. The recipient key is a privacy credential only; a wrong key / tampered envelope is the uniform `pkcs12/decrypt-failed`, and an enveloped safe with no `recipientKey` is `pkcs12/no-recipient-key`.
703
+ * - `maxIterations` (number): lower the PBKDF2 / MAC iteration cap for this call (downward-only).
704
+ * - `keys` (string): `der` (default) or `crypto` (also `pki.key.import` each private key to a CryptoKey).
705
705
  * - `importAlgorithm` -- forwarded to `pki.key.import` for the ambiguous RSA / EC arms when `keys: crypto`.
706
706
  * @example
707
707
  * var pair = await pki.key.generate("Ed25519");
package/lib/pki-build.js CHANGED
@@ -6,7 +6,7 @@
6
6
  // binds a domain namespace once and returns the shared PKIX producing primitives every signer module
7
7
  // composes: the distinguished-name encoder, the GeneralName + RFC 5280 sec. 4.2.1 extension-value
8
8
  // encoders, the embedded-input validators (a raw Name / a SubjectPublicKeyInfo / a pre-encoded Extension
9
- // run through the SAME parser the decoder uses), the sign-scheme bridge, and the post-sign signature
9
+ // run through the same parser the decoder uses), the sign-scheme bridge, and the post-sign signature
10
10
  // self-check (the key-match / proof-of-possession verify). Each is parameterized on the CALLER's error
11
11
  // class + code prefix, so pki.x509.sign keeps x509/* codes and pki.csr.sign keeps csr/*.
12
12
 
@@ -64,7 +64,7 @@ function makeBuilder(ctx) {
64
64
  }
65
65
  function encodeAtv(attrName, value) {
66
66
  if (value == null || value === "") throw E("bad-name", "the " + attrName + " attribute value must be a non-empty string");
67
- // oid.byName returns undefined (does not throw) for an unrecognized name -- reject it explicitly.
67
+ // For an unrecognized name oid.byName returns undefined and does not throw, so reject explicitly.
68
68
  var typeOid = O(attrName);
69
69
  if (typeOid == null) throw E("bad-name", "unknown distinguished-name attribute " + JSON.stringify(attrName));
70
70
  var valueTlv;
@@ -119,8 +119,8 @@ function makeBuilder(ctx) {
119
119
  case "uniformResourceIdentifier": case "uri": return b.contextPrimitive(6, ia5Content(v));
120
120
  case "iPAddress":
121
121
  // Accept a dotted-quad / colon-hex string (packed to its 4/16 network octets) as well as a
122
- // pre-packed Buffer, so an iPAddress SAN reads like dNSName/URI rather than forcing the caller
123
- // to pack octets by hand (RFC 5280 sec. 4.2.1.6 -- a GeneralName iPAddress is a bare host address).
122
+ // pre-packed Buffer, so an iPAddress SAN reads like dNSName/URI and the caller does not pack
123
+ // octets by hand (a GeneralName iPAddress is a bare host address, RFC 5280 sec. 4.2.1.6).
124
124
  var ipBuf = v;
125
125
  if (typeof v === "string") {
126
126
  ipBuf = ipUtils.packIpLiteral(v);
@@ -144,15 +144,15 @@ function makeBuilder(ctx) {
144
144
  return b.namedBitString(positions);
145
145
  }
146
146
  // Resolve an OID token to a dotted-decimal OID: a registered name via the registry, OR a raw dotted-OID
147
- // string accepted directly (an unregistered KeyPurposeId / policy OID -- BIMI, document-signing, vendor
148
- // purposes -- is a common valid input). A token that is neither fails closed (never silently accept a
147
+ // string accepted directly (an unregistered KeyPurposeId / policy OID for BIMI, document-signing or a
148
+ // vendor purpose is a common valid input). A token that is neither fails closed (never silently accept a
149
149
  // typo'd name); a dotted string that passes the shape check is still arc-validated by b.oid's encoder.
150
150
  function _resolveOid(n, label) {
151
151
  var dotted = O(n);
152
152
  if (dotted != null) return dotted;
153
153
  if (typeof n === "string" && DOTTED_OID_RE.test(n)) {
154
154
  // The regex fixes the general shape; b.oid's encoder is the authoritative X.660 arc-bounds check
155
- // (a first arc 0/1 caps the second at 39; an arc must DER-encode). A failure there is THIS producer's
155
+ // (a first arc 0/1 caps the second at 39; an arc must DER-encode). A failure there is this producer's
156
156
  // bad-input, not a leaked oid/* code, so every shared-builder consumer keeps its own error contract.
157
157
  try { b.oid(n); }
158
158
  catch (e) { throw E("bad-input", "invalid " + label + " OID " + JSON.stringify(n) + " (violates the X.660 arc bounds)", e); }
@@ -184,7 +184,7 @@ function makeBuilder(ctx) {
184
184
  function extAki(keyid) { return b.sequence([b.contextPrimitive(0, keyid)]); } // keyIdentifier [0] IMPLICIT OCTET STRING
185
185
  // GeneralNames ::= SEQUENCE SIZE(1..MAX) OF GeneralName. With no implicitTag it is a universal SEQUENCE
186
186
  // (subjectAltName / issuerAltName / IssuerSerial.issuer). With an implicitTag it is a context-constructed
187
- // [n] whose tag REPLACES the SEQUENCE tag (RFC 5755 IMPLICIT TAGS -- Holder.entityName [1],
187
+ // [n] whose tag REPLACES the SEQUENCE tag (RFC 5755 IMPLICIT TAGS: Holder.entityName [1],
188
188
  // RoleSyntax.roleAuthority [0], IetfAttrSyntax.policyAuthority [0]); the [n] node's children ARE the
189
189
  // GeneralName members, no inner SEQUENCE wrapper.
190
190
  function encodeGeneralNames(entries, implicitTag) {
@@ -213,7 +213,8 @@ function makeBuilder(ctx) {
213
213
  }
214
214
 
215
215
  // The SHA-1 subjectKeyIdentifier (RFC 5280 sec. 4.2.1.2 method 1): SHA-1 of the subjectPublicKey BIT
216
- // STRING CONTENT (past the unused-bits octet), NOT the whole SPKI or the BIT STRING TLV.
216
+ // STRING content, taken past the unused-bits octet. Hashing the whole SPKI or the BIT STRING TLV
217
+ // gives a different, wrong identifier.
217
218
  function spkiKeyId(spkiDer) {
218
219
  var keyBytes = asn1.read.bitString(asn1.decode(spkiDer).children[1]).bytes;
219
220
  // RFC 5280 sec. 4.2.1.2 method 1 DEFINES the subjectKeyIdentifier as the SHA-1 of the
@@ -233,7 +234,7 @@ function makeBuilder(ctx) {
233
234
  if (Buffer.isBuffer(v) || v instanceof Uint8Array) return guard.bytes.snapshot(v, ErrorClass, ctx.prefix + "/bad-input", what);
234
235
  throw E("bad-input", what + " must be a DER Buffer");
235
236
  }
236
- // Full validation of an embedded SubjectPublicKeyInfo via the SAME parser the decoder uses.
237
+ // Full validation of an embedded SubjectPublicKeyInfo, walked through the parser the decoder uses.
237
238
  function assertValidSpki(spkiDer, what) {
238
239
  var node;
239
240
  try { node = asn1.decode(spkiDer); }
@@ -344,10 +345,11 @@ function makeBuilder(ctx) {
344
345
  return { subjectPublicKeyInfo: { algorithm: { oid: keyOid, parameters: alg.children.length > 1 ? alg.children[1].bytes : undefined } } };
345
346
  }
346
347
 
347
- // Confirm the produced signature verifies under `spki` -- key-type-agnostic (a PKCS#8 key, a WebCrypto
348
- // CryptoKey, or any signer), where deriving-and-comparing the public key cannot (a non-extractable
349
- // CryptoKey has no exportable public half). This is the x509 chain self-check AND the CSR proof of
350
- // possession. Composite verifies both components. Returns a promise for composite, sync-throws for classical.
348
+ // Confirm the produced signature verifies under `spki`. This works for any key type (a PKCS#8
349
+ // key, a WebCrypto CryptoKey, or any signer), where deriving-and-comparing the public key cannot
350
+ // (a non-extractable CryptoKey has no exportable public half). This is the x509 chain self-check
351
+ // AND the CSR proof of possession. Composite verifies both components. Returns a promise for
352
+ // composite, sync-throws for classical.
351
353
  function assertSignatureVerifies(preimage, sig, spki, scheme) {
352
354
  if (scheme.composite) {
353
355
  return compositeSig.compositeVerify(spki, sig, preimage, scheme.composite, ErrorClass, code("unsupported-algorithm"), code("bad-input")).then(function (r) {
@@ -394,11 +396,11 @@ function tbsNameField(cert, which) {
394
396
  return tbs.children[(hasVersion ? 1 : 0) + (which === "subject" ? 4 : 2)].bytes;
395
397
  }
396
398
 
397
- // The serialNumber of a parsed X.509 certificate, read from the SIGNED bytes rather than off the
398
- // object. Same tbs layout as above, and the same reason: where a producer binds an identity to an
399
- // existing certificate, that identity is issuer AND serial together. Deriving one from the bytes
400
- // and reading the other from the object lets the halves name different certificates -- a Holder
401
- // whose issuer is genuine and whose serial is whatever the caller wrote.
399
+ // The serialNumber of a parsed X.509 certificate, read from the SIGNED bytes. Same tbs layout as
400
+ // above, and the same reason: where a producer binds an identity to an existing certificate, that
401
+ // identity is issuer AND serial together. Deriving one from the bytes and reading the other from
402
+ // the object lets the halves name different certificates, producing a Holder whose issuer is
403
+ // genuine and whose serial is whatever the caller wrote.
402
404
  function tbsSerialNumber(cert) {
403
405
  var tbs = asn1.decode(cert.tbsBytes);
404
406
  var hasVersion = tbs.children[0].tagClass === "context" && tbs.children[0].tagNumber === 0;
package/lib/rc2.js CHANGED
@@ -8,7 +8,7 @@
8
8
  //
9
9
  // rc2 -- a from-scratch RFC 2268 RC2-CBC. OpenSSL 3.x moved RC2 to the legacy provider (not loaded by Node),
10
10
  // so node:crypto cannot decrypt these bags; this in-tree primitive fills that single gap (Hard rule #1: own
11
- // code, no npm hop -- MANIFEST stays empty; a lib primitive like webcrypto.js, not a lib/vendor/ bundle). The
11
+ // code, no npm hop, so MANIFEST stays empty; it is a lib primitive alongside webcrypto.js, outside lib/vendor/). The
12
12
  // RFC 2268 sec. 5 known-answer vectors pin the cipher; the `openssl -legacy` store is the end-to-end KAT.
13
13
 
14
14
  // RFC 2268 sec. 2: PITABLE, a fixed 256-byte permutation of the digits of pi used by the key schedule.
package/lib/rfc3339.js CHANGED
@@ -41,13 +41,13 @@ function parse(v, E, code, label) {
41
41
  return new Date(v);
42
42
  }
43
43
 
44
- // RFC 3339 sec. 5.6 `full-date`: a calendar date with NO time component. A distinct production from
45
- // the date-time above, and deliberately a separate pair of functions rather than a flag: a consumer
44
+ // RFC 3339 sec. 5.6 `full-date`: a calendar date with no time component. A distinct production from
45
+ // the date-time above, and deliberately a separate pair of functions instead of a flag: a consumer
46
46
  // that expects one and is handed the other has a malformed value, not a permissible variant.
47
47
  var FULL_DATE_RE = /^(\d{4})-(\d{2})-(\d{2})$/;
48
48
 
49
49
  // isValidDate(v) -> boolean: v is a syntactically well-formed AND calendar-valid RFC 3339 full-date.
50
- // Calendar validity matters as much as shape -- "2021-02-30" parses as a Date in JS by rolling over
50
+ // Calendar validity matters as much as shape: "2021-02-30" parses as a Date in JS by rolling over
51
51
  // into March, so a shape-only check would silently accept a day that does not exist.
52
52
  function isValidDate(v) {
53
53
  if (typeof v !== "string") return false;
@@ -61,8 +61,8 @@ function isValidDate(v) {
61
61
  }
62
62
 
63
63
  // parseDate(v, E, code, label) -> Date at UTC midnight. Anchored explicitly at UTC ("T00:00:00Z")
64
- // rather than left to `new Date("YYYY-MM-DD")`, so the instant does not shift with the host time
65
- // zone -- a freshness or rollback comparison must not depend on where it runs.
64
+ // instead of left to `new Date("YYYY-MM-DD")`, so the instant does not shift with the host time
65
+ // zone. A freshness or rollback comparison must not depend on where it runs.
66
66
  function parseDate(v, E, code, label) {
67
67
  if (!isValidDate(v)) throw E(code, (label || "the value") + " is not a valid RFC 3339 full-date (YYYY-MM-DD)");
68
68
  return new Date(v + "T00:00:00Z");