@blamejs/pki 0.5.31 → 0.5.32

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 (51) hide show
  1. package/CHANGELOG.md +16 -1
  2. package/README.md +2 -2
  3. package/lib/acme.js +347 -90
  4. package/lib/asn1-der.js +93 -33
  5. package/lib/cmc-build.js +19 -8
  6. package/lib/cmc-verify.js +4 -4
  7. package/lib/cmp-build.js +36 -6
  8. package/lib/cmp-session.js +5 -5
  9. package/lib/cmp-verify.js +86 -16
  10. package/lib/cms-compress.js +2 -2
  11. package/lib/cms-decrypt.js +3 -3
  12. package/lib/cms-encrypt.js +1 -1
  13. package/lib/cms-sign.js +7 -7
  14. package/lib/cms-verify.js +9 -4
  15. package/lib/crl-sign.js +4 -4
  16. package/lib/crmf-sign.js +2 -1
  17. package/lib/csr-sign.js +1 -4
  18. package/lib/ct.js +8 -4
  19. package/lib/est.js +234 -34
  20. package/lib/framework-error.js +20 -6
  21. package/lib/guard-bytes.js +24 -3
  22. package/lib/http-digest.js +69 -16
  23. package/lib/http-retry-after.js +68 -24
  24. package/lib/http-transport.js +60 -6
  25. package/lib/inspect.js +13 -2
  26. package/lib/key.js +2 -2
  27. package/lib/lint.js +1 -1
  28. package/lib/mime.js +27 -4
  29. package/lib/ocsp.js +7 -7
  30. package/lib/oid.js +16 -0
  31. package/lib/path-validate.js +76 -18
  32. package/lib/pbes2.js +2 -2
  33. package/lib/pkcs12-build.js +2 -2
  34. package/lib/pki-build.js +6 -6
  35. package/lib/rfc3339.js +75 -17
  36. package/lib/schema-c509.js +36 -9
  37. package/lib/schema-cmc.js +3 -3
  38. package/lib/schema-pkix.js +174 -25
  39. package/lib/schema-tsp.js +10 -1
  40. package/lib/sign-scheme.js +1 -1
  41. package/lib/sigstore.js +52 -9
  42. package/lib/smime.js +86 -6
  43. package/lib/trust.js +114 -14
  44. package/lib/tsp-sign.js +39 -27
  45. package/lib/validator-tpm.js +2 -2
  46. package/lib/webauthn-mds.js +24 -6
  47. package/lib/webauthn.js +3 -3
  48. package/lib/webcrypto.js +1 -1
  49. package/lib/x509-sign.js +1 -1
  50. package/package.json +1 -1
  51. package/sbom.cdx.json +6 -6
package/lib/ocsp.js CHANGED
@@ -84,7 +84,7 @@ function _responseFromBytes(response) {
84
84
  }
85
85
 
86
86
  function _toDer(input, what) {
87
- if (Buffer.isBuffer(input) || input instanceof Uint8Array) return guard.bytes.snapshot(input, OcspError, "ocsp/bad-input", what || "input");
87
+ if (guard.bytes.isByteSource(input)) return guard.bytes.snapshotSource(input, OcspError, "ocsp/bad-input", what || "input");
88
88
  if (typeof input === "string") { try { return ocspSchema.pemDecode(input); } catch (e) { throw _err("ocsp/bad-input", (what || "input") + " PEM could not be decoded", e); } }
89
89
  throw _err("ocsp/bad-input", (what || "input") + " must be a DER Buffer, Uint8Array, or PEM string");
90
90
  }
@@ -221,16 +221,16 @@ function _buildRequest(query, opts) {
221
221
  }
222
222
  function _emitReq(der, opts) { return opts.pem ? ocspSchema.pemEncode(der, "OCSP REQUEST") : der; }
223
223
  function _nameDer(name) {
224
- if (Buffer.isBuffer(name)) return guard.bytes.snapshot(name, OcspError, "ocsp/bad-input", "requestorName");
224
+ if (guard.bytes.isByteSource(name)) return guard.bytes.snapshotSource(name, OcspError, "ocsp/bad-input", "requestorName");
225
225
  if (name && name.bytes) return name.bytes; // a parsed Name
226
- throw _err("ocsp/bad-input", "requestorName must be a DER Name Buffer or a parsed Name");
226
+ throw _err("ocsp/bad-input", "requestorName must be a DER Name BufferSource or a parsed Name");
227
227
  }
228
228
  // The RAW DER of a certificate that will be embedded verbatim (the responder cert in a
229
229
  // BasicOCSPResponse, the signer cert in a signed OCSPRequest). It must be supplied as bytes:
230
230
  // a parsed certificate does not retain its full DER encoding, and re-encoding it would risk
231
231
  // byte drift from the signed original, so a parsed cert is rejected rather than reconstructed.
