node-opcua-pki 6.10.1 → 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/bin/pki.mjs CHANGED
@@ -1070,7 +1070,8 @@ var init_certificate_manager = __esm({
1070
1070
  index.set(key, { crls: [], serialNumbers: {} });
1071
1071
  }
1072
1072
  const pemCertificate = toPem(crl, "X509 CRL");
1073
- const filename = path2.join(folder, `crl_${buildIdealCertificateName(crl)}.pem`);
1073
+ const sanitizedKey = key.replace(/:/g, "");
1074
+ const filename = path2.join(folder, `crl_[${sanitizedKey}].pem`);
1074
1075
  await fs4.promises.writeFile(filename, pemCertificate, "ascii");
1075
1076
  await this.#onCrlFileAdded(index, filename);
1076
1077
  await this.#waitAndCheckCRLProcessingStatus();
@@ -2285,6 +2286,39 @@ var init_with_openssl = __esm({
2285
2286
  }
2286
2287
  });
2287
2288
 
2289
+ // packages/node-opcua-pki/lib/pki/toolbox_pfx.ts
2290
+ import assert9 from "assert";
2291
+ import fs9 from "fs";
2292
+ async function createPFX(options) {
2293
+ const { certificateFile, privateKeyFile, outputFile, passphrase = "", caCertificateFiles } = options;
2294
+ assert9(fs9.existsSync(certificateFile), `Certificate file does not exist: ${certificateFile}`);
2295
+ assert9(fs9.existsSync(privateKeyFile), `Private key file does not exist: ${privateKeyFile}`);
2296
+ let cmd = `pkcs12 -export`;
2297
+ cmd += ` -in ${q3(n4(certificateFile))}`;
2298
+ cmd += ` -inkey ${q3(n4(privateKeyFile))}`;
2299
+ if (caCertificateFiles) {
2300
+ for (const caFile of caCertificateFiles) {
2301
+ assert9(fs9.existsSync(caFile), `CA certificate file does not exist: ${caFile}`);
2302
+ cmd += ` -certfile ${q3(n4(caFile))}`;
2303
+ }
2304
+ }
2305
+ cmd += ` -out ${q3(n4(outputFile))}`;
2306
+ cmd += ` -passout pass:${passphrase}`;
2307
+ await execute_openssl(cmd, {});
2308
+ }
2309
+ var q3, n4;
2310
+ var init_toolbox_pfx = __esm({
2311
+ "packages/node-opcua-pki/lib/pki/toolbox_pfx.ts"() {
2312
+ "use strict";
2313
+ init_esm_shims();
2314
+ init_common();
2315
+ init_common2();
2316
+ init_execute_openssl();
2317
+ q3 = quote;
2318
+ n4 = makePath;
2319
+ }
2320
+ });
2321
+
2288
2322
  // packages/node-opcua-pki/lib/ca/templates/ca_config_template.cnf.ts
2289
2323
  var config2, ca_config_template_cnf_default;
2290
2324
  var init_ca_config_template_cnf = __esm({
@@ -2425,18 +2459,21 @@ authorityKeyIdentifier = keyid:always,issuer:always
2425
2459
  });
2426
2460
 
2427
2461
  // packages/node-opcua-pki/lib/ca/certificate_authority.ts
2428
- import assert9 from "assert";
2429
- import fs9 from "fs";
2462
+ import assert10 from "assert";
2463
+ import fs10 from "fs";
2430
2464
  import os4 from "os";
2431
2465
  import path6 from "path";
2432
2466
  import chalk6 from "chalk";
2433
2467
  import {
2468
+ CertificatePurpose as CertificatePurpose2,
2469
+ certificateMatchesPrivateKey,
2434
2470
  convertPEMtoDER,
2435
2471
  exploreCertificate as exploreCertificate2,
2436
2472
  exploreCertificateSigningRequest,
2437
2473
  generatePrivateKeyFile as generatePrivateKeyFile2,
2438
2474
  readCertificatePEM,
2439
2475
  readCertificateSigningRequest,
2476
+ readPrivateKey,
2440
2477
  Subject as Subject4,
2441
2478
  toPem as toPem2
2442
2479
  } from "node-opcua-crypto";
