@blamejs/pki 0.8.58 → 0.8.60

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 (66) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/lib/acme.js +53 -30
  3. package/lib/alt-sig.js +3 -1
  4. package/lib/asn1-der.js +98 -39
  5. package/lib/attrcert-sign.js +19 -16
  6. package/lib/byte-writer.js +63 -13
  7. package/lib/cbor-det.js +9 -3
  8. package/lib/cmc-build.js +16 -10
  9. package/lib/cmp-build.js +45 -34
  10. package/lib/cmp-session.js +19 -9
  11. package/lib/cms-decrypt.js +28 -10
  12. package/lib/cms-encrypt.js +23 -17
  13. package/lib/cms-sign.js +65 -43
  14. package/lib/cms-verify.js +11 -7
  15. package/lib/crl-sign.js +27 -20
  16. package/lib/csr-sign.js +5 -2
  17. package/lib/ct.js +37 -17
  18. package/lib/est.js +55 -32
  19. package/lib/guard-bytes.js +5 -1
  20. package/lib/guard-der.js +6 -1
  21. package/lib/guard-identifier.js +1 -1
  22. package/lib/guard-intrinsic.js +12 -4
  23. package/lib/guard-list.js +64 -0
  24. package/lib/guard-name.js +1 -1
  25. package/lib/hpke.js +10 -3
  26. package/lib/http-transport.js +12 -3
  27. package/lib/inspect.js +10 -2
  28. package/lib/jose.js +3 -1
  29. package/lib/key.js +11 -7
  30. package/lib/lint.js +236 -152
  31. package/lib/mime.js +9 -5
  32. package/lib/ocsp.js +25 -22
  33. package/lib/path-validate.js +48 -18
  34. package/lib/pbes2.js +6 -2
  35. package/lib/pkcs11-uri.js +3 -1
  36. package/lib/pkcs12-build.js +14 -11
  37. package/lib/pki-build.js +18 -14
  38. package/lib/possession.js +3 -1
  39. package/lib/rc2.js +6 -2
  40. package/lib/revocation-fetch.js +78 -19
  41. package/lib/scep.js +14 -6
  42. package/lib/schema-attrcert.js +4 -2
  43. package/lib/schema-c509.js +94 -78
  44. package/lib/schema-cmc.js +5 -2
  45. package/lib/schema-cmp.js +6 -3
  46. package/lib/schema-cms.js +7 -4
  47. package/lib/schema-crl.js +1 -1
  48. package/lib/schema-crmf.js +1 -1
  49. package/lib/schema-csr.js +3 -3
  50. package/lib/schema-engine.js +36 -18
  51. package/lib/schema-pkcs1.js +7 -3
  52. package/lib/schema-pkcs12.js +9 -6
  53. package/lib/schema-pkix.js +19 -3
  54. package/lib/schema-sec1.js +4 -1
  55. package/lib/schema-tsp.js +4 -1
  56. package/lib/shbs.js +7 -3
  57. package/lib/sign-scheme.js +4 -4
  58. package/lib/smime.js +18 -14
  59. package/lib/tlog.js +17 -11
  60. package/lib/tuf.js +3 -1
  61. package/lib/validator-keydesc.js +4 -1
  62. package/lib/validator-tls.js +7 -2
  63. package/lib/webcrypto.js +14 -8
  64. package/lib/x509-sign.js +20 -15
  65. package/package.json +1 -1
  66. package/sbom.cdx.json +6 -6
package/lib/crl-sign.js CHANGED
@@ -24,6 +24,9 @@ var x509Schema = require("./schema-x509");
24
24
  var signScheme = require("./sign-scheme");
25
25
  var guard = require("./guard-all");
26
26
  var intrinsic = require("./guard-intrinsic");
27
+ /** @internal The append every list here is built with: `push` stores at the index and a store
28
+ * consults a setter inherited there, and these lists become the bytes that get signed. */
29
+ var _push = intrinsic.append;
27
30
  var _hasOwn = intrinsic.hasOwn, _bufferEquals = intrinsic.bufferEquals;
28
31
  var _arrSlice = intrinsic.arraySlice, _promiseResolve = intrinsic.uncurry(intrinsic.promiseResolve);