232
232
  function _normCertDer(cert, what) {
233
- if (Buffer.isBuffer(cert) || cert instanceof Uint8Array) return guard.bytes.snapshot(cert, OcspError, "ocsp/bad-input", what || "a certificate");
233
+ if (guard.bytes.isByteSource(cert)) return guard.bytes.snapshotSource(cert, OcspError, "ocsp/bad-input", what || "a certificate");
234
234
  if (typeof cert === "string") { try { return x509.pemDecode(cert); } catch (e) { throw _err("ocsp/bad-input", (what || "a certificate") + " PEM could not be decoded", e); } }
235
235
  if (cert && cert.tbsBytes && cert.subjectPublicKeyInfo) {
236
236
  throw _err("ocsp/bad-input", (what || "a certificate") + " to embed must be supplied as DER bytes or a PEM string, not a parsed certificate (the parser does not retain the full DER encoding needed to embed it verbatim)");
@@ -378,7 +378,7 @@ function _asDate(d) {
378
378
  // the aliasing window is wiped rather than left to the garbage collector. Only our own
379
379
  // allocations are listed: the caller's key is never written to.
380
380
  function _snapshotSignerKey(key, owned) {
381
- if (Buffer.isBuffer(key) || key instanceof Uint8Array) {
381
+ if (Buffer.isBuffer(key) || key instanceof Uint8Array) { // allow:byte-source-narrow -- responder private key on the key-ownership contract (Buffer / Uint8Array / PEM / CryptoKey); widening keys is a separate root decision
382
382
  var copy = guard.bytes.snapshot(key, OcspError, "ocsp/bad-input", "the responder key");
383
383
  owned.push(copy);
384
384
  return copy;
@@ -550,8 +550,8 @@ function verify(response, opts) {
550
550
  // A client that sent a nonce binds it (RFC 9654 / RFC 5019 sec. 4): a missing or mismatched
551
551
  // response nonce fails the verdict closed, even if the status/signature were otherwise good.
552
552
  var respNonce = _responseNonce(parsed);
553
- var reqNonce = (Buffer.isBuffer(opts.requestNonce) || opts.requestNonce instanceof Uint8Array)
554
- ? guard.bytes.snapshot(opts.requestNonce, OcspError, "ocsp/bad-input", "opts.requestNonce") : null;
553
+ var reqNonce = guard.bytes.isByteSource(opts.requestNonce)
554
+ ? guard.bytes.snapshotSource(opts.requestNonce, OcspError, "ocsp/bad-input", "opts.requestNonce") : null;
555
555
  var matched = respNonce != null && reqNonce != null && guard.crypto.constantTimeEqual(respNonce, reqNonce);
556
556
  var out = Object.assign({}, verdict, { nonceMatched: matched });
557
557
  // The downgrade applies to `good` ONLY. `unknown` is the closed direction for a
package/lib/oid.js CHANGED
@@ -652,6 +652,21 @@ function byName(n) {
652
652
  return _byName.get(n);
653
653
  }
654
654
 
655
+ // Does `s` look like a dotted-decimal OID -- one or more digit groups joined by single dots (at least two
656
+ // groups, no leading/trailing/doubled dot)? Distinguishes a numeric OID from a symbolic name so a caller may
657
+ // pass either. Decided by character scan (no regex); the arc-value bounds are the encoder's authority.
658
+ function isDottedDecimal(s) {
659
+ if (typeof s !== "string" || s.length === 0) return false;
660
+ var i, c, sawDot = false, atomEmpty = true;
661
+ for (i = 0; i < s.length; i += 1) {
662
+ c = s.charCodeAt(i);
663
+ if (c === 46) { if (atomEmpty) return false; sawDot = true; atomEmpty = true; } // "."
664
+ else if (c >= 48 && c <= 57) { atomEmpty = false; } // 0-9
665
+ else return false;
666
+ }
667
+ return sawDot && !atomEmpty;
668
+ }
669
+
655
670
  function has(dotted) {
656
671
  _assertDotted(dotted, "has");
657
672
  return _byOid.has(dotted);
@@ -876,6 +891,7 @@ function kemParams(oidOrName) { return KEM_PARAMS[oidOrName]; }
876
891
  module.exports = {
877
892
  name: name,
878
893
  byName: byName,
894
+ isDottedDecimal: isDottedDecimal,
879
895
  has: has,
880
896
  paramsMustBeAbsent: paramsMustBeAbsent,
881
897
  kemParams: kemParams,
@@ -49,6 +49,7 @@ var cmsVerify = require("./cms-verify");
49
49
  var cmpSession = require("./cmp-session");
50
50
  var guard = require("./guard-all");
51
51
  var intrinsic = require("./guard-intrinsic");
52
+ var _charCodeAt = intrinsic.uncurry(String.prototype.charCodeAt);
52
53
  var constants = require("./constants");
53
54
  var validator = require("./validator-all");
54
55
  var cms = require("./schema-cms");
@@ -568,11 +569,54 @@ function hostConstraintMatch(constraint, host) {
568
569
  // or a value carrying non-hostname characters (a scheme "://", a path "/", a
569
570
  // port ":") is not a FQDN and cannot be matched against a domain-suffix
570
571
  // constraint. Only [A-Za-z0-9.-] with at least one dot qualifies.
572
+ // A code-point membership table built from a string of the allowed characters, and the shared scan that
573
+ // checks every character of a non-empty string against one -- replacing the hostname-charset regexes
574
+ // through one loop (no per-predicate character-class chain).
575
+ function _charTable(chars) { var t = []; for (var i = 0; i < chars.length; i++) t[_charCodeAt(chars, i)] = true; return t; }
576
+ var _FQDN_TABLE = _charTable("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-"); // /^[a-z0-9.-]+$/i
577
+ var _DIGDOT_TABLE = _charTable("0123456789."); // /^[0-9.]+$/
578
+ function _allCharsIn(s, table) {
579
+ if (s.length === 0) return false;
580
+ for (var i = 0; i < s.length; i++) if (!table[_charCodeAt(s, i)]) return false;
581
+ return true;
582
+ }
583
+ // /^[0-9]/ : begins with an ASCII digit (a dotted-OID attempt, vs an EKU / purpose name).
584
+ function _startsWithDigit(s) { if (s.length === 0) return false; var c = _charCodeAt(s, 0); return c >= 48 && c <= 57; }
585
+
586
+ var _SCHEME_TABLE = _charTable("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+.-"); // [a-z0-9+.-]
587
+ // /^[a-z][a-z0-9+.-]*:\/\/([^/?#]*)/i : the [start, end) range of the authority (up to the first / ? #
588
+ // or end), or null when the input is not a scheme "//" URI. Returns a range so the caller slices once
589
+ // (the slice that replaces the removed .exec), not a fresh substring here.
590
+ function _uriAuthorityRange(uri) {
591
+ var n = uri.length;
592
+ if (n === 0) return null;
593
+ var c0 = _charCodeAt(uri, 0);
594
+ if (!((c0 >= 65 && c0 <= 90) || (c0 >= 97 && c0 <= 122))) return null; // scheme starts with a letter
595
+ var p = 1;
596
+ while (p < n && _SCHEME_TABLE[_charCodeAt(uri, p)]) p += 1;
597
+ if (_charCodeAt(uri, p) !== 58 || _charCodeAt(uri, p + 1) !== 47 || _charCodeAt(uri, p + 2) !== 47) return null; // "://"
598
+ p += 3;
599
+ var authStart = p;
600
+ while (p < n) { var d = _charCodeAt(uri, p); if (d === 47 || d === 63 || d === 35) break; p += 1; } // [^/?#]*
601
+ return [authStart, p];
602
+ }
603
+ // /:\d+$/ : the index at which a trailing ":" + digits port starts (to slice off), or s.length when absent.
604
+ function _portStripIndex(s) {
605
+ var i = s.length;
606
+ while (i > 0) { var c = _charCodeAt(s, i - 1); if (c >= 48 && c <= 57) i -= 1; else break; }
607
+ return (i < s.length && i > 0 && _charCodeAt(s, i - 1) === 58) ? i - 1 : s.length;
608
+ }
609
+ // /^\[(.*)\]$/ -> "$1" : an IPv6 literal's surrounding "[" "]" removed, else the string unchanged.
610
+ function _stripBrackets(s) {
611
+ var n = s.length;
612
+ return (n >= 2 && _charCodeAt(s, 0) === 91 && _charCodeAt(s, n - 1) === 93) ? s.slice(1, n - 1) : s;
613
+ }
614
+
571
615
  function isFqdnHost(host) {
572
616
  var h = stripTrailingDot(host);
573
617
  if (h === "" || h.indexOf(".") === -1) return false; // empty or single-label (localhost)
574
- if (!/^[a-z0-9.-]+$/i.test(h)) return false; // scheme/path/port/IPv6 chars, "@", etc.
575
- if (/^[0-9.]+$/.test(h)) return false; // IPv4 dotted-quad literal
618
+ if (!_allCharsIn(h, _FQDN_TABLE)) return false; // scheme/path/port/IPv6 chars, "@", etc.
619
+ if (_allCharsIn(h, _DIGDOT_TABLE)) return false; // IPv4 dotted-quad literal
576
620
  return true;
577
621
  }
578
622
 
@@ -595,9 +639,9 @@ function uriMatch(constraint, uri) {
595
639
  }
596
640
 
597
641
  function uriHost(uri) {
598
- var m = /^[a-z][a-z0-9+.-]*:\/\/([^/?#]*)/i.exec(uri);
599
- if (!m) return null;
600
- var authority = m[1];
642
+ var r = _uriAuthorityRange(uri);
643
+ if (r === null) return null;
644
+ var authority = uri.slice(r[0], r[1]);
601
645
  // authority = [ userinfo "@" ] host [ ":" port ]. RFC 3986 userinfo does not
602
646
  // contain a raw "@", so a conformant authority has at most one "@". With more
603
647
  // than one the host cannot be determined reliably, so this fails closed
@@ -606,7 +650,7 @@ function uriHost(uri) {
606
650
  var firstAt = authority.indexOf("@");
607
651
  if (firstAt !== authority.lastIndexOf("@")) return null;
608
652
  if (firstAt !== -1) authority = authority.slice(firstAt + 1);
609
- var host = authority.replace(/:\d+$/, "");
653
+ var host = authority.slice(0, _portStripIndex(authority));
610
654
  return host === "" ? null : host; // an empty authority cannot be evaluated -> unsupported
611
655
  }
612
656
 
@@ -788,8 +832,7 @@ function treeIsEmpty(tree) { return tree.children.length === 0; }
788
832
  function isSubtreeBaseValid(tag, base) {
789
833
  switch (tag) {
790
834
  case 1: case 2: case 6: return typeof base === "string"; // rfc822Name / dNSName / URI
791
- case 7: return (Buffer.isBuffer(base) || base instanceof Uint8Array) &&
792
- (base.length === 8 || base.length === 32); // iPAddress: address + mask
835
+ case 7: return Buffer.isBuffer(base) && (base.length === 8 || base.length === 32); // iPAddress: address + mask (any BufferSource is normalized to a Buffer in checkedSubtreeSeeds)
793
836
  case 4: return base !== null && typeof base === "object" && !!base.rdns && intrinsic.isArray(base.rdns); // directoryName
794
837
  default: return base !== undefined;
795
838
  }
@@ -803,10 +846,19 @@ function checkedSubtreeSeeds(list, optName) {
803
846
  if (list === undefined || list === null) return [];
804
847
  if (!intrinsic.isArray(list)) throw E("path/bad-input", "validate: opts." + optName + " must be an array of { tag, base } subtree entries");
805
848
  return list.map(function (st) {
806
- if (!st || typeof st !== "object" || !Number.isInteger(st.tag) || st.tag < 0 || st.tag > 8 || !isSubtreeBaseValid(st.tag, st.base)) {
849
+ if (!st || typeof st !== "object" || !Number.isInteger(st.tag) || st.tag < 0 || st.tag > 8) {
850
+ throw E("path/bad-input", "validate: opts." + optName + " entries must be { tag: <GeneralName tag number 0..8>, base: <that form's constraint value> }");
851
+ }
852
+ // An iPAddress base (address+mask) may arrive as any BufferSource; normalize it to a
853
+ // private Buffer so the matcher can index it by byte and a caller cannot mutate it once a
854
+ // microtask has passed. The name forms (string / directoryName) are validated as they stand.
855
+ var base = (st.tag === 7 && guard.bytes.isByteSource(st.base))
856
+ ? guard.bytes.snapshotSource(st.base, PathError, "path/bad-input", "an iPAddress subtree base")
857
+ : st.base;
858
+ if (!isSubtreeBaseValid(st.tag, base)) {
807
859
  throw E("path/bad-input", "validate: opts." + optName + " entries must be { tag: <GeneralName tag number 0..8>, base: <that form's constraint value> }");
808
860
  }
809
- return { tag: st.tag, base: st.base };
861
+ return { tag: st.tag, base: base };
810
862
  });
811
863
  }
812
864
 
@@ -2522,8 +2574,8 @@ function verifyOcspResponse(response, cert, issuerCert, time, opts) {
2522
2574
  var _OCSP_CLAIM = ["responseStatus", "basicResponse", "tbsResponseDataBytes"];
2523
2575
  function _ocspFromBytes(response) {
2524
2576
  return guard.parsed.fromTrustedSource(response, "ocspResponse", _OCSP_CLAIM, function (bytes) {
2525
- if (!Buffer.isBuffer(bytes) && !(bytes instanceof Uint8Array) && typeof bytes !== "string") {
2526
- throw E("path/bad-input", "verifyOcspResponse: the response must be an OCSP response DER Buffer, a PEM string, or a pki.schema.ocsp.parseResponse result");
2577
+ if (!guard.bytes.isByteSource(bytes) && typeof bytes !== "string") {
2578
+ throw E("path/bad-input", "verifyOcspResponse: the response must be an OCSP response DER BufferSource, a PEM string, or a pki.schema.ocsp.parseResponse result");
2527
2579
  }
2528
2580
  return ocsp.parseResponse(bytes);
2529
2581
  }, E, "path/bad-input",
@@ -2674,7 +2726,7 @@ function resolvePurposeOpts(opts) {
2674
2726
  // A dotted-form attempt (leads with a digit) must be a canonical OID -- a
2675
2727
  // loose regex accepted a leading-zero / out-of-bounds key that would never
2676
2728
  // match the canonical EKU the target advertises; anything else is a name.
2677
- if (/^[0-9]/.test(p)) return guard.identifier.assertCanonicalOid(p, E, "path/bad-input", "validate: opts.requiredEku entry " + JSON.stringify(p));
2729
+ if (_startsWithDigit(p)) return guard.identifier.assertCanonicalOid(p, E, "path/bad-input", "validate: opts.requiredEku entry " + JSON.stringify(p));
2678
2730
  var dotted = oid.byName(p);
2679
2731
  if (typeof dotted !== "string") throw E("path/bad-input", "validate: opts.requiredEku entry " + JSON.stringify(p) + " is not a registered OID name");
2680
2732
  return dotted;
@@ -2685,7 +2737,7 @@ function resolvePurposeOpts(opts) {
2685
2737
  if (typeof opts.checkPurpose !== "string" || opts.checkPurpose.length === 0) {
2686
2738
  throw E("path/bad-input", "validate: opts.checkPurpose must be a key-purpose OID name or dotted OID string");
2687
2739
  }
2688
- if (/^[0-9]/.test(opts.checkPurpose)) {
2740
+ if (_startsWithDigit(opts.checkPurpose)) {
2689
2741
  var cpDotted = guard.identifier.assertCanonicalOid(opts.checkPurpose, E, "path/bad-input", "validate: opts.checkPurpose");
2690
2742
  checkPurpose = oid.name(cpDotted) || cpDotted; // normalize a dotted purpose OID to its name for the anchor map
2691
2743
  } else {
@@ -2840,7 +2892,7 @@ function toAnchor(entry, verb) {
2840
2892
  // entry refusal, not a raw exception leaked past the typed guards. `alg` and the raw publicKey are PINNED
2841
2893
  // to ONE read here and used throughout, so a stateful accessor that returns a value now and throws (or
2842
2894
  // returns a different value) on a later read cannot slip past this guard at the shape check or the snapshot.
2843
- var isTuple = false, alg = null, pubRaw = null, nameRaw = null, pk = null, purposesSnap, distrustSnap;
2895
+ var isTuple = false, alg = null, pubRaw, nameRaw = null, pk = null, purposesSnap, distrustSnap;
2844
2896
  var subjectDerRaw, labelRaw, mozRaw;
2845
2897
  // A Proxy anchor is refused outright. Every field read below -- whether by property access or from an own
2846
2898
  // data descriptor -- is answered by the anchor's own reflection, and a Proxy's traps let the same read
@@ -2915,7 +2967,10 @@ function toAnchor(entry, verb) {
2915
2967
  // it is captured. A non-tuple leaves pk null / isTuple false and falls through to coerceCert below.
2916
2968
  pubRaw = entry.publicKey;
2917
2969
  if (guard.bytes.isByteSource(pubRaw)) {
2918
- pk = guard.bytes.snapshot(pubRaw, PathError, "path/bad-input", who + ": trustAnchor publicKey");
2970
+ // snapshotSource, not snapshot: isByteSource accepts all four BufferSource forms (Buffer, any view,
2971
+ // DataView, ArrayBuffer), so the normalizer must too -- snapshot accepts only Buffer/Uint8Array and
2972
+ // would accept-then-throw on an ArrayBuffer / DataView anchor publicKey.
2973
+ pk = guard.bytes.snapshotSource(pubRaw, PathError, "path/bad-input", who + ": trustAnchor publicKey");
2919
2974
  }
2920
2975
  nameRaw = entry.name;
2921
2976
  alg = entry.algorithm;
@@ -3005,7 +3060,10 @@ function toAnchor(entry, verb) {
3005
3060
  // resolve a polluted Object.prototype.rdns on a name that supplied none (and could invoke an inherited
3006
3061
  // throwing getter) -- means a name with no own rdns is refused, never accepted on an inherited array.
3007
3062
  var nameHasRdns = intrinsic.hasOwn(nameOut, "rdns") && intrinsic.isArray(nameOut.rdns);
3008
- if (!nameHasRdns || !Buffer.isBuffer(pubRaw) || algStr === null) {
3063
+ // Gate on the NORMALIZED key `pk` (a private Buffer from snapshotSource iff publicKey was any of the four
3064
+ // BufferSource forms), not the raw `pubRaw` -- Buffer.isBuffer(pubRaw) would reject a Uint8Array / view /
3065
+ // ArrayBuffer publicKey that isByteSource + snapshotSource just accepted.
3066
+ if (!nameHasRdns || !Buffer.isBuffer(pk) || algStr === null) {
3009
3067
  throw E("path/bad-input", who + ": a trustAnchor tuple must be { name: { rdns: [...] }, publicKey: Buffer, algorithm: an OID string or a SubjectPublicKeyInfo algorithm carrying an oid }");
3010
3068
  }
3011
3069
  // Hold the stated algorithm to a canonical dotted-decimal OID: a shape-valid but non-canonical value
@@ -3256,7 +3314,7 @@ async function _fetchAiaIssuers(current, aia) {
3256
3314
  // A DNS-NAME host's private RESOLUTION can only be blocked by a transport that filters the resolved address;
3257
3315
  // with an UNGUARDED transport (an injected fn that does not vouch blocksPrivateAddresses) fail closed -- fetch
3258
3316
  // IP literals only (already validated above), never a hostname whose resolved address we cannot verify.
3259
- if (net.isIP(u.hostname.replace(/^\[(.*)\]$/, "$1")) === 0 && !aia.transportGuardsAddresses) continue;
3317
+ if (net.isIP(_stripBrackets(u.hostname)) === 0 && !aia.transportGuardsAddresses) continue;
3260
3318
  u.hash = ""; // the fragment is never sent on the wire -> not part of the request/dedupe identity
3261
3319
  if (intrinsic.setHas(aia.fetchedUrls, u.href) || intrinsic.setHas(seenThisCert, u.href)) continue; // dedupe (build-wide OR same-cert) on the normalized URL
3262
3320
  if (seenThisCert.size >= aia.maxPerCert) break; // per-cert DISTINCT-url cap, checked BEFORE appending so maxAiaPerCert:0 collects nothing (no fetch at all)
package/lib/pbes2.js CHANGED
@@ -157,7 +157,7 @@ function pbes2Encrypt(pwBytes, plaintext, opts, E, prefix) {
157
157
  opts = opts || {};
158
158
  var cipherName = opts.cipher || "aes256-CBC";
159
159
  var keyBits = CONTENT_KEYBITS[O(cipherName)];
160
- if (!keyBits || !/CBC/.test(cipherName)) throw E(prefix + "/bad-input", "unsupported PBES2 cipher " + cipherName + " (AES-CBC only)");
160
+ if (!keyBits || cipherName.indexOf("CBC") === -1) throw E(prefix + "/bad-input", "unsupported PBES2 cipher " + cipherName + " (AES-CBC only)");
161
161
  var prf = opts.prf || "hmacWithSHA256";
162
162
  var prfNode = prfNodeByName(prf, E, prefix);
163
163
  var iterations = assertIterations(opts.iterations == null ? 2048 : opts.iterations, E, prefix);
@@ -200,7 +200,7 @@ function pbes2Decrypt(pwBytes, params, ciphertext, opts, E, prefix, budget) {
200
200
  pb = parsePbkdf2Params(kdf[1].bytes, opts, E, prefix, true); // strictPrf: reject a non-canonical explicit default prf
201
201
  var encOid = asn1.read.oid(encScheme[0]);
202
202
  keyBits = CONTENT_KEYBITS[encOid];
203
- if (!keyBits || !/CBC/.test(oid.name(encOid) || "")) throw E(prefix + "/unsupported-algorithm", "unsupported PBES2 encryptionScheme " + (oid.name(encOid) || encOid) + " (AES-CBC only)");
203
+ if (!keyBits || (oid.name(encOid) || "").indexOf("CBC") === -1) throw E(prefix + "/unsupported-algorithm", "unsupported PBES2 encryptionScheme " + (oid.name(encOid) || encOid) + " (AES-CBC only)");
204
204
  iv = asn1.read.octetString(encScheme[1]);
205
205
  if (iv.length !== 16) throw E(prefix + "/bad-algorithm-parameters", "the AES-CBC IV must be 16 octets");
206
206
  } catch (e) {
@@ -216,7 +216,7 @@ function _p12Encode(pw) {
216
216
  // A view first, so a detached backing store is a reject and never an empty password; then a copy,
217
217
  // because everything this function returns is reported owned and gets zeroized after derivation,
218
218
  // and handing back a view of a caller's Uint8Array would wipe the caller's own credential.
219
- if (Buffer.isBuffer(pw) || pw instanceof Uint8Array) return guard.bytes.snapshot(pw, Pkcs12Error, "pkcs12/bad-input", "the password");
219
+ if (Buffer.isBuffer(pw) || pw instanceof Uint8Array) return guard.bytes.snapshot(pw, Pkcs12Error, "pkcs12/bad-input", "the password"); // allow:byte-source-narrow -- password on the ownership contract (string / Buffer / Uint8Array); widening passwords is a separate root decision
220
220
  if (typeof pw !== "string") throw _err("pkcs12/bad-input", _MISSING_PASSWORD);
221
221
  var out = Buffer.alloc(pw.length * 2 + 2); // + the 2-byte NULL terminator
222
222
  for (var i = 0; i < pw.length; i++) {
@@ -507,7 +507,7 @@ async function _buildAuthSafeElement(sc, opts) {
507
507
  var alg = sc.contentEncryptionAlgorithm || "aes-256-cbc";
508
508
  // RFC 7292 sec. 4.1 lists only id-envelopedData for a public-key privacy safe (never id-ct-authEnvelopedData);
509
509
  // cms.encrypt DEFAULTS to aes-256-gcm (AEAD -> AuthEnvelopedData), so force a CBC content cipher and reject GCM.
510
- if (!/^aes-(128|192|256)-cbc$/.test(alg)) throw _err("pkcs12/bad-input", "a public-key privacy safe requires an AES-CBC content cipher (aes-128|192|256-cbc), not " + JSON.stringify(alg) + " -- RFC 7292 sec. 4.1 admits only id-envelopedData, not GCM/AuthEnvelopedData");
510
+ if (alg !== "aes-128-cbc" && alg !== "aes-192-cbc" && alg !== "aes-256-cbc") throw _err("pkcs12/bad-input", "a public-key privacy safe requires an AES-CBC content cipher (aes-128|192|256-cbc), not " + JSON.stringify(alg) + " -- RFC 7292 sec. 4.1 admits only id-envelopedData, not GCM/AuthEnvelopedData");
511
511
  var envCi = await cms.encrypt(safeContentsDer, sc.recipients, { contentEncryptionAlgorithm: alg, contentType: "data" });
512
512
  return b.raw(envCi); // cms.encrypt returns the whole id-envelopedData ContentInfo DER -- splice it verbatim
513
513
  }
package/lib/pki-build.js CHANGED
@@ -355,7 +355,7 @@ function makeBuilder(ctx) {
355
355
  // A DN spec -> RDNSequence DER. A string is shorthand for a single commonName RDN; a Buffer is raw
356
356
  // pre-encoded Name DER (validated through the parser). An empty array yields an empty RDNSequence.
357
357
  function encodeName(spec) {
358
- if (Buffer.isBuffer(spec)) { assertValidNameDer(spec); return spec; }
358
+ if (guard.bytes.isByteSource(spec)) { var _nd = guard.bytes.snapshotSource(spec, ErrorClass, ctx.prefix + "/bad-name", "raw Name DER"); assertValidNameDer(_nd); return _nd; }
359
359
  if (typeof spec === "string") spec = [{ commonName: spec }];
360
360
  if (!_isArray(spec)) throw E("bad-name", "a name must be a string, an array of RDNs, or raw Name DER");
361
361
  return b.sequence(spec.map(encodeRdn));
@@ -560,14 +560,14 @@ function makeBuilder(ctx) {
560
560
  return nodeCrypto.createHash("sha1").update(keyBytes).digest();
561
561
  }
562
562
  function skiKeyId(val, spkiDer) {
563
- if (Buffer.isBuffer(val)) return guard.bytes.snapshot(val, ErrorClass, ctx.prefix + "/bad-input", "subjectKeyIdentifier");
563
+ if (guard.bytes.isByteSource(val)) return guard.bytes.snapshotSource(val, ErrorClass, ctx.prefix + "/bad-input", "subjectKeyIdentifier");
564
564
  if (val === true) return spkiKeyId(spkiDer);
565
- throw E("bad-input", "subjectKeyIdentifier must be true (auto-derive) or a Buffer key id");
565
+ throw E("bad-input", "subjectKeyIdentifier must be true (auto-derive) or a BufferSource key id");
566
566
  }
567
567
 
568
568
  // ---- embedded-input validators ----
569
569
  function reqDer(v, what) {
570
- if (Buffer.isBuffer(v) || v instanceof Uint8Array) return guard.bytes.snapshot(v, ErrorClass, ctx.prefix + "/bad-input", what);
570
+ if (guard.bytes.isByteSource(v)) return guard.bytes.snapshotSource(v, ErrorClass, ctx.prefix + "/bad-input", what);
571
571
  throw E("bad-input", what + " must be a DER Buffer");
572
572
  }
573
573
  // Full validation of an embedded SubjectPublicKeyInfo, walked through the parser the decoder uses.
@@ -663,8 +663,8 @@ function makeBuilder(ctx) {
663
663
  } else if (typeof serial === "bigint") { v = serial; }
664
664
  else if (typeof serial === "number") { if (!Number.isSafeInteger(serial)) throw E("bad-serial", "serialNumber number must be a safe integer (pass a BigInt, hex string, or Buffer for a value above 2^53-1)"); v = BigInt(serial); }
665
665
  else if (typeof serial === "string") { try { v = BigInt(serial); } catch (e) { throw E("bad-serial", "serialNumber string must be a decimal or 0x-hex integer", e); } }
666
- else if (Buffer.isBuffer(serial)) { v = serial.length ? BigInt("0x" + serial.toString("hex")) : 0n; }
667
- else { throw E("bad-serial", "serialNumber must be a BigInt, integer, hex string, or Buffer"); }
666
+ else if (guard.bytes.isByteSource(serial)) { var _sb = guard.bytes.source(serial, ErrorClass, ctx.prefix + "/bad-serial", "serialNumber"); v = _sb.length ? BigInt("0x" + _sb.toString("hex")) : 0n; }
667
+ else { throw E("bad-serial", "serialNumber must be a BigInt, integer, hex string, or BufferSource"); }
668
668
  if (v <= 0n) throw E("bad-serial", "serialNumber must be a positive integer (RFC 5280 sec. 4.1.2.2)");
669
669
  var tlv = b.integer(v);
670
670
  if (asn1.decode(tlv).content.length > 20) throw E("bad-serial", "serialNumber must not exceed 20 octets (RFC 5280 sec. 4.1.2.2)");
package/lib/rfc3339.js CHANGED
@@ -13,23 +13,72 @@
13
13
  * domain fault code.
14
14
  */
15
15
 
16
- // date "T" time with a zone (Z or a numeric offset); an optional fractional second.
17
- var RFC3339_RE = /^(\d{4})-(\d{2})-(\d{2})[Tt](\d{2}):(\d{2}):(\d{2})(?:\.\d+)?(?:[Zz]|([+-])(\d{2}):(\d{2}))$/;
16
+ // Exactly `count` ASCII digits at `start`, as an integer, or null on any non-digit or short read.
17
+ // The grammar is decided character by character (no regex, whose match protocol re-dispatches through
18
+ // a replaceable `exec`); `\d` in the original is ASCII [0-9] only, matched here as 48..57.
19
+ function _digitsAt(v, start, count) {
20
+ if (start + count > v.length) return null;
21
+ var val = 0;
22
+ for (var i = 0; i < count; i++) {
23
+ var c = v.charCodeAt(start + i);
24
+ if (c < 48 || c > 57) return null;
25
+ val = val * 10 + (c - 48);
26
+ }
27
+ return val;
28
+ }
29
+
30
+ // RFC 3339 date-time scanned into its components, or null on any grammar violation:
31
+ // YYYY "-" MM "-" DD [Tt] HH ":" MM ":" SS, an optional "." + one-or-more fraction digits, then a
32
+ // zone -- [Zz] or ([+-]) OFFHH ":" OFFMM -- with nothing after. Calendar validity is checked by the
33
+ // caller. `offset` carries the numeric-offset hours/minutes when present, else null.
34
+ function _scanDateTime(v) {
35
+ var n = v.length, p = 0;
36
+ var year = _digitsAt(v, p, 4); if (year === null) return null; p += 4;
37
+ if (v.charAt(p) !== "-") return null; p += 1;
38
+ var month = _digitsAt(v, p, 2); if (month === null) return null; p += 2;
39
+ if (v.charAt(p) !== "-") return null; p += 1;
40
+ var day = _digitsAt(v, p, 2); if (day === null) return null; p += 2;
41
+ var t = v.charAt(p); if (t !== "T" && t !== "t") return null; p += 1;
42
+ var hour = _digitsAt(v, p, 2); if (hour === null) return null; p += 2;
43
+ if (v.charAt(p) !== ":") return null; p += 1;
44
+ var min = _digitsAt(v, p, 2); if (min === null) return null; p += 2;
45
+ if (v.charAt(p) !== ":") return null; p += 1;
46
+ var sec = _digitsAt(v, p, 2); if (sec === null) return null; p += 2;
47
+ if (v.charAt(p) === ".") { // optional fractional second: "." + one or more digits
48
+ p += 1;
49
+ var fracStart = p;
50
+ while (p < n) { var fc = v.charCodeAt(p); if (fc < 48 || fc > 57) break; p += 1; }
51
+ if (p === fracStart) return null;
52
+ }
53
+ var z = v.charAt(p), offset = null;
54
+ if (z === "Z" || z === "z") {
55
+ p += 1;
56
+ } else if (z === "+" || z === "-") {
57
+ p += 1;
58
+ var offHour = _digitsAt(v, p, 2); if (offHour === null) return null; p += 2;
59
+ if (v.charAt(p) !== ":") return null; p += 1;
60
+ var offMin = _digitsAt(v, p, 2); if (offMin === null) return null; p += 2;
61
+ offset = { hour: offHour, min: offMin };
62
+ } else {
63
+ return null; // a zone is required
64
+ }
65
+ if (p !== n) return null; // no trailing characters
66
+ return { year: year, month: month, day: day, hour: hour, min: min, sec: sec, offset: offset };
67
+ }
18
68
 
19
69
  // isValid(v) -> boolean: v is a syntactically well-formed AND calendar-valid RFC 3339 date-time string.
20
70
  function isValid(v) {
21
71
  if (typeof v !== "string") return false;
22
- var m = RFC3339_RE.exec(v);
23
- if (!m) return false;
24
- var year = +m[1], month = +m[2], day = +m[3], hour = +m[4], min = +m[5], sec = +m[6];
25
- if (month < 1 || month > 12) return false;
72
+ var t = _scanDateTime(v);
73
+ if (!t) return false;
74
+ if (t.month < 1 || t.month > 12) return false;
26
75
  // Reject a :60 leap second (Node's Date.parse returns NaN for it, so a comparison on such a value
27
76
  // would silently pass) and any hour/minute/second out of range.
28
- if (hour > 23 || min > 59 || sec > 59) return false;
29
- var leap = (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
77
+ if (t.hour > 23 || t.min > 59 || t.sec > 59) return false;
78
+ var leap = (t.year % 4 === 0 && t.year % 100 !== 0) || t.year % 400 === 0;
30
79
  var daysInMonth = [31, leap ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
31
- if (day < 1 || day > daysInMonth[month - 1]) return false;
32
- if (m[7]) { if (+m[8] > 23 || +m[9] > 59) return false; } // a numeric zone offset must itself be valid
80
+ if (t.day < 1 || t.day > daysInMonth[t.month - 1]) return false;
81
+ if (t.offset) { if (t.offset.hour > 23 || t.offset.min > 59) return false; } // a numeric zone offset must itself be valid
33
82
  return true;
34
83
  }
35
84
 
@@ -44,20 +93,29 @@ function parse(v, E, code, label) {
44
93
  // RFC 3339 sec. 5.6 `full-date`: a calendar date with no time component. A distinct production from
45
94
  // the date-time above, and deliberately a separate pair of functions instead of a flag: a consumer
46
95
  // that expects one and is handed the other has a malformed value, not a permissible variant.
47
- var FULL_DATE_RE = /^(\d{4})-(\d{2})-(\d{2})$/;
96
+ // RFC 3339 full-date scanned into its components (YYYY "-" MM "-" DD, nothing after), or null.
97
+ function _scanFullDate(v) {
98
+ var p = 0;
99
+ var year = _digitsAt(v, p, 4); if (year === null) return null; p += 4;
100
+ if (v.charAt(p) !== "-") return null; p += 1;
101
+ var month = _digitsAt(v, p, 2); if (month === null) return null; p += 2;
102
+ if (v.charAt(p) !== "-") return null; p += 1;
103
+ var day = _digitsAt(v, p, 2); if (day === null) return null; p += 2;
104
+ if (p !== v.length) return null;
105
+ return { year: year, month: month, day: day };
106
+ }
48
107
 
49
108
  // isValidDate(v) -> boolean: v is a syntactically well-formed AND calendar-valid RFC 3339 full-date.
50
109
  // Calendar validity matters as much as shape: "2021-02-30" parses as a Date in JS by rolling over
51
110
  // into March, so a shape-only check would silently accept a day that does not exist.
52
111
  function isValidDate(v) {
53
112
  if (typeof v !== "string") return false;
54
- var m = FULL_DATE_RE.exec(v);
55
- if (!m) return false;
56
- var year = +m[1], month = +m[2], day = +m[3];
57
- if (month < 1 || month > 12) return false;
58
- var leap = (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
113
+ var t = _scanFullDate(v);
114
+ if (!t) return false;
115
+ if (t.month < 1 || t.month > 12) return false;
116
+ var leap = (t.year % 4 === 0 && t.year % 100 !== 0) || t.year % 400 === 0;
59
117
  var daysInMonth = [31, leap ? 29 : 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
60
- return day >= 1 && day <= daysInMonth[month - 1];
118
+ return t.day >= 1 && t.day <= daysInMonth[t.month - 1];
61
119
  }
62
120
 
63
121
  // parseDate(v, E, code, label) -> Date at UTC midnight. Anchored explicitly at UTC ("T00:00:00Z")
@@ -263,16 +263,37 @@ function _specialText(node) {
263
263
  // name one certificate. A natively signed certificate is exempt: sec. 3.1.4 says bytes and tag 48
264
264
  // there "do not correspond to any predefined text string encoding and may also be used for other attribute
265
265
  // types", so no canonical text spelling exists to hold one to.
266
- var _HEX_OPTIMIZED = /^(?:[0-9a-f]{2})+$/;
267
- var _EUI64_TEXT = /^(?:[0-9A-F]{2}-){7}[0-9A-F]{2}$/;
266
+ // Even-length lowercase hex ("HHHH..."), decided by character so no regex match protocol -- a live,
267
+ // replaceable exec -- stands between the canonicalization gate and the value it inspects.
268
+ function _isEvenHexLower(s) {
269
+ var n = s.length;
270
+ if (n < 2 || (n & 1) !== 0) return false;
271
+ for (var i = 0; i < n; i++) {
272
+ var c = s.charCodeAt(i);
273
+ if (!((c >= 48 && c <= 57) || (c >= 97 && c <= 102))) return false; // 0-9 a-f
274
+ }
275
+ return true;
276
+ }
277
+ // EUI-64 text form: eight uppercase hex pairs joined by single hyphens ("HH-HH-...-HH", 23 chars).
278
+ function _isEui64Text(s) {
279
+ if (s.length !== 23) return false;
280
+ for (var i = 0; i < 23; i++) {
281
+ if ((i % 3) === 2) { if (s.charCodeAt(i) !== 45) return false; } // "-" at 2,5,...,20
282
+ else {
283
+ var c = s.charCodeAt(i);
284
+ if (!((c >= 48 && c <= 57) || (c >= 65 && c <= 70))) return false; // 0-9 A-F
285
+ }
286
+ }
287
+ return true;
288
+ }
268
289
  function _assertCanonicalSpecialText(node, isNative, E) {
269
290
  if (isNative) return;
270
291
  if (node.majorType === 3) {
271
292
  var t = cbor.read.textString(node);
272
- if (t.length >= 2 && _HEX_OPTIMIZED.test(t)) {
293
+ if (t.length >= 2 && _isEvenHexLower(t)) {
273
294
  throw _err(E, "a text attribute value of even-length hex characters must be encoded as a CBOR byte string (draft sec. 3.1.4)");
274
295
  }
275
- if (_EUI64_TEXT.test(t)) {
296
+ if (_isEui64Text(t)) {
276
297
  throw _err(E, "a text attribute value in EUI-64 form must be encoded as a CBOR tag-48 MAC address (draft sec. 3.1.4)");
277
298
  }
278
299
  return;
@@ -1973,7 +1994,7 @@ function _reconstructDer(r, sigNode) {
1973
1994
  // The signature is re-wrapped as a DER ECDSA-Sig-Value from the fixed-width r||s, so only an ECDSA
1974
1995
  // signature algorithm is in the type-3 reconstruction covered set (an RSA/EdDSA signature is raw bytes,
1975
1996
  // not r||s, so it is rejected). A wrong-length r||s surfaces the caller's typed code.
1976
- if (!/^ecdsa/i.test(r.signatureAlgorithm.name || "")) {
1997
+ if (String(r.signatureAlgorithm.name || "").toLowerCase().indexOf("ecdsa") !== 0) {
1977
1998
  throw _err("c509/non-invertible", "type-3 signature reconstruction covers only ECDSA; got " + r.signatureAlgorithm.name);
1978
1999
  }
1979
2000
  // The fixed-width r||s must split at a real curve field width: P-256/384/521 = 64/96/132 bytes
@@ -2143,7 +2164,7 @@ function _encAlgorithm(alg, toInt, key) {
2143
2164
  function _encSpecialText(rdn) {
2144
2165
  if (rdn.eui64) return cbor.build.tag(48, cbor.build.byteString(rdn.eui64));
2145
2166
  var v = String(rdn.value);
2146
- if (v.length >= 2 && _HEX_OPTIMIZED.test(v)) return cbor.build.byteString(Buffer.from(v, "hex"));
2167
+ if (v.length >= 2 && _isEvenHexLower(v)) return cbor.build.byteString(Buffer.from(v, "hex"));
2147
2168
  return cbor.build.textString(v);
2148
2169
  }
2149
2170
  // A Name -> CBOR: null (issuer only) | a bare SpecialText single utf8 commonName | an array of RDN pairs.
@@ -2293,9 +2314,15 @@ function _encodeC509Array(r) {
2293
2314
  // value (draft-20 sec. 3.2.3): an FF-FE-in-the-middle EUI-64 collapses to its 6-byte EUI-48, else the
2294
2315
  // 8-byte EUI-64 verbatim. A non-MAC commonName returns null (encoded as text). The exact inverse of
2295
2316
  // _macToEui64String, so the reconstruction rebuilds the identical DER commonName string.
2317
+ // The "-" characters removed from a string, by character scan (no regex replace protocol).
2318
+ function _stripHyphens(s) {
2319
+ var out = "";
2320
+ for (var i = 0; i < s.length; i++) { var ch = s.charAt(i); if (ch !== "-") out += ch; }
2321
+ return out;
2322
+ }
2296
2323
  function _euiFromCn(value) {
2297
- if (!/^[0-9A-F]{2}(-[0-9A-F]{2}){7}$/.test(value)) return null;
2298
- var bytes = Buffer.from(value.replace(/-/g, ""), "hex");
2324
+ if (!_isEui64Text(value)) return null;
2325
+ var bytes = Buffer.from(_stripHyphens(value), "hex");
2299
2326
  if (bytes[3] === 0xff && bytes[4] === 0xfe) return Buffer.concat([bytes.subarray(0, 3), bytes.subarray(5)]);
2300
2327
  return bytes;
2301
2328
  }
@@ -2415,7 +2442,7 @@ _derToType3 = function (input, opts) {
2415
2442
  // (A v3 certificate with the extensions field OMITTED is fully supported: sec. 3.1.10 encodes
2416
2443
  // an omitted 'extensions' field as an empty CBOR array.)
2417
2444
  if (c.version !== 3) throw _err("c509/non-invertible", "C509 covers X.509 v3 certificates; got v" + c.version);
2418
- if (!/^ecdsa/i.test(c.signatureAlgorithm.name || "")) throw _err("c509/non-invertible", "type-3 C509 encoding covers only ECDSA-signed certificates; got " + (c.signatureAlgorithm.name || "an unregistered algorithm"));
2445
+ if (String(c.signatureAlgorithm.name || "").toLowerCase().indexOf("ecdsa") !== 0) throw _err("c509/non-invertible", "type-3 C509 encoding covers only ECDSA-signed certificates; got " + (c.signatureAlgorithm.name || "an unregistered algorithm"));
2419
2446
  if (c.subjectPublicKeyInfo.algorithm.name !== "ecPublicKey") throw _err("c509/non-invertible", "type-3 C509 encoding covers only EC (ecPublicKey) certificates in v1; got " + (c.subjectPublicKeyInfo.algorithm.name || "an unregistered algorithm"));
2420
2447
  var curveOid = asn1.read.oid(asn1.decode(c.subjectPublicKeyInfo.algorithm.parameters));
2421
2448
  var curve = oid.name(curveOid);
package/lib/schema-cmc.js CHANGED
@@ -685,7 +685,7 @@ function _finishBody(body, where) {
685
685
  * d.controls.length; // 0 -- present and empty, which is legal
686
686
  */
687
687
  function parsePkiData(input) {
688
- var root = asn1.decode(Buffer.isBuffer(input) ? input : Buffer.from(input));
688
+ var root = asn1.decode(guard.bytes.isByteSource(input) ? guard.bytes.source(input, E, "cmc/bad-input", "the CMC DER") : Buffer.from(input));
689
689
  var body = schema.walk(PKI_DATA, root, NS).result;
690
690
  body.bytes = root.bytes;
691
691
  return _finishBody(body, "pkiData");
@@ -711,7 +711,7 @@ function parsePkiData(input) {
711
711
  * r.statuses.length; // 0 -- no status control means success is assumed
712
712
  */
713
713
  function parsePkiResponse(input) {
714
- var root = asn1.decode(Buffer.isBuffer(input) ? input : Buffer.from(input));
714
+ var root = asn1.decode(guard.bytes.isByteSource(input) ? guard.bytes.source(input, E, "cmc/bad-input", "the CMC DER") : Buffer.from(input));
715
715
  var body = schema.walk(PKI_RESPONSE, root, NS).result;
716
716
  body.bytes = root.bytes;
717
717
  return _finishBody(body, "pkiResponse");
@@ -752,7 +752,7 @@ function parse(input) {
752
752
  // encapContentInfo is the field this function goes on to read, so requiring it
753
753
  // is the same question the code below already asks.
754
754
  var parsedCms = (input && typeof input === "object" && !ArrayBuffer.isView(input) &&
755
- !(input instanceof ArrayBuffer) && input.encapContentInfo != null)
755
+ !guard.bytes.isByteSource(input) && input.encapContentInfo != null)
756
756
  ? input : cms.parse(input);
757
757
  // The CARRIER is part of the identity, not just the encapsulated content type.
758
758
  // RFC 5272 sec. 3.2 / 4.2 admit a SignedData or an AuthenticatedData; other CMS