node-opcua-pki 6.15.0 → 6.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -59,6 +59,17 @@ interface StartDateEndDateParam {
59
59
  endDate?: Date;
60
60
  /** Number of days the certificate is valid. @defaultValue 365 */
61
61
  validity?: number;
62
+ /**
63
+ * Certificate validity in milliseconds.
64
+ *
65
+ * When provided, takes precedence over {@link validity} and enables
66
+ * sub-day validity (X.509 supports second precision per RFC 5280
67
+ * §4.1.2.5; OpenSSL is invoked with `-startdate`/`-enddate` already).
68
+ *
69
+ * Typical use is short-lived certificates for demos or for renewal
70
+ * cycle testing. Existing day-based callers are unaffected.
71
+ */
72
+ validityMs?: number;
62
73
  }
63
74
  /**
64
75
  * Parameters for creating a self-signed certificate.
@@ -240,6 +251,13 @@ interface IssuedCertificateRecord {
240
251
  interface SignCertificateOptions {
241
252
  /** Certificate validity in days (default: 365). */
242
253
  validity?: number;
254
+ /**
255
+ * Certificate validity in milliseconds.
256
+ *
257
+ * When provided, takes precedence over {@link validity} and enables
258
+ * sub-day validity (e.g. 10-minute certificates for renewal demos).
259
+ */
260
+ validityMs?: number;
243
261
  /** Override the certificate start date. */
244
262
  startDate?: Date;
245
263
  /** Override DNS SANs. */
@@ -251,6 +269,34 @@ interface SignCertificateOptions {
251
269
  /** Override the X.500 subject. */
252
270
  subject?: SubjectOptions | string;
253
271
  }
272
+ /**
273
+ * Capabilities advertised by a PKI backend (or by this
274
+ * {@link CertificateAuthority}) so consumers can clamp requested
275
+ * validity to the limits the backend can actually honor.
276
+ *
277
+ * Useful for the GDS Pull / Push management flows, where the CA may
278
+ * be supplied by an external service (step-ca, EJBCA, …) with its
279
+ * own minimum / maximum / granularity constraints.
280
+ *
281
+ * @see CertificateAuthority.getCapabilities
282
+ */
283
+ interface PkiBackendCapabilities {
284
+ /** Smallest validity this backend can issue, in milliseconds. */
285
+ minValidityMs: number;
286
+ /** Largest validity this backend will issue, in milliseconds. */
287
+ maxValidityMs: number;
288
+ /**
289
+ * Validity is rounded up to the nearest multiple of this many
290
+ * milliseconds. For `node-opcua-pki`'s OpenSSL-based CA this is
291
+ * 1 000 ms (one second — the X.509 floor per RFC 5280 §4.1.2.5).
292
+ */
293
+ validityGranularityMs: number;
294
+ /**
295
+ * Native unit the backend works in. Diagnostic only — callers
296
+ * always pass `validityMs` (US-208 / US-210).
297
+ */
298
+ nativeUnit: "second" | "minute" | "hour" | "day";
299
+ }
254
300
  /**
255
301
  * Options for {@link CertificateAuthority.generateKeyPairAndSignDER}.
256
302
  */