29
32
  /** @internal The RECEIVER for the captured `Promise.resolve`, captured too. `resolve` builds through
@@ -108,8 +111,8 @@ var KNOWN_REVOKED_KEYS = intrinsic.assign(intrinsic.create(null), {
108
111
  });
109
112
 
110
113
  var REQUIRED_CRITICALITY = intrinsic.create(null);
111
- [["cRLNumber", false], ["authorityKeyIdentifier", false], ["freshestCRL", false], ["authorityInfoAccess", false],
112
- ["issuingDistributionPoint", true], ["deltaCRLIndicator", true]].forEach(function (r) { REQUIRED_CRITICALITY[O(r[0])] = r[1]; });
114
+ intrinsic.forEach([["cRLNumber", false], ["authorityKeyIdentifier", false], ["freshestCRL", false], ["authorityInfoAccess", false],
115
+ ["issuingDistributionPoint", true], ["deltaCRLIndicator", true]], function (r) { REQUIRED_CRITICALITY[O(r[0])] = r[1]; });
113
116
 
114
117
  var REQUIRED_ENTRY_CRITICALITY = intrinsic.create(null);
115
118
  (function () {
@@ -184,11 +187,11 @@ function _idpValue(idp) {
184
187
  if (idp.fullName != null) {
185
188
  var entries = Array.isArray(idp.fullName) ? pkiBuild.reqDenseArray(idp.fullName, "issuingDistributionPoint.fullName", _err, "crl/bad-idp") : [idp.fullName];
186
189
  if (!entries.length) throw _err("crl/bad-idp", "issuingDistributionPoint fullName must carry at least one GeneralName");
187
- children.push(b.contextConstructed(0, b.contextConstructed(0, Buffer.concat(entries.map(_encodeGeneralName)))));
190
+ _push(children,b.contextConstructed(0, b.contextConstructed(0, Buffer.concat(entries.map(_encodeGeneralName)))));
188
191
  }
189
192
  var scopeTrue = 0;
190
- if (idp.onlyContainsUserCerts === true) { children.push(b.contextPrimitive(1, Buffer.from([0xff]))); scopeTrue++; }
191
- if (idp.onlyContainsCACerts === true) { children.push(b.contextPrimitive(2, Buffer.from([0xff]))); scopeTrue++; }
193
+ if (idp.onlyContainsUserCerts === true) { _push(children,b.contextPrimitive(1, Buffer.from([0xff]))); scopeTrue++; }
194
+ if (idp.onlyContainsCACerts === true) { _push(children,b.contextPrimitive(2, Buffer.from([0xff]))); scopeTrue++; }
192
195
  if (idp.indirectCRL === true) throw _err("crl/bad-idp", _INDIRECT_IDP_DEFERRED);
193
196
  if (scopeTrue > 1) throw _err("crl/bad-idp", "at most one of onlyContainsUserCerts / onlyContainsCACerts may be TRUE (RFC 5280 sec. 5.2.5)");
194
197
  if (!children.length) throw _err("crl/bad-idp", "issuingDistributionPoint MUST NOT be empty (RFC 5280 sec. 5.2.5)");
@@ -199,7 +202,7 @@ var _PRE_ENCODED_IDP_SCHEMA = pkix.issuingDistributionPoint("crl/bad-idp");
199
202
  function _validatePreEncodedIdp(inner) {
200
203
  if (!inner.children || !inner.children.length) throw _err("crl/bad-idp", "pre-encoded issuingDistributionPoint MUST NOT be empty (RFC 5280 sec. 5.2.5)");
201
204
  var f = schema.walk(_PRE_ENCODED_IDP_SCHEMA, inner, NS).fields;
202
- ["onlyContainsUserCerts", "onlyContainsCACerts", "onlyContainsAttributeCerts"].forEach(function (name) {
205
+ intrinsic.forEach(["onlyContainsUserCerts", "onlyContainsCACerts", "onlyContainsAttributeCerts"], function (name) {
203
206
  if (f[name].present && f[name].value !== true) throw _err("crl/bad-idp", "pre-encoded issuingDistributionPoint " + name + " encodes its DEFAULT FALSE, which DER omits (X.690 sec. 11.5)");
204
207
  });
205
208
  if (f.indirectCRL.present) throw _err("crl/bad-idp", _INDIRECT_IDP_DEFERRED);
@@ -232,7 +235,7 @@ function _buildCrlExtensions(spec, ctx) {
232
235
  var id = O(oidName);
233
236
  if (seen[id]) throw _err("crl/bad-input", "duplicate CRL extension " + oidName + " (RFC 5280 sec. 5.2 -- at most one instance)");
234
237
  seen[id] = true;
235
- out.push(_ext(id, critical, valueDer));
238
+ _push(out,_ext(id, critical, valueDer));
236
239
  }
237
240
  var crlNumberVal = null;
238
241
  if (spec.crlNumber != null) { var cn = _boundedInteger(spec.crlNumber, "cRLNumber"); crlNumberVal = cn.value; push("cRLNumber", false, cn.tlv); }
@@ -264,7 +267,7 @@ function _buildCrlExtensions(spec, ctx) {
264
267
  }
265
268
  _assertExtensionValueDecodes(node, extnId, "extension");
266
269
  if (extnId === O("deltaCRLIndicator")) isDelta = true;
267
- out.push(b.raw(der));
270
+ _push(out,b.raw(der));
268
271
  });
269
272
  if (isDelta) {
270
273
  if (seen[O("freshestCRL")]) throw _err("crl/bad-input", "freshestCRL MUST NOT appear in a delta CRL (RFC 5280 sec. 5.2.6)");
@@ -323,7 +326,7 @@ function _buildRevoked(entryList, isDelta) {
323
326
  var id = O(oidName);
324
327
  if (seen[id]) throw _err("crl/bad-input", "duplicate entry extension " + oidName + " in revoked entry [" + idx + "]");
325
328
  seen[id] = true;
326
- entryExts.push(_ext(id, critical, valueDer));
329
+ _push(entryExts,_ext(id, critical, valueDer));
327
330
  }
328
331
  if (e.reason != null) {
329
332
  var codeNum = _resolveReason(e.reason, isDelta);
@@ -360,10 +363,10 @@ function _buildRevoked(entryList, isDelta) {
360
363
  }
361
364
  }
362
365
  _assertExtensionValueDecodes(xnode, extnId, "entry extension");
363
- entryExts.push(b.raw(der));
366
+ _push(entryExts,b.raw(der));
364
367
  });
365
368
  }
366
- if (entryExts.length) { anyExt = true; children.push(b.sequence(entryExts)); }
369
+ if (entryExts.length) { anyExt = true; _push(children,b.sequence(entryExts)); }
367
370
  return b.sequence(children);
368
371
  });
369
372
  return { entries: entries, anyExt: anyExt };
@@ -375,7 +378,11 @@ function _parseIssuerCert(cert) {
375
378
  }
376
379
 
377
380
  function _assertIssuerCanSignCrl(issuerCert) {
378
- var kuExt = (issuerCert.extensions || []).filter(function (e) { return e.oid === O("keyUsage"); })[0];
381
+ /** @internal The selection returns the first matching row or null. `filter(...)[0]` indexes a
382
+ * result that is EMPTY when the certificate carries no keyUsage, and index 0 of an empty array
383
+ * answers from the array prototype, so a value installed there would be decoded as the issuer's
384
+ * key usage and decide whether it may sign this CRL. */
385
+ var kuExt = guard.list.firstMatch(issuerCert.extensions || [], function (e) { return e.oid === O("keyUsage"); });
379
386
  if (!kuExt) return;
380
387
  var ku;
381
388
  try { ku = EXT_DECODERS[O("keyUsage")](kuExt.value); }