@@ -2457,39 +2494,49 @@ async function construct_CertificateAuthority(certificateAuthority) {
2457
2494
  await make_folders();
2458
2495
  async function construct_default_files() {
2459
2496
  const serial = path6.join(caRootDir, "serial");
2460
- if (!fs9.existsSync(serial)) {
2461
- await fs9.promises.writeFile(serial, "1000");
2497
+ if (!fs10.existsSync(serial)) {
2498
+ await fs10.promises.writeFile(serial, "1000");
2462
2499
  }
2463
2500
  const crlNumber = path6.join(caRootDir, "crlnumber");
2464
- if (!fs9.existsSync(crlNumber)) {
2465
- await fs9.promises.writeFile(crlNumber, "1000");
2501
+ if (!fs10.existsSync(crlNumber)) {
2502
+ await fs10.promises.writeFile(crlNumber, "1000");
2466
2503
  }
2467
2504
  const indexFile = path6.join(caRootDir, "index.txt");
2468
- if (!fs9.existsSync(indexFile)) {
2469
- await fs9.promises.writeFile(indexFile, "");
2505
+ if (!fs10.existsSync(indexFile)) {
2506
+ await fs10.promises.writeFile(indexFile, "");
2470
2507
  }
2471
2508
  }
2472
2509
  await construct_default_files();
2473
- if (fs9.existsSync(path6.join(caRootDir, "private/cakey.pem")) && !config3.forceCA) {
2474
- debugLog("CA private key already exists ... skipping");
2510
+ const caKeyExists = fs10.existsSync(path6.join(caRootDir, "private/cakey.pem"));
2511
+ const caCertExists = fs10.existsSync(path6.join(caRootDir, "public/cacert.pem"));
2512
+ if (caKeyExists && caCertExists && !config3.forceCA) {
2513
+ debugLog("CA private key and certificate already exist ... skipping");
2475
2514
  return;
2476
2515
  }
2516
+ if (caKeyExists && !caCertExists) {
2517
+ debugLog("CA private key exists but cacert.pem is missing \u2014 rebuilding CA");
2518
+ fs10.unlinkSync(path6.join(caRootDir, "private/cakey.pem"));
2519
+ const staleCsr = path6.join(caRootDir, "private/cakey.csr");
2520
+ if (fs10.existsSync(staleCsr)) {
2521
+ fs10.unlinkSync(staleCsr);
2522
+ }
2523
+ }
2477
2524
  displayTitle("Create Certificate Authority (CA)");
2478
2525
  const indexFileAttr = path6.join(caRootDir, "index.txt.attr");
2479
- if (!fs9.existsSync(indexFileAttr)) {
2480
- await fs9.promises.writeFile(indexFileAttr, "unique_subject = no");
2526
+ if (!fs10.existsSync(indexFileAttr)) {
2527
+ await fs10.promises.writeFile(indexFileAttr, "unique_subject = no");
2481
2528
  }
2482
2529
  const caConfigFile = certificateAuthority.configFile;
2483
2530
  if (1) {
2484
2531
  let data = configurationFileTemplate;
2485
2532
  data = makePath(data.replace(/%%ROOT_FOLDER%%/, caRootDir));
2486
- await fs9.promises.writeFile(caConfigFile, data);
2533
+ await fs10.promises.writeFile(caConfigFile, data);
2487
2534
  }
2488
2535
  const subjectOpt = ` -subj "${subject.toString()}" `;
2489
2536
  processAltNames({});
2490
2537
  const options = { cwd: caRootDir };
2491
2538
  const configFile = generateStaticConfig("conf/caconfig.cnf", options);
2492
- const configOption = ` -config ${q3(n4(configFile))}`;
2539
+ const configOption = ` -config ${q4(n5(configFile))}`;
2493
2540
  const keySize = certificateAuthority.keySize;
2494
2541
  const privateKeyFilename = path6.join(caRootDir, "private/cakey.pem");
2495
2542
  const csrFilename = path6.join(caRootDir, "private/cakey.csr");
@@ -2497,14 +2544,26 @@ async function construct_CertificateAuthority(certificateAuthority) {
2497
2544
  await generatePrivateKeyFile2(privateKeyFilename, keySize);
2498
2545
  displayTitle("Generate a certificate request for the CA key");
2499
2546
  await execute_openssl(
2500
- "req -new -sha256 -text -extensions v3_ca_req" + configOption + " -key " + q3(n4(privateKeyFilename)) + " -out " + q3(n4(csrFilename)) + " " + subjectOpt,
2501
- options
2502
- );
2503
- displayTitle("Generate CA Certificate (self-signed)");
2504
- await execute_openssl(
2505
- " 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",
2547
+ "req -new -sha256 -text -extensions v3_ca_req" + configOption + " -key " + q4(n5(privateKeyFilename)) + " -out " + q4(n5(csrFilename)) + " " + subjectOpt,
2506
2548
  options
2507
2549
  );
2550
+ const issuerCA = certificateAuthority._issuerCA;
2551
+ if (issuerCA) {
2552
+ displayTitle("Generate CA Certificate (signed by issuer CA)");
2553
+ const issuerCert = path6.resolve(issuerCA.caCertificate);
2554
+ const issuerKey = path6.resolve(issuerCA.rootDir, "private/cakey.pem");
2555
+ const issuerSerial = path6.resolve(issuerCA.rootDir, "serial");
2556
+ await execute_openssl(
2557
+ " x509 -sha256 -req -days 3650 -text -extensions v3_ca -extfile " + q4(n5(configFile)) + " -in private/cakey.csr -CA " + q4(n5(issuerCert)) + " -CAkey " + q4(n5(issuerKey)) + " -CAserial " + q4(n5(issuerSerial)) + " -out public/cacert.pem",
2558
+ options
2559
+ );
2560
+ } else {
2561
+ displayTitle("Generate CA Certificate (self-signed)");
2562
+ await execute_openssl(
2563
+ " x509 -sha256 -req -days 3650 -text -extensions v3_ca -extfile " + q4(n5(configFile)) + " -in private/cakey.csr -signkey " + q4(n5(privateKeyFilename)) + " -out public/cacert.pem",
2564
+ options
2565
+ );
2566
+ }
2508
2567
  displaySubtitle("generate initial CRL (Certificate Revocation List)");
2509
2568
  await regenerateCrl(certificateAuthority.revocationList, configOption, options);
2510
2569
  displayTitle("Create Certificate Authority (CA) ---> DONE");
@@ -2514,7 +2573,7 @@ async function regenerateCrl(revocationList, configOption, options) {
2514
2573
  await execute_openssl(`ca -gencrl ${configOption} -out crl/revocation_list.crl`, options);
2515
2574
  await execute_openssl("crl -in crl/revocation_list.crl -out crl/revocation_list.der -outform der", options);
2516
2575
  displaySubtitle("Display (Certificate Revocation List)");
2517
- await execute_openssl(`crl -in ${q3(n4(revocationList))} -text -noout`, options);
2576
+ await execute_openssl(`crl -in ${q4(n5(revocationList))} -text -noout`, options);
2518
2577
  }
2519
2578
  function parseOpenSSLDate(dateStr) {
2520
2579
  const raw = dateStr?.split(",")[0] ?? "";
@@ -2528,24 +2587,27 @@ function parseOpenSSLDate(dateStr) {
2528
2587
  const sec = raw.substring(10, 12);
2529
2588
  return `${year}-${month}-${day}T${hour}:${min}:${sec}Z`;
2530
2589
  }
2531
- var defaultSubject, configurationFileTemplate, config3, n4, q3, CertificateAuthority;
2590
+ var defaultSubject, configurationFileTemplate, configurationFileSimpleTemplate2, config3, n5, q4, CertificateAuthority;
2532
2591
  var init_certificate_authority = __esm({
2533
2592
  "packages/node-opcua-pki/lib/ca/certificate_authority.ts"() {
2534
2593
  "use strict";
2535
2594
  init_esm_shims();
2595
+ init_toolbox_pfx();
2536
2596
  init_toolbox();
2537
2597
  init_with_openssl();
2598
+ init_simple_config_template_cnf();
2538
2599
  init_ca_config_template_cnf();
2539
2600
  defaultSubject = "/C=FR/ST=IDF/L=Paris/O=Local NODE-OPCUA Certificate Authority/CN=NodeOPCUA-CA";
2540
2601
  configurationFileTemplate = ca_config_template_cnf_default;
2602
+ configurationFileSimpleTemplate2 = simple_config_template_cnf_default;
2541
2603
  config3 = {
2542
2604
  certificateDir: "INVALID",
2543
2605
  forceCA: false,
2544
2606
  pkiDir: "INVALID"
2545
2607
  };
2546
- n4 = makePath;
2547
- q3 = quote;
2548
- assert9(octetStringToIpAddress("c07b9179") === "192.123.145.121");
2608
+ n5 = makePath;
2609
+ q4 = quote;
2610
+ assert10(octetStringToIpAddress("c07b9179") === "192.123.145.121");
2549
2611
  CertificateAuthority = class {
2550
2612
  /** RSA key size used when generating the CA private key. */
2551
2613
  keySize;
@@ -2553,12 +2615,15 @@ var init_certificate_authority = __esm({
2553
2615
  location;
2554
2616
  /** X.500 subject of the CA certificate. */
2555
2617
  subject;
2618
+ /** @internal Parent CA (undefined for root CAs). */
2619
+ _issuerCA;
2556
2620
  constructor(options) {
2557
- assert9(Object.prototype.hasOwnProperty.call(options, "location"));
2558
- assert9(Object.prototype.hasOwnProperty.call(options, "keySize"));
2621
+ assert10(Object.prototype.hasOwnProperty.call(options, "location"));
2622
+ assert10(Object.prototype.hasOwnProperty.call(options, "keySize"));
2559
2623
  this.location = options.location;
2560
2624
  this.keySize = options.keySize || 2048;
2561
2625
  this.subject = new Subject4(options.subject || defaultSubject);
2626
+ this._issuerCA = options.issuerCA;
2562
2627
  }
2563
2628
  /** Absolute path to the CA root directory (alias for {@link location}). */
2564
2629
  get rootDir() {
@@ -2572,6 +2637,18 @@ var init_certificate_authority = __esm({
2572
2637
  get caCertificate() {
2573
2638
  return makePath(this.rootDir, "./public/cacert.pem");
2574
2639
  }
2640
+ /**
2641
+ * Path to the issuer certificate chain (`public/issuer_chain.pem`).
2642
+ *
2643
+ * This file is created by {@link installCACertificate} when the
2644
+ * provided cert file contains additional issuer certificates
2645
+ * (e.g. intermediate + root). It is appended to signed certs
2646
+ * by {@link constructCertificateChain} to produce a full chain
2647
+ * per OPC UA Part 6 §6.2.6.
2648
+ */
2649
+ get issuerCertificateChain() {
2650
+ return makePath(this.rootDir, "./public/issuer_chain.pem");
2651
+ }
2575
2652
  /**
2576
2653
  * Path to the current Certificate Revocation List in DER format.
2577
2654
  * (`crl/revocation_list.der`)
@@ -2629,10 +2706,10 @@ var init_certificate_authority = __esm({
2629
2706
  */
2630
2707
  getCRLDER() {
2631
2708
  const crlPath = this.revocationListDER;
2632
- if (!fs9.existsSync(crlPath)) {
2709
+ if (!fs10.existsSync(crlPath)) {
2633
2710
  return Buffer.alloc(0);
2634
2711
  }
2635
- return fs9.readFileSync(crlPath);
2712
+ return fs10.readFileSync(crlPath);
2636
2713
  }
2637
2714
  /**
2638
2715
  * Return the current Certificate Revocation List as a
@@ -2642,10 +2719,10 @@ var init_certificate_authority = __esm({
2642
2719
  */
2643
2720
  getCRLPEM() {
2644
2721
  const crlPath = this.revocationList;
2645
- if (!fs9.existsSync(crlPath)) {
2722
+ if (!fs10.existsSync(crlPath)) {
2646
2723
  return "";
2647
2724
  }
2648
- const raw = fs9.readFileSync(crlPath, "utf-8");
2725
+ const raw = fs10.readFileSync(crlPath, "utf-8");
2649
2726
  const beginMarker = "-----BEGIN X509 CRL-----";
2650
2727
  const idx = raw.indexOf(beginMarker);
2651
2728
  if (idx > 0) {
@@ -2698,7 +2775,7 @@ var init_certificate_authority = __esm({
2698
2775
  getCertificateBySerial(serial) {
2699
2776
  const upper = serial.toUpperCase();
2700
2777
  const certFile = path6.join(this.rootDir, "certs", `${upper}.pem`);
2701
- if (!fs9.existsSync(certFile)) {
2778
+ if (!fs10.existsSync(certFile)) {
2702
2779
  return void 0;
2703
2780
  }
2704
2781
  const pem = readCertificatePEM(certFile);
@@ -2727,10 +2804,10 @@ var init_certificate_authority = __esm({
2727
2804
  */
2728
2805
  _parseIndexTxt() {
2729
2806
  const indexPath = this.indexFile;
2730
- if (!fs9.existsSync(indexPath)) {
2807
+ if (!fs10.existsSync(indexPath)) {
2731
2808
  return [];
2732
2809
  }
2733
- const content = fs9.readFileSync(indexPath, "utf-8");
2810
+ const content = fs10.readFileSync(indexPath, "utf-8");
2734
2811
  const lines = content.split("\n").filter((l) => l.trim().length > 0);
2735
2812
  const records = [];
2736
2813
  for (const line of lines) {
@@ -2784,25 +2861,145 @@ var init_certificate_authority = __esm({
2784
2861
  * internally so that callers can work with in-memory
2785
2862
  * buffers only.
2786
2863
  *
2864
+ * The CA can override fields from the CSR by passing
2865
+ * `options.dns`, `options.ip`, `options.applicationUri`,
2866
+ * `options.startDate`, or `options.subject`.
2867
+ *
2787
2868
  * @param csrDer - the CSR as a DER-encoded buffer
2788
- * @param options - signing options
2789
- * @param options.validity - certificate validity in days
2790
- * (default: 365)
2869
+ * @param options - signing options and CA overrides
2791
2870
  * @returns the signed certificate as a DER-encoded buffer
2792
2871
  */
2793
2872
  async signCertificateRequestFromDER(csrDer, options) {
2794
2873
  const validity = options?.validity ?? 365;
2795
- const tmpDir = await fs9.promises.mkdtemp(path6.join(os4.tmpdir(), "pki-sign-"));
2874
+ const tmpDir = await fs10.promises.mkdtemp(path6.join(os4.tmpdir(), "pki-sign-"));
2796
2875
  try {
2797
2876
  const csrFile = path6.join(tmpDir, "request.csr");
2798
2877
  const certFile = path6.join(tmpDir, "certificate.pem");
2799
2878
  const csrPem = toPem2(csrDer, "CERTIFICATE REQUEST");
2800
- await fs9.promises.writeFile(csrFile, csrPem, "utf-8");
2801
- await this.signCertificateRequest(certFile, csrFile, { validity });
2879
+ await fs10.promises.writeFile(csrFile, csrPem, "utf-8");
2880
+ const signingParams = { validity };
2881
+ if (options?.startDate) signingParams.startDate = options.startDate;
2882
+ if (options?.dns) signingParams.dns = options.dns;
2883
+ if (options?.ip) signingParams.ip = options.ip;
2884
+ if (options?.applicationUri) signingParams.applicationUri = options.applicationUri;
2885
+ if (options?.subject) signingParams.subject = options.subject;
2886
+ await this.signCertificateRequest(certFile, csrFile, signingParams);
2802
2887
  const certPem = readCertificatePEM(certFile);
2803
2888
  return convertPEMtoDER(certPem);
2804
2889
  } finally {
2805
- await fs9.promises.rm(tmpDir, {
2890
+ await fs10.promises.rm(tmpDir, {
2891
+ recursive: true,
2892
+ force: true
2893
+ });
2894
+ }
2895
+ }
2896
+ /**
2897
+ * Generate a new RSA key pair, create an internal CSR, sign it
2898
+ * with this CA, and return both the certificate and private key
2899
+ * as DER-encoded buffers.
2900
+ *
2901
+ * The private key is **never stored** by the CA — it exists only
2902
+ * in a temporary directory that is cleaned up after the operation.
2903
+ *
2904
+ * This is used by `StartNewKeyPairRequest` (OPC UA Part 12) for
2905
+ * constrained devices that cannot generate their own keys.
2906
+ *
2907
+ * @param options - key generation and certificate parameters
2908
+ * @returns `{ certificateDer, privateKey }` — certificate as DER,
2909
+ * private key as a branded `PrivateKey` buffer
2910
+ */
2911
+ async generateKeyPairAndSignDER(options) {
2912
+ const keySize = options.keySize ?? 2048;
2913
+ const validity = options.validity ?? 365;
2914
+ const startDate = options.startDate ?? /* @__PURE__ */ new Date();
2915
+ const tmpDir = await fs10.promises.mkdtemp(path6.join(os4.tmpdir(), "pki-keygen-"));
2916
+ try {
2917
+ const privateKeyFile = path6.join(tmpDir, "private_key.pem");
2918
+ await generatePrivateKeyFile2(privateKeyFile, keySize);
2919
+ const configFile = path6.join(tmpDir, "openssl.cnf");
2920
+ await fs10.promises.writeFile(configFile, configurationFileSimpleTemplate2, "utf-8");
2921
+ const csrFile = path6.join(tmpDir, "request.csr");
2922
+ await createCertificateSigningRequestWithOpenSSL(csrFile, {
2923
+ rootDir: tmpDir,
2924
+ configFile,
2925
+ privateKey: privateKeyFile,
2926
+ applicationUri: options.applicationUri,
2927
+ subject: options.subject,
2928
+ dns: options.dns ?? [],
2929
+ ip: options.ip ?? [],
2930
+ purpose: CertificatePurpose2.ForApplication
2931
+ });
2932
+ const certFile = path6.join(tmpDir, "certificate.pem");
2933
+ await this.signCertificateRequest(certFile, csrFile, {
2934
+ applicationUri: options.applicationUri,
2935
+ dns: options.dns,
2936
+ ip: options.ip,
2937
+ startDate,
2938
+ validity
2939
+ });
2940
+ const certPem = readCertificatePEM(certFile);
2941
+ const certificateDer = convertPEMtoDER(certPem);
2942
+ const privateKey = readPrivateKey(privateKeyFile);
2943
+ return { certificateDer, privateKey };
2944
+ } finally {
2945
+ await fs10.promises.rm(tmpDir, {
2946
+ recursive: true,
2947
+ force: true
2948
+ });
2949
+ }
2950
+ }
2951
+ /**
2952
+ * Generate a new RSA key pair, create an internal CSR, sign it
2953
+ * with this CA, and return the result as a PKCS#12 (PFX)
2954
+ * buffer bundling the certificate, private key, and CA chain.
2955
+ *
2956
+ * The private key is **never stored** by the CA — it exists only
2957
+ * in a temporary directory that is cleaned up after the operation.
2958
+ *
2959
+ * @param options - key generation, certificate, and PFX options
2960
+ * @returns the PFX as a `Buffer`
2961
+ */
2962
+ async generateKeyPairAndSignPFX(options) {
2963
+ const keySize = options.keySize ?? 2048;
2964
+ const validity = options.validity ?? 365;
2965
+ const startDate = options.startDate ?? /* @__PURE__ */ new Date();
2966
+ const passphrase = options.passphrase ?? "";
2967
+ const tmpDir = await fs10.promises.mkdtemp(path6.join(os4.tmpdir(), "pki-keygen-pfx-"));
2968
+ try {
2969
+ const privateKeyFile = path6.join(tmpDir, "private_key.pem");
2970
+ await generatePrivateKeyFile2(privateKeyFile, keySize);
2971
+ const configFile = path6.join(tmpDir, "openssl.cnf");
2972
+ await fs10.promises.writeFile(configFile, configurationFileSimpleTemplate2, "utf-8");
2973
+ const csrFile = path6.join(tmpDir, "request.csr");
2974
+ await createCertificateSigningRequestWithOpenSSL(csrFile, {
2975
+ rootDir: tmpDir,
2976
+ configFile,
2977
+ privateKey: privateKeyFile,
2978
+ applicationUri: options.applicationUri,
2979
+ subject: options.subject,
2980
+ dns: options.dns ?? [],
2981
+ ip: options.ip ?? [],
2982
+ purpose: CertificatePurpose2.ForApplication
2983
+ });
2984
+ const certFile = path6.join(tmpDir, "certificate.pem");
2985
+ await this.signCertificateRequest(certFile, csrFile, {
2986
+ applicationUri: options.applicationUri,
2987
+ dns: options.dns,
2988
+ ip: options.ip,
2989
+ startDate,
2990
+ validity
2991
+ });
2992
+ const pfxFile = path6.join(tmpDir, "bundle.pfx");
2993
+ await createPFX({
2994
+ certificateFile: certFile,
2995
+ privateKeyFile,
2996
+ outputFile: pfxFile,
2997
+ passphrase,
2998
+ caCertificateFiles: [this.caCertificate]
2999
+ });
3000
+ return await fs10.promises.readFile(pfxFile);
3001
+ } finally {
3002
+ await fs10.promises.rm(tmpDir, {
2806
3003
  recursive: true,
2807
3004
  force: true
2808
3005
  });
@@ -2824,7 +3021,7 @@ var init_certificate_authority = __esm({
2824
3021
  const info = exploreCertificate2(certDer);
2825
3022
  const serial = info.tbsCertificate.serialNumber.replace(/:/g, "").toUpperCase();
2826
3023
  const storedCertFile = path6.join(this.rootDir, "certs", `${serial}.pem`);
2827
- if (!fs9.existsSync(storedCertFile)) {
3024
+ if (!fs10.existsSync(storedCertFile)) {
2828
3025
  throw new Error(`Cannot revoke: no stored certificate found for serial ${serial} at ${storedCertFile}`);
2829
3026
  }
2830
3027
  await this.revokeCertificate(storedCertFile, {
@@ -2839,6 +3036,204 @@ var init_certificate_authority = __esm({
2839
3036
  async initialize() {
2840
3037
  await construct_CertificateAuthority(this);
2841
3038
  }
3039
+ /**
3040
+ * Initialize the CA directory structure and generate the
3041
+ * private key + CSR **without signing**.
3042
+ *
3043
+ * Use this when the CA certificate will be signed by an
3044
+ * external (third-party) root CA. After receiving the signed
3045
+ * certificate, call {@link installCACertificate} to complete
3046
+ * the setup.
3047
+ *
3048
+ * **Idempotent / restart-safe:**
3049
+ * - If the CA certificate exists and is valid → `{ status: "ready" }`
3050
+ * - If the CA certificate has expired → `{ status: "expired", csrPath, expiryDate }`
3051
+ * (a new CSR is generated, preserving the existing private key)
3052
+ * - If key + CSR exist but no cert (restart before install) →
3053
+ * `{ status: "pending", csrPath }` without regenerating
3054
+ * - Otherwise → generates key + CSR → `{ status: "created", csrPath }`
3055
+ *
3056
+ * @returns an {@link InitializeCSRResult} describing the CA state
3057
+ */
3058
+ async initializeCSR() {
3059
+ const caRootDir = path6.resolve(this.rootDir);
3060
+ mkdirRecursiveSync(caRootDir);
3061
+ for (const dir of ["private", "public", "certs", "crl", "conf"]) {
3062
+ mkdirRecursiveSync(path6.join(caRootDir, dir));
3063
+ }
3064
+ const caCertFile = this.caCertificate;
3065
+ const privateKeyFile = path6.join(caRootDir, "private/cakey.pem");
3066
+ const csrFile = path6.join(caRootDir, "private/cakey.csr");
3067
+ if (fs10.existsSync(caCertFile)) {
3068
+ const certDer = convertPEMtoDER(readCertificatePEM(caCertFile));
3069
+ const certInfo = exploreCertificate2(certDer);
3070
+ const notAfter = certInfo.tbsCertificate.validity.notAfter;
3071
+ if (notAfter.getTime() < Date.now()) {
3072
+ debugLog("CA certificate has expired \u2014 generating renewal CSR");
3073
+ await this._generateCSR(caRootDir, privateKeyFile, csrFile);
3074
+ return { status: "expired", csrPath: csrFile, expiryDate: notAfter };
3075
+ }
3076
+ debugLog("CA certificate already exists and is valid \u2014 ready");
3077
+ return { status: "ready" };
3078
+ }
3079
+ if (fs10.existsSync(privateKeyFile) && fs10.existsSync(csrFile)) {
3080
+ debugLog("CA key + CSR already exist \u2014 pending external signing");
3081
+ return { status: "pending", csrPath: csrFile };
3082
+ }
3083
+ const serial = path6.join(caRootDir, "serial");
3084
+ if (!fs10.existsSync(serial)) {
3085
+ await fs10.promises.writeFile(serial, "1000");
3086
+ }
3087
+ const crlNumber = path6.join(caRootDir, "crlnumber");
3088
+ if (!fs10.existsSync(crlNumber)) {
3089
+ await fs10.promises.writeFile(crlNumber, "1000");
3090
+ }
3091
+ const indexFile = path6.join(caRootDir, "index.txt");
3092
+ if (!fs10.existsSync(indexFile)) {
3093
+ await fs10.promises.writeFile(indexFile, "");
3094
+ }
3095
+ const indexFileAttr = path6.join(caRootDir, "index.txt.attr");
3096
+ if (!fs10.existsSync(indexFileAttr)) {
3097
+ await fs10.promises.writeFile(indexFileAttr, "unique_subject = no");
3098
+ }
3099
+ const caConfigFile = this.configFile;
3100
+ let data = configurationFileTemplate;
3101
+ data = makePath(data.replace(/%%ROOT_FOLDER%%/, caRootDir));
3102
+ await fs10.promises.writeFile(caConfigFile, data);
3103
+ if (!fs10.existsSync(privateKeyFile)) {
3104
+ await generatePrivateKeyFile2(privateKeyFile, this.keySize);
3105
+ }
3106
+ await this._generateCSR(caRootDir, privateKeyFile, csrFile);
3107
+ return { status: "created", csrPath: csrFile };
3108
+ }
3109
+ /**
3110
+ * Check whether the CA certificate needs renewal and, if so,
3111
+ * generate a new CSR for re-signing by the external root CA.
3112
+ *
3113
+ * Use this while the CA is running to detect upcoming expiry
3114
+ * **before** it actually expires. The existing private key is
3115
+ * preserved so previously issued certs remain valid.
3116
+ *
3117
+ * @param thresholdDays - number of days before expiry at which
3118
+ * to trigger renewal (default: 30)
3119
+ * @returns an {@link InitializeCSRResult} — `"expired"` if
3120
+ * renewal is needed, `"ready"` if the cert is still valid
3121
+ */
3122
+ async renewCSR(thresholdDays = 30) {
3123
+ const caRootDir = path6.resolve(this.rootDir);
3124
+ const caCertFile = this.caCertificate;
3125
+ const privateKeyFile = path6.join(caRootDir, "private/cakey.pem");
3126
+ const csrFile = path6.join(caRootDir, "private/cakey.csr");
3127
+ if (!fs10.existsSync(caCertFile)) {
3128
+ return this.initializeCSR();
3129
+ }
3130
+ const certDer = convertPEMtoDER(readCertificatePEM(caCertFile));
3131
+ const certInfo = exploreCertificate2(certDer);
3132
+ const notAfter = certInfo.tbsCertificate.validity.notAfter;
3133
+ const thresholdMs = thresholdDays * 24 * 60 * 60 * 1e3;
3134
+ if (notAfter.getTime() - Date.now() < thresholdMs) {
3135
+ debugLog(`CA certificate expires within ${thresholdDays} days \u2014 generating renewal CSR`);
3136
+ await this._generateCSR(caRootDir, privateKeyFile, csrFile);
3137
+ return { status: "expired", csrPath: csrFile, expiryDate: notAfter };
3138
+ }
3139
+ return { status: "ready" };
3140
+ }
3141
+ /**
3142
+ * Generate a CSR using the existing private key.
3143
+ * @internal
3144
+ */
3145
+ async _generateCSR(caRootDir, privateKeyFile, csrFile) {
3146
+ const subjectOpt = ` -subj "${this.subject.toString()}" `;
3147
+ processAltNames({});
3148
+ const options = { cwd: caRootDir };
3149
+ const configFile = generateStaticConfig("conf/caconfig.cnf", options);
3150
+ const configOption = ` -config ${q4(n5(configFile))}`;
3151
+ await execute_openssl(
3152
+ "req -new -sha256 -text -extensions v3_ca_req" + configOption + " -key " + q4(n5(privateKeyFile)) + " -out " + q4(n5(csrFile)) + " " + subjectOpt,
3153
+ options
3154
+ );
3155
+ }
3156
+ /**
3157
+ * Install an externally-signed CA certificate and generate
3158
+ * the initial CRL.
3159
+ *
3160
+ * Call this after {@link initializeCSR} once the external
3161
+ * root CA has signed the CSR.
3162
+ *
3163
+ * **Safety checks:**
3164
+ * - Verifies that the certificate's public key matches the
3165
+ * CA private key before installing.
3166
+ *
3167
+ * @param signedCertFile - path to the PEM-encoded signed
3168
+ * CA certificate (issued by the external root CA)
3169
+ * @returns an {@link InstallCACertificateResult} with
3170
+ * `status: "success"` or `status: "error"` and a `reason`
3171
+ */
3172
+ async installCACertificate(signedCertFile) {
3173
+ const caRootDir = path6.resolve(this.rootDir);
3174
+ const caCertFile = this.caCertificate;
3175
+ const privateKeyFile = path6.join(caRootDir, "private/cakey.pem");
3176
+ const fullPem = await fs10.promises.readFile(signedCertFile, "utf8");
3177
+ const pemBlocks = fullPem.match(/-----BEGIN CERTIFICATE-----[\s\S]*?-----END CERTIFICATE-----/g);
3178
+ if (!pemBlocks || pemBlocks.length === 0) {
3179
+ return {
3180
+ status: "error",
3181
+ reason: "no_certificate_found",
3182
+ message: "The provided file does not contain any PEM-encoded certificate."
3183
+ };
3184
+ }
3185
+ const certDer = convertPEMtoDER(pemBlocks[0]);
3186
+ const privateKey = readPrivateKey(privateKeyFile);
3187
+ if (!certificateMatchesPrivateKey(certDer, privateKey)) {
3188
+ return {
3189
+ status: "error",
3190
+ reason: "certificate_key_mismatch",
3191
+ message: "The provided certificate does not match the CA private key. Ensure the certificate was signed from the CSR generated by initializeCSR()."
3192
+ };
3193
+ }
3194
+ await fs10.promises.writeFile(caCertFile, `${pemBlocks[0]}
3195
+ `);
3196
+ const issuerChainFile = this.issuerCertificateChain;
3197
+ if (pemBlocks.length > 1) {
3198
+ const issuerPem = `${pemBlocks.slice(1).join("\n")}
3199
+ `;
3200
+ await fs10.promises.writeFile(issuerChainFile, issuerPem);
3201
+ debugLog(`Stored ${pemBlocks.length - 1} issuer certificate(s) in issuer_chain.pem`);
3202
+ } else {
3203
+ if (fs10.existsSync(issuerChainFile)) {
3204
+ await fs10.promises.unlink(issuerChainFile);
3205
+ }
3206
+ }
3207
+ const options = { cwd: caRootDir };
3208
+ const configFile = generateStaticConfig("conf/caconfig.cnf", options);
3209
+ const configOption = ` -config ${q4(n5(configFile))}`;
3210
+ await regenerateCrl(this.revocationList, configOption, options);
3211
+ return { status: "success" };
3212
+ }
3213
+ /**
3214
+ * Sign a CSR with CA extensions (`v3_ca`), producing a
3215
+ * subordinate CA certificate.
3216
+ *
3217
+ * Unlike {@link signCertificateRequest} which signs with
3218
+ * end-entity extensions (SANs, etc.), this method signs
3219
+ * with `basicConstraints = CA:TRUE` and `keyUsage =
3220
+ * keyCertSign, cRLSign`.
3221
+ *
3222
+ * @param certFile - output path for the signed CA cert (PEM)
3223
+ * @param csrFile - path to the subordinate CA's CSR
3224
+ * @param params - signing parameters
3225
+ */
3226
+ async signCACertificateRequest(certFile, csrFile, params) {
3227
+ const caRootDir = path6.resolve(this.rootDir);
3228
+ const options = { cwd: caRootDir };
3229
+ const configFile = generateStaticConfig("conf/caconfig.cnf", options);
3230
+ const validity = params.validity ?? 3650;
3231
+ await execute_openssl(
3232
+ ` x509 -sha256 -req -days ${validity} -text -extensions v3_ca -extfile ` + q4(n5(configFile)) + " -in " + q4(n5(csrFile)) + " -CA " + q4(n5(this.caCertificate)) + " -CAkey " + q4(n5(path6.join(caRootDir, "private/cakey.pem"))) + " -CAserial " + q4(n5(path6.join(caRootDir, "serial"))) + " -out " + q4(n5(certFile)),
3233
+ options
3234
+ );
3235
+ await this.constructCertificateChain(certFile);
3236
+ }
2842
3237
  /**
2843
3238
  * Rebuild the combined CA certificate + CRL file.
2844
3239
  *
@@ -2848,13 +3243,13 @@ var init_certificate_authority = __esm({
2848
3243
  */
2849
3244
  async constructCACertificateWithCRL() {
2850
3245
  const cacertWithCRL = this.caCertificateWithCrl;
2851
- if (fs9.existsSync(this.revocationList)) {
2852
- await fs9.promises.writeFile(
3246
+ if (fs10.existsSync(this.revocationList)) {
3247
+ await fs10.promises.writeFile(
2853
3248
  cacertWithCRL,
2854
- fs9.readFileSync(this.caCertificate, "utf8") + fs9.readFileSync(this.revocationList, "utf8")
3249
+ fs10.readFileSync(this.caCertificate, "utf8") + fs10.readFileSync(this.revocationList, "utf8")
2855
3250
  );
2856
3251
  } else {
2857
- await fs9.promises.writeFile(cacertWithCRL, fs9.readFileSync(this.caCertificate));
3252
+ await fs10.promises.writeFile(cacertWithCRL, fs10.readFileSync(this.caCertificate));
2858
3253
  }
2859
3254
  }
2860
3255
  /**
@@ -2864,14 +3259,15 @@ var init_certificate_authority = __esm({
2864
3259
  * @param certificate - path to the certificate file to extend
2865
3260
  */
2866
3261
  async constructCertificateChain(certificate) {
2867
- assert9(fs9.existsSync(certificate));
2868
- assert9(fs9.existsSync(this.caCertificate));
3262
+ assert10(fs10.existsSync(certificate));
3263
+ assert10(fs10.existsSync(this.caCertificate));
2869
3264
  debugLog(chalk6.yellow(" certificate file :"), chalk6.cyan(certificate));
2870
- await fs9.promises.writeFile(
2871
- certificate,
2872
- await fs9.promises.readFile(certificate, "utf8") + await fs9.promises.readFile(this.caCertificate, "utf8")
2873
- // + fs.readFileSync(this.revocationList)
2874
- );
3265
+ let chain = await fs10.promises.readFile(certificate, "utf8");
3266
+ chain += await fs10.promises.readFile(this.caCertificate, "utf8");
3267
+ if (fs10.existsSync(this.issuerCertificateChain)) {
3268
+ chain += await fs10.promises.readFile(this.issuerCertificateChain, "utf8");
3269
+ }
3270
+ await fs10.promises.writeFile(certificate, chain);
2875
3271
  }
2876
3272
  /**
2877
3273
  * Create a self-signed certificate using OpenSSL.
@@ -2881,8 +3277,8 @@ var init_certificate_authority = __esm({
2881
3277
  * @param params - certificate parameters (subject, validity, SANs)
2882
3278
  */
2883
3279
  async createSelfSignedCertificate(certificateFile, privateKey, params) {
2884
- assert9(typeof privateKey === "string");
2885
- assert9(fs9.existsSync(privateKey));
3280
+ assert10(typeof privateKey === "string");
3281
+ assert10(fs10.existsSync(privateKey));
2886
3282
  if (!certificateFileExist(certificateFile)) {
2887
3283
  return;
2888
3284
  }
@@ -2890,7 +3286,7 @@ var init_certificate_authority = __esm({
2890
3286
  adjustApplicationUri(params);
2891
3287
  processAltNames(params);
2892
3288
  const csrFile = `${certificateFile}_csr`;
2893
- assert9(csrFile);
3289
+ assert10(csrFile);
2894
3290
  const configFile = generateStaticConfig(this.configFile, { cwd: this.rootDir });
2895
3291
  const options = {
2896
3292
  cwd: this.rootDir,
@@ -2901,19 +3297,19 @@ var init_certificate_authority = __esm({
2901
3297
  const subjectOptions = subject && subject.length > 1 ? ` -subj ${subject} ` : "";
2902
3298
  displaySubtitle("- the certificate signing request");
2903
3299
  await execute_openssl(
2904
- "req -new -sha256 -text " + configOption + subjectOptions + " -batch -key " + q3(n4(privateKey)) + " -out " + q3(n4(csrFile)),
3300
+ "req -new -sha256 -text " + configOption + subjectOptions + " -batch -key " + q4(n5(privateKey)) + " -out " + q4(n5(csrFile)),
2905
3301
  options
2906
3302
  );
2907
3303
  displaySubtitle("- creating the self-signed certificate");
2908
3304
  await execute_openssl(
2909
- "ca -selfsign -keyfile " + q3(n4(privateKey)) + " -startdate " + x509Date(params.startDate) + " -enddate " + x509Date(params.endDate) + " -batch -out " + q3(n4(certificateFile)) + " -in " + q3(n4(csrFile)),
3305
+ "ca -selfsign -keyfile " + q4(n5(privateKey)) + " -startdate " + x509Date(params.startDate) + " -enddate " + x509Date(params.endDate) + " -batch -out " + q4(n5(certificateFile)) + " -in " + q4(n5(csrFile)),
2910
3306
  options
2911
3307
  );
2912
3308
  displaySubtitle("- dump the certificate for a check");
2913
- await execute_openssl(`x509 -in ${q3(n4(certificateFile))} -dates -fingerprint -purpose -noout`, {});
3309
+ await execute_openssl(`x509 -in ${q4(n5(certificateFile))} -dates -fingerprint -purpose -noout`, {});
2914
3310
  displaySubtitle("- verify self-signed certificate");
2915
- await execute_openssl_no_failure(`verify -verbose -CAfile ${q3(n4(certificateFile))} ${q3(n4(certificateFile))}`, options);
2916
- await fs9.promises.unlink(csrFile);
3311
+ await execute_openssl_no_failure(`verify -verbose -CAfile ${q4(n5(certificateFile))} ${q4(n5(certificateFile))}`, options);
3312
+ await fs10.promises.unlink(csrFile);
2917
3313
  }
2918
3314
  /**
2919
3315
  * Revoke a certificate and regenerate the CRL.
@@ -2942,22 +3338,22 @@ var init_certificate_authority = __esm({
2942
3338
  setEnv("ALTNAME", "");
2943
3339
  const randomFile = path6.join(this.rootDir, "random.rnd");
2944
3340
  setEnv("RANDFILE", randomFile);
2945
- const configOption = ` -config ${q3(n4(configFile))}`;
3341
+ const configOption = ` -config ${q4(n5(configFile))}`;
2946
3342
  const reason = params.reason || "keyCompromise";
2947
- assert9(crlReasons.indexOf(reason) >= 0);
3343
+ assert10(crlReasons.indexOf(reason) >= 0);
2948
3344
  displayTitle(`Revoking certificate ${certificate}`);
2949
3345
  displaySubtitle("Revoke certificate");
2950
- await execute_openssl_no_failure(`ca -verbose ${configOption} -revoke ${q3(certificate)} -crl_reason ${reason}`, options);
3346
+ await execute_openssl_no_failure(`ca -verbose ${configOption} -revoke ${q4(certificate)} -crl_reason ${reason}`, options);
2951
3347
  await regenerateCrl(this.revocationList, configOption, options);
2952
3348
  displaySubtitle("Verify that certificate is revoked");
2953
3349
  await execute_openssl_no_failure(
2954
- "verify -verbose -CRLfile " + q3(n4(this.revocationList)) + " -CAfile " + q3(n4(this.caCertificate)) + " -crl_check " + q3(n4(certificate)),
3350
+ "verify -verbose -CRLfile " + q4(n5(this.revocationList)) + " -CAfile " + q4(n5(this.caCertificate)) + " -crl_check " + q4(n5(certificate)),
2955
3351
  options
2956
3352
  );
2957
3353
  displaySubtitle("Produce CRL in DER form ");
2958
- await execute_openssl(`crl -in ${q3(n4(this.revocationList))} -out crl/revocation_list.der -outform der`, options);
3354
+ await execute_openssl(`crl -in ${q4(n5(this.revocationList))} -out crl/revocation_list.der -outform der`, options);
2959
3355
  displaySubtitle("Produce CRL in PEM form ");
2960
- await execute_openssl(`crl -in ${q3(n4(this.revocationList))} -out crl/revocation_list.pem -outform pem -text `, options);
3356
+ await execute_openssl(`crl -in ${q4(n5(this.revocationList))} -out crl/revocation_list.pem -outform pem -text `, options);
2961
3357
  }
2962
3358
  /**
2963
3359
  * Sign a Certificate Signing Request (CSR) with this CA.
@@ -2973,7 +3369,7 @@ var init_certificate_authority = __esm({
2973
3369
  */
2974
3370
  async signCertificateRequest(certificate, certificateSigningRequestFilename, params1) {
2975
3371
  await ensure_openssl_installed();
2976
- assert9(fs9.existsSync(certificateSigningRequestFilename));
3372
+ assert10(fs10.existsSync(certificateSigningRequestFilename));
2977
3373
  if (!certificateFileExist(certificate)) {
2978
3374
  return "";
2979
3375
  }
@@ -3000,11 +3396,11 @@ var init_certificate_authority = __esm({
3000
3396
  displaySubtitle("- then we ask the authority to sign the certificate signing request");
3001
3397
  const configOption = ` -config ${configFile}`;
3002
3398
  await execute_openssl(
3003
- "ca " + configOption + " -startdate " + x509Date(params1.startDate) + " -enddate " + x509Date(params1.endDate) + " -batch -out " + q3(n4(certificate)) + " -in " + q3(n4(certificateSigningRequestFilename)),
3399
+ "ca " + configOption + " -startdate " + x509Date(params1.startDate) + " -enddate " + x509Date(params1.endDate) + " -batch -out " + q4(n5(certificate)) + " -in " + q4(n5(certificateSigningRequestFilename)),
3004
3400
  options
3005
3401
  );
3006
3402
  displaySubtitle("- dump the certificate for a check");
3007
- await execute_openssl(`x509 -in ${q3(n4(certificate))} -dates -fingerprint -purpose -noout`, options);
3403
+ await execute_openssl(`x509 -in ${q4(n5(certificate))} -dates -fingerprint -purpose -noout`, options);
3008
3404
  displaySubtitle("- construct CA certificate with CRL");
3009
3405
  await this.constructCACertificateWithCRL();
3010
3406
  displaySubtitle("- construct certificate chain");
@@ -3027,7 +3423,7 @@ var init_certificate_authority = __esm({
3027
3423
  const _configOption = ` -config ${configFile}`;
3028
3424
  _configOption;
3029
3425
  await execute_openssl_no_failure(
3030
- `verify -verbose -CAfile ${q3(n4(this.caCertificateWithCrl))} ${q3(n4(certificate))}`,
3426
+ `verify -verbose -CAfile ${q4(n5(this.caCertificateWithCrl))} ${q4(n5(certificate))}`,
3031
3427
  options
3032
3428
  );
3033
3429
  }
@@ -3037,13 +3433,13 @@ var init_certificate_authority = __esm({
3037
3433
  });
3038
3434
 
3039
3435
  // packages/node-opcua-pki/lib/ca/crypto_create_CA.ts
3040
- import assert10 from "assert";
3041
- import fs10 from "fs";
3436
+ import assert11 from "assert";
3437
+ import fs11 from "fs";
3042
3438
  import { createRequire } from "module";
3043
3439
  import os5 from "os";
3044
3440
  import path7 from "path";
3045
3441
  import chalk7 from "chalk";
3046
- import { CertificatePurpose as CertificatePurpose2, generatePrivateKeyFile as generatePrivateKeyFile3, Subject as Subject5 } from "node-opcua-crypto";
3442
+ import { CertificatePurpose as CertificatePurpose3, generatePrivateKeyFile as generatePrivateKeyFile3, Subject as Subject5 } from "node-opcua-crypto";
3047
3443
  import commandLineArgs from "command-line-args";
3048
3444
  import commandLineUsage from "command-line-usage";
3049
3445
  function get_offset_date(date, nbDays) {
@@ -3052,8 +3448,8 @@ function get_offset_date(date, nbDays) {
3052
3448
  return d;
3053
3449
  }
3054
3450
  async function construct_CertificateAuthority2(subject) {
3055
- assert10(typeof gLocalConfig.CAFolder === "string", "expecting a CAFolder in config");
3056
- assert10(typeof gLocalConfig.keySize === "number", "expecting a keySize in config");
3451
+ assert11(typeof gLocalConfig.CAFolder === "string", "expecting a CAFolder in config");
3452
+ assert11(typeof gLocalConfig.keySize === "number", "expecting a keySize in config");
3057
3453
  if (!g_certificateAuthority) {
3058
3454
  g_certificateAuthority = new CertificateAuthority({
3059
3455
  keySize: gLocalConfig.keySize,
@@ -3064,7 +3460,7 @@ async function construct_CertificateAuthority2(subject) {
3064
3460
  }
3065
3461
  }
3066
3462
  async function construct_CertificateManager() {
3067
- assert10(typeof gLocalConfig.PKIFolder === "string", "expecting a PKIFolder in config");
3463
+ assert11(typeof gLocalConfig.PKIFolder === "string", "expecting a PKIFolder in config");
3068
3464
  if (!certificateManager) {
3069
3465
  certificateManager = new CertificateManager({
3070
3466
  keySize: gLocalConfig.keySize,
@@ -3075,35 +3471,35 @@ async function construct_CertificateManager() {
3075
3471
  }
3076
3472
  function default_template_content() {
3077
3473
  if (process.pkg?.entrypoint) {
3078
- const a = fs10.readFileSync(path7.join(__dirname, "../../bin/pki_config.example.js"), "utf8");
3474
+ const a = fs11.readFileSync(path7.join(__dirname, "../../bin/pki_config.example.js"), "utf8");
3079
3475
  return a;
3080
3476
  }
3081
3477
  function find_default_config_template() {
3082
3478
  const rootFolder = find_module_root_folder();
3083
3479
  const configName = "pki_config.example.js";
3084
3480
  let default_config_template2 = path7.join(rootFolder, "bin", configName);
3085
- if (!fs10.existsSync(default_config_template2)) {
3481
+ if (!fs11.existsSync(default_config_template2)) {
3086
3482
  default_config_template2 = path7.join(__dirname, "..", configName);
3087
- if (!fs10.existsSync(default_config_template2)) {
3483
+ if (!fs11.existsSync(default_config_template2)) {
3088
3484
  default_config_template2 = path7.join(__dirname, `../bin/${configName}`);
3089
3485
  }
3090
3486
  }
3091
3487
  return default_config_template2;
3092
3488
  }
3093
3489
  const default_config_template = find_default_config_template();
3094
- assert10(fs10.existsSync(default_config_template));
3095
- const default_config_template_content = fs10.readFileSync(default_config_template, "utf8");
3490
+ assert11(fs11.existsSync(default_config_template));
3491
+ const default_config_template_content = fs11.readFileSync(default_config_template, "utf8");
3096
3492
  return default_config_template_content;
3097
3493
  }
3098
3494
  function find_module_root_folder() {
3099
3495
  let rootFolder = path7.join(__dirname);
3100
3496
  for (let i = 0; i < 4; i++) {
3101
- if (fs10.existsSync(path7.join(rootFolder, "package.json"))) {
3497
+ if (fs11.existsSync(path7.join(rootFolder, "package.json"))) {
3102
3498
  return rootFolder;
3103
3499
  }
3104
3500
  rootFolder = path7.join(rootFolder, "..");
3105
3501
  }
3106
- assert10(fs10.existsSync(path7.join(rootFolder, "package.json")), "root folder must have a package.json file");
3502
+ assert11(fs11.existsSync(path7.join(rootFolder, "package.json")), "root folder must have a package.json file");
3107
3503
  return rootFolder;
3108
3504
  }
3109
3505
  async function readConfiguration(argv) {
@@ -3132,19 +3528,19 @@ async function readConfiguration(argv) {
3132
3528
  return makePath(tmp);
3133
3529
  }
3134
3530
  certificateDir = argv.root;
3135
- assert10(typeof certificateDir === "string");
3531
+ assert11(typeof certificateDir === "string");
3136
3532
  certificateDir = prepare(certificateDir);
3137
3533
  mkdirRecursiveSync(certificateDir);
3138
- assert10(fs10.existsSync(certificateDir));
3534
+ assert11(fs11.existsSync(certificateDir));
3139
3535
  const default_config = path7.join(certificateDir, "config.js");
3140
- if (!fs10.existsSync(default_config)) {
3536
+ if (!fs11.existsSync(default_config)) {
3141
3537
  debugLog(chalk7.yellow(" Creating default g_config file "), chalk7.cyan(default_config));
3142
3538
  const default_config_template_content = default_template_content();
3143
- fs10.writeFileSync(default_config, default_config_template_content);
3539
+ fs11.writeFileSync(default_config, default_config_template_content);
3144
3540
  } else {
3145
3541
  debugLog(chalk7.yellow(" using g_config file "), chalk7.cyan(default_config));
3146
3542
  }
3147
- if (!fs10.existsSync(default_config)) {
3543
+ if (!fs11.existsSync(default_config)) {
3148
3544
  debugLog(chalk7.redBright(" cannot find config file ", default_config));
3149
3545
  }
3150
3546
  const defaultRandomFile = path7.join(path7.dirname(default_config), "random.rnd");
@@ -3200,7 +3596,7 @@ async function readConfiguration(argv) {
3200
3596
  }
3201
3597
  }
3202
3598
  async function createDefaultCertificate(base_name, prefix, key_length, applicationUri, dev) {
3203
- assert10(key_length === 1024 || key_length === 2048 || key_length === 3072 || key_length === 4096);
3599
+ assert11(key_length === 1024 || key_length === 2048 || key_length === 3072 || key_length === 4096);
3204
3600
  const private_key_file = makePath(base_name, `${prefix}key_${key_length}.pem`);
3205
3601
  const public_key_file = makePath(base_name, `${prefix}public_key_${key_length}.pub`);
3206
3602
  const certificate_file = makePath(base_name, `${prefix}cert_${key_length}.pem`);
@@ -3220,7 +3616,7 @@ async function createDefaultCertificate(base_name, prefix, key_length, applicati
3220
3616
  }
3221
3617
  const ip = [];
3222
3618
  async function createCertificateIfNotExist(certificate, private_key, applicationUri2, startDate, validity) {
3223
- if (fs10.existsSync(certificate)) {
3619
+ if (fs11.existsSync(certificate)) {
3224
3620
  warningLog(chalk7.yellow(" certificate"), chalk7.cyan(certificate), chalk7.yellow(" already exists => skipping"));
3225
3621
  return "";
3226
3622
  } else {
@@ -3239,7 +3635,7 @@ async function createDefaultCertificate(base_name, prefix, key_length, applicati
3239
3635
  configFile,
3240
3636
  dns: dns3,
3241
3637
  ip: ip2,
3242
- purpose: CertificatePurpose2.ForApplication
3638
+ purpose: CertificatePurpose3.ForApplication
3243
3639
  };
3244
3640
  await createCertificateSigningRequestWithOpenSSL(certificateSigningRequestFile, params);
3245
3641
  return await g_certificateAuthority.signCertificateRequest(certificate, certificateSigningRequestFile, {
@@ -3263,7 +3659,7 @@ async function createDefaultCertificate(base_name, prefix, key_length, applicati
3263
3659
  await g_certificateAuthority.revokeCertificate(certificate, {});
3264
3660
  }
3265
3661
  async function createPrivateKeyIfNotExist(privateKey, keyLength) {
3266
- if (fs10.existsSync(privateKey)) {
3662
+ if (fs11.existsSync(privateKey)) {
3267
3663
  warningLog(chalk7.yellow(" privateKey"), chalk7.cyan(privateKey), chalk7.yellow(" already exists => skipping"));
3268
3664
  return;
3269
3665
  } else {
@@ -3277,14 +3673,14 @@ async function createDefaultCertificate(base_name, prefix, key_length, applicati
3277
3673
  displaySubtitle(` create Certificate ${certificate_file}`);
3278
3674
  await createCertificateIfNotExist(certificate_file, private_key_file, applicationUri, yesterday, 365);
3279
3675
  displaySubtitle(` create self signed Certificate ${self_signed_certificate_file}`);
3280
- if (fs10.existsSync(self_signed_certificate_file)) {
3676
+ if (fs11.existsSync(self_signed_certificate_file)) {
3281
3677
  return;
3282
3678
  }
3283
3679
  await createSelfSignedCertificate2(self_signed_certificate_file, private_key_file, applicationUri, yesterday, 365);
3284
3680
  if (dev) {
3285
3681
  await createCertificateIfNotExist(certificate_file_outofdate, private_key_file, applicationUri, two_years_ago, 365);
3286
3682
  await createCertificateIfNotExist(certificate_file_not_active_yet, private_key_file, applicationUri, next_year, 365);
3287
- if (!fs10.existsSync(certificate_revoked)) {
3683
+ if (!fs11.existsSync(certificate_revoked)) {
3288
3684
  const certificate = await createCertificateIfNotExist(
3289
3685
  certificate_revoked,
3290
3686
  private_key_file,
@@ -3306,9 +3702,9 @@ async function wrap(func) {
3306
3702
  }
3307
3703
  }
3308
3704
  async function create_default_certificates(dev) {
3309
- assert10(gLocalConfig);
3705
+ assert11(gLocalConfig);
3310
3706
  const base_name = gLocalConfig.certificateDir || "";
3311
- assert10(fs10.existsSync(base_name));
3707
+ assert11(fs11.existsSync(base_name));
3312
3708
  let clientURN;
3313
3709
  let serverURN;
3314
3710
  let discoveryServerURN;
@@ -3405,7 +3801,7 @@ ${epilog}`
3405
3801
  }
3406
3802
  if (command === "version") {
3407
3803
  const rootFolder = find_module_root_folder();
3408
- const pkg = JSON.parse(fs10.readFileSync(path7.join(rootFolder, "package.json"), "utf-8"));
3804
+ const pkg = JSON.parse(fs11.readFileSync(path7.join(rootFolder, "package.json"), "utf-8"));
3409
3805
  console.log(pkg.version);
3410
3806
  return;
3411
3807
  }
@@ -3430,12 +3826,12 @@ ${epilog}`
3430
3826
  await readConfiguration(local_argv);
3431
3827
  if (local_argv.clean) {
3432
3828
  displayTitle("Cleaning old certificates");
3433
- assert10(gLocalConfig);
3829
+ assert11(gLocalConfig);
3434
3830
  const certificateDir = gLocalConfig.certificateDir || "";
3435
- const files = await fs10.promises.readdir(certificateDir);
3831
+ const files = await fs11.promises.readdir(certificateDir);
3436
3832
  for (const file of files) {
3437
3833
  if (file.includes(".pem") || file.includes(".pub")) {
3438
- await fs10.promises.unlink(path7.join(certificateDir, file));
3834
+ await fs11.promises.unlink(path7.join(certificateDir, file));
3439
3835
  }
3440
3836
  }
3441
3837
  mkdirRecursiveSync(certificateDir);
@@ -3542,7 +3938,7 @@ ${epilog}`
3542
3938
  await readConfiguration(local_argv2);
3543
3939
  await construct_CertificateManager();
3544
3940
  await construct_CertificateAuthority2("");
3545
- assert10(fs10.existsSync(gLocalConfig.CAFolder || ""), " CA folder must exist");
3941
+ assert11(fs11.existsSync(gLocalConfig.CAFolder || ""), " CA folder must exist");
3546
3942
  gLocalConfig.privateKey = void 0;
3547
3943
  gLocalConfig.subject = local_argv2.subject && local_argv2.subject.length > 1 ? local_argv2.subject : gLocalConfig.subject;
3548
3944
  const csr_file = await certificateManager.createCertificateRequest(
@@ -3553,7 +3949,7 @@ ${epilog}`
3553
3949
  }
3554
3950
  warningLog(" csr_file = ", csr_file);
3555
3951
  const certificate = csr_file.replace(".csr", ".pem");
3556
- if (fs10.existsSync(certificate)) {
3952
+ if (fs11.existsSync(certificate)) {
3557
3953
  throw new Error(` File ${certificate} already exist`);
3558
3954
  }
3559
3955
  await g_certificateAuthority.signCertificateRequest(
@@ -3561,8 +3957,8 @@ ${epilog}`
3561
3957
  csr_file,
3562
3958
  gLocalConfig
3563
3959
  );
3564
- assert10(typeof gLocalConfig.outputFile === "string");
3565
- fs10.writeFileSync(gLocalConfig.outputFile || "", fs10.readFileSync(certificate, "ascii"));
3960
+ assert11(typeof gLocalConfig.outputFile === "string");
3961
+ fs11.writeFileSync(gLocalConfig.outputFile || "", fs11.readFileSync(certificate, "ascii"));
3566
3962
  }
3567
3963
  await wrap(async () => await command_certificate(local_argv));
3568
3964
  return;
@@ -3583,7 +3979,7 @@ ${epilog}`
3583
3979
  await wrap(async () => {
3584
3980
  const certificate = path7.resolve(local_argv.certificateFile);
3585
3981
  warningLog(chalk7.yellow(" Certificate to revoke : "), chalk7.cyan(certificate));
3586
- if (!fs10.existsSync(certificate)) {
3982
+ if (!fs11.existsSync(certificate)) {
3587
3983
  throw new Error(`cannot find certificate to revoke ${certificate}`);
3588
3984
  }
3589
3985
  await readConfiguration(local_argv);
@@ -3630,11 +4026,11 @@ ${epilog}`
3630
4026
  if (local_argv.help) return showHelp("csr", "create a certificate signing request", optionsDef);
3631
4027
  await wrap(async () => {
3632
4028
  await readConfiguration(local_argv);
3633
- if (!fs10.existsSync(gLocalConfig.PKIFolder || "")) {
4029
+ if (!fs11.existsSync(gLocalConfig.PKIFolder || "")) {
3634
4030
  warningLog("PKI folder must exist");
3635
4031
  }
3636
4032
  await construct_CertificateManager();
3637
- if (!gLocalConfig.outputFile || fs10.existsSync(gLocalConfig.outputFile)) {
4033
+ if (!gLocalConfig.outputFile || fs11.existsSync(gLocalConfig.outputFile)) {
3638
4034
  throw new Error(` File ${gLocalConfig.outputFile} already exist`);
3639
4035
  }
3640
4036
  gLocalConfig.privateKey = void 0;
@@ -3649,8 +4045,8 @@ ${epilog}`
3649
4045
  warningLog("please specify a output file");
3650
4046
  return;
3651
4047
  }
3652
- const csr = await fs10.promises.readFile(internal_csr_file, "utf-8");
3653
- fs10.writeFileSync(gLocalConfig.outputFile || "", csr, "utf-8");
4048
+ const csr = await fs11.promises.readFile(internal_csr_file, "utf-8");
4049
+ fs11.writeFileSync(gLocalConfig.outputFile || "", csr, "utf-8");
3654
4050
  warningLog("Subject = ", gLocalConfig.subject);
3655
4051
  warningLog("applicationUri = ", gLocalConfig.applicationUri);
3656
4052
  warningLog("altNames = ", gLocalConfig.altNames);
@@ -3678,16 +4074,16 @@ ${epilog}`
3678
4074
  return showHelp("sign", "validate a certificate signing request and generate a certificate", optionsDef);
3679
4075
  await wrap(async () => {
3680
4076
  await readConfiguration(local_argv);
3681
- if (!fs10.existsSync(gLocalConfig.CAFolder || "")) {
4077
+ if (!fs11.existsSync(gLocalConfig.CAFolder || "")) {
3682
4078
  throw new Error(`CA folder must exist:${gLocalConfig.CAFolder}`);
3683
4079
  }
3684
4080
  await construct_CertificateAuthority2("");
3685
4081
  const csr_file = path7.resolve(local_argv.csr || "");
3686
- if (!fs10.existsSync(csr_file)) {
4082
+ if (!fs11.existsSync(csr_file)) {
3687
4083
  throw new Error(`Certificate signing request doesn't exist: ${csr_file}`);
3688
4084
  }
3689
4085
  const certificate = path7.resolve(local_argv.output || csr_file.replace(".csr", ".pem"));
3690
- if (fs10.existsSync(certificate)) {
4086
+ if (fs11.existsSync(certificate)) {
3691
4087
  throw new Error(` File ${certificate} already exist`);
3692
4088
  }
3693
4089
  await g_certificateAuthority.signCertificateRequest(
@@ -3695,8 +4091,8 @@ ${epilog}`
3695
4091
  csr_file,
3696
4092
  gLocalConfig
3697
4093
  );
3698
- assert10(typeof gLocalConfig.outputFile === "string");
3699
- fs10.writeFileSync(gLocalConfig.outputFile || "", fs10.readFileSync(certificate, "ascii"));
4094
+ assert11(typeof gLocalConfig.outputFile === "string");
4095
+ fs11.writeFileSync(gLocalConfig.outputFile || "", fs11.readFileSync(certificate, "ascii"));
3700
4096
  });
3701
4097
  return;
3702
4098
  }