@blamejs/pki 0.5.22 → 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.
@@ -17,6 +17,43 @@ var asn1 = require("./asn1-der");
17
17
  var constants = require("./constants");
18
18
  var schema = require("./schema-engine");
19
19
  var guard = require("./guard-all");
20
+ var intrinsic = require("./guard-intrinsic");
21
+ // Own-key membership through an operation taken at load. Written out, the question reads two
22
+ // replaceable properties to answer one thing, and here it decides which version numbers a format
23
+ // accepts -- shared by every format module, so one admitted name widens all of them at once.
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);
20
57
  // ct is a leaf format module (requires only the codec / oid / constants / error
21
58
  // core, never pkix) so the SCT-list extension VALUE decoder registers here as a
22
59
  // registry row, not a switch. The one-directional edge keeps the layering acyclic.
@@ -43,10 +80,10 @@ function pemDecode(text, label, PemError) {
43
80
  text = guard.text.decode(text, constants.LIMITS.PEM_MAX_BYTES, PemError, {
44
81
  charset: "latin1", tooLarge: "pem/too-large", badInput: "pem/bad-input", label: "PEM input",
45
82
  });
46
- var m = PEM_RE.exec(text);
83
+ var m = _reExec(PEM_RE, text);
47
84
  if (!m) throw new PemError("pem/no-block", "no PEM block found");
48
- if (label && m[1] !== label) throw new PemError("pem/label-mismatch", "expected " + JSON.stringify(label) + " block, got " + JSON.stringify(m[1]));
49
- 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, "");
50
87
  // Strict canonical base64 (RFC 4648 sec. 3.5) via the shared encoding guard.
51
88
  return guard.encoding.base64(b64, null, function (c, msg) { return new PemError(c, msg); }, "pem/bad-base64", "PEM base64 body");
52
89
  }
@@ -65,15 +102,15 @@ function pemDecodeAll(text, label, PemError) {
65
102
  var re = /-----BEGIN ([A-Z0-9 ]+)-----([\s\S]*?)-----END \1-----/g;
66
103
  var blocks = [];
67
104
  var lastEnd = 0, m;
68
- while ((m = re.exec(text)) !== null) {
69
- 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)");
70
- if (m[1] !== label) throw new PemError("pem/label-mismatch", "expected " + JSON.stringify(label) + " block, got " + JSON.stringify(m[1]));
71
- var b64 = m[2].replace(/[\r\n\t ]+/g, "");
72
- 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"));
73
110
  lastEnd = re.lastIndex;
74
111
  }
75
112
  if (blocks.length === 0) throw new PemError("pem/no-block", "no PEM block found");
76
- 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)");
77
114
  return blocks;
78
115
  }
79
116
 
@@ -83,14 +120,14 @@ function pemDecodeAll(text, label, PemError) {
83
120
  // an embedded "-----" or newline) would emit armor pemDecode itself rejects
84
121
  // or corrupt the armor grammar: a config-time authoring fault, thrown here.
85
122
  function pemEncode(der, label, PemError) {
86
- 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)) {
87
124
  throw new PemError("pem/bad-label", "pemEncode requires an uppercase A-Z0-9 label with single spaces");
88
125
  }
89
126
  // Re-view through the byte guard: a string input would silently utf8-armor into
90
127
  // a bogus PEM, and a detached-backed Buffer would armor an empty body; both
91
128
  // fail closed (a Uint8Array / Buffer of real DER re-views cleanly).
92
129
  var buf = guard.bytes.view(der, PemError, "pem/bad-input", "pemEncode DER input");
93
- 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$/, "");
94
131
  return "-----BEGIN " + label + "-----\n" + b64 + "\n-----END " + label + "-----\n";
95
132
  }
96
133
 