@@ -453,13 +460,13 @@ function _sign(spec, issuer, opts) {
453
460
  * into the PreTBSCertList the alternative signature covers. */
454
461
  function tbsOver(extList, omitSignatureAlg) {
455
462
  var tbsChildren = [];
456
- if (version === 2) tbsChildren.push(b.integer(1n));
457
- if (omitSignatureAlg !== true) tbsChildren.push(scheme.sigAlgId);
458
- tbsChildren.push(issuerDer);
459
- tbsChildren.push(thisU);
460
- if (nextU) tbsChildren.push(nextU);
461
- if (revoked.entries.length) tbsChildren.push(b.sequence(revoked.entries));
462
- if (extList.length) tbsChildren.push(b.explicit(0, b.sequence(extList)));
463
+ if (version === 2) _push(tbsChildren,b.integer(1n));
464
+ if (omitSignatureAlg !== true) _push(tbsChildren,scheme.sigAlgId);
465
+ _push(tbsChildren,issuerDer);
466
+ _push(tbsChildren,thisU);
467
+ if (nextU) _push(tbsChildren,nextU);
468
+ if (revoked.entries.length) _push(tbsChildren,b.sequence(revoked.entries));
469
+ if (extList.length) _push(tbsChildren,b.explicit(0, b.sequence(extList)));
463
470
  return b.sequence(tbsChildren);
464
471
  }
465
472
 
@@ -813,7 +820,7 @@ function isRevoked(crl, serialNumber, opts) {
813
820
 
814
821
  function _findExtOid(list, name) {
815
822
  var want = O(name);
816
- return (list || []).filter(function (e) { return e.oid === want; })[0] || null;
823
+ return guard.list.firstMatch(list || [], function (e) { return e.oid === want; });
817
824
  }
818
825
 
819
826
  var _IDP_SCHEMA = pkix.issuingDistributionPoint("crl/scope-not-authoritative");
package/lib/csr-sign.js CHANGED
@@ -26,6 +26,9 @@ var pkiBuild = require("./pki-build");
26
26
  var frameworkError = require("./framework-error");
27
27
  var guard = require("./guard-all");
28
28
  var intrinsic = require("./guard-intrinsic");
29
+ /** @internal The append every list here is built with: `push` stores at the index and a store
30
+ * consults a setter inherited there, and these lists become the bytes that get signed. */
31
+ var _push = intrinsic.append;
29
32
  /** @internal The promise a self-check is awaited through, built from the constructor captured at load.
30
33
  * `Promise.resolve` builds from its RECEIVER, so reading the global binding at the call hands the
31
34
  * construction to whatever that binding holds, and a constructor settling without awaiting its
@@ -224,7 +227,7 @@ function _sign(spec, key, opts) {
224
227
  function addAttr(attrType, valueTlv) {
225
228
  if (seenAttr[attrType]) throw _err("csr/bad-input", "duplicate " + (oid.name(attrType) || attrType) + " attribute");
226
229
  seenAttr[attrType] = true;
227
- attrs.push(b.sequence([b.oid(attrType), b.set([valueTlv])]));
230
+ _push(attrs,b.sequence([b.oid(attrType), b.set([valueTlv])]));
228
231
  }
229
232
  if (spec.extensionRequest != null) addAttr(O("extensionRequest"), _buildRequestedExtensions(spec.extensionRequest, subjectSpki));
230
233
  if (spec.challengePassword != null) addAttr(O("challengePassword"), _challengePassword(spec.challengePassword));
@@ -259,7 +262,7 @@ function _sign(spec, key, opts) {
259
262
  if (!n.children[1].children || n.children[1].children.length === 0) throw _err("csr/bad-input", "pre-encoded attribute [" + i + "] value SET must contain at least one value (RFC 2986 SET SIZE(1..MAX))");
260
263
  if (seenAttr[at]) throw _err("csr/bad-input", "duplicate " + (oid.name(at) || at) + " attribute");
261
264
  seenAttr[at] = true;
262
- attrs.push(b.raw(der));
265
+ _push(attrs,b.raw(der));
263
266
  });
264
267
  }
265
268
 
package/lib/ct.js CHANGED
@@ -63,6 +63,8 @@ var _bufToString = intrinsic.bufToString;
63
63
  var _bufferCompare = intrinsic.compare;
64
64
  var _subarray = intrinsic.subarray;
65
65
  var _toLowerCase = intrinsic.toLowerCase;
66
+ var _ctTrim = intrinsic.uncurry(String.prototype.trim);
67
+ var _writeBigUInt64BE = intrinsic.uncurry(Buffer.prototype.writeBigUInt64BE);
66
68
  var _bufCopy = intrinsic.uncurry(Buffer.prototype.copy);
67
69
  var _writeU64BE = intrinsic.uncurry(Buffer.prototype.writeBigUInt64BE);
68
70
  var _searchSet = intrinsic.uncurry(URLSearchParams.prototype.set);
@@ -292,8 +294,11 @@ function parseSctList(extValue) {
292
294
  }
293
295
  sctCount.tick();
294
296
  var one = _parseSct(outer.subReader(sctLen, "ct/list-trailing-bytes"), sctLen);
295
- if (one.unknown) { var u = { version: one.version, rawSct: one.rawSct }; unknownScts.push(u); all.push(u); }
296
- else { scts.push(one); all.push(one); }
297
+ /** @internal The parsed timestamps are appended by defining their indexes: the lists a caller
298
+ * reads its verdict from, and the `all` list a policy counts, are what a numeric setter on the
299
+ * array prototype would otherwise take an entry out of. */
300
+ if (one.unknown) { var u = { version: one.version, rawSct: one.rawSct }; intrinsic.append(unknownScts, u); intrinsic.append(all, u); }
301
+ else { intrinsic.append(scts, one); intrinsic.append(all, one); }
297
302
  }
298
303
  return guard.verdict.of({ scts: scts, unknownScts: unknownScts, all: all });
299
304
  }
