@blamejs/pki 0.5.23 → 0.5.24

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.
@@ -22,6 +22,38 @@ var intrinsic = require("./guard-intrinsic");
22
22
  // replaceable properties to answer one thing, and here it decides which version numbers a format
23
23
  // accepts -- shared by every format module, so one admitted name widens all of them at once.
24
24
  var _hasOwn = intrinsic.hasOwn;
25
+ // The rest of the operations this module decides with, taken at load for the same reason. What
26
+ // these factories produce is what a consumer compares an identity against -- a certificate's
27
+ // subject alternative names against an enrollment's own, a distinguished name against an issuer's
28
+ // -- so a name that traversal, folding or a byte copy invents here is a name the encoded structure
29
+ // never carried, and the comparison downstream still answers true.
30
+ var _forEach = intrinsic.forEach;
31
+ var _map = intrinsic.map;
32
+ var _push = intrinsic.push;
33
+ var _join = intrinsic.join;
34
+ var _stringify = intrinsic.stringify;
35
+ var _String = intrinsic.String;
36
+ var _isBuffer = intrinsic.isBuffer;
37
+ var _bufferFrom = intrinsic.bufferFrom;
38
+ var _bufferConcat = intrinsic.bufferConcat;
39
+ var _assign = intrinsic.assign;
40
+ var _subarray = intrinsic.subarray;
41
+ var _strIndexOf = intrinsic.stringIndexOf;
42
+ var _bufToString = intrinsic.uncurry(Buffer.prototype.toString);
43
+ var _strSlice = intrinsic.uncurry(String.prototype.slice);
44
+ var _charAt = intrinsic.uncurry(String.prototype.charAt);
45
+ var _strReplace = intrinsic.uncurry(String.prototype.replace);
46
+ var _split = intrinsic.uncurry(String.prototype.split);
47
+ var _reExec = intrinsic.uncurry(RegExp.prototype.exec);
48
+ var _reTest = intrinsic.uncurry(RegExp.prototype.test);
49
+ var _create = intrinsic.create;
50
+ var _isUint8Array = intrinsic.types.isUint8Array;
51
+ var _bigIntToString = intrinsic.bigIntToString;
52
+ var _weakGet = intrinsic.weakGet;
53
+ var _weakSet = intrinsic.weakSet;
54
+ var _WeakMapI = intrinsic.WeakMap;
55
+ var _arrayFrom = Array.from;
56
+ var _getUTCFullYear = intrinsic.uncurry(Date.prototype.getUTCFullYear);
25
57
  // ct is a leaf format module (requires only the codec / oid / constants / error
26
58
  // core, never pkix) so the SCT-list extension VALUE decoder registers here as a
27
59
  // registry row, not a switch. The one-directional edge keeps the layering acyclic.
@@ -48,10 +80,10 @@ function pemDecode(text, label, PemError) {
48
80
  text = guard.text.decode(text, constants.LIMITS.PEM_MAX_BYTES, PemError, {
49
81
  charset: "latin1", tooLarge: "pem/too-large", badInput: "pem/bad-input", label: "PEM input",
50
82
  });
51
- var m = PEM_RE.exec(text);
83
+ var m = _reExec(PEM_RE, text);
52
84
  if (!m) throw new PemError("pem/no-block", "no PEM block found");
53
- if (label && m[1] !== label) throw new PemError("pem/label-mismatch", "expected " + JSON.stringify(label) + " block, got " + JSON.stringify(m[1]));
54
- var b64 = m[2].replace(/[\r\n\t ]+/g, "");
85
+ if (label && m[1] !== label) throw new PemError("pem/label-mismatch", "expected " + _stringify(label) + " block, got " + _stringify(m[1]));
86
+ var b64 = _strReplace(m[2], /[\r\n\t ]+/g, "");
55
87
  // Strict canonical base64 (RFC 4648 sec. 3.5) via the shared encoding guard.
56
88
  return guard.encoding.base64(b64, null, function (c, msg) { return new PemError(c, msg); }, "pem/bad-base64", "PEM base64 body");
57
89
  }
