@blamejs/pki 0.8.55 → 0.8.56

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 (50) hide show
  1. package/CHANGELOG.md +66 -0
  2. package/lib/acme.js +2 -2
  3. package/lib/asn1-der.js +17 -5
  4. package/lib/attrcert-verify.js +1 -1
  5. package/lib/cmc-verify.js +1 -1
  6. package/lib/cmp-session.js +2 -2
  7. package/lib/cmp-verify.js +2 -2
  8. package/lib/cms-decrypt.js +4 -1
  9. package/lib/cms-encrypt.js +4 -1
  10. package/lib/cms-sign.js +26 -12
  11. package/lib/cms-verify.js +1 -1
  12. package/lib/composite-kem.js +30 -12
  13. package/lib/composite-sig.js +42 -23
  14. package/lib/constants.js +7 -2
  15. package/lib/crl-verify.js +1 -1
  16. package/lib/crmf-sign.js +72 -43
  17. package/lib/crmf-verify.js +1 -1
  18. package/lib/csr-verify.js +1 -1
  19. package/lib/ct.js +2 -2
  20. package/lib/edwards-point.js +1 -1
  21. package/lib/est.js +3 -3
  22. package/lib/guard-async.js +22 -1
  23. package/lib/guard-bytes.js +6 -3
  24. package/lib/guard-identifier.js +1 -1
  25. package/lib/guard-intrinsic.js +474 -0
  26. package/lib/http-digest.js +146 -62
  27. package/lib/http-transport.js +82 -17
  28. package/lib/identity-match.js +2 -2
  29. package/lib/merkle.js +2 -2
  30. package/lib/ocsp-request-verify.js +1 -1
  31. package/lib/ocsp.js +46 -22
  32. package/lib/path-validate.js +169 -76
  33. package/lib/pbes2.js +14 -7
  34. package/lib/schema-attrcert.js +2 -2
  35. package/lib/schema-cmc.js +2 -2
  36. package/lib/schema-cmp.js +2 -2
  37. package/lib/schema-cms.js +2 -2
  38. package/lib/schema-crmf.js +2 -2
  39. package/lib/schema-csr.js +2 -2
  40. package/lib/schema-pkix.js +3 -3
  41. package/lib/schema-x509.js +2 -2
  42. package/lib/sigstore.js +1 -1
  43. package/lib/tlog.js +7 -4
  44. package/lib/trust.js +187 -104
  45. package/lib/tsp-sign.js +1 -1
  46. package/lib/webauthn-mds.js +257 -121
  47. package/lib/webauthn.js +327 -164
  48. package/lib/webcrypto.js +10 -3
  49. package/package.json +1 -1
  50. package/sbom.cdx.json +6 -6
package/lib/trust.js CHANGED
@@ -44,10 +44,25 @@ var intrinsic = require("./guard-intrinsic");
44
44
  var _hasOwn = intrinsic.hasOwn;
45
45
  var _charCodeAt = intrinsic.uncurry(String.prototype.charCodeAt);
46
46
  var _strSlice = intrinsic.uncurry(String.prototype.slice);
47
+ /** @internal The operations a Trust Bits cell is read through. The token lookup GRANTS a purpose, so
48
+ * read off the live prototype these decide what an anchor is trusted for: measured, with the fold
49
+ * replaced for one token, a row stating only `Email` produced an anchor carrying `serverAuth`. */
50
+ var _strSplit = intrinsic.uncurry(String.prototype.split);
51
+ var _strTrim = intrinsic.uncurry(String.prototype.trim);
52
+ var _charAt = intrinsic.uncurry(String.prototype.charAt);
53
+ var _arrIndexOf = intrinsic.uncurry(Array.prototype.indexOf);
54
+ var _arrJoin = intrinsic.uncurry(Array.prototype.join);
55
+ var _arrEvery = intrinsic.uncurry(Array.prototype.every);
47
56
  var x509 = require("./schema-x509");
48
57
  var pkix = require("./schema-pkix");
49
58
  var oid = require("./oid");
50
59
  var nodeFs = require("fs");
60
+ /** @internal The three file operations a CA bundle is read with, captured at load. The bytes they
61
+ * return become the host's trust anchors, so a replaced `readSync` substitutes the anchor set
62
+ * itself, which is a wider result than any single verdict. The exports are writable. */
63
+ var _fsOpenSync = nodeFs.openSync;
64
+ var _fsReadSync = nodeFs.readSync;
65
+ var _fsCloseSync = nodeFs.closeSync;
51
66
  var nodeTls = require("tls");
52
67
  var trustanchorSchema = require("./schema-trustanchor");
53
68
 
@@ -65,10 +80,10 @@ var PURPOSE_ATTRS = [
65
80
  ["CKA_TRUST_CODE_SIGNING", "codeSigning"],
66
81
  ];
67
82
 
68
- var CKT_RECOGNIZED = Object.create(null);
69
- ["CKT_NSS_TRUSTED_DELEGATOR", "CKT_NSS_TRUSTED", "CKT_NSS_MUST_VERIFY_TRUST",
70
- "CKT_NSS_TRUST_UNKNOWN", "CKT_NSS_NOT_TRUSTED", "CKT_NSS_VALID_DELEGATOR"]
71
- .forEach(function (t) { CKT_RECOGNIZED[t] = true; });
83
+ var CKT_RECOGNIZED = intrinsic.create(null);
84
+ intrinsic.forEach(["CKT_NSS_TRUSTED_DELEGATOR", "CKT_NSS_TRUSTED", "CKT_NSS_MUST_VERIFY_TRUST",
85
+ "CKT_NSS_TRUST_UNKNOWN", "CKT_NSS_NOT_TRUSTED", "CKT_NSS_VALID_DELEGATOR"],
86
+ function (t) { CKT_RECOGNIZED[t] = true; });
72
87
  var CKT_DELEGATOR = "CKT_NSS_TRUSTED_DELEGATOR";
73
88
 
74
89
  function _isNameChar(c) { return (c >= 65 && c <= 90) || (c >= 48 && c <= 57) || c === 95; }
@@ -105,16 +120,21 @@ function _unquote(s) {
105
120
  return _strSlice(s, 1, n - 1);
106
121
  }
107
122
 