@@ -365,29 +370,36 @@ function reconstructSignedData(entry, sct) {
365
370
  throw new CtError("ct/bad-input", "reconstructSignedData expects a decoded v1 SCT from parseSctList().scts[]");
366
371
  }
367
372
  var tsVal = guard.range.uint64(sct.timestamp, _ctErr, "ct/bad-input", "sct.timestamp (RFC 6962 3.2)");
373
+ /** @internal EVERY component of this preimage is appended by defining its index, and the
374
+ * concatenation is the captured one. These bytes are what a log's signature is verified over, so a
375
+ * numeric setter inherited from the array prototype replacing any one of them, the version, the
376
+ * signature type, the timestamp, the entry type, the certificate or the extensions, puts the
377
+ * verification on bytes the log never signed. Converting only the timestamp left the rest open,
378
+ * which is the whole class: the rule belongs to the function, not to the line it was found on. */
368
379
  var parts = [];
369
- parts.push(_bufferFrom([sct.version & 0xff]));
370
- parts.push(_bufferFrom([0]));
371
- var ts = _bufferAlloc(8); ts.writeBigUInt64BE(tsVal); parts.push(ts);
372
- parts.push(_bufferFrom([(entryType >> 8) & 0xff, entryType & 0xff]));
380
+ intrinsic.append(parts, _bufferFrom([sct.version & 0xff]));
381
+ intrinsic.append(parts, _bufferFrom([0]));
382
+ var ts = _bufferAlloc(8); _writeBigUInt64BE(ts, tsVal); intrinsic.append(parts, ts);
383
+ intrinsic.append(parts, _bufferFrom([(entryType >> 8) & 0xff, entryType & 0xff]));
373
384
  if (entryType === 0) {
374
385
  var cert = _toBuffer(entry.leafCert, "leafCert", undefined, undefined, 0xffffff, "ct/bad-tbs-length");
375
- parts.push(_u24Bytes(cert.length)); parts.push(cert);
386
+ intrinsic.append(parts, _u24Bytes(cert.length)); intrinsic.append(parts, cert);
376
387
  } else {
377
388
  var ikh = _toBuffer(entry.issuerKeyHash, "issuerKeyHash");
378
389
  if (ikh.length !== 32) {
379
390
  throw new CtError("ct/bad-issuer-key-hash", "issuer_key_hash must be exactly 32 bytes (SHA-256 of the issuer SPKI), got " + ikh.length + " (RFC 6962 sec. 3.2)");
380
391
  }
381
392
  var tbs = _toBuffer(entry.tbsCertificate, "tbsCertificate", undefined, undefined, 0xffffff, "ct/bad-tbs-length");
382
- parts.push(ikh);
383
- parts.push(_u24Bytes(tbs.length)); parts.push(tbs);
393
+ intrinsic.append(parts, ikh);
394
+ intrinsic.append(parts, _u24Bytes(tbs.length)); intrinsic.append(parts, tbs);
384
395
  }
385
396
  var ext = _toBuffer(sct.extensions, "sct.extensions", undefined, undefined, 0xffff, "ct/bad-extensions");
386
397
  if (ext.length > 0xffff) {
387
398
  throw new CtError("ct/bad-extensions", "CtExtensions must be 0..65535 bytes, got " + ext.length + " (RFC 6962 3.2)");
388
399
  }
389
- parts.push(_bufferFrom([(ext.length >> 8) & 0xff, ext.length & 0xff])); parts.push(ext);
390
- return Buffer.concat(parts);
400
+ intrinsic.append(parts, _bufferFrom([(ext.length >> 8) & 0xff, ext.length & 0xff]));
401
+ intrinsic.append(parts, ext);
402
+ return intrinsic.bufferConcat(parts);
391
403
  }
392
404
 
393
405
  var CT_HASH = intrinsic.assign(intrinsic.create(null), { sha256: "SHA-256" });
@@ -583,7 +595,7 @@ function encodeSctList(scts) {
583
595
  var el = ew.build();
584
596
  total += el.length;
585
597
  if (total > 0xffff) throw new CtError("ct/too-large", "the SCT list body exceeds the 65535-byte maximum (RFC 6962 sec. 3.3)");
586
- elements.push(el);
598
+ intrinsic.append(elements, el);
587
599
  }
588
600
  var lw = new TlsWriter();
589
601
  lw.vector(2, 1, 0xffff, Buffer.concat(elements, total), "ct/too-large");
@@ -802,7 +814,7 @@ function parseLogList(json, opts) {
802
814
  continue;
803
815
  }
804
816
  byLogId[rec.logIdHex] = rec;
805
- logs.push(rec);
817
+ intrinsic.append(logs, rec);
806
818
  }
807
819
  }
808
820
  }
@@ -1091,13 +1103,13 @@ function x509CertEntry(cert, issuer) {
1091
1103
  for (var j = 0; j < extsSeq.children.length; j++) {
1092
1104
  var ext = extsSeq.children[j];
1093
1105
  if (ext.children[0] && intrinsic.bufferEquals(ext.children[0].bytes, sctOid)) { removed++; continue; }
1094
- intrinsic.push(kept, ext.bytes);
1106
+ intrinsic.append(kept, ext.bytes);
1095
1107
  }
1096
1108
  if (removed === 0) throw _ctErr("ct/no-sct-extension", "the certificate carries no signedCertificateTimestampList extension (RFC 6962 sec. 3.2)");
1097
1109
  var tbsChildren = [];
1098
1110
  for (var k = 0; k < tbs.children.length; k++) {
1099
- if (k !== wrapIdx) { intrinsic.push(tbsChildren, tbs.children[k].bytes); continue; }
1100
- if (kept.length > 0) intrinsic.push(tbsChildren, asn1.build.explicit(3, asn1.build.sequence(kept)));
1111
+ if (k !== wrapIdx) { intrinsic.append(tbsChildren, tbs.children[k].bytes); continue; }
1112
+ if (kept.length > 0) intrinsic.append(tbsChildren, asn1.build.explicit(3, asn1.build.sequence(kept)));
1101
1113
  }
1102
1114
  var issuerKeyHash = nodeCrypto.createHash("sha256").update(issSpki).digest();
1103
1115
  return { entryType: 1, tbsCertificate: asn1.build.sequence(tbsChildren), issuerKeyHash: issuerKeyHash };
@@ -1230,7 +1242,15 @@ function _assertTransport(opts) {
1230
1242
  "(request) => Promise<{ status, headers, body }>");
1231
1243
  }