@@ -265,6 +311,13 @@ interface GenerateKeyPairAndSignOptions {
265
311
  ip?: string[];
266
312
  /** Certificate validity in days (default: 365). */
267
313
  validity?: number;
314
+ /**
315
+ * Certificate validity in milliseconds.
316
+ *
317
+ * When provided, takes precedence over {@link validity} and enables
318
+ * sub-day validity (e.g. 10-minute certificates for renewal demos).
319
+ */
320
+ validityMs?: number;
268
321
  /** Certificate start date (default: now). */
269
322
  startDate?: Date;
270
323
  /** RSA key size in bits (default: 2048). */
@@ -475,6 +528,28 @@ declare class CertificateAuthority {
475
528
  * @returns the signed certificate as a DER-encoded buffer
476
529
  */
477
530
  signCertificateRequestFromDER(csrDer: Buffer, options?: SignCertificateOptions): Promise<Buffer>;
531
+ /**
532
+ * Advertise the validity limits this CA can honor.
533
+ *
534
+ * Consumers (notably the GDS server in [`cert_auth.ts`](https://github.com/sterfive/node-opcua-gds))
535
+ * clamp a requested validity against these bounds before calling
536
+ * {@link signCertificateRequestFromDER}, so a misconfigured
537
+ * `defaultCertValidity` cannot ask the CA for something it cannot
538
+ * produce.
539
+ *
540
+ * Defaults match the OpenSSL-backed implementation:
541
+ * - `minValidityMs = 60_000` (1 minute) — practical floor; the
542
+ * X.509 spec floor is 1 second but very short certs are rarely
543
+ * useful and pathological for any real deployment.
544
+ * - `maxValidityMs = 10 * 365 * 86_400_000` (≈ 10 years) — long
545
+ * enough for root CAs.
546
+ * - `validityGranularityMs = 1_000` (1 second) — RFC 5280 §4.1.2.5
547
+ * floor on `notBefore` / `notAfter`.
548
+ * - `nativeUnit = "second"` — what `x509Date()` actually encodes.
549
+ *
550
+ * @see US-208 — the consumer-side capability story.
551
+ */
552
+ getCapabilities(): PkiBackendCapabilities;
478
553
  /**
479
554
  * Generate a new RSA key pair, create an internal CSR, sign it
480
555
  * with this CA, and return both the certificate and private key
@@ -1440,4 +1515,4 @@ declare function dumpPFX(pfxFile: Filename, passphrase?: string): Promise<string
1440
1515
  */
1441
1516
  declare function install_prerequisite(): Promise<string>;
1442
1517
 
1443
- export { type AddCertificateValidationOptions, CertificateAuthority, type CertificateAuthorityOptions, CertificateManager, type CertificateManagerEvents, type CertificateManagerOptions, CertificateManagerState, type CertificateStatus, type CertificateStore, type ChainCompletionResult, ChainCompletionStatus, type CreateCertificateSigningRequestOptions, type CreateCertificateSigningRequestWithConfigOptions, type CreatePFXOptions, type CreateSelfSignCertificateParam, type CreateSelfSignCertificateParam1, type CreateSelfSignCertificateWithConfigParam, type CrlStore, type ExtractPFXOptions, type ExtractPFXResult, type Filename, type GenerateKeyPairAndSignOptions, type GenerateKeyPairAndSignPFXOptions, type InitializeCSRResult, type InstallCACertificateResult, type KeyLength, type KeySize, type Params, type ProcessAltNamesParam, type SignCertificateOptions, type StartDateEndDateParam, type Thumbprint, VerificationStatus, type VerifyCertificateOptions, adjustApplicationUri, adjustDate, coerceCertificateChain, convertPFXtoPEM, createPFX, dumpPFX, extractAllFromPFX, extractCACertificatesFromPFX, extractCertificateFromPFX, extractPrivateKeyFromPFX, findIssuerCertificateInChain, install_prerequisite, isIntermediateIssuer, isIssuer, isRootIssuer, makeFingerprint, quote };
1518
+ export { type AddCertificateValidationOptions, CertificateAuthority, type CertificateAuthorityOptions, CertificateManager, type CertificateManagerEvents, type CertificateManagerOptions, CertificateManagerState, type CertificateStatus, type CertificateStore, type ChainCompletionResult, ChainCompletionStatus, type CreateCertificateSigningRequestOptions, type CreateCertificateSigningRequestWithConfigOptions, type CreatePFXOptions, type CreateSelfSignCertificateParam, type CreateSelfSignCertificateParam1, type CreateSelfSignCertificateWithConfigParam, type CrlStore, type ExtractPFXOptions, type ExtractPFXResult, type Filename, type GenerateKeyPairAndSignOptions, type GenerateKeyPairAndSignPFXOptions, type InitializeCSRResult, type InstallCACertificateResult, type KeyLength, type KeySize, type Params, type PkiBackendCapabilities, type ProcessAltNamesParam, type SignCertificateOptions, type StartDateEndDateParam, type Thumbprint, VerificationStatus, type VerifyCertificateOptions, adjustApplicationUri, adjustDate, coerceCertificateChain, convertPFXtoPEM, createPFX, dumpPFX, extractAllFromPFX, extractCACertificatesFromPFX, extractCertificateFromPFX, extractPrivateKeyFromPFX, findIssuerCertificateInChain, install_prerequisite, isIntermediateIssuer, isIssuer, isRootIssuer, makeFingerprint, quote };
package/dist/index.d.ts CHANGED
@@ -59,6 +59,17 @@ interface StartDateEndDateParam {
59
59
  endDate?: Date;
60
60
  /** Number of days the certificate is valid. @defaultValue 365 */
61
61
  validity?: number;
62
+ /**
63
+ * Certificate validity in milliseconds.
64
+ *
65
+ * When provided, takes precedence over {@link validity} and enables
66
+ * sub-day validity (X.509 supports second precision per RFC 5280
67
+ * §4.1.2.5; OpenSSL is invoked with `-startdate`/`-enddate` already).
68
+ *
69
+ * Typical use is short-lived certificates for demos or for renewal
70
+ * cycle testing. Existing day-based callers are unaffected.
71
+ */
72
+ validityMs?: number;
62
73
  }
63
74
  /**
64
75
  * Parameters for creating a self-signed certificate.
@@ -240,6 +251,13 @@ interface IssuedCertificateRecord {
240
251
  interface SignCertificateOptions {
241
252
  /** Certificate validity in days (default: 365). */
242
253
  validity?: number;
254
+ /**
255
+ * Certificate validity in milliseconds.
256
+ *
257
+ * When provided, takes precedence over {@link validity} and enables
258
+ * sub-day validity (e.g. 10-minute certificates for renewal demos).
259
+ */
260
+ validityMs?: number;
243
261
  /** Override the certificate start date. */
244
262
  startDate?: Date;
245
263
  /** Override DNS SANs. */
@@ -251,6 +269,34 @@ interface SignCertificateOptions {
251
269
  /** Override the X.500 subject. */
252
270
  subject?: SubjectOptions | string;
253
271
  }
272
+ /**
273
+ * Capabilities advertised by a PKI backend (or by this
274
+ * {@link CertificateAuthority}) so consumers can clamp requested
275
+ * validity to the limits the backend can actually honor.
276
+ *
277
+ * Useful for the GDS Pull / Push management flows, where the CA may
278
+ * be supplied by an external service (step-ca, EJBCA, …) with its
279
+ * own minimum / maximum / granularity constraints.
280
+ *
281
+ * @see CertificateAuthority.getCapabilities
282
+ */
283
+ interface PkiBackendCapabilities {
284
+ /** Smallest validity this backend can issue, in milliseconds. */
285
+ minValidityMs: number;
286
+ /** Largest validity this backend will issue, in milliseconds. */
287
+ maxValidityMs: number;
288
+ /**
289
+ * Validity is rounded up to the nearest multiple of this many
290
+ * milliseconds. For `node-opcua-pki`'s OpenSSL-based CA this is
291
+ * 1 000 ms (one second — the X.509 floor per RFC 5280 §4.1.2.5).
292
+ */
293
+ validityGranularityMs: number;
294
+ /**
295
+ * Native unit the backend works in. Diagnostic only — callers
296
+ * always pass `validityMs` (US-208 / US-210).
297
+ */
298
+ nativeUnit: "second" | "minute" | "hour" | "day";
299
+ }
254
300
  /**
255
301
  * Options for {@link CertificateAuthority.generateKeyPairAndSignDER}.
256
302
  */
@@ -265,6 +311,13 @@ interface GenerateKeyPairAndSignOptions {
265
311
  ip?: string[];
266
312
  /** Certificate validity in days (default: 365). */
267
313
  validity?: number;
314
+ /**
315
+ * Certificate validity in milliseconds.
316
+ *
317
+ * When provided, takes precedence over {@link validity} and enables
318
+ * sub-day validity (e.g. 10-minute certificates for renewal demos).
319
+ */
320
+ validityMs?: number;
268
321
  /** Certificate start date (default: now). */
269
322
  startDate?: Date;
270
323
  /** RSA key size in bits (default: 2048). */
@@ -475,6 +528,28 @@ declare class CertificateAuthority {
475
528
  * @returns the signed certificate as a DER-encoded buffer
476
529
  */
477
530
  signCertificateRequestFromDER(csrDer: Buffer, options?: SignCertificateOptions): Promise<Buffer>;
531
+ /**
532
+ * Advertise the validity limits this CA can honor.
533
+ *
534
+ * Consumers (notably the GDS server in [`cert_auth.ts`](https://github.com/sterfive/node-opcua-gds))
535
+ * clamp a requested validity against these bounds before calling
536
+ * {@link signCertificateRequestFromDER}, so a misconfigured
537
+ * `defaultCertValidity` cannot ask the CA for something it cannot
538
+ * produce.
539
+ *
540
+ * Defaults match the OpenSSL-backed implementation:
541
+ * - `minValidityMs = 60_000` (1 minute) — practical floor; the
542
+ * X.509 spec floor is 1 second but very short certs are rarely
543
+ * useful and pathological for any real deployment.
544
+ * - `maxValidityMs = 10 * 365 * 86_400_000` (≈ 10 years) — long
545
+ * enough for root CAs.
546
+ * - `validityGranularityMs = 1_000` (1 second) — RFC 5280 §4.1.2.5
547
+ * floor on `notBefore` / `notAfter`.
548
+ * - `nativeUnit = "second"` — what `x509Date()` actually encodes.
549
+ *
550
+ * @see US-208 — the consumer-side capability story.
551
+ */
552
+ getCapabilities(): PkiBackendCapabilities;
478
553
  /**
479
554
  * Generate a new RSA key pair, create an internal CSR, sign it
480
555
  * with this CA, and return both the certificate and private key
@@ -1440,4 +1515,4 @@ declare function dumpPFX(pfxFile: Filename, passphrase?: string): Promise<string
1440
1515
  */
1441
1516
  declare function install_prerequisite(): Promise<string>;
1442
1517
 
1443
- export { type AddCertificateValidationOptions, CertificateAuthority, type CertificateAuthorityOptions, CertificateManager, type CertificateManagerEvents, type CertificateManagerOptions, CertificateManagerState, type CertificateStatus, type CertificateStore, type ChainCompletionResult, ChainCompletionStatus, type CreateCertificateSigningRequestOptions, type CreateCertificateSigningRequestWithConfigOptions, type CreatePFXOptions, type CreateSelfSignCertificateParam, type CreateSelfSignCertificateParam1, type CreateSelfSignCertificateWithConfigParam, type CrlStore, type ExtractPFXOptions, type ExtractPFXResult, type Filename, type GenerateKeyPairAndSignOptions, type GenerateKeyPairAndSignPFXOptions, type InitializeCSRResult, type InstallCACertificateResult, type KeyLength, type KeySize, type Params, type ProcessAltNamesParam, type SignCertificateOptions, type StartDateEndDateParam, type Thumbprint, VerificationStatus, type VerifyCertificateOptions, adjustApplicationUri, adjustDate, coerceCertificateChain, convertPFXtoPEM, createPFX, dumpPFX, extractAllFromPFX, extractCACertificatesFromPFX, extractCertificateFromPFX, extractPrivateKeyFromPFX, findIssuerCertificateInChain, install_prerequisite, isIntermediateIssuer, isIssuer, isRootIssuer, makeFingerprint, quote };
1518
+ export { type AddCertificateValidationOptions, CertificateAuthority, type CertificateAuthorityOptions, CertificateManager, type CertificateManagerEvents, type CertificateManagerOptions, CertificateManagerState, type CertificateStatus, type CertificateStore, type ChainCompletionResult, ChainCompletionStatus, type CreateCertificateSigningRequestOptions, type CreateCertificateSigningRequestWithConfigOptions, type CreatePFXOptions, type CreateSelfSignCertificateParam, type CreateSelfSignCertificateParam1, type CreateSelfSignCertificateWithConfigParam, type CrlStore, type ExtractPFXOptions, type ExtractPFXResult, type Filename, type GenerateKeyPairAndSignOptions, type GenerateKeyPairAndSignPFXOptions, type InitializeCSRResult, type InstallCACertificateResult, type KeyLength, type KeySize, type Params, type PkiBackendCapabilities, type ProcessAltNamesParam, type SignCertificateOptions, type StartDateEndDateParam, type Thumbprint, VerificationStatus, type VerifyCertificateOptions, adjustApplicationUri, adjustDate, coerceCertificateChain, convertPFXtoPEM, createPFX, dumpPFX, extractAllFromPFX, extractCACertificatesFromPFX, extractCertificateFromPFX, extractPrivateKeyFromPFX, findIssuerCertificateInChain, install_prerequisite, isIntermediateIssuer, isIssuer, isRootIssuer, makeFingerprint, quote };
package/dist/index.js CHANGED
@@ -77,9 +77,17 @@ function adjustDate(params) {
77
77
  (0, import_node_assert.default)(params instanceof Object);
78
78
  params.startDate = params.startDate || /* @__PURE__ */ new Date();
79
79
  (0, import_node_assert.default)(params.startDate instanceof Date);
80
- params.validity = params.validity || 365;
81
- params.endDate = new Date(params.startDate.getTime());
82
- params.endDate.setDate(params.startDate.getDate() + params.validity);
80
+ if (params.validityMs !== void 0) {
81
+ if (params.validityMs <= 0) {
82
+ throw new RangeError(`validityMs must be > 0 (got ${params.validityMs})`);
83
+ }
84
+ params.endDate = new Date(params.startDate.getTime() + params.validityMs);
85
+ params.validity = Math.ceil(params.validityMs / 864e5);
86
+ } else {
87
+ params.validity = params.validity || 365;
88
+ params.endDate = new Date(params.startDate.getTime());
89
+ params.endDate.setDate(params.startDate.getDate() + params.validity);
90
+ }
83
91
  (0, import_node_assert.default)(params.endDate instanceof Date);
84
92
  (0, import_node_assert.default)(params.startDate instanceof Date);
85
93
  }
@@ -1400,14 +1408,15 @@ var CertificateAuthority = class {
1400
1408
  * @returns the signed certificate as a DER-encoded buffer
1401
1409
  */
1402
1410
  async signCertificateRequestFromDER(csrDer, options) {
1403
- const validity = options?.validity ?? 365;
1404
1411
  const tmpDir = await import_node_fs7.default.promises.mkdtemp(import_node_path5.default.join(import_node_os3.default.tmpdir(), "pki-sign-"));
1405
1412
  try {
1406
1413
  const csrFile = import_node_path5.default.join(tmpDir, "request.csr");
1407
1414
  const certFile = import_node_path5.default.join(tmpDir, "certificate.pem");
1408
1415
  const csrPem = (0, import_node_opcua_crypto2.toPem)(csrDer, "CERTIFICATE REQUEST");
1409
1416
  await import_node_fs7.default.promises.writeFile(csrFile, csrPem, "utf-8");
1410
- const signingParams = { validity };
1417
+ const signingParams = {};
1418
+ if (options?.validityMs !== void 0) signingParams.validityMs = options.validityMs;
1419
+ else signingParams.validity = options?.validity ?? 365;
1411
1420
  if (options?.startDate) signingParams.startDate = options.startDate;
1412
1421
  if (options?.dns) signingParams.dns = options.dns;
1413
1422
  if (options?.ip) signingParams.ip = options.ip;
@@ -1423,6 +1432,35 @@ var CertificateAuthority = class {
1423
1432
  });
1424
1433
  }
1425
1434
  }
1435
+ /**
1436
+ * Advertise the validity limits this CA can honor.
1437
+ *
1438
+ * Consumers (notably the GDS server in [`cert_auth.ts`](https://github.com/sterfive/node-opcua-gds))
1439
+ * clamp a requested validity against these bounds before calling
1440
+ * {@link signCertificateRequestFromDER}, so a misconfigured
1441
+ * `defaultCertValidity` cannot ask the CA for something it cannot
1442
+ * produce.
1443
+ *
1444
+ * Defaults match the OpenSSL-backed implementation:
1445
+ * - `minValidityMs = 60_000` (1 minute) — practical floor; the
1446
+ * X.509 spec floor is 1 second but very short certs are rarely
1447
+ * useful and pathological for any real deployment.
1448
+ * - `maxValidityMs = 10 * 365 * 86_400_000` (≈ 10 years) — long
1449
+ * enough for root CAs.
1450
+ * - `validityGranularityMs = 1_000` (1 second) — RFC 5280 §4.1.2.5
1451
+ * floor on `notBefore` / `notAfter`.
1452
+ * - `nativeUnit = "second"` — what `x509Date()` actually encodes.
1453
+ *
1454
+ * @see US-208 — the consumer-side capability story.
1455
+ */
1456
+ getCapabilities() {
1457
+ return {
1458
+ minValidityMs: 6e4,
1459
+ maxValidityMs: 10 * 365 * 864e5,
1460
+ validityGranularityMs: 1e3,
1461
+ nativeUnit: "second"
1462
+ };
1463
+ }
1426
1464
  /**
1427
1465
  * Generate a new RSA key pair, create an internal CSR, sign it
1428
1466
  * with this CA, and return both the certificate and private key
@@ -1440,7 +1478,6 @@ var CertificateAuthority = class {
1440
1478
  */
1441
1479
  async generateKeyPairAndSignDER(options) {
1442
1480
  const keySize = options.keySize ?? 2048;
1443
- const validity = options.validity ?? 365;
1444
1481
  const startDate = options.startDate ?? /* @__PURE__ */ new Date();
1445
1482
  const tmpDir = await import_node_fs7.default.promises.mkdtemp(import_node_path5.default.join(import_node_os3.default.tmpdir(), "pki-keygen-"));
1446
1483
  try {
@@ -1460,13 +1497,15 @@ var CertificateAuthority = class {
1460
1497
  purpose: import_node_opcua_crypto2.CertificatePurpose.ForApplication
1461
1498
  });
1462
1499
  const certFile = import_node_path5.default.join(tmpDir, "certificate.pem");
1463
- await this.signCertificateRequest(certFile, csrFile, {
1500
+ const signingParams = {
1464
1501
  applicationUri: options.applicationUri,
1465
1502
  dns: options.dns,
1466
1503
  ip: options.ip,
1467
- startDate,
1468
- validity
1469
- });
1504
+ startDate
1505
+ };
1506
+ if (options.validityMs !== void 0) signingParams.validityMs = options.validityMs;
1507
+ else signingParams.validity = options.validity ?? 365;
1508
+ await this.signCertificateRequest(certFile, csrFile, signingParams);
1470
1509
  const certPem = (0, import_node_opcua_crypto2.readCertificatePEM)(certFile);
1471
1510
  const certificateDer = (0, import_node_opcua_crypto2.convertPEMtoDER)(certPem);
1472
1511
  const privateKey = (0, import_node_opcua_crypto2.readPrivateKey)(privateKeyFile);
@@ -1491,7 +1530,6 @@ var CertificateAuthority = class {
1491
1530
  */
1492
1531
  async generateKeyPairAndSignPFX(options) {
1493
1532
  const keySize = options.keySize ?? 2048;
1494
- const validity = options.validity ?? 365;
1495
1533
  const startDate = options.startDate ?? /* @__PURE__ */ new Date();
1496
1534
  const passphrase = options.passphrase ?? "";
1497
1535
  const tmpDir = await import_node_fs7.default.promises.mkdtemp(import_node_path5.default.join(import_node_os3.default.tmpdir(), "pki-keygen-pfx-"));
@@ -1512,13 +1550,15 @@ var CertificateAuthority = class {
1512
1550
  purpose: import_node_opcua_crypto2.CertificatePurpose.ForApplication
1513
1551
  });
1514
1552
  const certFile = import_node_path5.default.join(tmpDir, "certificate.pem");
1515
- await this.signCertificateRequest(certFile, csrFile, {
1553
+ const signingParams = {
1516
1554
  applicationUri: options.applicationUri,
1517
1555
  dns: options.dns,
1518
1556
  ip: options.ip,
1519
- startDate,
1520
- validity
1521
- });
1557
+ startDate
1558
+ };
1559
+ if (options.validityMs !== void 0) signingParams.validityMs = options.validityMs;
1560
+ else signingParams.validity = options.validity ?? 365;
1561
+ await this.signCertificateRequest(certFile, csrFile, signingParams);
1522
1562
  const pfxFile = import_node_path5.default.join(tmpDir, "bundle.pfx");
1523
1563
  await createPFX({
1524
1564
  certificateFile: certFile,