node-opcua-pki 6.21.0 → 6.22.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 +115 -11
- package/dist/bin/pki.mjs.map +1 -1
- package/dist/{chunk-2HTNH73K.mjs → chunk-EQ4DGI4M.mjs} +5 -1
- package/dist/chunk-EQ4DGI4M.mjs.map +1 -0
- package/dist/{core-C6faZClF.d.mts → core-BwqSJPHc.d.mts} +19 -10
- package/dist/{core-C6faZClF.d.ts → core-BwqSJPHc.d.ts} +19 -10
- package/dist/core.d.mts +1 -1
- package/dist/core.d.ts +1 -1
- package/dist/core.js.map +1 -1
- package/dist/core.mjs +1 -1
- package/dist/index.d.mts +48 -4
- package/dist/index.d.ts +48 -4
- package/dist/index.js +115 -11
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +119 -13
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
- package/dist/chunk-2HTNH73K.mjs.map +0 -1
package/dist/core.mjs
CHANGED
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { PrivateKey, Certificate, SubjectOptions, DER, CertificateRevocationList } from 'node-opcua-crypto';
|
|
2
|
-
export { PrivateKeyPassphraseRequiredError, Subject, SubjectOptions } from 'node-opcua-crypto';
|
|
3
|
-
import { C as CaBackend, a as CertificateAuthorityCore, P as Params, b as ProcessAltNamesParam, c as CertificateAuthorityCoreOptions, K as KeySize, d as PrivateKeyPassphrase, e as PrivateKeyProvider, f as CreateSelfSignCertificateParam, F as Filename } from './core-
|
|
4
|
-
export { g as CertificateStatus, h as CreateCertificateSigningRequestOptions, i as CreateCertificateSigningRequestWithConfigOptions, j as CreateSelfSignCertificateWithConfigParam, G as GenerateKeyPairAndSignOptions, k as GenerateKeyPairAndSignPFXOptions, I as InitializeCSRResult, l as InstallCACertificateResult, m as KeyLength, N as NativeCaBackend, n as PkiBackendCapabilities, S as SignCertificateOptions, o as StartDateEndDateParam, T as Thumbprint, p as adjustApplicationUri, q as adjustDate, r as
|
|
1
|
+
import { IKeyOperations, PrivateKey, Certificate, SubjectOptions, DER, CertificateRevocationList } from 'node-opcua-crypto';
|
|
2
|
+
export { AsymmetricDecryptParams, AsymmetricSignParams, IKeyOperations, KeyMetadata, PrivateKeyPassphraseRequiredError, PrivateKeyUnavailableError, Subject, SubjectOptions } from 'node-opcua-crypto';
|
|
3
|
+
import { C as CaBackend, a as CertificateAuthorityCore, P as Params, b as ProcessAltNamesParam, c as CertificateAuthorityCoreOptions, K as KeySize, d as PrivateKeyPassphrase, e as PrivateKeyProvider, f as CreateSelfSignCertificateParam, F as Filename } from './core-BwqSJPHc.mjs';
|
|
4
|
+
export { g as CertificateStatus, h as CreateCertificateSigningRequestOptions, i as CreateCertificateSigningRequestWithConfigOptions, j as CreateSelfSignCertificateWithConfigParam, G as GenerateKeyPairAndSignOptions, k as GenerateKeyPairAndSignPFXOptions, I as InitializeCSRResult, l as InstallCACertificateResult, m as KeyLength, N as NativeCaBackend, n as PkiBackendCapabilities, S as SignCertificateOptions, o as StartDateEndDateParam, T as Thumbprint, p as adjustApplicationUri, q as adjustDate, r as isOpaqueSigner, s as quote, t as resolvePrivateKeyPassphrase } from './core-BwqSJPHc.mjs';
|
|
5
5
|
import { EventEmitter } from 'node:events';
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -239,6 +239,29 @@ interface CertificateManagerOptions {
|
|
|
239
239
|
* ignored.
|
|
240
240
|
*/
|
|
241
241
|
privateKeyProvider?: PrivateKeyProvider;
|
|
242
|
+
/**
|
|
243
|
+
* Use a private key this manager can never read: an opaque
|
|
244
|
+
* {@link IKeyOperations} provider (HSM, KMS, TPM, OS keystore, ...).
|
|
245
|
+
*
|
|
246
|
+
* The distinction with `privateKeyProvider` matters: a
|
|
247
|
+
* `privateKeyProvider` *sources raw key material* from elsewhere and
|
|
248
|
+
* hands it back; `keyOperations` never reveals the key — only sign and
|
|
249
|
+
* decrypt operations on it. Prefer `keyOperations` whenever the key
|
|
250
|
+
* does not need to be exportable.
|
|
251
|
+
*
|
|
252
|
+
* When set:
|
|
253
|
+
* - {@link CertificateManager.getPrivateKey} and
|
|
254
|
+
* {@link CertificateManager.reencryptPrivateKey} throw
|
|
255
|
+
* `PrivateKeyUnavailableError` — there is no key material to return
|
|
256
|
+
* or rewrite, and no on-disk key is generated or expected;
|
|
257
|
+
* - {@link CertificateManager.getKeyOperations} returns this object;
|
|
258
|
+
* - `initialize()` fails closed if the provider cannot answer
|
|
259
|
+
* `getKeyMetadata()` (unreachable HSM, misconfiguration);
|
|
260
|
+
* - mutually exclusive with `privateKeyProvider` and
|
|
261
|
+
* `privateKeyPassphrase` — both describe key *material*, which an
|
|
262
|
+
* opaque configuration does not have.
|
|
263
|
+
*/
|
|
264
|
+
keyOperations?: IKeyOperations;
|
|
242
265
|
}
|
|
243
266
|
/**
|
|
244
267
|
* Parameters for {@link createSelfSignedCertificate}.
|
|
@@ -533,6 +556,27 @@ declare class CertificateManager extends EventEmitter {
|
|
|
533
556
|
* authority on what the current key is.
|
|
534
557
|
*/
|
|
535
558
|
getPrivateKey(): Promise<PrivateKey>;
|
|
559
|
+
/**
|
|
560
|
+
* True when this manager's key is opaque — configured through
|
|
561
|
+
* `keyOperations`, held by an HSM/KMS, never obtainable as material.
|
|
562
|
+
* When true, {@link getPrivateKey} throws `PrivateKeyUnavailableError`
|
|
563
|
+
* and {@link getKeyOperations} is the only way to use the key.
|
|
564
|
+
*/
|
|
565
|
+
isPrivateKeyOpaque(): boolean;
|
|
566
|
+
/**
|
|
567
|
+
* The key as an opaque {@link IKeyOperations} — the recommended way to
|
|
568
|
+
* *use* the private key regardless of where it lives.
|
|
569
|
+
*
|
|
570
|
+
* Returns the configured `keyOperations` object when the key is opaque.
|
|
571
|
+
* Otherwise returns a stable lazy wrap over {@link getPrivateKey}: its
|
|
572
|
+
* methods resolve the key on first use (disk read, passphrase,
|
|
573
|
+
* `privateKeyProvider` — all async), so the wrap offers no synchronous
|
|
574
|
+
* fast path; callers that need one resolve the key themselves and build
|
|
575
|
+
* a `LocalKeyOperations` over it. The wrap follows key rotation: a
|
|
576
|
+
* `privateKeyProvider` that starts returning a different key gets a
|
|
577
|
+
* fresh underlying `LocalKeyOperations`.
|
|
578
|
+
*/
|
|
579
|
+
getKeyOperations(): IKeyOperations;
|
|
536
580
|
/**
|
|
537
581
|
* Enable, disable, or rotate the passphrase protecting the on-disk
|
|
538
582
|
* private key: decrypt with `oldPassphrase` (omit if the key is
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { PrivateKey, Certificate, SubjectOptions, DER, CertificateRevocationList } from 'node-opcua-crypto';
|
|
2
|
-
export { PrivateKeyPassphraseRequiredError, Subject, SubjectOptions } from 'node-opcua-crypto';
|
|
3
|
-
import { C as CaBackend, a as CertificateAuthorityCore, P as Params, b as ProcessAltNamesParam, c as CertificateAuthorityCoreOptions, K as KeySize, d as PrivateKeyPassphrase, e as PrivateKeyProvider, f as CreateSelfSignCertificateParam, F as Filename } from './core-
|
|
4
|
-
export { g as CertificateStatus, h as CreateCertificateSigningRequestOptions, i as CreateCertificateSigningRequestWithConfigOptions, j as CreateSelfSignCertificateWithConfigParam, G as GenerateKeyPairAndSignOptions, k as GenerateKeyPairAndSignPFXOptions, I as InitializeCSRResult, l as InstallCACertificateResult, m as KeyLength, N as NativeCaBackend, n as PkiBackendCapabilities, S as SignCertificateOptions, o as StartDateEndDateParam, T as Thumbprint, p as adjustApplicationUri, q as adjustDate, r as
|
|
1
|
+
import { IKeyOperations, PrivateKey, Certificate, SubjectOptions, DER, CertificateRevocationList } from 'node-opcua-crypto';
|
|
2
|
+
export { AsymmetricDecryptParams, AsymmetricSignParams, IKeyOperations, KeyMetadata, PrivateKeyPassphraseRequiredError, PrivateKeyUnavailableError, Subject, SubjectOptions } from 'node-opcua-crypto';
|
|
3
|
+
import { C as CaBackend, a as CertificateAuthorityCore, P as Params, b as ProcessAltNamesParam, c as CertificateAuthorityCoreOptions, K as KeySize, d as PrivateKeyPassphrase, e as PrivateKeyProvider, f as CreateSelfSignCertificateParam, F as Filename } from './core-BwqSJPHc.js';
|
|
4
|
+
export { g as CertificateStatus, h as CreateCertificateSigningRequestOptions, i as CreateCertificateSigningRequestWithConfigOptions, j as CreateSelfSignCertificateWithConfigParam, G as GenerateKeyPairAndSignOptions, k as GenerateKeyPairAndSignPFXOptions, I as InitializeCSRResult, l as InstallCACertificateResult, m as KeyLength, N as NativeCaBackend, n as PkiBackendCapabilities, S as SignCertificateOptions, o as StartDateEndDateParam, T as Thumbprint, p as adjustApplicationUri, q as adjustDate, r as isOpaqueSigner, s as quote, t as resolvePrivateKeyPassphrase } from './core-BwqSJPHc.js';
|
|
5
5
|
import { EventEmitter } from 'node:events';
|
|
6
6
|
|
|
7
7
|
/**
|
|
@@ -239,6 +239,29 @@ interface CertificateManagerOptions {
|
|
|
239
239
|
* ignored.
|
|
240
240
|
*/
|
|
241
241
|
privateKeyProvider?: PrivateKeyProvider;
|
|
242
|
+
/**
|
|
243
|
+
* Use a private key this manager can never read: an opaque
|
|
244
|
+
* {@link IKeyOperations} provider (HSM, KMS, TPM, OS keystore, ...).
|
|
245
|
+
*
|
|
246
|
+
* The distinction with `privateKeyProvider` matters: a
|
|
247
|
+
* `privateKeyProvider` *sources raw key material* from elsewhere and
|
|
248
|
+
* hands it back; `keyOperations` never reveals the key — only sign and
|
|
249
|
+
* decrypt operations on it. Prefer `keyOperations` whenever the key
|
|
250
|
+
* does not need to be exportable.
|
|
251
|
+
*
|
|
252
|
+
* When set:
|
|
253
|
+
* - {@link CertificateManager.getPrivateKey} and
|
|
254
|
+
* {@link CertificateManager.reencryptPrivateKey} throw
|
|
255
|
+
* `PrivateKeyUnavailableError` — there is no key material to return
|
|
256
|
+
* or rewrite, and no on-disk key is generated or expected;
|
|
257
|
+
* - {@link CertificateManager.getKeyOperations} returns this object;
|
|
258
|
+
* - `initialize()` fails closed if the provider cannot answer
|
|
259
|
+
* `getKeyMetadata()` (unreachable HSM, misconfiguration);
|
|
260
|
+
* - mutually exclusive with `privateKeyProvider` and
|
|
261
|
+
* `privateKeyPassphrase` — both describe key *material*, which an
|
|
262
|
+
* opaque configuration does not have.
|
|
263
|
+
*/
|
|
264
|
+
keyOperations?: IKeyOperations;
|
|
242
265
|
}
|
|
243
266
|
/**
|
|
244
267
|
* Parameters for {@link createSelfSignedCertificate}.
|
|
@@ -533,6 +556,27 @@ declare class CertificateManager extends EventEmitter {
|
|
|
533
556
|
* authority on what the current key is.
|
|
534
557
|
*/
|
|
535
558
|
getPrivateKey(): Promise<PrivateKey>;
|
|
559
|
+
/**
|
|
560
|
+
* True when this manager's key is opaque — configured through
|
|
561
|
+
* `keyOperations`, held by an HSM/KMS, never obtainable as material.
|
|
562
|
+
* When true, {@link getPrivateKey} throws `PrivateKeyUnavailableError`
|
|
563
|
+
* and {@link getKeyOperations} is the only way to use the key.
|
|
564
|
+
*/
|
|
565
|
+
isPrivateKeyOpaque(): boolean;
|
|
566
|
+
/**
|
|
567
|
+
* The key as an opaque {@link IKeyOperations} — the recommended way to
|
|
568
|
+
* *use* the private key regardless of where it lives.
|
|
569
|
+
*
|
|
570
|
+
* Returns the configured `keyOperations` object when the key is opaque.
|
|
571
|
+
* Otherwise returns a stable lazy wrap over {@link getPrivateKey}: its
|
|
572
|
+
* methods resolve the key on first use (disk read, passphrase,
|
|
573
|
+
* `privateKeyProvider` — all async), so the wrap offers no synchronous
|
|
574
|
+
* fast path; callers that need one resolve the key themselves and build
|
|
575
|
+
* a `LocalKeyOperations` over it. The wrap follows key rotation: a
|
|
576
|
+
* `privateKeyProvider` that starts returning a different key gets a
|
|
577
|
+
* fresh underlying `LocalKeyOperations`.
|
|
578
|
+
*/
|
|
579
|
+
getKeyOperations(): IKeyOperations;
|
|
536
580
|
/**
|
|
537
581
|
* Enable, disable, or rotate the passphrase protecting the on-disk
|
|
538
582
|
* private key: decrypt with `oldPassphrase` (omit if the key is
|
package/dist/index.js
CHANGED
|
@@ -38,6 +38,7 @@ __export(lib_exports, {
|
|
|
38
38
|
NativeCaBackend: () => NativeCaBackend,
|
|
39
39
|
OpenSslCaBackend: () => OpenSslCaBackend,
|
|
40
40
|
PrivateKeyPassphraseRequiredError: () => import_node_opcua_crypto10.PrivateKeyPassphraseRequiredError,
|
|
41
|
+
PrivateKeyUnavailableError: () => import_node_opcua_crypto10.PrivateKeyUnavailableError,
|
|
41
42
|
Subject: () => import_node_opcua_crypto3.Subject,
|
|
42
43
|
VerificationStatus: () => VerificationStatus,
|
|
43
44
|
adjustApplicationUri: () => adjustApplicationUri,
|
|
@@ -54,6 +55,7 @@ __export(lib_exports, {
|
|
|
54
55
|
install_prerequisite: () => install_prerequisite,
|
|
55
56
|
isIntermediateIssuer: () => isIntermediateIssuer,
|
|
56
57
|
isIssuer: () => isIssuer,
|
|
58
|
+
isOpaqueSigner: () => isOpaqueSigner,
|
|
57
59
|
isRootIssuer: () => isRootIssuer,
|
|
58
60
|
makeFingerprint: () => makeFingerprint,
|
|
59
61
|
quote: () => quote,
|
|
@@ -72,6 +74,9 @@ var import_node_assert = __toESM(require("assert"));
|
|
|
72
74
|
function quote(str) {
|
|
73
75
|
return `"${str || ""}"`;
|
|
74
76
|
}
|
|
77
|
+
function isOpaqueSigner(privateKey) {
|
|
78
|
+
return typeof privateKey !== "string" && typeof privateKey.sign === "function";
|
|
79
|
+
}
|
|
75
80
|
async function resolvePrivateKeyPassphrase(passphrase) {
|
|
76
81
|
if (passphrase === void 0) {
|
|
77
82
|
return void 0;
|
|
@@ -2887,8 +2892,9 @@ async function createCertificateSigningRequestAsync(certificateSigningRequestFil
|
|
|
2887
2892
|
(0, import_node_assert6.default)(typeof certificateSigningRequestFilename === "string");
|
|
2888
2893
|
const subject = params.subject ? new import_node_opcua_crypto6.Subject(params.subject).toString() : void 0;
|
|
2889
2894
|
displaySubtitle("- Creating a Certificate Signing Request with subtile");
|
|
2890
|
-
const
|
|
2891
|
-
|
|
2895
|
+
const privateKey = isOpaqueSigner(params.privateKey) ? params.privateKey : await (0, import_node_opcua_crypto6.pemToPrivateKey)(
|
|
2896
|
+
typeof params.privateKey === "string" ? await import_node_fs9.default.promises.readFile(params.privateKey, "utf-8") : (0, import_node_opcua_crypto6.coercePrivateKeyPem)(params.privateKey)
|
|
2897
|
+
);
|
|
2892
2898
|
const { csr } = await (0, import_node_opcua_crypto6.createCertificateSigningRequest)({
|
|
2893
2899
|
privateKey,
|
|
2894
2900
|
dns: params.dns,
|
|
@@ -2898,7 +2904,9 @@ async function createCertificateSigningRequestAsync(certificateSigningRequestFil
|
|
|
2898
2904
|
purpose: params.purpose
|
|
2899
2905
|
});
|
|
2900
2906
|
await import_node_fs9.default.promises.writeFile(certificateSigningRequestFilename, csr, "utf-8");
|
|
2901
|
-
display(
|
|
2907
|
+
display(
|
|
2908
|
+
`- privateKey ${typeof params.privateKey === "string" ? params.privateKey : isOpaqueSigner(params.privateKey) ? "<opaque-signer>" : "<in-memory>"}`
|
|
2909
|
+
);
|
|
2902
2910
|
display(`- certificateSigningRequestFilename ${certificateSigningRequestFilename}`);
|
|
2903
2911
|
}
|
|
2904
2912
|
|
|
@@ -2925,8 +2933,9 @@ async function createSelfSignedCertificateAsync(certificate, params) {
|
|
|
2925
2933
|
subject = subject.toString();
|
|
2926
2934
|
const purpose = params.purpose;
|
|
2927
2935
|
displayTitle("Generate a certificate request");
|
|
2928
|
-
const
|
|
2929
|
-
|
|
2936
|
+
const privateKey = isOpaqueSigner(params.privateKey) ? params.privateKey : await (0, import_node_opcua_crypto7.pemToPrivateKey)(
|
|
2937
|
+
typeof params.privateKey === "string" ? await import_node_fs10.default.promises.readFile(params.privateKey, "utf-8") : (0, import_node_opcua_crypto7.coercePrivateKeyPem)(params.privateKey)
|
|
2938
|
+
);
|
|
2930
2939
|
const { cert } = await (0, import_node_opcua_crypto7.createSelfSignedCertificate)({
|
|
2931
2940
|
privateKey,
|
|
2932
2941
|
notBefore: params.startDate,
|
|
@@ -3231,6 +3240,9 @@ var CertificateManager = class _CertificateManager extends import_node_events.Ev
|
|
|
3231
3240
|
#disableFileWatchers;
|
|
3232
3241
|
#privateKeyPassphrase;
|
|
3233
3242
|
#privateKeyProvider;
|
|
3243
|
+
#keyOperations;
|
|
3244
|
+
/** The stable lazy wrap handed out by {@link getKeyOperations} for non-opaque configurations. */
|
|
3245
|
+
#lazyLocalKeyOperations;
|
|
3234
3246
|
/**
|
|
3235
3247
|
* The on-disk key, decrypted once and kept for the instance's lifetime,
|
|
3236
3248
|
* so the passphrase (or its resolver function) is consulted at most
|
|
@@ -3274,6 +3286,17 @@ var CertificateManager = class _CertificateManager extends import_node_events.Ev
|
|
|
3274
3286
|
this.#disableFileWatchers = options.disableFileWatchers ?? process.env.OPCUA_PKI_DISABLE_FILE_WATCHERS === "true";
|
|
3275
3287
|
this.#privateKeyPassphrase = options.privateKeyPassphrase;
|
|
3276
3288
|
this.#privateKeyProvider = options.privateKeyProvider;
|
|
3289
|
+
this.#keyOperations = options.keyOperations;
|
|
3290
|
+
if (this.#keyOperations && this.#privateKeyProvider) {
|
|
3291
|
+
throw new Error(
|
|
3292
|
+
"CertificateManager: 'keyOperations' and 'privateKeyProvider' are mutually exclusive: one hides the key, the other sources its material"
|
|
3293
|
+
);
|
|
3294
|
+
}
|
|
3295
|
+
if (this.#keyOperations && this.#privateKeyPassphrase) {
|
|
3296
|
+
throw new Error(
|
|
3297
|
+
"CertificateManager: 'privateKeyPassphrase' is meaningless with 'keyOperations': there is no key material for a passphrase to protect"
|
|
3298
|
+
);
|
|
3299
|
+
}
|
|
3277
3300
|
mkdirRecursiveSync(options.location);
|
|
3278
3301
|
if (!import_node_fs11.default.existsSync(this.#location)) {
|
|
3279
3302
|
throw new Error(`CertificateManager cannot access location ${this.#location}`);
|
|
@@ -3315,6 +3338,11 @@ var CertificateManager = class _CertificateManager extends import_node_events.Ev
|
|
|
3315
3338
|
* authority on what the current key is.
|
|
3316
3339
|
*/
|
|
3317
3340
|
async getPrivateKey() {
|
|
3341
|
+
if (this.#keyOperations) {
|
|
3342
|
+
throw new import_node_opcua_crypto8.PrivateKeyUnavailableError(
|
|
3343
|
+
"CertificateManager.getPrivateKey is not available when keyOperations is configured: the private key is held by the key-operations provider (HSM/KMS) and cannot be read \u2014 use getKeyOperations() instead"
|
|
3344
|
+
);
|
|
3345
|
+
}
|
|
3318
3346
|
if (this.#privateKeyProvider) {
|
|
3319
3347
|
return await this.#privateKeyProvider.getPrivateKey();
|
|
3320
3348
|
}
|
|
@@ -3340,6 +3368,75 @@ var CertificateManager = class _CertificateManager extends import_node_events.Ev
|
|
|
3340
3368
|
}
|
|
3341
3369
|
/** In-flight first read of the on-disk key, so concurrent callers share one passphrase resolution. */
|
|
3342
3370
|
#privateKeyPromise;
|
|
3371
|
+
/**
|
|
3372
|
+
* True when this manager's key is opaque — configured through
|
|
3373
|
+
* `keyOperations`, held by an HSM/KMS, never obtainable as material.
|
|
3374
|
+
* When true, {@link getPrivateKey} throws `PrivateKeyUnavailableError`
|
|
3375
|
+
* and {@link getKeyOperations} is the only way to use the key.
|
|
3376
|
+
*/
|
|
3377
|
+
isPrivateKeyOpaque() {
|
|
3378
|
+
return !!this.#keyOperations;
|
|
3379
|
+
}
|
|
3380
|
+
/**
|
|
3381
|
+
* The key as an opaque {@link IKeyOperations} — the recommended way to
|
|
3382
|
+
* *use* the private key regardless of where it lives.
|
|
3383
|
+
*
|
|
3384
|
+
* Returns the configured `keyOperations` object when the key is opaque.
|
|
3385
|
+
* Otherwise returns a stable lazy wrap over {@link getPrivateKey}: its
|
|
3386
|
+
* methods resolve the key on first use (disk read, passphrase,
|
|
3387
|
+
* `privateKeyProvider` — all async), so the wrap offers no synchronous
|
|
3388
|
+
* fast path; callers that need one resolve the key themselves and build
|
|
3389
|
+
* a `LocalKeyOperations` over it. The wrap follows key rotation: a
|
|
3390
|
+
* `privateKeyProvider` that starts returning a different key gets a
|
|
3391
|
+
* fresh underlying `LocalKeyOperations`.
|
|
3392
|
+
*/
|
|
3393
|
+
getKeyOperations() {
|
|
3394
|
+
if (this.#keyOperations) {
|
|
3395
|
+
return this.#keyOperations;
|
|
3396
|
+
}
|
|
3397
|
+
if (!this.#lazyLocalKeyOperations) {
|
|
3398
|
+
let cached;
|
|
3399
|
+
const resolve = async () => {
|
|
3400
|
+
const key = await this.getPrivateKey();
|
|
3401
|
+
if (!cached || cached.key !== key) {
|
|
3402
|
+
cached = { key, ops: (0, import_node_opcua_crypto8.keyOperationsFromPrivateKey)(key) };
|
|
3403
|
+
}
|
|
3404
|
+
return cached.ops;
|
|
3405
|
+
};
|
|
3406
|
+
this.#lazyLocalKeyOperations = {
|
|
3407
|
+
sign: async (data, params) => (await resolve()).sign(data, params),
|
|
3408
|
+
decryptBlock: async (block, params) => (await resolve()).decryptBlock(block, params),
|
|
3409
|
+
getKeyMetadata: async () => (await resolve()).getKeyMetadata(),
|
|
3410
|
+
getPublicKey: async () => (await resolve()).getPublicKey()
|
|
3411
|
+
};
|
|
3412
|
+
}
|
|
3413
|
+
return this.#lazyLocalKeyOperations;
|
|
3414
|
+
}
|
|
3415
|
+
/**
|
|
3416
|
+
* Fail closed at `initialize()` time, not on the first certificate
|
|
3417
|
+
* operation, if the key cannot actually be used: wrong/missing
|
|
3418
|
+
* passphrase on an encrypted key, a broken `privateKeyProvider`, or an
|
|
3419
|
+
* unreachable `keyOperations` provider (probed via `getKeyMetadata`).
|
|
3420
|
+
*/
|
|
3421
|
+
async #probePrivateKey() {
|
|
3422
|
+
if (this.#keyOperations) {
|
|
3423
|
+
await this.#keyOperations.getKeyMetadata();
|
|
3424
|
+
return;
|
|
3425
|
+
}
|
|
3426
|
+
await this.getPrivateKey();
|
|
3427
|
+
}
|
|
3428
|
+
/**
|
|
3429
|
+
* The key to hand to a certificate-issuance primitive: the raw
|
|
3430
|
+
* {@link PrivateKey} for a local configuration, or a {@link CaSigner}
|
|
3431
|
+
* adapted from `keyOperations` when the key is opaque — which requires
|
|
3432
|
+
* the provider to implement `getPublicKey` (the adapter says so if not).
|
|
3433
|
+
*/
|
|
3434
|
+
async #resolveSigningKey() {
|
|
3435
|
+
if (this.#keyOperations) {
|
|
3436
|
+
return (0, import_node_opcua_crypto8.caSignerFromKeyOperations)(this.#keyOperations);
|
|
3437
|
+
}
|
|
3438
|
+
return await this.getPrivateKey();
|
|
3439
|
+
}
|
|
3343
3440
|
/**
|
|
3344
3441
|
* Enable, disable, or rotate the passphrase protecting the on-disk
|
|
3345
3442
|
* private key: decrypt with `oldPassphrase` (omit if the key is
|
|
@@ -3361,6 +3458,11 @@ var CertificateManager = class _CertificateManager extends import_node_events.Ev
|
|
|
3361
3458
|
* disk file for this method to rewrite).
|
|
3362
3459
|
*/
|
|
3363
3460
|
async reencryptPrivateKey(oldPassphrase, newPassphrase) {
|
|
3461
|
+
if (this.#keyOperations) {
|
|
3462
|
+
throw new import_node_opcua_crypto8.PrivateKeyUnavailableError(
|
|
3463
|
+
"reencryptPrivateKey: not supported when keyOperations is configured \u2014 there is no key material to rewrite"
|
|
3464
|
+
);
|
|
3465
|
+
}
|
|
3364
3466
|
if (this.#privateKeyProvider) {
|
|
3365
3467
|
throw new Error("reencryptPrivateKey: not supported when a privateKeyProvider is configured");
|
|
3366
3468
|
}
|
|
@@ -3709,7 +3811,7 @@ var CertificateManager = class _CertificateManager extends import_node_events.Ev
|
|
|
3709
3811
|
mkdirRecursiveSync(import_node_path8.default.join(pkiDir, "issuers"));
|
|
3710
3812
|
mkdirRecursiveSync(import_node_path8.default.join(pkiDir, "issuers/certs"));
|
|
3711
3813
|
mkdirRecursiveSync(import_node_path8.default.join(pkiDir, "issuers/crl"));
|
|
3712
|
-
const ownsDiskKey = !this.#privateKeyProvider;
|
|
3814
|
+
const ownsDiskKey = !this.#privateKeyProvider && !this.#keyOperations;
|
|
3713
3815
|
const needsKeyGeneration = ownsDiskKey && !import_node_fs11.default.existsSync(this.privateKey);
|
|
3714
3816
|
const needsKeyEncryption = ownsDiskKey && !needsKeyGeneration && this.#privateKeyPassphrase !== void 0 && !isEncryptedPrivateKeyFile(this.privateKey);
|
|
3715
3817
|
if (!import_node_fs11.default.existsSync(this.configFile) || needsKeyGeneration || needsKeyEncryption) {
|
|
@@ -3735,14 +3837,14 @@ var CertificateManager = class _CertificateManager extends import_node_events.Ev
|
|
|
3735
3837
|
if (ownsDiskKey) {
|
|
3736
3838
|
restrictPrivateFilePermissions(this.privateKey, 384);
|
|
3737
3839
|
}
|
|
3738
|
-
await this
|
|
3840
|
+
await this.#probePrivateKey();
|
|
3739
3841
|
await this.#readCertificates();
|
|
3740
3842
|
});
|
|
3741
3843
|
} else {
|
|
3742
3844
|
if (ownsDiskKey) {
|
|
3743
3845
|
restrictPrivateFilePermissions(this.privateKey, 384);
|
|
3744
3846
|
}
|
|
3745
|
-
await this
|
|
3847
|
+
await this.#probePrivateKey();
|
|
3746
3848
|
await this.#readCertificates();
|
|
3747
3849
|
}
|
|
3748
3850
|
}
|
|
@@ -3827,7 +3929,7 @@ var CertificateManager = class _CertificateManager extends import_node_events.Ev
|
|
|
3827
3929
|
if (typeof params.applicationUri !== "string") {
|
|
3828
3930
|
throw new Error("createSelfSignedCertificate: expecting applicationUri to be a string");
|
|
3829
3931
|
}
|
|
3830
|
-
if (!this.#privateKeyProvider && !import_node_fs11.default.existsSync(this.privateKey)) {
|
|
3932
|
+
if (!this.#privateKeyProvider && !this.#keyOperations && !import_node_fs11.default.existsSync(this.privateKey)) {
|
|
3831
3933
|
throw new Error(`Cannot find private key ${this.privateKey}`);
|
|
3832
3934
|
}
|
|
3833
3935
|
let certificateFilename = import_node_path8.default.join(this.rootDir, "own/certs/self_signed_certificate.pem");
|
|
@@ -3836,7 +3938,7 @@ var CertificateManager = class _CertificateManager extends import_node_events.Ev
|
|
|
3836
3938
|
...params,
|
|
3837
3939
|
rootDir: this.rootDir,
|
|
3838
3940
|
configFile: this.configFile,
|
|
3839
|
-
privateKey: await this
|
|
3941
|
+
privateKey: await this.#resolveSigningKey(),
|
|
3840
3942
|
subject: params.subject || "CN=FIXME"
|
|
3841
3943
|
};
|
|
3842
3944
|
await this.withLock2(async () => {
|
|
@@ -3864,7 +3966,7 @@ var CertificateManager = class _CertificateManager extends import_node_events.Ev
|
|
|
3864
3966
|
...params,
|
|
3865
3967
|
rootDir: import_node_path8.default.resolve(this.rootDir),
|
|
3866
3968
|
configFile: import_node_path8.default.resolve(this.configFile),
|
|
3867
|
-
privateKey: await this
|
|
3969
|
+
privateKey: await this.#resolveSigningKey()
|
|
3868
3970
|
};
|
|
3869
3971
|
return await this.withLock2(async () => {
|
|
3870
3972
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -4840,6 +4942,7 @@ async function dumpPFX(pfxFile, passphrase = "") {
|
|
|
4840
4942
|
NativeCaBackend,
|
|
4841
4943
|
OpenSslCaBackend,
|
|
4842
4944
|
PrivateKeyPassphraseRequiredError,
|
|
4945
|
+
PrivateKeyUnavailableError,
|
|
4843
4946
|
Subject,
|
|
4844
4947
|
VerificationStatus,
|
|
4845
4948
|
adjustApplicationUri,
|
|
@@ -4856,6 +4959,7 @@ async function dumpPFX(pfxFile, passphrase = "") {
|
|
|
4856
4959
|
install_prerequisite,
|
|
4857
4960
|
isIntermediateIssuer,
|
|
4858
4961
|
isIssuer,
|
|
4962
|
+
isOpaqueSigner,
|
|
4859
4963
|
isRootIssuer,
|
|
4860
4964
|
makeFingerprint,
|
|
4861
4965
|
quote,
|