node-opcua-pki 6.22.0 → 6.22.1

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.
package/dist/index.mjs CHANGED
@@ -411,8 +411,32 @@ function passinArg(passphrase = "") {
411
411
  function renderForDisplay(file, args) {
412
412
  return [file, ...args].map((a) => a === "" || /[\s"'`$\\]/.test(a) ? JSON.stringify(a) : a).join(" ");
413
413
  }
414
+ function hasUnsafeArgChar(value) {
415
+ for (const ch of value) {
416
+ const code = ch.codePointAt(0);
417
+ if (code < 32 || code === 127) {
418
+ return true;
419
+ }
420
+ if (code < 128) {
421
+ continue;
422
+ }
423
+ if (/[\p{L}\p{N}\p{M}]/u.test(ch)) {
424
+ continue;
425
+ }
426
+ return true;
427
+ }
428
+ return false;
429
+ }
430
+ function checkArgs(file, args) {
431
+ for (const value of [file, ...args]) {
432
+ if (typeof value === "string" && hasUnsafeArgChar(value)) {
433
+ throw new Error(`execute_openssl: refusing argument with an unexpected character: ${JSON.stringify(value)}`);
434
+ }
435
+ }
436
+ }
414
437
  async function execute2(file, args, options) {
415
438
  const from = new Error();
439
+ checkArgs(file, args);
416
440
  options.cwd = options.cwd || process.cwd();
417
441
  if (!g_config.silent) {
418
442
  warningLog(chalk2.cyan(" CWD "), options.cwd);
@@ -1128,18 +1152,31 @@ function makeFingerprint(certificate) {
1128
1152
  function short(stringToShorten) {
1129
1153
  return stringToShorten.substring(0, 10);
1130
1154
  }
1131
- var forbiddenChars = /[\x00-\x1F<>:"/\\|?*]/g;
1155
+ var disallowedInLabel = /[^A-Za-z0-9._ -]/g;
1156
+ function toFilenameLabel(commonName) {
1157
+ const label = (commonName || "").normalize("NFKC").replace(disallowedInLabel, "_").replace(/[^\x20-\x7E]/g, "").slice(0, 64).trim();
1158
+ return label || "certificate";
1159
+ }
1132
1160
  function buildIdealCertificateName(certificate) {
1133
1161
  const chain = coerceCertificateChain(certificate);
1134
1162
  const fingerprint = makeFingerprint(chain);
1135
1163
  try {
1136
1164
  const commonName = exploreCertificate(chain[0]).tbsCertificate.subject.commonName || "";
1137
- const sanitizedCommonName = commonName.replace(forbiddenChars, "_");
1165
+ const sanitizedCommonName = toFilenameLabel(commonName);
1138
1166
  return `${sanitizedCommonName}[${fingerprint}]`;
1139
1167
  } catch (_err) {
1140
1168
  return `invalid_certificate_[${fingerprint}]`;
1141
1169
  }
1142
1170
  }
1171
+ function safeStoreJoin(folder, filename) {
1172
+ const full = path4.resolve(folder, filename);
1173
+ const base = path4.resolve(folder);
1174
+ if (full !== base && !full.startsWith(base + path4.sep)) {
1175
+ warningLog("refusing to write certificate outside its store folder:", filename);
1176
+ throw new Error(`certificate filename escapes its store folder: ${filename}`);
1177
+ }
1178
+ return full;
1179
+ }
1143
1180
  function findMatchingIssuerKey(entries, wantedIssuerKey) {
1144
1181
  return entries.filter((entry) => {
1145
1182
  const info = getOrComputeInfo(entry);
@@ -1715,7 +1752,7 @@ var CertificateManager = class _CertificateManager extends EventEmitter {
1715
1752
  } catch (_err) {
1716
1753
  return "BadCertificateInvalid";
1717
1754
  }
1718
- const filename = path4.join(this.rejectedFolder, `${buildIdealCertificateName(leafCertificate)}.pem`);
1755
+ const filename = safeStoreJoin(this.rejectedFolder, `${buildIdealCertificateName(leafCertificate)}.pem`);
1719
1756
  debugLog("certificate has never been seen before and is now rejected (untrusted) ", filename);
1720
1757
  await fsWriteFile(filename, toPem(chain, "CERTIFICATE"));
1721
1758
  this.#thumbs.rejected.set(fingerprint, { certificate: leafCertificate, filename });
@@ -2123,7 +2160,7 @@ var CertificateManager = class _CertificateManager extends EventEmitter {
2123
2160
  if (this.#thumbs.issuers.certs.has(fingerprint)) {
2124
2161
  return "Good" /* Good */;
2125
2162
  }
2126
- const filename = path4.join(this.issuersCertFolder, `issuer_${buildIdealCertificateName(certificate)}.pem`);
2163
+ const filename = safeStoreJoin(this.issuersCertFolder, `issuer_${buildIdealCertificateName(certificate)}.pem`);
2127
2164
  await fs7.promises.writeFile(filename, pemCertificate, "ascii");
2128
2165
  this.#thumbs.issuers.certs.set(fingerprint, { certificate, filename });
2129
2166
  if (addInTrustList) {
@@ -2582,7 +2619,7 @@ var CertificateManager = class _CertificateManager extends EventEmitter {
2582
2619
  let status = await this.#checkRejectedOrTrusted(certificate);
2583
2620
  if (status === "unknown") {
2584
2621
  const pem = toPem(chain, "CERTIFICATE");
2585
- const filename = path4.join(this.rejectedFolder, `${buildIdealCertificateName(certificate)}.pem`);
2622
+ const filename = safeStoreJoin(this.rejectedFolder, `${buildIdealCertificateName(certificate)}.pem`);
2586
2623
  await fs7.promises.writeFile(filename, pem);
2587
2624
  this.#thumbs.rejected.set(fingerprint, { certificate, filename });
2588
2625
  status = "rejected";
@@ -2599,7 +2636,7 @@ var CertificateManager = class _CertificateManager extends EventEmitter {
2599
2636
  throw new Error(`#moveCertificate: certificate ${fingerprint.substring(0, 10)} not found in ${status} index`);
2600
2637
  }
2601
2638
  const destFolder = newStatus === "trusted" ? this.trustedFolder : this.rejectedFolder;
2602
- const certificateDest = path4.join(destFolder, path4.basename(srcEntry.filename));
2639
+ const certificateDest = safeStoreJoin(destFolder, path4.basename(srcEntry.filename));
2603
2640
  debugLog("#moveCertificate", fingerprint.substring(0, 10), "old name", srcEntry.filename);
2604
2641
  debugLog("#moveCertificate", fingerprint.substring(0, 10), "new name", certificateDest);
2605
2642
  await fs7.promises.rename(srcEntry.filename, certificateDest);
@@ -3101,6 +3138,8 @@ export {
3101
3138
  isRootIssuer,
3102
3139
  makeFingerprint,
3103
3140
  quote,
3104
- resolvePrivateKeyPassphrase
3141
+ resolvePrivateKeyPassphrase,
3142
+ safeStoreJoin,
3143
+ toFilenameLabel
3105
3144
  };
3106
3145
  //# sourceMappingURL=index.mjs.map