@blamejs/pki 0.8.31 → 0.8.48

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 (87) hide show
  1. package/CHANGELOG.md +393 -0
  2. package/README.md +66 -15
  3. package/bin/pki.js +716 -30
  4. package/examples/issue-a-certificate.js +90 -0
  5. package/examples/post-quantum.js +66 -0
  6. package/examples/read-a-certificate.js +56 -0
  7. package/examples/revoke-and-check.js +86 -0
  8. package/examples/sign-and-verify-cms.js +63 -0
  9. package/index.js +18 -5
  10. package/lib/acme.js +223 -74
  11. package/lib/alt-sig.js +441 -0
  12. package/lib/asn1-der.js +48 -25
  13. package/lib/attrcert-sign.js +27 -19
  14. package/lib/cbor-det.js +24 -14
  15. package/lib/cmc-build.js +9 -2
  16. package/lib/cmc-verify.js +14 -3
  17. package/lib/cmp-build.js +17 -5
  18. package/lib/cmp-session.js +24 -11
  19. package/lib/cmp-verify.js +28 -19
  20. package/lib/cms-compress.js +3 -1
  21. package/lib/cms-decrypt.js +102 -7
  22. package/lib/cms-encrypt.js +59 -7
  23. package/lib/cms-sign.js +31 -9
  24. package/lib/cms-verify.js +22 -18
  25. package/lib/composite-kem.js +30 -18
  26. package/lib/composite-sig.js +29 -14
  27. package/lib/constants.js +26 -0
  28. package/lib/crl-sign.js +111 -19
  29. package/lib/crmf-sign.js +167 -15
  30. package/lib/csr-sign.js +117 -6
  31. package/lib/ct.js +939 -48
  32. package/lib/est.js +29 -16
  33. package/lib/framework-error.js +12 -0
  34. package/lib/guard-async.js +1 -1
  35. package/lib/guard-bytes.js +103 -20
  36. package/lib/guard-crypto.js +205 -3
  37. package/lib/guard-encoding.js +6 -1
  38. package/lib/guard-identifier.js +55 -8
  39. package/lib/guard-intrinsic.js +43 -0
  40. package/lib/guard-json.js +122 -9
  41. package/lib/guard-limits.js +12 -1
  42. package/lib/guard-list.js +63 -8
  43. package/lib/guard-name.js +167 -20
  44. package/lib/guard-range.js +43 -5
  45. package/lib/guard-text.js +41 -0
  46. package/lib/guard-verdict.js +39 -8
  47. package/lib/hpke.js +688 -42
  48. package/lib/http-transport.js +156 -4
  49. package/lib/identity-match.js +4 -4
  50. package/lib/inspect.js +33 -6
  51. package/lib/jose.js +93 -25
  52. package/lib/key.js +18 -13
  53. package/lib/lint.js +165 -1
  54. package/lib/merkle.js +233 -27
  55. package/lib/ocsp.js +27 -14
  56. package/lib/oid.js +14 -4
  57. package/lib/path-validate.js +143 -61
  58. package/lib/pkcs12-build.js +7 -2
  59. package/lib/pki-build.js +31 -7
  60. package/lib/possession.js +575 -0
  61. package/lib/related-cert.js +708 -0
  62. package/lib/revocation-fetch.js +6 -6
  63. package/lib/scep.js +15 -5
  64. package/lib/schema-c509.js +5 -2
  65. package/lib/schema-cmc.js +1 -1
  66. package/lib/schema-cmp.js +8 -8
  67. package/lib/schema-cms.js +2 -15
  68. package/lib/schema-csr.js +69 -0
  69. package/lib/schema-engine.js +10 -3
  70. package/lib/schema-pkix.js +228 -2
  71. package/lib/schema-tsp.js +7 -6
  72. package/lib/sign-scheme.js +22 -9
  73. package/lib/sigstore.js +684 -168
  74. package/lib/sleep.js +8 -1
  75. package/lib/smime.js +22 -1
  76. package/lib/tlog.js +1235 -0
  77. package/lib/tls-cert-compress.js +25 -8
  78. package/lib/tsp-sign.js +120 -35
  79. package/lib/tuf.js +1395 -0
  80. package/lib/validator-tpm.js +4 -1
  81. package/lib/verify-seam.js +7 -1
  82. package/lib/webauthn-mds.js +41 -4
  83. package/lib/webauthn.js +43 -25
  84. package/lib/webcrypto.js +48 -46
  85. package/lib/x509-sign.js +225 -19
  86. package/package.json +2 -1
  87. package/sbom.cdx.json +6 -6
