@blamejs/pki 0.6.39 → 0.6.40

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.
@@ -556,12 +556,12 @@ async function verifyMac(pfx, password, opts) {
556
556
  var m = _storeFromBytes(pfx);
557
557
  var valid = await _verifyMacOfStore(m, password, opts);
558
558
  var isHmac = m.mac.kind === "hmac";
559
- return {
559
+ return guard.verdict.of({
560
560
  valid: valid,
561
561
  macAlgorithm: m.mac.kind,
562
562
  macAlgorithmName: isHmac ? _toLower(m.mac.hashName || "") : m.mac.pbmac1.schemeName,
563
563
  iterationCount: isHmac ? m.mac.iterations : m.mac.pbmac1.kdf.iterationCount,
564
- };
564
+ });
565
565
  }
566
566
 
567
567
  async function _verifyMacOfStore(m, password, opts) {
@@ -669,13 +669,15 @@ async function open(pfx, password, opts) {
669
669
  } else if (!opts.allowUnauthenticated) {
670
670
  throw _err("pkcs12/no-integrity", "the store carries no integrity MAC (integrityMode " + m.integrityMode + "); set opts.allowUnauthenticated to open it anyway");
671
671
  }
672
- var out = { valid: macVerified || m.integrityMode === "public-key", integrityMode: m.integrityMode, macVerified: macVerified, signers: signers, keys: [], certs: [], crls: [], secrets: [] };
672
+ var out = guard.verdict.of({ valid: macVerified || m.integrityMode === "public-key", integrityMode: m.integrityMode, macVerified: macVerified, signers: signers, keys: [], certs: [], crls: [], secrets: [] });
673
673
  var i;
674
674
  var kdfBudget = { rounds: KDF_MAX_ROUNDS };
675
675
  for (i = 0; i < m.safeBags.length; i++) _openBag(m.safeBags[i], password, opts, out, 0, kdfBudget);
676
676
  for (i = 0; i < m.encryptedSafes.length; i++) await _openEncryptedSafe(m.encryptedSafes[i], password, opts, out, 0, kdfBudget);
677
677
  if (opts.keys === "crypto") {
678
- for (i = 0; i < out.keys.length; i++) out.keys[i].key = await key.import(out.keys[i].pkcs8, { algorithm: opts.importAlgorithm });
678
+ for (i = 0; i < out.keys.length; i++) {
679
+ guard.verdict.set(out.keys[i], "key", await key.import(out.keys[i].pkcs8, { algorithm: opts.importAlgorithm }));
680
+ }
679
681
  }
680
682
  return out;
681
683
  }
