node-opcua-server-configuration 2.166.0 → 2.168.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/clientTools/push_certificate_management_client.d.ts +2 -2
- package/dist/clientTools/push_certificate_management_client.js +9 -2
- package/dist/clientTools/push_certificate_management_client.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/server/{install_push_certitifate_management.d.ts → install_push_certificate_management.d.ts} +4 -7
- package/dist/server/install_push_certificate_management.js +122 -0
- package/dist/server/install_push_certificate_management.js.map +1 -0
- package/dist/server/promote_trust_list.js +32 -4
- package/dist/server/promote_trust_list.js.map +1 -1
- package/dist/server/push_certificate_manager/create_signing_request.js +3 -3
- package/dist/server/push_certificate_manager/create_signing_request.js.map +1 -1
- package/dist/server/push_certificate_manager/update_certificate.js +12 -3
- package/dist/server/push_certificate_manager/update_certificate.js.map +1 -1
- package/dist/server/push_certificate_manager_helpers.js +3 -3
- package/dist/server/push_certificate_manager_helpers.js.map +1 -1
- package/dist/server/push_certificate_manager_server_impl.js.map +1 -1
- package/dist/server/trust_list_server.js +9 -3
- package/dist/server/trust_list_server.js.map +1 -1
- package/package.json +25 -27
- package/source/clientTools/push_certificate_management_client.ts +11 -3
- package/source/index.ts +1 -1
- package/source/server/install_push_certificate_management.ts +160 -0
- package/source/server/promote_trust_list.ts +41 -9
- package/source/server/push_certificate_manager/create_signing_request.ts +3 -3
- package/source/server/push_certificate_manager/update_certificate.ts +16 -5
- package/source/server/push_certificate_manager_helpers.ts +3 -3
- package/source/server/push_certificate_manager_server_impl.ts +3 -9
- package/source/server/trust_list_server.ts +9 -3
- package/dist/server/install_push_certitifate_management.js +0 -178
- package/dist/server/install_push_certitifate_management.js.map +0 -1
- package/source/server/install_push_certitifate_management.ts +0 -250
|
@@ -2,13 +2,18 @@ import fs from "node:fs";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { BinaryStream } from "node-opcua-binary-stream";
|
|
4
4
|
import type { OPCUACertificateManager } from "node-opcua-certificate-manager";
|
|
5
|
-
import {
|
|
5
|
+
import { readCertificateChainAsync, readCertificateRevocationList } from "node-opcua-crypto";
|
|
6
6
|
import { make_errorLog } from "node-opcua-debug";
|
|
7
7
|
import type { AbstractFs } from "node-opcua-file-transfer";
|
|
8
8
|
import { TrustListDataType } from "node-opcua-types";
|
|
9
9
|
|
|
10
10
|
const errorLog = make_errorLog("TrustListServer");
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Read all certificate (chains) and CRLs in a folder
|
|
14
|
+
* @param folder
|
|
15
|
+
* @returns
|
|
16
|
+
*/
|
|
12
17
|
async function readAll(folder: string): Promise<Buffer[]> {
|
|
13
18
|
const results: Buffer[] = [];
|
|
14
19
|
const files = await fs.promises.readdir(folder);
|
|
@@ -16,8 +21,9 @@ async function readAll(folder: string): Promise<Buffer[]> {
|
|
|
16
21
|
const file = path.join(folder, f);
|
|
17
22
|
const ext = path.extname(file);
|
|
18
23
|
if (ext === ".der" || ext === ".pem") {
|
|
19
|
-
const
|
|
20
|
-
|
|
24
|
+
const chain = await readCertificateChainAsync(file);
|
|
25
|
+
const concatenated = Buffer.concat(chain);
|
|
26
|
+
results.push(concatenated);
|
|
21
27
|
} else if (ext === ".crl") {
|
|
22
28
|
// Strict validation: only accept valid CRL files
|
|
23
29
|
const buf = await readCertificateRevocationList(file);
|
|
@@ -1,178 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module node-opcua-server-configuration-server
|
|
3
|
-
*/
|
|
4
|
-
import fs from "node:fs";
|
|
5
|
-
import path from "node:path";
|
|
6
|
-
import chalk from "chalk";
|
|
7
|
-
import { assert } from "node-opcua-assert";
|
|
8
|
-
import { readPrivateKey } from "node-opcua-crypto";
|
|
9
|
-
import { convertPEMtoDER, split_der } from "node-opcua-crypto/web";
|
|
10
|
-
import { checkDebugFlag, make_debugLog, make_errorLog } from "node-opcua-debug";
|
|
11
|
-
import { getFullyQualifiedDomainName, getIpAddresses } from "node-opcua-hostname";
|
|
12
|
-
import { installPushCertificateManagement } from "./push_certificate_manager_helpers.js";
|
|
13
|
-
// node 14 onward : import { readFile } from "fs/promises";
|
|
14
|
-
const { readFile } = fs.promises;
|
|
15
|
-
const debugLog = make_debugLog("ServerConfiguration");
|
|
16
|
-
const errorLog = make_errorLog("ServerConfiguration");
|
|
17
|
-
const doDebug = checkDebugFlag("ServerConfiguration");
|
|
18
|
-
function getCertificate() {
|
|
19
|
-
if (!this.$$certificate) {
|
|
20
|
-
const certificateChain = getCertificateChain.call(this);
|
|
21
|
-
this.$$certificate = split_der(certificateChain)[0];
|
|
22
|
-
}
|
|
23
|
-
return this.$$certificate;
|
|
24
|
-
}
|
|
25
|
-
function getCertificateChain() {
|
|
26
|
-
if (!this.$$certificateChain) {
|
|
27
|
-
throw new Error("internal Error. cannot find $$certificateChain");
|
|
28
|
-
}
|
|
29
|
-
return this.$$certificateChain;
|
|
30
|
-
}
|
|
31
|
-
function getPrivateKey() {
|
|
32
|
-
// c8 ignore next
|
|
33
|
-
if (!this.$$privateKey) {
|
|
34
|
-
throw new Error("internal Error. cannot find $$privateKey");
|
|
35
|
-
}
|
|
36
|
-
return this.$$privateKey;
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
*
|
|
40
|
-
*/
|
|
41
|
-
async function install() {
|
|
42
|
-
doDebug && debugLog("install push certificate management", this.serverCertificateManager.rootDir);
|
|
43
|
-
Object.defineProperty(this, "privateKeyFile", {
|
|
44
|
-
get: () => this.serverCertificateManager.privateKey,
|
|
45
|
-
configurable: true
|
|
46
|
-
});
|
|
47
|
-
Object.defineProperty(this, "certificateFile", {
|
|
48
|
-
get: () => path.join(this.serverCertificateManager.rootDir, "own/certs/certificate.pem"),
|
|
49
|
-
configurable: true
|
|
50
|
-
});
|
|
51
|
-
if (!this.$$privateKey) {
|
|
52
|
-
this.$$privateKey = readPrivateKey(this.serverCertificateManager.privateKey);
|
|
53
|
-
}
|
|
54
|
-
if (!this.$$certificateChain) {
|
|
55
|
-
const certificateFile = this.certificateFile;
|
|
56
|
-
if (!fs.existsSync(certificateFile)) {
|
|
57
|
-
// this is the first time server is launch
|
|
58
|
-
// let's create a default self signed certificate with limited validity
|
|
59
|
-
const fqdn = await getFullyQualifiedDomainName();
|
|
60
|
-
const ipAddresses = await getIpAddresses();
|
|
61
|
-
const applicationUri = (this.serverInfo ? this.serverInfo.applicationUri : null) || "uri:MISSING";
|
|
62
|
-
const options = {
|
|
63
|
-
applicationUri,
|
|
64
|
-
dns: [fqdn],
|
|
65
|
-
ip: ipAddresses,
|
|
66
|
-
subject: `/CN=${applicationUri};/L=Paris`,
|
|
67
|
-
startDate: new Date(),
|
|
68
|
-
validity: 365 * 5, // five year
|
|
69
|
-
/* */
|
|
70
|
-
outputFile: certificateFile
|
|
71
|
-
};
|
|
72
|
-
doDebug && debugLog("creating self signed certificate", options);
|
|
73
|
-
await this.serverCertificateManager.createSelfSignedCertificate(options);
|
|
74
|
-
}
|
|
75
|
-
const certificatePEM = await readFile(certificateFile, "utf8");
|
|
76
|
-
this.$$certificateChain = convertPEMtoDER(certificatePEM);
|
|
77
|
-
// await this.serverCertificateManager.trustCertificate( this.$$certificateChain);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
function getCertificateChainEP() {
|
|
81
|
-
const certificateFile = path.join(this.certificateManager.rootDir, "own/certs/certificate.pem");
|
|
82
|
-
const certificatePEM = fs.readFileSync(certificateFile, "utf8");
|
|
83
|
-
const $$certificateChain = convertPEMtoDER(certificatePEM);
|
|
84
|
-
return $$certificateChain;
|
|
85
|
-
}
|
|
86
|
-
function getPrivateKeyEP() {
|
|
87
|
-
const privateKey = readPrivateKey(this.certificateManager.privateKey);
|
|
88
|
-
return privateKey;
|
|
89
|
-
}
|
|
90
|
-
async function onCertificateAboutToChange(server) {
|
|
91
|
-
doDebug && debugLog(chalk.yellow(" onCertificateAboutToChange => Suspending End points"));
|
|
92
|
-
await server.suspendEndPoints();
|
|
93
|
-
doDebug && debugLog(chalk.yellow(" onCertificateAboutToChange => End points suspended"));
|
|
94
|
-
}
|
|
95
|
-
/**
|
|
96
|
-
* onCertificateChange is called when the serverConfiguration notifies
|
|
97
|
-
* that the server certificate and/or private key has changed.
|
|
98
|
-
*
|
|
99
|
-
* this function suspends all endpoint listeners and stop all existing channels
|
|
100
|
-
* then start all endpoint listener
|
|
101
|
-
*
|
|
102
|
-
* @param server
|
|
103
|
-
*/
|
|
104
|
-
async function onCertificateChange(server) {
|
|
105
|
-
doDebug && debugLog("on CertificateChanged");
|
|
106
|
-
const _server = server;
|
|
107
|
-
_server.$$privateKey = readPrivateKey(server.serverCertificateManager.privateKey);
|
|
108
|
-
const certificateFile = path.join(server.serverCertificateManager.rootDir, "own/certs/certificate.pem");
|
|
109
|
-
const certificatePEM = fs.readFileSync(certificateFile, "utf8");
|
|
110
|
-
const privateKeyFile = server.serverCertificateManager.privateKey;
|
|
111
|
-
const privateKey = readPrivateKey(privateKeyFile);
|
|
112
|
-
// also reread the private key
|
|
113
|
-
_server.$$certificateChain = convertPEMtoDER(certificatePEM);
|
|
114
|
-
_server.$$privateKey = privateKey;
|
|
115
|
-
// note : $$certificate will be reconstructed on demand
|
|
116
|
-
_server.$$certificate = split_der(_server.$$certificateChain)[0];
|
|
117
|
-
setTimeout(async () => {
|
|
118
|
-
try {
|
|
119
|
-
doDebug && debugLog(chalk.yellow(" onCertificateChange => shutting down channels"));
|
|
120
|
-
await server.shutdownChannels();
|
|
121
|
-
doDebug && debugLog(chalk.yellow(" onCertificateChange => channels shut down"));
|
|
122
|
-
doDebug && debugLog(chalk.yellow(" onCertificateChange => resuming end points"));
|
|
123
|
-
await server.resumeEndPoints();
|
|
124
|
-
doDebug && debugLog(chalk.yellow(" onCertificateChange => end points resumed"));
|
|
125
|
-
debugLog(chalk.yellow("channels have been closed -> client should reconnect "));
|
|
126
|
-
}
|
|
127
|
-
catch (err) {
|
|
128
|
-
errorLog("Error in CertificateChanged handler ", err.message);
|
|
129
|
-
debugLog("err = ", err);
|
|
130
|
-
}
|
|
131
|
-
}, 2000);
|
|
132
|
-
}
|
|
133
|
-
export async function installPushCertificateManagementOnServer(server) {
|
|
134
|
-
if (!server.engine || !server.engine.addressSpace) {
|
|
135
|
-
throw new Error("Server must have a valid address space." +
|
|
136
|
-
"you need to call installPushCertificateManagementOnServer after server has been initialized");
|
|
137
|
-
}
|
|
138
|
-
await install.call(server);
|
|
139
|
-
server.getCertificate = getCertificate;
|
|
140
|
-
server.getCertificateChain = getCertificateChain;
|
|
141
|
-
server.getPrivateKey = getPrivateKey;
|
|
142
|
-
for (const endpoint of server.endpoints) {
|
|
143
|
-
const endpointPriv = endpoint;
|
|
144
|
-
endpointPriv._certificateChain = null;
|
|
145
|
-
endpointPriv._privateKey = null;
|
|
146
|
-
endpoint.getCertificateChain = getCertificateChainEP;
|
|
147
|
-
endpoint.getPrivateKey = getPrivateKeyEP;
|
|
148
|
-
for (const e of endpoint.endpointDescriptions()) {
|
|
149
|
-
Object.defineProperty(e, "serverCertificate", {
|
|
150
|
-
get: () => endpoint.getCertificate(),
|
|
151
|
-
configurable: true
|
|
152
|
-
});
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
await installPushCertificateManagement(server.engine.addressSpace, {
|
|
156
|
-
applicationGroup: server.serverCertificateManager,
|
|
157
|
-
userTokenGroup: server.userCertificateManager,
|
|
158
|
-
applicationUri: server.serverInfo.applicationUri || "InvalidURI"
|
|
159
|
-
});
|
|
160
|
-
const serverConfiguration = server.engine.addressSpace.rootFolder.objects.server.getChildByName("ServerConfiguration");
|
|
161
|
-
const serverConfigurationPriv = serverConfiguration;
|
|
162
|
-
assert(serverConfigurationPriv.$pushCertificateManager);
|
|
163
|
-
serverConfigurationPriv.$pushCertificateManager.on("CertificateAboutToChange", (actionQueue) => {
|
|
164
|
-
actionQueue.push(async () => {
|
|
165
|
-
doDebug && debugLog("CertificateAboutToChange Event received");
|
|
166
|
-
await onCertificateAboutToChange(server);
|
|
167
|
-
doDebug && debugLog("CertificateAboutToChange Event processed");
|
|
168
|
-
});
|
|
169
|
-
});
|
|
170
|
-
serverConfigurationPriv.$pushCertificateManager.on("CertificateChanged", (actionQueue) => {
|
|
171
|
-
actionQueue.push(async () => {
|
|
172
|
-
doDebug && debugLog("CertificateChanged Event received");
|
|
173
|
-
await onCertificateChange(server);
|
|
174
|
-
doDebug && debugLog("CertificateChanged Event processed");
|
|
175
|
-
});
|
|
176
|
-
});
|
|
177
|
-
}
|
|
178
|
-
//# sourceMappingURL=install_push_certitifate_management.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"install_push_certitifate_management.js","sourceRoot":"","sources":["../../source/server/install_push_certitifate_management.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,250 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module node-opcua-server-configuration-server
|
|
3
|
-
*/
|
|
4
|
-
import fs from "node:fs";
|
|
5
|
-
import path from "node:path";
|
|
6
|
-
|
|
7
|
-
import chalk from "chalk";
|
|
8
|
-
|
|
9
|
-
import type { AddressSpace, UAServerConfiguration } from "node-opcua-address-space";
|
|
10
|
-
import { assert } from "node-opcua-assert";
|
|
11
|
-
import type { OPCUACertificateManager } from "node-opcua-certificate-manager";
|
|
12
|
-
import type { ICertificateKeyPairProviderPriv } from "node-opcua-common";
|
|
13
|
-
import { readPrivateKey } from "node-opcua-crypto";
|
|
14
|
-
import { type Certificate, convertPEMtoDER, type PrivateKey, split_der } from "node-opcua-crypto/web";
|
|
15
|
-
import { checkDebugFlag, make_debugLog, make_errorLog } from "node-opcua-debug";
|
|
16
|
-
import { getFullyQualifiedDomainName, getIpAddresses } from "node-opcua-hostname";
|
|
17
|
-
import type { OPCUAServer, OPCUAServerEndPoint } from "node-opcua-server";
|
|
18
|
-
import type { ApplicationDescriptionOptions } from "node-opcua-types";
|
|
19
|
-
|
|
20
|
-
import { installPushCertificateManagement } from "./push_certificate_manager_helpers.js";
|
|
21
|
-
import type { ActionQueue, PushCertificateManagerServerImpl } from "./push_certificate_manager_server_impl.js";
|
|
22
|
-
|
|
23
|
-
// node 14 onward : import { readFile } from "fs/promises";
|
|
24
|
-
const { readFile } = fs.promises;
|
|
25
|
-
|
|
26
|
-
const debugLog = make_debugLog("ServerConfiguration");
|
|
27
|
-
const errorLog = make_errorLog("ServerConfiguration");
|
|
28
|
-
const doDebug = checkDebugFlag("ServerConfiguration");
|
|
29
|
-
|
|
30
|
-
export interface OPCUAServerPartial extends ICertificateKeyPairProviderPriv {
|
|
31
|
-
serverInfo?: ApplicationDescriptionOptions;
|
|
32
|
-
serverCertificateManager: OPCUACertificateManager;
|
|
33
|
-
privateKeyFile: string;
|
|
34
|
-
certificateFile: string;
|
|
35
|
-
$$certificate: null | Certificate;
|
|
36
|
-
$$certificateChain: null | Certificate;
|
|
37
|
-
$$privateKey: null | PrivateKey;
|
|
38
|
-
engine: { addressSpace?: AddressSpace };
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function getCertificate(this: OPCUAServerPartial): Certificate {
|
|
42
|
-
if (!this.$$certificate) {
|
|
43
|
-
const certificateChain = getCertificateChain.call(this);
|
|
44
|
-
this.$$certificate = split_der(certificateChain)[0];
|
|
45
|
-
}
|
|
46
|
-
return this.$$certificate;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function getCertificateChain(this: OPCUAServerPartial): Certificate {
|
|
50
|
-
if (!this.$$certificateChain) {
|
|
51
|
-
throw new Error("internal Error. cannot find $$certificateChain");
|
|
52
|
-
}
|
|
53
|
-
return this.$$certificateChain;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
function getPrivateKey(this: OPCUAServerPartial): PrivateKey {
|
|
57
|
-
// c8 ignore next
|
|
58
|
-
if (!this.$$privateKey) {
|
|
59
|
-
throw new Error("internal Error. cannot find $$privateKey");
|
|
60
|
-
}
|
|
61
|
-
return this.$$privateKey;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
*
|
|
68
|
-
*/
|
|
69
|
-
async function install(this: OPCUAServerPartial): Promise<void> {
|
|
70
|
-
doDebug && debugLog("install push certificate management", this.serverCertificateManager.rootDir);
|
|
71
|
-
|
|
72
|
-
Object.defineProperty(this, "privateKeyFile", {
|
|
73
|
-
get: () => this.serverCertificateManager.privateKey,
|
|
74
|
-
configurable: true
|
|
75
|
-
});
|
|
76
|
-
Object.defineProperty(this, "certificateFile", {
|
|
77
|
-
get: () => path.join(this.serverCertificateManager.rootDir, "own/certs/certificate.pem"),
|
|
78
|
-
configurable: true
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
if (!this.$$privateKey) {
|
|
82
|
-
this.$$privateKey = readPrivateKey(this.serverCertificateManager.privateKey);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
if (!this.$$certificateChain) {
|
|
86
|
-
const certificateFile = this.certificateFile;
|
|
87
|
-
|
|
88
|
-
if (!fs.existsSync(certificateFile)) {
|
|
89
|
-
// this is the first time server is launch
|
|
90
|
-
// let's create a default self signed certificate with limited validity
|
|
91
|
-
|
|
92
|
-
const fqdn = await getFullyQualifiedDomainName();
|
|
93
|
-
const ipAddresses = await getIpAddresses();
|
|
94
|
-
|
|
95
|
-
const applicationUri = (this.serverInfo ? this.serverInfo.applicationUri : null) || "uri:MISSING";
|
|
96
|
-
|
|
97
|
-
const options = {
|
|
98
|
-
applicationUri,
|
|
99
|
-
|
|
100
|
-
dns: [fqdn],
|
|
101
|
-
ip: ipAddresses,
|
|
102
|
-
|
|
103
|
-
subject: `/CN=${applicationUri};/L=Paris`,
|
|
104
|
-
|
|
105
|
-
startDate: new Date(),
|
|
106
|
-
|
|
107
|
-
validity: 365 * 5, // five year
|
|
108
|
-
|
|
109
|
-
/* */
|
|
110
|
-
outputFile: certificateFile
|
|
111
|
-
};
|
|
112
|
-
|
|
113
|
-
doDebug && debugLog("creating self signed certificate", options);
|
|
114
|
-
await this.serverCertificateManager.createSelfSignedCertificate(options);
|
|
115
|
-
}
|
|
116
|
-
const certificatePEM = await readFile(certificateFile, "utf8");
|
|
117
|
-
|
|
118
|
-
this.$$certificateChain = convertPEMtoDER(certificatePEM);
|
|
119
|
-
|
|
120
|
-
// await this.serverCertificateManager.trustCertificate( this.$$certificateChain);
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
function getCertificateChainEP(this: OPCUAServerEndPoint): Certificate {
|
|
125
|
-
const certificateFile = path.join(this.certificateManager.rootDir, "own/certs/certificate.pem");
|
|
126
|
-
const certificatePEM = fs.readFileSync(certificateFile, "utf8");
|
|
127
|
-
const $$certificateChain = convertPEMtoDER(certificatePEM);
|
|
128
|
-
return $$certificateChain;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
function getPrivateKeyEP(this: OPCUAServerEndPoint): PrivateKey {
|
|
132
|
-
const privateKey = readPrivateKey(this.certificateManager.privateKey);
|
|
133
|
-
return privateKey;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
async function onCertificateAboutToChange(server: OPCUAServer) {
|
|
137
|
-
doDebug && debugLog(chalk.yellow(" onCertificateAboutToChange => Suspending End points"));
|
|
138
|
-
await server.suspendEndPoints();
|
|
139
|
-
doDebug && debugLog(chalk.yellow(" onCertificateAboutToChange => End points suspended"));
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
/**
|
|
143
|
-
* onCertificateChange is called when the serverConfiguration notifies
|
|
144
|
-
* that the server certificate and/or private key has changed.
|
|
145
|
-
*
|
|
146
|
-
* this function suspends all endpoint listeners and stop all existing channels
|
|
147
|
-
* then start all endpoint listener
|
|
148
|
-
*
|
|
149
|
-
* @param server
|
|
150
|
-
*/
|
|
151
|
-
async function onCertificateChange(server: OPCUAServer) {
|
|
152
|
-
doDebug && debugLog("on CertificateChanged");
|
|
153
|
-
|
|
154
|
-
const _server = server as unknown as OPCUAServerPartial;
|
|
155
|
-
|
|
156
|
-
_server.$$privateKey = readPrivateKey(server.serverCertificateManager.privateKey);
|
|
157
|
-
const certificateFile = path.join(server.serverCertificateManager.rootDir, "own/certs/certificate.pem");
|
|
158
|
-
const certificatePEM = fs.readFileSync(certificateFile, "utf8");
|
|
159
|
-
|
|
160
|
-
const privateKeyFile = server.serverCertificateManager.privateKey;
|
|
161
|
-
const privateKey = readPrivateKey(privateKeyFile);
|
|
162
|
-
// also reread the private key
|
|
163
|
-
|
|
164
|
-
_server.$$certificateChain = convertPEMtoDER(certificatePEM);
|
|
165
|
-
_server.$$privateKey = privateKey;
|
|
166
|
-
// note : $$certificate will be reconstructed on demand
|
|
167
|
-
_server.$$certificate = split_der(_server.$$certificateChain)[0];
|
|
168
|
-
|
|
169
|
-
setTimeout(async () => {
|
|
170
|
-
try {
|
|
171
|
-
doDebug && debugLog(chalk.yellow(" onCertificateChange => shutting down channels"));
|
|
172
|
-
await server.shutdownChannels();
|
|
173
|
-
doDebug && debugLog(chalk.yellow(" onCertificateChange => channels shut down"));
|
|
174
|
-
|
|
175
|
-
doDebug && debugLog(chalk.yellow(" onCertificateChange => resuming end points"));
|
|
176
|
-
await server.resumeEndPoints();
|
|
177
|
-
doDebug && debugLog(chalk.yellow(" onCertificateChange => end points resumed"));
|
|
178
|
-
|
|
179
|
-
debugLog(chalk.yellow("channels have been closed -> client should reconnect "));
|
|
180
|
-
} catch (err) {
|
|
181
|
-
errorLog("Error in CertificateChanged handler ", (err as Error).message);
|
|
182
|
-
debugLog("err = ", err);
|
|
183
|
-
}
|
|
184
|
-
}, 2000);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
interface UAServerConfigurationEx extends UAServerConfiguration {
|
|
188
|
-
$pushCertificateManager: PushCertificateManagerServerImpl;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
type OPCUAServerEndPointEx = typeof OPCUAServerEndPoint & {
|
|
192
|
-
_certificateChain: Buffer | null;
|
|
193
|
-
_privateKey: PrivateKey | null;
|
|
194
|
-
};
|
|
195
|
-
|
|
196
|
-
export async function installPushCertificateManagementOnServer(server: OPCUAServer): Promise<void> {
|
|
197
|
-
if (!server.engine || !server.engine.addressSpace) {
|
|
198
|
-
throw new Error(
|
|
199
|
-
"Server must have a valid address space." +
|
|
200
|
-
"you need to call installPushCertificateManagementOnServer after server has been initialized"
|
|
201
|
-
);
|
|
202
|
-
}
|
|
203
|
-
await install.call(server as unknown as OPCUAServerPartial);
|
|
204
|
-
|
|
205
|
-
server.getCertificate = getCertificate;
|
|
206
|
-
server.getCertificateChain = getCertificateChain;
|
|
207
|
-
server.getPrivateKey = getPrivateKey;
|
|
208
|
-
|
|
209
|
-
for (const endpoint of server.endpoints) {
|
|
210
|
-
const endpointPriv: OPCUAServerEndPointEx = endpoint as unknown as OPCUAServerEndPointEx;
|
|
211
|
-
endpointPriv._certificateChain = null;
|
|
212
|
-
endpointPriv._privateKey = null;
|
|
213
|
-
|
|
214
|
-
endpoint.getCertificateChain = getCertificateChainEP;
|
|
215
|
-
endpoint.getPrivateKey = getPrivateKeyEP;
|
|
216
|
-
|
|
217
|
-
for (const e of endpoint.endpointDescriptions()) {
|
|
218
|
-
Object.defineProperty(e, "serverCertificate", {
|
|
219
|
-
get: () => endpoint.getCertificate(),
|
|
220
|
-
configurable: true
|
|
221
|
-
});
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
await installPushCertificateManagement(server.engine.addressSpace, {
|
|
226
|
-
applicationGroup: server.serverCertificateManager,
|
|
227
|
-
userTokenGroup: server.userCertificateManager,
|
|
228
|
-
|
|
229
|
-
applicationUri: server.serverInfo.applicationUri || "InvalidURI"
|
|
230
|
-
});
|
|
231
|
-
|
|
232
|
-
const serverConfiguration = server.engine.addressSpace.rootFolder.objects.server.getChildByName("ServerConfiguration");
|
|
233
|
-
const serverConfigurationPriv = serverConfiguration as UAServerConfigurationEx;
|
|
234
|
-
assert(serverConfigurationPriv.$pushCertificateManager);
|
|
235
|
-
|
|
236
|
-
serverConfigurationPriv.$pushCertificateManager.on("CertificateAboutToChange", (actionQueue: ActionQueue) => {
|
|
237
|
-
actionQueue.push(async (): Promise<void> => {
|
|
238
|
-
doDebug && debugLog("CertificateAboutToChange Event received");
|
|
239
|
-
await onCertificateAboutToChange(server);
|
|
240
|
-
doDebug && debugLog("CertificateAboutToChange Event processed");
|
|
241
|
-
});
|
|
242
|
-
});
|
|
243
|
-
serverConfigurationPriv.$pushCertificateManager.on("CertificateChanged", (actionQueue: ActionQueue) => {
|
|
244
|
-
actionQueue.push(async (): Promise<void> => {
|
|
245
|
-
doDebug && debugLog("CertificateChanged Event received");
|
|
246
|
-
await onCertificateChange(server);
|
|
247
|
-
doDebug && debugLog("CertificateChanged Event processed");
|
|
248
|
-
});
|
|
249
|
-
});
|
|
250
|
-
}
|