@@ -168,11 +168,19 @@ function _resolveAllowed(opts) {
168
168
  */
169
169
  function decompressCertificate(bytes, opts) {
170
170
  opts = opts || {};
171
- var view = guard.bytes.view(bytes, TlsError, "tls/bad-input", "the compressed certificate message");
172
- if (view.length > C.LIMITS.TLS_CERT_MSG_MAX_BYTES) {
173
- throw _err("tls/too-large", "the compressed certificate message is " + view.length +
171
+ /** @internal Viewed, CAPPED, then COPIED, and only then are the options read. A view stays a window
172
+ * onto the caller's buffer, and `_resolveCap` reads `opts`, which is caller code when it is an
173
+ * accessor: a `maxOutputBytes` getter that wrote another valid message of the same length over the
174
+ * buffer had this verb decompress the REPLACEMENT, having framed the one it was handed. Measured, a
175
+ * message framing `0141000000` came back as `0142000000`. `compressCertificate` takes its copy before
176
+ * reading `opts.algorithm` for the same reason; this is the other half of that pair. The cap sits
177
+ * ahead of the copy so the copy is not an allocation the size of whatever arrived. */
178
+ var viewed = guard.bytes.source(bytes, TlsError, "tls/bad-input", "the compressed certificate message");
179
+ if (guard.bytes.lengthOf(viewed) > C.LIMITS.TLS_CERT_MSG_MAX_BYTES) {
180
+ throw _err("tls/too-large", "the compressed certificate message is " + guard.bytes.lengthOf(viewed) +
174
181
  " bytes, over the " + C.LIMITS.TLS_CERT_MSG_MAX_BYTES + "-byte handshake framing limit");
175
182
  }
183
+ var view = guard.bytes.snapshot(viewed, TlsError, "tls/bad-input", "the compressed certificate message");
176
184
  var cap = _resolveCap(opts);
177
185
  var allowed = _resolveAllowed(opts);
178
186
 
@@ -308,7 +316,20 @@ function parseCertificateMessage(bytes, opts) {
308
316
  */
309
317
  function compressCertificate(certificateMessage, opts) {
310
318
  opts = opts || {};
311
- var view = guard.bytes.view(certificateMessage, TlsError, "tls/bad-input", "the certificate message");
319
+ /** @internal Copied, not viewed. `opts.algorithm` is read below, and reading an option is caller code
320
+ * when it is an accessor, so over a view it would run between the message being looked at and being
321
+ * compressed and replace what this verb compresses, after it had accepted the message it was handed.
322
+ * A substitute the framing check below accepts goes through unseen, so the copy has to come first. */
323
+ /** @internal Viewed, CAPPED, then copied, in that order, and the option is read after all three. The
324
+ * copy has to come before the option for the reason above; the cap has to come before the copy or the
325
+ * copy is an allocation the size of whatever arrived: measured, a 64 MiB message allocated another
326
+ * 64 MiB before the framing limit below refused it. Viewing allocates nothing, so both hold. */
327
+ var viewed = guard.bytes.source(certificateMessage, TlsError, "tls/bad-input", "the certificate message");
328
+ if (guard.bytes.lengthOf(viewed) > C.LIMITS.TLS_CERT_MSG_MAX_BYTES) {
329
+ throw _err("tls/too-large", "the certificate message is " + guard.bytes.lengthOf(viewed) +
330
+ " bytes, over the " + C.LIMITS.TLS_CERT_MSG_MAX_BYTES + "-byte handshake framing limit");
331
+ }
332
+ var view = guard.bytes.snapshot(viewed, TlsError, "tls/bad-input", "the certificate message");
312
333
  var sel = opts.algorithm === undefined ? "zlib" : opts.algorithm;
313
334
  var name = (typeof sel === "number") ? ALG_BY_NUMBER[sel] : sel;
314
335
  if (typeof name !== "string" || SUPPORTED.indexOf(name) === -1) {
@@ -317,10 +338,6 @@ function compressCertificate(certificateMessage, opts) {
317
338
  if (view.length < MIN_CERT_MSG_BYTES) {
318
339
  throw _err("tls/bad-input", "a Certificate message is at least " + MIN_CERT_MSG_BYTES + " bytes (RFC 8446 sec. 4.4.2)");
319
340
  }
320
- if (view.length > C.LIMITS.TLS_CERT_MSG_MAX_BYTES) {
321
- throw _err("tls/too-large", "the certificate message is " + view.length + " bytes, over the " +
322
- C.LIMITS.TLS_CERT_MSG_MAX_BYTES + "-byte handshake framing limit");
323
- }
324
341
  if (opts.level !== undefined && (typeof opts.level !== "number" || !isFinite(opts.level) || Math.floor(opts.level) !== opts.level)) {
325
342
  throw _err("tls/bad-input", "opts.level must be an integer");
326
343
  }
package/lib/tsp-sign.js CHANGED
@@ -15,7 +15,6 @@
15
15
  * @card Create an RFC 3161 timestamp token (a CMS SignedData over a TSTInfo).
16
16
  */
17
17
 
18
- var nodeCrypto = require("crypto");
19
18
  var asn1 = require("./asn1-der");
20
19
  var oid = require("./oid");
21
20
  var cmsSign = require("./cms-sign");
@@ -27,6 +26,11 @@ var schemaTsp = require("./schema-tsp");
27
26
  var guard = require("./guard-all");
28
27
  var intrinsic = require("./guard-intrinsic");
29
28
  var _charCodeAt = intrinsic.uncurry(String.prototype.charCodeAt);
29
+ var _compare = intrinsic.compare;
30
+ var _pop = intrinsic.pop;
31
+ var _reverse = intrinsic.reverse;
32
+ var _arrSlice = intrinsic.arraySlice;
33
+ var _bufferFrom = intrinsic.bufferFrom;
30
34
  var frameworkError = require("./framework-error");
31
35
 
32
36
  var pkix = require("./schema-pkix");
@@ -85,7 +89,7 @@ function _certDer(c) {
85
89
  }
86
90
 
87
91
  function _signingCertV2(certDer, hashName) {
88
- var certHash = nodeCrypto.createHash(NODE_DIGEST[hashName]).update(certDer).digest();
92
+ var certHash = guard.crypto.digest(NODE_DIGEST[hashName], certDer);
89
93
  var essCertId = hashName === "sha256"
90
94
  ? b.sequence([b.octetString(certHash)])
91
95
  : b.sequence([_hashAlgId(hashName), b.octetString(certHash)]);
@@ -195,7 +199,10 @@ function _sign(messageImprint, tsa, opts) {
195
199
  var tstInfo = b.sequence(fields);
196
200
 
197
201
  var signCert = { type: "signingCertificateV2", values: [_signingCertV2(certDer, certHashAlg)] };
198
- var extra = [signCert].concat(opts.additionalSignedAttributes || []);
202
+ /** @internal Through the capture: assembled by a live `Array.prototype.concat`, the signed attribute
203
+ * set was that method's to choose, and the first entry is the signing-certificate attribute that
204
+ * binds the token to the certificate it names. A replacement could drop it. */
205
+ var extra = intrinsic.concat([signCert], opts.additionalSignedAttributes || []);
199
206
  var signer = { cert: certDer, key: tsa && tsa.key, digestAlgorithm: opts.digestAlgorithm, pss: opts.pss };
200
207
  return cmsSign.sign(tstInfo, signer, {
201
208
  eContentType: "tSTInfo",
@@ -428,16 +435,28 @@ function parseResponse(input) { return schemaTsp.parse(input); }
428
435
  var _VERIFY_DIGEST = intrinsic.assign(intrinsic.create(null), { sha256: "sha256", sha384: "sha384", sha512: "sha512", sha1: "sha1" });
429
436
  var _VERIFY_DIGEST_LEN = constants.NAMES.DIGEST_OCTETS;
430
437
  var _BIND_DIGEST = intrinsic.assign(intrinsic.create(null), { sha256: "sha256", sha384: "sha384", sha512: "sha512" });
438
+ /** @internal The digests admitted for an imprint that are not collision resistant, so a token under one
439
+ * binds nothing an attacker with a collision cannot move. They verify only under `allowWeakDigests`. */
440
+ var _WEAK_IMPRINT_DIGEST = intrinsic.assign(intrinsic.create(null), { sha1: 1 });
431
441
 
432
- function _imprintMatches(mi, data) {
442
+ function _imprintMatches(mi, data, allowWeakDigests) {
433
443
  var name = mi.hashAlgorithm && mi.hashAlgorithm.name;
434
444
  var nodeAlg = (name && intrinsic.hasOwn(_VERIFY_DIGEST, name)) ? _VERIFY_DIGEST[name] : null;
435
445
  if (!nodeAlg) return "tsp/unsupported-algorithm";
446
+ /** @internal The imprint is the ONLY thing binding a token to the data it timestamps, so the digest
447
+ * that computes it carries the whole binding and a collision in it substitutes the data under a
448
+ * genuine token. `allowWeakDigests` used to reach only the token's own signature digest, through
449
+ * `cmsVerify.verify`, so a SHA-1 imprint verified under every setting of it including `false`.
450
+ * NO FETCHED CLAUSE FORBIDS SHA-1 HERE: the one quoted algorithm prohibition is EN 319 122-1 clause
451
+ * 6.2.1 on MD5. Refusing it by default is this toolkit's posture, matching what `pki.cms.verify`
452
+ * already does with a signature digest, and the opt-in is the same option an archived token needs. */
453
+ if (!allowWeakDigests && intrinsic.hasOwn(_WEAK_IMPRINT_DIGEST, name)) return "tsp/weak-digest";
436
454
  var wantLen = _VERIFY_DIGEST_LEN[name];
437
455
  if (mi.hashedMessage.length !== wantLen) return "tsp/imprint-mismatch";
438
456
  var actual;
439
457
  if (guard.bytes.isByteSource(data)) {
440
- actual = nodeCrypto.createHash(nodeAlg).update(guard.bytes.source(data, TspError, "tsp/bad-input", "data")).digest();
458
+ var dataBytes = guard.bytes.source(data, TspError, "tsp/bad-input", "data");
459
+ actual = guard.crypto.digest(nodeAlg, dataBytes);
441
460
  } else if (data && typeof data === "object" && guard.bytes.isByteSource(data.hashedMessage)) {
442
461
  if (data.hashAlgorithm !== name) return "tsp/imprint-mismatch";
443
462
  var dhmLen = guard.bytes.source(data.hashedMessage, TspError, "tsp/bad-input", "precomputed imprint hashedMessage").length;
@@ -446,43 +465,109 @@ function _imprintMatches(mi, data) {
446
465
  } else {
447
466
  throw _err("tsp/bad-input", "pki.tsp.verify data must be a Buffer or a { hashAlgorithm, hashedMessage } imprint");
448
467
  }
449
- return Buffer.compare(actual, Buffer.from(mi.hashedMessage)) === 0 ? true : "tsp/imprint-mismatch";
468
+ return _compare(actual, _bufferFrom(mi.hashedMessage)) === 0 ? true : "tsp/imprint-mismatch";
450
469
  }
451
470
 
452
- function _checkCertBinding(signerInfo, tsaCertDer) {
453
- var attrs = (signerInfo && signerInfo.signedAttrs) || [];
454
- var sc = null, scV1 = null;
455
- for (var i = 0; i < attrs.length; i++) {
456
- if (attrs[i].type === O("signingCertificateV2")) { sc = attrs[i]; break; }
457
- if (attrs[i].type === O("signingCertificate") && !scV1) scV1 = attrs[i];
458
- }
459
- if (!sc) sc = scV1;
460
- if (!sc) return "tsp/missing-signing-certificate";
471
+ /** @internal The certificate one binding attribute names, and the digest under which it names it.
472
+ * An ESSCertID v1 carries NO hashAlgorithm field: it is SHA-1 by definition (RFC 2634 sec. 5.4.1),
473
+ * and EN 319 122-1 clause 5.2.2.2 says the v1 attribute "shall be used if the SHA-1 hash algorithm is
474
+ * used", so these tokens exist. An absent algorithm therefore means SHA-1 rather than nothing, and
475
+ * reporting `tsp/unsupported-algorithm` for one named the wrong fault: the algorithm is known and the
476
+ * binding is deliberately weak, which is a different refusal from one this build cannot compute.
477
+ * ABSENT IS NOT THE SAME AS UNRECOGNIZED: a v1 ESSCertID omits the field, so absent carries the type's
478
+ * default of SHA-1; an ESSCertIDv2 naming an OID this build does not know carries an algorithm that
479
+ * genuinely cannot be computed, and that one is `tsp/unsupported-algorithm`.
480
+ * Returns a refusal code, or the ESSCertID with the digest resolved. SHA-1 resolves rather than
481
+ * refusing, because whether a weak binding is a refusal depends on what the caller is doing with it:
482
+ * the attribute the verdict rests on is held to it, and an attribute read only for agreement is not. */
483
+ function _readBinding(attr) {
461
484
  var decoded;
462
- try { decoded = smime.decodeAttribute(sc); }
485
+ try { decoded = smime.decodeAttribute(attr); }
463
486
  catch (_e) { return "tsp/bad-signing-certificate"; }
464
487
  var essCert = decoded.certs && decoded.certs[0];
465
488
  if (!essCert) return "tsp/bad-signing-certificate";
466
- var nodeAlg = essCert.hashAlgorithm && _BIND_DIGEST[essCert.hashAlgorithm.name];
467
- if (!nodeAlg) return "tsp/unsupported-algorithm";
468
- var actual = nodeCrypto.createHash(nodeAlg).update(tsaCertDer).digest();
469
- if (Buffer.compare(actual, Buffer.from(essCert.certHash)) !== 0) return "tsp/cert-binding-mismatch";
470
- if (essCert.issuerSerial) {
471
- var signerCert;
472
- try { signerCert = pkiX509.parse(tsaCertDer); }
473
- catch (_e) { return "tsp/bad-signing-certificate"; }
474
- if (essCert.issuerSerial.serialNumber !== signerCert.serialNumber) return "tsp/cert-binding-mismatch";
475
- var names = essCert.issuerSerial.issuer.names || [];
476
- var gn = null;
477
- try { if (names.length === 1) gn = schemaTsp.decodeGeneralName(names[0].bytes); }
478
- catch (_e) { return "tsp/cert-binding-mismatch"; }
479
- if (!gn || gn.tagNumber !== 4 || !gn.value || !guard.name.dnEqual(gn.value.rdns, signerCert.issuer.rdns, _err, "tsp/cert-binding-mismatch", "the ESSCertID issuer")) {
480
- return "tsp/cert-binding-mismatch";
481
- }
489
+ var name = essCert.hashAlgorithm == null ? "sha1" : essCert.hashAlgorithm.name;
490
+ if (name === "sha1") return { essCert: essCert, nodeDigest: "sha1", weak: true };
491
+ if (!name || !intrinsic.hasOwn(_BIND_DIGEST, name)) return "tsp/unsupported-algorithm";
492
+ return { essCert: essCert, nodeDigest: _BIND_DIGEST[name], weak: false };
493
+ }
494
+
495
+ /** @internal Whether one ESSCertID names the certificate that signed the token, by every claim it
496
+ * carries: the hash under its own digest, and the issuer and serial where it states them. Returns
497
+ * true or the refusal code. An ESSCertID states the signer in two independent ways and both are
498
+ * compared, because a hash that agrees beside an issuer and serial that name another certificate is
499
+ * the same contradiction as two attributes disagreeing. Certificate identifiers after the first are
500
+ * not read: RFC 2634 sec. 5.4 makes the first the signing certificate and leaves the rest as the
501
+ * chain, so they say nothing about the signer. */
502
+ function _bindingNamesCert(read, tsaCertDer) {
503
+ /** @internal Through the captured digest: this comparison IS the binding between a token and the
504
+ * certificate its signing-certificate attribute names, so what the digest covers is not the
505
+ * caller's to choose. */
506
+ if (_compare(guard.crypto.digest(read.nodeDigest, tsaCertDer),
507
+ _bufferFrom(read.essCert.certHash)) !== 0) return "tsp/cert-binding-mismatch";
508
+ var issuerSerial = read.essCert.issuerSerial;
509
+ if (!issuerSerial) return true;
510
+ var signerCert;
511
+ try { signerCert = pkiX509.parse(tsaCertDer); }
512
+ catch (_e) { return "tsp/bad-signing-certificate"; }
513
+ if (issuerSerial.serialNumber !== signerCert.serialNumber) return "tsp/cert-binding-mismatch";
514
+ var names = issuerSerial.issuer.names || [];
515
+ var gn = null;
516
+ try { if (names.length === 1) gn = schemaTsp.decodeGeneralName(names[0].bytes); }
517
+ catch (_e2) { return "tsp/cert-binding-mismatch"; }
518
+ if (!gn || gn.tagNumber !== 4 || !gn.value || !guard.name.dnEqual(gn.value.rdns, signerCert.issuer.rdns, _err, "tsp/cert-binding-mismatch", "the ESSCertID issuer")) {
519
+ return "tsp/cert-binding-mismatch";
482
520
  }
483
521
  return true;
484
522
  }
485
523
 
524
+ function _checkCertBinding(signerInfo, tsaCertDer) {
525
+ var attrs = (signerInfo && signerInfo.signedAttrs) || [];
526
+ var binding = [];
527
+ for (var i = 0; i < attrs.length; i++) {
528
+ if (attrs[i].type === O("signingCertificateV2") || attrs[i].type === O("signingCertificate")) {
529
+ intrinsic.push(binding, attrs[i]);
530
+ }
531
+ }
532
+ if (!binding.length) return "tsp/missing-signing-certificate";
533
+ /** @internal A v2 binding supersedes a v1 one (RFC 5035), and that is why the verdict rests on the v2
534
+ * where there is one. But the v1 attribute does not stop existing: a token carrying both used to be
535
+ * checked against the v2 alone, so one naming the real signer in v2 and a DIFFERENT certificate in v1
536
+ * verified, and a legacy verifier reading only v1 resolves a certificate this one never checked. Both
537
+ * sit in signedAttrs, so the TSA signed the contradiction. One structure making two incompatible
538
+ * claims about one fact is refused rather than resolved in favor of whichever attribute a reader
539
+ * prefers.
540
+ * EVERY BINDING ATTRIBUTE IS COLLECTED, not the first of each type. signedAttrs is a DER SET OF,
541
+ * sorted by encoded value, so which of the two attributes comes first is a function of their lengths
542
+ * and the producer of a hostile token chooses it: a scan that stopped at the v2 caught the
543
+ * contradiction in one ordering and missed it in the other, and an ordering-dependent check is no
544
+ * check. The same applies to a repeated instance of either type, which `pki.cms.verify` refuses
545
+ * before this runs and which is not relied on here.
546
+ * THE SHA-1 ON A SUPERSEDED ATTRIBUTE PINS NOTHING. It detects a disagreement, while the binding the
547
+ * verdict rests on is the v2 one. A collision would let a disagreeing v1 pass for an agreeing one,
548
+ * which costs an attacker the refusal and gains them nothing: the certificate the token is held to is
549
+ * the one v2 names, under its own digest. */
550
+ var chosen = 0;
551
+ for (var j = 0; j < binding.length; j++) {
552
+ if (binding[j].type === O("signingCertificateV2")) { chosen = j; break; }
553
+ }
554
+ for (var k = 0; k < binding.length; k++) {
555
+ if (k === chosen) continue;
556
+ var alt = _readBinding(binding[k]);
557
+ if (typeof alt === "string") return alt;
558
+ var altCode = _bindingNamesCert(alt, tsaCertDer);
559
+ if (altCode !== true) return altCode;
560
+ }
561
+ var read = _readBinding(binding[chosen]);
562
+ if (typeof read === "string") return read;
563
+ /** @internal The refusal of a weak binding stands whatever `allowWeakDigests` says, because a binding
564
+ * is not the archived-signature case the option exists for. Whether it should follow the imprint and
565
+ * become an opt-in is a posture question, and the refusal was pinned deliberately, so it is left as
566
+ * it was. */
567
+ if (read.weak) return "tsp/weak-digest";
568
+ return _bindingNamesCert(read, tsaCertDer);
569
+ }
570
+
486
571
  function _checkTsaCertUsage(tsaCertDer) {
487
572
  var cert;
488
573
  try { cert = pkiX509.parse(tsaCertDer); }
@@ -540,12 +625,12 @@ function _buildTsaChains(leaf, pool) {
540
625
  if (guard.name.dnEqual(pool[i].subject.rdns, current.issuer.rdns, _err, "tsp/bad-tsa-certificate", "the TSA certificate subject")) {
541
626
  used[i] = true; guard.list.append(acc, pool[i]);
542
627
  dfs(pool[i], acc, used);
543
- acc.pop(); used[i] = false;
628
+ _pop(acc); used[i] = false;
544
629
  }
545
630
  }
546
631
  }
547
632
  dfs(leaf, [leaf], []);
548
- return chains.map(function (c) { return c.slice().reverse(); }).sort(function (a, b) { return b.length - a.length; });
633
+ return chains.map(function (c) { return _reverse(_arrSlice(c)); }).sort(function (a, b) { return b.length - a.length; });
549
634
  }
550
635
 
551
636
  /**
@@ -643,7 +728,7 @@ async function verify(token, data, opts) {
643
728
  if (!cmsRes.valid) return fail("tsp/bad-signature", signer && (signer.code || signer.message));
644
729
  var tsaCertDer = signer && signer.cert;
645
730
  if (!tsaCertDer) return fail("tsp/bad-signature", "the TSA signer certificate was not found");
646
- var mi = _imprintMatches(tst.messageImprint, data);
731
+ var mi = _imprintMatches(tst.messageImprint, data, opts.allowWeakDigests === true);
647
732
  if (mi !== true) return fail(mi);
648
733
  if (opts.nonce != null) {
649
734
  var wantNonce = guard.range.authoredInteger(opts.nonce, _err, "tsp/bad-input", "opts.nonce");