123
+ /** @internal Each piece is APPENDED with the operation that defines an own property. An index
124
+ * assignment writes through Set, which walks the prototype for a numeric setter, so an accessor
125
+ * installed on `Array.prototype` takes the piece and the index reads back as whatever its getter
126
+ * answers: substituting a line of a certdata trust object replaced its `CK_TRUST` token, and a root
127
+ * the file marks NOT_TRUSTED produced an anchor trusted as a delegator for server authentication. */
108
128
  function _splitWhitespace(s) {
109
129
  var out = [], i = 0, n = s.length, pieceStart = 0;
110
130
  while (i < n) {
111
131
  if (_isWsCode(_charCodeAt(s, i))) {
112
- out[out.length] = _strSlice(s, pieceStart, i);
132
+ intrinsic.append(out, _strSlice(s, pieceStart, i));
113
133
  while (i < n && _isWsCode(_charCodeAt(s, i))) i += 1;
114
134
  pieceStart = i;
115
135
  } else i += 1;
116
136
  }
117
- out[out.length] = _strSlice(s, pieceStart);
137
+ intrinsic.append(out, _strSlice(s, pieceStart));
118
138
  return out;
119
139
  }
120
140
 
@@ -129,15 +149,15 @@ function _splitLines(text) {
129
149
  while (i < n) {
130
150
  var c = _charCodeAt(text, i);
131
151
  if (c === 13) {
132
- out[out.length] = _strSlice(text, start, i);
152
+ intrinsic.append(out, _strSlice(text, start, i));
133
153
  if (i + 1 < n && _charCodeAt(text, i + 1) === 10) i += 1;
134
154
  i += 1; start = i;
135
155
  } else if (c === 10) {
136
- out[out.length] = _strSlice(text, start, i);
156
+ intrinsic.append(out, _strSlice(text, start, i));
137
157
  i += 1; start = i;
138
158
  } else i += 1;
139
159
  }
140
- out[out.length] = _strSlice(text, start);
160
+ intrinsic.append(out, _strSlice(text, start));
141
161
  return out;
142
162
  }
143
163
 
