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/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,49 +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
- const caKeyExists = fs9.existsSync(path6.join(caRootDir, "private/cakey.pem"));
2474
- const caCertExists = fs9.existsSync(path6.join(caRootDir, "public/cacert.pem"));
2510
+ const caKeyExists = fs10.existsSync(path6.join(caRootDir, "private/cakey.pem"));
2511
+ const caCertExists = fs10.existsSync(path6.join(caRootDir, "public/cacert.pem"));
2475
2512
  if (caKeyExists && caCertExists && !config3.forceCA) {
2476
2513
  debugLog("CA private key and certificate already exist ... skipping");
2477
2514
  return;
2478
2515
  }
2479
2516
  if (caKeyExists && !caCertExists) {
2480
2517
  debugLog("CA private key exists but cacert.pem is missing \u2014 rebuilding CA");
2481
- fs9.unlinkSync(path6.join(caRootDir, "private/cakey.pem"));
2518
+ fs10.unlinkSync(path6.join(caRootDir, "private/cakey.pem"));
2482
2519
  const staleCsr = path6.join(caRootDir, "private/cakey.csr");
2483
- if (fs9.existsSync(staleCsr)) {
2484
- fs9.unlinkSync(staleCsr);
2520
+ if (fs10.existsSync(staleCsr)) {
2521
+ fs10.unlinkSync(staleCsr);
2485
2522
  }
2486
2523
  }
2487
2524
  displayTitle("Create Certificate Authority (CA)");
2488
2525
  const indexFileAttr = path6.join(caRootDir, "index.txt.attr");
2489
- if (!fs9.existsSync(indexFileAttr)) {
2490
- await fs9.promises.writeFile(indexFileAttr, "unique_subject = no");
2526
+ if (!fs10.existsSync(indexFileAttr)) {
2527
+ await fs10.promises.writeFile(indexFileAttr, "unique_subject = no");
2491
2528
  }
2492
2529
  const caConfigFile = certificateAuthority.configFile;
2493
2530
  if (1) {
2494
2531
  let data = configurationFileTemplate;
2495
2532
  data = makePath(data.replace(/%%ROOT_FOLDER%%/, caRootDir));
2496
- await fs9.promises.writeFile(caConfigFile, data);
2533
+ await fs10.promises.writeFile(caConfigFile, data);
2497
2534
  }
2498
2535
  const subjectOpt = ` -subj "${subject.toString()}" `;
2499
2536
  processAltNames({});
2500
2537
  const options = { cwd: caRootDir };
2501
2538
  const configFile = generateStaticConfig("conf/caconfig.cnf", options);
2502
- const configOption = ` -config ${q3(n4(configFile))}`;
2539
+ const configOption = ` -config ${q4(n5(configFile))}`;
2503
2540
  const keySize = certificateAuthority.keySize;
2504
2541
  const privateKeyFilename = path6.join(caRootDir, "private/cakey.pem");
2505
2542
  const csrFilename = path6.join(caRootDir, "private/cakey.csr");
@@ -2507,14 +2544,26 @@ async function construct_CertificateAuthority(certificateAuthority) {
2507
2544
  await generatePrivateKeyFile2(privateKeyFilename, keySize);
2508
2545
  displayTitle("Generate a certificate request for the CA key");
2509
2546
  await execute_openssl(
2510
- "req -new -sha256 -text -extensions v3_ca_req" + configOption + " -key " + q3(n4(privateKeyFilename)) + " -out " + q3(n4(csrFilename)) + " " + subjectOpt,
2511
- options
2512
- );
2513
- displayTitle("Generate CA Certificate (self-signed)");
2514
- await execute_openssl(
2515
- " 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,
2516
2548
  options
2517
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
+ }
2518
2567
  displaySubtitle("generate initial CRL (Certificate Revocation List)");
2519
2568
  await regenerateCrl(certificateAuthority.revocationList, configOption, options);
2520
2569
  displayTitle("Create Certificate Authority (CA) ---> DONE");
@@ -2524,7 +2573,7 @@ async function regenerateCrl(revocationList, configOption, options) {
2524
2573
  await execute_openssl(`ca -gencrl ${configOption} -out crl/revocation_list.crl`, options);
2525
2574
  await execute_openssl("crl -in crl/revocation_list.crl -out crl/revocation_list.der -outform der", options);
2526
2575
  displaySubtitle("Display (Certificate Revocation List)");
2527
- await execute_openssl(`crl -in ${q3(n4(revocationList))} -text -noout`, options);
2576
+ await execute_openssl(`crl -in ${q4(n5(revocationList))} -text -noout`, options);
2528
2577
  }
2529
2578
  function parseOpenSSLDate(dateStr) {
2530
2579
  const raw = dateStr?.split(",")[0] ?? "";
@@ -2538,24 +2587,27 @@ function parseOpenSSLDate(dateStr) {
2538
2587
  const sec = raw.substring(10, 12);
2539
2588
  return `${year}-${month}-${day}T${hour}:${min}:${sec}Z`;
2540
2589
  }
2541
- var defaultSubject, configurationFileTemplate, config3, n4, q3, CertificateAuthority;
2590
+ var defaultSubject, configurationFileTemplate, configurationFileSimpleTemplate2, config3, n5, q4, CertificateAuthority;
2542
2591
  var init_certificate_authority = __esm({
2543
2592
  "packages/node-opcua-pki/lib/ca/certificate_authority.ts"() {
2544
2593
  "use strict";
2545
2594
  init_esm_shims();
2595
+ init_toolbox_pfx();
2546
2596
  init_toolbox();
2547
2597
  init_with_openssl();
2598
+ init_simple_config_template_cnf();
2548
2599
  init_ca_config_template_cnf();
2549
2600
  defaultSubject = "/C=FR/ST=IDF/L=Paris/O=Local NODE-OPCUA Certificate Authority/CN=NodeOPCUA-CA";
2550
2601
  configurationFileTemplate = ca_config_template_cnf_default;
2602
+ configurationFileSimpleTemplate2 = simple_config_template_cnf_default;
2551
2603
  config3 = {
2552
2604
  certificateDir: "INVALID",
2553
2605
  forceCA: false,
2554
2606
  pkiDir: "INVALID"
2555
2607
  };
2556
- n4 = makePath;
2557
- q3 = quote;
2558
- assert9(octetStringToIpAddress("c07b9179") === "192.123.145.121");
2608
+ n5 = makePath;
2609
+ q4 = quote;
2610
+ assert10(octetStringToIpAddress("c07b9179") === "192.123.145.121");
2559
2611
  CertificateAuthority = class {
2560
2612
  /** RSA key size used when generating the CA private key. */
2561
2613
  keySize;
@@ -2563,12 +2615,15 @@ var init_certificate_authority = __esm({
2563
2615
  location;
2564
2616
  /** X.500 subject of the CA certificate. */
2565
2617
  subject;
2618
+ /** @internal Parent CA (undefined for root CAs). */
2619
+ _issuerCA;
2566
2620
  constructor(options) {
2567
- assert9(Object.prototype.hasOwnProperty.call(options, "location"));
2568
- assert9(Object.prototype.hasOwnProperty.call(options, "keySize"));
2621
+ assert10(Object.prototype.hasOwnProperty.call(options, "location"));
2622
+ assert10(Object.prototype.hasOwnProperty.call(options, "keySize"));
2569
2623
  this.location = options.location;
2570
2624
  this.keySize = options.keySize || 2048;
2571
2625
  this.subject = new Subject4(options.subject || defaultSubject);
2626
+ this._issuerCA = options.issuerCA;
2572
2627
  }
2573
2628
  /** Absolute path to the CA root directory (alias for {@link location}). */
2574
2629
  get rootDir() {
@@ -2582,6 +2637,18 @@ var init_certificate_authority = __esm({
2582
2637
  get caCertificate() {
2583
2638
  return makePath(this.rootDir, "./public/cacert.pem");
2584
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
+ }
2585
2652
  /**
2586
2653
  * Path to the current Certificate Revocation List in DER format.
2587
2654
  * (`crl/revocation_list.der`)
@@ -2639,10 +2706,10 @@ var init_certificate_authority = __esm({
2639
2706
  */
2640
2707
  getCRLDER() {
2641
2708
  const crlPath = this.revocationListDER;
2642
- if (!fs9.existsSync(crlPath)) {
2709
+ if (!fs10.existsSync(crlPath)) {
2643
2710
  return Buffer.alloc(0);
2644
2711
  }
2645
- return fs9.readFileSync(crlPath);
2712
+ return fs10.readFileSync(crlPath);
2646
2713
  }
2647
2714
  /**
2648
2715
  * Return the current Certificate Revocation List as a
@@ -2652,10 +2719,10 @@ var init_certificate_authority = __esm({
2652
2719
  */
2653
2720
  getCRLPEM() {
2654
2721
  const crlPath = this.revocationList;
2655
- if (!fs9.existsSync(crlPath)) {
2722
+ if (!fs10.existsSync(crlPath)) {
2656
2723
  return "";
2657
2724
  }
2658
- const raw = fs9.readFileSync(crlPath, "utf-8");
2725
+ const raw = fs10.readFileSync(crlPath, "utf-8");
2659
2726
  const beginMarker = "-----BEGIN X509 CRL-----";
2660
2727
  const idx = raw.indexOf(beginMarker);
2661
2728
  if (idx > 0) {
@@ -2708,7 +2775,7 @@ var init_certificate_authority = __esm({
2708
2775
  getCertificateBySerial(serial) {
2709
2776
  const upper = serial.toUpperCase();
2710
2777
  const certFile = path6.join(this.rootDir, "certs", `${upper}.pem`);
2711
- if (!fs9.existsSync(certFile)) {
2778
+ if (!fs10.existsSync(certFile)) {
2712
2779
  return void 0;
2713
2780
  }
2714
2781
  const pem = readCertificatePEM(certFile);
@@ -2737,10 +2804,10 @@ var init_certificate_authority = __esm({
2737
2804
  */
2738
2805
  _parseIndexTxt() {
2739
2806
  const indexPath = this.indexFile;
2740
- if (!fs9.existsSync(indexPath)) {
2807
+ if (!fs10.existsSync(indexPath)) {
2741
2808
  return [];
2742
2809
  }
2743
- const content = fs9.readFileSync(indexPath, "utf-8");
2810
+ const content = fs10.readFileSync(indexPath, "utf-8");
2744
2811
  const lines = content.split("\n").filter((l) => l.trim().length > 0);
2745
2812
  const records = [];
2746
2813
  for (const line of lines) {
@@ -2794,25 +2861,145 @@ var init_certificate_authority = __esm({
2794
2861
  * internally so that callers can work with in-memory
2795
2862
  * buffers only.
2796
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
+ *
2797
2868
  * @param csrDer - the CSR as a DER-encoded buffer
2798
- * @param options - signing options
2799
- * @param options.validity - certificate validity in days
2800
- * (default: 365)
2869
+ * @param options - signing options and CA overrides
2801
2870
  * @returns the signed certificate as a DER-encoded buffer
2802
2871
  */
2803
2872
  async signCertificateRequestFromDER(csrDer, options) {
2804
2873
  const validity = options?.validity ?? 365;
2805
- 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-"));
2806
2875
  try {
2807
2876
  const csrFile = path6.join(tmpDir, "request.csr");
2808
2877
  const certFile = path6.join(tmpDir, "certificate.pem");
2809
2878
  const csrPem = toPem2(csrDer, "CERTIFICATE REQUEST");
2810
- await fs9.promises.writeFile(csrFile, csrPem, "utf-8");
2811
- 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);
2812
2887
  const certPem = readCertificatePEM(certFile);
2813
2888
  return convertPEMtoDER(certPem);
2814
2889
  } finally {
2815
- 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, {
2816
3003
  recursive: true,
2817
3004
  force: true
2818
3005
  });
@@ -2834,7 +3021,7 @@ var init_certificate_authority = __esm({
2834
3021
  const info = exploreCertificate2(certDer);
2835
3022
  const serial = info.tbsCertificate.serialNumber.replace(/:/g, "").toUpperCase();
2836
3023
  const storedCertFile = path6.join(this.rootDir, "certs", `${serial}.pem`);
2837
- if (!fs9.existsSync(storedCertFile)) {
3024
+ if (!fs10.existsSync(storedCertFile)) {
2838
3025
  throw new Error(`Cannot revoke: no stored certificate found for serial ${serial} at ${storedCertFile}`);
2839
3026
  }
2840
3027
  await this.revokeCertificate(storedCertFile, {
@@ -2849,6 +3036,204 @@ var init_certificate_authority = __esm({
2849
3036
  async initialize() {
2850
3037
  await construct_CertificateAuthority(this);
2851
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
+ }
2852
3237
  /**
2853
3238
  * Rebuild the combined CA certificate + CRL file.
2854
3239
  *
@@ -2858,13 +3243,13 @@ var init_certificate_authority = __esm({
2858
3243
  */
2859
3244
  async constructCACertificateWithCRL() {
2860
3245
  const cacertWithCRL = this.caCertificateWithCrl;
2861
- if (fs9.existsSync(this.revocationList)) {
2862
- await fs9.promises.writeFile(
3246
+ if (fs10.existsSync(this.revocationList)) {
3247
+ await fs10.promises.writeFile(
2863
3248
  cacertWithCRL,
2864
- fs9.readFileSync(this.caCertificate, "utf8") + fs9.readFileSync(this.revocationList, "utf8")
3249
+ fs10.readFileSync(this.caCertificate, "utf8") + fs10.readFileSync(this.revocationList, "utf8")
2865
3250
  );
2866
3251
  } else {
2867
- await fs9.promises.writeFile(cacertWithCRL, fs9.readFileSync(this.caCertificate));
3252
+ await fs10.promises.writeFile(cacertWithCRL, fs10.readFileSync(this.caCertificate));
2868
3253
  }
2869
3254
  }
2870
3255
  /**
@@ -2874,14 +3259,15 @@ var init_certificate_authority = __esm({
2874
3259
  * @param certificate - path to the certificate file to extend
2875
3260
  */
2876
3261
  async constructCertificateChain(certificate) {
2877
- assert9(fs9.existsSync(certificate));
2878
- assert9(fs9.existsSync(this.caCertificate));
3262
+ assert10(fs10.existsSync(certificate));
3263
+ assert10(fs10.existsSync(this.caCertificate));
2879
3264
  debugLog(chalk6.yellow(" certificate file :"), chalk6.cyan(certificate));
2880
- await fs9.promises.writeFile(
2881
- certificate,
2882
- await fs9.promises.readFile(certificate, "utf8") + await fs9.promises.readFile(this.caCertificate, "utf8")
2883
- // + fs.readFileSync(this.revocationList)
2884
- );
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);
2885
3271
  }
2886
3272
  /**
2887
3273
  * Create a self-signed certificate using OpenSSL.
@@ -2891,8 +3277,8 @@ var init_certificate_authority = __esm({
2891
3277
  * @param params - certificate parameters (subject, validity, SANs)
2892
3278
  */
2893
3279
  async createSelfSignedCertificate(certificateFile, privateKey, params) {
2894
- assert9(typeof privateKey === "string");
2895
- assert9(fs9.existsSync(privateKey));
3280
+ assert10(typeof privateKey === "string");
3281
+ assert10(fs10.existsSync(privateKey));
2896
3282
  if (!certificateFileExist(certificateFile)) {
2897
3283
  return;
2898
3284
  }
@@ -2900,7 +3286,7 @@ var init_certificate_authority = __esm({
2900
3286
  adjustApplicationUri(params);
2901
3287
  processAltNames(params);
2902
3288
  const csrFile = `${certificateFile}_csr`;
2903
- assert9(csrFile);
3289
+ assert10(csrFile);
2904
3290
  const configFile = generateStaticConfig(this.configFile, { cwd: this.rootDir });
2905
3291
  const options = {
2906
3292
  cwd: this.rootDir,
@@ -2911,19 +3297,19 @@ var init_certificate_authority = __esm({
2911
3297
  const subjectOptions = subject && subject.length > 1 ? ` -subj ${subject} ` : "";
2912
3298
  displaySubtitle("- the certificate signing request");
2913
3299
  await execute_openssl(
2914
- "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)),
2915
3301
  options
2916
3302
  );
2917
3303
  displaySubtitle("- creating the self-signed certificate");
2918
3304
  await execute_openssl(
2919
- "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)),
2920
3306
  options
2921
3307
  );
2922
3308
  displaySubtitle("- dump the certificate for a check");
2923
- 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`, {});
2924
3310
  displaySubtitle("- verify self-signed certificate");
2925
- await execute_openssl_no_failure(`verify -verbose -CAfile ${q3(n4(certificateFile))} ${q3(n4(certificateFile))}`, options);
2926
- 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);
2927
3313
  }
2928
3314
  /**
2929
3315
  * Revoke a certificate and regenerate the CRL.
@@ -2952,22 +3338,22 @@ var init_certificate_authority = __esm({
2952
3338
  setEnv("ALTNAME", "");
2953
3339
  const randomFile = path6.join(this.rootDir, "random.rnd");
2954
3340
  setEnv("RANDFILE", randomFile);
2955
- const configOption = ` -config ${q3(n4(configFile))}`;
3341
+ const configOption = ` -config ${q4(n5(configFile))}`;
2956
3342
  const reason = params.reason || "keyCompromise";
2957
- assert9(crlReasons.indexOf(reason) >= 0);
3343
+ assert10(crlReasons.indexOf(reason) >= 0);
2958
3344
  displayTitle(`Revoking certificate ${certificate}`);
2959
3345
  displaySubtitle("Revoke certificate");
2960
- 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);
2961
3347
  await regenerateCrl(this.revocationList, configOption, options);
2962
3348
  displaySubtitle("Verify that certificate is revoked");
2963
3349
  await execute_openssl_no_failure(
2964
- "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)),
2965
3351
  options
2966
3352
  );
2967
3353
  displaySubtitle("Produce CRL in DER form ");
2968
- 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);
2969
3355
  displaySubtitle("Produce CRL in PEM form ");
2970
- 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);
2971
3357
  }
2972
3358
  /**
2973
3359
  * Sign a Certificate Signing Request (CSR) with this CA.
@@ -2983,7 +3369,7 @@ var init_certificate_authority = __esm({
2983
3369
  */
2984
3370
  async signCertificateRequest(certificate, certificateSigningRequestFilename, params1) {
2985
3371
  await ensure_openssl_installed();
2986
- assert9(fs9.existsSync(certificateSigningRequestFilename));
3372
+ assert10(fs10.existsSync(certificateSigningRequestFilename));
2987
3373
  if (!certificateFileExist(certificate)) {
2988
3374
  return "";
2989
3375
  }
@@ -3010,11 +3396,11 @@ var init_certificate_authority = __esm({
3010
3396
  displaySubtitle("- then we ask the authority to sign the certificate signing request");
3011
3397
  const configOption = ` -config ${configFile}`;
3012
3398
  await execute_openssl(
3013
- "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)),
3014
3400
  options
3015
3401
  );
3016
3402
  displaySubtitle("- dump the certificate for a check");
3017
- 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);
3018
3404
  displaySubtitle("- construct CA certificate with CRL");
3019
3405
  await this.constructCACertificateWithCRL();
3020
3406
  displaySubtitle("- construct certificate chain");
@@ -3037,7 +3423,7 @@ var init_certificate_authority = __esm({
3037
3423
  const _configOption = ` -config ${configFile}`;
3038
3424
  _configOption;
3039
3425
  await execute_openssl_no_failure(
3040
- `verify -verbose -CAfile ${q3(n4(this.caCertificateWithCrl))} ${q3(n4(certificate))}`,
3426
+ `verify -verbose -CAfile ${q4(n5(this.caCertificateWithCrl))} ${q4(n5(certificate))}`,
3041
3427
  options
3042
3428
  );
3043
3429
  }
@@ -3047,13 +3433,13 @@ var init_certificate_authority = __esm({
3047
3433
  });
3048
3434
 
3049
3435
  // packages/node-opcua-pki/lib/ca/crypto_create_CA.ts
3050
- import assert10 from "assert";
3051
- import fs10 from "fs";
3436
+ import assert11 from "assert";
3437
+ import fs11 from "fs";
3052
3438
  import { createRequire } from "module";
3053
3439
  import os5 from "os";
3054
3440
  import path7 from "path";
3055
3441
  import chalk7 from "chalk";
3056
- 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";
3057
3443
  import commandLineArgs from "command-line-args";
3058
3444
  import commandLineUsage from "command-line-usage";
3059
3445
  function get_offset_date(date, nbDays) {
@@ -3062,8 +3448,8 @@ function get_offset_date(date, nbDays) {
3062
3448
  return d;
3063
3449
  }
3064
3450
  async function construct_CertificateAuthority2(subject) {
3065
- assert10(typeof gLocalConfig.CAFolder === "string", "expecting a CAFolder in config");
3066
- 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");
3067
3453
  if (!g_certificateAuthority) {
3068
3454
  g_certificateAuthority = new CertificateAuthority({
3069
3455
  keySize: gLocalConfig.keySize,
@@ -3074,7 +3460,7 @@ async function construct_CertificateAuthority2(subject) {
3074
3460
  }
3075
3461
  }
3076
3462
  async function construct_CertificateManager() {
3077
- assert10(typeof gLocalConfig.PKIFolder === "string", "expecting a PKIFolder in config");
3463
+ assert11(typeof gLocalConfig.PKIFolder === "string", "expecting a PKIFolder in config");
3078
3464
  if (!certificateManager) {
3079
3465
  certificateManager = new CertificateManager({
3080
3466
  keySize: gLocalConfig.keySize,
@@ -3085,35 +3471,35 @@ async function construct_CertificateManager() {
3085
3471
  }
3086
3472
  function default_template_content() {
3087
3473
  if (process.pkg?.entrypoint) {
3088
- 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");
3089
3475
  return a;
3090
3476
  }
3091
3477
  function find_default_config_template() {
3092
3478
  const rootFolder = find_module_root_folder();
3093
3479
  const configName = "pki_config.example.js";
3094
3480
  let default_config_template2 = path7.join(rootFolder, "bin", configName);
3095
- if (!fs10.existsSync(default_config_template2)) {
3481
+ if (!fs11.existsSync(default_config_template2)) {
3096
3482
  default_config_template2 = path7.join(__dirname, "..", configName);
3097
- if (!fs10.existsSync(default_config_template2)) {
3483
+ if (!fs11.existsSync(default_config_template2)) {
3098
3484
  default_config_template2 = path7.join(__dirname, `../bin/${configName}`);
3099
3485
  }
3100
3486
  }
3101
3487
  return default_config_template2;
3102
3488
  }
3103
3489
  const default_config_template = find_default_config_template();
3104
- assert10(fs10.existsSync(default_config_template));
3105
- 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");
3106
3492
  return default_config_template_content;
3107
3493
  }
3108
3494
  function find_module_root_folder() {
3109
3495
  let rootFolder = path7.join(__dirname);
3110
3496
  for (let i = 0; i < 4; i++) {
3111
- if (fs10.existsSync(path7.join(rootFolder, "package.json"))) {
3497
+ if (fs11.existsSync(path7.join(rootFolder, "package.json"))) {
3112
3498
  return rootFolder;
3113
3499
  }
3114
3500
  rootFolder = path7.join(rootFolder, "..");
3115
3501
  }
3116
- 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");
3117
3503
  return rootFolder;
3118
3504
  }
3119
3505
  async function readConfiguration(argv) {
@@ -3142,19 +3528,19 @@ async function readConfiguration(argv) {
3142
3528
  return makePath(tmp);
3143
3529
  }
3144
3530
  certificateDir = argv.root;
3145
- assert10(typeof certificateDir === "string");
3531
+ assert11(typeof certificateDir === "string");
3146
3532
  certificateDir = prepare(certificateDir);
3147
3533
  mkdirRecursiveSync(certificateDir);
3148
- assert10(fs10.existsSync(certificateDir));
3534
+ assert11(fs11.existsSync(certificateDir));
3149
3535
  const default_config = path7.join(certificateDir, "config.js");
3150
- if (!fs10.existsSync(default_config)) {
3536
+ if (!fs11.existsSync(default_config)) {
3151
3537
  debugLog(chalk7.yellow(" Creating default g_config file "), chalk7.cyan(default_config));
3152
3538
  const default_config_template_content = default_template_content();
3153
- fs10.writeFileSync(default_config, default_config_template_content);
3539
+ fs11.writeFileSync(default_config, default_config_template_content);
3154
3540
  } else {
3155
3541
  debugLog(chalk7.yellow(" using g_config file "), chalk7.cyan(default_config));
3156
3542
  }
3157
- if (!fs10.existsSync(default_config)) {
3543
+ if (!fs11.existsSync(default_config)) {
3158
3544
  debugLog(chalk7.redBright(" cannot find config file ", default_config));
3159
3545
  }
3160
3546
  const defaultRandomFile = path7.join(path7.dirname(default_config), "random.rnd");
@@ -3210,7 +3596,7 @@ async function readConfiguration(argv) {
3210
3596
  }
3211
3597
  }
3212
3598
  async function createDefaultCertificate(base_name, prefix, key_length, applicationUri, dev) {
3213
- 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);
3214
3600
  const private_key_file = makePath(base_name, `${prefix}key_${key_length}.pem`);
3215
3601
  const public_key_file = makePath(base_name, `${prefix}public_key_${key_length}.pub`);
3216
3602
  const certificate_file = makePath(base_name, `${prefix}cert_${key_length}.pem`);
@@ -3230,7 +3616,7 @@ async function createDefaultCertificate(base_name, prefix, key_length, applicati
3230
3616
  }
3231
3617
  const ip = [];
3232
3618
  async function createCertificateIfNotExist(certificate, private_key, applicationUri2, startDate, validity) {
3233
- if (fs10.existsSync(certificate)) {
3619
+ if (fs11.existsSync(certificate)) {
3234
3620
  warningLog(chalk7.yellow(" certificate"), chalk7.cyan(certificate), chalk7.yellow(" already exists => skipping"));
3235
3621
  return "";
3236
3622
  } else {
@@ -3249,7 +3635,7 @@ async function createDefaultCertificate(base_name, prefix, key_length, applicati
3249
3635
  configFile,
3250
3636
  dns: dns3,
3251
3637
  ip: ip2,
3252
- purpose: CertificatePurpose2.ForApplication
3638
+ purpose: CertificatePurpose3.ForApplication
3253
3639
  };
3254
3640
  await createCertificateSigningRequestWithOpenSSL(certificateSigningRequestFile, params);
3255
3641
  return await g_certificateAuthority.signCertificateRequest(certificate, certificateSigningRequestFile, {
@@ -3273,7 +3659,7 @@ async function createDefaultCertificate(base_name, prefix, key_length, applicati
3273
3659
  await g_certificateAuthority.revokeCertificate(certificate, {});
3274
3660
  }
3275
3661
  async function createPrivateKeyIfNotExist(privateKey, keyLength) {
3276
- if (fs10.existsSync(privateKey)) {
3662
+ if (fs11.existsSync(privateKey)) {
3277
3663
  warningLog(chalk7.yellow(" privateKey"), chalk7.cyan(privateKey), chalk7.yellow(" already exists => skipping"));
3278
3664
  return;
3279
3665
  } else {
@@ -3287,14 +3673,14 @@ async function createDefaultCertificate(base_name, prefix, key_length, applicati
3287
3673
  displaySubtitle(` create Certificate ${certificate_file}`);
3288
3674
  await createCertificateIfNotExist(certificate_file, private_key_file, applicationUri, yesterday, 365);
3289
3675
  displaySubtitle(` create self signed Certificate ${self_signed_certificate_file}`);
3290
- if (fs10.existsSync(self_signed_certificate_file)) {
3676
+ if (fs11.existsSync(self_signed_certificate_file)) {
3291
3677
  return;
3292
3678
  }
3293
3679
  await createSelfSignedCertificate2(self_signed_certificate_file, private_key_file, applicationUri, yesterday, 365);
3294
3680
  if (dev) {
3295
3681
  await createCertificateIfNotExist(certificate_file_outofdate, private_key_file, applicationUri, two_years_ago, 365);
3296
3682
  await createCertificateIfNotExist(certificate_file_not_active_yet, private_key_file, applicationUri, next_year, 365);
3297
- if (!fs10.existsSync(certificate_revoked)) {
3683
+ if (!fs11.existsSync(certificate_revoked)) {
3298
3684
  const certificate = await createCertificateIfNotExist(
3299
3685
  certificate_revoked,
3300
3686
  private_key_file,
@@ -3316,9 +3702,9 @@ async function wrap(func) {
3316
3702
  }
3317
3703
  }
3318
3704
  async function create_default_certificates(dev) {
3319
- assert10(gLocalConfig);
3705
+ assert11(gLocalConfig);
3320
3706
  const base_name = gLocalConfig.certificateDir || "";
3321
- assert10(fs10.existsSync(base_name));
3707
+ assert11(fs11.existsSync(base_name));
3322
3708
  let clientURN;
3323
3709
  let serverURN;
3324
3710
  let discoveryServerURN;
@@ -3415,7 +3801,7 @@ ${epilog}`
3415
3801
  }
3416
3802
  if (command === "version") {
3417
3803
  const rootFolder = find_module_root_folder();
3418
- 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"));
3419
3805
  console.log(pkg.version);
3420
3806
  return;
3421
3807
  }
@@ -3440,12 +3826,12 @@ ${epilog}`
3440
3826
  await readConfiguration(local_argv);
3441
3827
  if (local_argv.clean) {
3442
3828
  displayTitle("Cleaning old certificates");
3443
- assert10(gLocalConfig);
3829
+ assert11(gLocalConfig);
3444
3830
  const certificateDir = gLocalConfig.certificateDir || "";
3445
- const files = await fs10.promises.readdir(certificateDir);
3831
+ const files = await fs11.promises.readdir(certificateDir);
3446
3832
  for (const file of files) {
3447
3833
  if (file.includes(".pem") || file.includes(".pub")) {
3448
- await fs10.promises.unlink(path7.join(certificateDir, file));
3834
+ await fs11.promises.unlink(path7.join(certificateDir, file));
3449
3835
  }
3450
3836
  }
3451
3837
  mkdirRecursiveSync(certificateDir);
@@ -3552,7 +3938,7 @@ ${epilog}`
3552
3938
  await readConfiguration(local_argv2);
3553
3939
  await construct_CertificateManager();
3554
3940
  await construct_CertificateAuthority2("");
3555
- assert10(fs10.existsSync(gLocalConfig.CAFolder || ""), " CA folder must exist");
3941
+ assert11(fs11.existsSync(gLocalConfig.CAFolder || ""), " CA folder must exist");
3556
3942
  gLocalConfig.privateKey = void 0;
3557
3943
  gLocalConfig.subject = local_argv2.subject && local_argv2.subject.length > 1 ? local_argv2.subject : gLocalConfig.subject;
3558
3944
  const csr_file = await certificateManager.createCertificateRequest(
@@ -3563,7 +3949,7 @@ ${epilog}`
3563
3949
  }
3564
3950
  warningLog(" csr_file = ", csr_file);
3565
3951
  const certificate = csr_file.replace(".csr", ".pem");
3566
- if (fs10.existsSync(certificate)) {
3952
+ if (fs11.existsSync(certificate)) {
3567
3953
  throw new Error(` File ${certificate} already exist`);
3568
3954
  }
3569
3955
  await g_certificateAuthority.signCertificateRequest(
@@ -3571,8 +3957,8 @@ ${epilog}`
3571
3957
  csr_file,
3572
3958
  gLocalConfig
3573
3959
  );
3574
- assert10(typeof gLocalConfig.outputFile === "string");
3575
- fs10.writeFileSync(gLocalConfig.outputFile || "", fs10.readFileSync(certificate, "ascii"));
3960
+ assert11(typeof gLocalConfig.outputFile === "string");
3961
+ fs11.writeFileSync(gLocalConfig.outputFile || "", fs11.readFileSync(certificate, "ascii"));
3576
3962
  }
3577
3963
  await wrap(async () => await command_certificate(local_argv));
3578
3964
  return;
@@ -3593,7 +3979,7 @@ ${epilog}`
3593
3979
  await wrap(async () => {
3594
3980
  const certificate = path7.resolve(local_argv.certificateFile);
3595
3981
  warningLog(chalk7.yellow(" Certificate to revoke : "), chalk7.cyan(certificate));
3596
- if (!fs10.existsSync(certificate)) {
3982
+ if (!fs11.existsSync(certificate)) {
3597
3983
  throw new Error(`cannot find certificate to revoke ${certificate}`);
3598
3984
  }
3599
3985
  await readConfiguration(local_argv);
@@ -3640,11 +4026,11 @@ ${epilog}`
3640
4026
  if (local_argv.help) return showHelp("csr", "create a certificate signing request", optionsDef);
3641
4027
  await wrap(async () => {
3642
4028
  await readConfiguration(local_argv);
3643
- if (!fs10.existsSync(gLocalConfig.PKIFolder || "")) {
4029
+ if (!fs11.existsSync(gLocalConfig.PKIFolder || "")) {
3644
4030
  warningLog("PKI folder must exist");
3645
4031
  }
3646
4032
  await construct_CertificateManager();
3647
- if (!gLocalConfig.outputFile || fs10.existsSync(gLocalConfig.outputFile)) {
4033
+ if (!gLocalConfig.outputFile || fs11.existsSync(gLocalConfig.outputFile)) {
3648
4034
  throw new Error(` File ${gLocalConfig.outputFile} already exist`);
3649
4035
  }
3650
4036
  gLocalConfig.privateKey = void 0;
@@ -3659,8 +4045,8 @@ ${epilog}`
3659
4045
  warningLog("please specify a output file");
3660
4046
  return;
3661
4047
  }
3662
- const csr = await fs10.promises.readFile(internal_csr_file, "utf-8");
3663
- 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");
3664
4050
  warningLog("Subject = ", gLocalConfig.subject);
3665
4051
  warningLog("applicationUri = ", gLocalConfig.applicationUri);
3666
4052
  warningLog("altNames = ", gLocalConfig.altNames);
@@ -3688,16 +4074,16 @@ ${epilog}`
3688
4074
  return showHelp("sign", "validate a certificate signing request and generate a certificate", optionsDef);
3689
4075
  await wrap(async () => {
3690
4076
  await readConfiguration(local_argv);
3691
- if (!fs10.existsSync(gLocalConfig.CAFolder || "")) {
4077
+ if (!fs11.existsSync(gLocalConfig.CAFolder || "")) {
3692
4078
  throw new Error(`CA folder must exist:${gLocalConfig.CAFolder}`);
3693
4079
  }
3694
4080
  await construct_CertificateAuthority2("");
3695
4081
  const csr_file = path7.resolve(local_argv.csr || "");
3696
- if (!fs10.existsSync(csr_file)) {
4082
+ if (!fs11.existsSync(csr_file)) {
3697
4083
  throw new Error(`Certificate signing request doesn't exist: ${csr_file}`);
3698
4084
  }
3699
4085
  const certificate = path7.resolve(local_argv.output || csr_file.replace(".csr", ".pem"));
3700
- if (fs10.existsSync(certificate)) {
4086
+ if (fs11.existsSync(certificate)) {
3701
4087
  throw new Error(` File ${certificate} already exist`);
3702
4088
  }
3703
4089
  await g_certificateAuthority.signCertificateRequest(
@@ -3705,8 +4091,8 @@ ${epilog}`
3705
4091
  csr_file,
3706
4092
  gLocalConfig
3707
4093
  );
3708
- assert10(typeof gLocalConfig.outputFile === "string");
3709
- fs10.writeFileSync(gLocalConfig.outputFile || "", fs10.readFileSync(certificate, "ascii"));
4094
+ assert11(typeof gLocalConfig.outputFile === "string");
4095
+ fs11.writeFileSync(gLocalConfig.outputFile || "", fs11.readFileSync(certificate, "ascii"));
3710
4096
  });
3711
4097
  return;
3712
4098
  }