@blamejs/pki 0.8.59 → 0.8.61

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/lib/acme.js +15 -7
  3. package/lib/alt-sig.js +3 -1
  4. package/lib/asn1-der.js +82 -34
  5. package/lib/attrcert-sign.js +19 -16
  6. package/lib/byte-writer.js +63 -13
  7. package/lib/cbor-det.js +9 -3
  8. package/lib/cmc-build.js +26 -18
  9. package/lib/cmp-build.js +35 -33
  10. package/lib/cmp-session.js +19 -9
  11. package/lib/cms-decrypt.js +37 -23
  12. package/lib/cms-digest.js +2 -3
  13. package/lib/cms-encrypt.js +38 -33
  14. package/lib/cms-sign.js +65 -43
  15. package/lib/cms-verify.js +8 -4
  16. package/lib/composite-kem.js +28 -29
  17. package/lib/crl-sign.js +24 -17
  18. package/lib/crmf-sign.js +11 -17
  19. package/lib/csr-sign.js +5 -2
  20. package/lib/ct.js +38 -25
  21. package/lib/est.js +12 -9
  22. package/lib/guard-bytes.js +5 -1
  23. package/lib/guard-crypto.js +506 -14
  24. package/lib/guard-der.js +6 -1
  25. package/lib/guard-intrinsic.js +12 -4
  26. package/lib/guard-list.js +64 -0
  27. package/lib/guard-name.js +1 -1
  28. package/lib/guard-secret.js +3 -2
  29. package/lib/hpke.js +34 -27
  30. package/lib/http-digest.js +5 -7
  31. package/lib/http-transport.js +12 -3
  32. package/lib/inspect.js +10 -2
  33. package/lib/jose.js +3 -1
  34. package/lib/key.js +41 -29
  35. package/lib/lint.js +236 -152
  36. package/lib/mime.js +9 -5
  37. package/lib/ocsp.js +26 -24
  38. package/lib/path-validate.js +43 -13
  39. package/lib/pbes2.js +12 -9
  40. package/lib/pkcs11-uri.js +3 -1
  41. package/lib/pkcs12-build.js +19 -17
  42. package/lib/pki-build.js +17 -13
  43. package/lib/possession.js +3 -1
  44. package/lib/rc2.js +6 -2
  45. package/lib/revocation-fetch.js +78 -19
  46. package/lib/scep.js +21 -14
  47. package/lib/schema-attrcert.js +4 -2
  48. package/lib/schema-c509.js +94 -78
  49. package/lib/schema-cmc.js +5 -2
  50. package/lib/schema-cmp.js +6 -3
  51. package/lib/schema-cms.js +7 -4
  52. package/lib/schema-crl.js +1 -1
  53. package/lib/schema-crmf.js +1 -1
  54. package/lib/schema-csr.js +3 -3
  55. package/lib/schema-engine.js +36 -18
  56. package/lib/schema-pkcs1.js +7 -3
  57. package/lib/schema-pkcs12.js +9 -6
  58. package/lib/schema-pkix.js +19 -3
  59. package/lib/schema-sec1.js +4 -1
  60. package/lib/schema-tsp.js +7 -4
  61. package/lib/shbs.js +10 -9
  62. package/lib/sign-scheme.js +2 -2
  63. package/lib/sigstore.js +9 -9
  64. package/lib/smime.js +19 -16
  65. package/lib/tlog.js +20 -13
  66. package/lib/tuf.js +7 -4
  67. package/lib/validator-cose.js +2 -2
  68. package/lib/validator-keydesc.js +4 -1
  69. package/lib/validator-tls.js +7 -2
  70. package/lib/webauthn-mds.js +3 -7
  71. package/lib/webauthn.js +4 -11
  72. package/lib/webcrypto.js +70 -49
  73. package/lib/x509-sign.js +20 -15
  74. package/package.json +1 -1
  75. package/sbom.cdx.json +6 -6
@@ -4,7 +4,6 @@
4
4
  // @internal
5
5
  // @primitive pki.cms.encrypt block live in cms-verify.js, which re-exports this function (the
6
6
 
7
- var nodeCrypto = require("crypto");
8
7
  var asn1 = require("./asn1-der");
9
8
  var pkiBuild = require("./pki-build");
10
9
  var oid = require("./oid");
@@ -14,6 +13,10 @@ var webcrypto = require("./webcrypto");
14
13
  var frameworkError = require("./framework-error");
15
14
  var guard = require("./guard-all");
16
15
  var intrinsic = require("./guard-intrinsic");
16
+ /** @internal The append every list here is built with: `push` stores at the index and a store
17
+ * consults a setter inherited there. These lists become a recipient info and the key-derivation
18
+ * input beside it. */
19
+ var _push = intrinsic.append;
17
20
  var pbes2 = require("./pbes2");
18
21
  var compositeKem = require("./composite-kem");
19
22
  var b = asn1.build;