@@ -164,25 +184,28 @@ function _readOctalBody(lines, idx) {
164
184
  var out = [];
165
185
  var cap = LIMITS.TRUST_MAX_OCTAL_BYTES;
166
186
  for (var i = idx; i < lines.length; i++) {
167
- var t = lines[i].trim();
168
- if (t === "END") return { bytes: Buffer.from(out), next: i + 1 };
187
+ var t = _strTrim(lines[i]);
188
+ /** @internal The bytes a MULTILINE_OCTAL body decodes to are constructed with the capture. This is
189
+ * the certificate DER itself, along with the CKA_ISSUER and CKA_SERIAL_NUMBER a pairing is decided
190
+ * on, so a replaced construction substitutes an anchor rather than steering one check. */
191
+ if (t === "END") return { bytes: intrinsic.bufferFrom(out), next: i + 1 };
169
192
  if (t === "") throw E("trust/bad-octal", "MULTILINE_OCTAL body interrupted by a blank line before END");
170
193
  var chunks = _splitWhitespace(t);
171
194
  for (var c = 0; c < chunks.length; c++) {
172
195
  var chunk = chunks[c];
173
196
  for (var k = 0; k < chunk.length; k += 4) {
174
- if (chunk.charCodeAt(k) !== 92 ) {
175
- throw E("trust/bad-octal", "MULTILINE_OCTAL expects \\ooo escapes, got " + JSON.stringify(chunk.slice(k, k + 4)));
197
+ if (_charCodeAt(chunk, k) !== 92 ) {
198
+ throw E("trust/bad-octal", "MULTILINE_OCTAL expects \\ooo escapes, got " + intrinsic.stringify(_strSlice(chunk, k, k + 4)));
176
199
  }
177
- var d = chunk.slice(k + 1, k + 4);
200
+ var d = _strSlice(chunk, k + 1, k + 4);
178
201
  if (!_isOctal3(d)) {
179
- throw E("trust/bad-octal", "a MULTILINE_OCTAL escape is a backslash + exactly three octal digits, got " + JSON.stringify("\\" + d));
202
+ throw E("trust/bad-octal", "a MULTILINE_OCTAL escape is a backslash + exactly three octal digits, got " + intrinsic.stringify("\\" + d));
180
203
  }
181
- if (d.charCodeAt(0) > 51 ) {
204
+ if (_charCodeAt(d, 0) > 51 ) {
182
205
  throw E("trust/bad-octal", "octal escape \\" + d + " exceeds \\377 (one byte)");
183
206
  }
184
207
  if (out.length >= cap) throw E("trust/bad-block", "MULTILINE_OCTAL blob exceeds LIMITS.TRUST_MAX_OCTAL_BYTES");
185
- out.push(parseInt(d, 8));
208
+ guard.list.append(out, intrinsic.parseInt(d, 8));
186
209
  }
187
210
  }
188
211
  }
@@ -194,27 +217,27 @@ function _lexObjects(text) {
194
217
  var n = lines.length;
195
218
  var i = 0, sawBegin = false;
196
219
  for (; i < n; i++) {
197
- if (lines[i].trim() === "BEGINDATA") { sawBegin = true; i++; break; }
220
+ if (_strTrim(lines[i]) === "BEGINDATA") { sawBegin = true; i++; break; }
198
221
  }
199
222
  if (!sawBegin) throw E("trust/bad-input", "not a certdata stream: no BEGINDATA line");
200
223
 
201
224
  var objects = [];
202
225
  var cur = null;
203
226
  while (i < n) {
204
- var t = lines[i].trim();
227
+ var t = _strTrim(lines[i]);
205
228
  if (t === "") {
206
- if (cur) { objects.push(cur); cur = null; }
229
+ if (cur) { guard.list.append(objects, cur); cur = null; }
207
230
  i++; continue;
208
231
  }
209
- if (t.charAt(0) === "#") { i++; continue; }
232
+ if (_charAt(t, 0) === "#") { i++; continue; }
210
233
  var m = _parseAttrLine(t);
211
- if (!m) throw E("trust/bad-block", "unexpected line in the certdata object stream: " + JSON.stringify(t.slice(0, 64)));
234
+ if (!m) throw E("trust/bad-block", "unexpected line in the certdata object stream: " + intrinsic.stringify(_strSlice(t, 0, 64)));
212
235
  var name = m[0], type = m[1];
213
- var rawVal = m[2] !== undefined ? m[2].trim() : undefined;
236
+ var rawVal = m[2] !== undefined ? _strTrim(m[2]) : undefined;
214
237
  if (!type) throw E("trust/bad-block", "attribute line is missing its type token: " + name);
215
238
  if (!cur) {
216
239
  if (objects.length >= LIMITS.TRUST_MAX_OBJECTS) throw E("trust/bad-block", "certdata object count exceeds LIMITS.TRUST_MAX_OBJECTS");
217
- cur = { attrs: Object.create(null) };
240
+ cur = { attrs: intrinsic.create(null) };
218
241
  }
219
242
  if (cur.attrs[name]) throw E("trust/bad-block", "duplicate attribute " + name + " within one object block");
220
243
 
@@ -235,18 +258,18 @@ function _lexObjects(text) {
235
258
  entry = { type: type, value: q };
236
259
  } else if (type === "CK_TRUST") {
237
260
  if (rawVal === undefined || _containsWs(rawVal)) throw E("trust/bad-block", name + " CK_TRUST must carry a single token value");
238
- if (!CKT_RECOGNIZED[rawVal]) throw E("trust/bad-trust-value", "unrecognized CK_TRUST value " + JSON.stringify(rawVal) + " on " + name);
261
+ if (!CKT_RECOGNIZED[rawVal]) throw E("trust/bad-trust-value", "unrecognized CK_TRUST value " + intrinsic.stringify(rawVal) + " on " + name);
239
262
  entry = { type: type, value: rawVal };
240
263
  } else if (type === "CK_OBJECT_CLASS" || type === "CK_CERTIFICATE_TYPE") {
241
264
  if (rawVal === undefined || _containsWs(rawVal)) throw E("trust/bad-block", name + " " + type + " must carry a single token value");
242
265
  entry = { type: type, value: rawVal };
243
266
  } else {
244
- throw E("trust/bad-block", "unrecognized attribute type " + JSON.stringify(type) + " on " + name);
267
+ throw E("trust/bad-block", "unrecognized attribute type " + intrinsic.stringify(type) + " on " + name);
245
268
  }
246
269
  cur.attrs[name] = entry;
247
270
  i++;
248
271
  }
249
- if (cur) objects.push(cur);
272
+ if (cur) guard.list.append(objects, cur);
250
273
  return objects;
251
274
  }
252
275
 
@@ -259,10 +282,13 @@ function _requireOctal(obj, name, what) {
259
282
  return a.bytes;
260
283
  }
261
284
 
285
+ /** @internal The TLV the time is decoded from is assembled with captured operations. A distrust date
286
+ * decides from when an anchor is no longer trusted for a purpose, so an assembly answering with a
287
+ * later date leaves a distrusted root in service. */
262
288
  function _strictTime(payload, code, label) {
263
289
  var tlv;
264
- if (payload.length === 13) tlv = Buffer.concat([Buffer.from([0x17, 0x0d]), payload]);
265
- else if (payload.length === 15) tlv = Buffer.concat([Buffer.from([0x18, 0x0f]), payload]);
290
+ if (payload.length === 13) tlv = intrinsic.bufferConcat([intrinsic.bufferFrom([0x17, 0x0d]), payload]);
291
+ else if (payload.length === 15) tlv = intrinsic.bufferConcat([intrinsic.bufferFrom([0x18, 0x0f]), payload]);
266
292
  else throw E(code, label + " must be a 13-byte UTCTime or a 15-byte GeneralizedTime payload, got " + payload.length + " bytes");
267
293
  try { return asn1.read.time(asn1.decode(tlv)); }
268
294
  catch (e) { throw E(code, label + " does not decode as a strict time", e); }
@@ -288,14 +314,17 @@ function _certEntry(obj) {
288
314
  var issuer = _requireOctal(obj, "CKA_ISSUER", "certificate");
289
315
  var serial = _requireOctal(obj, "CKA_SERIAL_NUMBER", "certificate");
290
316
 
291
- if (!issuer.equals(cert.issuer.bytes)) {
317
+ /** @internal Each of the three pairing refusals below compares through a captured operation. They
318
+ * decide that a certdata trust object describes THIS certificate, so one answering that two
319
+ * different values are equal attaches another object's purposes to it. */
320
+ if (!intrinsic.bufferEquals(issuer, cert.issuer.bytes)) {
292
321
  throw E("trust/pairing-mismatch", "CKA_ISSUER disagrees with the certificate's issuer DER");
293
322
  }
294
323
  var serialContentHex;
295
324
  try {
296
325
  var sn = asn1.decode(serial);
297
326
  asn1.read.integer(sn);
298
- serialContentHex = sn.content.toString("hex");
327
+ serialContentHex = intrinsic.bufToString(sn.content, "hex");
299
328
  } catch (e) {
300
329
  throw E("trust/pairing-mismatch", "CKA_SERIAL_NUMBER is not a DER INTEGER", e);
301
330
  }
@@ -303,7 +332,7 @@ function _certEntry(obj) {
303
332
  throw E("trust/pairing-mismatch", "CKA_SERIAL_NUMBER disagrees with the certificate's serial");
304
333
  }
305
334
  var subject = obj.attrs["CKA_SUBJECT"];
306
- if (subject && (subject.type !== "MULTILINE_OCTAL" || !subject.bytes.equals(cert.subject.bytes))) {
335
+ if (subject && (subject.type !== "MULTILINE_OCTAL" || !intrinsic.bufferEquals(subject.bytes, cert.subject.bytes))) {
307
336
  throw E("trust/pairing-mismatch", "CKA_SUBJECT disagrees with the certificate's subject DER");
308
337
  }
309
338
 
@@ -312,14 +341,17 @@ function _certEntry(obj) {
312
341
  var policy = obj.attrs["CKA_NSS_MOZILLA_CA_POLICY"];
313
342
  if (policy && policy.type !== "CK_BBOOL") throw E("trust/bad-block", "CKA_NSS_MOZILLA_CA_POLICY must be CK_BBOOL");
314
343
 
315
- var distrustAfter = {};
344
+ var distrustAfter = intrinsic.create(null);
316
345
  var server = _distrustDate(obj, "CKA_NSS_SERVER_DISTRUST_AFTER");
317
346
  if (server) distrustAfter.serverAuth = server;
318
347
  var email = _distrustDate(obj, "CKA_NSS_EMAIL_DISTRUST_AFTER");
319
348
  if (email) distrustAfter.emailProtection = email;
320
349
 
350
+ /** @internal The pairing key is built with the captured encoding. It is what a trust object and a
351
+ * certificate are matched on, so an encoding answering with another certificate's issuer or serial
352
+ * hands an otherwise orphaned object's delegator purposes to an unrelated certificate. */
321
353
  return {
322
- key: issuer.toString("hex") + "/" + serial.toString("hex"),
354
+ key: intrinsic.bufToString(issuer, "hex") + "/" + intrinsic.bufToString(serial, "hex"),
323
355
  der: der,
324
356
  cert: cert,
325
357
  label: label ? label.value : null,
@@ -333,13 +365,13 @@ function _trustEntry(obj) {
333
365
  var issuer = _requireOctal(obj, "CKA_ISSUER", "trust");
334
366
  var serial = _requireOctal(obj, "CKA_SERIAL_NUMBER", "trust");
335
367
  var purposes = intrinsic.assign(intrinsic.create(null), { serverAuth: false, emailProtection: false, codeSigning: false });
336
- PURPOSE_ATTRS.forEach(function (pair) {
368
+ intrinsic.forEach(PURPOSE_ATTRS, function (pair) {
337
369
  var a = obj.attrs[pair[0]];
338
370
  if (!a) return;
339
371
  if (a.type !== "CK_TRUST") throw E("trust/bad-block", pair[0] + " must be CK_TRUST");
340
372
  purposes[pair[1]] = a.value === CKT_DELEGATOR;
341
373
  });
342
- return { key: issuer.toString("hex") + "/" + serial.toString("hex"), purposes: purposes };
374
+ return { key: intrinsic.bufToString(issuer, "hex") + "/" + intrinsic.bufToString(serial, "hex"), purposes: purposes };
343
375
  }
344
376
 
345
377
 
@@ -366,9 +398,9 @@ function _mkAnchor(cert, meta) {
366
398
  }
367
399
  var derived = {
368
400
  name: _copyName(cert.subject),
369
- publicKey: Buffer.from(spki.bytes),
401
+ publicKey: intrinsic.bufferFrom(spki.bytes),
370
402
  algorithm: spki.algorithm.oid,
371
- parameters: spki.algorithm.parameters == null ? spki.algorithm.parameters : Buffer.from(spki.algorithm.parameters),
403
+ parameters: spki.algorithm.parameters == null ? spki.algorithm.parameters : intrinsic.bufferFrom(spki.algorithm.parameters),
372
404
  purposes: _purposesOrNull(meta.purposes),
373
405
  distrustAfter: _copyDistrustAfter(meta.distrustAfter),
374
406
  };
@@ -379,7 +411,7 @@ function _mkAnchor(cert, meta) {
379
411
  dc.pathLenConstraint = certPathLen;
380
412
  derived.constraints = dc;
381
413
  }
382
- _DERIVED_FROM.set(entry, derived);
414
+ intrinsic.weakSet(_DERIVED_FROM, entry, derived);
383
415
  return entry;
384
416
  }
385
417
  var _DERIVED_FROM = new WeakMap();
@@ -408,34 +440,44 @@ function _copyDistrustAfter(src) {
408
440
  if (!src || typeof src !== "object") return out;
409
441
  var names = guard.identifier.optionNames(src);
410
442
  for (var i = 0; i < names.length; i++) {
411
- out[names[i]] = guard.time.isDate(src[names[i]]) ? new Date(guard.time.instantOf(src[names[i]])) : src[names[i]];
443
+ out[names[i]] = guard.time.isDate(src[names[i]]) ? new intrinsic.Date(guard.time.instantOf(src[names[i]])) : src[names[i]];
412
444
  }
413
445
  return out;
414
446
  }
415
447
 
448
+ /** @internal The three classifications that decide whether a field is copied are captured. Each one
449
+ * answering `false` returns the caller's own object or buffer in place of the copy, which leaves the
450
+ * anchor's name mutable after it has been validated. */
416
451
  function _copyName(name) {
417
- if (!name || !Array.isArray(name.rdns)) return name;
452
+ if (!name || !intrinsic.isArray(name.rdns)) return name;
418
453
  var out = guard.identifier.ownOptions(name);
419
454
  out.rdns = guard.list.copyMap(name.rdns, function (rdn) {
420
- return Array.isArray(rdn) ? guard.list.copyMap(rdn, function (atv) { return guard.identifier.ownOptions(atv); }) : rdn;
455
+ return intrinsic.isArray(rdn) ? guard.list.copyMap(rdn, function (atv) { return guard.identifier.ownOptions(atv); }) : rdn;
421
456
  });
422
- out.bytes = Buffer.isBuffer(name.bytes) ? Buffer.from(name.bytes) : name.bytes;
457
+ out.bytes = intrinsic.isBuffer(name.bytes) ? intrinsic.bufferFrom(name.bytes) : name.bytes;
423
458
  return out;
424
459
  }
425
460
 
461
+ /** @internal The sort comes from the capture like the join and the test below it. Read off the live
462
+ * prototype it decides what the comparison SEES: a replacement answering with empty arrays makes the
463
+ * joins equal and the per-name test vacuous, so two rows for one root stop disagreeing without a
464
+ * single date being compared, and the pairing refusal is skipped while the later cutoff is kept. */
426
465
  function _datesEqual(x, y) {
427
- var kx = guard.identifier.optionNames(x).sort(), ky = guard.identifier.optionNames(y).sort();
428
- if (kx.join(",") !== ky.join(",")) return false;
429
- return kx.every(function (k) { return guard.time.instantOf(x[k]) === guard.time.instantOf(y[k]); });
466
+ var kx = intrinsic.sort(guard.identifier.optionNames(x)), ky = intrinsic.sort(guard.identifier.optionNames(y));
467
+ if (_arrJoin(kx, ",") !== _arrJoin(ky, ",")) return false;
468
+ return _arrEvery(kx, function (k) { return guard.time.instantOf(x[k]) === guard.time.instantOf(y[k]); });
430
469
  }
431
470
 
471
+ /** @internal The comparison that decides whether two rows for one root AGREE comes from the capture.
472
+ * A replacement answering `true` makes a conflicting pair compare equal, so the pairing refusal is
473
+ * skipped and the first row's grants are kept for both. */
432
474
  function _purposesEqual(x, y) {
433
- return PURPOSES.every(function (p) { return x[p] === y[p]; });
475
+ return _arrEvery(PURPOSES, function (p) { return x[p] === y[p]; });
434
476
  }
435
477
 
436
478
  function _paramsEqual(x, y) {
437
479
  if (x === null || y === null) return x === y;
438
- return Buffer.isBuffer(x) && Buffer.isBuffer(y) && x.equals(y);
480
+ return intrinsic.isBuffer(x) && intrinsic.isBuffer(y) && intrinsic.bufferEquals(x, y);
439
481
  }
440
482
 
441
483
  function _anchorsAgree(x, y) {
@@ -447,13 +489,17 @@ function _anchorsAgree(x, y) {
447
489
  _datesEqual(x.distrustAfter, y.distrustAfter);
448
490
  }
449
491
 
492
+ /** @internal The dedup key identifies a root by its subject and its key, and the map that holds the
493
+ * keys is constructed here. Both come from captures: an encoding that answers with another root's
494
+ * bytes, or a map already holding this root's key, makes a second row for one root compare against
495
+ * metadata it never carried, which is how a disagreeing pair passes the refusal below. */
450
496
  function _dedupAnchors(anchors) {
451
- var seen = Object.create(null);
497
+ var seen = intrinsic.create(null);
452
498
  var out = [];
453
- anchors.forEach(function (a) {
454
- var key = a.subjectDer.toString("hex") + "/" + a.publicKey.toString("hex");
499
+ intrinsic.forEach(anchors, function (a) {
500
+ var key = intrinsic.bufToString(a.subjectDer, "hex") + "/" + intrinsic.bufToString(a.publicKey, "hex");
455
501
  var prev = seen[key];
456
- if (!prev) { seen[key] = a; out.push(a); return; }
502
+ if (!prev) { seen[key] = a; guard.list.append(out, a); return; }
457
503
  if (!_anchorsAgree(prev, a)) {
458
504
  throw E("trust/pairing-mismatch", "two entries for one root (same subject + key) disagree on trust metadata");
459
505
  }
@@ -513,9 +559,12 @@ function parseCertdata(text) {
513
559
  var objects = _lexObjects(text);
514
560
 
515
561
  var certs = [];
516
- var byKey = Object.create(null);
562
+ /** @internal The pairing map is constructed from the capture. A map that already holds an entry
563
+ * under a key a trust object will present is the same bypass as a mis-encoded key: the lookup
564
+ * below finds it and the object's purposes reach a certificate it does not describe. */
565
+ var byKey = intrinsic.create(null);
517
566
  var trusts = [];
518
- objects.forEach(function (obj) {
567
+ intrinsic.forEach(objects, function (obj) {
519
568
  var cls = obj.attrs["CKA_CLASS"];
520
569
  if (!cls || cls.type !== "CK_OBJECT_CLASS") {
521
570
  throw E("trust/bad-block", "object block is missing CKA_CLASS CK_OBJECT_CLASS");
@@ -524,7 +573,7 @@ function parseCertdata(text) {
524
573
  var e = _certEntry(obj);
525
574
  var prev = byKey[e.key];
526
575
  if (prev) {
527
- if (!prev.der.equals(e.der) || prev.label !== e.label ||
576
+ if (!intrinsic.bufferEquals(prev.der, e.der) || prev.label !== e.label ||
528
577
  prev.mozillaCaPolicy !== e.mozillaCaPolicy ||
529
578
  !_datesEqual(prev.distrustAfter, e.distrustAfter)) {
530
579
  throw E("trust/pairing-mismatch", "two certificate objects share an (issuer, serial) but disagree");
@@ -532,13 +581,13 @@ function parseCertdata(text) {
532
581
  return;
533
582
  }
534
583
  byKey[e.key] = e;
535
- certs.push(e);
584
+ guard.list.append(certs, e);
536
585
  } else if (cls.value === "CKO_NSS_TRUST") {
537
- trusts.push(_trustEntry(obj));
586
+ guard.list.append(trusts, _trustEntry(obj));
538
587
  }
539
588
  });
540
589
 
541
- trusts.forEach(function (t) {
590
+ intrinsic.forEach(trusts, function (t) {
542
591
  var c = byKey[t.key];
543
592
  if (!c) return;
544
593
  if (c.purposes) {
@@ -551,7 +600,7 @@ function parseCertdata(text) {
551
600
  });
552
601
 
553
602
  return {
554
- anchors: _dedupAnchors(certs.map(function (c) {
603
+ anchors: _dedupAnchors(intrinsic.mapList(certs, function (c) {
555
604
  return _mkAnchor(c.cert, {
556
605
  distrustAfter: c.distrustAfter,
557
606
  purposes: c.purposes || _copyPurposes(null),
@@ -580,19 +629,24 @@ function _csvRows(text) {
580
629
  if (field.length >= fieldCap) throw E("trust/bad-csv", "a CSV field exceeds LIMITS.TRUST_MAX_CSV_FIELD_BYTES");
581
630
  field += c;
582
631
  }
583
- function endField() { row.push(field); field = ""; quoted = false; closed = false; }
632
+ function endField() { guard.list.append(row, field); field = ""; quoted = false; closed = false; }
584
633
  function endRow() {
585
634
  endField();
586
635
  if (rows.length >= LIMITS.TRUST_MAX_CSV_ROWS) throw E("trust/bad-csv", "CSV row count exceeds LIMITS.TRUST_MAX_CSV_ROWS");
587
- rows.push(row); row = [];
636
+ guard.list.append(rows, row); row = [];
588
637
  }
589
638
 
639
+ /** @internal The lexer reads every character through the capture. It decides which characters
640
+ * reach the cell readers, so a replaced `charAt` changes the TOKEN those readers are handed even
641
+ * though they read it safely: measured, feeding the characters of `Email` at a `Bogus` token's
642
+ * offsets turned a refusal into an anchor carrying `emailProtection`. Converting the readers alone
643
+ * left this, which is why the module is converted rather than the sites that kept being found. */
590
644
  var i = 0, n = text.length;
591
645
  while (i < n) {
592
- var ch = text.charAt(i);
646
+ var ch = _charAt(text, i);
593
647
  if (inQuotes) {
594
648
  if (ch === "\"") {
595
- if (text.charAt(i + 1) === "\"") { appendChar("\""); i += 2; continue; }
649
+ if (_charAt(text, i + 1) === "\"") { appendChar("\""); i += 2; continue; }
596
650
  inQuotes = false; closed = true; i++; continue;
597
651
  }
598
652
  appendChar(ch); i++; continue;
@@ -602,7 +656,7 @@ function _csvRows(text) {
602
656
  inQuotes = true; quoted = true; i++; continue;
603
657
  }
604
658
  if (ch === ",") { endField(); i++; continue; }
605
- if (ch === "\r" && text.charAt(i + 1) === "\n") { endRow(); i += 2; continue; }
659
+ if (ch === "\r" && _charAt(text, i + 1) === "\n") { endRow(); i += 2; continue; }
606
660
  if (ch === "\n" || ch === "\r") { endRow(); i++; continue; }
607
661
  if (closed) throw E("trust/bad-csv", "content after a closing quote (RFC 4180)");
608
662
  appendChar(ch); i++;
@@ -621,12 +675,20 @@ var _TRUST_BIT_TOKENS = intrinsic.assign(intrinsic.create(null), {
621
675
  });
622
676
  function _trustBits(cell) {
623
677
  var purposes = intrinsic.assign(intrinsic.create(null), { serverAuth: false, emailProtection: false, codeSigning: false });
624
- String(cell).split(";").forEach(function (tok) {
625
- var t = tok.trim();
678
+ /** @internal The string conversion is captured as well. A CSV field is already a string, so this
679
+ * guards the case where it is not; read off the live global it is one more operation that decides
680
+ * the TOKEN, and a `String` replacement mapping the cell `Email` to `Websites` reproduced the whole
681
+ * trust-widening bypass that the captured split, trim and fold had just closed. */
682
+ /** @internal The cell is scanned on the delimiter CHARACTER. A separator string carries a
683
+ * `Symbol.split` method the split operation is specified to look up and call, so capturing `split`
684
+ * leaves the separator's prototype chain in the operation; hard rule 11 bans `split` in lib/ for
685
+ * that reason. A hook answering `Websites` for a cell reading `Email` grants `serverAuth`. */
686
+ intrinsic.forEach(intrinsic.splitChar(intrinsic.String(cell), 59), function (tok) {
687
+ var t = _strTrim(tok);
626
688
  if (t === "") return;
627
- var l = t.toLowerCase();
689
+ var l = intrinsic.toLowerCase(t);
628
690
  if (!_hasOwn(_TRUST_BIT_TOKENS, l)) {
629
- throw E("trust/bad-csv", "unrecognized Trust Bits token " + JSON.stringify(t));
691
+ throw E("trust/bad-csv", "unrecognized Trust Bits token " + intrinsic.stringify(t));
630
692
  }
631
693
  var p = _TRUST_BIT_TOKENS[l];
632
694
  if (p) purposes[p] = true;
@@ -634,25 +696,30 @@ function _trustBits(cell) {
634
696
  return purposes;
635
697
  }
636
698
 
699
+ /** @internal The trim comes from the capture: an empty cell means NO distrust date, so a replacement
700
+ * answering with the empty string for a cell the parser would have refused removes a distrust date
701
+ * rather than failing. Measured, `not-a-date` trimmed to `""` turned `trust/bad-csv` into `null`. */
637
702
  function _csvDate(cell, label) {
638
- var s = String(cell).trim();
703
+ var s = _strTrim(intrinsic.String(cell));
639
704
  if (s === "") return null;
640
705
  var m = _parseYmd(s);
641
- if (!m) throw E("trust/bad-csv", label + " must be a Y-M-D date, got " + JSON.stringify(s));
706
+ if (!m) throw E("trust/bad-csv", label + " must be a Y-M-D date, got " + intrinsic.stringify(s));
642
707
  var pad = function (x) { return x.length === 1 ? "0" + x : x; };
643
- var payload = Buffer.from(m[0] + pad(m[1]) + pad(m[2]) + "235959Z", "latin1");
708
+ var payload = intrinsic.bufferFrom(m[0] + pad(m[1]) + pad(m[2]) + "235959Z", "latin1");
644
709
  try { return _strictTime(payload, "trust/bad-csv", label); }
645
710
  catch (e) {
646
711
  if (e && e.code === "trust/bad-csv") throw e;
647
- throw E("trust/bad-csv", label + " is not a real calendar date: " + JSON.stringify(s), e);
712
+ throw E("trust/bad-csv", label + " is not a real calendar date: " + intrinsic.stringify(s), e);
648
713
  }
649
714
  }
650
715
 
716
+ /** @internal The cell this reads holds the CERTIFICATE an anchor is built from, so the operations
717
+ * that unquote it come from the captures like the rest of the CSV path. */
651
718
  function _pemCell(cell) {
652
- var s = String(cell).trim();
653
- if (s.charAt(0) === "'") s = s.slice(1);
654
- if (s.charAt(s.length - 1) === "'") s = s.slice(0, -1);
655
- s = s.trim();
719
+ var s = _strTrim(intrinsic.String(cell));
720
+ if (_charCodeAt(s, 0) === 39) s = _strSlice(s, 1);
721
+ if (_charCodeAt(s, s.length - 1) === 39) s = _strSlice(s, 0, -1);
722
+ s = _strTrim(s);
656
723
  if (s === "") throw E("trust/bad-csv", "PEM Info cell is empty");
657
724
  try { return x509.parse(s); }
658
725
  catch (e) { throw E("trust/not-a-certificate", "PEM Info does not parse as an X.509 certificate", e); }
@@ -702,17 +769,28 @@ function parseCcadbCsv(text) {
702
769
  var rows = _csvRows(text);
703
770
  if (rows.length === 0) throw E("trust/bad-csv", "CSV input carries no header row");
704
771
 
705
- var header = rows[0].map(function (h) { return h.trim(); });
706
- var col = Object.create(null);
707
- header.forEach(function (h, idx) {
772
+ /** @internal The header names decide WHICH column each field is read from, so the trim comes from
773
+ * the capture. Read off the live prototype, a replacement that renames the real Trust Bits header
774
+ * and answers `Trust Bits` for another column makes the purposes come from that column: measured, a
775
+ * row stating `Email` produced an anchor carrying `serverAuth` taken from a decoy cell. */
776
+ var header = intrinsic.mapList(rows[0], function (h) { return _strTrim(h); });
777
+ /** @internal The name-to-index map is constructed from the capture as well. A map handed back
778
+ * already holding `Trust Bits` is the same result as a mis-trimmed header: the required-column
779
+ * check below finds the name present and every field is read from the column it names. */
780
+ var col = intrinsic.create(null);
781
+ /** @internal The iteration that maps a header NAME to its column index, and the membership test
782
+ * that refuses a duplicated required column, both come from the captures. A replaced `forEach`
783
+ * supplied the decoy column's index for `Trust Bits` and swapped the two distrust-date columns, and
784
+ * a replaced `indexOf` answering -1 let a duplicated required column through. */
785
+ intrinsic.forEach(header, function (h, idx) {
708
786
  if (col[h] !== undefined) {
709
- if (CSV_REQUIRED.indexOf(h) !== -1) throw E("trust/bad-csv", "duplicate required column " + JSON.stringify(h));
787
+ if (_arrIndexOf(CSV_REQUIRED, h) !== -1) throw E("trust/bad-csv", "duplicate required column " + intrinsic.stringify(h));
710
788
  return;
711
789
  }
712
790
  col[h] = idx;
713
791
  });
714
- CSV_REQUIRED.forEach(function (r) {
715
- if (col[r] === undefined) throw E("trust/bad-csv", "CSV is missing the required column " + JSON.stringify(r));
792
+ intrinsic.forEach(CSV_REQUIRED, function (r) {
793
+ if (col[r] === undefined) throw E("trust/bad-csv", "CSV is missing the required column " + intrinsic.stringify(r));
716
794
  });
717
795
 
718
796
  var anchors = [];
@@ -721,13 +799,13 @@ function parseCcadbCsv(text) {
721
799
  if (row.length !== header.length) {
722
800
  throw E("trust/bad-csv", "CSV row " + (i + 1) + " has " + row.length + " fields; the header has " + header.length);
723
801
  }
724
- var distrustAfter = {};
802
+ var distrustAfter = intrinsic.create(null);
725
803
  var tls = _csvDate(row[col["Distrust for TLS After Date"]], "Distrust for TLS After Date");
726
804
  if (tls) distrustAfter.serverAuth = tls;
727
805
  var smime = _csvDate(row[col["Distrust for S/MIME After Date"]], "Distrust for S/MIME After Date");
728
806
  if (smime) distrustAfter.emailProtection = smime;
729
- var label = row[col["Common Name or Certificate Name"]].trim();
730
- anchors.push(_mkAnchor(_pemCell(row[col["PEM Info"]]), {
807
+ var label = _strTrim(row[col["Common Name or Certificate Name"]]);
808
+ guard.list.append(anchors, _mkAnchor(_pemCell(row[col["PEM Info"]]), {
731
809
  distrustAfter: distrustAfter,
732
810
  purposes: _trustBits(row[col["Trust Bits"]]),
733
811
  label: label === "" ? null : label,
@@ -948,15 +1026,18 @@ function anchor(entry, opts) {
948
1026
  }
949
1027
  opts = guard.identifier.optionsObject(opts, E, "trust/bad-input", "pki.trust.anchor options");
950
1028
  guard.identifier.assertKnownKeys(opts, _ANCHOR_OPTS, E, "trust/bad-input", "unknown pki.trust.anchor option ");
951
- var derived = _DERIVED_FROM.get(entry);
1029
+ /** @internal The provenance lookup goes through the capture. A hit here is what says this entry is
1030
+ * one the store produced, so a replacement answering with metadata of its own both supplies the
1031
+ * purposes the gate below reads and waives the refusal that stops a rebuilt entry carrying them. */
1032
+ var derived = intrinsic.weakGet(_DERIVED_FROM, entry);
952
1033
  var meta = derived || entry;
953
- if (!derived && (!Buffer.isBuffer(entry.publicKey) || typeof entry.algorithm !== "string" ||
954
- !entry.name || !Array.isArray(entry.name.rdns))) {
1034
+ if (!derived && (!intrinsic.isBuffer(entry.publicKey) || typeof entry.algorithm !== "string" ||
1035
+ !entry.name || !intrinsic.isArray(entry.name.rdns))) {
955
1036
  throw E("trust/bad-input", "anchor expects a trust-store entry ({ name, publicKey, algorithm, ... })");
956
1037
  }
957
1038
  if (opts.purpose !== undefined) {
958
- if (PURPOSES.indexOf(opts.purpose) === -1) {
959
- throw E("trust/bad-input", "anchor: opts.purpose must be one of " + PURPOSES.join(" | "));
1039
+ if (_arrIndexOf(PURPOSES, opts.purpose) === -1) {
1040
+ throw E("trust/bad-input", "anchor: opts.purpose must be one of " + _arrJoin(PURPOSES, " | "));
960
1041
  }
961
1042
  if (!meta.purposes || meta.purposes[opts.purpose] !== true) {
962
1043
  throw E("trust/purpose-not-trusted", "this root is not a trusted delegator for " + opts.purpose);
@@ -968,9 +1049,9 @@ function anchor(entry, opts) {
968
1049
  var nameConstraints = _copyNameConstraints(opts.nameConstraints);
969
1050
  var out = {
970
1051
  name: _copyName(meta.name),
971
- publicKey: Buffer.isBuffer(meta.publicKey) ? Buffer.from(meta.publicKey) : meta.publicKey,
1052
+ publicKey: intrinsic.isBuffer(meta.publicKey) ? intrinsic.bufferFrom(meta.publicKey) : meta.publicKey,
972
1053
  algorithm: meta.algorithm,
973
- parameters: Buffer.isBuffer(meta.parameters) ? Buffer.from(meta.parameters)
1054
+ parameters: intrinsic.isBuffer(meta.parameters) ? intrinsic.bufferFrom(meta.parameters)
974
1055
  : (meta.parameters !== undefined ? meta.parameters : null),
975
1056
  distrustAfter: _copyDistrustAfter(meta.distrustAfter),
976
1057
  purposes: _purposesOrNull(meta.purposes),
@@ -1001,7 +1082,7 @@ function _copyConstraints(c) {
1001
1082
  excluded: _copySubtrees(c.nameConstraints.excluded, "excluded"),
1002
1083
  };
1003
1084
  }
1004
- if (c.policySet) out.policySet = intrinsic.map(c.policySet, function (p) { return p; });
1085
+ if (c.policySet) out.policySet = intrinsic.mapList(c.policySet, function (p) { return p; });
1005
1086
  if (c.policyFlags) {
1006
1087
  var f = intrinsic.create(null);
1007
1088
  intrinsic.forEach(trustanchorSchema.policyFlagBits, function (k) { f[k] = c.policyFlags[k] === true; });
@@ -1031,13 +1112,13 @@ function _anchorConstraintsOf(taInfo) {
1031
1112
  var any = false;
1032
1113
  if (cp.nameConstr !== null) {
1033
1114
  out.nameConstraints = {
1034
- permitted: intrinsic.map(cp.nameConstr.permittedSubtrees || [], _subtreeOf),
1035
- excluded: intrinsic.map(cp.nameConstr.excludedSubtrees || [], _subtreeOf),
1115
+ permitted: intrinsic.mapList(cp.nameConstr.permittedSubtrees || [], _subtreeOf),
1116
+ excluded: intrinsic.mapList(cp.nameConstr.excludedSubtrees || [], _subtreeOf),
1036
1117
  };
1037
1118
  any = true;
1038
1119
  }
1039
1120
  if (cp.policySet !== null) {
1040
- out.policySet = intrinsic.map(cp.policySet, function (p) { return p.policyIdentifier; });
1121
+ out.policySet = intrinsic.mapList(cp.policySet, function (p) { return p.policyIdentifier; });
1041
1122
  any = true;
1042
1123
  }
1043
1124
  if (cp.policyFlags !== null) { out.policyFlags = cp.policyFlags; any = true; }
@@ -1116,7 +1197,7 @@ function _entryFromAnchor(a, i) {
1116
1197
  * obvious thing. Keeping the constraints out of reach of that call would hand them an
1117
1198
  * UNCONSTRAINED anchor and silently drop every restriction the list stated. */
1118
1199
  if (constraints) guard.verdict.set(entry, "constraints", constraints);
1119
- _DERIVED_FROM.set(entry, {
1200
+ intrinsic.weakSet(_DERIVED_FROM, entry, {
1120
1201
  name: _copyName(info.certPath.taName),
1121
1202
  publicKey: intrinsic.bufferFrom(spki.bytes),
1122
1203
  algorithm: spki.algorithm.oid,
@@ -1194,26 +1275,26 @@ function discoversBundles(platform) {
1194
1275
  function _readBundleText(chosen, maxBytes) {
1195
1276
  var fd = null, raw, read;
1196
1277
  try {
1197
- fd = nodeFs.openSync(chosen, "r");
1278
+ fd = _fsOpenSync(chosen, "r");
1198
1279
  var buf = intrinsic.bufferAlloc(maxBytes + 1);
1199
1280
  /** @internal readSync may return fewer bytes than asked for, so the prefix of one call is not
1200
1281
  * the file. Taking it as the whole bundle would drop the roots below the break with nothing
1201
1282
  * reported, and would let a file above the cap pass the check underneath it. */
1202
1283
  read = 0;
1203
1284
  for (;;) {
1204
- var got = nodeFs.readSync(fd, buf, read, (maxBytes + 1) - read, read);
1285
+ var got = _fsReadSync(fd, buf, read, (maxBytes + 1) - read, read);
1205
1286
  if (got === 0) break;
1206
1287
  read += got;
1207
1288
  if (read >= maxBytes + 1) break;
1208
1289
  }
1209
- raw = buf.subarray(0, read);
1290
+ raw = intrinsic.byteSlice(buf, 0, read);
1210
1291
  } catch (e) {
1211
1292
  throw E("trust/no-readable-store", "no CA bundle could be read at " + guard.text.showValue(chosen) +
1212
1293
  "; " + _exportHint() + ", or pass opts.allowNodeBundle to use the Mozilla set compiled into " +
1213
1294
  "Node, which is NOT what this host trusts", e);
1214
1295
  } finally {
1215
1296
  if (fd !== null) {
1216
- try { nodeFs.closeSync(fd); }
1297
+ try { _fsCloseSync(fd); }
1217
1298
  // allow:swallow-unverified the descriptor is released on a best-effort basis
1218
1299
  catch (_e) { void 0; }
1219
1300
  }
@@ -1260,7 +1341,7 @@ function _readBundleText(chosen, maxBytes) {
1260
1341
  * console.log(store.skipped.length >= 0); // -> true (entries named, never dropped silently)
1261
1342
  */
1262
1343
  function systemAnchors(opts) {
1263
- opts = opts || {};
1344
+ opts = opts || intrinsic.create(null);
1264
1345
  guard.identifier.assertPlainRecord(opts, E, "trust/bad-input", "systemAnchors opts");
1265
1346
  guard.identifier.assertKnownKeys(opts, _SYSTEM_ANCHOR_OPTS, E, "trust/bad-input",
1266
1347
  "unknown systemAnchors option ");
@@ -1438,11 +1519,13 @@ function _systemResult(anchors, source, chosen, skipped) {
1438
1519
  return out;
1439
1520
  }
1440
1521
 
1441
- module.exports = {
1522
+ /** @internal Frozen, so a consumer that reads one of these off this object at the call cannot be
1523
+ * handed a replacement in place of it. */
1524
+ module.exports = intrinsic.freeze({
1442
1525
  parseCertdata: parseCertdata,
1443
1526
  parseCcadbCsv: parseCcadbCsv,
1444
1527
  parseTrustAnchorList: parseTrustAnchorList,
1445
1528
  systemAnchors: systemAnchors,
1446
1529
  discoversBundles: discoversBundles,
1447
1530
  anchor: anchor,
1448
- };
1531
+ });