@@ -70,15 +102,15 @@ function pemDecodeAll(text, label, PemError) {
70
102
  var re = /-----BEGIN ([A-Z0-9 ]+)-----([\s\S]*?)-----END \1-----/g;
71
103
  var blocks = [];
72
104
  var lastEnd = 0, m;
73
- while ((m = re.exec(text)) !== null) {
74
- if (/\S/.test(text.slice(lastEnd, m.index))) throw new PemError("pem/explanatory-text", "explanatory text is not permitted around PEM blocks (RFC 8555 sec. 9.1)");
75
- if (m[1] !== label) throw new PemError("pem/label-mismatch", "expected " + JSON.stringify(label) + " block, got " + JSON.stringify(m[1]));
76
- var b64 = m[2].replace(/[\r\n\t ]+/g, "");
77
- blocks.push(guard.encoding.base64(b64, null, function (c, msg) { return new PemError(c, msg); }, "pem/bad-base64", "PEM base64 body"));
105
+ while ((m = _reExec(re, text)) !== null) {
106
+ if (_reTest(/\S/, _strSlice(text, lastEnd, m.index))) throw new PemError("pem/explanatory-text", "explanatory text is not permitted around PEM blocks (RFC 8555 sec. 9.1)");
107
+ if (m[1] !== label) throw new PemError("pem/label-mismatch", "expected " + _stringify(label) + " block, got " + _stringify(m[1]));
108
+ var b64 = _strReplace(m[2], /[\r\n\t ]+/g, "");
109
+ _push(blocks, guard.encoding.base64(b64, null, function (c, msg) { return new PemError(c, msg); }, "pem/bad-base64", "PEM base64 body"));
78
110
  lastEnd = re.lastIndex;
79
111
  }
80
112
  if (blocks.length === 0) throw new PemError("pem/no-block", "no PEM block found");
81
- if (/\S/.test(text.slice(lastEnd))) throw new PemError("pem/explanatory-text", "explanatory text is not permitted after the PEM chain (RFC 8555 sec. 9.1)");
113
+ if (_reTest(/\S/, _strSlice(text, lastEnd))) throw new PemError("pem/explanatory-text", "explanatory text is not permitted after the PEM chain (RFC 8555 sec. 9.1)");
82
114
  return blocks;
83
115
  }
84
116
 
@@ -88,14 +120,14 @@ function pemDecodeAll(text, label, PemError) {
88
120
  // an embedded "-----" or newline) would emit armor pemDecode itself rejects
89
121
  // or corrupt the armor grammar: a config-time authoring fault, thrown here.
90
122
  function pemEncode(der, label, PemError) {
91
- if (typeof label !== "string" || !/^[A-Z0-9]+( [A-Z0-9]+)*$/.test(label)) {
123
+ if (typeof label !== "string" || !_reTest(/^[A-Z0-9]+( [A-Z0-9]+)*$/, label)) {
92
124
  throw new PemError("pem/bad-label", "pemEncode requires an uppercase A-Z0-9 label with single spaces");
93
125
  }
94
126
  // Re-view through the byte guard: a string input would silently utf8-armor into
95
127
  // a bogus PEM, and a detached-backed Buffer would armor an empty body; both
96
128
  // fail closed (a Uint8Array / Buffer of real DER re-views cleanly).
97
129
  var buf = guard.bytes.view(der, PemError, "pem/bad-input", "pemEncode DER input");
98
- var b64 = buf.toString("base64").replace(/(.{64})/g, "$1\n").replace(/\n$/, "");
130
+ var b64 = _strReplace(_strReplace(_bufToString(buf, "base64"), /(.{64})/g, "$1\n"), /\n$/, "");
99
131
  return "-----BEGIN " + label + "-----\n" + b64 + "\n-----END " + label + "-----\n";
100
132
  }
101
133
 
@@ -104,7 +136,7 @@ function pemEncode(der, label, PemError) {
104
136
  // Uint8Array is taken as bytes. opts: { pemLabel, PemError, ErrorClass, prefix }.
105
137
  function coerceToDer(input, opts) {
106
138
  if (typeof input === "string") return pemDecode(input, opts.pemLabel, opts.PemError);
107
- if (Buffer.isBuffer(input) || input instanceof Uint8Array) {
139
+ if (_isBuffer(input) || _isUint8Array(input)) {
108
140
  // Route the DER Buffer / Uint8Array through the shared byte guard so a
109
141
  // detached backing store fails closed here for every format that composes
110
142
  // this boundary (x509/crl/csr/pkcs8/cms/pkcs12), not per-format.
@@ -120,8 +152,8 @@ function coerceToDer(input, opts) {
120
152
  // leading tag+length bytes are non-printable, so a non-SEQUENCE DER (a bare
121
153
  // SET / INTEGER) is not misrouted here; it decodes and fails closed structurally.
122
154
  function _isPemArmor(buf) {
123
- var head = buf.slice(0, 4096).toString("latin1");
124
- var idx = head.indexOf("-----BEGIN");
155
+ var head = _bufToString(_subarray(buf, 0, 4096), "latin1");
156
+ var idx = _strIndexOf(head, "-----BEGIN");
125
157
  if (idx === -1) return false;
126
158
  for (var i = 0; i < idx; i++) {
127
159
  var c = buf[i];
@@ -143,7 +175,7 @@ function decodeRoot(der, opts) {
143
175
  // strictness verdict included.
144
176
  try { return asn1.decode(der, opts.ber ? { ber: true } : undefined); }
145
177
  catch (e) {
146
- throw new opts.ErrorClass(opts.prefix + "/bad-der", (opts.what || "input") + " DER did not decode: " + ((e && e.message) || String(e)), e);
178
+ throw new opts.ErrorClass(opts.prefix + "/bad-der", (opts.what || "input") + " DER did not decode: " + ((e && e.message) || _String(e)), e);
147
179
  }
148
180
  }
149
181
 
@@ -178,7 +210,7 @@ function makeNS(prefix, ErrorClass, oidModule) {
178
210
  // version is rejected at the leaf (asn1/*).
179
211
  function versionReader(ns, accept) {
180
212
  return schema.decode(function (n) {
181
- var key = asn1.read.integer(n).toString();
213
+ var key = _bigIntToString(asn1.read.integer(n));
182
214
  if (_hasOwn(accept, key)) return accept[key];
183
215
  throw ns.E(ns.prefix + "/bad-version", "unsupported version " + key);
184
216
  });
@@ -337,7 +369,7 @@ function attrValueToString(ns) {
337
369
  try { s = asn1.read.string(node); }
338
370
  catch (e) {
339
371
  if (!e || (e.code !== "asn1/expected-string" && e.code !== "asn1/expected-primitive")) {
340
- throw ns.E(ns.prefix + "/bad-atv", "malformed string in attribute value: " + ((e && e.message) || String(e)));
372
+ throw ns.E(ns.prefix + "/bad-atv", "malformed string in attribute value: " + ((e && e.message) || _String(e)));
341
373
  }
342
374
  // asn1.read.string does not read NumericString, and that is deliberate: a value that returns a plain
343
375
  // string joins the RFC 5280 sec. 7.1 name-comparison identity class, and NumericString is not a
@@ -347,11 +379,11 @@ function attrValueToString(ns) {
347
379
  // surfacing it in the type-distinct RFC 4514 hex form, which keeps it out of that identity class.
348
380
  if (node.tagClass === "universal" && node.tagNumber === asn1.TAGS.NUMERIC_STRING) {
349
381
  try { asn1.read.numericString(node); }
350
- catch (e2) { throw ns.E(ns.prefix + "/bad-atv", "malformed NumericString in attribute value: " + ((e2 && e2.message) || String(e2))); }
382
+ catch (e2) { throw ns.E(ns.prefix + "/bad-atv", "malformed NumericString in attribute value: " + ((e2 && e2.message) || _String(e2))); }
351
383
  }
352
- return "#" + node.bytes.toString("hex");
384
+ return "#" + _bufToString(node.bytes, "hex");
353
385
  }
354
- if (s.charAt(0) === "#" || s.charAt(0) === "\\") return "\\" + s;
386
+ if (_charAt(s, 0) === "#" || _charAt(s, 0) === "\\") return "\\" + s;
355
387
  return s;
356
388
  }, function (value) {
357
389
  // encode: a leading '\' escapes the next character (the decode's escape of a
@@ -361,9 +393,9 @@ function attrValueToString(ns) {
361
393
  // the first invalid character and would emit truncated bytes. Any other
362
394
  // string encodes as UTF8String (the decode does not preserve the original
363
395
  // string type, so this is the canonical re-encoding, not a byte-exact one).
364
- if (typeof value === "string" && value.charAt(0) === "\\") return asn1.build.utf8(value.slice(1));
365
- if (typeof value === "string" && value.charAt(0) === "#") {
366
- var hex = value.slice(1);
396
+ if (typeof value === "string" && _charAt(value, 0) === "\\") return asn1.build.utf8(_strSlice(value, 1));
397
+ if (typeof value === "string" && _charAt(value, 0) === "#") {
398
+ var hex = _strSlice(value, 1);
367
399
  if (hex.length === 0) {
368
400
  throw ns.E(ns.prefix + "/bad-atv", "a #hex attribute value must be a non-empty even run of hex digits (RFC 4514 sec. 2.4)");
369
401
  }
@@ -395,8 +427,8 @@ var _escapeDnValue = guard.name.escapeDnValue;
395
427
  // the semantic string and then rendered with the full escape set.
396
428
  function _dnDisplayValue(v) {
397
429
  if (typeof v !== "string") return v;
398
- if (v.charAt(0) === "#") return v;
399
- return _escapeDnValue(v.charAt(0) === "\\" ? v.slice(1) : v);
430
+ if (_charAt(v, 0) === "#") return v;
431
+ return _escapeDnValue(_charAt(v, 0) === "\\" ? _strSlice(v, 1) : v);
400
432
  }
401
433
 
402
434
  // time(ns): the RFC 5280 Time production under its profile encoding rule
@@ -415,7 +447,7 @@ function time(ns) {
415
447
  return schema.decode(function (n, ctx) {
416
448
  var d = base.fn(n, ctx);
417
449
  if (n.tagNumber === asn1.TAGS.GENERALIZED_TIME) {
418
- var y = d.getUTCFullYear();
450
+ var y = _getUTCFullYear(d);
419
451
  if (y >= 1950 && y < 2050) {
420
452
  throw ctx.E(ctx.prefix + "/bad-time", "a date through 2049 must be encoded as UTCTime, not GeneralizedTime (RFC 5280 sec. 4.1.2.5)");
421
453
  }
@@ -453,16 +485,19 @@ function name(ns, opts) {
453
485
  opts = opts || {};
454
486
  function nameBuild(m) {
455
487
  var rdns = [], parts = [];
456
- m.items.forEach(function (rdnItem) {
488
+ // Through the captured traversal: `rdns` is the parsed subject a consumer reads a common name
489
+ // out of, so a replaced Array.prototype.forEach or push could drop the name the certificate
490
+ // carries and seat one it does not.
491
+ _forEach(m.items, function (rdnItem) {
457
492
  var atvs = [], atvParts = [];
458
- rdnItem.value.items.forEach(function (atvItem) {
493
+ _forEach(rdnItem.value.items, function (atvItem) {
459
494
  var a = atvItem.value.result; // atvItem.value = the atv seq-match; .result = its build result
460
- atvs.push(a);
461
- var label = (a.name && DN_SHORT[a.name]) || a.name || a.type;
462
- atvParts.push(label + "=" + _dnDisplayValue(a.value));
495
+ _push(atvs, a);
496
+ var label = (a.name && _hasOwn(DN_SHORT, a.name) && DN_SHORT[a.name]) || a.name || a.type;
497
+ _push(atvParts, label + "=" + _dnDisplayValue(a.value));
463
498
  });
464
- rdns.push(atvs);
465
- parts.push(atvParts.join("+"));
499
+ _push(rdns, atvs);
500
+ _push(parts, _join(atvParts, "+"));
466
501
  });
467
502
  // `dn` is a DISPLAY string, and its spelling is `openssl x509 -subject`: the RDNs in the
468
503
  // certificate's own order, joined by ", ". That is deliberately not the RFC 4514 / LDAP
@@ -473,7 +508,7 @@ function name(ns, opts) {
473
508
  // guard.name.dnEqual compares the DER under RFC 5280 sec. 7.1, and `bytes` below carries the raw
474
509
  // Name DER for a consumer that needs the exact octets (the EST re-enroll subject MUST). Every
475
510
  // renderer in the toolkit uses this one spelling, so a certificate has one dn whichever parsed it.
476
- return { rdns: rdns, dn: parts.join(", "), bytes: opts.implicitTag != null ? asn1.sequenceTlv(m.node) : m.node.bytes };
511
+ return { rdns: rdns, dn: _join(parts, ", "), bytes: opts.implicitTag != null ? asn1.sequenceTlv(m.node) : m.node.bytes };
477
512
  }
478
513
  if (opts.implicitTag != null) {
479
514
  return schema.implicitSeqOf(opts.implicitTag, relativeDistinguishedName(ns), {
@@ -561,8 +596,13 @@ function rawNonEmptySequence(ns, opts) {
561
596
  // (shared with the OCSP revoked-status decoder, which surfaces the same numeric code).
562
597
  var CRL_REASON_NAMES = constants.NAMES.CRL_REASON;
563
598
 
564
- var GN_CONSTRUCTED = { 0: 1, 3: 1, 4: 1, 5: 1 };
565
- var GN_IA5 = { 1: 1, 2: 1, 6: 1 };
599
+ // Which GeneralName alternatives are constructed, and which carry an IA5String. Both tables answer
600
+ // off a tag number the encoded value supplies, and both decide which validation an alternative
601
+ // gets, so neither may inherit: with an ordinary prototype a planted numeric property routes a tag
602
+ // down another alternative's arm, and a dNSName then reaches the IA5 arm's control-byte reject as
603
+ // a constructed value, or misses it altogether.
604
+ var GN_CONSTRUCTED = _assign(_create(null), { 0: 1, 3: 1, 4: 1, 5: 1 });
605
+ var GN_IA5 = _assign(_create(null), { 1: 1, 2: 1, 6: 1 });
566
606
  function generalName(ns, opts) {
567
607
  opts = opts || {};
568
608
  var code = opts.code || (ns.prefix + "/bad-general-name");
@@ -602,7 +642,7 @@ function generalName(ns, opts) {
602
642
  // 7-bit IA5, no C0/DEL control byte. An embedded NUL/control in a
603
643
  // dNSName/rfc822Name/URI enables a name-truncation bypass (CVE-2009-2408).
604
644
  guard.name.assertPrintableIa5(n.content, ctx.E, code, "GeneralName [" + t + "]");
605
- if (decodeValue) value = n.content.toString("latin1");
645
+ if (decodeValue) value = _bufToString(n.content, "latin1");
606
646
  } else if (t === 7) {
607
647
  if (subtreeBase) {
608
648
  if (n.content.length !== 8 && n.content.length !== 32) throw ctx.E(code, "GeneralName iPAddress [7] subtree base must be an 8- or 32-octet address+mask (RFC 5280 sec. 4.2.1.10)");
@@ -611,7 +651,7 @@ function generalName(ns, opts) {
611
651
  }
612
652
  // n.content is proven non-null here (the primitive-form guard above
613
653
  // threw on a constructed node); copy the octets out.
614
- if (decodeValue) value = Buffer.concat([n.content]);
654
+ if (decodeValue) value = _bufferConcat([n.content]);
615
655
  } else if (t === 8) {
616
656
  var regId;
617
657
  try { regId = asn1.decodeOidContent(n.content); }
@@ -642,7 +682,10 @@ function generalNames(ns, opts) {
642
682
  // decodeValue / subtreeBase thread through to each element (the path
643
683
  // validator's constraint matcher passes decodeValue:true).
644
684
  var gn = generalName(ns, { code: code, decodeValue: opts.decodeValue === true, subtreeBase: opts.subtreeBase === true });
645
- function build(m) { return { names: m.items.map(function (it) { return it.value; }), bytes: m.node.bytes }; }
685
+ // Through the captured traversal: the names this yields are what a consumer compares an identity
686
+ // against -- a certificate's subject alternative names against an enrollment's own -- and a
687
+ // replaced Array.prototype.map could present a name the encoded GeneralNames does not carry.
688
+ function build(m) { return { names: _map(m.items, function (it) { return it.value; }), bytes: m.node.bytes }; }
646
689
  if (opts.implicitTag != null) {
647
690
  return schema.implicitSeqOf(opts.implicitTag, gn, { min: 1, code: code, what: opts.what || "GeneralNames", build: build });
648
691
  }
@@ -667,7 +710,7 @@ function generalNames(ns, opts) {
667
710
  function distributionPointName(ns, node, code) {
668
711
  if (node && node.tagClass === "context" && node.tagNumber === 0) {
669
712
  var gns = schema.walk(generalNames(ns, { implicitTag: 0, code: code, what: "DistributionPointName fullName" }), node, ns).result;
670
- return { kind: "fullName", names: gns.names.map(function (n) { return n.bytes; }) };
713
+ return { kind: "fullName", names: _map(gns.names, function (n) { return n.bytes; }) };
671
714
  }
672
715
  if (node && node.tagClass === "context" && node.tagNumber === 1) {
673
716
  // In [1] IMPLICIT RelativeDistinguishedName the context tag replaces the
@@ -692,14 +735,14 @@ function distributionPointName(ns, node, code) {
692
735
  //
693
736
  // `E(code, message, cause)` is the caller's typed error factory, so each boundary keeps its own
694
737
  // domain while the RULE stays single-homed.
695
- var _KU_DECODER = new WeakMap(); // one decoder table per namespace, built on first use
738
+ var _KU_DECODER = new _WeakMapI(); // one decoder table per namespace, built on first use
696
739
  function keyUsageOf(ns, cert, E, code, label) {
697
740
  var exts = (cert && cert.extensions) || [];
698
741
  var want = ns.oid.byName("keyUsage");
699
742
  for (var i = 0; i < exts.length; i++) {
700
743
  if (exts[i].oid !== want || exts[i].value == null) continue;
701
- var dec = _KU_DECODER.get(ns);
702
- if (!dec) { dec = certExtensionDecoders(ns).byOid[want]; _KU_DECODER.set(ns, dec); }
744
+ var dec = _weakGet(_KU_DECODER, ns);
745
+ if (!dec) { dec = certExtensionDecoders(ns).byOid[want]; _weakSet(_KU_DECODER, ns, dec); }
703
746
  try { return dec(exts[i].value); }
704
747
  catch (e) { throw E(code, "the " + label + " keyUsage extension is malformed", e); }
705
748
  }
@@ -765,7 +808,7 @@ function assertPolicyQualifiers(qNode, fail) {
765
808
  if (qNode.tagClass !== "universal" || qNode.tagNumber !== _T.SEQUENCE || !qNode.children || !qNode.children.length) {
766
809
  fail("policyQualifiers must be a non-empty SEQUENCE (RFC 5280 sec. 4.2.1.4)");
767
810
  }
768
- qNode.children.forEach(function (pq) {
811
+ _forEach(qNode.children, function (pq) {
769
812
  if (pq.tagClass !== "universal" || pq.tagNumber !== _T.SEQUENCE || !pq.children || pq.children.length !== 2) {
770
813
  fail("policyQualifiers element must be a PolicyQualifierInfo SEQUENCE { policyQualifierId, qualifier } (RFC 5280 sec. 4.2.1.4)");
771
814
  }
@@ -786,7 +829,7 @@ function assertPolicyQualifiers(qNode, fail) {
786
829
  // octets, so `.length` (UTF-16 units) or a byte count would misjudge a valid value. Exported so
787
830
  // every layer that reports the bound counts it identically instead of keeping its own copy.
788
831
  var DISPLAY_TEXT_MAX = 200;
789
- function displayTextChars(str) { return Array.from(str).length; }
832
+ function displayTextChars(str) { return _arrayFrom(str).length; }
790
833
 
791
834
  // @internal
792
835
  // userNoticeTexts(qualifier) -- the DisplayText values of a decoded UserNotice qualifier, as
@@ -803,7 +846,9 @@ function displayTextChars(str) { return Array.from(str).length; }
803
846
  var _DISPLAY_TEXT_TAGS = null;
804
847
  function _isDisplayTextNode(n) {
805
848
  if (!_DISPLAY_TEXT_TAGS) {
806
- _DISPLAY_TEXT_TAGS = {};
849
+ // Indexed by a tag number the encoded value supplies, so it holds no prototype: an inherited
850
+ // numeric name would make an unregistered universal tag read as a DisplayText alternative.
851
+ _DISPLAY_TEXT_TAGS = _create(null);
807
852
  _DISPLAY_TEXT_TAGS[_T.IA5_STRING] = 1; _DISPLAY_TEXT_TAGS[_T.VISIBLE_STRING] = 1;
808
853
  _DISPLAY_TEXT_TAGS[_T.BMP_STRING] = 1; _DISPLAY_TEXT_TAGS[_T.UTF8_STRING] = 1;
809
854
  }
@@ -836,9 +881,9 @@ function _dtEntry(field, node) {
836
881
  function _noticeNumbers(node) {
837
882
  if (!node || node.tagClass !== "universal" || node.tagNumber !== _T.SEQUENCE || !node.children) return null;
838
883
  var nums = [], ok = true;
839
- node.children.forEach(function (n) {
884
+ _forEach(node.children, function (n) {
840
885
  // allow:swallow-unverified a non-INTEGER member makes the whole reference undecodable, and the caller falls back
841
- try { nums.push(String(asn1.read.integer(n))); } catch (_e) { ok = false; }
886
+ try { _push(nums, _String(asn1.read.integer(n))); } catch (_e) { ok = false; }
842
887
  });
843
888
  return ok ? nums : null;
844
889
  }
@@ -863,13 +908,13 @@ function userNoticeTexts(qualifier) {
863
908
  if (!nr.children || nr.children.length !== 2 || !_isDisplayTextNode(nr.children[0])) return [];
864
909
  var org = _dtEntry("organization", nr.children[0]);
865
910
  org.noticeNumbers = _noticeNumbers(nr.children[1]);
866
- out.push(org);
911
+ _push(out, org);
867
912
  i++;
868
913
  }
869
914
  // explicitText [absent | last]: a DisplayText. Anything else remaining is not a UserNotice member.
870
915
  if (i < kids.length) {
871
916
  if (!_isDisplayTextNode(kids[i])) return [];
872
- out.push(_dtEntry("explicitText", kids[i]));
917
+ _push(out, _dtEntry("explicitText", kids[i]));
873
918
  i++;
874
919
  }
875
920
  return i === kids.length ? out : [];
@@ -882,7 +927,7 @@ function _decodeHelpers(ns) {
882
927
  function decodeTop(buf, code, what) {
883
928
  var n;
884
929
  try { n = asn1.decode(buf); }
885
- catch (e) { throw ns.E(code, "malformed " + what + " value: " + ((e && e.message) || String(e)), e); }
930
+ catch (e) { throw ns.E(code, "malformed " + what + " value: " + ((e && e.message) || _String(e)), e); }
886
931
  return n;
887
932
  }
888
933
  function seqChildren(buf, code, what) {
@@ -900,7 +945,7 @@ function _decodeHelpers(ns) {
900
945
  // by an unresolved name would silently never match, treating a real extension/attribute as opaque).
901
946
  function O(nm) {
902
947
  var d = ns.oid.byName(nm);
903
- if (typeof d !== "string") throw new TypeError("pki.schema.pkix: " + JSON.stringify(nm) + " is not a registered OID name");
948
+ if (typeof d !== "string") throw new TypeError("pki.schema.pkix: " + _stringify(nm) + " is not a registered OID name");
904
949
  return d;
905
950
  }
906
951
  return { decodeTop: decodeTop, seqChildren: seqChildren, readInt: readInt, O: O };
@@ -950,7 +995,7 @@ function certExtensionDecoders(ns) {
950
995
  // KeyUsage is a NamedBitList -- enforce the shared X.690 sec. 11.2.2 minimal-DER rule.
951
996
  schema.assertMinimalNamedBits(bs.unusedBits, bs.bytes, function (m) { throw ns.E(C, m); });
952
997
  var out = {};
953
- KU_BITS.forEach(function (nm, bit) {
998
+ _forEach(KU_BITS, function (nm, bit) {
954
999
  var byte = bit >> 3, mask = 0x80 >> (bit & 7);
955
1000
  out[nm] = byte < bs.bytes.length && (bs.bytes[byte] & mask) !== 0;
956
1001
  });
@@ -971,7 +1016,7 @@ function certExtensionDecoders(ns) {
971
1016
  // GeneralSubtrees is SIZE(1..MAX) -- an explicitly present but empty subtree
972
1017
  // list (a0 00) absorbs no constraint and is malformed, not a no-op.
973
1018
  if (!node.children || node.children.length < 1) throw ns.E(C, "NameConstraints permittedSubtrees/excludedSubtrees must be a non-empty GeneralSubtrees (SIZE 1..MAX, RFC 5280 sec. 4.2.1.10)");
974
- return node.children.map(function (st) {
1019
+ return _map(node.children, function (st) {
975
1020
  if (st.tagClass !== "universal" || st.tagNumber !== _T.SEQUENCE || !st.children || st.children.length < 1) {
976
1021
  throw ns.E(C, "GeneralSubtree must be a SEQUENCE { base, minimum?, maximum? }");
977
1022
  }
@@ -989,7 +1034,7 @@ function certExtensionDecoders(ns) {
989
1034
  var C = ns.prefix + "/bad-name-constraints";
990
1035
  var kids = seqChildren(buf, C, "NameConstraints");
991
1036
  var permitted = [], excluded = [], sawP = false, sawE = false, ncLastTag = -1;
992
- kids.forEach(function (k) {
1037
+ _forEach(kids, function (k) {
993
1038
  if (k.tagClass !== "context" || !k.children) throw ns.E(C, "NameConstraints fields are [0] permittedSubtrees / [1] excludedSubtrees");
994
1039
  if (k.tagNumber <= ncLastTag) throw ns.E(C, "NameConstraints fields must be unique and in ascending order (DER)");
995
1040
  ncLastTag = k.tagNumber;
@@ -1006,8 +1051,10 @@ function certExtensionDecoders(ns) {
1006
1051
  var C = ns.prefix + "/bad-policy";
1007
1052
  var kids = seqChildren(buf, C, "CertificatePolicies");
1008
1053
  if (kids.length < 1) throw ns.E(C, "CertificatePolicies must contain at least one PolicyInformation (RFC 5280 sec. 4.2.1.4)");
1009
- var seen = {};
1010
- return kids.map(function (pi) {
1054
+ // The duplicate-policy set answers off a dotted OID the encoded value supplies, so it holds no
1055
+ // prototype: an inherited name would report a policy as already seen and reject a valid one.
1056
+ var seen = _create(null);
1057
+ return _map(kids, function (pi) {
1011
1058
  // PolicyInformation ::= SEQUENCE { policyIdentifier, policyQualifiers
1012
1059
  // SEQUENCE SIZE(1..MAX) OPTIONAL }. Exactly one or two fields; a second
1013
1060
  // field, if present, MUST be a SEQUENCE. Extra/mis-typed fields are malformed.
@@ -1035,7 +1082,7 @@ function certExtensionDecoders(ns) {
1035
1082
  var C = ns.prefix + "/bad-policy";
1036
1083
  var kids = seqChildren(buf, C, "PolicyMappings");
1037
1084
  if (kids.length < 1) throw ns.E(C, "PolicyMappings must contain at least one mapping (RFC 5280 sec. 4.2.1.5)");
1038
- return kids.map(function (mp) {
1085
+ return _map(kids, function (mp) {
1039
1086
  if (mp.tagClass !== "universal" || mp.tagNumber !== _T.SEQUENCE || !mp.children || mp.children.length !== 2) {
1040
1087
  throw ns.E(C, "policy mapping must be a SEQUENCE { issuerDomainPolicy, subjectDomainPolicy }");
1041
1088
  }
@@ -1052,7 +1099,7 @@ function certExtensionDecoders(ns) {
1052
1099
  var kids = seqChildren(buf, C, "PolicyConstraints");
1053
1100
  if (kids.length < 1) throw ns.E(C, "PolicyConstraints must contain at least one field (RFC 5280 sec. 4.2.1.11)");
1054
1101
  var rep = null, ipm = null, pcLastTag = -1;
1055
- kids.forEach(function (k) {
1102
+ _forEach(kids, function (k) {
1056
1103
  if (k.tagClass !== "context") throw ns.E(C, "PolicyConstraints fields are context-tagged [0]/[1]");
1057
1104
  if (k.tagNumber <= pcLastTag) throw ns.E(C, "PolicyConstraints fields must be unique and in ascending order (DER)");
1058
1105
  pcLastTag = k.tagNumber;
@@ -1098,7 +1145,7 @@ function certExtensionDecoders(ns) {
1098
1145
  var descs = seqChildren(buf, C, "AuthorityInfoAccessSyntax");
1099
1146
  if (descs.length < 1) throw ns.E(C, "AuthorityInfoAccessSyntax must contain at least one AccessDescription (RFC 5280 sec. 4.2.2.1, SIZE(1..MAX))");
1100
1147
  var GN = generalName(ns, { decodeValue: true, code: C });
1101
- return descs.map(function (d) {
1148
+ return _map(descs, function (d) {
1102
1149
  if (d.tagClass !== "universal" || d.tagNumber !== _T.SEQUENCE || !d.children || d.children.length !== 2) {
1103
1150
  throw ns.E(C, "AccessDescription must be a SEQUENCE { accessMethod, accessLocation } (RFC 5280 sec. 4.2.2.1)");
1104
1151
  }
@@ -1115,7 +1162,7 @@ function certExtensionDecoders(ns) {
1115
1162
  var C = ns.prefix + "/bad-extension-value";
1116
1163
  var kids = seqChildren(buf, C, "ExtKeyUsage");
1117
1164
  if (kids.length < 1) throw ns.E(C, "ExtKeyUsage must contain at least one KeyPurposeId (RFC 5280 sec. 4.2.1.12)");
1118
- return kids.map(function (k) {
1165
+ return _map(kids, function (k) {
1119
1166
  try { return asn1.read.oid(k); } catch (e) { throw ns.E(C, "ExtKeyUsage KeyPurposeId must be an OBJECT IDENTIFIER", e); }
1120
1167
  });
1121
1168
  }
@@ -1126,7 +1173,7 @@ function certExtensionDecoders(ns) {
1126
1173
  var kids = seqChildren(buf, C, "AuthorityKeyIdentifier");
1127
1174
  var out = { keyIdentifier: null, authorityCertIssuer: null, authorityCertSerialNumber: null };
1128
1175
  var lastTag = -1;
1129
- kids.forEach(function (k) {
1176
+ _forEach(kids, function (k) {
1130
1177
  if (k.tagClass !== "context") throw ns.E(C, "AuthorityKeyIdentifier fields are context-tagged");
1131
1178
  // DER: the OPTIONAL fields appear at most once and in ascending tag order.
1132
1179
  if (k.tagNumber <= lastTag) throw ns.E(C, "AuthorityKeyIdentifier fields must be unique and in ascending order (DER)");
@@ -1135,7 +1182,7 @@ function certExtensionDecoders(ns) {
1135
1182
  // [2] IMPLICIT INTEGER are primitive leaves; the readers enforce the
1136
1183
  // primitive form fail-closed (a constructed context node is rejected,
1137
1184
  // never dereferenced for its absent content).
1138
- if (k.tagNumber === 0) { try { out.keyIdentifier = Buffer.from(asn1.read.octetStringImplicit(k, 0)); } catch (e) { throw ns.E(C, "AuthorityKeyIdentifier keyIdentifier [0] must be an IMPLICIT OCTET STRING", e); } }
1185
+ if (k.tagNumber === 0) { try { out.keyIdentifier = _bufferFrom(asn1.read.octetStringImplicit(k, 0)); } catch (e) { throw ns.E(C, "AuthorityKeyIdentifier keyIdentifier [0] must be an IMPLICIT OCTET STRING", e); } }
1139
1186
  else if (k.tagNumber === 1) out.authorityCertIssuer = schema.walk(generalNames(ns, { implicitTag: 1, decodeValue: true, code: C }), k, ns).result;
1140
1187
  else if (k.tagNumber === 2) { try { out.authorityCertSerialNumber = asn1.read.integerImplicit(k, 2); } catch (e) { throw ns.E(C, "authorityCertSerialNumber must be an INTEGER", e); } }
1141
1188
  else throw ns.E(C, "AuthorityKeyIdentifier has an unexpected field [" + k.tagNumber + "]");
@@ -1150,7 +1197,7 @@ function certExtensionDecoders(ns) {
1150
1197
  function subjectKeyIdentifier(buf) {
1151
1198
  var C = ns.prefix + "/bad-extension-value";
1152
1199
  var n = decodeTop(buf, C, "SubjectKeyIdentifier");
1153
- try { return Buffer.concat([asn1.read.octetString(n)]); }
1200
+ try { return _bufferConcat([asn1.read.octetString(n)]); }
1154
1201
  catch (e) { throw ns.E(C, "SubjectKeyIdentifier must be an OCTET STRING (RFC 5280 sec. 4.2.1.2)", e); }
1155
1202
  }
1156
1203
 
@@ -1193,13 +1240,13 @@ function certExtensionDecoders(ns) {
1193
1240
  var C = ns.prefix + "/bad-crl-distribution-points";
1194
1241
  var kids = seqChildren(buf, C, "CRLDistributionPoints");
1195
1242
  if (kids.length < 1) throw ns.E(C, "CRLDistributionPoints must contain at least one DistributionPoint (RFC 5280 sec. 4.2.1.13)");
1196
- return kids.map(function (dp) {
1243
+ return _map(kids, function (dp) {
1197
1244
  if (dp.tagClass !== "universal" || dp.tagNumber !== _T.SEQUENCE || !dp.children) {
1198
1245
  throw ns.E(C, "DistributionPoint must be a SEQUENCE { distributionPoint?, reasons?, cRLIssuer? }");
1199
1246
  }
1200
1247
  var out = { distributionPoint: null, reasons: null, cRLIssuer: null };
1201
1248
  var lastTag = -1;
1202
- dp.children.forEach(function (f) {
1249
+ _forEach(dp.children, function (f) {
1203
1250
  if (f.tagClass !== "context") throw ns.E(C, "DistributionPoint fields are context-tagged [0]/[1]/[2]");
1204
1251
  if (f.tagNumber <= lastTag) throw ns.E(C, "DistributionPoint fields must be unique and in ascending order (DER)");
1205
1252
  lastTag = f.tagNumber;
@@ -1241,7 +1288,7 @@ function certExtensionDecoders(ns) {
1241
1288
  }
1242
1289
  function _qcOidSeq(node, C, what) { // a non-empty SEQUENCE OF OBJECT IDENTIFIER
1243
1290
  if (!node || node.tagClass !== "universal" || node.tagNumber !== _T.SEQUENCE || !node.children || !node.children.length) throw ns.E(C, what + " must be a non-empty SEQUENCE OF OBJECT IDENTIFIER");
1244
- return node.children.map(function (c) {
1291
+ return _map(node.children, function (c) {
1245
1292
  if (c.tagClass !== "universal" || c.tagNumber !== _T.OBJECT_IDENTIFIER) throw ns.E(C, what + " members must be OBJECT IDENTIFIERs");
1246
1293
  try { return asn1.read.oid(c); } catch (e) { throw ns.E(C, what + " member is not a valid OID", e); }
1247
1294
  });
@@ -1266,14 +1313,16 @@ function certExtensionDecoders(ns) {
1266
1313
  if (i !== node.children.length) throw ns.E(C, "SemanticsInformation has unexpected trailing fields");
1267
1314
  return { semanticsIdentifier: sid, nameRegistrationAuthorities: nras };
1268
1315
  }
1269
- var qcInfoByOid = {};
1316
+ // The per-statement decoder table answers off a dotted OID the encoded value supplies, so it holds
1317
+ // no prototype: an inherited name would hand a statement a decoder nothing registered.
1318
+ var qcInfoByOid = _create(null);
1270
1319
  qcInfoByOid[O("qcCompliance")] = _qcPresenceOnly("QcCompliance");
1271
1320
  qcInfoByOid[O("qcSSCD")] = _qcPresenceOnly("QcSSCD");
1272
1321
  qcInfoByOid[O("qcsPkixQCSyntaxV1")] = _qcSemantics;
1273
1322
  qcInfoByOid[O("qcsPkixQCSyntaxV2")] = _qcSemantics;
1274
1323
  qcInfoByOid[O("qcType")] = function (node, C) {
1275
1324
  var oids = _qcOidSeq(node, C, "QcType"); // SIZE(1) in EN 319 412-5 V2.5.1; accept >=1 for legacy certs
1276
- return { types: oids, typeNames: oids.map(function (d) { return ns.oid.name(d) || null; }) };
1325
+ return { types: oids, typeNames: _map(oids, function (d) { return ns.oid.name(d) || null; }) };
1277
1326
  };
1278
1327
  qcInfoByOid[O("qcRetentionPeriod")] = function (node, C) {
1279
1328
  if (!node) throw ns.E(C, "QcRetentionPeriod requires an INTEGER statementInfo");
@@ -1302,11 +1351,11 @@ function certExtensionDecoders(ns) {
1302
1351
  };
1303
1352
  qcInfoByOid[O("qcCClegislation")] = function (node, C) { // SEQUENCE OF CountryName (PrintableString SIZE 2)
1304
1353
  if (!node || node.tagClass !== "universal" || node.tagNumber !== _T.SEQUENCE || !node.children || !node.children.length) throw ns.E(C, "QcCClegislation must be a non-empty SEQUENCE OF CountryName");
1305
- return { countries: node.children.map(function (c) { var v = _qcStr(c, _T.PRINTABLE_STRING, C, "QcCClegislation CountryName must be a PrintableString"); if (v.length !== 2) throw ns.E(C, "QcCClegislation CountryName must be a 2-letter ISO 3166-1 code"); return v; }) };
1354
+ return { countries: _map(node.children, function (c) { var v = _qcStr(c, _T.PRINTABLE_STRING, C, "QcCClegislation CountryName must be a PrintableString"); if (v.length !== 2) throw ns.E(C, "QcCClegislation CountryName must be a 2-letter ISO 3166-1 code"); return v; }) };
1306
1355
  };
1307
1356
  qcInfoByOid[O("qcPDS")] = function (node, C) { // PdsLocations ::= SEQUENCE OF PdsLocation { url IA5, language Printable(2) }
1308
1357
  if (!node || node.tagClass !== "universal" || node.tagNumber !== _T.SEQUENCE || !node.children || !node.children.length) throw ns.E(C, "QcPDS must be a non-empty SEQUENCE OF PdsLocation");
1309
- return { locations: node.children.map(function (loc) {
1358
+ return { locations: _map(node.children, function (loc) {
1310
1359
  if (loc.tagClass !== "universal" || loc.tagNumber !== _T.SEQUENCE || !loc.children || loc.children.length !== 2) throw ns.E(C, "a QcPDS PdsLocation must be a SEQUENCE { url, language }");
1311
1360
  var lang = _qcStr(loc.children[1], _T.PRINTABLE_STRING, C, "a QcPDS language must be a PrintableString");
1312
1361
  if (lang.length !== 2) throw ns.E(C, "a QcPDS language must be a 2-letter ISO 639-1 code");
@@ -1317,11 +1366,11 @@ function certExtensionDecoders(ns) {
1317
1366
  // QcQSCDlegislation (SEQUENCE OF CountryName, like QcCClegislation). Both are registered ids, decoded.
1318
1367
  qcInfoByOid[O("qcIdentMethod")] = function (node, C) {
1319
1368
  var oids = _qcOidSeq(node, C, "QcIdentMethod");
1320
- return { methods: oids, methodNames: oids.map(function (d) { return ns.oid.name(d) || null; }) };
1369
+ return { methods: oids, methodNames: _map(oids, function (d) { return ns.oid.name(d) || null; }) };
1321
1370
  };
1322
1371
  qcInfoByOid[O("qcQSCDlegislation")] = function (node, C) {
1323
1372
  if (!node || node.tagClass !== "universal" || node.tagNumber !== _T.SEQUENCE || !node.children || !node.children.length) throw ns.E(C, "QcQSCDlegislation must be a non-empty SEQUENCE OF CountryName");
1324
- return { countries: node.children.map(function (c) { var v = _qcStr(c, _T.PRINTABLE_STRING, C, "QcQSCDlegislation CountryName must be a PrintableString"); if (v.length !== 2) throw ns.E(C, "QcQSCDlegislation CountryName must be a 2-letter ISO 3166-1 code"); return v; }) };
1373
+ return { countries: _map(node.children, function (c) { var v = _qcStr(c, _T.PRINTABLE_STRING, C, "QcQSCDlegislation CountryName must be a PrintableString"); if (v.length !== 2) throw ns.E(C, "QcQSCDlegislation CountryName must be a 2-letter ISO 3166-1 code"); return v; }) };
1325
1374
  };
1326
1375
  function qcStatements(buf) {
1327
1376
  var C = ns.prefix + "/bad-qc-statements", CS = ns.prefix + "/bad-qc-statement";
@@ -1338,7 +1387,7 @@ function certExtensionDecoders(ns) {
1338
1387
  var infoNode = st.children.length === 2 ? st.children[1] : null;
1339
1388
  var decoder = qcInfoByOid[id];
1340
1389
  var info = decoder ? decoder(infoNode, CS) : { opaque: true, bytes: infoNode ? infoNode.bytes : null };
1341
- out.push({ statementId: id, name: ns.oid.name(id) || null, info: info });
1390
+ _push(out, { statementId: id, name: ns.oid.name(id) || null, info: info });
1342
1391
  }
1343
1392
  return out;
1344
1393
  }
@@ -1388,13 +1437,16 @@ function certExtensionDecoders(ns) {
1388
1437
  var C = ns.prefix + "/bad-ms-previous-cert-hash";
1389
1438
  var n = decodeTop(buf, C, "CAPrevCertHash");
1390
1439
  var hash;
1391
- try { hash = Buffer.concat([asn1.read.octetString(n)]); }
1440
+ try { hash = _bufferConcat([asn1.read.octetString(n)]); }
1392
1441
  catch (e) { throw ns.E(C, "CAPrevCertHash must be an OCTET STRING", e); }
1393
1442
  if (hash.length !== 20) throw ns.E(C, "CAPrevCertHash must be a 20-octet SHA-1 certificate thumbprint");
1394
1443
  return hash;
1395
1444
  }
1396
1445
 
1397
- var byOid = {};
1446
+ // The extension-decoder registry every consumer indexes with an OID read off the wire
1447
+ // (path validation, inspection, the ACME certificate binding), so it holds no prototype: a
1448
+ // planted dotted name would otherwise hand an extension a decoder nothing registered.
1449
+ var byOid = _create(null);
1398
1450
  byOid[O("qcStatements")] = qcStatements;
1399
1451
  byOid[O("basicConstraints")] = basicConstraints;
1400
1452
  byOid[O("keyUsage")] = keyUsage;
@@ -1460,10 +1512,10 @@ function extensions(ns, opts) {
1460
1512
  var extOpts = {
1461
1513
  min: 1, code: ns.prefix + "/bad-extensions", what: "Extensions",
1462
1514
  unique: function (it) { return it.value.oid; }, dupCode: ns.prefix + "/duplicate-extension",
1463
- build: function (m) { return m.items.map(function (it) { return it.value; }); },
1515
+ build: function (m) { return _map(m.items, function (it) { return it.value; }); },
1464
1516
  };
1465
1517
  if (opts.implicitTag != null) return schema.implicitSeqOf(opts.implicitTag, EXT, extOpts);
1466
- return schema.seqOf(EXT, Object.assign({ assert: "sequence" }, extOpts));
1518
+ return schema.seqOf(EXT, _assign({ assert: "sequence" }, extOpts));
1467
1519
  }
1468
1520
 
1469
1521
  // SubjectPublicKeyInfo ::= SEQUENCE { algorithm AlgorithmIdentifier,
@@ -1517,7 +1569,7 @@ function attribute(ns, opts) {
1517
1569
  return {
1518
1570
  type: t,
1519
1571
  name: ctx.oid.name(t) || null,
1520
- values: m.fields.values.value.items.map(function (it) { return it.node.bytes; }),
1572
+ values: _map(m.fields.values.value.items, function (it) { return it.node.bytes; }),
1521
1573
  };
1522
1574
  },
1523
1575
  });
@@ -1622,10 +1674,10 @@ function signedEnvelope(ns, tbsSchema, opts) {
1622
1674
  function dnsNameProblem(s) {
1623
1675
  if (typeof s !== "string" || !s.length) return "empty";
1624
1676
  if (s.length > 253) return "exceeds 253 octets";
1625
- if (/\s/.test(s)) return "whitespace";
1626
- if (s.charAt(0) === "." || s.charAt(s.length - 1) === ".") return "leading/trailing dot";
1627
- if (s.indexOf("_") !== -1) return "underscore forbidden in dNSName";
1628
- var labels = s.split(".");
1677
+ if (_reTest(/\s/, s)) return "whitespace";
1678
+ if (_charAt(s, 0) === "." || _charAt(s, s.length - 1) === ".") return "leading/trailing dot";
1679
+ if (_strIndexOf(s, "_") !== -1) return "underscore forbidden in dNSName";
1680
+ var labels = _split(s, ".");
1629
1681
  for (var i = 0; i < labels.length; i++) {
1630
1682
  var label = labels[i];
1631
1683
  if (label.length === 0) return "empty label";
@@ -1634,7 +1686,7 @@ function dnsNameProblem(s) {
1634
1686
  if (labels.length < 2) return "bare wildcard";
1635
1687
  continue;
1636
1688
  }
1637
- if (!/^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/i.test(label)) return "invalid label syntax";
1689
+ if (!_reTest(/^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/i, label)) return "invalid label syntax";
1638
1690
  }
1639
1691
  return null;
1640
1692
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blamejs/pki",
3
- "version": "0.5.23",
3
+ "version": "0.5.24",
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",