@@ -685,19 +687,19 @@ function _openBag(bag, password, opts, out, depth, budget) {
685
687
  case "keyBag":
686
688
  try { pkcs8.parse(bag.keyDer); }
687
689
  catch (e) { throw _err("pkcs12/bad-der", "a plaintext keyBag PrivateKeyInfo is not canonical DER", e); }
688
- out.keys.push({ pkcs8: bag.keyDer, encrypted: false, friendlyName: bag.friendlyName, localKeyId: bag.localKeyId });
690
+ guard.list.append(out.keys, { pkcs8: bag.keyDer, encrypted: false, friendlyName: bag.friendlyName, localKeyId: bag.localKeyId });
689
691
  break;
690
692
  case "pkcs8ShroudedKeyBag":
691
- out.keys.push({ pkcs8: _decryptShroudedKey(bag.encrypted, password, opts, budget), encrypted: true, friendlyName: bag.friendlyName, localKeyId: bag.localKeyId });
693
+ guard.list.append(out.keys, { pkcs8: _decryptShroudedKey(bag.encrypted, password, opts, budget), encrypted: true, friendlyName: bag.friendlyName, localKeyId: bag.localKeyId });
692
694
  break;
693
695
  case "certBag":
694
- out.certs.push({ cert: bag.certValue, certType: bag.certType, friendlyName: bag.friendlyName, localKeyId: bag.localKeyId });
696
+ guard.list.append(out.certs, { cert: bag.certValue, certType: bag.certType, friendlyName: bag.friendlyName, localKeyId: bag.localKeyId });
695
697
  break;
696
698
  case "crlBag":
697
- out.crls.push({ crl: bag.crlValue, crlType: bag.crlType, friendlyName: bag.friendlyName, localKeyId: bag.localKeyId });
699
+ guard.list.append(out.crls, { crl: bag.crlValue, crlType: bag.crlType, friendlyName: bag.friendlyName, localKeyId: bag.localKeyId });
698
700
  break;
699
701
  case "secretBag":
700
- out.secrets.push({ secretTypeId: bag.secretTypeId, secretTypeName: bag.secretTypeName, secretValue: bag.secretValue, friendlyName: bag.friendlyName, localKeyId: bag.localKeyId });
702
+ guard.list.append(out.secrets, { secretTypeId: bag.secretTypeId, secretTypeName: bag.secretTypeName, secretValue: bag.secretValue, friendlyName: bag.friendlyName, localKeyId: bag.localKeyId });
701
703
  break;
702
704
  case "safeContentsBag":
703
705
  if (depth + 1 > C.LIMITS.PKCS12_MAX_BAG_DEPTH) throw _err("pkcs12/too-deep", "safeContentsBag nesting exceeds the depth cap " + C.LIMITS.PKCS12_MAX_BAG_DEPTH);
package/lib/sigstore.js CHANGED
@@ -360,10 +360,19 @@ function _normRoots(fulcioRoots) {
360
360
 
361
361
  function _pathToAnchor(leaf, anchor, intBySubject) {
362
362
  var anchorSubj = _dn(anchor, "subject");
363
- var path = [leaf], cur = leaf, seen = {}, guardN = 0;
363
+ /** @internal Issuers are collected leaf-first and the path is assembled once, so no element is
364
+ * ever moved to a new index: an indexed setter has nothing to intercept and cannot replace the
365
+ * leaf the preceding signature checks authenticated. */
366
+ var above = [], cur = leaf, seen = {}, guardN = 0;
367
+ function assemble() {
368
+ var path = [];
369
+ for (var k = above.length - 1; k >= 0; k--) guard.list.append(path, above[k]);
370
+ guard.list.append(path, leaf);
371
+ return path;
372
+ }
364
373
  while (guardN++ < 16) {
365
374
  var issuerDn = _dn(cur, "issuer");
366
- if (issuerDn === anchorSubj) return path;
375
+ if (issuerDn === anchorSubj) return assemble();
367
376
  var cands = intBySubject[issuerDn] || [];
368
377
  var next = null;
369
378
  for (var j = 0; j < cands.length; j++) {
@@ -372,7 +381,7 @@ function _pathToAnchor(leaf, anchor, intBySubject) {
372
381
  }
373
382
  if (!next) return null;
374
383
  seen[_dn(next, "subject")] = 1;
375
- path.unshift(next);
384
+ guard.list.append(above, next);
376
385
  cur = next;
377
386
  }
378
387
  return null;
@@ -382,7 +391,7 @@ async function _verifyChain(leaf, chainDers, fulcioRoots, timeMs) {
382
391
  var roots = _normRoots(fulcioRoots);
383
392
  var bundleLinks = chainDers.slice(1).map(function (d, i) { return _parseCert(d, "bundle intermediate [" + i + "]"); });
384
393
  var intBySubject = {};
385
- function addInt(c) { (intBySubject[_dn(c, "subject")] = intBySubject[_dn(c, "subject")] || []).push(c); }
394
+ function addInt(c) { guard.list.append(intBySubject[_dn(c, "subject")] = intBySubject[_dn(c, "subject")] || [], c); }
386
395
  roots.forEach(function (r) { addInt(r.cert); });
387
396
  bundleLinks.forEach(addInt);
388
397
  var candidates = roots.filter(function (r) { return _inWindow(timeMs, r.validFor); });
@@ -446,7 +455,7 @@ function _sanValue(ext) {
446
455
  }
447
456
  val = { type: "otherName", oid: asn1.read.oid(n.children[0]), value: v };
448
457
  }
449
- if (val) names.push(val);
458
+ if (val) guard.list.append(names, val);
450
459
  }
451
460
  if (names.length > 1) throw _err("sigstore/bad-certificate", "the Fulcio certificate carries multiple SAN identities");
452
461
  return names[0] || null;
@@ -582,7 +591,7 @@ async function verifyBundle(bundle, opts) {
582
591
 
583
592
  var st = _statement(payload, env.payloadType, opts.predicateType);
584
593
 
585
- return {
594
+ return guard.verdict.of({
586
595
  valid: true,
587
596
  verified: true,
588
597
  payload: payload,
@@ -596,7 +605,7 @@ async function verifyBundle(bundle, opts) {
596
605
  integratedTime: integratedTime,
597
606
  logIndex: rekor.logIndex,
598
607
  logId: rekor.logId,
599
- };
608
+ });
600
609
  }
601
610
 
602
611
  module.exports = {
package/lib/smime.js CHANGED
@@ -334,7 +334,7 @@ function _signerEmails(certDer) {
334
334
  catch (sanFailed) { out.unreadable++; out.reason = sanFailed.code || "bad-san"; }
335
335
  if (dec === null) return;
336
336
  (dec.names || []).forEach(function (n) {
337
- if (n.tagNumber === 1) { out.addresses.push(String(n.value)); return; }
337
+ if (n.tagNumber === 1) { guard.list.append(out.addresses, String(n.value)); return; }
338
338
  if (n.tagNumber !== 0) return;
339
339
  var typeId = n.value && typeof n.value === "object" ? n.value.typeId : undefined;
340
340
  if (typeId === undefined) { out.unreadable++; return; }
@@ -346,7 +346,7 @@ function _signerEmails(certDer) {
346
346
  (rdns || []).forEach(function (rdn) {
347
347
  (rdn || []).forEach(function (attr) {
348
348
  if (!attr || attr.type !== EMAIL_ADDRESS_ATTR || typeof attr.value !== "string") return;
349
- if (out.addresses.indexOf(attr.value) === -1) out.addresses.push(attr.value);
349
+ if (out.addresses.indexOf(attr.value) === -1) guard.list.append(out.addresses, attr.value);
350
350
  });
351
351
  });
352
352
  return out;
@@ -362,7 +362,7 @@ function _senderSurface(signers, outerEnt, expectedSender) {
362
362
  }
363
363
  else {
364
364
  var froms = [];
365
- outerEnt.headers.forEach(function (h) { if (h.lname === "from") froms.push(h.value.trim()); });
365
+ outerEnt.headers.forEach(function (h) { if (h.lname === "from") guard.list.append(froms, h.value.trim()); });
366
366
  if (froms.length === 1) { expected = _addrSpec(froms[0]); source = expected === null ? null : "from"; }
367
367
  }
368
368
  var identities = [], undecidable = false, sawIdentity = false;
@@ -371,7 +371,7 @@ function _senderSurface(signers, outerEnt, expectedSender) {
371
371
  var e = s.cert ? _signerEmails(s.cert) : null;
372
372
  if (e === null) { undecidable = true; return; }
373
373
  if (e.unreadable > 0) { undecidable = true; sawIdentity = true; }
374
- e.addresses.forEach(function (a) { sawIdentity = true; if (identities.indexOf(a) === -1) identities.push(a); });
374
+ e.addresses.forEach(function (a) { sawIdentity = true; if (identities.indexOf(a) === -1) guard.list.append(identities, a); });
375
375
  });
376
376
  if (expected === null) return { checked: false, expected: null, source: null, identities: identities, match: null };
377
377
  if (!sawIdentity) return { checked: true, expected: expected, source: source, identities: identities, match: null };
package/lib/tsp-sign.js CHANGED
@@ -171,9 +171,9 @@ function _sign(messageImprint, tsa, opts) {
171
171
  var genTime = guard.time.isDate(opts.genTime) ? opts.genTime : new Date();
172
172
  var serial = guard.range.authoredInteger(opts.serialNumber, _err, "tsp/bad-input", "serialNumber");
173
173
  var fields = [b.integer(1n), _policy(opts.policy), imprint, b.integer(serial), b.generalizedTime(genTime)];
174
- if (opts.accuracy) fields.push(_accuracy(opts.accuracy));
175
- if (opts.ordering === true) fields.push(b.boolean(true));
176
- if (opts.nonce != null) fields.push(b.integer(guard.range.authoredInteger(opts.nonce, _err, "tsp/bad-input", "nonce")));
174
+ if (opts.accuracy) guard.list.append(fields,_accuracy(opts.accuracy));
175
+ if (opts.ordering === true) guard.list.append(fields,b.boolean(true));
176
+ if (opts.nonce != null) guard.list.append(fields,b.integer(guard.range.authoredInteger(opts.nonce, _err, "tsp/bad-input", "nonce")));
177
177
  var tstInfo = b.sequence(fields);
178
178
 
179
179
  var signCert = { type: "signingCertificateV2", values: [_signingCertV2(certDer, certHashAlg)] };
@@ -199,10 +199,10 @@ function _accuracy(a) {
199
199
  if (typeof sec !== "number" && typeof sec !== "bigint") throw _err("tsp/bad-input", "Accuracy seconds must be a non-negative integer, got " + guard.text.showValue(sec));
200
200
  var s = intrinsic.Number(sec);
201
201
  if (!Number.isInteger(s) || s < 0 || s > 0x7fffffff) throw _err("tsp/bad-input", "Accuracy seconds must be a non-negative integer");
202
- f.push(b.integer(BigInt(s)));
202
+ guard.list.append(f,b.integer(BigInt(s)));
203
203
  }
204
- if (mil != null) f.push(b.contextPrimitive(0, _subMilliBytes(mil, "millis")));
205
- if (mic != null) f.push(b.contextPrimitive(1, _subMilliBytes(mic, "micros")));
204
+ if (mil != null) guard.list.append(f,b.contextPrimitive(0, _subMilliBytes(mil, "millis")));
205
+ if (mic != null) guard.list.append(f,b.contextPrimitive(1, _subMilliBytes(mic, "micros")));
206
206
  return b.sequence(f);
207
207
  }
208
208
  function _subMilliBytes(n, label) {
@@ -276,10 +276,10 @@ function request(messageImprint, opts) {
276
276
  _assertImprint(mi);
277
277
  var imprint = b.sequence([_hashAlgId(mi.hashAlgorithm), b.octetString(guard.bytes.source(mi.hashedMessage, TspError, "tsp/bad-input", "messageImprint.hashedMessage"))]);
278
278
  var fields = [b.integer(1n), imprint];
279
- if (opts.reqPolicy != null) fields.push(_policy(opts.reqPolicy));
280
- if (opts.nonce != null) fields.push(b.integer(guard.range.authoredInteger(opts.nonce, _err, "tsp/bad-input", "nonce")));
279
+ if (opts.reqPolicy != null) guard.list.append(fields,_policy(opts.reqPolicy));
280
+ if (opts.nonce != null) guard.list.append(fields,b.integer(guard.range.authoredInteger(opts.nonce, _err, "tsp/bad-input", "nonce")));
281
281
  if (opts.certReq != null && typeof opts.certReq !== "boolean") throw _err("tsp/bad-input", "certReq must be a boolean");
282
- if (opts.certReq === true) fields.push(b.boolean(true));
282
+ if (opts.certReq === true) guard.list.append(fields,b.boolean(true));
283
283
  if (opts.extensions != null) {
284
284
  if (!Array.isArray(opts.extensions) || !guard.list.allMatch(opts.extensions, function (e) { return guard.bytes.isByteSource(e); })) throw _err("tsp/bad-input", "extensions must be an array of encoded Extension DER buffers");
285
285
  var seenExt = {};
@@ -291,7 +291,7 @@ function request(messageImprint, opts) {
291
291
  seenExt[extnId] = true;
292
292
  return der;
293
293
  });
294
- if (encoded.length) fields.push(b.contextConstructed(0, Buffer.concat(encoded)));
294
+ if (encoded.length) guard.list.append(fields,b.contextConstructed(0, Buffer.concat(encoded)));
295
295
  }
296
296
  var der = b.sequence(fields);
297
297
  return opts.pem ? schemaTsp.pemEncode(der, "TIMESTAMP REQUEST") : der;
@@ -364,14 +364,14 @@ function response(token, opts) {
364
364
  if (opts.statusString != null) {
365
365
  var texts = Array.isArray(opts.statusString) ? opts.statusString : [opts.statusString];
366
366
  if (!texts.length) throw _err("tsp/bad-input", "statusString must carry at least one PKIFreeText element (RFC 4210 SEQUENCE SIZE 1..MAX)");
367
- siFields.push(b.sequence(texts.map(function (t) { return b.utf8(String(t)); })));
367
+ guard.list.append(siFields,b.sequence(texts.map(function (t) { return b.utf8(String(t)); })));
368
368
  }
369
369
  if (opts.failInfo != null) {
370
370
  if (status !== 2) throw _err("tsp/unexpected-failinfo", "failInfo is present only when the status is rejection(2) (RFC 3161 sec. 2.4.2)");
371
- siFields.push(_failInfoBits(opts.failInfo));
371
+ guard.list.append(siFields,_failInfoBits(opts.failInfo));
372
372
  }
373
373
  var respFields = [b.sequence(siFields)];
374
- if (token != null) respFields.push(b.raw(_tokenDer(token)));
374
+ if (token != null) guard.list.append(respFields, b.raw(_tokenDer(token)));
375
375
  var der = b.sequence(respFields);
376
376
  return opts.pem ? schemaTsp.pemEncode(der, "TIMESTAMP RESPONSE") : der;
377
377
  }
@@ -508,12 +508,12 @@ function _buildTsaChains(leaf, pool) {
508
508
  var chains = [];
509
509
  function dfs(current, acc, used) {
510
510
  if (chains.length >= MAX_TSA_CHAINS) return;
511
- chains.push(acc.slice());
511
+ guard.list.append(chains, acc.slice());
512
512
  for (var i = 0; i < pool.length && chains.length < MAX_TSA_CHAINS; i++) {
513
513
  if (used[i]) continue;
514
514
  if (pool[i].serialNumberHex === current.serialNumberHex && guard.name.dnEqual(pool[i].issuer.rdns, current.issuer.rdns, _err, "tsp/bad-tsa-certificate", "the TSA certificate issuer")) continue;
515
515
  if (guard.name.dnEqual(pool[i].subject.rdns, current.issuer.rdns, _err, "tsp/bad-tsa-certificate", "the TSA certificate subject")) {
516
- used[i] = true; acc.push(pool[i]);
516
+ used[i] = true; guard.list.append(acc, pool[i]);
517
517
  dfs(pool[i], acc, used);
518
518
  acc.pop(); used[i] = false;
519
519
  }
@@ -605,7 +605,7 @@ async function verify(token, data, opts) {
605
605
  var revocationChecked = false;
606
606
  var anchorConstraints = null;
607
607
  function fail(code, reason) {
608
- return { valid: false, trusted: false, revocationChecked: revocationChecked, anchorConstraints: anchorConstraints, code: code, reason: reason || null, genTime: tst.genTime, accuracy: tst.accuracy, serialNumber: tst.serialNumber, serialNumberHex: tst.serialNumberHex, policy: tst.policy, policyName: tst.policyName, nonce: tst.nonce, tsa: tst.tsa, tstInfo: tst, signer: null };
608
+ return guard.verdict.of({ valid: false, trusted: false, revocationChecked: revocationChecked, anchorConstraints: anchorConstraints, code: code, reason: reason || null, genTime: tst.genTime, accuracy: tst.accuracy, serialNumber: tst.serialNumber, serialNumberHex: tst.serialNumberHex, policy: tst.policy, policyName: tst.policyName, nonce: tst.nonce, tsa: tst.tsa, tstInfo: tst, signer: null });
609
609
  }
610
610
  var cmsRes = await cmsVerify.verify(tokenDer, { certs: opts.certs });
611
611
  var signer = cmsRes.signers[0];
@@ -642,7 +642,7 @@ async function verify(token, data, opts) {
642
642
  var ceilT = (tst.genTimeFraction != null && _hasNonZeroDigit(tst.genTimeFraction.slice(3))) ? new Date(guard.time.instantOf(floorT) + 1) : floorT;
643
643
  try {
644
644
  var pool = (parsed.certificates || []).filter(function (c) { return c.tagClass === "universal"; }).map(function (c) { return pkiX509.parse(c.bytes); });
645
- (opts.certs || []).forEach(function (c) { pool.push(pkiX509.parse(c)); });
645
+ (opts.certs || []).forEach(function (c) { guard.list.append(pool, pkiX509.parse(c)); });
646
646
  async function validateAt(chain, when) {
647
647
  var res = await pathValidate.validate(chain, {
648
648
  time: when, trustAnchors: opts.trustAnchors, requiredEku: ["timeStamping"], checkPurpose: "timeStamping", revocationChecker: opts.revocationChecker,
@@ -662,13 +662,13 @@ async function verify(token, data, opts) {
662
662
  anchorConstraints = pathRes.anchorConstraints;
663
663
  trusted = true;
664
664
  }
665
- return {
665
+ return guard.verdict.of({
666
666
  valid: true, trusted: trusted, revocationChecked: revocationChecked, anchorConstraints: anchorConstraints,
667
667
  genTime: tst.genTime, accuracy: tst.accuracy,
668
668
  serialNumber: tst.serialNumber, serialNumberHex: tst.serialNumberHex,
669
669
  policy: tst.policy, policyName: tst.policyName, nonce: tst.nonce, tsa: tst.tsa,
670
670
  tstInfo: tst, signer: { cert: tsaCertDer, sid: signer.sid },
671
- };
671
+ });
672
672
  }
673
673
 
674
674
  module.exports = { sign: sign, request: request, parseRequest: parseRequest, response: response, parseResponse: parseResponse, verify: verify };
package/lib/webauthn.js CHANGED
@@ -395,8 +395,8 @@ function _applyCallerRoots(res, supplied, vopts, onlyPaths) {
395
395
  .map(function (el) { return { tp: el.trustPath, at: el.chainValidatedAt }; })
396
396
  : (res.trustPath && res.trustPath.length ? [{ tp: res.trustPath, at: res.chainValidatedAt }] : []));
397
397
  if (!onlyPaths) {
398
- res.anchoredElements = { total: (res.fmt === "compound" && Array.isArray(res.compound)) ? res.compound.length : 1,
399
- anchored: paths.length };
398
+ res = guard.verdict.of(res, { anchoredElements: { total: (res.fmt === "compound" && Array.isArray(res.compound)) ? res.compound.length : 1,
399
+ anchored: paths.length } });
400
400
  }
401
401
  if (!paths.length) {
402
402
  throw _err("webauthn/anchor-not-applicable",
@@ -410,8 +410,7 @@ function _applyCallerRoots(res, supplied, vopts, onlyPaths) {
410
410
  "attestation trust path (against the roots supplied as opts.rootCertificates)");
411
411
  });
412
412
  }, Promise.resolve()).then(function () {
413
- res.anchoredTo = _anchoredRoutes(res, "rootCertificates");
414
- return res;
413
+ return guard.verdict.of(res, { anchoredTo: _anchoredRoutes(res, "rootCertificates") });
415
414
  });
416
415
  }
417
416
 
@@ -425,7 +424,7 @@ function _safetyNetAnchored(res) {
425
424
 
426
425
  function _anchoredRoutes(res, base) {
427
426
  var routes = base ? base.split("+") : [];
428
- if (_safetyNetAnchored(res) && routes.indexOf("safetyNetRoots") < 0) routes.push("safetyNetRoots");
427
+ if (_safetyNetAnchored(res) && routes.indexOf("safetyNetRoots") < 0) guard.list.append(routes, "safetyNetRoots");
429
428
  return routes.length ? routes.join("+") : null;
430
429
  }
431
430
 
@@ -604,9 +603,8 @@ var VERIFIERS = {
604
603
  _checkAikCert(aik);
605
604
  _checkAaguidExt(aik, att.authData.aaguid);
606
605
  validator.tpm.assertObjectAttributePolicy(pub, tpmPolicy, WebauthnError, "webauthn/tpm-policy", "webauthn/bad-tpm");
607
- var tpmRes = _result("tpm", "AttCA", chain, att);
608
- tpmRes.tpm = { objectAttributes: pub.objectAttributes, attributes: pub.attributes, authPolicy: pub.authPolicy };
609
- return tpmRes;
606
+ return guard.verdict.of(_result("tpm", "AttCA", chain, att),
607
+ { tpm: { objectAttributes: pub.objectAttributes, attributes: pub.attributes, authPolicy: pub.authPolicy } });
610
608
  });
611
609
  },
612
610
 
@@ -680,9 +678,8 @@ var VERIFIERS = {
680
678
  ? new Date(payload.timestampMs) : undefined);
681
679
  return _safetyNetChainTrusted(chain, roots, chainAt);
682
680
  }).then(function () {
683
- var res = _result("android-safetynet", "Basic", chain, att);
684
- res.safetyNet = signals;
685
- if (chainAt !== undefined) res.chainValidatedAt = chainAt;
681
+ var res = guard.verdict.of(_result("android-safetynet", "Basic", chain, att), { safetyNet: signals });
682
+ if (chainAt !== undefined) res = guard.verdict.of(res, { chainValidatedAt: chainAt });
686
683
  return res;
687
684
  });
688
685
  },
@@ -710,14 +707,12 @@ var VERIFIERS = {
710
707
  return elements.reduce(function (p, e) {
711
708
  return p.then(function () {
712
709
  return Promise.resolve().then(function () { return VERIFIERS[e.fmt](e.att, clientDataHash, opts); })
713
- .then(function (r) { out.push(r); }, function (err) {
710
+ .then(function (r) { guard.list.append(out, r); }, function (err) {
714
711
  throw _err("webauthn/compound-element-failed", "compound element " + e.index + " (format '" + e.fmt + "') did not verify", err);
715
712
  });
716
713
  });
717
714
  }, Promise.resolve()).then(function () {
718
- var res = _result("compound", "Compound", [], att);
719
- res.compound = out;
720
- return res;
715
+ return guard.verdict.of(_result("compound", "Compound", [], att), { compound: out });
721
716
  });
722
717
  },
723
718
 
@@ -761,7 +756,7 @@ function _safetyNetChainTrusted(chain, roots, time) {
761
756
  }
762
757
 
763
758
  function _result(fmt, attestationType, chain, att) {
764
- return {
759
+ return guard.verdict.of({
765
760
  valid: true, attestationVerified: true, fmt: fmt, attestationType: attestationType,
766
761
  trustPath: (chain || []).slice().reverse(),
767
762
  aaguid: att.authData.aaguid,
@@ -772,7 +767,7 @@ function _result(fmt, attestationType, chain, att) {
772
767
  flags: att.authData.flags,
773
768
  rpIdHash: att.authData.rpIdHash,
774
769
  extensions: att.authData.extensions,
775
- };
770
+ });
776
771
  }
777
772
 
778
773
  function _appleNonce(extValue) {
@@ -969,37 +964,41 @@ function verify(attestationObject, clientDataHash, opts) {
969
964
  } catch (e) { return Promise.reject(e); }
970
965
  return Promise.resolve().then(function () { return verifier(att, clientDataHash, vopts); })
971
966
  .then(function (res) {
972
- res.clientData = clientData;
973
- return res;
967
+ return guard.verdict.of(res, { clientData: clientData });
974
968
  })
975
969
  .then(function (res) {
976
970
  if (vopts.metadata === undefined) {
977
971
  if (vopts.rootCertificates !== undefined) return _applyCallerRoots(res, vopts.rootCertificates, vopts);
978
- res.anchoredTo = _anchoredRoutes(res, null);
979
- var sn = _safetyNetAnchored(res);
972
+ var anchored = guard.verdict.of(res, { anchoredTo: _anchoredRoutes(res, null) });
973
+ var sn = _safetyNetAnchored(anchored);
980
974
  if (sn) {
981
- res.anchoredElements = { total: (res.fmt === "compound" && Array.isArray(res.compound)) ? res.compound.length : 1,
982
- anchored: sn };
975
+ anchored = guard.verdict.of(anchored, { anchoredElements: {
976
+ total: (anchored.fmt === "compound" && Array.isArray(anchored.compound)) ? anchored.compound.length : 1,
977
+ anchored: sn } });
983
978
  }
984
- return res;
979
+ return anchored;
985
980
  }
986
981
  return Promise.resolve().then(function () { return _applyMetadata(res, att, vopts); })
987
- .then(function (out) { out.anchoredTo = _anchoredRoutes(out, "metadata"); return out; }, function (e) {
982
+ .then(function (out) { return guard.verdict.of(out, { anchoredTo: _anchoredRoutes(out, "metadata") }); }, function (e) {
988
983
  if (!e || e.code !== "webauthn/metadata-not-found" || vopts.rootCertificates === undefined) throw e;
989
984
  return Promise.resolve(_applyCallerRoots(res, vopts.rootCertificates, vopts, e.missedPaths))
990
- .then(function (out) {
985
+ .then(function (withRoots) {
986
+ /** @internal The element coverage the metadata attempt measured is the whole
987
+ * statement's, so it travels on the error rather than being recomputed from the
988
+ * fallback's own paths. */
989
+ var out = e.anchoredElements ? guard.verdict.of(withRoots, { anchoredElements: e.anchoredElements }) : withRoots;
991
990
  var applied = e.appliedEntries || [];
992
991
  if (!applied.length) return out;
993
992
  var primary = applied[0];
994
- out.metadata = { aaguid: primary.entry.aaguid, keyIdentifiers: primary.entry.keyIdentifiers || [],
993
+ var withMd = guard.verdict.of(out, { metadata: { aaguid: primary.entry.aaguid,
994
+ keyIdentifiers: primary.entry.keyIdentifiers || [],
995
995
  entry: primary.entry, entries: applied.map(function (a) { return a.entry; }),
996
- anchors: primary.anchors.length };
997
- out.anchoredTo = _anchoredRoutes(out, "metadata+rootCertificates");
998
- return out;
996
+ anchors: primary.anchors.length } });
997
+ return guard.verdict.of(withMd, { anchoredTo: _anchoredRoutes(withMd, "metadata+rootCertificates") });
999
998
  });
1000
999
  });
1001
1000
  })
1002
- .then(function (res) { res.bindingChecked = bindingChecked; return res; });
1001
+ .then(function (res) { return guard.verdict.of(res, { bindingChecked: bindingChecked }); });
1003
1002
  }
1004
1003
 
1005
1004
  function _applyMetadata(res, att, opts) {
@@ -1011,8 +1010,9 @@ function _applyMetadata(res, att, opts) {
1011
1010
  ? res.compound.filter(function (el) { return el.trustPath && el.trustPath.length; })
1012
1011
  .map(function (el) { return { tp: el.trustPath, fmt: el.fmt, at: el.chainValidatedAt }; })
1013
1012
  : (res.trustPath && res.trustPath.length ? [{ tp: res.trustPath, fmt: res.fmt, at: res.chainValidatedAt }] : []);
1014
- res.anchoredElements = { total: (res.fmt === "compound" && Array.isArray(res.compound)) ? res.compound.length : 1,
1015
- anchored: paths.length };
1013
+ res = guard.verdict.of(res, { anchoredElements: {
1014
+ total: (res.fmt === "compound" && Array.isArray(res.compound)) ? res.compound.length : 1,
1015
+ anchored: paths.length } });
1016
1016
  if (!paths.length) {
1017
1017
  throw _err("webauthn/metadata-not-applicable", "opts.metadata was supplied, but this attestation carries no trust path to anchor (format '" + res.fmt + "')");
1018
1018
  }
@@ -1036,7 +1036,7 @@ function _applyMetadata(res, att, opts) {
1036
1036
  }
1037
1037
  var anchors = mds.metadataAnchors(entry, { metadata: md, time: at, certificate: tp[tp.length - 1] });
1038
1038
  if (!anchors.length) throw _err("webauthn/metadata-no-anchor", "the metadata entry for " + identifier + " supplies no attestation root certificate");
1039
- applied.push({ entry: entry, anchors: anchors, identifier: identifier });
1039
+ guard.list.append(applied, { entry: entry, anchors: anchors, identifier: identifier });
1040
1040
  return { anchors: anchors, identifier: identifier };
1041
1041
  }
1042
1042
  var at = opts.time !== undefined ? opts.time : new Date();
@@ -1046,13 +1046,17 @@ function _applyMetadata(res, att, opts) {
1046
1046
  var missedPaths = [];
1047
1047
  for (var gi = 0; gi < paths.length; gi++) {
1048
1048
  try {
1049
- governed.push({ info: paths[gi], g: govern(paths[gi]) });
1049
+ guard.list.append(governed, { info: paths[gi], g: govern(paths[gi]) });
1050
1050
  } catch (ge) {
1051
- if (ge && ge.code === "webauthn/metadata-not-found") { missed = missed || ge; missedPaths.push(paths[gi]); continue; }
1051
+ if (ge && ge.code === "webauthn/metadata-not-found") { missed = missed || ge; guard.list.append(missedPaths, paths[gi]); continue; }
1052
1052
  throw ge;
1053
1053
  }
1054
1054
  }
1055
- if (missed) { missed.missedPaths = missedPaths; missed.appliedEntries = applied; }
1055
+ if (missed) {
1056
+ guard.verdict.set(missed, "missedPaths", missedPaths);
1057
+ guard.verdict.set(missed, "appliedEntries", applied);
1058
+ guard.verdict.set(missed, "anchoredElements", res.anchoredElements);
1059
+ }
1056
1060
  return governed.reduce(function (p, item) {
1057
1061
  return p.then(function () {
1058
1062
  var g = item.g, info = item.info;
@@ -1064,10 +1068,10 @@ function _applyMetadata(res, att, opts) {
1064
1068
  .then(function () {
1065
1069
  if (missed) throw missed;
1066
1070
  var primary = applied[0];
1067
- res.metadata = { aaguid: primary.entry.aaguid, keyIdentifiers: primary.entry.keyIdentifiers || [],
1071
+ return guard.verdict.of(res, { metadata: { aaguid: primary.entry.aaguid,
1072
+ keyIdentifiers: primary.entry.keyIdentifiers || [],
1068
1073
  entry: primary.entry, entries: applied.map(function (a) { return a.entry; }),
1069
- anchors: primary.anchors.length };
1070
- return res;
1074
+ anchors: primary.anchors.length } });
1071
1075
  });
1072
1076
  }
1073
1077
 
@@ -1558,7 +1562,7 @@ function verifyAssertion(input) {
1558
1562
  signCountChecked = true;
1559
1563
  }
1560
1564
  }
1561
- return {
1565
+ return guard.verdict.of({
1562
1566
  valid: true,
1563
1567
  signatureVerified: true,
1564
1568
  signCount: authData.signCount,
@@ -1568,7 +1572,7 @@ function verifyAssertion(input) {
1568
1572
  extensions: authData.extensions,
1569
1573
  clientData: clientData,
1570
1574
  bindingChecked: bindingChecked,
1571
- };
1575
+ });
1572
1576
  });
1573
1577
  });
1574
1578
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blamejs/pki",
3
- "version": "0.6.39",
3
+ "version": "0.6.40",
4
4
  "description": "Pure-JavaScript PKI toolkit that owns its stack — X.509, ASN.1/DER, CMS, PQC-first.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "blamejs contributors",
package/sbom.cdx.json CHANGED
@@ -2,10 +2,10 @@
2
2
  "$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
3
3
  "bomFormat": "CycloneDX",
4
4
  "specVersion": "1.5",
5
- "serialNumber": "urn:uuid:b1c86284-d109-4852-8e85-dc5992b74178",
5
+ "serialNumber": "urn:uuid:2af62d9e-82a4-4f11-8c8c-7b2c8b1ae891",
6
6
  "version": 1,
7
7
  "metadata": {
8
- "timestamp": "2026-09-05T11:25:26.514Z",
8
+ "timestamp": "2026-09-05T15:01:32.918Z",
9
9
  "lifecycles": [
10
10
  {
11
11
  "phase": "build"
@@ -19,14 +19,14 @@
19
19
  }
20
20
  ],
21
21
  "component": {
22
- "bom-ref": "@blamejs/pki@0.6.39",
22
+ "bom-ref": "@blamejs/pki@0.6.40",
23
23
  "type": "application",
24
24
  "name": "pki",
25
- "version": "0.6.39",
25
+ "version": "0.6.40",
26
26
  "scope": "required",
27
27
  "author": "blamejs contributors",
28
28
  "description": "Pure-JavaScript PKI toolkit that owns its stack — X.509, ASN.1/DER, CMS, PQC-first.",
29
- "purl": "pkg:npm/%40blamejs/pki@0.6.39",
29
+ "purl": "pkg:npm/%40blamejs/pki@0.6.40",
30
30
  "properties": [],
31
31
  "externalReferences": [
32
32
  {
@@ -54,7 +54,7 @@
54
54
  "components": [],
55
55
  "dependencies": [
56
56
  {
57
- "ref": "@blamejs/pki@0.6.39",
57
+ "ref": "@blamejs/pki@0.6.40",
58
58
  "dependsOn": []
59
59
  }
60
60
  ]