node-opcua-pki 6.10.2 → 6.11.0

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.js CHANGED
@@ -51,13 +51,17 @@ __export(lib_exports, {
51
51
  module.exports = __toCommonJS(lib_exports);
52
52
 
53
53
  // packages/node-opcua-pki/lib/ca/certificate_authority.ts
54
- var import_node_assert6 = __toESM(require("assert"));
55
- var import_node_fs6 = __toESM(require("fs"));
54
+ var import_node_assert7 = __toESM(require("assert"));
55
+ var import_node_fs7 = __toESM(require("fs"));
56
56
  var import_node_os3 = __toESM(require("os"));
57
57
  var import_node_path5 = __toESM(require("path"));
58
58
  var import_chalk5 = __toESM(require("chalk"));
59
59
  var import_node_opcua_crypto2 = require("node-opcua-crypto");
60
60
 
61
+ // packages/node-opcua-pki/lib/pki/toolbox_pfx.ts
62
+ var import_node_assert4 = __toESM(require("assert"));
63
+ var import_node_fs4 = __toESM(require("fs"));
64
+
61
65
  // packages/node-opcua-pki/lib/toolbox/common.ts
62
66
  var import_node_assert = __toESM(require("assert"));
63
67
  function quote(str) {
@@ -134,30 +138,13 @@ function makePath(folderName, filename) {
134
138
  return s;
135
139
  }
136
140
 
137
- // packages/node-opcua-pki/lib/toolbox/display.ts
138
- var import_chalk2 = __toESM(require("chalk"));
139
- function displayTitle(str) {
140
- if (!g_config.silent) {
141
- warningLog("");
142
- warningLog(import_chalk2.default.yellowBright(str));
143
- warningLog(import_chalk2.default.yellow(new Array(str.length + 1).join("=")), "\n");
144
- }
145
- }
146
- function displaySubtitle(str) {
147
- if (!g_config.silent) {
148
- warningLog("");
149
- warningLog(` ${import_chalk2.default.yellowBright(str)}`);
150
- warningLog(` ${import_chalk2.default.white(new Array(str.length + 1).join("-"))}`, "\n");
151
- }
152
- }
153
- function display(str) {
154
- if (!g_config.silent) {
155
- warningLog(` ${str}`);
156
- }
157
- }
158
-
159
- // packages/node-opcua-pki/lib/toolbox/with_openssl/index.ts
160
- var import_node_constants = __toESM(require("constants"));
141
+ // packages/node-opcua-pki/lib/toolbox/with_openssl/execute_openssl.ts
142
+ var import_node_assert3 = __toESM(require("assert"));
143
+ var import_node_child_process2 = __toESM(require("child_process"));
144
+ var import_node_fs3 = __toESM(require("fs"));
145
+ var import_node_os2 = __toESM(require("os"));
146
+ var import_byline2 = __toESM(require("byline"));
147
+ var import_chalk3 = __toESM(require("chalk"));
161
148
 
162
149
  // packages/node-opcua-pki/lib/toolbox/with_openssl/_env.ts
163
150
  var exportedEnvVars = {};
@@ -198,22 +185,6 @@ function processAltNames(params) {
198
185
  setEnv("ALTNAME", subjectAltNameString);
199
186
  }
200
187
 
201
- // packages/node-opcua-pki/lib/toolbox/with_openssl/create_certificate_signing_request.ts
202
- var import_node_assert5 = __toESM(require("assert"));
203
- var import_node_fs5 = __toESM(require("fs"));
204
- var import_node_path4 = __toESM(require("path"));
205
-
206
- // packages/node-opcua-pki/lib/misc/subject.ts
207
- var import_node_opcua_crypto = require("node-opcua-crypto");
208
-
209
- // packages/node-opcua-pki/lib/toolbox/with_openssl/execute_openssl.ts
210
- var import_node_assert3 = __toESM(require("assert"));
211
- var import_node_child_process2 = __toESM(require("child_process"));
212
- var import_node_fs3 = __toESM(require("fs"));
213
- var import_node_os2 = __toESM(require("os"));
214
- var import_byline2 = __toESM(require("byline"));
215
- var import_chalk4 = __toESM(require("chalk"));
216
-
217
188
  // packages/node-opcua-pki/lib/toolbox/with_openssl/install_prerequisite.ts
218
189
  var import_node_child_process = __toESM(require("child_process"));
219
190
  var import_node_fs2 = __toESM(require("fs"));
@@ -221,7 +192,7 @@ var import_node_os = __toESM(require("os"));
221
192
  var import_node_path2 = __toESM(require("path"));
222
193
  var import_node_url = __toESM(require("url"));
223
194
  var import_byline = __toESM(require("byline"));
224
- var import_chalk3 = __toESM(require("chalk"));
195
+ var import_chalk2 = __toESM(require("chalk"));
225
196
  var import_progress = __toESM(require("progress"));
226
197
  var import_wget_improved_2 = __toESM(require("wget-improved-2"));
227
198
  var import_yauzl = __toESM(require("yauzl"));
@@ -239,7 +210,7 @@ function makeOptions() {
239
210
  proxyAuth: auth
240
211
  }
241
212
  };
242
- warningLog(import_chalk3.default.green("- using proxy "), proxy);
213
+ warningLog(import_chalk2.default.green("- using proxy "), proxy);
243
214
  warningLog(options);
244
215
  return options;
245
216
  }
@@ -268,7 +239,7 @@ async function execute(cmd, cwd) {
268
239
  output += `${line}
269
240
  `;
270
241
  if (doDebug2) {
271
- process.stdout.write(` stdout ${import_chalk3.default.yellow(line)}
242
+ process.stdout.write(` stdout ${import_chalk2.default.yellow(line)}
272
243
  `);
273
244
  }
274
245
  });
@@ -291,8 +262,8 @@ async function getopensslExecPath() {
291
262
  const exitCode = result1?.exitCode;
292
263
  const output = result1?.output;
293
264
  if (exitCode !== 0) {
294
- warningLog(import_chalk3.default.yellow(" it seems that ") + import_chalk3.default.cyan("openssl") + import_chalk3.default.yellow(" is not installed on your computer "));
295
- warningLog(import_chalk3.default.yellow("Please install it before running this programs"));
265
+ warningLog(import_chalk2.default.yellow(" it seems that ") + import_chalk2.default.cyan("openssl") + import_chalk2.default.yellow(" is not installed on your computer "));
266
+ warningLog(import_chalk2.default.yellow("Please install it before running this programs"));
296
267
  throw new Error("Cannot find openssl");
297
268
  }
298
269
  const opensslExecPath = output.replace(/\n\r/g, "").trim();
@@ -302,7 +273,7 @@ async function check_system_openssl_version() {
302
273
  const opensslExecPath = await getopensslExecPath();
303
274
  const q_opensslExecPath = quote2(opensslExecPath);
304
275
  if (doDebug2) {
305
- warningLog(` OpenSSL found in : ${import_chalk3.default.yellow(opensslExecPath)}`);
276
+ warningLog(` OpenSSL found in : ${import_chalk2.default.yellow(opensslExecPath)}`);
306
277
  }
307
278
  const result = await execute(`${q_opensslExecPath} version`);
308
279
  const exitCode = result?.exitCode;
@@ -310,9 +281,9 @@ async function check_system_openssl_version() {
310
281
  const version = output.trim();
311
282
  const versionOK = exitCode === 0 && is_expected_openssl_version(version);
312
283
  if (!versionOK) {
313
- let message = import_chalk3.default.whiteBright("Warning !!!!!!!!!!!! ") + "\nyour version of openssl is " + version + ". It doesn't match the expected version";
284
+ let message = import_chalk2.default.whiteBright("Warning !!!!!!!!!!!! ") + "\nyour version of openssl is " + version + ". It doesn't match the expected version";
314
285
  if (process.platform === "darwin") {
315
- message += import_chalk3.default.cyan("\nplease refer to :") + import_chalk3.default.yellow(" https://github.com/node-opcua/node-opcua/wiki/installing-node-opcua-or-node-red-on-MacOS");
286
+ message += import_chalk2.default.cyan("\nplease refer to :") + import_chalk2.default.yellow(" https://github.com/node-opcua/node-opcua/wiki/installing-node-opcua-or-node-red-on-MacOS");
316
287
  }
317
288
  console.log(message);
318
289
  }
@@ -338,7 +309,7 @@ async function install_and_check_win32_openssl_version() {
338
309
  const exists = import_node_fs2.default.existsSync(opensslExecPath2);
339
310
  if (!exists) {
340
311
  warningLog("checking presence of ", opensslExecPath2);
341
- warningLog(import_chalk3.default.red(" cannot find file ") + opensslExecPath2);
312
+ warningLog(import_chalk2.default.red(" cannot find file ") + opensslExecPath2);
342
313
  return {
343
314
  opensslOk: false,
344
315
  version: `cannot find file ${opensslExecPath2}`
@@ -372,12 +343,12 @@ async function install_and_check_win32_openssl_version() {
372
343
  async function download_openssl() {
373
344
  const url2 = win32or64() === 64 ? "https://github.com/node-opcua/node-opcua-pki/releases/download/2.14.2/openssl-1.0.2u-x64_86-win64.zip" : "https://github.com/node-opcua/node-opcua-pki/releases/download/2.14.2/openssl-1.0.2u-i386-win32.zip";
374
345
  const outputFilename = import_node_path2.default.join(downloadFolder, import_node_path2.default.basename(url2));
375
- warningLog(`downloading ${import_chalk3.default.yellow(url2)} to ${outputFilename}`);
346
+ warningLog(`downloading ${import_chalk2.default.yellow(url2)} to ${outputFilename}`);
376
347
  if (import_node_fs2.default.existsSync(outputFilename)) {
377
348
  return { downloadedFile: outputFilename };
378
349
  }
379
350
  const options = makeOptions();
380
- const bar = new import_progress.default(import_chalk3.default.cyan("[:bar]") + import_chalk3.default.cyan(" :percent ") + import_chalk3.default.white(":etas"), {
351
+ const bar = new import_progress.default(import_chalk2.default.cyan("[:bar]") + import_chalk2.default.cyan(" :percent ") + import_chalk2.default.white(":etas"), {
381
352
  complete: "=",
382
353
  incomplete: " ",
383
354
  total: 100,
@@ -459,21 +430,21 @@ async function install_and_check_win32_openssl_version() {
459
430
  }
460
431
  const { opensslOk, version: _version } = await check_openssl_win32();
461
432
  if (!opensslOk) {
462
- warningLog(import_chalk3.default.yellow("openssl seems to be missing and need to be installed"));
433
+ warningLog(import_chalk2.default.yellow("openssl seems to be missing and need to be installed"));
463
434
  const { downloadedFile } = await download_openssl();
464
435
  if (doDebug2) {
465
- warningLog("deflating ", import_chalk3.default.yellow(downloadedFile));
436
+ warningLog("deflating ", import_chalk2.default.yellow(downloadedFile));
466
437
  }
467
438
  await unzip_openssl(downloadedFile);
468
439
  const opensslExists = !!import_node_fs2.default.existsSync(opensslExecPath);
469
440
  if (doDebug2) {
470
- warningLog("verifying ", opensslExists, opensslExists ? import_chalk3.default.green("OK ") : import_chalk3.default.red(" Error"), opensslExecPath);
441
+ warningLog("verifying ", opensslExists, opensslExists ? import_chalk2.default.green("OK ") : import_chalk2.default.red(" Error"), opensslExecPath);
471
442
  }
472
443
  const _opensslExecPath2 = await check_openssl_win32();
473
444
  return opensslExecPath;
474
445
  } else {
475
446
  if (doDebug2) {
476
- warningLog(import_chalk3.default.green("openssl is already installed and have the expected version."));
447
+ warningLog(import_chalk2.default.green("openssl is already installed and have the expected version."));
477
448
  }
478
449
  return opensslExecPath;
479
450
  }
@@ -504,7 +475,7 @@ async function execute2(cmd, options) {
504
475
  const from = new Error();
505
476
  options.cwd = options.cwd || process.cwd();
506
477
  if (!g_config.silent) {
507
- warningLog(import_chalk4.default.cyan(" CWD "), options.cwd);
478
+ warningLog(import_chalk3.default.cyan(" CWD "), options.cwd);
508
479
  }
509
480
  const outputs = [];
510
481
  return await new Promise((resolve, reject) => {
@@ -518,10 +489,10 @@ async function execute2(cmd, options) {
518
489
  if (err) {
519
490
  if (!options.hideErrorMessage) {
520
491
  const fence = "###########################################";
521
- console.error(import_chalk4.default.bgWhiteBright.redBright(`${fence} OPENSSL ERROR ${fence}`));
522
- console.error(import_chalk4.default.bgWhiteBright.redBright(`CWD = ${options.cwd}`));
523
- console.error(import_chalk4.default.bgWhiteBright.redBright(err.message));
524
- console.error(import_chalk4.default.bgWhiteBright.redBright(`${fence} OPENSSL ERROR ${fence}`));
492
+ console.error(import_chalk3.default.bgWhiteBright.redBright(`${fence} OPENSSL ERROR ${fence}`));
493
+ console.error(import_chalk3.default.bgWhiteBright.redBright(`CWD = ${options.cwd}`));
494
+ console.error(import_chalk3.default.bgWhiteBright.redBright(err.message));
495
+ console.error(import_chalk3.default.bgWhiteBright.redBright(`${fence} OPENSSL ERROR ${fence}`));
525
496
  console.error(from.stack);
526
497
  }
527
498
  reject(new Error(err.message));
@@ -540,7 +511,7 @@ async function execute2(cmd, options) {
540
511
  stream2.on("data", (line) => {
541
512
  line = line.toString();
542
513
  if (doDebug) {
543
- process.stdout.write(`${import_chalk4.default.white(" stdout ") + import_chalk4.default.whiteBright(line)}
514
+ process.stdout.write(`${import_chalk3.default.white(" stdout ") + import_chalk3.default.whiteBright(line)}
544
515
  `);
545
516
  }
546
517
  });
@@ -552,7 +523,7 @@ async function execute2(cmd, options) {
552
523
  stream1.on("data", (line) => {
553
524
  line = line.toString();
554
525
  if (displayError) {
555
- process.stdout.write(`${import_chalk4.default.white(" stderr ") + import_chalk4.default.red(line)}
526
+ process.stdout.write(`${import_chalk3.default.white(" stderr ") + import_chalk3.default.red(line)}
556
527
  `);
557
528
  }
558
529
  });
@@ -596,17 +567,107 @@ async function execute_openssl(cmd, options) {
596
567
  (0, import_node_assert3.default)(options.openssl_conf);
597
568
  setEnv("OPENSSL_CONF", options.openssl_conf);
598
569
  if (!g_config.silent) {
599
- warningLog(import_chalk4.default.cyan(" OPENSSL_CONF"), process.env.OPENSSL_CONF);
600
- warningLog(import_chalk4.default.cyan(" RANDFILE "), process.env.RANDFILE);
601
- warningLog(import_chalk4.default.cyan(" CMD openssl "), import_chalk4.default.cyanBright(cmd));
570
+ warningLog(import_chalk3.default.cyan(" OPENSSL_CONF"), process.env.OPENSSL_CONF);
571
+ warningLog(import_chalk3.default.cyan(" RANDFILE "), process.env.RANDFILE);
572
+ warningLog(import_chalk3.default.cyan(" CMD openssl "), import_chalk3.default.cyanBright(cmd));
602
573
  }
603
574
  await ensure_openssl_installed();
604
575
  return await execute2(`${quote(opensslPath)} ${cmd}`, options);
605
576
  }
606
577
 
578
+ // packages/node-opcua-pki/lib/pki/toolbox_pfx.ts
579
+ var q = quote;
580
+ var n2 = makePath;
581
+ async function createPFX(options) {
582
+ const { certificateFile, privateKeyFile, outputFile, passphrase = "", caCertificateFiles } = options;
583
+ (0, import_node_assert4.default)(import_node_fs4.default.existsSync(certificateFile), `Certificate file does not exist: ${certificateFile}`);
584
+ (0, import_node_assert4.default)(import_node_fs4.default.existsSync(privateKeyFile), `Private key file does not exist: ${privateKeyFile}`);
585
+ let cmd = `pkcs12 -export`;
586
+ cmd += ` -in ${q(n2(certificateFile))}`;
587
+ cmd += ` -inkey ${q(n2(privateKeyFile))}`;
588
+ if (caCertificateFiles) {
589
+ for (const caFile of caCertificateFiles) {
590
+ (0, import_node_assert4.default)(import_node_fs4.default.existsSync(caFile), `CA certificate file does not exist: ${caFile}`);
591
+ cmd += ` -certfile ${q(n2(caFile))}`;
592
+ }
593
+ }
594
+ cmd += ` -out ${q(n2(outputFile))}`;
595
+ cmd += ` -passout pass:${passphrase}`;
596
+ await execute_openssl(cmd, {});
597
+ }
598
+ async function extractCertificateFromPFX(options) {
599
+ const { pfxFile, passphrase = "" } = options;
600
+ (0, import_node_assert4.default)(import_node_fs4.default.existsSync(pfxFile), `PFX file does not exist: ${pfxFile}`);
601
+ const cmd = `pkcs12 -in ${q(n2(pfxFile))} -clcerts -nokeys -nodes -passin pass:${passphrase}`;
602
+ return await execute_openssl(cmd, {});
603
+ }
604
+ async function extractPrivateKeyFromPFX(options) {
605
+ const { pfxFile, passphrase = "" } = options;
606
+ (0, import_node_assert4.default)(import_node_fs4.default.existsSync(pfxFile), `PFX file does not exist: ${pfxFile}`);
607
+ const cmd = `pkcs12 -in ${q(n2(pfxFile))} -nocerts -nodes -passin pass:${passphrase}`;
608
+ return await execute_openssl(cmd, {});
609
+ }
610
+ async function extractCACertificatesFromPFX(options) {
611
+ const { pfxFile, passphrase = "" } = options;
612
+ (0, import_node_assert4.default)(import_node_fs4.default.existsSync(pfxFile), `PFX file does not exist: ${pfxFile}`);
613
+ const cmd = `pkcs12 -in ${q(n2(pfxFile))} -cacerts -nokeys -nodes -passin pass:${passphrase}`;
614
+ return await execute_openssl(cmd, {});
615
+ }
616
+ async function extractAllFromPFX(options) {
617
+ const [certificate, privateKey, caCertificates] = await Promise.all([
618
+ extractCertificateFromPFX(options),
619
+ extractPrivateKeyFromPFX(options),
620
+ extractCACertificatesFromPFX(options)
621
+ ]);
622
+ return { certificate, privateKey, caCertificates };
623
+ }
624
+ async function convertPFXtoPEM(pfxFile, pemFile, passphrase = "") {
625
+ (0, import_node_assert4.default)(import_node_fs4.default.existsSync(pfxFile), `PFX file does not exist: ${pfxFile}`);
626
+ const cmd = `pkcs12 -in ${q(n2(pfxFile))} -out ${q(n2(pemFile))} -nodes -passin pass:${passphrase}`;
627
+ await execute_openssl(cmd, {});
628
+ }
629
+ async function dumpPFX(pfxFile, passphrase = "") {
630
+ (0, import_node_assert4.default)(import_node_fs4.default.existsSync(pfxFile), `PFX file does not exist: ${pfxFile}`);
631
+ const cmd = `pkcs12 -in ${q(n2(pfxFile))} -info -nodes -passin pass:${passphrase}`;
632
+ return await execute_openssl(cmd, {});
633
+ }
634
+
635
+ // packages/node-opcua-pki/lib/toolbox/display.ts
636
+ var import_chalk4 = __toESM(require("chalk"));
637
+ function displayTitle(str) {
638
+ if (!g_config.silent) {
639
+ warningLog("");
640
+ warningLog(import_chalk4.default.yellowBright(str));
641
+ warningLog(import_chalk4.default.yellow(new Array(str.length + 1).join("=")), "\n");
642
+ }
643
+ }
644
+ function displaySubtitle(str) {
645
+ if (!g_config.silent) {
646
+ warningLog("");
647
+ warningLog(` ${import_chalk4.default.yellowBright(str)}`);
648
+ warningLog(` ${import_chalk4.default.white(new Array(str.length + 1).join("-"))}`, "\n");
649
+ }
650
+ }
651
+ function display(str) {
652
+ if (!g_config.silent) {
653
+ warningLog(` ${str}`);
654
+ }
655
+ }
656
+
657
+ // packages/node-opcua-pki/lib/toolbox/with_openssl/index.ts
658
+ var import_node_constants = __toESM(require("constants"));
659
+
660
+ // packages/node-opcua-pki/lib/toolbox/with_openssl/create_certificate_signing_request.ts
661
+ var import_node_assert6 = __toESM(require("assert"));
662
+ var import_node_fs6 = __toESM(require("fs"));
663
+ var import_node_path4 = __toESM(require("path"));
664
+
665
+ // packages/node-opcua-pki/lib/misc/subject.ts
666
+ var import_node_opcua_crypto = require("node-opcua-crypto");
667
+
607
668
  // packages/node-opcua-pki/lib/toolbox/with_openssl/toolbox.ts
608
- var import_node_assert4 = __toESM(require("assert"));
609
- var import_node_fs4 = __toESM(require("fs"));
669
+ var import_node_assert5 = __toESM(require("assert"));
670
+ var import_node_fs5 = __toESM(require("fs"));
610
671
  var import_node_path3 = __toESM(require("path"));
611
672
  function openssl_require2DigitYearInDate() {
612
673
  if (!g_config.opensslVersion) {
@@ -621,13 +682,13 @@ var _counter = 0;
621
682
  function generateStaticConfig(configPath, options) {
622
683
  const prePath = options?.cwd || "";
623
684
  const originalFilename = !import_node_path3.default.isAbsolute(configPath) ? import_node_path3.default.join(prePath, configPath) : configPath;
624
- let staticConfig = import_node_fs4.default.readFileSync(originalFilename, { encoding: "utf8" });
685
+ let staticConfig = import_node_fs5.default.readFileSync(originalFilename, { encoding: "utf8" });
625
686
  for (const envVar of getEnvironmentVarNames()) {
626
687
  staticConfig = staticConfig.replace(new RegExp(envVar.pattern, "gi"), getEnv(envVar.key));
627
688
  }
628
689
  const staticConfigPath = `${configPath}.${process.pid}-${_counter++}.tmp`;
629
690
  const temporaryConfigPath = !import_node_path3.default.isAbsolute(configPath) ? import_node_path3.default.join(prePath, staticConfigPath) : staticConfigPath;
630
- import_node_fs4.default.writeFileSync(temporaryConfigPath, staticConfig);
691
+ import_node_fs5.default.writeFileSync(temporaryConfigPath, staticConfig);
631
692
  if (options?.cwd) {
632
693
  return import_node_path3.default.relative(options.cwd, temporaryConfigPath);
633
694
  } else {
@@ -652,8 +713,38 @@ function x509Date(date) {
652
713
  }
653
714
  }
654
715
 
716
+ // packages/node-opcua-pki/lib/toolbox/with_openssl/create_certificate_signing_request.ts
717
+ var q2 = quote;
718
+ var n3 = makePath;
719
+ async function createCertificateSigningRequestWithOpenSSL(certificateSigningRequestFilename, params) {
720
+ (0, import_node_assert6.default)(params);
721
+ (0, import_node_assert6.default)(params.rootDir);
722
+ (0, import_node_assert6.default)(params.configFile);
723
+ (0, import_node_assert6.default)(params.privateKey);
724
+ (0, import_node_assert6.default)(typeof params.privateKey === "string");
725
+ (0, import_node_assert6.default)(import_node_fs6.default.existsSync(params.configFile), `config file must exist ${params.configFile}`);
726
+ (0, import_node_assert6.default)(import_node_fs6.default.existsSync(params.privateKey), `Private key must exist${params.privateKey}`);
727
+ (0, import_node_assert6.default)(import_node_fs6.default.existsSync(params.rootDir), "RootDir key must exist");
728
+ (0, import_node_assert6.default)(typeof certificateSigningRequestFilename === "string");
729
+ processAltNames(params);
730
+ const configFile = generateStaticConfig(params.configFile, { cwd: params.rootDir });
731
+ const options = { cwd: params.rootDir, openssl_conf: import_node_path4.default.relative(params.rootDir, configFile) };
732
+ const configOption = ` -config ${q2(n3(configFile))}`;
733
+ const subject = params.subject ? new import_node_opcua_crypto.Subject(params.subject).toString() : void 0;
734
+ const subjectOptions = subject ? ` -subj "${subject}"` : "";
735
+ displaySubtitle("- Creating a Certificate Signing Request with openssl");
736
+ await execute_openssl(
737
+ "req -new -sha256 -batch -text " + configOption + " -key " + q2(n3(params.privateKey)) + subjectOptions + " -out " + q2(n3(certificateSigningRequestFilename)),
738
+ options
739
+ );
740
+ }
741
+
742
+ // packages/node-opcua-pki/lib/pki/templates/simple_config_template.cnf.ts
743
+ var config = '##################################################################################################\n## SIMPLE OPENSSL CONFIG FILE FOR SELF-SIGNED CERTIFICATE GENERATION\n################################################################################################################\n\ndistinguished_name = req_distinguished_name\ndefault_md = sha1\n\ndefault_md = sha256 # The default digest algorithm\n\n[ v3_ca ]\nsubjectKeyIdentifier = hash\nauthorityKeyIdentifier = keyid:always,issuer:always\n\n# authorityKeyIdentifier = keyid\nbasicConstraints = CA:TRUE\nkeyUsage = critical, cRLSign, keyCertSign\nnsComment = "Self-signed Certificate for CA generated by Node-OPCUA Certificate utility"\n#nsCertType = sslCA, emailCA\n#subjectAltName = email:copy\n#issuerAltName = issuer:copy\n#obj = DER:02:03\n# crlDistributionPoints = @crl_info\n# [ crl_info ]\n# URI.0 = http://localhost:8900/crl.pem\nsubjectAltName = $ENV::ALTNAME\n\n[ req ]\ndays = 390\nreq_extensions = v3_req\nx509_extensions = v3_ca\n\n[v3_req]\nbasicConstraints = CA:false\nkeyUsage = critical, cRLSign, keyCertSign\nsubjectAltName = $ENV::ALTNAME\n\n[ v3_ca_signed]\nsubjectKeyIdentifier = hash\nauthorityKeyIdentifier = keyid,issuer\nbasicConstraints = critical, CA:FALSE\nkeyUsage = nonRepudiation, digitalSignature, keyEncipherment, dataEncipherment, keyCertSign\nextendedKeyUsage = clientAuth,serverAuth \nnsComment = "certificate generated by Node-OPCUA Certificate utility and signed by a CA"\nsubjectAltName = $ENV::ALTNAME\n[ v3_selfsigned]\nsubjectKeyIdentifier = hash\nauthorityKeyIdentifier = keyid,issuer\nbasicConstraints = critical, CA:FALSE\nkeyUsage = nonRepudiation, digitalSignature, keyEncipherment, dataEncipherment, keyCertSign\nextendedKeyUsage = clientAuth,serverAuth \nnsComment = "Self-signed certificate generated by Node-OPCUA Certificate utility"\nsubjectAltName = $ENV::ALTNAME\n[ req_distinguished_name ]\ncountryName = Country Name (2 letter code)\ncountryName_default = FR\ncountryName_min = 2\ncountryName_max = 2\n# stateOrProvinceName = State or Province Name (full name)\n# stateOrProvinceName_default = Ile de France\n# localityName = Locality Name (city, district)\n# localityName_default = Paris\norganizationName = Organization Name (company)\norganizationName_default = NodeOPCUA\n# organizationalUnitName = Organizational Unit Name (department, division)\n# organizationalUnitName_default = R&D\ncommonName = Common Name (hostname, FQDN, IP, or your name)\ncommonName_max = 256\ncommonName_default = NodeOPCUA\n# emailAddress = Email Address\n# emailAddress_max = 40\n# emailAddress_default = node-opcua (at) node-opcua (dot) com\nsubjectAltName = $ENV::ALTNAME';
744
+ var simple_config_template_cnf_default = config;
745
+
655
746
  // packages/node-opcua-pki/lib/ca/templates/ca_config_template.cnf.ts
656
- var config = `#.........DO NOT MODIFY BY HAND .........................
747
+ var config2 = `#.........DO NOT MODIFY BY HAND .........................
657
748
  [ ca ]
658
749
  default_ca = CA_default
659
750
  [ CA_default ]
@@ -782,22 +873,23 @@ subjectAltName = $ENV::ALTNAME
782
873
  #issuerAltName = issuer:copy
783
874
  authorityKeyIdentifier = keyid:always,issuer:always
784
875
  #authorityInfoAccess = @issuer_info`;
785
- var ca_config_template_cnf_default = config;
876
+ var ca_config_template_cnf_default = config2;
786
877
 
787
878
  // packages/node-opcua-pki/lib/ca/certificate_authority.ts
788
879
  var defaultSubject = "/C=FR/ST=IDF/L=Paris/O=Local NODE-OPCUA Certificate Authority/CN=NodeOPCUA-CA";
789
880
  var configurationFileTemplate = ca_config_template_cnf_default;
790
- var config2 = {
881
+ var configurationFileSimpleTemplate = simple_config_template_cnf_default;
882
+ var config3 = {
791
883
  certificateDir: "INVALID",
792
884
  forceCA: false,
793
885
  pkiDir: "INVALID"
794
886
  };
795
- var n2 = makePath;
796
- var q = quote;
887
+ var n4 = makePath;
888
+ var q3 = quote;
797
889
  function octetStringToIpAddress(a) {
798
890
  return parseInt(a.substring(0, 2), 16).toString() + "." + parseInt(a.substring(2, 4), 16).toString() + "." + parseInt(a.substring(4, 6), 16).toString() + "." + parseInt(a.substring(6, 8), 16).toString();
799
891
  }
800
- (0, import_node_assert6.default)(octetStringToIpAddress("c07b9179") === "192.123.145.121");
892
+ (0, import_node_assert7.default)(octetStringToIpAddress("c07b9179") === "192.123.145.121");
801
893
  async function construct_CertificateAuthority(certificateAuthority) {
802
894
  const subject = certificateAuthority.subject;
803
895
  const caRootDir = import_node_path5.default.resolve(certificateAuthority.rootDir);
@@ -812,49 +904,49 @@ async function construct_CertificateAuthority(certificateAuthority) {
812
904
  await make_folders();
813
905
  async function construct_default_files() {
814
906
  const serial = import_node_path5.default.join(caRootDir, "serial");
815
- if (!import_node_fs6.default.existsSync(serial)) {
816
- await import_node_fs6.default.promises.writeFile(serial, "1000");
907
+ if (!import_node_fs7.default.existsSync(serial)) {
908
+ await import_node_fs7.default.promises.writeFile(serial, "1000");
817
909
  }
818
910
  const crlNumber = import_node_path5.default.join(caRootDir, "crlnumber");
819
- if (!import_node_fs6.default.existsSync(crlNumber)) {
820
- await import_node_fs6.default.promises.writeFile(crlNumber, "1000");
911
+ if (!import_node_fs7.default.existsSync(crlNumber)) {
912
+ await import_node_fs7.default.promises.writeFile(crlNumber, "1000");
821
913
  }
822
914
  const indexFile = import_node_path5.default.join(caRootDir, "index.txt");
823
- if (!import_node_fs6.default.existsSync(indexFile)) {
824
- await import_node_fs6.default.promises.writeFile(indexFile, "");
915
+ if (!import_node_fs7.default.existsSync(indexFile)) {
916
+ await import_node_fs7.default.promises.writeFile(indexFile, "");
825
917
  }
826
918
  }
827
919
  await construct_default_files();
828
- const caKeyExists = import_node_fs6.default.existsSync(import_node_path5.default.join(caRootDir, "private/cakey.pem"));
829
- const caCertExists = import_node_fs6.default.existsSync(import_node_path5.default.join(caRootDir, "public/cacert.pem"));
830
- if (caKeyExists && caCertExists && !config2.forceCA) {
920
+ const caKeyExists = import_node_fs7.default.existsSync(import_node_path5.default.join(caRootDir, "private/cakey.pem"));
921
+ const caCertExists = import_node_fs7.default.existsSync(import_node_path5.default.join(caRootDir, "public/cacert.pem"));
922
+ if (caKeyExists && caCertExists && !config3.forceCA) {
831
923
  debugLog("CA private key and certificate already exist ... skipping");
832
924
  return;
833
925
  }
834
926
  if (caKeyExists && !caCertExists) {
835
927
  debugLog("CA private key exists but cacert.pem is missing \u2014 rebuilding CA");
836
- import_node_fs6.default.unlinkSync(import_node_path5.default.join(caRootDir, "private/cakey.pem"));
928
+ import_node_fs7.default.unlinkSync(import_node_path5.default.join(caRootDir, "private/cakey.pem"));
837
929
  const staleCsr = import_node_path5.default.join(caRootDir, "private/cakey.csr");
838
- if (import_node_fs6.default.existsSync(staleCsr)) {
839
- import_node_fs6.default.unlinkSync(staleCsr);
930
+ if (import_node_fs7.default.existsSync(staleCsr)) {
931
+ import_node_fs7.default.unlinkSync(staleCsr);
840
932
  }
841
933
  }
842
934
  displayTitle("Create Certificate Authority (CA)");
843
935
  const indexFileAttr = import_node_path5.default.join(caRootDir, "index.txt.attr");
844
- if (!import_node_fs6.default.existsSync(indexFileAttr)) {
845
- await import_node_fs6.default.promises.writeFile(indexFileAttr, "unique_subject = no");
936
+ if (!import_node_fs7.default.existsSync(indexFileAttr)) {
937
+ await import_node_fs7.default.promises.writeFile(indexFileAttr, "unique_subject = no");
846
938
  }
847
939
  const caConfigFile = certificateAuthority.configFile;
848
940
  if (1) {
849
941
  let data = configurationFileTemplate;
850
942
  data = makePath(data.replace(/%%ROOT_FOLDER%%/, caRootDir));
851
- await import_node_fs6.default.promises.writeFile(caConfigFile, data);
943
+ await import_node_fs7.default.promises.writeFile(caConfigFile, data);
852
944
  }
853
945
  const subjectOpt = ` -subj "${subject.toString()}" `;
854
946
  processAltNames({});
855
947
  const options = { cwd: caRootDir };
856
948
  const configFile = generateStaticConfig("conf/caconfig.cnf", options);
857
- const configOption = ` -config ${q(n2(configFile))}`;
949
+ const configOption = ` -config ${q3(n4(configFile))}`;
858
950
  const keySize = certificateAuthority.keySize;
859
951
  const privateKeyFilename = import_node_path5.default.join(caRootDir, "private/cakey.pem");
860
952
  const csrFilename = import_node_path5.default.join(caRootDir, "private/cakey.csr");
@@ -862,14 +954,26 @@ async function construct_CertificateAuthority(certificateAuthority) {
862
954
  await (0, import_node_opcua_crypto2.generatePrivateKeyFile)(privateKeyFilename, keySize);
863
955
  displayTitle("Generate a certificate request for the CA key");
864
956
  await execute_openssl(
865
- "req -new -sha256 -text -extensions v3_ca_req" + configOption + " -key " + q(n2(privateKeyFilename)) + " -out " + q(n2(csrFilename)) + " " + subjectOpt,
866
- options
867
- );
868
- displayTitle("Generate CA Certificate (self-signed)");
869
- await execute_openssl(
870
- " x509 -sha256 -req -days 3650 -text -extensions v3_ca -extfile " + q(n2(configFile)) + " -in private/cakey.csr -signkey " + q(n2(privateKeyFilename)) + " -out public/cacert.pem",
957
+ "req -new -sha256 -text -extensions v3_ca_req" + configOption + " -key " + q3(n4(privateKeyFilename)) + " -out " + q3(n4(csrFilename)) + " " + subjectOpt,
871
958
  options
872
959
  );
960
+ const issuerCA = certificateAuthority._issuerCA;
961
+ if (issuerCA) {
962
+ displayTitle("Generate CA Certificate (signed by issuer CA)");
963
+ const issuerCert = import_node_path5.default.resolve(issuerCA.caCertificate);
964
+ const issuerKey = import_node_path5.default.resolve(issuerCA.rootDir, "private/cakey.pem");
965
+ const issuerSerial = import_node_path5.default.resolve(issuerCA.rootDir, "serial");
966
+ await execute_openssl(
967
+ " x509 -sha256 -req -days 3650 -text -extensions v3_ca -extfile " + q3(n4(configFile)) + " -in private/cakey.csr -CA " + q3(n4(issuerCert)) + " -CAkey " + q3(n4(issuerKey)) + " -CAserial " + q3(n4(issuerSerial)) + " -out public/cacert.pem",
968
+ options
969
+ );
970
+ } else {
971
+ displayTitle("Generate CA Certificate (self-signed)");
972
+ await execute_openssl(
973
+ " x509 -sha256 -req -days 3650 -text -extensions v3_ca -extfile " + q3(n4(configFile)) + " -in private/cakey.csr -signkey " + q3(n4(privateKeyFilename)) + " -out public/cacert.pem",
974
+ options
975
+ );
976
+ }
873
977
  displaySubtitle("generate initial CRL (Certificate Revocation List)");
874
978
  await regenerateCrl(certificateAuthority.revocationList, configOption, options);
875
979
  displayTitle("Create Certificate Authority (CA) ---> DONE");
@@ -879,7 +983,7 @@ async function regenerateCrl(revocationList, configOption, options) {
879
983
  await execute_openssl(`ca -gencrl ${configOption} -out crl/revocation_list.crl`, options);
880
984
  await execute_openssl("crl -in crl/revocation_list.crl -out crl/revocation_list.der -outform der", options);
881
985
  displaySubtitle("Display (Certificate Revocation List)");
882
- await execute_openssl(`crl -in ${q(n2(revocationList))} -text -noout`, options);
986
+ await execute_openssl(`crl -in ${q3(n4(revocationList))} -text -noout`, options);
883
987
  }
884
988
  function parseOpenSSLDate(dateStr) {
885
989
  const raw = dateStr?.split(",")[0] ?? "";
@@ -900,12 +1004,15 @@ var CertificateAuthority = class {
900
1004
  location;
901
1005
  /** X.500 subject of the CA certificate. */
902
1006
  subject;
1007
+ /** @internal Parent CA (undefined for root CAs). */
1008
+ _issuerCA;
903
1009
  constructor(options) {
904
- (0, import_node_assert6.default)(Object.prototype.hasOwnProperty.call(options, "location"));
905
- (0, import_node_assert6.default)(Object.prototype.hasOwnProperty.call(options, "keySize"));
1010
+ (0, import_node_assert7.default)(Object.prototype.hasOwnProperty.call(options, "location"));
1011
+ (0, import_node_assert7.default)(Object.prototype.hasOwnProperty.call(options, "keySize"));
906
1012
  this.location = options.location;
907
1013
  this.keySize = options.keySize || 2048;
908
1014
  this.subject = new import_node_opcua_crypto2.Subject(options.subject || defaultSubject);
1015
+ this._issuerCA = options.issuerCA;
909
1016
  }
910
1017
  /** Absolute path to the CA root directory (alias for {@link location}). */
911
1018
  get rootDir() {
@@ -919,6 +1026,18 @@ var CertificateAuthority = class {
919
1026
  get caCertificate() {
920
1027
  return makePath(this.rootDir, "./public/cacert.pem");
921
1028
  }
1029
+ /**
1030
+ * Path to the issuer certificate chain (`public/issuer_chain.pem`).
1031
+ *
1032
+ * This file is created by {@link installCACertificate} when the
1033
+ * provided cert file contains additional issuer certificates
1034
+ * (e.g. intermediate + root). It is appended to signed certs
1035
+ * by {@link constructCertificateChain} to produce a full chain
1036
+ * per OPC UA Part 6 §6.2.6.
1037
+ */
1038
+ get issuerCertificateChain() {
1039
+ return makePath(this.rootDir, "./public/issuer_chain.pem");
1040
+ }
922
1041
  /**
923
1042
  * Path to the current Certificate Revocation List in DER format.
924
1043
  * (`crl/revocation_list.der`)
@@ -976,10 +1095,10 @@ var CertificateAuthority = class {
976
1095
  */
977
1096
  getCRLDER() {
978
1097
  const crlPath = this.revocationListDER;
979
- if (!import_node_fs6.default.existsSync(crlPath)) {
1098
+ if (!import_node_fs7.default.existsSync(crlPath)) {
980
1099
  return Buffer.alloc(0);
981
1100
  }
982
- return import_node_fs6.default.readFileSync(crlPath);
1101
+ return import_node_fs7.default.readFileSync(crlPath);
983
1102
  }
984
1103
  /**
985
1104
  * Return the current Certificate Revocation List as a
@@ -989,10 +1108,10 @@ var CertificateAuthority = class {
989
1108
  */
990
1109
  getCRLPEM() {
991
1110
  const crlPath = this.revocationList;
992
- if (!import_node_fs6.default.existsSync(crlPath)) {
1111
+ if (!import_node_fs7.default.existsSync(crlPath)) {
993
1112
  return "";
994
1113
  }
995
- const raw = import_node_fs6.default.readFileSync(crlPath, "utf-8");
1114
+ const raw = import_node_fs7.default.readFileSync(crlPath, "utf-8");
996
1115
  const beginMarker = "-----BEGIN X509 CRL-----";
997
1116
  const idx = raw.indexOf(beginMarker);
998
1117
  if (idx > 0) {
@@ -1045,7 +1164,7 @@ var CertificateAuthority = class {
1045
1164
  getCertificateBySerial(serial) {
1046
1165
  const upper = serial.toUpperCase();
1047
1166
  const certFile = import_node_path5.default.join(this.rootDir, "certs", `${upper}.pem`);
1048
- if (!import_node_fs6.default.existsSync(certFile)) {
1167
+ if (!import_node_fs7.default.existsSync(certFile)) {
1049
1168
  return void 0;
1050
1169
  }
1051
1170
  const pem = (0, import_node_opcua_crypto2.readCertificatePEM)(certFile);
@@ -1074,10 +1193,10 @@ var CertificateAuthority = class {
1074
1193
  */
1075
1194
  _parseIndexTxt() {
1076
1195
  const indexPath = this.indexFile;
1077
- if (!import_node_fs6.default.existsSync(indexPath)) {
1196
+ if (!import_node_fs7.default.existsSync(indexPath)) {
1078
1197
  return [];
1079
1198
  }
1080
- const content = import_node_fs6.default.readFileSync(indexPath, "utf-8");
1199
+ const content = import_node_fs7.default.readFileSync(indexPath, "utf-8");
1081
1200
  const lines = content.split("\n").filter((l) => l.trim().length > 0);
1082
1201
  const records = [];
1083
1202
  for (const line of lines) {
@@ -1131,25 +1250,145 @@ var CertificateAuthority = class {
1131
1250
  * internally so that callers can work with in-memory
1132
1251
  * buffers only.
1133
1252
  *
1253
+ * The CA can override fields from the CSR by passing
1254
+ * `options.dns`, `options.ip`, `options.applicationUri`,
1255
+ * `options.startDate`, or `options.subject`.
1256
+ *
1134
1257
  * @param csrDer - the CSR as a DER-encoded buffer
1135
- * @param options - signing options
1136
- * @param options.validity - certificate validity in days
1137
- * (default: 365)
1258
+ * @param options - signing options and CA overrides
1138
1259
  * @returns the signed certificate as a DER-encoded buffer
1139
1260
  */
1140
1261
  async signCertificateRequestFromDER(csrDer, options) {
1141
1262
  const validity = options?.validity ?? 365;
1142
- const tmpDir = await import_node_fs6.default.promises.mkdtemp(import_node_path5.default.join(import_node_os3.default.tmpdir(), "pki-sign-"));
1263
+ const tmpDir = await import_node_fs7.default.promises.mkdtemp(import_node_path5.default.join(import_node_os3.default.tmpdir(), "pki-sign-"));
1143
1264
  try {
1144
1265
  const csrFile = import_node_path5.default.join(tmpDir, "request.csr");
1145
1266
  const certFile = import_node_path5.default.join(tmpDir, "certificate.pem");
1146
1267
  const csrPem = (0, import_node_opcua_crypto2.toPem)(csrDer, "CERTIFICATE REQUEST");
1147
- await import_node_fs6.default.promises.writeFile(csrFile, csrPem, "utf-8");
1148
- await this.signCertificateRequest(certFile, csrFile, { validity });
1268
+ await import_node_fs7.default.promises.writeFile(csrFile, csrPem, "utf-8");
1269
+ const signingParams = { validity };
1270
+ if (options?.startDate) signingParams.startDate = options.startDate;
1271
+ if (options?.dns) signingParams.dns = options.dns;
1272
+ if (options?.ip) signingParams.ip = options.ip;
1273
+ if (options?.applicationUri) signingParams.applicationUri = options.applicationUri;
1274
+ if (options?.subject) signingParams.subject = options.subject;
1275
+ await this.signCertificateRequest(certFile, csrFile, signingParams);
1149
1276
  const certPem = (0, import_node_opcua_crypto2.readCertificatePEM)(certFile);
1150
1277
  return (0, import_node_opcua_crypto2.convertPEMtoDER)(certPem);
1151
1278
  } finally {
1152
- await import_node_fs6.default.promises.rm(tmpDir, {
1279
+ await import_node_fs7.default.promises.rm(tmpDir, {
1280
+ recursive: true,
1281
+ force: true
1282
+ });
1283
+ }
1284
+ }
1285
+ /**
1286
+ * Generate a new RSA key pair, create an internal CSR, sign it
1287
+ * with this CA, and return both the certificate and private key
1288
+ * as DER-encoded buffers.
1289
+ *
1290
+ * The private key is **never stored** by the CA — it exists only
1291
+ * in a temporary directory that is cleaned up after the operation.
1292
+ *
1293
+ * This is used by `StartNewKeyPairRequest` (OPC UA Part 12) for
1294
+ * constrained devices that cannot generate their own keys.
1295
+ *
1296
+ * @param options - key generation and certificate parameters
1297
+ * @returns `{ certificateDer, privateKey }` — certificate as DER,
1298
+ * private key as a branded `PrivateKey` buffer
1299
+ */
1300
+ async generateKeyPairAndSignDER(options) {
1301
+ const keySize = options.keySize ?? 2048;
1302
+ const validity = options.validity ?? 365;
1303
+ const startDate = options.startDate ?? /* @__PURE__ */ new Date();
1304
+ const tmpDir = await import_node_fs7.default.promises.mkdtemp(import_node_path5.default.join(import_node_os3.default.tmpdir(), "pki-keygen-"));
1305
+ try {
1306
+ const privateKeyFile = import_node_path5.default.join(tmpDir, "private_key.pem");
1307
+ await (0, import_node_opcua_crypto2.generatePrivateKeyFile)(privateKeyFile, keySize);
1308
+ const configFile = import_node_path5.default.join(tmpDir, "openssl.cnf");
1309
+ await import_node_fs7.default.promises.writeFile(configFile, configurationFileSimpleTemplate, "utf-8");
1310
+ const csrFile = import_node_path5.default.join(tmpDir, "request.csr");
1311
+ await createCertificateSigningRequestWithOpenSSL(csrFile, {
1312
+ rootDir: tmpDir,
1313
+ configFile,
1314
+ privateKey: privateKeyFile,
1315
+ applicationUri: options.applicationUri,
1316
+ subject: options.subject,
1317
+ dns: options.dns ?? [],
1318
+ ip: options.ip ?? [],
1319
+ purpose: import_node_opcua_crypto2.CertificatePurpose.ForApplication
1320
+ });
1321
+ const certFile = import_node_path5.default.join(tmpDir, "certificate.pem");
1322
+ await this.signCertificateRequest(certFile, csrFile, {
1323
+ applicationUri: options.applicationUri,
1324
+ dns: options.dns,
1325
+ ip: options.ip,
1326
+ startDate,
1327
+ validity
1328
+ });
1329
+ const certPem = (0, import_node_opcua_crypto2.readCertificatePEM)(certFile);
1330
+ const certificateDer = (0, import_node_opcua_crypto2.convertPEMtoDER)(certPem);
1331
+ const privateKey = (0, import_node_opcua_crypto2.readPrivateKey)(privateKeyFile);
1332
+ return { certificateDer, privateKey };
1333
+ } finally {
1334
+ await import_node_fs7.default.promises.rm(tmpDir, {
1335
+ recursive: true,
1336
+ force: true
1337
+ });
1338
+ }
1339
+ }
1340
+ /**
1341
+ * Generate a new RSA key pair, create an internal CSR, sign it
1342
+ * with this CA, and return the result as a PKCS#12 (PFX)
1343
+ * buffer bundling the certificate, private key, and CA chain.
1344
+ *
1345
+ * The private key is **never stored** by the CA — it exists only
1346
+ * in a temporary directory that is cleaned up after the operation.
1347
+ *
1348
+ * @param options - key generation, certificate, and PFX options
1349
+ * @returns the PFX as a `Buffer`
1350
+ */
1351
+ async generateKeyPairAndSignPFX(options) {
1352
+ const keySize = options.keySize ?? 2048;
1353
+ const validity = options.validity ?? 365;
1354
+ const startDate = options.startDate ?? /* @__PURE__ */ new Date();
1355
+ const passphrase = options.passphrase ?? "";
1356
+ const tmpDir = await import_node_fs7.default.promises.mkdtemp(import_node_path5.default.join(import_node_os3.default.tmpdir(), "pki-keygen-pfx-"));
1357
+ try {
1358
+ const privateKeyFile = import_node_path5.default.join(tmpDir, "private_key.pem");
1359
+ await (0, import_node_opcua_crypto2.generatePrivateKeyFile)(privateKeyFile, keySize);
1360
+ const configFile = import_node_path5.default.join(tmpDir, "openssl.cnf");
1361
+ await import_node_fs7.default.promises.writeFile(configFile, configurationFileSimpleTemplate, "utf-8");
1362
+ const csrFile = import_node_path5.default.join(tmpDir, "request.csr");
1363
+ await createCertificateSigningRequestWithOpenSSL(csrFile, {
1364
+ rootDir: tmpDir,
1365
+ configFile,
1366
+ privateKey: privateKeyFile,
1367
+ applicationUri: options.applicationUri,
1368
+ subject: options.subject,
1369
+ dns: options.dns ?? [],
1370
+ ip: options.ip ?? [],
1371
+ purpose: import_node_opcua_crypto2.CertificatePurpose.ForApplication
1372
+ });
1373
+ const certFile = import_node_path5.default.join(tmpDir, "certificate.pem");
1374
+ await this.signCertificateRequest(certFile, csrFile, {
1375
+ applicationUri: options.applicationUri,
1376
+ dns: options.dns,
1377
+ ip: options.ip,
1378
+ startDate,
1379
+ validity
1380
+ });
1381
+ const pfxFile = import_node_path5.default.join(tmpDir, "bundle.pfx");
1382
+ await createPFX({
1383
+ certificateFile: certFile,
1384
+ privateKeyFile,
1385
+ outputFile: pfxFile,
1386
+ passphrase,
1387
+ caCertificateFiles: [this.caCertificate]
1388
+ });
1389
+ return await import_node_fs7.default.promises.readFile(pfxFile);
1390
+ } finally {
1391
+ await import_node_fs7.default.promises.rm(tmpDir, {
1153
1392
  recursive: true,
1154
1393
  force: true
1155
1394
  });
@@ -1171,7 +1410,7 @@ var CertificateAuthority = class {
1171
1410
  const info = (0, import_node_opcua_crypto2.exploreCertificate)(certDer);
1172
1411
  const serial = info.tbsCertificate.serialNumber.replace(/:/g, "").toUpperCase();
1173
1412
  const storedCertFile = import_node_path5.default.join(this.rootDir, "certs", `${serial}.pem`);
1174
- if (!import_node_fs6.default.existsSync(storedCertFile)) {
1413
+ if (!import_node_fs7.default.existsSync(storedCertFile)) {
1175
1414
  throw new Error(`Cannot revoke: no stored certificate found for serial ${serial} at ${storedCertFile}`);
1176
1415
  }
1177
1416
  await this.revokeCertificate(storedCertFile, {
@@ -1186,6 +1425,204 @@ var CertificateAuthority = class {
1186
1425
  async initialize() {
1187
1426
  await construct_CertificateAuthority(this);
1188
1427
  }
1428
+ /**
1429
+ * Initialize the CA directory structure and generate the
1430
+ * private key + CSR **without signing**.
1431
+ *
1432
+ * Use this when the CA certificate will be signed by an
1433
+ * external (third-party) root CA. After receiving the signed
1434
+ * certificate, call {@link installCACertificate} to complete
1435
+ * the setup.
1436
+ *
1437
+ * **Idempotent / restart-safe:**
1438
+ * - If the CA certificate exists and is valid → `{ status: "ready" }`
1439
+ * - If the CA certificate has expired → `{ status: "expired", csrPath, expiryDate }`
1440
+ * (a new CSR is generated, preserving the existing private key)
1441
+ * - If key + CSR exist but no cert (restart before install) →
1442
+ * `{ status: "pending", csrPath }` without regenerating
1443
+ * - Otherwise → generates key + CSR → `{ status: "created", csrPath }`
1444
+ *
1445
+ * @returns an {@link InitializeCSRResult} describing the CA state
1446
+ */
1447
+ async initializeCSR() {
1448
+ const caRootDir = import_node_path5.default.resolve(this.rootDir);
1449
+ mkdirRecursiveSync(caRootDir);
1450
+ for (const dir of ["private", "public", "certs", "crl", "conf"]) {
1451
+ mkdirRecursiveSync(import_node_path5.default.join(caRootDir, dir));
1452
+ }
1453
+ const caCertFile = this.caCertificate;
1454
+ const privateKeyFile = import_node_path5.default.join(caRootDir, "private/cakey.pem");
1455
+ const csrFile = import_node_path5.default.join(caRootDir, "private/cakey.csr");
1456
+ if (import_node_fs7.default.existsSync(caCertFile)) {
1457
+ const certDer = (0, import_node_opcua_crypto2.convertPEMtoDER)((0, import_node_opcua_crypto2.readCertificatePEM)(caCertFile));
1458
+ const certInfo = (0, import_node_opcua_crypto2.exploreCertificate)(certDer);
1459
+ const notAfter = certInfo.tbsCertificate.validity.notAfter;
1460
+ if (notAfter.getTime() < Date.now()) {
1461
+ debugLog("CA certificate has expired \u2014 generating renewal CSR");
1462
+ await this._generateCSR(caRootDir, privateKeyFile, csrFile);
1463
+ return { status: "expired", csrPath: csrFile, expiryDate: notAfter };
1464
+ }
1465
+ debugLog("CA certificate already exists and is valid \u2014 ready");
1466
+ return { status: "ready" };
1467
+ }
1468
+ if (import_node_fs7.default.existsSync(privateKeyFile) && import_node_fs7.default.existsSync(csrFile)) {
1469
+ debugLog("CA key + CSR already exist \u2014 pending external signing");
1470
+ return { status: "pending", csrPath: csrFile };
1471
+ }
1472
+ const serial = import_node_path5.default.join(caRootDir, "serial");
1473
+ if (!import_node_fs7.default.existsSync(serial)) {
1474
+ await import_node_fs7.default.promises.writeFile(serial, "1000");
1475
+ }
1476
+ const crlNumber = import_node_path5.default.join(caRootDir, "crlnumber");
1477
+ if (!import_node_fs7.default.existsSync(crlNumber)) {
1478
+ await import_node_fs7.default.promises.writeFile(crlNumber, "1000");
1479
+ }
1480
+ const indexFile = import_node_path5.default.join(caRootDir, "index.txt");
1481
+ if (!import_node_fs7.default.existsSync(indexFile)) {
1482
+ await import_node_fs7.default.promises.writeFile(indexFile, "");
1483
+ }
1484
+ const indexFileAttr = import_node_path5.default.join(caRootDir, "index.txt.attr");
1485
+ if (!import_node_fs7.default.existsSync(indexFileAttr)) {
1486
+ await import_node_fs7.default.promises.writeFile(indexFileAttr, "unique_subject = no");
1487
+ }
1488
+ const caConfigFile = this.configFile;
1489
+ let data = configurationFileTemplate;
1490
+ data = makePath(data.replace(/%%ROOT_FOLDER%%/, caRootDir));
1491
+ await import_node_fs7.default.promises.writeFile(caConfigFile, data);
1492
+ if (!import_node_fs7.default.existsSync(privateKeyFile)) {
1493
+ await (0, import_node_opcua_crypto2.generatePrivateKeyFile)(privateKeyFile, this.keySize);
1494
+ }
1495
+ await this._generateCSR(caRootDir, privateKeyFile, csrFile);
1496
+ return { status: "created", csrPath: csrFile };
1497
+ }
1498
+ /**
1499
+ * Check whether the CA certificate needs renewal and, if so,
1500
+ * generate a new CSR for re-signing by the external root CA.
1501
+ *
1502
+ * Use this while the CA is running to detect upcoming expiry
1503
+ * **before** it actually expires. The existing private key is
1504
+ * preserved so previously issued certs remain valid.
1505
+ *
1506
+ * @param thresholdDays - number of days before expiry at which
1507
+ * to trigger renewal (default: 30)
1508
+ * @returns an {@link InitializeCSRResult} — `"expired"` if
1509
+ * renewal is needed, `"ready"` if the cert is still valid
1510
+ */
1511
+ async renewCSR(thresholdDays = 30) {
1512
+ const caRootDir = import_node_path5.default.resolve(this.rootDir);
1513
+ const caCertFile = this.caCertificate;
1514
+ const privateKeyFile = import_node_path5.default.join(caRootDir, "private/cakey.pem");
1515
+ const csrFile = import_node_path5.default.join(caRootDir, "private/cakey.csr");
1516
+ if (!import_node_fs7.default.existsSync(caCertFile)) {
1517
+ return this.initializeCSR();
1518
+ }
1519
+ const certDer = (0, import_node_opcua_crypto2.convertPEMtoDER)((0, import_node_opcua_crypto2.readCertificatePEM)(caCertFile));
1520
+ const certInfo = (0, import_node_opcua_crypto2.exploreCertificate)(certDer);
1521
+ const notAfter = certInfo.tbsCertificate.validity.notAfter;
1522
+ const thresholdMs = thresholdDays * 24 * 60 * 60 * 1e3;
1523
+ if (notAfter.getTime() - Date.now() < thresholdMs) {
1524
+ debugLog(`CA certificate expires within ${thresholdDays} days \u2014 generating renewal CSR`);
1525
+ await this._generateCSR(caRootDir, privateKeyFile, csrFile);
1526
+ return { status: "expired", csrPath: csrFile, expiryDate: notAfter };
1527
+ }
1528
+ return { status: "ready" };
1529
+ }
1530
+ /**
1531
+ * Generate a CSR using the existing private key.
1532
+ * @internal
1533
+ */
1534
+ async _generateCSR(caRootDir, privateKeyFile, csrFile) {
1535
+ const subjectOpt = ` -subj "${this.subject.toString()}" `;
1536
+ processAltNames({});
1537
+ const options = { cwd: caRootDir };
1538
+ const configFile = generateStaticConfig("conf/caconfig.cnf", options);
1539
+ const configOption = ` -config ${q3(n4(configFile))}`;
1540
+ await execute_openssl(
1541
+ "req -new -sha256 -text -extensions v3_ca_req" + configOption + " -key " + q3(n4(privateKeyFile)) + " -out " + q3(n4(csrFile)) + " " + subjectOpt,
1542
+ options
1543
+ );
1544
+ }
1545
+ /**
1546
+ * Install an externally-signed CA certificate and generate
1547
+ * the initial CRL.
1548
+ *
1549
+ * Call this after {@link initializeCSR} once the external
1550
+ * root CA has signed the CSR.
1551
+ *
1552
+ * **Safety checks:**
1553
+ * - Verifies that the certificate's public key matches the
1554
+ * CA private key before installing.
1555
+ *
1556
+ * @param signedCertFile - path to the PEM-encoded signed
1557
+ * CA certificate (issued by the external root CA)
1558
+ * @returns an {@link InstallCACertificateResult} with
1559
+ * `status: "success"` or `status: "error"` and a `reason`
1560
+ */
1561
+ async installCACertificate(signedCertFile) {
1562
+ const caRootDir = import_node_path5.default.resolve(this.rootDir);
1563
+ const caCertFile = this.caCertificate;
1564
+ const privateKeyFile = import_node_path5.default.join(caRootDir, "private/cakey.pem");
1565
+ const fullPem = await import_node_fs7.default.promises.readFile(signedCertFile, "utf8");
1566
+ const pemBlocks = fullPem.match(/-----BEGIN CERTIFICATE-----[\s\S]*?-----END CERTIFICATE-----/g);
1567
+ if (!pemBlocks || pemBlocks.length === 0) {
1568
+ return {
1569
+ status: "error",
1570
+ reason: "no_certificate_found",
1571
+ message: "The provided file does not contain any PEM-encoded certificate."
1572
+ };
1573
+ }
1574
+ const certDer = (0, import_node_opcua_crypto2.convertPEMtoDER)(pemBlocks[0]);
1575
+ const privateKey = (0, import_node_opcua_crypto2.readPrivateKey)(privateKeyFile);
1576
+ if (!(0, import_node_opcua_crypto2.certificateMatchesPrivateKey)(certDer, privateKey)) {
1577
+ return {
1578
+ status: "error",
1579
+ reason: "certificate_key_mismatch",
1580
+ message: "The provided certificate does not match the CA private key. Ensure the certificate was signed from the CSR generated by initializeCSR()."
1581
+ };
1582
+ }
1583
+ await import_node_fs7.default.promises.writeFile(caCertFile, `${pemBlocks[0]}
1584
+ `);
1585
+ const issuerChainFile = this.issuerCertificateChain;
1586
+ if (pemBlocks.length > 1) {
1587
+ const issuerPem = `${pemBlocks.slice(1).join("\n")}
1588
+ `;
1589
+ await import_node_fs7.default.promises.writeFile(issuerChainFile, issuerPem);
1590
+ debugLog(`Stored ${pemBlocks.length - 1} issuer certificate(s) in issuer_chain.pem`);
1591
+ } else {
1592
+ if (import_node_fs7.default.existsSync(issuerChainFile)) {
1593
+ await import_node_fs7.default.promises.unlink(issuerChainFile);
1594
+ }
1595
+ }
1596
+ const options = { cwd: caRootDir };
1597
+ const configFile = generateStaticConfig("conf/caconfig.cnf", options);
1598
+ const configOption = ` -config ${q3(n4(configFile))}`;
1599
+ await regenerateCrl(this.revocationList, configOption, options);
1600
+ return { status: "success" };
1601
+ }
1602
+ /**
1603
+ * Sign a CSR with CA extensions (`v3_ca`), producing a
1604
+ * subordinate CA certificate.
1605
+ *
1606
+ * Unlike {@link signCertificateRequest} which signs with
1607
+ * end-entity extensions (SANs, etc.), this method signs
1608
+ * with `basicConstraints = CA:TRUE` and `keyUsage =
1609
+ * keyCertSign, cRLSign`.
1610
+ *
1611
+ * @param certFile - output path for the signed CA cert (PEM)
1612
+ * @param csrFile - path to the subordinate CA's CSR
1613
+ * @param params - signing parameters
1614
+ */
1615
+ async signCACertificateRequest(certFile, csrFile, params) {
1616
+ const caRootDir = import_node_path5.default.resolve(this.rootDir);
1617
+ const options = { cwd: caRootDir };
1618
+ const configFile = generateStaticConfig("conf/caconfig.cnf", options);
1619
+ const validity = params.validity ?? 3650;
1620
+ await execute_openssl(
1621
+ ` x509 -sha256 -req -days ${validity} -text -extensions v3_ca -extfile ` + q3(n4(configFile)) + " -in " + q3(n4(csrFile)) + " -CA " + q3(n4(this.caCertificate)) + " -CAkey " + q3(n4(import_node_path5.default.join(caRootDir, "private/cakey.pem"))) + " -CAserial " + q3(n4(import_node_path5.default.join(caRootDir, "serial"))) + " -out " + q3(n4(certFile)),
1622
+ options
1623
+ );
1624
+ await this.constructCertificateChain(certFile);
1625
+ }
1189
1626
  /**
1190
1627
  * Rebuild the combined CA certificate + CRL file.
1191
1628
  *
@@ -1195,13 +1632,13 @@ var CertificateAuthority = class {
1195
1632
  */
1196
1633
  async constructCACertificateWithCRL() {
1197
1634
  const cacertWithCRL = this.caCertificateWithCrl;
1198
- if (import_node_fs6.default.existsSync(this.revocationList)) {
1199
- await import_node_fs6.default.promises.writeFile(
1635
+ if (import_node_fs7.default.existsSync(this.revocationList)) {
1636
+ await import_node_fs7.default.promises.writeFile(
1200
1637
  cacertWithCRL,
1201
- import_node_fs6.default.readFileSync(this.caCertificate, "utf8") + import_node_fs6.default.readFileSync(this.revocationList, "utf8")
1638
+ import_node_fs7.default.readFileSync(this.caCertificate, "utf8") + import_node_fs7.default.readFileSync(this.revocationList, "utf8")
1202
1639
  );
1203
1640
  } else {
1204
- await import_node_fs6.default.promises.writeFile(cacertWithCRL, import_node_fs6.default.readFileSync(this.caCertificate));
1641
+ await import_node_fs7.default.promises.writeFile(cacertWithCRL, import_node_fs7.default.readFileSync(this.caCertificate));
1205
1642
  }
1206
1643
  }
1207
1644
  /**
@@ -1211,14 +1648,15 @@ var CertificateAuthority = class {
1211
1648
  * @param certificate - path to the certificate file to extend
1212
1649
  */
1213
1650
  async constructCertificateChain(certificate) {
1214
- (0, import_node_assert6.default)(import_node_fs6.default.existsSync(certificate));
1215
- (0, import_node_assert6.default)(import_node_fs6.default.existsSync(this.caCertificate));
1651
+ (0, import_node_assert7.default)(import_node_fs7.default.existsSync(certificate));
1652
+ (0, import_node_assert7.default)(import_node_fs7.default.existsSync(this.caCertificate));
1216
1653
  debugLog(import_chalk5.default.yellow(" certificate file :"), import_chalk5.default.cyan(certificate));
1217
- await import_node_fs6.default.promises.writeFile(
1218
- certificate,
1219
- await import_node_fs6.default.promises.readFile(certificate, "utf8") + await import_node_fs6.default.promises.readFile(this.caCertificate, "utf8")
1220
- // + fs.readFileSync(this.revocationList)
1221
- );
1654
+ let chain = await import_node_fs7.default.promises.readFile(certificate, "utf8");
1655
+ chain += await import_node_fs7.default.promises.readFile(this.caCertificate, "utf8");
1656
+ if (import_node_fs7.default.existsSync(this.issuerCertificateChain)) {
1657
+ chain += await import_node_fs7.default.promises.readFile(this.issuerCertificateChain, "utf8");
1658
+ }
1659
+ await import_node_fs7.default.promises.writeFile(certificate, chain);
1222
1660
  }
1223
1661
  /**
1224
1662
  * Create a self-signed certificate using OpenSSL.
@@ -1228,8 +1666,8 @@ var CertificateAuthority = class {
1228
1666
  * @param params - certificate parameters (subject, validity, SANs)
1229
1667
  */
1230
1668
  async createSelfSignedCertificate(certificateFile, privateKey, params) {
1231
- (0, import_node_assert6.default)(typeof privateKey === "string");
1232
- (0, import_node_assert6.default)(import_node_fs6.default.existsSync(privateKey));
1669
+ (0, import_node_assert7.default)(typeof privateKey === "string");
1670
+ (0, import_node_assert7.default)(import_node_fs7.default.existsSync(privateKey));
1233
1671
  if (!certificateFileExist(certificateFile)) {
1234
1672
  return;
1235
1673
  }
@@ -1237,7 +1675,7 @@ var CertificateAuthority = class {
1237
1675
  adjustApplicationUri(params);
1238
1676
  processAltNames(params);
1239
1677
  const csrFile = `${certificateFile}_csr`;
1240
- (0, import_node_assert6.default)(csrFile);
1678
+ (0, import_node_assert7.default)(csrFile);
1241
1679
  const configFile = generateStaticConfig(this.configFile, { cwd: this.rootDir });
1242
1680
  const options = {
1243
1681
  cwd: this.rootDir,
@@ -1248,19 +1686,19 @@ var CertificateAuthority = class {
1248
1686
  const subjectOptions = subject && subject.length > 1 ? ` -subj ${subject} ` : "";
1249
1687
  displaySubtitle("- the certificate signing request");
1250
1688
  await execute_openssl(
1251
- "req -new -sha256 -text " + configOption + subjectOptions + " -batch -key " + q(n2(privateKey)) + " -out " + q(n2(csrFile)),
1689
+ "req -new -sha256 -text " + configOption + subjectOptions + " -batch -key " + q3(n4(privateKey)) + " -out " + q3(n4(csrFile)),
1252
1690
  options
1253
1691
  );
1254
1692
  displaySubtitle("- creating the self-signed certificate");
1255
1693
  await execute_openssl(
1256
- "ca -selfsign -keyfile " + q(n2(privateKey)) + " -startdate " + x509Date(params.startDate) + " -enddate " + x509Date(params.endDate) + " -batch -out " + q(n2(certificateFile)) + " -in " + q(n2(csrFile)),
1694
+ "ca -selfsign -keyfile " + q3(n4(privateKey)) + " -startdate " + x509Date(params.startDate) + " -enddate " + x509Date(params.endDate) + " -batch -out " + q3(n4(certificateFile)) + " -in " + q3(n4(csrFile)),
1257
1695
  options
1258
1696
  );
1259
1697
  displaySubtitle("- dump the certificate for a check");
1260
- await execute_openssl(`x509 -in ${q(n2(certificateFile))} -dates -fingerprint -purpose -noout`, {});
1698
+ await execute_openssl(`x509 -in ${q3(n4(certificateFile))} -dates -fingerprint -purpose -noout`, {});
1261
1699
  displaySubtitle("- verify self-signed certificate");
1262
- await execute_openssl_no_failure(`verify -verbose -CAfile ${q(n2(certificateFile))} ${q(n2(certificateFile))}`, options);
1263
- await import_node_fs6.default.promises.unlink(csrFile);
1700
+ await execute_openssl_no_failure(`verify -verbose -CAfile ${q3(n4(certificateFile))} ${q3(n4(certificateFile))}`, options);
1701
+ await import_node_fs7.default.promises.unlink(csrFile);
1264
1702
  }
1265
1703
  /**
1266
1704
  * Revoke a certificate and regenerate the CRL.
@@ -1289,22 +1727,22 @@ var CertificateAuthority = class {
1289
1727
  setEnv("ALTNAME", "");
1290
1728
  const randomFile = import_node_path5.default.join(this.rootDir, "random.rnd");
1291
1729
  setEnv("RANDFILE", randomFile);
1292
- const configOption = ` -config ${q(n2(configFile))}`;
1730
+ const configOption = ` -config ${q3(n4(configFile))}`;
1293
1731
  const reason = params.reason || "keyCompromise";
1294
- (0, import_node_assert6.default)(crlReasons.indexOf(reason) >= 0);
1732
+ (0, import_node_assert7.default)(crlReasons.indexOf(reason) >= 0);
1295
1733
  displayTitle(`Revoking certificate ${certificate}`);
1296
1734
  displaySubtitle("Revoke certificate");
1297
- await execute_openssl_no_failure(`ca -verbose ${configOption} -revoke ${q(certificate)} -crl_reason ${reason}`, options);
1735
+ await execute_openssl_no_failure(`ca -verbose ${configOption} -revoke ${q3(certificate)} -crl_reason ${reason}`, options);
1298
1736
  await regenerateCrl(this.revocationList, configOption, options);
1299
1737
  displaySubtitle("Verify that certificate is revoked");
1300
1738
  await execute_openssl_no_failure(
1301
- "verify -verbose -CRLfile " + q(n2(this.revocationList)) + " -CAfile " + q(n2(this.caCertificate)) + " -crl_check " + q(n2(certificate)),
1739
+ "verify -verbose -CRLfile " + q3(n4(this.revocationList)) + " -CAfile " + q3(n4(this.caCertificate)) + " -crl_check " + q3(n4(certificate)),
1302
1740
  options
1303
1741
  );
1304
1742
  displaySubtitle("Produce CRL in DER form ");
1305
- await execute_openssl(`crl -in ${q(n2(this.revocationList))} -out crl/revocation_list.der -outform der`, options);
1743
+ await execute_openssl(`crl -in ${q3(n4(this.revocationList))} -out crl/revocation_list.der -outform der`, options);
1306
1744
  displaySubtitle("Produce CRL in PEM form ");
1307
- await execute_openssl(`crl -in ${q(n2(this.revocationList))} -out crl/revocation_list.pem -outform pem -text `, options);
1745
+ await execute_openssl(`crl -in ${q3(n4(this.revocationList))} -out crl/revocation_list.pem -outform pem -text `, options);
1308
1746
  }
1309
1747
  /**
1310
1748
  * Sign a Certificate Signing Request (CSR) with this CA.
@@ -1320,7 +1758,7 @@ var CertificateAuthority = class {
1320
1758
  */
1321
1759
  async signCertificateRequest(certificate, certificateSigningRequestFilename, params1) {
1322
1760
  await ensure_openssl_installed();
1323
- (0, import_node_assert6.default)(import_node_fs6.default.existsSync(certificateSigningRequestFilename));
1761
+ (0, import_node_assert7.default)(import_node_fs7.default.existsSync(certificateSigningRequestFilename));
1324
1762
  if (!certificateFileExist(certificate)) {
1325
1763
  return "";
1326
1764
  }
@@ -1347,11 +1785,11 @@ var CertificateAuthority = class {
1347
1785
  displaySubtitle("- then we ask the authority to sign the certificate signing request");
1348
1786
  const configOption = ` -config ${configFile}`;
1349
1787
  await execute_openssl(
1350
- "ca " + configOption + " -startdate " + x509Date(params1.startDate) + " -enddate " + x509Date(params1.endDate) + " -batch -out " + q(n2(certificate)) + " -in " + q(n2(certificateSigningRequestFilename)),
1788
+ "ca " + configOption + " -startdate " + x509Date(params1.startDate) + " -enddate " + x509Date(params1.endDate) + " -batch -out " + q3(n4(certificate)) + " -in " + q3(n4(certificateSigningRequestFilename)),
1351
1789
  options
1352
1790
  );
1353
1791
  displaySubtitle("- dump the certificate for a check");
1354
- await execute_openssl(`x509 -in ${q(n2(certificate))} -dates -fingerprint -purpose -noout`, options);
1792
+ await execute_openssl(`x509 -in ${q3(n4(certificate))} -dates -fingerprint -purpose -noout`, options);
1355
1793
  displaySubtitle("- construct CA certificate with CRL");
1356
1794
  await this.constructCACertificateWithCRL();
1357
1795
  displaySubtitle("- construct certificate chain");
@@ -1374,7 +1812,7 @@ var CertificateAuthority = class {
1374
1812
  const _configOption = ` -config ${configFile}`;
1375
1813
  _configOption;
1376
1814
  await execute_openssl_no_failure(
1377
- `verify -verbose -CAfile ${q(n2(this.caCertificateWithCrl))} ${q(n2(certificate))}`,
1815
+ `verify -verbose -CAfile ${q3(n4(this.caCertificateWithCrl))} ${q3(n4(certificate))}`,
1378
1816
  options
1379
1817
  );
1380
1818
  }
@@ -1383,7 +1821,7 @@ var CertificateAuthority = class {
1383
1821
 
1384
1822
  // packages/node-opcua-pki/lib/pki/certificate_manager.ts
1385
1823
  var import_node_events = require("events");
1386
- var import_node_fs9 = __toESM(require("fs"));
1824
+ var import_node_fs10 = __toESM(require("fs"));
1387
1825
  var import_node_path6 = __toESM(require("path"));
1388
1826
  var import_global_mutex = require("@ster5/global-mutex");
1389
1827
  var import_chalk6 = __toESM(require("chalk"));
@@ -1391,21 +1829,21 @@ var import_chokidar = __toESM(require("chokidar"));
1391
1829
  var import_node_opcua_crypto5 = require("node-opcua-crypto");
1392
1830
 
1393
1831
  // packages/node-opcua-pki/lib/toolbox/without_openssl/create_certificate_signing_request.ts
1394
- var import_node_assert7 = __toESM(require("assert"));
1395
- var import_node_fs7 = __toESM(require("fs"));
1832
+ var import_node_assert8 = __toESM(require("assert"));
1833
+ var import_node_fs8 = __toESM(require("fs"));
1396
1834
  var import_node_opcua_crypto3 = require("node-opcua-crypto");
1397
1835
  async function createCertificateSigningRequestAsync(certificateSigningRequestFilename, params) {
1398
- (0, import_node_assert7.default)(params);
1399
- (0, import_node_assert7.default)(params.rootDir);
1400
- (0, import_node_assert7.default)(params.configFile);
1401
- (0, import_node_assert7.default)(params.privateKey);
1402
- (0, import_node_assert7.default)(typeof params.privateKey === "string");
1403
- (0, import_node_assert7.default)(import_node_fs7.default.existsSync(params.privateKey), `Private key must exist${params.privateKey}`);
1404
- (0, import_node_assert7.default)(import_node_fs7.default.existsSync(params.rootDir), "RootDir key must exist");
1405
- (0, import_node_assert7.default)(typeof certificateSigningRequestFilename === "string");
1836
+ (0, import_node_assert8.default)(params);
1837
+ (0, import_node_assert8.default)(params.rootDir);
1838
+ (0, import_node_assert8.default)(params.configFile);
1839
+ (0, import_node_assert8.default)(params.privateKey);
1840
+ (0, import_node_assert8.default)(typeof params.privateKey === "string");
1841
+ (0, import_node_assert8.default)(import_node_fs8.default.existsSync(params.privateKey), `Private key must exist${params.privateKey}`);
1842
+ (0, import_node_assert8.default)(import_node_fs8.default.existsSync(params.rootDir), "RootDir key must exist");
1843
+ (0, import_node_assert8.default)(typeof certificateSigningRequestFilename === "string");
1406
1844
  const subject = params.subject ? new import_node_opcua_crypto3.Subject(params.subject).toString() : void 0;
1407
1845
  displaySubtitle("- Creating a Certificate Signing Request with subtile");
1408
- const privateKeyPem = await import_node_fs7.default.promises.readFile(params.privateKey, "utf-8");
1846
+ const privateKeyPem = await import_node_fs8.default.promises.readFile(params.privateKey, "utf-8");
1409
1847
  const privateKey = await (0, import_node_opcua_crypto3.pemToPrivateKey)(privateKeyPem);
1410
1848
  const { csr } = await (0, import_node_opcua_crypto3.createCertificateSigningRequest)({
1411
1849
  privateKey,
@@ -1415,33 +1853,33 @@ async function createCertificateSigningRequestAsync(certificateSigningRequestFil
1415
1853
  applicationUri: params.applicationUri,
1416
1854
  purpose: params.purpose
1417
1855
  });
1418
- await import_node_fs7.default.promises.writeFile(certificateSigningRequestFilename, csr, "utf-8");
1856
+ await import_node_fs8.default.promises.writeFile(certificateSigningRequestFilename, csr, "utf-8");
1419
1857
  display(`- privateKey ${params.privateKey}`);
1420
1858
  display(`- certificateSigningRequestFilename ${certificateSigningRequestFilename}`);
1421
1859
  }
1422
1860
 
1423
1861
  // packages/node-opcua-pki/lib/toolbox/without_openssl/create_self_signed_certificate.ts
1424
- var import_node_assert8 = __toESM(require("assert"));
1425
- var import_node_fs8 = __toESM(require("fs"));
1862
+ var import_node_assert9 = __toESM(require("assert"));
1863
+ var import_node_fs9 = __toESM(require("fs"));
1426
1864
  var import_node_opcua_crypto4 = require("node-opcua-crypto");
1427
1865
  async function createSelfSignedCertificateAsync(certificate, params) {
1428
1866
  params.purpose = params.purpose || import_node_opcua_crypto4.CertificatePurpose.ForApplication;
1429
- (0, import_node_assert8.default)(params.purpose, "Please provide a Certificate Purpose");
1430
- (0, import_node_assert8.default)(import_node_fs8.default.existsSync(params.configFile));
1431
- (0, import_node_assert8.default)(import_node_fs8.default.existsSync(params.rootDir));
1432
- (0, import_node_assert8.default)(import_node_fs8.default.existsSync(params.privateKey));
1867
+ (0, import_node_assert9.default)(params.purpose, "Please provide a Certificate Purpose");
1868
+ (0, import_node_assert9.default)(import_node_fs9.default.existsSync(params.configFile));
1869
+ (0, import_node_assert9.default)(import_node_fs9.default.existsSync(params.rootDir));
1870
+ (0, import_node_assert9.default)(import_node_fs9.default.existsSync(params.privateKey));
1433
1871
  if (!params.subject) {
1434
1872
  throw Error("Missing subject");
1435
1873
  }
1436
- (0, import_node_assert8.default)(typeof params.applicationUri === "string");
1437
- (0, import_node_assert8.default)(Array.isArray(params.dns));
1874
+ (0, import_node_assert9.default)(typeof params.applicationUri === "string");
1875
+ (0, import_node_assert9.default)(Array.isArray(params.dns));
1438
1876
  adjustDate(params);
1439
- (0, import_node_assert8.default)(Object.prototype.hasOwnProperty.call(params, "validity"));
1877
+ (0, import_node_assert9.default)(Object.prototype.hasOwnProperty.call(params, "validity"));
1440
1878
  let subject = new import_node_opcua_crypto4.Subject(params.subject);
1441
1879
  subject = subject.toString();
1442
1880
  const purpose = params.purpose;
1443
1881
  displayTitle("Generate a certificate request");
1444
- const privateKeyPem = await import_node_fs8.default.promises.readFile(params.privateKey, "utf-8");
1882
+ const privateKeyPem = await import_node_fs9.default.promises.readFile(params.privateKey, "utf-8");
1445
1883
  const privateKey = await (0, import_node_opcua_crypto4.pemToPrivateKey)(privateKeyPem);
1446
1884
  const { cert } = await (0, import_node_opcua_crypto4.createSelfSignedCertificate)({
1447
1885
  privateKey,
@@ -1454,19 +1892,15 @@ async function createSelfSignedCertificateAsync(certificate, params) {
1454
1892
  applicationUri: params.applicationUri,
1455
1893
  purpose
1456
1894
  });
1457
- await import_node_fs8.default.promises.writeFile(certificate, cert, "utf-8");
1895
+ await import_node_fs9.default.promises.writeFile(certificate, cert, "utf-8");
1458
1896
  }
1459
1897
  async function createSelfSignedCertificate(certificate, params) {
1460
1898
  await createSelfSignedCertificateAsync(certificate, params);
1461
1899
  }
1462
1900
 
1463
- // packages/node-opcua-pki/lib/pki/templates/simple_config_template.cnf.ts
1464
- var config3 = '##################################################################################################\n## SIMPLE OPENSSL CONFIG FILE FOR SELF-SIGNED CERTIFICATE GENERATION\n################################################################################################################\n\ndistinguished_name = req_distinguished_name\ndefault_md = sha1\n\ndefault_md = sha256 # The default digest algorithm\n\n[ v3_ca ]\nsubjectKeyIdentifier = hash\nauthorityKeyIdentifier = keyid:always,issuer:always\n\n# authorityKeyIdentifier = keyid\nbasicConstraints = CA:TRUE\nkeyUsage = critical, cRLSign, keyCertSign\nnsComment = "Self-signed Certificate for CA generated by Node-OPCUA Certificate utility"\n#nsCertType = sslCA, emailCA\n#subjectAltName = email:copy\n#issuerAltName = issuer:copy\n#obj = DER:02:03\n# crlDistributionPoints = @crl_info\n# [ crl_info ]\n# URI.0 = http://localhost:8900/crl.pem\nsubjectAltName = $ENV::ALTNAME\n\n[ req ]\ndays = 390\nreq_extensions = v3_req\nx509_extensions = v3_ca\n\n[v3_req]\nbasicConstraints = CA:false\nkeyUsage = critical, cRLSign, keyCertSign\nsubjectAltName = $ENV::ALTNAME\n\n[ v3_ca_signed]\nsubjectKeyIdentifier = hash\nauthorityKeyIdentifier = keyid,issuer\nbasicConstraints = critical, CA:FALSE\nkeyUsage = nonRepudiation, digitalSignature, keyEncipherment, dataEncipherment, keyCertSign\nextendedKeyUsage = clientAuth,serverAuth \nnsComment = "certificate generated by Node-OPCUA Certificate utility and signed by a CA"\nsubjectAltName = $ENV::ALTNAME\n[ v3_selfsigned]\nsubjectKeyIdentifier = hash\nauthorityKeyIdentifier = keyid,issuer\nbasicConstraints = critical, CA:FALSE\nkeyUsage = nonRepudiation, digitalSignature, keyEncipherment, dataEncipherment, keyCertSign\nextendedKeyUsage = clientAuth,serverAuth \nnsComment = "Self-signed certificate generated by Node-OPCUA Certificate utility"\nsubjectAltName = $ENV::ALTNAME\n[ req_distinguished_name ]\ncountryName = Country Name (2 letter code)\ncountryName_default = FR\ncountryName_min = 2\ncountryName_max = 2\n# stateOrProvinceName = State or Province Name (full name)\n# stateOrProvinceName_default = Ile de France\n# localityName = Locality Name (city, district)\n# localityName_default = Paris\norganizationName = Organization Name (company)\norganizationName_default = NodeOPCUA\n# organizationalUnitName = Organizational Unit Name (department, division)\n# organizationalUnitName_default = R&D\ncommonName = Common Name (hostname, FQDN, IP, or your name)\ncommonName_max = 256\ncommonName_default = NodeOPCUA\n# emailAddress = Email Address\n# emailAddress_max = 40\n# emailAddress_default = node-opcua (at) node-opcua (dot) com\nsubjectAltName = $ENV::ALTNAME';
1465
- var simple_config_template_cnf_default = config3;
1466
-
1467
1901
  // packages/node-opcua-pki/lib/pki/certificate_manager.ts
1468
- var configurationFileSimpleTemplate = simple_config_template_cnf_default;
1469
- var fsWriteFile = import_node_fs9.default.promises.writeFile;
1902
+ var configurationFileSimpleTemplate2 = simple_config_template_cnf_default;
1903
+ var fsWriteFile = import_node_fs10.default.promises.writeFile;
1470
1904
  function getOrComputeInfo(entry) {
1471
1905
  if (!entry.info) {
1472
1906
  entry.info = exploreCertificateCached(entry.certificate);
@@ -1693,7 +2127,7 @@ var CertificateManager = class _CertificateManager extends import_node_events.Ev
1693
2127
  this.#location = makePath(options.location, "");
1694
2128
  this.keySize = options.keySize;
1695
2129
  mkdirRecursiveSync(options.location);
1696
- if (!import_node_fs9.default.existsSync(this.#location)) {
2130
+ if (!import_node_fs10.default.existsSync(this.#location)) {
1697
2131
  throw new Error(`CertificateManager cannot access location ${this.#location}`);
1698
2132
  }
1699
2133
  }
@@ -2006,15 +2440,15 @@ var CertificateManager = class _CertificateManager extends import_node_events.Ev
2006
2440
  mkdirRecursiveSync(import_node_path6.default.join(pkiDir, "issuers"));
2007
2441
  mkdirRecursiveSync(import_node_path6.default.join(pkiDir, "issuers/certs"));
2008
2442
  mkdirRecursiveSync(import_node_path6.default.join(pkiDir, "issuers/crl"));
2009
- if (!import_node_fs9.default.existsSync(this.configFile) || !import_node_fs9.default.existsSync(this.privateKey)) {
2443
+ if (!import_node_fs10.default.existsSync(this.configFile) || !import_node_fs10.default.existsSync(this.privateKey)) {
2010
2444
  return await this.withLock2(async () => {
2011
2445
  if (this.state === 3 /* Disposing */ || this.state === 4 /* Disposed */) {
2012
2446
  return;
2013
2447
  }
2014
- if (!import_node_fs9.default.existsSync(this.configFile)) {
2015
- import_node_fs9.default.writeFileSync(this.configFile, configurationFileSimpleTemplate);
2448
+ if (!import_node_fs10.default.existsSync(this.configFile)) {
2449
+ import_node_fs10.default.writeFileSync(this.configFile, configurationFileSimpleTemplate2);
2016
2450
  }
2017
- if (!import_node_fs9.default.existsSync(this.privateKey)) {
2451
+ if (!import_node_fs10.default.existsSync(this.privateKey)) {
2018
2452
  debugLog("generating private key ...");
2019
2453
  await (0, import_node_opcua_crypto5.generatePrivateKeyFile)(this.privateKey, this.keySize);
2020
2454
  await this.#readCertificates();
@@ -2104,7 +2538,7 @@ var CertificateManager = class _CertificateManager extends import_node_events.Ev
2104
2538
  if (typeof params.applicationUri !== "string") {
2105
2539
  throw new Error("createSelfSignedCertificate: expecting applicationUri to be a string");
2106
2540
  }
2107
- if (!import_node_fs9.default.existsSync(this.privateKey)) {
2541
+ if (!import_node_fs10.default.existsSync(this.privateKey)) {
2108
2542
  throw new Error(`Cannot find private key ${this.privateKey}`);
2109
2543
  }
2110
2544
  let certificateFilename = import_node_path6.default.join(this.rootDir, "own/certs/self_signed_certificate.pem");
@@ -2168,7 +2602,7 @@ var CertificateManager = class _CertificateManager extends import_node_events.Ev
2168
2602
  return "Good" /* Good */;
2169
2603
  }
2170
2604
  const filename = import_node_path6.default.join(this.issuersCertFolder, `issuer_${buildIdealCertificateName(certificate)}.pem`);
2171
- await import_node_fs9.default.promises.writeFile(filename, pemCertificate, "ascii");
2605
+ await import_node_fs10.default.promises.writeFile(filename, pemCertificate, "ascii");
2172
2606
  this.#thumbs.issuers.certs.set(fingerprint, { certificate, filename });
2173
2607
  if (addInTrustList) {
2174
2608
  await this.trustCertificate(certificate);
@@ -2191,8 +2625,9 @@ var CertificateManager = class _CertificateManager extends import_node_events.Ev
2191
2625
  index.set(key, { crls: [], serialNumbers: {} });
2192
2626
  }
2193
2627
  const pemCertificate = (0, import_node_opcua_crypto5.toPem)(crl, "X509 CRL");
2194
- const filename = import_node_path6.default.join(folder, `crl_${buildIdealCertificateName(crl)}.pem`);
2195
- await import_node_fs9.default.promises.writeFile(filename, pemCertificate, "ascii");
2628
+ const sanitizedKey = key.replace(/:/g, "");
2629
+ const filename = import_node_path6.default.join(folder, `crl_[${sanitizedKey}].pem`);
2630
+ await import_node_fs10.default.promises.writeFile(filename, pemCertificate, "ascii");
2196
2631
  await this.#onCrlFileAdded(index, filename);
2197
2632
  await this.#waitAndCheckCRLProcessingStatus();
2198
2633
  return "Good" /* Good */;
@@ -2211,11 +2646,11 @@ var CertificateManager = class _CertificateManager extends import_node_events.Ev
2211
2646
  async clearRevocationLists(target) {
2212
2647
  const clearFolder = async (folder, index) => {
2213
2648
  try {
2214
- const files = await import_node_fs9.default.promises.readdir(folder);
2649
+ const files = await import_node_fs10.default.promises.readdir(folder);
2215
2650
  for (const file of files) {
2216
2651
  const ext = import_node_path6.default.extname(file).toLowerCase();
2217
2652
  if (ext === ".crl" || ext === ".pem" || ext === ".der") {
2218
- await import_node_fs9.default.promises.unlink(import_node_path6.default.join(folder, file));
2653
+ await import_node_fs10.default.promises.unlink(import_node_path6.default.join(folder, file));
2219
2654
  }
2220
2655
  }
2221
2656
  } catch (err) {
@@ -2257,7 +2692,7 @@ var CertificateManager = class _CertificateManager extends import_node_events.Ev
2257
2692
  return null;
2258
2693
  }
2259
2694
  try {
2260
- await import_node_fs9.default.promises.unlink(entry.filename);
2695
+ await import_node_fs10.default.promises.unlink(entry.filename);
2261
2696
  } catch (err) {
2262
2697
  if (err.code !== "ENOENT") {
2263
2698
  throw err;
@@ -2281,7 +2716,7 @@ var CertificateManager = class _CertificateManager extends import_node_events.Ev
2281
2716
  return null;
2282
2717
  }
2283
2718
  try {
2284
- await import_node_fs9.default.promises.unlink(entry.filename);
2719
+ await import_node_fs10.default.promises.unlink(entry.filename);
2285
2720
  } catch (err) {
2286
2721
  if (err.code !== "ENOENT") {
2287
2722
  throw err;
@@ -2304,7 +2739,7 @@ var CertificateManager = class _CertificateManager extends import_node_events.Ev
2304
2739
  if (!crlData) return;
2305
2740
  for (const crlEntry of crlData.crls) {
2306
2741
  try {
2307
- await import_node_fs9.default.promises.unlink(crlEntry.filename);
2742
+ await import_node_fs10.default.promises.unlink(crlEntry.filename);
2308
2743
  } catch (err) {
2309
2744
  if (err.code !== "ENOENT") {
2310
2745
  throw err;
@@ -2457,7 +2892,7 @@ var CertificateManager = class _CertificateManager extends import_node_events.Ev
2457
2892
  if (status === "unknown") {
2458
2893
  const pem = (0, import_node_opcua_crypto5.toPem)(certificate, "CERTIFICATE");
2459
2894
  const filename = import_node_path6.default.join(this.rejectedFolder, `${buildIdealCertificateName(certificate)}.pem`);
2460
- await import_node_fs9.default.promises.writeFile(filename, pem);
2895
+ await import_node_fs10.default.promises.writeFile(filename, pem);
2461
2896
  this.#thumbs.rejected.set(fingerprint, { certificate, filename });
2462
2897
  status = "rejected";
2463
2898
  }
@@ -2476,7 +2911,7 @@ var CertificateManager = class _CertificateManager extends import_node_events.Ev
2476
2911
  const certificateDest = import_node_path6.default.join(destFolder, import_node_path6.default.basename(srcEntry.filename));
2477
2912
  debugLog("#moveCertificate", fingerprint.substring(0, 10), "old name", srcEntry.filename);
2478
2913
  debugLog("#moveCertificate", fingerprint.substring(0, 10), "new name", certificateDest);
2479
- await import_node_fs9.default.promises.rename(srcEntry.filename, certificateDest);
2914
+ await import_node_fs10.default.promises.rename(srcEntry.filename, certificateDest);
2480
2915
  indexSrc.delete(fingerprint);
2481
2916
  const indexDest = newStatus === "trusted" ? this.#thumbs.trusted : this.#thumbs.rejected;
2482
2917
  indexDest.set(fingerprint, { certificate, filename: certificateDest });
@@ -2586,11 +3021,11 @@ var CertificateManager = class _CertificateManager extends import_node_events.Ev
2586
3021
  persistent: false
2587
3022
  };
2588
3023
  const allCapturedHandles = [];
2589
- const origWatch = import_node_fs9.default.watch;
3024
+ const origWatch = import_node_fs10.default.watch;
2590
3025
  let watcherReadyCount = 0;
2591
3026
  const totalWatchers = 5;
2592
- import_node_fs9.default.watch = ((...args) => {
2593
- const handle = origWatch.apply(import_node_fs9.default, args);
3027
+ import_node_fs10.default.watch = ((...args) => {
3028
+ const handle = origWatch.apply(import_node_fs10.default, args);
2594
3029
  handle.setMaxListeners(handle.getMaxListeners() + 1);
2595
3030
  handle.on("error", () => {
2596
3031
  });
@@ -2606,7 +3041,7 @@ var CertificateManager = class _CertificateManager extends import_node_events.Ev
2606
3041
  }
2607
3042
  watcherReadyCount++;
2608
3043
  if (watcherReadyCount >= totalWatchers) {
2609
- import_node_fs9.default.watch = origWatch;
3044
+ import_node_fs10.default.watch = origWatch;
2610
3045
  }
2611
3046
  };
2612
3047
  return { w, capturedHandles: allCapturedHandles.slice(startIdx), unreffAll };
@@ -2630,12 +3065,12 @@ var CertificateManager = class _CertificateManager extends import_node_events.Ev
2630
3065
  * file reads, preventing main-loop stalls with large folders.
2631
3066
  */
2632
3067
  async #scanCertFolder(folder, index) {
2633
- if (!import_node_fs9.default.existsSync(folder)) return;
2634
- const files = await import_node_fs9.default.promises.readdir(folder);
3068
+ if (!import_node_fs10.default.existsSync(folder)) return;
3069
+ const files = await import_node_fs10.default.promises.readdir(folder);
2635
3070
  for (const file of files) {
2636
3071
  const filename = import_node_path6.default.join(folder, file);
2637
3072
  try {
2638
- const stat = await import_node_fs9.default.promises.stat(filename);
3073
+ const stat = await import_node_fs10.default.promises.stat(filename);
2639
3074
  if (!stat.isFile()) continue;
2640
3075
  const certificate = await (0, import_node_opcua_crypto5.readCertificateAsync)(filename);
2641
3076
  const info = exploreCertificateCached(certificate);
@@ -2651,12 +3086,12 @@ var CertificateManager = class _CertificateManager extends import_node_events.Ev
2651
3086
  * Scan a CRL folder and populate the in-memory CRL index.
2652
3087
  */
2653
3088
  async #scanCrlFolder(folder, index) {
2654
- if (!import_node_fs9.default.existsSync(folder)) return;
2655
- const files = await import_node_fs9.default.promises.readdir(folder);
3089
+ if (!import_node_fs10.default.existsSync(folder)) return;
3090
+ const files = await import_node_fs10.default.promises.readdir(folder);
2656
3091
  for (const file of files) {
2657
3092
  const filename = import_node_path6.default.join(folder, file);
2658
3093
  try {
2659
- const stat = await import_node_fs9.default.promises.stat(filename);
3094
+ const stat = await import_node_fs10.default.promises.stat(filename);
2660
3095
  if (!stat.isFile()) continue;
2661
3096
  this.#onCrlFileAdded(index, filename);
2662
3097
  } catch (err) {
@@ -2781,65 +3216,6 @@ var CertificateManager = class _CertificateManager extends import_node_events.Ev
2781
3216
  });
2782
3217
  }
2783
3218
  };
2784
-
2785
- // packages/node-opcua-pki/lib/pki/toolbox_pfx.ts
2786
- var import_node_assert9 = __toESM(require("assert"));
2787
- var import_node_fs10 = __toESM(require("fs"));
2788
- var q2 = quote;
2789
- var n3 = makePath;
2790
- async function createPFX(options) {
2791
- const { certificateFile, privateKeyFile, outputFile, passphrase = "", caCertificateFiles } = options;
2792
- (0, import_node_assert9.default)(import_node_fs10.default.existsSync(certificateFile), `Certificate file does not exist: ${certificateFile}`);
2793
- (0, import_node_assert9.default)(import_node_fs10.default.existsSync(privateKeyFile), `Private key file does not exist: ${privateKeyFile}`);
2794
- let cmd = `pkcs12 -export`;
2795
- cmd += ` -in ${q2(n3(certificateFile))}`;
2796
- cmd += ` -inkey ${q2(n3(privateKeyFile))}`;
2797
- if (caCertificateFiles) {
2798
- for (const caFile of caCertificateFiles) {
2799
- (0, import_node_assert9.default)(import_node_fs10.default.existsSync(caFile), `CA certificate file does not exist: ${caFile}`);
2800
- cmd += ` -certfile ${q2(n3(caFile))}`;
2801
- }
2802
- }
2803
- cmd += ` -out ${q2(n3(outputFile))}`;
2804
- cmd += ` -passout pass:${passphrase}`;
2805
- await execute_openssl(cmd, {});
2806
- }
2807
- async function extractCertificateFromPFX(options) {
2808
- const { pfxFile, passphrase = "" } = options;
2809
- (0, import_node_assert9.default)(import_node_fs10.default.existsSync(pfxFile), `PFX file does not exist: ${pfxFile}`);
2810
- const cmd = `pkcs12 -in ${q2(n3(pfxFile))} -clcerts -nokeys -nodes -passin pass:${passphrase}`;
2811
- return await execute_openssl(cmd, {});
2812
- }
2813
- async function extractPrivateKeyFromPFX(options) {
2814
- const { pfxFile, passphrase = "" } = options;
2815
- (0, import_node_assert9.default)(import_node_fs10.default.existsSync(pfxFile), `PFX file does not exist: ${pfxFile}`);
2816
- const cmd = `pkcs12 -in ${q2(n3(pfxFile))} -nocerts -nodes -passin pass:${passphrase}`;
2817
- return await execute_openssl(cmd, {});
2818
- }
2819
- async function extractCACertificatesFromPFX(options) {
2820
- const { pfxFile, passphrase = "" } = options;
2821
- (0, import_node_assert9.default)(import_node_fs10.default.existsSync(pfxFile), `PFX file does not exist: ${pfxFile}`);
2822
- const cmd = `pkcs12 -in ${q2(n3(pfxFile))} -cacerts -nokeys -nodes -passin pass:${passphrase}`;
2823
- return await execute_openssl(cmd, {});
2824
- }
2825
- async function extractAllFromPFX(options) {
2826
- const [certificate, privateKey, caCertificates] = await Promise.all([
2827
- extractCertificateFromPFX(options),
2828
- extractPrivateKeyFromPFX(options),
2829
- extractCACertificatesFromPFX(options)
2830
- ]);
2831
- return { certificate, privateKey, caCertificates };
2832
- }
2833
- async function convertPFXtoPEM(pfxFile, pemFile, passphrase = "") {
2834
- (0, import_node_assert9.default)(import_node_fs10.default.existsSync(pfxFile), `PFX file does not exist: ${pfxFile}`);
2835
- const cmd = `pkcs12 -in ${q2(n3(pfxFile))} -out ${q2(n3(pemFile))} -nodes -passin pass:${passphrase}`;
2836
- await execute_openssl(cmd, {});
2837
- }
2838
- async function dumpPFX(pfxFile, passphrase = "") {
2839
- (0, import_node_assert9.default)(import_node_fs10.default.existsSync(pfxFile), `PFX file does not exist: ${pfxFile}`);
2840
- const cmd = `pkcs12 -in ${q2(n3(pfxFile))} -info -nodes -passin pass:${passphrase}`;
2841
- return await execute_openssl(cmd, {});
2842
- }
2843
3219
  // Annotate the CommonJS export names for ESM import in node:
2844
3220
  0 && (module.exports = {
2845
3221
  CertificateAuthority,