@@ -66,7 +69,7 @@ function _wrapOidForKek(keyBytes) {
66
69
 
67
70
  function _gcmParams(nonce, icvLen) {
68
71
  var kids = [b.octetString(nonce)];
69
- if (icvLen !== 12) kids.push(b.integer(BigInt(icvLen)));
72
+ if (icvLen !== 12) _push(kids,b.integer(BigInt(icvLen)));
70
73
  return b.sequence(kids);
71
74
  }
72
75
 
@@ -124,12 +127,12 @@ MONT_KA[O("X448")] = { name: "X448", hkdf: "SHA-512", scheme: "dhSinglePass-stdD
124
127
 
125
128
  function _eccSharedInfo(wrapName, ukm, kekBytes) {
126
129
  var kids = [_algId(wrapName, "absent")];
127
- if (ukm) kids.push(b.explicit(0, b.octetString(ukm)));
130
+ if (ukm) _push(kids,b.explicit(0, b.octetString(ukm)));
128
131
  /** @internal The SuppPubInfo key length is written with the capture. It is KDF input, so it is part
129
132
  * of what the key-encryption key derives from, and a replaced write derives a different KEK from
130
133
  * the same shared secret. */
131
134
  var supp = Buffer.alloc(4); intrinsic.writeUInt32BE(supp, kekBytes * 8, 0);
132
- kids.push(b.explicit(2, b.octetString(supp)));
135
+ _push(kids,b.explicit(2, b.octetString(supp)));
133
136
  return b.sequence(kids);
134
137
  }
135
138
  async function _buildKari(cek, cert, opts) {
@@ -179,8 +182,9 @@ async function _buildKari(cek, cert, opts) {
179
182
  var rek = b.sequence([b.sequence([ridNode, b.octetString(encryptedKey)])]);
180
183
  var kekAlg = b.sequence([b.oid(O(origKeyAlgId.scheme)), _algId(wrapName, "absent")]);
181
184
  var kariKids = [b.integer(3n), b.explicit(0, originatorKey)];
182
- if (ukm) kariKids.push(b.explicit(1, b.octetString(ukm)));
183
- kariKids.push(kekAlg, rek);
185
+ if (ukm) _push(kariKids,b.explicit(1, b.octetString(ukm)));
186
+ _push(kariKids,kekAlg);
187
+ _push(kariKids,rek);
184
188
  return { tag: 1, node: b.sequence(kariKids) };
185
189
  } finally {
186
190
  guard.secret.zeroizeAll([z, mz, kek], CmsError, "cms/bad-input", "the key-agreement shared secret");
@@ -198,7 +202,7 @@ async function _buildKekri(cek, desc) {
198
202
 
199
203
  async function _buildPwri(cek, desc) {
200
204
  var iterations = pbes2.assertIterations(desc.iterations == null ? 600000 : desc.iterations, _err, "cms");
201
- var salt = desc.salt ? pbes2.assertSalt(guard.bytes.view(desc.salt, CmsError, "cms/bad-input", "salt"), _err, "cms") : nodeCrypto.randomBytes(16);
205
+ var salt = desc.salt ? pbes2.assertSalt(guard.bytes.view(desc.salt, CmsError, "cms/bad-input", "salt"), _err, "cms") : guard.crypto.randomBytes(16);
202
206
  var prf = desc.prf || "hmacWithSHA256";
203
207
  _prfHash(prf);
204
208
  var innerKeyBytes = 32;
@@ -208,7 +212,7 @@ async function _buildPwri(cek, desc) {
208
212
  var kek = Buffer.from(await subtle.deriveBits({ name: "PBKDF2", hash: _prfHash(prf), salt: salt, iterations: iterations }, kekKey, innerKeyBytes * 8));
209
213
  if (pwOwn.owned) guard.secret.zeroize(password, CmsError, "cms/bad-input", "the password encoding");
210
214
  try {
211
- var iv = nodeCrypto.randomBytes(16);
215
+ var iv = guard.crypto.randomBytes(16);
212
216
  var encryptedKey = _pwriWrapIv(kek, cek, iv);
213
217
  var kdfParams = pbes2.pbkdf2ParamsSeq(salt, iterations, prf);
214
218
  var kdfAlg = b.contextConstructed(0, Buffer.concat([b.oid(O("pbkdf2")), kdfParams]));
@@ -227,7 +231,7 @@ var KEM_WC = intrinsic.create(null); KEM_WC[O("id-ml-kem-512")] = "ML-KEM-512";
227
231
 
228
232
  function _kemOtherInfo(wrapName, kekBytes, ukm) {
229
233
  var kids = [_algId(wrapName, "absent"), b.integer(BigInt(kekBytes))];
230
- if (ukm) kids.push(b.explicit(0, b.octetString(ukm)));
234
+ if (ukm) _push(kids,b.explicit(0, b.octetString(ukm)));
231
235
  return b.sequence(kids);
232
236
  }
233
237
  async function _kemEncapsulate(keyOid, cert) {
@@ -258,8 +262,9 @@ async function _buildKemri(cek, cert, opts) {
258
262
  var encryptedKey = await _aesKwWrap(kek, cek);
259
263
  var rid = _rid(cert, opts.keyIdentifier);
260
264
  var kemriKids = [b.integer(0n), rid.node, _algId(oid.name(keyOid), "absent"), b.octetString(kemct), _algId("hkdfWithSha256", "absent"), b.integer(BigInt(kekBytes))];
261
- if (ukm) kemriKids.push(b.explicit(0, b.octetString(ukm)));
262
- kemriKids.push(_algId(wrapName, "absent"), b.octetString(encryptedKey));
265
+ if (ukm) _push(kemriKids,b.explicit(0, b.octetString(ukm)));
266
+ _push(kemriKids,_algId(wrapName, "absent"));
267
+ _push(kemriKids,b.octetString(encryptedKey));
263
268
  var kemri = b.sequence(kemriKids);
264
269
  return { tag: 4, node: b.sequence([b.oid(O("kem")), kemri]) };
265
270
  } finally {
@@ -282,17 +287,17 @@ function _pwriFormat(cek) {
282
287
  var blk = 16;
283
288
  var padLen = body.length % blk === 0 ? 0 : blk - (body.length % blk);
284
289
  if (body.length + padLen < 2 * blk) padLen += (2 * blk - (body.length + padLen));
285
- var wrapped = Buffer.concat([body, nodeCrypto.randomBytes(padLen)]);
290
+ var wrapped = Buffer.concat([body, guard.crypto.randomBytes(padLen)]);
286
291
  guard.secret.zeroizeAll([check, body], CmsError, "cms/bad-input", "a PWRI formatting intermediate");
287
292
  return wrapped;
288
293
  }
289
294
  function _pwriWrapIv(kek, cek, iv) {
290
295
  var wk = _pwriFormat(cek);
291
296
  try {
292
- var c1 = nodeCrypto.createCipheriv("aes-256-cbc", kek, iv); c1.setAutoPadding(false);
297
+ var c1 = guard.crypto.cipher("aes-256-cbc", kek, iv); guard.crypto.transformNoPadding(c1);
293
298
  var pass1 = guard.secret.cipherFinish(c1, wk, CmsError, "cms/bad-input", "the PWRI first-pass ciphertext");
294
299
  var iv2 = pass1.subarray(pass1.length - 16);
295
- var c2 = nodeCrypto.createCipheriv("aes-256-cbc", kek, iv2); c2.setAutoPadding(false);
300
+ var c2 = guard.crypto.cipher("aes-256-cbc", kek, iv2); guard.crypto.transformNoPadding(c2);
296
301
  return guard.secret.cipherFinish(c2, pass1, CmsError, "cms/bad-input", "the PWRI wrapped key");
297
302
  } finally {
298
303
  guard.secret.zeroize(wk, CmsError, "cms/bad-input", "the PWRI plaintext block");
@@ -438,7 +443,7 @@ async function _encryptImpl(content, recipients, opts) {
438
443
  * them. */
439
444
  var contentBytes = contentStream ? null : guard.bytes.view(content, CmsError, "cms/bad-input", "content");
440
445
  var contentType = opts.contentType || "data";
441
- var cek = nodeCrypto.randomBytes(ca.keyBits / 8);
446
+ var cek = guard.crypto.randomBytes(ca.keyBits / 8);
442
447
 
443
448
  try {
444
449
  if (!Array.isArray(recipients)) return await _encryptedData(contentBytes, contentStream, recipients, ca, contentType, opts, cek);
@@ -446,7 +451,7 @@ async function _encryptImpl(content, recipients, opts) {
446
451
  if (!recipients.length) throw _err("cms/bad-input", "at least one recipient is required (RFC 5652 sec. 6.1)");
447
452
  var recips = [];
448
453
  var consumed = intrinsic.create(null);
449
- for (var i = 0; i < recipients.length; i++) recips.push(await _buildRecipient(cek, recipients[i], opts, consumed));
454
+ for (var i = 0; i < recipients.length; i++) _push(recips,await _buildRecipient(cek, recipients[i], opts, consumed));
450
455
  _assertDefaultsConsumed(opts, consumed);
451
456
  var riNodes = recips.map(_taggedRecipient);
452
457
 
@@ -471,7 +476,7 @@ async function _encStream(spec, stream) {
471
476
  }
472
477
 
473
478
  async function _envelopedData(contentBytes, contentStream, cek, ca, contentType, riNodes, recips) {
474
- var iv = nodeCrypto.randomBytes(16);
479
+ var iv = guard.crypto.randomBytes(16);
475
480
  var enc = contentStream
476
481
  ? (await _encStream({ algNode: "aes-" + ca.keyBits + "-cbc", key: cek, iv: iv }, contentStream)).ciphertext
477
482
  : pbes2.cbcEncrypt(cek, iv, contentBytes, ca.keyBits, CmsError, "cms/bad-input");
@@ -516,7 +521,7 @@ var AUTH_ENVELOPED_FORBIDDEN = intrinsic.assign(intrinsic.create(null), {
516
521
  });
517
522
 
518
523
  async function _authEnvelopedData(contentBytes, contentStream, cek, ca, contentType, opts, riNodes, recips) {
519
- var nonce = nodeCrypto.randomBytes(12);
524
+ var nonce = guard.crypto.randomBytes(12);
520
525
  var authAttrsDer = null, aad = Buffer.alloc(0);
521
526
  if (contentType !== "data" && !(opts.authAttrs && opts.authAttrs.length)) {
522
527
  throw _err("cms/bad-input", "AuthEnvelopedData with a non-data contentType requires authAttrs (RFC 5083 sec. 2.1)");
@@ -535,8 +540,8 @@ async function _authEnvelopedData(contentBytes, contentStream, cek, ca, contentT
535
540
  }
536
541
  var eci = b.sequence([b.oid(O(contentType)), b.sequence([b.oid(O(ca.oid)), _gcmParams(nonce, 16)]), b.contextPrimitive(0, g.ct)]);
537
542
  var kids = [b.integer(0n), b.setOf(riNodes), eci];
538
- if (authAttrsDer) kids.push(authAttrsDer);
539
- kids.push(b.octetString(g.tag));
543
+ if (authAttrsDer) _push(kids,authAttrsDer);
544
+ _push(kids,b.octetString(g.tag));
540
545
  void recips;
541
546
  return b.sequence(kids);
542
547
  }
@@ -555,7 +560,7 @@ async function _encryptedData(contentBytes, contentStream, desc, ca, contentType
555
560
  " EncryptedData descriptor; that field is not read for this arm";
556
561
  });
557
562
  }
558
- var iv = nodeCrypto.randomBytes(16);
563
+ var iv = guard.crypto.randomBytes(16);
559
564
  var contentAlgNode, encKey;
560
565
  if (desc && desc.cek != null) {
561
566
  encKey = guard.bytes.view(desc.cek, CmsError, "cms/bad-input", "cek");
@@ -578,9 +583,9 @@ async function _encryptedDataPbes2(contentBytes, contentStream, desc, ca, conten
578
583
  var pwOwn2 = pbes2.passwordBytesOwned(desc.password, _err, "cms");
579
584
  var password = pwOwn2.bytes;
580
585
  var iterations = pbes2.assertIterations(desc.iterations == null ? 600000 : desc.iterations, _err, "cms");
581
- var salt = desc.salt ? pbes2.assertSalt(guard.bytes.view(desc.salt, CmsError, "cms/bad-input", "salt"), _err, "cms") : nodeCrypto.randomBytes(16);
586
+ var salt = desc.salt ? pbes2.assertSalt(guard.bytes.view(desc.salt, CmsError, "cms/bad-input", "salt"), _err, "cms") : guard.crypto.randomBytes(16);
582
587
  var prf = desc.prf || "hmacWithSHA256";
583
- var key = nodeCrypto.pbkdf2Sync(password, salt, iterations, ca.keyBits / 8, pbes2.prfNodeByName(prf, _err, "cms"));
588
+ var key = guard.crypto.pbkdf2(password, salt, iterations, ca.keyBits / 8, pbes2.prfNodeByName(prf, _err, "cms"));
584
589
  if (pwOwn2.owned) guard.secret.zeroize(password, CmsError, "cms/bad-input", "the password encoding");
585
590
  try {
586
591
  var enc = contentStream
@@ -596,10 +601,10 @@ async function _encryptedDataPbes2(contentBytes, contentStream, desc, ca, conten
596
601
  }
597
602
 
598
603
  function _gcmEncrypt(key, nonce, plaintext, aad, keyBits, tagLen) {
599
- var c = nodeCrypto.createCipheriv("aes-" + keyBits + "-gcm", key, nonce, { authTagLength: tagLen });
600
- if (aad && aad.length) c.setAAD(aad);
604
+ var c = guard.crypto.cipher("aes-" + keyBits + "-gcm", key, nonce, { authTagLength: tagLen });
605
+ if (aad && aad.length) guard.crypto.transformSetAAD(c, aad);
601
606
  var ct = guard.secret.cipherFinish(c, plaintext, CmsError, "cms/bad-input", "a content-encryption intermediate");
602
- return { ct: ct, tag: c.getAuthTag() };
607
+ return { ct: ct, tag: guard.crypto.cipherAuthTag(c) };
603
608
  }
604
609
 
605
610
  function _tlvHeaderLen(der) {
@@ -676,11 +681,11 @@ async function _authenticateImpl(content, recipients, opts) {
676
681
  var contentType = opts.contentType || "data";
677
682
  if (contentType !== "data" && !withAttrs) throw _err("cms/bad-input", "AuthenticatedData with a non-data contentType requires authenticated attributes (RFC 5652 sec. 9.1)");
678
683
 
679
- var macKey = nodeCrypto.randomBytes(MAC_KEY_OCTETS);
684
+ var macKey = guard.crypto.randomBytes(MAC_KEY_OCTETS);
680
685
  try {
681
686
  var recips = [];
682
687
  var consumedAuth = {};
683
- for (var i = 0; i < recipients.length; i++) recips.push(await _buildRecipient(macKey, recipients[i], opts, consumedAuth));
688
+ for (var i = 0; i < recipients.length; i++) _push(recips,await _buildRecipient(macKey, recipients[i], opts, consumedAuth));
684
689
  _assertDefaultsConsumed(opts, consumedAuth);
685
690
  var riNodes = recips.map(_taggedRecipient);
686
691
 
@@ -705,7 +710,7 @@ async function _authenticateImpl(content, recipients, opts) {
705
710
  * MAC algorithm substitution attack, which is difficult because the attacker does not know
706
711
  * the authentication key". Built from the same values the two outer fields are built from. */
707
712
  if (protectionOid) {
708
- intrinsic.push(pairs, b.sequence([
713
+ intrinsic.append(pairs, b.sequence([
709
714
  b.oid(protectionOid),
710
715
  b.setOf([b.sequence([_algId(digestName), b.implicit(2, _algId(mac.oid))])]),
711
716
  ]));
@@ -732,10 +737,10 @@ async function _authenticateImpl(content, recipients, opts) {
732
737
 
733
738
  var eci = b.sequence([b.oid(O(contentType)), b.explicit(0, b.octetString(contentBytes))]);
734
739
  var kids = [b.integer(0n), b.setOf(riNodes), _algId(mac.oid)];
735
- if (digestAlgTagged) kids.push(digestAlgTagged);
736
- kids.push(eci);
737
- if (authAttrsDer) kids.push(authAttrsDer);
738
- kids.push(b.octetString(macValue));
740
+ if (digestAlgTagged) _push(kids,digestAlgTagged);
741
+ _push(kids,eci);
742
+ if (authAttrsDer) _push(kids,authAttrsDer);
743
+ _push(kids,b.octetString(macValue));
739
744
  var ci = b.sequence([b.oid(O("authData")), b.explicit(0, b.sequence(kids))]);
740
745
  try { schemaCms.parse(ci); } catch (e) { throw (e instanceof CmsError) ? e : _err("cms/bad-input", "the supplied authenticated attributes produced an invalid AuthenticatedData", e); }
741
746
  return opts.pem ? schemaCms.pemEncode(ci, "CMS") : ci;
package/lib/cms-sign.js CHANGED
@@ -15,6 +15,12 @@ var webcrypto = require("./webcrypto");
15
15
  var signScheme = require("./sign-scheme");
16
16
  var guard = require("./guard-all");
17
17
  var intrinsic = require("./guard-intrinsic");
18
+ /** @internal `append`, not a captured `push`: appending with `push` STORES at the index, and a store
19
+ * walks the prototype chain for a setter, so an accessor installed at an array index receives each
20
+ * element as it is appended and can define something else in its place. The lists built here become
21
+ * a message's signed attributes, its certificate set and its signer infos. `append` defines the
22
+ * index on the array itself. */
23
+ var _push = intrinsic.append;
18
24
  /** @internal `resolve` and `all` build their promise from the RECEIVER, so reading the global binding
19
25
  * at the call hands the construction to whatever that binding holds. Each signer's digest and
20
26
  * signature are awaited through one of these, and a replacement that settles without awaiting emits a
@@ -73,7 +79,11 @@ function _digest(digestName, content) {
73
79
 
74
80
 
75
81
  function _skiValue(cert) {
76
- var ext = (cert.extensions || []).filter(function (e) { return e.oid === OID_SKI; })[0];
82
+ /** @internal The selection returns the first matching row or null, because `filter(...)[0]` indexes
83
+ * a result that is EMPTY when the extension is absent, and index 0 of an empty array answers from
84
+ * the array prototype: the refusal below would then not be reached for a certificate that carries
85
+ * no SKI. */
86
+ var ext = guard.list.firstMatch(cert.extensions || [], function (e) { return e.oid === OID_SKI; });
77
87
  if (!ext) throw _err("cms/no-ski", "a subjectKeyIdentifier signer identifier requires the signer certificate to carry an SKI extension");
78
88
  try { return asn1.read.octetString(asn1.decode(ext.value)); }
79
89
  catch (e) { throw _err("cms/no-ski", "the signer certificate's subjectKeyIdentifier extension value is not an OCTET STRING", e); }
@@ -216,10 +226,10 @@ async function _finishSignerInfo(rc, md, content, eContentType, opts) {
216
226
  { type: O("contentType"), values: [b.oid(eContentType)] },
217
227
  { type: O("messageDigest"), values: [b.octetString(md)] },
218
228
  ];
219
- if (opts.signingTime !== false) intrinsic.push(pairs, { type: O("signingTime"), values: [_timeValue(opts.signingTime)] });
229
+ if (opts.signingTime !== false) _push(pairs, { type: O("signingTime"), values: [_timeValue(opts.signingTime)] });
220
230
  var apOid = cms.algorithmProtectionOid(opts.algorithmProtection, _err);
221
231
  if (apOid) {
222
- intrinsic.push(pairs, _algorithmProtectionPair(apOid,
232
+ _push(pairs, _algorithmProtectionPair(apOid,
223
233
  rc.scheme.digestAlgId, rc.scheme.sigAlgId, 1));
224
234
  }
225
235
  pairs = intrinsic.concat(pairs, _resolveAttrPairs(opts.additionalSignedAttributes, "a signed attribute value"));
@@ -230,10 +240,13 @@ async function _finishSignerInfo(rc, md, content, eContentType, opts) {
230
240
  var sig = await signScheme.signOverTbs(rc.scheme, rc.soKey, signedBytes, _signE);
231
241
  await _assertKeyMatchesSpki(rc.keyOnly, rc.soKey, rc.soSpki, rc.scheme, sig, signedBytes, rc.cert);
232
242
  var fields = [b.integer(BigInt(rc.version)), rc.sid, rc.scheme.digestAlgId];
233
- if (toSign.wire) intrinsic.push(fields, toSign.wire);
234
- intrinsic.push(fields, rc.scheme.sigAlgId, b.octetString(sig));
243
+ if (toSign.wire) _push(fields, toSign.wire);
244
+ /** @internal Two appends, because `append` takes one value where `push` took many: the algorithm
245
+ * identifier and the signature it describes are adjacent fields of the same SignerInfo. */
246
+ _push(fields, rc.scheme.sigAlgId);
247
+ _push(fields, b.octetString(sig));
235
248
  var ua = _buildUnsignedAttrs(opts.unsignedAttributes);
236
- if (ua) intrinsic.push(fields, ua);
249
+ if (ua) _push(fields, ua);
237
250
  return { si: b.sequence(fields), digestAlgId: rc.scheme.digestAlgId, version: rc.version, certDer: rc.certDer };
238
251
  }
239
252
 
@@ -367,7 +380,7 @@ async function _signStream(stream, signers, opts) {
367
380
  if (opts.signingTime != null && opts.signingTime !== false) guard.time.assertEncodable(opts.signingTime, _err, "cms/bad-input", "signingTime");
368
381
  var rcs = intrinsic.map(list, function (s) { return _resolveSignerContext(s, opts); });
369
382
  var digestNames = [], seenDigest = intrinsic.create(null);
370
- intrinsic.forEach(rcs, function (r) { if (!seenDigest[r.scheme.digest]) { seenDigest[r.scheme.digest] = 1; intrinsic.push(digestNames, r.scheme.digest); } });
383
+ intrinsic.forEach(rcs, function (r) { if (!seenDigest[r.scheme.digest]) { seenDigest[r.scheme.digest] = 1; _push(digestNames, r.scheme.digest); } });
371
384
  var wcNames = intrinsic.map(digestNames, function (n) { return DIGEST_HASH[n]; });
372
385
  var digests;
373
386
  try {
@@ -379,7 +392,7 @@ async function _signStream(stream, signers, opts) {
379
392
  intrinsic.forEach(digestNames, function (n, i) { byName[n] = intrinsic.bufferFrom(digests[i]); });
380
393
  var built = [];
381
394
  for (var _ip = 0; _ip < rcs.length; _ip++) {
382
- intrinsic.push(built, await _finishSignerInfo(rcs[_ip], byName[rcs[_ip].scheme.digest], null, eContentType, opts));
395
+ _push(built, await _finishSignerInfo(rcs[_ip], byName[rcs[_ip].scheme.digest], null, eContentType, opts));
383
396
  }
384
397
  return _assembleSignedData(built, eContentType, opts, null);
385
398
  }
@@ -420,19 +433,19 @@ function _sign(content, signers, opts) {
420
433
 
421
434
  function _assembleSignedData(built, eContentType, opts, contentBuf) {
422
435
  var seen = intrinsic.create(null), digestAlgs = [];
423
- intrinsic.forEach(built, function (x) { var k = intrinsic.bufToString(x.digestAlgId, "hex"); if (!seen[k]) { seen[k] = 1; intrinsic.push(digestAlgs, x.digestAlgId); } });
436
+ intrinsic.forEach(built, function (x) { var k = intrinsic.bufToString(x.digestAlgId, "hex"); if (!seen[k]) { seen[k] = 1; _push(digestAlgs, x.digestAlgId); } });
424
437
  var v3 = intrinsic.some(built, function (x) { return x.version === 3; }) || eContentType !== OID_DATA;
425
438
  var version = v3 ? 3 : 1;
426
439
  var encapFields = [b.oid(eContentType)];
427
- if (!opts.detached) intrinsic.push(encapFields, b.explicit(0, b.octetString(contentBuf)));
440
+ if (!opts.detached) _push(encapFields, b.explicit(0, b.octetString(contentBuf)));
428
441
  var encap = b.sequence(encapFields);
429
442
  var sdFields = [b.integer(BigInt(version)), b.set(digestAlgs), encap];
430
443
  if (opts.certificates !== false) {
431
444
  var certDers = intrinsic.sort(_dedupe(intrinsic.filter(intrinsic.map(built, function (x) { return x.certDer; }),
432
445
  function (d) { return d != null; })), intrinsic.compare);
433
- if (certDers.length) intrinsic.push(sdFields, b.contextConstructed(0, intrinsic.bufferConcat(certDers)));
446
+ if (certDers.length) _push(sdFields, b.contextConstructed(0, intrinsic.bufferConcat(certDers)));
434
447
  }
435
- intrinsic.push(sdFields, b.set(intrinsic.map(built, function (x) { return x.si; })));
448
+ _push(sdFields, b.set(intrinsic.map(built, function (x) { return x.si; })));
436
449
  var signedData = b.sequence(sdFields);
437
450
  var contentInfo = b.sequence([b.oid(OID_SIGNED_DATA), b.explicit(0, signedData)]);
438
451
  return opts.pem ? pkix.pemEncode(contentInfo, "CMS", frameworkError.PemError) : contentInfo;
@@ -450,7 +463,7 @@ function _digestAlgIdentifier(der) {
450
463
 
451
464
  function _dedupe(ders) {
452
465
  var seen = intrinsic.create(null), out = [];
453
- intrinsic.forEach(ders, function (d) { var k = intrinsic.bufToString(d, "hex"); if (!seen[k]) { seen[k] = 1; intrinsic.push(out, d); } });
466
+ intrinsic.forEach(ders, function (d) { var k = intrinsic.bufToString(d, "hex"); if (!seen[k]) { seen[k] = 1; _push(out, d); } });
454
467
  return out;
455
468
  }
456
469
 
@@ -496,9 +509,9 @@ function certsOnly(certs, opts) {
496
509
  var crlDers = intrinsic.sort(_dedupe(intrinsic.map(crlList, function (c) { return _normEntityDer(c, "a CRL", "X509 CRL", _parseCrl); })), intrinsic.compare);
497
510
  var encap = b.sequence([b.oid(OID_DATA)]);
498
511
  var sdFields = [b.integer(1n), b.set([]), encap];
499
- if (certDers.length) intrinsic.push(sdFields, b.contextConstructed(0, intrinsic.bufferConcat(certDers)));
500
- if (crlDers.length) intrinsic.push(sdFields, b.contextConstructed(1, intrinsic.bufferConcat(crlDers)));
501
- intrinsic.push(sdFields, b.set([]));
512
+ if (certDers.length) _push(sdFields, b.contextConstructed(0, intrinsic.bufferConcat(certDers)));
513
+ if (crlDers.length) _push(sdFields, b.contextConstructed(1, intrinsic.bufferConcat(crlDers)));
514
+ _push(sdFields, b.set([]));
502
515
  var signedData = b.sequence(sdFields);
503
516
  var contentInfo = b.sequence([b.oid(OID_SIGNED_DATA), b.explicit(0, signedData)]);
504
517
  return opts.pem ? pkix.pemEncode(contentInfo, "CMS", frameworkError.PemError) : contentInfo;
@@ -512,7 +525,7 @@ function _toBuf(v, what) {
512
525
 
513
526
  function _resolveSignerIndices(spec, n) {
514
527
  if (spec == null) { if (n < 1) throw _err("cms/bad-input", "the SignedData carries no SignerInfo to countersign"); return [0]; }
515
- if (spec === "all") { var all = []; for (var i = 0; i < n; i++) all.push(i); return all; }
528
+ if (spec === "all") { var all = []; for (var i = 0; i < n; i++) _push(all, i); return all; }
516
529
  var arr = Array.isArray(spec) ? spec : [spec];
517
530
  if (!arr.length) throw _err("cms/bad-input", "signerIndex must select at least one signer");
518
531
  arr.forEach(function (i) { if (typeof i !== "number" || !Number.isInteger(i) || i < 0 || i >= n) throw _err("cms/bad-input", "signerIndex out of range: " + i); });
@@ -534,10 +547,10 @@ function _buildCountersignature(targetSigOctets, countersigner, opts) {
534
547
  if (opts.signedAttributes === false) return null;
535
548
  return intrinsic.chain(_digest(scheme.digest, targetSigOctets), function (md) {
536
549
  var pairs = [{ type: O("messageDigest"), values: [b.octetString(md)] }];
537
- if (opts.signingTime !== false) pairs.push({ type: O("signingTime"), values: [_timeValue(opts.signingTime)] });
550
+ if (opts.signingTime !== false) _push(pairs, { type: O("signingTime"), values: [_timeValue(opts.signingTime)] });
538
551
  var csApOid = cms.algorithmProtectionOid(opts.algorithmProtection, _err);
539
552
  if (csApOid) {
540
- intrinsic.push(pairs, _algorithmProtectionPair(csApOid, scheme.digestAlgId, scheme.sigAlgId, 1));
553
+ _push(pairs, _algorithmProtectionPair(csApOid, scheme.digestAlgId, scheme.sigAlgId, 1));
541
554
  }
542
555
  var extra = _resolveAttrPairs(opts.additionalSignedAttributes, "a countersignature signed attribute value");
543
556
  extra.forEach(function (p) { if (p.type === O("contentType")) throw _err("cms/bad-input", "a countersignature must not carry a content-type attribute (RFC 5652 sec. 11.4)"); });
@@ -556,8 +569,9 @@ function _buildCountersignature(targetSigOctets, countersigner, opts) {
556
569
  });
557
570
  return intrinsic.chain(selfChecked, function () {
558
571
  var fields = [b.integer(BigInt(sidv.version)), sidv.sid, scheme.digestAlgId];
559
- if (attrs) fields.push(attrs.wire);
560
- fields.push(scheme.sigAlgId, b.octetString(sig));
572
+ if (attrs) _push(fields, attrs.wire);
573
+ _push(fields, scheme.sigAlgId);
574
+ _push(fields, b.octetString(sig));
561
575
  return { value: b.sequence(fields), certDer: certDer, digestAlgId: scheme.digestAlgId };
562
576
  });
563
577
  });
@@ -568,13 +582,17 @@ function _mergeCountersig(uaNode, newCsValues) {
568
582
  var CS = O("countersignature");
569
583
  var others = [], csValues = [];
570
584
  if (uaNode) uaNode.children.forEach(function (attr) {
571
- if (asn1.read.oid(attr.children[0]) === CS) attr.children[1].children.forEach(function (v) { csValues.push(v.bytes); });
572
- else others.push(attr.bytes);
585
+ if (asn1.read.oid(attr.children[0]) === CS) intrinsic.forEach(attr.children[1].children, function (v) { _push(csValues, v.bytes); });
586
+ else _push(others, attr.bytes);
573
587
  });
574
- newCsValues.forEach(function (v) { csValues.push(v); });
588
+ intrinsic.forEach(newCsValues, function (v) { _push(csValues, v); });
575
589
  var csAttr = b.sequence([b.oid(CS), b.set(csValues)]);
576
- var setOf = b.set(others.concat([csAttr]));
577
- var wire = Buffer.from(setOf); wire[0] = 0xA1;
590
+ /** @internal `concatList`, not `concat`: `Array.prototype.concat` builds its result through the
591
+ * species constructor, so a species answering with a Proxy intercepted the countersignature
592
+ * attribute as it was inserted and the merged value went out without it. `concatList` copies own
593
+ * indexes into an array it made itself. */
594
+ var setOf = b.set(intrinsic.concatList(others, [csAttr]));
595
+ var wire = intrinsic.bufferFrom(setOf); wire[0] = 0xA1;
578
596
  return wire;
579
597
  }
580
598
 
@@ -583,7 +601,7 @@ function _appendCountersigs(siNode, newCsValues) {
583
601
  var last = kids[kids.length - 1];
584
602
  var hasUa = last.tagClass === "context" && last.tagNumber === 1;
585
603
  var base = (hasUa ? kids.slice(0, kids.length - 1) : kids).map(function (k) { return k.bytes; });
586
- base.push(_mergeCountersig(hasUa ? last : null, newCsValues));
604
+ _push(base, _mergeCountersig(hasUa ? last : null, newCsValues));
587
605
  return b.sequence(base);
588
606
  }
589
607
 
@@ -603,7 +621,7 @@ function _spliceNested(siNode, j, newCsValues) {
603
621
  if (!found) throw _err("cms/bad-input", "the target signer carries no countersignature to countersign");
604
622
  var setOf = b.set(attrs); var wire = Buffer.from(setOf); wire[0] = 0xA1;
605
623
  var base = kids.slice(0, kids.length - 1).map(function (k) { return k.bytes; });
606
- base.push(wire);
624
+ _push(base, wire);
607
625
  return b.sequence(base);
608
626
  }
609
627
 
@@ -619,7 +637,11 @@ function _targetPreimage(siNode, opts) {
619
637
  var last = siNode.children[siNode.children.length - 1];
620
638
  var CS = O("countersignature");
621
639
  if (!last || last.tagClass !== "context" || last.tagNumber !== 1) throw _err("cms/bad-input", "the target signer carries no countersignature to countersign");
622
- var attr = last.children.filter(function (a) { return asn1.read.oid(a.children[0]) === CS; })[0];
640
+ /** @internal The selection returns the first matching attribute or null, because `filter(...)[0]`
641
+ * indexes a result that is EMPTY when the signer carries no countersignature attribute, and index
642
+ * 0 of an empty array answers from the array prototype: the refusal below would then not be
643
+ * reached and the signature bytes would be taken from whatever the accessor answered with. */
644
+ var attr = guard.list.firstMatch(last.children, function (a) { return asn1.read.oid(a.children[0]) === CS; });
623
645
  if (!attr) throw _err("cms/bad-input", "the target signer carries no countersignature to countersign");
624
646
  var values = attr.children[1].children;
625
647
  var j = opts.countersignatureOf;
@@ -653,15 +675,15 @@ function _countersign(cmsInput, signers, opts) {
653
675
  var jobs = [];
654
676
  targets.forEach(function (t) {
655
677
  var preimage = _targetPreimage(siSet.children[t], opts);
656
- list.forEach(function (cs) { jobs.push({ t: t, p: _buildCountersignature(preimage, cs, opts) }); });
678
+ intrinsic.forEach(list, function (cs) { _push(jobs, { t: t, p: _buildCountersignature(preimage, cs, opts) }); });
657
679
  });
658
680
  return intrinsic.chain(intrinsic.allOf(intrinsic.mapList(jobs, function (j) { return j.p; })), function (built) {
659
681
  var byTarget = intrinsic.create(null), certDers = [], csDigestAlgs = [];
660
682
  intrinsic.forEach(built, function (res, i) {
661
683
  var slot = byTarget[jobs[i].t] || (byTarget[jobs[i].t] = []);
662
- intrinsic.push(slot, res.value);
663
- intrinsic.push(certDers, res.certDer);
664
- intrinsic.push(csDigestAlgs, res.digestAlgId);
684
+ _push(slot, res.value);
685
+ _push(certDers, res.certDer);
686
+ _push(csDigestAlgs, res.digestAlgId);
665
687
  });
666
688
 
667
689
  var newSiSet = b.set(siSet.children.map(function (siNode, idx) {
@@ -675,8 +697,8 @@ function _countersign(cmsInput, signers, opts) {
675
697
  else if (sdKids[i].tagClass === "context" && sdKids[i].tagNumber === 1) crlsNode = sdKids[i];
676
698
  }
677
699
  var existing = [];
678
- if (certsNode) certsNode.children.forEach(function (c) { existing.push(c.bytes); });
679
- if (opts.certificates !== false) certDers.forEach(function (d) { existing.push(d); });
700
+ if (certsNode) intrinsic.forEach(certsNode.children, function (c) { _push(existing, c.bytes); });
701
+ if (opts.certificates !== false) intrinsic.forEach(certDers, function (d) { _push(existing, d); });
680
702
  /** @internal The DER SET ordering through the captured copy, sort AND comparator: read off its own
681
703
  * home, any of the three decides which certificate lands where in the set this message carries. */
682
704
  var allCerts = guard.list.sortedCopy(_dedupe(existing), intrinsic.compare);
@@ -693,20 +715,20 @@ function _countersign(cmsInput, signers, opts) {
693
715
  * comparison would list it a second time. */
694
716
  var listed = [];
695
717
  intrinsic.forEach(intrinsic.isArray(parsed.digestAlgorithms) ? parsed.digestAlgorithms : [],
696
- function (a) { intrinsic.push(listed, a); });
718
+ function (a) { _push(listed, a); });
697
719
  var digestAlgs = intrinsic.map(sdKids[1].children, function (d) { return d.bytes; });
698
720
  intrinsic.forEach(csDigestAlgs, function (der) {
699
721
  var info = _digestAlgIdentifier(der);
700
722
  var already = false;
701
723
  intrinsic.forEach(listed, function (alg) { if (cms.sameDigestAlgorithm(alg, info)) already = true; });
702
724
  if (already) return;
703
- intrinsic.push(listed, info);
704
- intrinsic.push(digestAlgs, der);
725
+ _push(listed, info);
726
+ _push(digestAlgs, der);
705
727
  });
706
728
  var newSdFields = [sdKids[0].bytes, b.set(digestAlgs), sdKids[2].bytes];
707
- if (allCerts.length) newSdFields.push(b.contextConstructed(0, Buffer.concat(allCerts)));
708
- if (crlsNode) newSdFields.push(crlsNode.bytes);
709
- newSdFields.push(newSiSet);
729
+ if (allCerts.length) _push(newSdFields, b.contextConstructed(0, intrinsic.bufferConcat(allCerts)));
730
+ if (crlsNode) _push(newSdFields, crlsNode.bytes);
731
+ _push(newSdFields, newSiSet);
710
732
  var newCi = b.sequence([root.children[0].bytes, b.explicit(0, b.sequence(newSdFields))]);
711
733
  return opts.pem ? pkix.pemEncode(newCi, "CMS", frameworkError.PemError) : newCi;
712
734
  });
@@ -732,7 +754,7 @@ function _appendUnsignedAttr(siNode, attrDer) {
732
754
  var existing = hasUa ? intrinsic.map(last.children, function (a) { return a.bytes; }) : [];
733
755
  var setOf = b.set(intrinsic.concat(existing, [attrDer]));
734
756
  var wire = intrinsic.bufferFrom(setOf); wire[0] = 0xA1;
735
- intrinsic.push(base, wire);
757
+ _push(base, wire);
736
758
  return b.sequence(base);
737
759
  }
738
760
 
@@ -955,7 +977,7 @@ function _attachTimestamp(input, token, opts) {
955
977
  }));
956
978
  var sdKids = t.sd.children;
957
979
  var newSdFields = intrinsic.map(intrinsic.arraySlice(sdKids, 0, sdKids.length - 1), function (k) { return k.bytes; });
958
- intrinsic.push(newSdFields, newSiSet);
980
+ _push(newSdFields, newSiSet);
959
981
  var out = b.sequence([t.root.children[0].bytes, b.explicit(0, b.sequence(newSdFields))]);
960
982
  return opts.pem ? pkix.pemEncode(out, "CMS", frameworkError.PemError) : out;
961
983
  }
package/lib/cms-verify.js CHANGED
@@ -203,7 +203,11 @@ function _preferBoundCandidate(si, candidates) {
203
203
  }
204
204
 
205
205
  function _certSki(cert) {
206
- var ext = (cert.extensions || []).filter(function (e) { return e.oid === oid.byName("subjectKeyIdentifier"); })[0];
206
+ /** @internal The selection returns the first matching row or null. `filter(...)[0]` indexes a
207
+ * result that is EMPTY when the extension is absent, and index 0 of an empty array answers from
208
+ * the array prototype, so a value installed there reads at the test below as an extension the
209
+ * certificate does not carry. */
210
+ var ext = guard.list.firstMatch(cert.extensions || [], function (e) { return e.oid === oid.byName("subjectKeyIdentifier"); });
207
211
  if (!ext) return null;
208
212
  try {
209
213
  return asn1.read.octetString(asn1.decode(ext.value));
@@ -359,7 +363,7 @@ async function _computeCountersigBytes(si, csTarget) {
359
363
  attrs = _decodeSignedAttrs(reTagged);
360
364
  } catch (e) { if (e instanceof CmsError) throw e; throw _err("cms/bad-signed-attrs", "the countersignature signedAttrs is not a valid SET OF Attribute", e); }
361
365
  if (intrinsic.filter(attrs, function (a) { return a.type === OID_CONTENT_TYPE; }).length) throw _err("cms/misplaced-attr", "a countersignature must not carry a content-type attribute (RFC 5652 sec. 11.4)");
362
- var mdAttr = intrinsic.filter(attrs, function (a) { return a.type === OID_MESSAGE_DIGEST; })[0];
366
+ var mdAttr = guard.list.firstMatch(attrs, function (a) { return a.type === OID_MESSAGE_DIGEST; });
363
367
  if (!mdAttr || mdAttr.values.length !== 1) throw _err("cms/bad-signed-attrs", "a countersignature's signedAttrs must carry exactly one message-digest attribute (RFC 5652 sec. 11.4)");
364
368
  var declared;
365
369
  try {
@@ -402,7 +406,7 @@ async function _computeSignedBytes(si, content, eContentType, digestByName) {
402
406
  ctOid = asn1.read.oid(ctAttr[0].values[0]);
403
407
  } catch (e) { throw _err("cms/bad-signed-attrs", "the content-type attribute value is not an OBJECT IDENTIFIER", e); }
404
408
  if (ctOid !== eContentType) return { mismatch: { code: "cms/content-type-mismatch", message: "the content-type signed attribute does not match the SignedData eContentType (RFC 5652 sec. 5.3)" } };
405
- var mdAttr = intrinsic.filter(attrs, function (a) { return a.type === OID_MESSAGE_DIGEST; })[0];
409
+ var mdAttr = guard.list.firstMatch(attrs, function (a) { return a.type === OID_MESSAGE_DIGEST; });
406
410
  if (!mdAttr || mdAttr.values.length !== 1) throw _err("cms/bad-signed-attrs", "signedAttrs must carry exactly one message-digest attribute (RFC 5652 sec. 5.4)");
407
411
  var declared;
408
412
  try {
@@ -1172,7 +1176,7 @@ var _permitsSigning = pkix.keyUsagePermits(pkix.makeNS("cms", CmsError, oid),
1172
1176
  ["digitalSignature", "contentCommitment", "nonRepudiation"]);
1173
1177
 
1174
1178
  function _keyUsagePermitsSigning(parsedCerts, der) {
1175
- var entry = intrinsic.filter(parsedCerts, function (c) { return intrinsic.bufferEquals(c.der, der); })[0];
1179
+ var entry = guard.list.firstMatch(parsedCerts, function (c) { return intrinsic.bufferEquals(c.der, der); });
1176
1180
  if (!entry) return true;
1177
1181
  return _permitsSigning(entry.cert);
1178
1182
  }