@@ -99,7 +136,7 @@ function pemEncode(der, label, PemError) {
99
136
  // Uint8Array is taken as bytes. opts: { pemLabel, PemError, ErrorClass, prefix }.
100
137
  function coerceToDer(input, opts) {
101
138
  if (typeof input === "string") return pemDecode(input, opts.pemLabel, opts.PemError);
102
- if (Buffer.isBuffer(input) || input instanceof Uint8Array) {
139
+ if (_isBuffer(input) || _isUint8Array(input)) {
103
140
  // Route the DER Buffer / Uint8Array through the shared byte guard so a
104
141
  // detached backing store fails closed here for every format that composes
105
142
  // this boundary (x509/crl/csr/pkcs8/cms/pkcs12), not per-format.
@@ -115,8 +152,8 @@ function coerceToDer(input, opts) {
115
152
  // leading tag+length bytes are non-printable, so a non-SEQUENCE DER (a bare
116
153
  // SET / INTEGER) is not misrouted here; it decodes and fails closed structurally.
117
154
  function _isPemArmor(buf) {
118
- var head = buf.slice(0, 4096).toString("latin1");
119
- var idx = head.indexOf("-----BEGIN");
155
+ var head = _bufToString(_subarray(buf, 0, 4096), "latin1");
156
+ var idx = _strIndexOf(head, "-----BEGIN");
120
157
  if (idx === -1) return false;
121
158
  for (var i = 0; i < idx; i++) {
122
159
  var c = buf[i];
@@ -138,7 +175,7 @@ function decodeRoot(der, opts) {
138
175
  // strictness verdict included.
139
176
  try { return asn1.decode(der, opts.ber ? { ber: true } : undefined); }
140
177
  catch (e) {
141
- 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);
142
179
  }
143
180
  }
144
181
 
@@ -173,8 +210,8 @@ function makeNS(prefix, ErrorClass, oidModule) {
173
210
  // version is rejected at the leaf (asn1/*).
174
211
  function versionReader(ns, accept) {
175
212
  return schema.decode(function (n) {
176
- var key = asn1.read.integer(n).toString();
177
- if (Object.prototype.hasOwnProperty.call(accept, key)) return accept[key];
213
+ var key = _bigIntToString(asn1.read.integer(n));
214
+ if (_hasOwn(accept, key)) return accept[key];
178
215
  throw ns.E(ns.prefix + "/bad-version", "unsupported version " + key);
179
216
  });
180
217
  }
@@ -332,7 +369,7 @@ function attrValueToString(ns) {
332
369
  try { s = asn1.read.string(node); }
333
370
  catch (e) {
334
371
  if (!e || (e.code !== "asn1/expected-string" && e.code !== "asn1/expected-primitive")) {
335
- 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)));
336
373
  }
337
374
  // asn1.read.string does not read NumericString, and that is deliberate: a value that returns a plain
338
375
  // string joins the RFC 5280 sec. 7.1 name-comparison identity class, and NumericString is not a
@@ -342,11 +379,11 @@ function attrValueToString(ns) {
342
379
  // surfacing it in the type-distinct RFC 4514 hex form, which keeps it out of that identity class.
343
380
  if (node.tagClass === "universal" && node.tagNumber === asn1.TAGS.NUMERIC_STRING) {
344
381
  try { asn1.read.numericString(node); }
345
- 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))); }
346
383
  }
347
- return "#" + node.bytes.toString("hex");
384
+ return "#" + _bufToString(node.bytes, "hex");
348
385
  }
349
- if (s.charAt(0) === "#" || s.charAt(0) === "\\") return "\\" + s;
386
+ if (_charAt(s, 0) === "#" || _charAt(s, 0) === "\\") return "\\" + s;
350
387
  return s;
351
388
  }, function (value) {
352
389
  // encode: a leading '\' escapes the next character (the decode's escape of a
@@ -356,9 +393,9 @@ function attrValueToString(ns) {
356
393
  // the first invalid character and would emit truncated bytes. Any other
357
394
  // string encodes as UTF8String (the decode does not preserve the original
358
395
  // string type, so this is the canonical re-encoding, not a byte-exact one).
359
- if (typeof value === "string" && value.charAt(0) === "\\") return asn1.build.utf8(value.slice(1));
360
- if (typeof value === "string" && value.charAt(0) === "#") {
361
- 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);
362
399
  if (hex.length === 0) {
363
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)");
364
401
  }
@@ -390,8 +427,8 @@ var _escapeDnValue = guard.name.escapeDnValue;
390
427
  // the semantic string and then rendered with the full escape set.
391
428
  function _dnDisplayValue(v) {
392
429
  if (typeof v !== "string") return v;
393
- if (v.charAt(0) === "#") return v;
394
- 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);
395
432
  }
396
433
 
397
434
  // time(ns): the RFC 5280 Time production under its profile encoding rule
@@ -410,7 +447,7 @@ function time(ns) {
410
447
  return schema.decode(function (n, ctx) {
411
448
  var d = base.fn(n, ctx);
412
449
  if (n.tagNumber === asn1.TAGS.GENERALIZED_TIME) {
413
- var y = d.getUTCFullYear();
450
+ var y = _getUTCFullYear(d);
414
451
  if (y >= 1950 && y < 2050) {
415
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)");
416
453
  }
@@ -448,16 +485,19 @@ function name(ns, opts) {
448
485
  opts = opts || {};
449
486
  function nameBuild(m) {
450
487
  var rdns = [], parts = [];
451
- 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) {
452
492
  var atvs = [], atvParts = [];
453
- rdnItem.value.items.forEach(function (atvItem) {
493
+ _forEach(rdnItem.value.items, function (atvItem) {
454
494
  var a = atvItem.value.result; // atvItem.value = the atv seq-match; .result = its build result
455
- atvs.push(a);
456
- var label = (a.name && DN_SHORT[a.name]) || a.name || a.type;
457
- 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));
458
498
  });
459
- rdns.push(atvs);
460
- parts.push(atvParts.join("+"));
499
+ _push(rdns, atvs);
500
+ _push(parts, _join(atvParts, "+"));
461
501
  });
462
502
  // `dn` is a DISPLAY string, and its spelling is `openssl x509 -subject`: the RDNs in the
463
503
  // certificate's own order, joined by ", ". That is deliberately not the RFC 4514 / LDAP
@@ -468,7 +508,7 @@ function name(ns, opts) {
468
508
  // guard.name.dnEqual compares the DER under RFC 5280 sec. 7.1, and `bytes` below carries the raw
469
509
  // Name DER for a consumer that needs the exact octets (the EST re-enroll subject MUST). Every
470
510
  // renderer in the toolkit uses this one spelling, so a certificate has one dn whichever parsed it.
471
- 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 };
472
512
  }
473
513
  if (opts.implicitTag != null) {
474
514
  return schema.implicitSeqOf(opts.implicitTag, relativeDistinguishedName(ns), {
@@ -556,8 +596,13 @@ function rawNonEmptySequence(ns, opts) {
556
596
  // (shared with the OCSP revoked-status decoder, which surfaces the same numeric code).
557
597
  var CRL_REASON_NAMES = constants.NAMES.CRL_REASON;
558
598
 
559
- var GN_CONSTRUCTED = { 0: 1, 3: 1, 4: 1, 5: 1 };
560
- 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 });
561
606
  function generalName(ns, opts) {
562
607
  opts = opts || {};
563
608
  var code = opts.code || (ns.prefix + "/bad-general-name");
@@ -597,7 +642,7 @@ function generalName(ns, opts) {
597
642
  // 7-bit IA5, no C0/DEL control byte. An embedded NUL/control in a
598
643
  // dNSName/rfc822Name/URI enables a name-truncation bypass (CVE-2009-2408).
599
644
  guard.name.assertPrintableIa5(n.content, ctx.E, code, "GeneralName [" + t + "]");
600
- if (decodeValue) value = n.content.toString("latin1");
645
+ if (decodeValue) value = _bufToString(n.content, "latin1");
601
646
  } else if (t === 7) {
602
647
  if (subtreeBase) {
603
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)");
@@ -606,7 +651,7 @@ function generalName(ns, opts) {
606
651
  }
607
652
  // n.content is proven non-null here (the primitive-form guard above
608
653
  // threw on a constructed node); copy the octets out.
609
- if (decodeValue) value = Buffer.concat([n.content]);
654
+ if (decodeValue) value = _bufferConcat([n.content]);
610
655
  } else if (t === 8) {
611
656
  var regId;
612
657
  try { regId = asn1.decodeOidContent(n.content); }
@@ -637,7 +682,10 @@ function generalNames(ns, opts) {
637
682
  // decodeValue / subtreeBase thread through to each element (the path
638
683
  // validator's constraint matcher passes decodeValue:true).
639
684
  var gn = generalName(ns, { code: code, decodeValue: opts.decodeValue === true, subtreeBase: opts.subtreeBase === true });
640
- 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 }; }
641
689
  if (opts.implicitTag != null) {
642
690
  return schema.implicitSeqOf(opts.implicitTag, gn, { min: 1, code: code, what: opts.what || "GeneralNames", build: build });
643
691
  }
@@ -662,7 +710,7 @@ function generalNames(ns, opts) {
662
710
  function distributionPointName(ns, node, code) {
663
711
  if (node && node.tagClass === "context" && node.tagNumber === 0) {
664
712
  var gns = schema.walk(generalNames(ns, { implicitTag: 0, code: code, what: "DistributionPointName fullName" }), node, ns).result;
665
- 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; }) };
666
714
  }
667
715
  if (node && node.tagClass === "context" && node.tagNumber === 1) {
668
716
  // In [1] IMPLICIT RelativeDistinguishedName the context tag replaces the
@@ -687,14 +735,14 @@ function distributionPointName(ns, node, code) {
687
735
  //
688
736
  // `E(code, message, cause)` is the caller's typed error factory, so each boundary keeps its own
689
737
  // domain while the RULE stays single-homed.
690
- 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
691
739
  function keyUsageOf(ns, cert, E, code, label) {
692
740
  var exts = (cert && cert.extensions) || [];
693
741
  var want = ns.oid.byName("keyUsage");
694
742
  for (var i = 0; i < exts.length; i++) {
695
743
  if (exts[i].oid !== want || exts[i].value == null) continue;
696
- var dec = _KU_DECODER.get(ns);
697
- 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); }
698
746
  try { return dec(exts[i].value); }
699
747
  catch (e) { throw E(code, "the " + label + " keyUsage extension is malformed", e); }
700
748
  }
@@ -760,7 +808,7 @@ function assertPolicyQualifiers(qNode, fail) {
760
808
  if (qNode.tagClass !== "universal" || qNode.tagNumber !== _T.SEQUENCE || !qNode.children || !qNode.children.length) {
761
809
  fail("policyQualifiers must be a non-empty SEQUENCE (RFC 5280 sec. 4.2.1.4)");
762
810
  }
763
- qNode.children.forEach(function (pq) {
811
+ _forEach(qNode.children, function (pq) {
764
812
  if (pq.tagClass !== "universal" || pq.tagNumber !== _T.SEQUENCE || !pq.children || pq.children.length !== 2) {
765
813
  fail("policyQualifiers element must be a PolicyQualifierInfo SEQUENCE { policyQualifierId, qualifier } (RFC 5280 sec. 4.2.1.4)");
766
814
  }
@@ -781,7 +829,7 @@ function assertPolicyQualifiers(qNode, fail) {
781
829
  // octets, so `.length` (UTF-16 units) or a byte count would misjudge a valid value. Exported so
782
830
  // every layer that reports the bound counts it identically instead of keeping its own copy.
783
831
  var DISPLAY_TEXT_MAX = 200;
784
- function displayTextChars(str) { return Array.from(str).length; }
832
+ function displayTextChars(str) { return _arrayFrom(str).length; }
785
833
 
786
834
  // @internal
787
835
  // userNoticeTexts(qualifier) -- the DisplayText values of a decoded UserNotice qualifier, as
@@ -798,7 +846,9 @@ function displayTextChars(str) { return Array.from(str).length; }
798
846
  var _DISPLAY_TEXT_TAGS = null;
799
847
  function _isDisplayTextNode(n) {
800
848
  if (!_DISPLAY_TEXT_TAGS) {
801
- _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);
802
852
  _DISPLAY_TEXT_TAGS[_T.IA5_STRING] = 1; _DISPLAY_TEXT_TAGS[_T.VISIBLE_STRING] = 1;
803
853
  _DISPLAY_TEXT_TAGS[_T.BMP_STRING] = 1; _DISPLAY_TEXT_TAGS[_T.UTF8_STRING] = 1;
804
854
  }
@@ -831,9 +881,9 @@ function _dtEntry(field, node) {
831
881
  function _noticeNumbers(node) {
832
882
  if (!node || node.tagClass !== "universal" || node.tagNumber !== _T.SEQUENCE || !node.children) return null;
833
883
  var nums = [], ok = true;
834
- node.children.forEach(function (n) {
884
+ _forEach(node.children, function (n) {
835
885
  // allow:swallow-unverified a non-INTEGER member makes the whole reference undecodable, and the caller falls back
836
- 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; }
837
887
  });
838
888
  return ok ? nums : null;
839
889
  }
@@ -858,13 +908,13 @@ function userNoticeTexts(qualifier) {
858
908
  if (!nr.children || nr.children.length !== 2 || !_isDisplayTextNode(nr.children[0])) return [];
859
909
  var org = _dtEntry("organization", nr.children[0]);
860
910
  org.noticeNumbers = _noticeNumbers(nr.children[1]);
861
- out.push(org);
911
+ _push(out, org);
862
912
  i++;
863
913
  }
864
914
  // explicitText [absent | last]: a DisplayText. Anything else remaining is not a UserNotice member.
865
915
  if (i < kids.length) {
866
916
  if (!_isDisplayTextNode(kids[i])) return [];
867
- out.push(_dtEntry("explicitText", kids[i]));
917
+ _push(out, _dtEntry("explicitText", kids[i]));
868
918
  i++;
869
919
  }
870
920
  return i === kids.length ? out : [];
@@ -877,7 +927,7 @@ function _decodeHelpers(ns) {
877
927
  function decodeTop(buf, code, what) {
878
928
  var n;
879
929
  try { n = asn1.decode(buf); }
880
- 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); }
881
931
  return n;
882
932
  }
883
933
  function seqChildren(buf, code, what) {
@@ -895,7 +945,7 @@ function _decodeHelpers(ns) {
895
945
  // by an unresolved name would silently never match, treating a real extension/attribute as opaque).
896
946
  function O(nm) {
897
947
  var d = ns.oid.byName(nm);
898
- 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");
899
949
  return d;
900
950
  }
901
951
  return { decodeTop: decodeTop, seqChildren: seqChildren, readInt: readInt, O: O };
@@ -945,7 +995,7 @@ function certExtensionDecoders(ns) {
945
995
  // KeyUsage is a NamedBitList -- enforce the shared X.690 sec. 11.2.2 minimal-DER rule.
946
996
  schema.assertMinimalNamedBits(bs.unusedBits, bs.bytes, function (m) { throw ns.E(C, m); });
947
997
  var out = {};
948
- KU_BITS.forEach(function (nm, bit) {
998
+ _forEach(KU_BITS, function (nm, bit) {
949
999
  var byte = bit >> 3, mask = 0x80 >> (bit & 7);
950
1000
  out[nm] = byte < bs.bytes.length && (bs.bytes[byte] & mask) !== 0;
951
1001
  });
@@ -966,7 +1016,7 @@ function certExtensionDecoders(ns) {
966
1016
  // GeneralSubtrees is SIZE(1..MAX) -- an explicitly present but empty subtree
967
1017
  // list (a0 00) absorbs no constraint and is malformed, not a no-op.
968
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)");
969
- return node.children.map(function (st) {
1019
+ return _map(node.children, function (st) {
970
1020
  if (st.tagClass !== "universal" || st.tagNumber !== _T.SEQUENCE || !st.children || st.children.length < 1) {
971
1021
  throw ns.E(C, "GeneralSubtree must be a SEQUENCE { base, minimum?, maximum? }");
972
1022
  }
@@ -984,7 +1034,7 @@ function certExtensionDecoders(ns) {
984
1034
  var C = ns.prefix + "/bad-name-constraints";
985
1035
  var kids = seqChildren(buf, C, "NameConstraints");
986
1036
  var permitted = [], excluded = [], sawP = false, sawE = false, ncLastTag = -1;
987
- kids.forEach(function (k) {
1037
+ _forEach(kids, function (k) {
988
1038
  if (k.tagClass !== "context" || !k.children) throw ns.E(C, "NameConstraints fields are [0] permittedSubtrees / [1] excludedSubtrees");
989
1039
  if (k.tagNumber <= ncLastTag) throw ns.E(C, "NameConstraints fields must be unique and in ascending order (DER)");
990
1040
  ncLastTag = k.tagNumber;
@@ -1001,8 +1051,10 @@ function certExtensionDecoders(ns) {
1001
1051
  var C = ns.prefix + "/bad-policy";
1002
1052
  var kids = seqChildren(buf, C, "CertificatePolicies");
1003
1053
  if (kids.length < 1) throw ns.E(C, "CertificatePolicies must contain at least one PolicyInformation (RFC 5280 sec. 4.2.1.4)");
1004
- var seen = {};
1005
- 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) {
1006
1058
  // PolicyInformation ::= SEQUENCE { policyIdentifier, policyQualifiers
1007
1059
  // SEQUENCE SIZE(1..MAX) OPTIONAL }. Exactly one or two fields; a second
1008
1060
  // field, if present, MUST be a SEQUENCE. Extra/mis-typed fields are malformed.
@@ -1030,7 +1082,7 @@ function certExtensionDecoders(ns) {
1030
1082
  var C = ns.prefix + "/bad-policy";
1031
1083
  var kids = seqChildren(buf, C, "PolicyMappings");
1032
1084
  if (kids.length < 1) throw ns.E(C, "PolicyMappings must contain at least one mapping (RFC 5280 sec. 4.2.1.5)");
1033
- return kids.map(function (mp) {
1085
+ return _map(kids, function (mp) {
1034
1086
  if (mp.tagClass !== "universal" || mp.tagNumber !== _T.SEQUENCE || !mp.children || mp.children.length !== 2) {
1035
1087
  throw ns.E(C, "policy mapping must be a SEQUENCE { issuerDomainPolicy, subjectDomainPolicy }");
1036
1088
  }
@@ -1047,7 +1099,7 @@ function certExtensionDecoders(ns) {
1047
1099
  var kids = seqChildren(buf, C, "PolicyConstraints");
1048
1100
  if (kids.length < 1) throw ns.E(C, "PolicyConstraints must contain at least one field (RFC 5280 sec. 4.2.1.11)");
1049
1101
  var rep = null, ipm = null, pcLastTag = -1;
1050
- kids.forEach(function (k) {
1102
+ _forEach(kids, function (k) {
1051
1103
  if (k.tagClass !== "context") throw ns.E(C, "PolicyConstraints fields are context-tagged [0]/[1]");
1052
1104
  if (k.tagNumber <= pcLastTag) throw ns.E(C, "PolicyConstraints fields must be unique and in ascending order (DER)");
1053
1105
  pcLastTag = k.tagNumber;
@@ -1093,7 +1145,7 @@ function certExtensionDecoders(ns) {
1093
1145
  var descs = seqChildren(buf, C, "AuthorityInfoAccessSyntax");
1094
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))");
1095
1147
  var GN = generalName(ns, { decodeValue: true, code: C });
1096
- return descs.map(function (d) {
1148
+ return _map(descs, function (d) {
1097
1149
  if (d.tagClass !== "universal" || d.tagNumber !== _T.SEQUENCE || !d.children || d.children.length !== 2) {
1098
1150
  throw ns.E(C, "AccessDescription must be a SEQUENCE { accessMethod, accessLocation } (RFC 5280 sec. 4.2.2.1)");
1099
1151
  }
@@ -1110,7 +1162,7 @@ function certExtensionDecoders(ns) {
1110
1162
  var C = ns.prefix + "/bad-extension-value";
1111
1163
  var kids = seqChildren(buf, C, "ExtKeyUsage");
1112
1164
  if (kids.length < 1) throw ns.E(C, "ExtKeyUsage must contain at least one KeyPurposeId (RFC 5280 sec. 4.2.1.12)");
1113
- return kids.map(function (k) {
1165
+ return _map(kids, function (k) {
1114
1166
  try { return asn1.read.oid(k); } catch (e) { throw ns.E(C, "ExtKeyUsage KeyPurposeId must be an OBJECT IDENTIFIER", e); }
1115
1167
  });
1116
1168
  }
@@ -1121,7 +1173,7 @@ function certExtensionDecoders(ns) {
1121
1173
  var kids = seqChildren(buf, C, "AuthorityKeyIdentifier");
1122
1174
  var out = { keyIdentifier: null, authorityCertIssuer: null, authorityCertSerialNumber: null };
1123
1175
  var lastTag = -1;
1124
- kids.forEach(function (k) {
1176
+ _forEach(kids, function (k) {
1125
1177
  if (k.tagClass !== "context") throw ns.E(C, "AuthorityKeyIdentifier fields are context-tagged");
1126
1178
  // DER: the OPTIONAL fields appear at most once and in ascending tag order.
1127
1179
  if (k.tagNumber <= lastTag) throw ns.E(C, "AuthorityKeyIdentifier fields must be unique and in ascending order (DER)");
@@ -1130,7 +1182,7 @@ function certExtensionDecoders(ns) {
1130
1182
  // [2] IMPLICIT INTEGER are primitive leaves; the readers enforce the
1131
1183
  // primitive form fail-closed (a constructed context node is rejected,
1132
1184
  // never dereferenced for its absent content).
1133
- 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); } }
1134
1186
  else if (k.tagNumber === 1) out.authorityCertIssuer = schema.walk(generalNames(ns, { implicitTag: 1, decodeValue: true, code: C }), k, ns).result;
1135
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); } }
1136
1188
  else throw ns.E(C, "AuthorityKeyIdentifier has an unexpected field [" + k.tagNumber + "]");
@@ -1145,7 +1197,7 @@ function certExtensionDecoders(ns) {
1145
1197
  function subjectKeyIdentifier(buf) {
1146
1198
  var C = ns.prefix + "/bad-extension-value";
1147
1199
  var n = decodeTop(buf, C, "SubjectKeyIdentifier");
1148
- try { return Buffer.concat([asn1.read.octetString(n)]); }
1200
+ try { return _bufferConcat([asn1.read.octetString(n)]); }
1149
1201
  catch (e) { throw ns.E(C, "SubjectKeyIdentifier must be an OCTET STRING (RFC 5280 sec. 4.2.1.2)", e); }
1150
1202
  }
1151
1203
 
@@ -1188,13 +1240,13 @@ function certExtensionDecoders(ns) {
1188
1240
  var C = ns.prefix + "/bad-crl-distribution-points";
1189
1241
  var kids = seqChildren(buf, C, "CRLDistributionPoints");
1190
1242
  if (kids.length < 1) throw ns.E(C, "CRLDistributionPoints must contain at least one DistributionPoint (RFC 5280 sec. 4.2.1.13)");
1191
- return kids.map(function (dp) {
1243
+ return _map(kids, function (dp) {
1192
1244
  if (dp.tagClass !== "universal" || dp.tagNumber !== _T.SEQUENCE || !dp.children) {
1193
1245
  throw ns.E(C, "DistributionPoint must be a SEQUENCE { distributionPoint?, reasons?, cRLIssuer? }");
1194
1246
  }
1195
1247
  var out = { distributionPoint: null, reasons: null, cRLIssuer: null };
1196
1248
  var lastTag = -1;
1197
- dp.children.forEach(function (f) {
1249
+ _forEach(dp.children, function (f) {
1198
1250
  if (f.tagClass !== "context") throw ns.E(C, "DistributionPoint fields are context-tagged [0]/[1]/[2]");
1199
1251
  if (f.tagNumber <= lastTag) throw ns.E(C, "DistributionPoint fields must be unique and in ascending order (DER)");
1200
1252
  lastTag = f.tagNumber;
@@ -1236,7 +1288,7 @@ function certExtensionDecoders(ns) {
1236
1288
  }
1237
1289
  function _qcOidSeq(node, C, what) { // a non-empty SEQUENCE OF OBJECT IDENTIFIER
1238
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");
1239
- return node.children.map(function (c) {
1291
+ return _map(node.children, function (c) {
1240
1292
  if (c.tagClass !== "universal" || c.tagNumber !== _T.OBJECT_IDENTIFIER) throw ns.E(C, what + " members must be OBJECT IDENTIFIERs");
1241
1293
  try { return asn1.read.oid(c); } catch (e) { throw ns.E(C, what + " member is not a valid OID", e); }
1242
1294
  });
@@ -1261,14 +1313,16 @@ function certExtensionDecoders(ns) {
1261
1313
  if (i !== node.children.length) throw ns.E(C, "SemanticsInformation has unexpected trailing fields");
1262
1314
  return { semanticsIdentifier: sid, nameRegistrationAuthorities: nras };
1263
1315
  }
1264
- 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);
1265
1319
  qcInfoByOid[O("qcCompliance")] = _qcPresenceOnly("QcCompliance");
1266
1320
  qcInfoByOid[O("qcSSCD")] = _qcPresenceOnly("QcSSCD");
1267
1321
  qcInfoByOid[O("qcsPkixQCSyntaxV1")] = _qcSemantics;
1268
1322
  qcInfoByOid[O("qcsPkixQCSyntaxV2")] = _qcSemantics;
1269
1323
  qcInfoByOid[O("qcType")] = function (node, C) {
1270
1324
  var oids = _qcOidSeq(node, C, "QcType"); // SIZE(1) in EN 319 412-5 V2.5.1; accept >=1 for legacy certs
1271
- 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; }) };
1272
1326
  };
1273
1327
  qcInfoByOid[O("qcRetentionPeriod")] = function (node, C) {
1274
1328
  if (!node) throw ns.E(C, "QcRetentionPeriod requires an INTEGER statementInfo");
@@ -1297,11 +1351,11 @@ function certExtensionDecoders(ns) {
1297
1351
  };
1298
1352
  qcInfoByOid[O("qcCClegislation")] = function (node, C) { // SEQUENCE OF CountryName (PrintableString SIZE 2)
1299
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");
1300
- 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; }) };
1301
1355
  };
1302
1356
  qcInfoByOid[O("qcPDS")] = function (node, C) { // PdsLocations ::= SEQUENCE OF PdsLocation { url IA5, language Printable(2) }
1303
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");
1304
- return { locations: node.children.map(function (loc) {
1358
+ return { locations: _map(node.children, function (loc) {
1305
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 }");
1306
1360
  var lang = _qcStr(loc.children[1], _T.PRINTABLE_STRING, C, "a QcPDS language must be a PrintableString");
1307
1361
  if (lang.length !== 2) throw ns.E(C, "a QcPDS language must be a 2-letter ISO 639-1 code");
@@ -1312,11 +1366,11 @@ function certExtensionDecoders(ns) {
1312
1366
  // QcQSCDlegislation (SEQUENCE OF CountryName, like QcCClegislation). Both are registered ids, decoded.
1313
1367
  qcInfoByOid[O("qcIdentMethod")] = function (node, C) {
1314
1368
  var oids = _qcOidSeq(node, C, "QcIdentMethod");
1315
- 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; }) };
1316
1370
  };
1317
1371
  qcInfoByOid[O("qcQSCDlegislation")] = function (node, C) {
1318
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");
1319
- 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; }) };
1320
1374
  };
1321
1375
  function qcStatements(buf) {
1322
1376
  var C = ns.prefix + "/bad-qc-statements", CS = ns.prefix + "/bad-qc-statement";
@@ -1333,7 +1387,7 @@ function certExtensionDecoders(ns) {
1333
1387
  var infoNode = st.children.length === 2 ? st.children[1] : null;
1334
1388
  var decoder = qcInfoByOid[id];
1335
1389
  var info = decoder ? decoder(infoNode, CS) : { opaque: true, bytes: infoNode ? infoNode.bytes : null };
1336
- 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 });
1337
1391
  }
1338
1392
  return out;
1339
1393
  }
@@ -1383,13 +1437,16 @@ function certExtensionDecoders(ns) {
1383
1437
  var C = ns.prefix + "/bad-ms-previous-cert-hash";
1384
1438
  var n = decodeTop(buf, C, "CAPrevCertHash");
1385
1439
  var hash;
1386
- try { hash = Buffer.concat([asn1.read.octetString(n)]); }
1440
+ try { hash = _bufferConcat([asn1.read.octetString(n)]); }
1387
1441
  catch (e) { throw ns.E(C, "CAPrevCertHash must be an OCTET STRING", e); }
1388
1442
  if (hash.length !== 20) throw ns.E(C, "CAPrevCertHash must be a 20-octet SHA-1 certificate thumbprint");
1389
1443
  return hash;
1390
1444
  }
1391
1445
 
1392
- 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);
1393
1450
  byOid[O("qcStatements")] = qcStatements;
1394
1451
  byOid[O("basicConstraints")] = basicConstraints;
1395
1452
  byOid[O("keyUsage")] = keyUsage;
@@ -1455,10 +1512,10 @@ function extensions(ns, opts) {
1455
1512
  var extOpts = {
1456
1513
  min: 1, code: ns.prefix + "/bad-extensions", what: "Extensions",
1457
1514
  unique: function (it) { return it.value.oid; }, dupCode: ns.prefix + "/duplicate-extension",
1458
- 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; }); },
1459
1516
  };
1460
1517
  if (opts.implicitTag != null) return schema.implicitSeqOf(opts.implicitTag, EXT, extOpts);
1461
- return schema.seqOf(EXT, Object.assign({ assert: "sequence" }, extOpts));
1518
+ return schema.seqOf(EXT, _assign({ assert: "sequence" }, extOpts));
1462
1519
  }
1463
1520
 
1464
1521
  // SubjectPublicKeyInfo ::= SEQUENCE { algorithm AlgorithmIdentifier,
@@ -1512,7 +1569,7 @@ function attribute(ns, opts) {
1512
1569
  return {
1513
1570
  type: t,
1514
1571
  name: ctx.oid.name(t) || null,
1515
- 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; }),
1516
1573
  };
1517
1574
  },
1518
1575
  });
@@ -1617,10 +1674,10 @@ function signedEnvelope(ns, tbsSchema, opts) {
1617
1674
  function dnsNameProblem(s) {
1618
1675
  if (typeof s !== "string" || !s.length) return "empty";
1619
1676
  if (s.length > 253) return "exceeds 253 octets";
1620
- if (/\s/.test(s)) return "whitespace";
1621
- if (s.charAt(0) === "." || s.charAt(s.length - 1) === ".") return "leading/trailing dot";
1622
- if (s.indexOf("_") !== -1) return "underscore forbidden in dNSName";
1623
- 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, ".");
1624
1681
  for (var i = 0; i < labels.length; i++) {
1625
1682
  var label = labels[i];
1626
1683
  if (label.length === 0) return "empty label";
@@ -1629,7 +1686,7 @@ function dnsNameProblem(s) {
1629
1686
  if (labels.length < 2) return "bare wildcard";
1630
1687
  continue;
1631
1688
  }
1632
- 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";
1633
1690
  }
1634
1691
  return null;
1635
1692
  }
@@ -52,6 +52,10 @@
52
52
 
53
53
  var C = require("./constants");
54
54
  var guard = require("./guard-all");
55
+ var intrinsic = require("./guard-intrinsic");
56
+ // Own-key membership through an operation taken at load. Written out, the question reads two
57
+ // replaceable properties to answer one thing, and here it decides which algorithms are supported.
58
+ var _hasOwn = intrinsic.hasOwn;
55
59
  var frameworkError = require("./framework-error");
56
60
  var validator = require("./validator-all");
57
61
  var ByteWriter = require("./byte-writer");
@@ -88,7 +92,7 @@ var LEVEL_OPT = {
88
92
  // guard on this runtime. An algorithm the guard cannot decompress must never be offered
89
93
  // or accepted: advertising one would mean accepting a message we then cannot open.
90
94
  var SUPPORTED = guard.compress.algorithms().filter(function (n) {
91
- return Object.prototype.hasOwnProperty.call(ALG_BY_NAME, n) && typeof COMPRESS[n] === "function";
95
+ return _hasOwn(ALG_BY_NAME, n) && typeof COMPRESS[n] === "function";
92
96
  });
93
97
 
94
98
  // The minimum Certificate message size and the widest opaque<..2^24-1> vector, both owned