@blamejs/pki 0.8.58 → 0.8.60

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 (66) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/lib/acme.js +53 -30
  3. package/lib/alt-sig.js +3 -1
  4. package/lib/asn1-der.js +98 -39
  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 +16 -10
  9. package/lib/cmp-build.js +45 -34
  10. package/lib/cmp-session.js +19 -9
  11. package/lib/cms-decrypt.js +28 -10
  12. package/lib/cms-encrypt.js +23 -17
  13. package/lib/cms-sign.js +65 -43
  14. package/lib/cms-verify.js +11 -7
  15. package/lib/crl-sign.js +27 -20
  16. package/lib/csr-sign.js +5 -2
  17. package/lib/ct.js +37 -17
  18. package/lib/est.js +55 -32
  19. package/lib/guard-bytes.js +5 -1
  20. package/lib/guard-der.js +6 -1
  21. package/lib/guard-identifier.js +1 -1
  22. package/lib/guard-intrinsic.js +12 -4
  23. package/lib/guard-list.js +64 -0
  24. package/lib/guard-name.js +1 -1
  25. package/lib/hpke.js +10 -3
  26. package/lib/http-transport.js +12 -3
  27. package/lib/inspect.js +10 -2
  28. package/lib/jose.js +3 -1
  29. package/lib/key.js +11 -7
  30. package/lib/lint.js +236 -152
  31. package/lib/mime.js +9 -5
  32. package/lib/ocsp.js +25 -22
  33. package/lib/path-validate.js +48 -18
  34. package/lib/pbes2.js +6 -2
  35. package/lib/pkcs11-uri.js +3 -1
  36. package/lib/pkcs12-build.js +14 -11
  37. package/lib/pki-build.js +18 -14
  38. package/lib/possession.js +3 -1
  39. package/lib/rc2.js +6 -2
  40. package/lib/revocation-fetch.js +78 -19
  41. package/lib/scep.js +14 -6
  42. package/lib/schema-attrcert.js +4 -2
  43. package/lib/schema-c509.js +94 -78
  44. package/lib/schema-cmc.js +5 -2
  45. package/lib/schema-cmp.js +6 -3
  46. package/lib/schema-cms.js +7 -4
  47. package/lib/schema-crl.js +1 -1
  48. package/lib/schema-crmf.js +1 -1
  49. package/lib/schema-csr.js +3 -3
  50. package/lib/schema-engine.js +36 -18
  51. package/lib/schema-pkcs1.js +7 -3
  52. package/lib/schema-pkcs12.js +9 -6
  53. package/lib/schema-pkix.js +19 -3
  54. package/lib/schema-sec1.js +4 -1
  55. package/lib/schema-tsp.js +4 -1
  56. package/lib/shbs.js +7 -3
  57. package/lib/sign-scheme.js +4 -4
  58. package/lib/smime.js +18 -14
  59. package/lib/tlog.js +17 -11
  60. package/lib/tuf.js +3 -1
  61. package/lib/validator-keydesc.js +4 -1
  62. package/lib/validator-tls.js +7 -2
  63. package/lib/webcrypto.js +14 -8
  64. package/lib/x509-sign.js +20 -15
  65. package/package.json +1 -1
  66. package/sbom.cdx.json +6 -6
@@ -15,6 +15,10 @@ var crmfSign = require("./crmf-sign");
15
15
  var cmpBuild = require("./cmp-build");
16
16
  var csr = require("./schema-csr");
17
17
  var guard = require("./guard-all");
18
+ /** @internal The append every list here is built with: `push` stores at the index and a store
19
+ * consults a setter inherited there, and one of these lists is the accumulated CA certificates a
20
+ * later leg is authenticated against. */
21
+ var _push = guard.list.append;
18
22
  var compositeSig = require("./composite-sig");
19
23
  var constants = require("./constants");
20
24
  var webcrypto = require("./webcrypto");
@@ -34,7 +38,7 @@ function setEngine(engine) { _engine = engine; }
34
38
  var HASHLESS_SIG_OIDS = Object.create(null);