1232
1244
 
1233
- function _fetchCtypeToken(headers) { return String((headers || {})["content-type"] || "").split(";")[0].trim().toLowerCase(); }
1245
+ /** @internal The media type is read through the captured operations, and on the delimiter CHARACTER
1246
+ * rather than through `split`, which hard rule 11 bans in lib/ because the separator's own
1247
+ * `Symbol.split` is part of that operation. The token decides which parser a log's response body is
1248
+ * handed to. */
1249
+ function _fetchCtypeToken(headers) {
1250
+ var raw = intrinsic.String((headers || {})["content-type"] || "");
1251
+ var parts = intrinsic.splitChar(raw, 59);
1252
+ return _toLowerCase(_ctTrim(parts.length ? parts[0] : ""));
1253
+ }
1234
1254
 
1235
1255
  function _parseHttpsUrl(u, label) {
1236
1256
  var parsed;
package/lib/est.js CHANGED
@@ -73,9 +73,15 @@ var crmfFmt = require("./schema-crmf");
73
73
  var frameworkError = require("./framework-error");
74
74
  var guard = require("./guard-all");
75
75
  var intrinsic = require("./guard-intrinsic");
76
+ /** @internal The append every list here is built with: `push` stores at the index and a store
77
+ * consults a setter inherited there, which takes the element being appended. */
78
+ var _push = intrinsic.append;
76
79
  var _charCodeAt = intrinsic.uncurry(String.prototype.charCodeAt);
77
80
  var _strSlice = intrinsic.uncurry(String.prototype.slice);
78
81
  var _toLowerCase = intrinsic.uncurry(String.prototype.toLowerCase);
82
+ var _estTrim = intrinsic.uncurry(String.prototype.trim);
83
+ var _estCharAt = intrinsic.uncurry(String.prototype.charAt);
84
+ var _estIndexOf = intrinsic.stringIndexOf;
79
85
  /** @internal Each verb gates its body on a resolved promise and returns its refusals as rejected ones,
80
86
  * and both build from the RECEIVER, so reading the global binding at the call decides whether the body
81
87
  * runs and whether a refusal stays a refusal. Taken at load. */
@@ -250,7 +256,7 @@ function _isMultipartMixedPrefix(ct) {
250
256
  }
251
257
 
252
258
  function _multipartBoundary(contentType) {
253
- var ct = String(contentType || "");
259
+ var ct = _stringOf(contentType || "");
254
260
  if (!_isMultipartMixedPrefix(ct)) return null;
255
261
  var bp = _ctParam(ct, "boundary");
256
262
  if (bp.duplicated) {
@@ -356,12 +362,16 @@ function splitMultipartMixed(body, contentType) {
356
362
  var lines = _splitCrlf(_unfoldHeaders(rawHeaders));
357
363
  for (var li = 0; li < lines.length; li++) {
358
364
  var line = lines[li];
359
- var col = line.indexOf(":");
360
- if (col > 0) headers[line.slice(0, col).trim().toLowerCase()] = line.slice(col + 1).trim();
365
+ /** @internal A part's header name and value are cut, trimmed and folded through the captured
366
+ * operations. One of those headers is the part's own content type, which selects the reader
367
+ * its body goes to: measured, a part stating `application/pkcs8` was read as
368
+ * `application/pkcs7-mime` with a `smime-type` of `certs-only`. */
369
+ var col = _estIndexOf(line, ":");
370
+ if (col > 0) headers[_toLowerCase(_estTrim(_strSlice(line, 0, col)))] = _estTrim(_strSlice(line, col + 1));
361
371
  }
362
372
  var partCt = headers["content-type"] || "";
363
373
  if (_ciStartsWith(partCt, "MULTIPART/")) throw E("est/bad-multipart", "a nested multipart part is not permitted");
364
- parts.push({ headers: headers, contentType: partCt, body: partBody });
374
+ intrinsic.append(parts, { headers: headers, contentType: partCt, body: partBody });
365
375
  }
366
376
  return parts;
367
377
  }
@@ -416,7 +426,7 @@ function findIssuedCert(certs, target) {
416
426
 
417
427
  function _recipientKeyIds(recipientInfos, kind) {
418
428
  var ids = [];
419
- function push(v) { if (Buffer.isBuffer(v)) ids.push(v); }
429
+ function push(v) { if (Buffer.isBuffer(v)) _push(ids,v); }
420
430
  (recipientInfos || []).forEach(function (r) {
421
431
  if (kind !== "symmetric") {
422
432
  if (r.rid) push(r.rid.subjectKeyIdentifier);
@@ -432,7 +442,7 @@ function _recipientKeyIds(recipientInfos, kind) {
432
442
 
433
443
  function _recipientIssuerSerials(recipientInfos) {
434
444
  var out = [];
435
- function push(rid) { if (rid && rid.issuer && Buffer.isBuffer(rid.issuer.bytes) && rid.serialNumber != null) out.push({ issuer: rid.issuer.bytes, serialNumber: rid.serialNumber }); }
445
+ function push(rid) { if (rid && rid.issuer && Buffer.isBuffer(rid.issuer.bytes) && rid.serialNumber != null) _push(out,{ issuer: rid.issuer.bytes, serialNumber: rid.serialNumber }); }
436
446
  (recipientInfos || []).forEach(function (r) {
437
447
  push(r.rid);
438
448
  if (r.kemri) push(r.kemri.rid);
@@ -457,29 +467,37 @@ function _recipientMatches(recipientInfos, opts) {
457
467
  return false;
458
468
  }
459
469
 
470
+ /** @internal The segments are collected through the captured append. Read off the prototype, a
471
+ * replacement decides which segments a parameter is then looked for in, and one of those parameters
472
+ * is the multipart boundary a response body is divided on: measured, a `boundary=wire` header
473
+ * yielded `forged`. */
460
474
  function _splitContentTypeParams(s) {
461
475
  var segs = [], cur = "", inQuote = false;
462
476
  for (var i = 0; i < s.length; i++) {
463
- var ch = s[i];
477
+ var ch = _estCharAt(s, i);
464
478
  if (ch === '"') { inQuote = !inQuote; cur += ch; }
465
- else if (ch === ";" && !inQuote) { segs.push(cur); cur = ""; }
479
+ else if (ch === ";" && !inQuote) { intrinsic.append(segs, cur); cur = ""; }
466
480
  else cur += ch;
467
481
  }
468
- segs.push(cur);
482
+ intrinsic.append(segs, cur);
469
483
  return segs;
470
484
  }
471
485
 
472
486
  function _ctParam(contentType, name) {
473
- var segs = _splitContentTypeParams(String(contentType || ""));
487
+ var segs = _splitContentTypeParams(_stringOf(contentType || ""));
474
488
  var value = null, count = 0;
489
+ /** @internal Each parameter is read through the captured operations. The name decides which
490
+ * parameter this is, and the value it returns is the one a caller acts on: for the RFC 7030
491
+ * multipart boundary, it is where a response body is split. */
475
492
  for (var i = 1; i < segs.length; i++) {
476
- var eq = segs[i].indexOf("=");
493
+ var seg = segs[i];
494
+ var eq = _estIndexOf(seg, "=");
477
495
  if (eq === -1) continue;
478
- if (segs[i].slice(0, eq).trim().toLowerCase() !== name) continue;
496
+ if (_toLowerCase(_estTrim(_strSlice(seg, 0, eq))) !== name) continue;
479
497
  count++;
480
498
  if (count > 1) continue;
481
- var val = segs[i].slice(eq + 1).trim();
482
- if (val.length >= 2 && val.charAt(0) === '"' && val.charAt(val.length - 1) === '"') val = val.slice(1, -1);
499
+ var val = _estTrim(_strSlice(seg, eq + 1));
500
+ if (val.length >= 2 && _estCharAt(val, 0) === '"' && _estCharAt(val, val.length - 1) === '"') val = _strSlice(val, 1, -1);
483
501
  value = val;
484
502
  }
485
503
  return { value: value, duplicated: count > 1 };
@@ -501,12 +519,15 @@ function _mediaType(seg) {
501
519
  return _toLowerCase(_strSlice(seg, a, b));
502
520
  }
503
521
 
522
+ /** @internal The media type and the S/MIME type are produced through the captured conversions. The
523
+ * media type selects which reader a part's body goes to, and read through the live global `String`
524
+ * a replacement chose it: measured, `text/plain` arrived as `application/pkcs8`. */
504
525
  function _partMediaType(contentType) {
505
- var segs = _splitContentTypeParams(String(contentType || ""));
526
+ var segs = _splitContentTypeParams(_stringOf(contentType || ""));
506
527
  var st = _ctParam(contentType, "smime-type");
507
528
  return {
508
529
  media: _mediaType(segs[0]),
509
- smimeType: st.value === null ? null : st.value.toLowerCase(),
530
+ smimeType: st.value === null ? null : _toLowerCase(st.value),
510
531
  ambiguous: st.duplicated,
511
532
  };
512
533
  }
@@ -740,7 +761,7 @@ function smimeCapabilitiesAttr(capabilities) {
740
761
  if (!Array.isArray(capabilities) || capabilities.length === 0) throw E("est/bad-input", "smimeCapabilitiesAttr requires a non-empty capability list");
741
762
  var caps = capabilities.map(function (c) {
742
763
  var seq = [asn1.build.oid(c.capabilityID)];
743
- if (c.parameters !== undefined && c.parameters !== null) seq.push(Buffer.isBuffer(c.parameters) ? c.parameters : asn1.build.oid(c.parameters));
764
+ if (c.parameters !== undefined && c.parameters !== null) _push(seq,Buffer.isBuffer(c.parameters) ? c.parameters : asn1.build.oid(c.parameters));
744
765
  return asn1.build.sequence(seq);
745
766
  });
746
767
  return _attr(OID_SMIME_CAPABILITIES, [asn1.build.sequence(caps)]);
@@ -762,7 +783,7 @@ function buildEnrollAttributes(csrattrsParsed) {
762
783
  if (plan.keyType) throw E("est/ambiguous-key-type", "a non-template CsrAttrs response must carry exactly one key-type attribute (RFC 9908 sec. 3.2)");
763
784
  plan.keyType = { type: it.name, curve: it.curve || null, keySize: it.keySize || null, values: it.values || [] };
764
785
  }
765
- else plan.unhandled.push({ kind: it.kind, oid: it.oid, name: it.name });
786
+ else _push(plan.unhandled,{ kind: it.kind, oid: it.oid, name: it.name });
766
787
  }
767
788
  return plan;
768
789
  }
@@ -1199,7 +1220,7 @@ function _correlateIssued(bag, wanted, arm) {
1199
1220
  function _allMatching(bag, key) {
1200
1221
  var rest = bag.slice(), out = [], hit;
1201
1222
  while ((hit = findIssuedCert(rest, key)) !== null) {
1202
- out.push(hit);
1223
+ _push(out,hit);
1203
1224
  rest = rest.filter(function (c) { return c !== hit; });
1204
1225
  }
1205
1226
  return out;
@@ -1222,7 +1243,7 @@ function _requestedPublicKeys(der) {
1222
1243
  try {
1223
1244
  if (r.certificationRequestBytes) {
1224
1245
  var spki = csr.parse(r.certificationRequestBytes).subjectPublicKeyInfo;
1225
- if (spki && Buffer.isBuffer(spki.bytes)) out.push(spki.bytes);
1246
+ if (spki && Buffer.isBuffer(spki.bytes)) _push(out,spki.bytes);
1226
1247
  if (out.length === before) _unreadableArm();
1227
1248
  return;
1228
1249
  }
@@ -1233,7 +1254,7 @@ function _requestedPublicKeys(der) {
1233
1254
  var pk = (tmpl && tmpl.publicKey) ||
1234
1255
  (msg0 && msg0.popo && msg0.popo.poposkInput && msg0.popo.poposkInput.publicKey);
1235
1256
  var pkBytes = Buffer.isBuffer(pk) ? pk : (pk && pk.bytes);
1236
- if (Buffer.isBuffer(pkBytes)) out.push(pkBytes);
1257
+ if (Buffer.isBuffer(pkBytes)) _push(out,pkBytes);
1237
1258
  if (out.length === before) _unreadableArm();
1238
1259
  }
1239
1260
  } catch (e) {
@@ -1279,9 +1300,9 @@ function _requestBinding(der) {
1279
1300
  var body = cmcFmt.parse(der);
1280
1301
  var ids = [];
1281
1302
  var paths = [];
1282
- [body.requests, body.controls, body.cmsSequence, body.otherMsgs].forEach(function (list) {
1303
+ intrinsic.forEach([body.requests, body.controls, body.cmsSequence, body.otherMsgs], function (list) {
1283
1304
  (list || []).forEach(function (el) {
1284
- if (el && el.bodyPartID != null) { ids.push(el.bodyPartID); paths.push([el.bodyPartID]); }
1305
+ if (el && el.bodyPartID != null) { _push(ids,el.bodyPartID); _push(paths,[el.bodyPartID]); }
1285
1306
  });
1286
1307
  });
1287
1308
  _collectNestedPaths(body.cmsSequence, [], paths, 0);
@@ -1325,8 +1346,8 @@ function _collectNestedPaths(list, prefix, out, depth) {
1325
1346
  catch (_e) { /* allow:swallow-unverified the outer request must itself parse for this to run, which already rejects a malformed nested ContentInfo; a payload that survives that and still fails to read back lands on the same no-path refusal the non-pkiData route below takes, which the vectors drive */ return; }
1326
1347
  if (!inner || inner.kind !== "pkiData") return;
1327
1348
  var path = prefix.concat([el.bodyPartID]);
1328
- [inner.requests, inner.controls, inner.cmsSequence, inner.otherMsgs].forEach(function (l) {
1329
- (l || []).forEach(function (e2) { if (e2 && e2.bodyPartID != null) out.push(path.concat([e2.bodyPartID])); });
1349
+ intrinsic.forEach([inner.requests, inner.controls, inner.cmsSequence, inner.otherMsgs], function (l) {
1350
+ (l || []).forEach(function (e2) { if (e2 && e2.bodyPartID != null) _push(out,path.concat([e2.bodyPartID])); });
1330
1351
  });
1331
1352
  _collectNestedPaths(inner.cmsSequence, path, out, depth + 1);
1332
1353
  });
@@ -1405,7 +1426,7 @@ function _fullcmcResult(res, opts, wanted, sent) {
1405
1426
  }
1406
1427
  var smimeType = pt200.smimeType;
1407
1428
  if (smimeType === "certs-only") {
1408
- var unecho = ["transactionId", "senderNonce", "dataReturn"].filter(function (k) {
1429
+ var unecho = intrinsic.selectList(["transactionId", "senderNonce", "dataReturn"], function (k) {
1409
1430
  return sent[k] != null;
1410
1431
  });
1411
1432
  if (unecho.length) {
@@ -1731,21 +1752,23 @@ function _assertConfidentialCipher(res) {
1731
1752
 
1732
1753
  function _ciHeaderList(headers, name) {
1733
1754
  headers = headers || {};
1734
- var lname = name.toLowerCase(), keys = guard.identifier.optionNames(headers), parts = [];
1755
+ /** @internal The header NAME a value is selected under is folded through the captured conversion on
1756
+ * both sides of the comparison: the match decides which header this response is read from. */
1757
+ var lname = _toLowerCase(name), keys = guard.identifier.optionNames(headers), parts = [];
1735
1758
  for (var i = 0; i < keys.length; i++) {
1736
- if (keys[i].toLowerCase() !== lname) continue;
1759
+ if (_toLowerCase(keys[i]) !== lname) continue;
1737
1760
  var v = headers[keys[i]];
1738
1761
  if (v == null) continue;
1739
- parts.push(Array.isArray(v) ? v.join(", ") : String(v));
1762
+ intrinsic.append(parts, intrinsic.isArray(v) ? intrinsic.join(v, ", ") : _stringOf(v));
1740
1763
  }
1741
- return parts.length ? parts.join(", ") : null;
1764
+ return parts.length ? intrinsic.join(parts, ", ") : null;
1742
1765
  }
1743
1766
 
1744
1767
  function _ciHeader(headers, name) {
1745
1768
  headers = headers || {};
1746
- var lname = name.toLowerCase(), keys = guard.identifier.optionNames(headers), found = null, n = 0;
1769
+ var lname = _toLowerCase(name), keys = guard.identifier.optionNames(headers), found = null, n = 0;
1747
1770
  for (var i = 0; i < keys.length; i++) {
1748
- if (keys[i].toLowerCase() !== lname) continue;
1771
+ if (_toLowerCase(keys[i]) !== lname) continue;
1749
1772
  n += 1;
1750
1773
  if (n === 1) found = headers[keys[i]];
1751
1774
  }
@@ -446,7 +446,11 @@ function _deep(v, ErrorClass, code, label, cap, depth, collect, work) {
446
446
  var element;
447
447
  try { element = v[k]; }
448
448
  catch (e) { throw _raise(ErrorClass, code, label + ": reading element " + k + " threw", e); }
449
- arr[k] = _deep(element, ErrorClass, code, label, cap, depth + 1, collect, work);
449
+ /** @internal The copy's slot is DEFINED, not stored at. The indices walked here are the ones
450
+ * the source holds of its own, so they can skip: a store at an index this copy has no own
451
+ * property at walks the prototype chain for a setter, which would take the copied element at
452
+ * the toolkit's own door for caller byte structures. */
453
+ _defineProperty(arr, k, { value: _deep(element, ErrorClass, code, label, cap, depth + 1, collect, work), writable: true, enumerable: true, configurable: true });
450
454
  });
451
455
  arr.length = vCount;
452
456
  _copyNamed(v, arr, ErrorClass, code, label, cap, depth, collect, work);
package/lib/guard-der.js CHANGED
@@ -9,6 +9,7 @@ var _sizeOf = require("./guard-intrinsic").sizeOf;
9
9
  var _create = require("./guard-intrinsic").create;
10
10
  var _isBuffer = require("./guard-intrinsic").isBuffer;
11
11
  var _isArray = require("./guard-intrinsic").isArray;
12
+ var _append = require("./guard-intrinsic").append;
12
13
 
13
14
  var asn1 = null;
14
15
  function _asn1() { if (asn1 === null) asn1 = require("./asn1-der"); return asn1; }
@@ -117,7 +118,11 @@ function _element(node, E, code, label) {
117
118
  throw E(code, label + " of universal constructed type " + tag + " has no strict DER structure validator here");
118
119
  }
119
120
  var n = kids.length, members = [];
120
- for (var i = 0; i < n; i++) members[i] = _element(kids[i], E, code, label);
121
+ /** @internal Appended by defining the index. A store at an index the list has no own property at
122
+ * consults a setter inherited from the array prototype, and the SET ordering below is checked
123
+ * over this list, so a member read back through such a hole is one the canonical-order check
124
+ * never saw. */
125
+ for (var i = 0; i < n; i++) _append(members, _element(kids[i], E, code, label));
121
126
  if (cls === "universal" && tag === C.SET && !setOrderOk(members)) {
122
127
  throw E(code, label + " has a SET whose members are in no canonical DER order (X.690 sec. 11.6 / X.680 sec. 8.6)");
123
128
  }
@@ -257,7 +257,7 @@ var _CONCRETE_TYPED_MEMBERS = ["BYTES_PER_ELEMENT"];
257
257
  var _BUFFER_PROTO_MEMBERS = ["parent", "offset"];
258
258
 
259
259
  var _ARRAY_MEMBERS = _ARRAY_PROTO_MEMBERS;
260
- var _REGEXP_MEMBERS = ["lastIndex"].concat(_REGEXP_PROTO_MEMBERS);
260
+ var _REGEXP_MEMBERS = intrinsic.concatList(["lastIndex"], _REGEXP_PROTO_MEMBERS);
261
261
  var _VIEW_MEMBERS = _TYPED_PROTO_MEMBERS.concat(_CONCRETE_TYPED_MEMBERS);
262
262
  var _BUFFER_KIND_MEMBERS = _VIEW_MEMBERS.concat(_BUFFER_PROTO_MEMBERS);
263
263
  var _DATAVIEW_MEMBERS = _DATAVIEW_PROTO_MEMBERS;
@@ -528,14 +528,24 @@ var _arrSort = uncurry(Array.prototype.sort);
528
528
  var _arrConcat = uncurry(Array.prototype.concat);
529
529
  var _arrSlice = uncurry(Array.prototype.slice);
530
530
  var _arrJoin = uncurry(Array.prototype.join);
531
- var _arrPush = uncurry(Array.prototype.push);
531
+ /** @internal `push` is NOT captured and NOT offered. Capturing it closes who `push` is, not what
532
+ * `push` DOES: it STORES at the index, and a store walks the prototype chain for a setter, so an
533
+ * accessor installed at an array index receives each element as it is appended and can define
534
+ * something else in its place. Measured through `pki.asn1.read.oid`: the content octets of `1.2.3`
535
+ * rendered `0.1.3` through a captured push. `append` below defines the index on the array itself,
536
+ * and `concatList` / `copyList` / `selectList` / `mapList` build their results the same way. With
537
+ * nothing to reach for, no module in lib/ can take the storing form. */
532
538
  /** @internal The mutators. A list is what a rule is enforced over, so an operation that drops or moves
533
539
  * an element decides whether the rule reaches it: a replaced `pop` that popped twice took a signed
534
540
  * note's last signature line away with the empty tail element, and the forged signature on that line
535
541
  * was never checked. */
542
+ /** @internal `unshift` is absent for the reason `push` is: it GROWS the list, so it stores at an
543
+ * index the array has no own property at, and a store walks the prototype chain for a setter. The
544
+ * mutators kept below move or drop elements that already have own slots, which reaches no accessor
545
+ * on a list this toolkit built by defining. A module prepending to a list counts its elements and
546
+ * appends them in order instead; `encodeLength` and `intToDer` in lib/asn1-der.js are the pattern. */
536
547
  var _arrPop = uncurry(Array.prototype.pop);
537
548
  var _arrShift = uncurry(Array.prototype.shift);
538
- var _arrUnshift = uncurry(Array.prototype.unshift);
539
549
  var _arrSplice = uncurry(Array.prototype.splice);
540
550
  var _arrReverse = uncurry(Array.prototype.reverse);
541
551
 
@@ -706,10 +716,8 @@ module.exports = Object.freeze({
706
716
  min: _mathMin,
707
717
  max: _mathMax,
708
718
  parseInt: _parseInt,
709
- push: _arrPush,
710
719
  pop: _arrPop,
711
720
  shift: _arrShift,
712
- unshift: _arrUnshift,
713
721
  splice: _arrSplice,
714
722
  reverse: _arrReverse,
715
723
  toUpperCase: _strToUpperCase,