35
39
  (function () {
36
40
  var names = ["Ed25519", "Ed448", "id-ml-dsa-44", "id-ml-dsa-65", "id-ml-dsa-87"];
37
- ["sha2", "shake"].forEach(function (h) { ["128s", "128f", "192s", "192f", "256s", "256f"].forEach(function (s) { names.push("id-slh-dsa-" + h + "-" + s); }); });
41
+ ["sha2", "shake"].forEach(function (h) { ["128s", "128f", "192s", "192f", "256s", "256f"].forEach(function (s) { _push(names,"id-slh-dsa-" + h + "-" + s); }); });
38
42
  names.forEach(function (n) { var o = oid.byName(n); if (o) HASHLESS_SIG_OIDS[o] = 1; });
39
43
  })();
40
44
  var SIG_OID_TO_HASH = Object.create(null);
@@ -136,11 +140,11 @@ function _asCertList(v) { return v == null ? [] : (Array.isArray(v) ? guard.list
136
140
  function _boundedPool(base, added) {
137
141
  var ceiling = constants.LIMITS.PATH_BUILD_MAX_CANDIDATES;
138
142
  var seen = Object.create(null), distinctBase = [];
139
- base.forEach(function (c) { var k = _certIdentity(c); if (k == null) { distinctBase.push(c); return; } if (!seen[k]) { seen[k] = 1; distinctBase.push(c); } });
143
+ base.forEach(function (c) { var k = _certIdentity(c); if (k == null) { _push(distinctBase,c); return; } if (!seen[k]) { seen[k] = 1; _push(distinctBase,c); } });
140
144
  var room = ceiling - distinctBase.length;
141
145
  if (room <= 0) return distinctBase;
142
146
  var useful = [];
143
- added.forEach(function (c) { var k = _certIdentity(c); if (k != null && seen[k]) return; if (k != null) seen[k] = 1; useful.push(c); });
147
+ added.forEach(function (c) { var k = _certIdentity(c); if (k != null && seen[k]) return; if (k != null) seen[k] = 1; _push(useful,c); });
144
148
  return distinctBase.concat(useful.slice(0, room));
145
149
  }
146
150
  function _certIdentity(cert) {
@@ -228,7 +232,7 @@ function _responseExtraCerts(responseBytes) {
228
232
  seen[key] = true;
229
233
  try { x509.parse(c); }
230
234
  catch (_e) { continue; }
231
- out.push(Buffer.from(c));
235
+ _push(out,Buffer.from(c));
232
236
  }
233
237
  return out;
234
238
  }
@@ -682,7 +686,13 @@ function session(opts) {
682
686
  if (!Buffer.isBuffer(c)) return;
683
687
  var k = c.toString("base64");
684
688
  if (caPubsSeen[k]) {
685
- if (isGrantLeg) { for (var pi = 0; pi < caPubsAccum.length; pi++) { if (caPubsAccum[pi].toString("base64") === k) { guard.list.append(caPubsAccum, caPubsAccum.splice(pi, 1)[0]); if (pi < caPubsWaitingCount) caPubsWaitingCount--; break; } } }
689
+ /** @internal The entry is read, removed and appended as three steps rather than through
690
+ * `splice`. `splice` RETURNS what it removed, so it builds that result through
691
+ * `ArraySpeciesCreate`, which reads the receiver's `constructor` and then its
692
+ * `Symbol.species`: a getter installed on `Array.prototype.constructor` is handed this
693
+ * accumulator as its `this` while the move is in progress, and the list holds the CA
694
+ * certificates a later leg is authenticated against. */
695
+ if (isGrantLeg) { for (var pi = 0; pi < caPubsAccum.length; pi++) { if (caPubsAccum[pi].toString("base64") === k) { var moved = caPubsAccum[pi]; guard.list.removeAt(caPubsAccum, pi); guard.list.append(caPubsAccum, moved); if (pi < caPubsWaitingCount) caPubsWaitingCount--; break; } } }
686
696
  return;
687
697
  }
688
698
  try { x509.parse(c); } catch (e) { throw _err("cmp/bad-cert-response", "an authenticated caPubs entry is not a valid X.509 certificate", e); }
@@ -963,10 +973,10 @@ function session(opts) {
963
973
  async function _validateLeaf(leaf, caPubs) {
964
974
  if (_engine == null || opts.trustAnchors == null) return;
965
975
  var caPubsList = [];
966
- if (Array.isArray(caPubs)) caPubs.forEach(function (c) { if (Buffer.isBuffer(c)) caPubsList.push(c); });
976
+ if (Array.isArray(caPubs)) caPubs.forEach(function (c) { if (Buffer.isBuffer(c)) _push(caPubsList,c); });
967
977
  var added = _asCertList(opts.intermediates);
968
- if (Buffer.isBuffer(cachedSignerCert)) added.push(cachedSignerCert);
969
- cachedChain.forEach(function (c) { if (Buffer.isBuffer(c)) added.push(c); });
978
+ if (Buffer.isBuffer(cachedSignerCert)) _push(added,cachedSignerCert);
979
+ cachedChain.forEach(function (c) { if (Buffer.isBuffer(c)) _push(added,c); });
970
980
  var pool = _boundedPool(caPubsList, added);
971
981
  var res;
972
982
  try { res = await _engine.build(leaf, { trustAnchors: _asCertList(opts.trustAnchors), intermediates: pool, validate: true, time: opts.time != null ? opts.time : new Date() }); }
@@ -1395,7 +1405,7 @@ function session(opts) {
1395
1405
  if (limit.total !== null && total > limit.total) {
1396
1406
  throw _err("cmp/bad-input", "the resumeToken " + name + " exceeds the " + limit.total + "-byte pool a transaction holds");
1397
1407
  }
1398
- out.push(der);
1408
+ _push(out,der);
1399
1409
  }
1400
1410
  return out;
1401
1411
  }
@@ -121,10 +121,10 @@ function _selectCandidates(recips, km, opts) {
121
121
  for (var k = 0; k < recips.length; k++) {
122
122
  var r = recips[k];
123
123
  if (want === "asym" && (r.type === "ktri" || r.type === "kari" || r.type === "ori")) {
124
- if (cert && _ridMatches(r, cert)) out.push({ ri: r, index: k });
125
- } else if (want === "pwri" && r.type === "pwri") { out.push({ ri: r, index: k }); }
124
+ if (cert && _ridMatches(r, cert)) intrinsic.append(out, { ri: r, index: k });
125
+ } else if (want === "pwri" && r.type === "pwri") { intrinsic.append(out, { ri: r, index: k }); }
126
126
  else if (want === "kekri" && r.type === "kekri") {
127
- if (km.kekId == null || _kekIdMatches(r, km.kekId)) out.push({ ri: r, index: k });
127
+ if (km.kekId == null || _kekIdMatches(r, km.kekId)) intrinsic.append(out, { ri: r, index: k });
128
128
  }
129
129
  }
130
130
  if (!out.length) throw _err("cms/no-matching-recipient", "no recipient matches the supplied key material");
@@ -563,19 +563,23 @@ async function _aesKwUnwrap(kek, wrapped) {
563
563
  guard.secret.zeroize(new Uint8Array(rawAb), CmsError, "cms/bad-input", "the unwrapped content key");
564
564
  }
565
565
  }
566
+ /** @internal Both KDF-input structures APPEND by defining the index. A store at an index the list
567
+ * has no own property at consults a setter inherited from the array prototype, so an accessor there
568
+ * would decide the SharedInfo these bytes become and derive a different KEK from the same shared
569
+ * secret. */
566
570
  function _eccSharedInfo(wrapName, ukm, kekBytes) {
567
571
  var kids = [b.sequence([b.oid(O(wrapName))])];
568
- if (ukm) kids.push(b.explicit(0, b.octetString(ukm)));
572
+ if (ukm) intrinsic.append(kids, b.explicit(0, b.octetString(ukm)));
569
573
  /** @internal The SuppPubInfo key length is written with the capture, for the same reason the
570
574
  * encrypt side does it: this is KDF input, and a replaced write derives a different KEK from the
571
575
  * same shared secret. */
572
576
  var supp = Buffer.alloc(4); intrinsic.writeUInt32BE(supp, kekBytes * 8, 0);
573
- kids.push(b.explicit(2, b.octetString(supp)));
577
+ intrinsic.append(kids, b.explicit(2, b.octetString(supp)));
574
578
  return b.sequence(kids);
575
579
  }
576
580
  function _kemOtherInfo(wrapName, kekBytes, ukm) {
577
581
  var kids = [b.sequence([b.oid(O(wrapName))]), b.integer(BigInt(kekBytes))];
578
- if (ukm) kids.push(b.explicit(0, b.octetString(ukm)));
582
+ if (ukm) intrinsic.append(kids, b.explicit(0, b.octetString(ukm)));
579
583
  return b.sequence(kids);
580
584
  }
581
585
  function _pwriUnwrap(kek, wrapped, iv, keyBits) {
@@ -631,9 +635,13 @@ var HASH_W3C = intrinsic.create(null); HASH_W3C[O("sha1")] = "SHA-1"; HASH_W3C[O
631
635
  function _hashW3c(o) { if (!HASH_W3C[o]) throw _err("cms/unsupported-algorithm", "unsupported OAEP hash " + o); return HASH_W3C[o]; }
632
636
 
633
637
  var X963_HASH = intrinsic.create(null);
634
- [["dhSinglePass-stdDH-sha1kdf-scheme", "SHA-1"], ["dhSinglePass-stdDH-sha224kdf-scheme", "SHA-224"], ["dhSinglePass-stdDH-sha256kdf-scheme", "SHA-256"], ["dhSinglePass-stdDH-sha384kdf-scheme", "SHA-384"], ["dhSinglePass-stdDH-sha512kdf-scheme", "SHA-512"],
638
+ var _X963_ROWS = [["dhSinglePass-stdDH-sha1kdf-scheme", "SHA-1"], ["dhSinglePass-stdDH-sha224kdf-scheme", "SHA-224"], ["dhSinglePass-stdDH-sha256kdf-scheme", "SHA-256"], ["dhSinglePass-stdDH-sha384kdf-scheme", "SHA-384"], ["dhSinglePass-stdDH-sha512kdf-scheme", "SHA-512"],
635
639
  ["dhSinglePass-cofactorDH-sha1kdf-scheme", "SHA-1"], ["dhSinglePass-cofactorDH-sha224kdf-scheme", "SHA-224"], ["dhSinglePass-cofactorDH-sha256kdf-scheme", "SHA-256"], ["dhSinglePass-cofactorDH-sha384kdf-scheme", "SHA-384"], ["dhSinglePass-cofactorDH-sha512kdf-scheme", "SHA-512"]
636
- ].forEach(function (r) { X963_HASH[O(r[0])] = r[1]; });
640
+ ];
641
+ /** @internal The registry is built through the captured walk. The method is read off the live
642
+ * prototype at the moment it runs even where the receiver is a literal, and these rows decide which
643
+ * hash a key-agreement recipient's KDF uses. */
644
+ intrinsic.forEach(_X963_ROWS, function (r) { X963_HASH[O(r[0])] = r[1]; });
637
645
  function _x963Hash(scheme) { if (!X963_HASH[scheme]) throw _err("cms/unsupported-algorithm", "unsupported kari key-agreement scheme " + scheme); return X963_HASH[scheme]; }
638
646
  function _kariWrap(kea) {
639
647
  var params = asn1.decode(kea.parameters);
@@ -644,7 +652,7 @@ function _originatorSpki(originator) {
644
652
  if (!originator || originator.form !== "originatorKey") throw _err("cms/unsupported-algorithm", "kari requires an originatorKey (ephemeral-static ECDH)");
645
653
  var v = originator.value;
646
654
  var algKids = [b.oid(v.algorithm.oid)];
647
- if (v.algorithm.parameters != null) algKids.push(b.raw(v.algorithm.parameters));
655
+ if (v.algorithm.parameters != null) intrinsic.append(algKids, b.raw(v.algorithm.parameters));
648
656
  return b.sequence([b.sequence(algKids), b.bitString(v.publicKey.bytes, v.publicKey.unusedBits)]);
649
657
  }
650
658
  var MONT = intrinsic.create(null); MONT[O("X25519")] = { name: "X25519", hkdf: "SHA-256" }; MONT[O("X448")] = { name: "X448", hkdf: "SHA-512" };
@@ -706,7 +714,17 @@ async function _verifyAuthenticatedData(parsed, km, opts, requireProtection) {
706
714
  guard.der.assertParams(parsed.digestAlgorithm.parameters, "absentOrNull", _err,
707
715
  "cms/unsupported-algorithm", parsed.digestAlgorithm.name + " digestAlgorithm (RFC 5754 sec. 2)");
708
716
  preimage = _explicitSetOf(parsed.authAttrsBytes);
709
- var mdAttr = (parsed.authAttrs || []).filter(function (a) { return a.type === O("messageDigest"); })[0];
717
+ /** @internal The selection returns the first matching attribute or null. `filter(...)[0]` indexes
718
+ * a result that is EMPTY when the attribute is absent, and index 0 of an empty array answers
719
+ * from the array prototype, so a value installed there would supply the digest this comparison
720
+ * is made against. The refusal restates an invariant the parse already holds: an
721
+ * AuthenticatedData with authAttrs is walked through the content-binding check, which requires
722
+ * the message-digest attribute (`cms/missing-message-digest`), so this is not reachable from a
723
+ * message and is here so the read below cannot be made on something that is not an attribute. */
724
+ var mdAttr = guard.list.firstMatch(parsed.authAttrs || [], function (a) { return a.type === O("messageDigest"); });
725
+ if (!mdAttr || mdAttr.values.length !== 1) {
726
+ throw _err("cms/bad-auth-attrs", "authenticated attributes must carry exactly one message-digest attribute (RFC 5652 sec. 9.2)");
727
+ }
710
728
  mdCheck = { hash: dHash, declared: asn1.read.octetString(asn1.decode(mdAttr.values[0])) };
711
729
  /** @internal RFC 6211 sec. 3.2 on this content type: the two comparisons are what make the
712
730
  * outer `digestAlgorithm` and `macAlgorithm` fields mean anything, since the MAC input is the
@@ -14,6 +14,10 @@ var webcrypto = require("./webcrypto");
14
14
  var frameworkError = require("./framework-error");
15
15
  var guard = require("./guard-all");
16
16
  var intrinsic = require("./guard-intrinsic");
17
+ /** @internal The append every list here is built with: `push` stores at the index and a store
18
+ * consults a setter inherited there. These lists become a recipient info and the key-derivation
19
+ * input beside it. */
20
+ var _push = intrinsic.append;
17
21
  var pbes2 = require("./pbes2");
18
22
  var compositeKem = require("./composite-kem");
19
23
  var b = asn1.build;
@@ -66,7 +70,7 @@ function _wrapOidForKek(keyBytes) {
66
70
 
67
71
  function _gcmParams(nonce, icvLen) {
68
72
  var kids = [b.octetString(nonce)];
69
- if (icvLen !== 12) kids.push(b.integer(BigInt(icvLen)));
73
+ if (icvLen !== 12) _push(kids,b.integer(BigInt(icvLen)));
70
74
  return b.sequence(kids);
71
75
  }
72
76
 
@@ -124,12 +128,12 @@ MONT_KA[O("X448")] = { name: "X448", hkdf: "SHA-512", scheme: "dhSinglePass-stdD
124
128
 
125
129
  function _eccSharedInfo(wrapName, ukm, kekBytes) {
126
130
  var kids = [_algId(wrapName, "absent")];
127
- if (ukm) kids.push(b.explicit(0, b.octetString(ukm)));
131
+ if (ukm) _push(kids,b.explicit(0, b.octetString(ukm)));
128
132
  /** @internal The SuppPubInfo key length is written with the capture. It is KDF input, so it is part
129
133
  * of what the key-encryption key derives from, and a replaced write derives a different KEK from
130
134
  * the same shared secret. */
131
135
  var supp = Buffer.alloc(4); intrinsic.writeUInt32BE(supp, kekBytes * 8, 0);
132
- kids.push(b.explicit(2, b.octetString(supp)));
136
+ _push(kids,b.explicit(2, b.octetString(supp)));
133
137
  return b.sequence(kids);
134
138
  }
135
139
  async function _buildKari(cek, cert, opts) {
@@ -179,8 +183,9 @@ async function _buildKari(cek, cert, opts) {
179
183
  var rek = b.sequence([b.sequence([ridNode, b.octetString(encryptedKey)])]);
180
184
  var kekAlg = b.sequence([b.oid(O(origKeyAlgId.scheme)), _algId(wrapName, "absent")]);
181
185
  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);
186
+ if (ukm) _push(kariKids,b.explicit(1, b.octetString(ukm)));
187
+ _push(kariKids,kekAlg);
188
+ _push(kariKids,rek);
184
189
  return { tag: 1, node: b.sequence(kariKids) };
185
190
  } finally {
186
191
  guard.secret.zeroizeAll([z, mz, kek], CmsError, "cms/bad-input", "the key-agreement shared secret");
@@ -227,7 +232,7 @@ var KEM_WC = intrinsic.create(null); KEM_WC[O("id-ml-kem-512")] = "ML-KEM-512";
227
232
 
228
233
  function _kemOtherInfo(wrapName, kekBytes, ukm) {
229
234
  var kids = [_algId(wrapName, "absent"), b.integer(BigInt(kekBytes))];
230
- if (ukm) kids.push(b.explicit(0, b.octetString(ukm)));
235
+ if (ukm) _push(kids,b.explicit(0, b.octetString(ukm)));
231
236
  return b.sequence(kids);
232
237
  }
233
238
  async function _kemEncapsulate(keyOid, cert) {
@@ -258,8 +263,9 @@ async function _buildKemri(cek, cert, opts) {
258
263
  var encryptedKey = await _aesKwWrap(kek, cek);
259
264
  var rid = _rid(cert, opts.keyIdentifier);
260
265
  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));
266
+ if (ukm) _push(kemriKids,b.explicit(0, b.octetString(ukm)));
267
+ _push(kemriKids,_algId(wrapName, "absent"));
268
+ _push(kemriKids,b.octetString(encryptedKey));
263
269
  var kemri = b.sequence(kemriKids);
264
270
  return { tag: 4, node: b.sequence([b.oid(O("kem")), kemri]) };
265
271
  } finally {
@@ -446,7 +452,7 @@ async function _encryptImpl(content, recipients, opts) {
446
452
  if (!recipients.length) throw _err("cms/bad-input", "at least one recipient is required (RFC 5652 sec. 6.1)");
447
453
  var recips = [];
448
454
  var consumed = intrinsic.create(null);
449
- for (var i = 0; i < recipients.length; i++) recips.push(await _buildRecipient(cek, recipients[i], opts, consumed));
455
+ for (var i = 0; i < recipients.length; i++) _push(recips,await _buildRecipient(cek, recipients[i], opts, consumed));
450
456
  _assertDefaultsConsumed(opts, consumed);
451
457
  var riNodes = recips.map(_taggedRecipient);
452
458
 
@@ -535,8 +541,8 @@ async function _authEnvelopedData(contentBytes, contentStream, cek, ca, contentT
535
541
  }
536
542
  var eci = b.sequence([b.oid(O(contentType)), b.sequence([b.oid(O(ca.oid)), _gcmParams(nonce, 16)]), b.contextPrimitive(0, g.ct)]);
537
543
  var kids = [b.integer(0n), b.setOf(riNodes), eci];
538
- if (authAttrsDer) kids.push(authAttrsDer);
539
- kids.push(b.octetString(g.tag));
544
+ if (authAttrsDer) _push(kids,authAttrsDer);
545
+ _push(kids,b.octetString(g.tag));
540
546
  void recips;
541
547
  return b.sequence(kids);
542
548
  }
@@ -680,7 +686,7 @@ async function _authenticateImpl(content, recipients, opts) {
680
686
  try {
681
687
  var recips = [];
682
688
  var consumedAuth = {};
683
- for (var i = 0; i < recipients.length; i++) recips.push(await _buildRecipient(macKey, recipients[i], opts, consumedAuth));
689
+ for (var i = 0; i < recipients.length; i++) _push(recips,await _buildRecipient(macKey, recipients[i], opts, consumedAuth));
684
690
  _assertDefaultsConsumed(opts, consumedAuth);
685
691
  var riNodes = recips.map(_taggedRecipient);
686
692
 
@@ -705,7 +711,7 @@ async function _authenticateImpl(content, recipients, opts) {
705
711
  * MAC algorithm substitution attack, which is difficult because the attacker does not know
706
712
  * the authentication key". Built from the same values the two outer fields are built from. */
707
713
  if (protectionOid) {
708
- intrinsic.push(pairs, b.sequence([
714
+ intrinsic.append(pairs, b.sequence([
709
715
  b.oid(protectionOid),
710
716
  b.setOf([b.sequence([_algId(digestName), b.implicit(2, _algId(mac.oid))])]),
711
717
  ]));
@@ -732,10 +738,10 @@ async function _authenticateImpl(content, recipients, opts) {
732
738
 
733
739
  var eci = b.sequence([b.oid(O(contentType)), b.explicit(0, b.octetString(contentBytes))]);
734
740
  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));
741
+ if (digestAlgTagged) _push(kids,digestAlgTagged);
742
+ _push(kids,eci);
743
+ if (authAttrsDer) _push(kids,authAttrsDer);
744
+ _push(kids,b.octetString(macValue));
739
745
  var ci = b.sequence([b.oid(O("authData")), b.explicit(0, b.sequence(kids))]);
740
746
  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
747
  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
@@ -126,9 +126,9 @@ var SIG_SCHEME = intrinsic.assign(intrinsic.create(null), {
126
126
  ecdsaWithSHA384: { kind: "ec", hash: "SHA-384", params: "absent" },
127
127
  ecdsaWithSHA512: { kind: "ec", hash: "SHA-512", params: "absent" },
128
128
  });
129
- ["sha2-128s", "sha2-128f", "sha2-192s", "sha2-192f", "sha2-256s", "sha2-256f",
130
- "shake-128s", "shake-128f", "shake-192s", "shake-192f", "shake-256s", "shake-256f"
131
- ].forEach(function (s) { SIG_SCHEME["id-slh-dsa-" + s] = { kind: "slhdsa", name: "SLH-DSA-" + s.toUpperCase(), params: "absent", sameKeyOid: true, digest: SLHDSA_BY_OID[oid.byName("id-slh-dsa-" + s)].digest }; });
129
+ intrinsic.forEach(["sha2-128s", "sha2-128f", "sha2-192s", "sha2-192f", "sha2-256s", "sha2-256f",
130
+ "shake-128s", "shake-128f", "shake-192s", "shake-192f", "shake-256s", "shake-256f"
131
+ ], function (s) { SIG_SCHEME["id-slh-dsa-" + s] = { kind: "slhdsa", name: "SLH-DSA-" + intrinsic.toUpperCase(s), params: "absent", sameKeyOid: true, digest: SLHDSA_BY_OID[oid.byName("id-slh-dsa-" + s)].digest }; });
132
132
  function _isDerNull(p) { return guard.der.isNull(p); }
133
133
  function _algParamsOk(shape, p) { return shape === "null" ? _isDerNull(p) : (p === null || p === undefined); }
134
134
  var EC_CURVE = intrinsic.create(null);
@@ -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
  }