node-opcua-server-configuration 2.113.0 → 2.115.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.
@@ -22,22 +22,6 @@ var __importStar = (this && this.__importStar) || function (mod) {
22
22
  __setModuleDefault(result, mod);
23
23
  return result;
24
24
  };
25
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
26
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
27
- return new (P || (P = Promise))(function (resolve, reject) {
28
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
29
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
30
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
31
- step((generator = generator.apply(thisArg, _arguments || [])).next());
32
- });
33
- };
34
- var __asyncValues = (this && this.__asyncValues) || function (o) {
35
- if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
36
- var m = o[Symbol.asyncIterator], i;
37
- return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
38
- function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
39
- function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
40
- };
41
25
  var __importDefault = (this && this.__importDefault) || function (mod) {
42
26
  return (mod && mod.__esModule) ? mod : { "default": mod };
43
27
  };
@@ -81,56 +65,48 @@ function findCertificateGroupName(certificateGroupNodeId) {
81
65
  }
82
66
  return "";
83
67
  }
84
- function copyFile(source, dest) {
85
- return __awaiter(this, void 0, void 0, function* () {
86
- try {
87
- debugLog("copying file \n source ", source, "\n =>\n dest ", dest);
88
- const sourceExist = fs.existsSync(source);
89
- if (sourceExist) {
90
- yield fs.promises.copyFile(source, dest);
91
- }
68
+ async function copyFile(source, dest) {
69
+ try {
70
+ debugLog("copying file \n source ", source, "\n =>\n dest ", dest);
71
+ const sourceExist = fs.existsSync(source);
72
+ if (sourceExist) {
73
+ await fs.promises.copyFile(source, dest);
92
74
  }
93
- catch (err) {
94
- errorLog(err);
95
- }
96
- });
75
+ }
76
+ catch (err) {
77
+ errorLog(err);
78
+ }
97
79
  }
98
80
  exports.copyFile = copyFile;
99
- function deleteFile(file) {
100
- return __awaiter(this, void 0, void 0, function* () {
101
- try {
102
- const exists = yield fs.existsSync(file);
103
- if (exists) {
104
- debugLog("deleting file ", file);
105
- yield fs.promises.unlink(file);
106
- }
81
+ async function deleteFile(file) {
82
+ try {
83
+ const exists = await fs.existsSync(file);
84
+ if (exists) {
85
+ debugLog("deleting file ", file);
86
+ await fs.promises.unlink(file);
107
87
  }
108
- catch (err) {
109
- errorLog(err);
110
- }
111
- });
88
+ }
89
+ catch (err) {
90
+ errorLog(err);
91
+ }
112
92
  }
113
93
  exports.deleteFile = deleteFile;
114
- function moveFile(source, dest) {
115
- return __awaiter(this, void 0, void 0, function* () {
116
- debugLog("moving file file \n source ", source, "\n =>\n dest ", dest);
117
- try {
118
- yield copyFile(source, dest);
119
- yield deleteFile(source);
120
- }
121
- catch (err) {
122
- errorLog(err);
123
- }
124
- });
94
+ async function moveFile(source, dest) {
95
+ debugLog("moving file file \n source ", source, "\n =>\n dest ", dest);
96
+ try {
97
+ await copyFile(source, dest);
98
+ await deleteFile(source);
99
+ }
100
+ catch (err) {
101
+ errorLog(err);
102
+ }
125
103
  }
126
104
  exports.moveFile = moveFile;
127
- function moveFileWithBackup(source, dest) {
128
- return __awaiter(this, void 0, void 0, function* () {
129
- // let make a copy of the destination file
130
- debugLog("moveFileWithBackup file \n source ", source, "\n =>\n dest ", dest);
131
- yield copyFile(dest, dest + "_old");
132
- yield moveFile(source, dest);
133
- });
105
+ async function moveFileWithBackup(source, dest) {
106
+ // let make a copy of the destination file
107
+ debugLog("moveFileWithBackup file \n source ", source, "\n =>\n dest ", dest);
108
+ await copyFile(dest, dest + "_old");
109
+ await moveFile(source, dest);
134
110
  }
135
111
  exports.moveFileWithBackup = moveFileWithBackup;
136
112
  function subjectToString(subject) {
@@ -179,326 +155,308 @@ class PushCertificateManagerServerImpl extends events_1.EventEmitter {
179
155
  }
180
156
  }
181
157
  }
182
- initialize() {
183
- return __awaiter(this, void 0, void 0, function* () {
184
- if (this.applicationGroup) {
185
- yield this.applicationGroup.initialize();
186
- }
187
- if (this.userTokenGroup) {
188
- yield this.userTokenGroup.initialize();
189
- }
190
- if (this.httpsGroup) {
191
- yield this.httpsGroup.initialize();
192
- }
193
- });
158
+ async initialize() {
159
+ if (this.applicationGroup) {
160
+ await this.applicationGroup.initialize();
161
+ }
162
+ if (this.userTokenGroup) {
163
+ await this.userTokenGroup.initialize();
164
+ }
165
+ if (this.httpsGroup) {
166
+ await this.httpsGroup.initialize();
167
+ }
194
168
  }
195
169
  get supportedPrivateKeyFormats() {
196
170
  return ["PEM"];
197
171
  }
198
- getSupportedPrivateKeyFormats() {
199
- return __awaiter(this, void 0, void 0, function* () {
200
- return this.supportedPrivateKeyFormats;
201
- });
172
+ async getSupportedPrivateKeyFormats() {
173
+ return this.supportedPrivateKeyFormats;
202
174
  }
203
- createSigningRequest(certificateGroupId, certificateTypeId, subjectName, regeneratePrivateKey, nonce) {
204
- return __awaiter(this, void 0, void 0, function* () {
205
- let certificateManager = this.getCertificateManager(certificateGroupId);
206
- if (!certificateManager) {
207
- debugLog(" cannot find group ", certificateGroupId);
175
+ async createSigningRequest(certificateGroupId, certificateTypeId, subjectName, regeneratePrivateKey, nonce) {
176
+ let certificateManager = this.getCertificateManager(certificateGroupId);
177
+ if (!certificateManager) {
178
+ debugLog(" cannot find group ", certificateGroupId);
179
+ return {
180
+ statusCode: node_opcua_basic_types_1.StatusCodes.BadInvalidArgument
181
+ };
182
+ }
183
+ if (!subjectName) {
184
+ // reuse existing subjectName
185
+ const currentCertificateFilename = path.join(certificateManager.rootDir, "own/certs/certificate.pem");
186
+ if (!fs.existsSync(currentCertificateFilename)) {
187
+ errorLog("Cannot find existing certificate to extract subjectName", currentCertificateFilename);
188
+ return {
189
+ statusCode: node_opcua_basic_types_1.StatusCodes.BadInvalidState
190
+ };
191
+ }
192
+ const certificate = (0, node_opcua_crypto_1.readCertificate)(currentCertificateFilename);
193
+ const e = (0, node_opcua_crypto_1.exploreCertificate)(certificate);
194
+ subjectName = subjectToString(e.tbsCertificate.subject);
195
+ warningLog("reusing existing certificate subjectAltName = ", subjectName);
196
+ }
197
+ // todo : at this time regenerate private key is not supported
198
+ if (regeneratePrivateKey) {
199
+ // The Server shall create a new Private Key which it stores until the
200
+ // matching signed Certificate is uploaded with the UpdateCertificate Method.
201
+ // Previously created Private Keys may be discarded if UpdateCertificate was not
202
+ // called before calling this method again.
203
+ // Additional entropy which the caller shall provide if regeneratePrivateKey is TRUE.
204
+ // It shall be at least 32 bytes long
205
+ if (!nonce || nonce.length < 32) {
206
+ (0, node_opcua_debug_1.make_warningLog)(" nonce should be provided when regeneratePrivateKey is set, and length shall be greater than 32 bytes");
208
207
  return {
209
208
  statusCode: node_opcua_basic_types_1.StatusCodes.BadInvalidArgument
210
209
  };
211
210
  }
212
- if (!subjectName) {
213
- // reuse existing subjectName
214
- const currentCertificateFilename = path.join(certificateManager.rootDir, "own/certs/certificate.pem");
215
- if (!fs.existsSync(currentCertificateFilename)) {
216
- errorLog("Cannot find existing certificate to extract subjectName", currentCertificateFilename);
217
- return {
218
- statusCode: node_opcua_basic_types_1.StatusCodes.BadInvalidState
219
- };
220
- }
221
- const certificate = (0, node_opcua_crypto_1.readCertificate)(currentCertificateFilename);
222
- const e = (0, node_opcua_crypto_1.exploreCertificate)(certificate);
223
- subjectName = subjectToString(e.tbsCertificate.subject);
224
- warningLog("reusing existing certificate subjectAltName = ", subjectName);
211
+ const location = path.join(certificateManager.rootDir, "tmp");
212
+ if (fs.existsSync(location)) {
213
+ await (0, util_1.promisify)(rimraf_1.default)(path.join(location));
225
214
  }
226
- // todo : at this time regenerate private key is not supported
227
- if (regeneratePrivateKey) {
228
- // The Server shall create a new Private Key which it stores until the
229
- // matching signed Certificate is uploaded with the UpdateCertificate Method.
230
- // Previously created Private Keys may be discarded if UpdateCertificate was not
231
- // called before calling this method again.
232
- // Additional entropy which the caller shall provide if regeneratePrivateKey is TRUE.
233
- // It shall be at least 32 bytes long
234
- if (!nonce || nonce.length < 32) {
235
- (0, node_opcua_debug_1.make_warningLog)(" nonce should be provided when regeneratePrivateKey is set, and length shall be greater than 32 bytes");
236
- return {
237
- statusCode: node_opcua_basic_types_1.StatusCodes.BadInvalidArgument
238
- };
239
- }
240
- const location = path.join(certificateManager.rootDir, "tmp");
241
- if (fs.existsSync(location)) {
242
- yield (0, util_1.promisify)(rimraf_1.default)(path.join(location));
243
- }
244
- if (!fs.existsSync(location)) {
245
- yield fs.promises.mkdir(location);
246
- }
247
- const destCertificateManager = certificateManager;
248
- const keySize = certificateManager.keySize; // because keySize is private !
249
- certificateManager = new node_opcua_certificate_manager_1.CertificateManager({
250
- keySize,
251
- location
252
- });
253
- debugLog("generating a new private key ...");
254
- yield certificateManager.initialize();
255
- this._tmpCertificateManager = certificateManager;
256
- this.addPendingTask(() => __awaiter(this, void 0, void 0, function* () {
257
- yield moveFileWithBackup(certificateManager.privateKey, destCertificateManager.privateKey);
258
- }));
259
- this.addPendingTask(() => __awaiter(this, void 0, void 0, function* () {
260
- yield (0, util_1.promisify)(rimraf_1.default)(path.join(location));
261
- }));
215
+ if (!fs.existsSync(location)) {
216
+ await fs.promises.mkdir(location);
262
217
  }
263
- else {
264
- // The Server uses its existing Private Key
218
+ const destCertificateManager = certificateManager;
219
+ const keySize = certificateManager.keySize; // because keySize is private !
220
+ certificateManager = new node_opcua_certificate_manager_1.CertificateManager({
221
+ keySize,
222
+ location
223
+ });
224
+ debugLog("generating a new private key ...");
225
+ await certificateManager.initialize();
226
+ this._tmpCertificateManager = certificateManager;
227
+ this.addPendingTask(async () => {
228
+ await moveFileWithBackup(certificateManager.privateKey, destCertificateManager.privateKey);
229
+ });
230
+ this.addPendingTask(async () => {
231
+ await (0, util_1.promisify)(rimraf_1.default)(path.join(location));
232
+ });
233
+ }
234
+ else {
235
+ // The Server uses its existing Private Key
236
+ }
237
+ if (typeof subjectName !== "string") {
238
+ return { statusCode: node_opcua_basic_types_1.StatusCodes.BadInternalError };
239
+ }
240
+ const options = {
241
+ applicationUri: this.applicationUri,
242
+ subject: subjectName
243
+ };
244
+ await certificateManager.initialize();
245
+ const csrFile = await certificateManager.createCertificateRequest(options);
246
+ const csrPEM = await readFile(csrFile, "utf8");
247
+ const certificateSigningRequest = (0, node_opcua_crypto_1.convertPEMtoDER)(csrPEM);
248
+ this.addPendingTask(() => deleteFile(csrFile));
249
+ return {
250
+ certificateSigningRequest,
251
+ statusCode: node_opcua_basic_types_1.StatusCodes.Good
252
+ };
253
+ }
254
+ async getRejectedList() {
255
+ // rejectedList comes from each group
256
+ async function extractRejectedList(group, certificateList) {
257
+ if (!group) {
258
+ return;
265
259
  }
266
- if (typeof subjectName !== "string") {
267
- return { statusCode: node_opcua_basic_types_1.StatusCodes.BadInternalError };
260
+ const rejectedFolder = path.join(group.rootDir, "rejected");
261
+ const files = await readdir(rejectedFolder);
262
+ const stat = fs.promises.stat;
263
+ const promises1 = [];
264
+ for (const certFile of files) {
265
+ // read date
266
+ promises1.push(stat(path.join(rejectedFolder, certFile)));
268
267
  }
269
- const options = {
270
- applicationUri: this.applicationUri,
271
- subject: subjectName
272
- };
273
- yield certificateManager.initialize();
274
- const csrFile = yield certificateManager.createCertificateRequest(options);
275
- const csrPEM = yield readFile(csrFile, "utf8");
276
- const certificateSigningRequest = (0, node_opcua_crypto_1.convertPEMtoDER)(csrPEM);
277
- this.addPendingTask(() => deleteFile(csrFile));
268
+ const stats = await Promise.all(promises1);
269
+ for (let i = 0; i < stats.length; i++) {
270
+ certificateList.push({
271
+ filename: path.join(rejectedFolder, files[i]),
272
+ stat: stats[i]
273
+ });
274
+ }
275
+ }
276
+ const list = [];
277
+ await extractRejectedList(this.applicationGroup, list);
278
+ await extractRejectedList(this.userTokenGroup, list);
279
+ await extractRejectedList(this.httpsGroup, list);
280
+ // now sort list from newer file to older file
281
+ list.sort((a, b) => b.stat.mtime.getTime() - a.stat.mtime.getTime());
282
+ const promises = [];
283
+ for (const item of list) {
284
+ promises.push(readFile(item.filename, "utf8"));
285
+ }
286
+ const certificatesPEM = await Promise.all(promises);
287
+ const certificates = certificatesPEM.map(node_opcua_crypto_1.convertPEMtoDER);
288
+ return {
289
+ certificates,
290
+ statusCode: node_opcua_basic_types_1.StatusCodes.Good
291
+ };
292
+ }
293
+ // eslint-disable-next-line max-statements
294
+ async updateCertificate(certificateGroupId, certificateTypeId, certificate, issuerCertificates, privateKeyFormat, privateKey) {
295
+ // Result Code Description
296
+ // BadInvalidArgument The certificateTypeId or certificateGroupId is not valid.
297
+ // BadCertificateInvalid The Certificate is invalid or the format is not supported.
298
+ // BadNotSupported The Private Key is invalid or the format is not supported.
299
+ // BadUserAccessDenied The current user does not have the rights required.
300
+ // BadSecurityChecksFailed Some failure occurred verifying the integrity of the Certificate.
301
+ const certificateManager = this.getCertificateManager(certificateGroupId);
302
+ if (!certificateManager) {
303
+ debugLog(" cannot find group ", certificateGroupId);
278
304
  return {
279
- certificateSigningRequest,
280
- statusCode: node_opcua_basic_types_1.StatusCodes.Good
305
+ statusCode: node_opcua_basic_types_1.StatusCodes.BadInvalidArgument
281
306
  };
282
- });
283
- }
284
- getRejectedList() {
285
- return __awaiter(this, void 0, void 0, function* () {
286
- // rejectedList comes from each group
287
- function extractRejectedList(group, certificateList) {
288
- return __awaiter(this, void 0, void 0, function* () {
289
- if (!group) {
290
- return;
291
- }
292
- const rejectedFolder = path.join(group.rootDir, "rejected");
293
- const files = yield readdir(rejectedFolder);
294
- const stat = fs.promises.stat;
295
- const promises1 = [];
296
- for (const certFile of files) {
297
- // read date
298
- promises1.push(stat(path.join(rejectedFolder, certFile)));
299
- }
300
- const stats = yield Promise.all(promises1);
301
- for (let i = 0; i < stats.length; i++) {
302
- certificateList.push({
303
- filename: path.join(rejectedFolder, files[i]),
304
- stat: stats[i]
305
- });
306
- }
307
- });
307
+ }
308
+ async function preInstallCertificate(self) {
309
+ const certFolder = path.join(certificateManager.rootDir, "own/certs");
310
+ const certificateFileDER = path.join(certFolder, `_pending_certificate${fileCounter++}.der`);
311
+ const certificateFilePEM = path.join(certFolder, `_pending_certificate${fileCounter++}.pem`);
312
+ await writeFile(certificateFileDER, certificate, "binary");
313
+ await writeFile(certificateFilePEM, (0, node_opcua_crypto_1.toPem)(certificate, "CERTIFICATE"));
314
+ const destDER = path.join(certFolder, "certificate.der");
315
+ const destPEM = path.join(certFolder, "certificate.pem");
316
+ // put existing file in security by backing them up
317
+ self.addPendingTask(() => moveFileWithBackup(certificateFileDER, destDER));
318
+ self.addPendingTask(() => moveFileWithBackup(certificateFilePEM, destPEM));
319
+ }
320
+ async function preInstallPrivateKey(self) {
321
+ (0, node_opcua_assert_1.assert)(privateKeyFormat.toUpperCase() === "PEM");
322
+ const ownPrivateFolder = path.join(certificateManager.rootDir, "own/private");
323
+ const privateKeyFilePEM = path.join(ownPrivateFolder, `_pending_private_key${fileCounter++}.pem`);
324
+ if (privateKey) {
325
+ const privateKey1 = (0, node_opcua_crypto_1.coercePEMorDerToPrivateKey)(privateKey);
326
+ const privateKeyPEM = await (0, node_opcua_crypto_1.coercePrivateKeyPem)(privateKey1);
327
+ await writeFile(privateKeyFilePEM, privateKeyPEM, "utf-8");
328
+ self.addPendingTask(() => moveFileWithBackup(privateKeyFilePEM, certificateManager.privateKey));
308
329
  }
309
- const list = [];
310
- yield extractRejectedList(this.applicationGroup, list);
311
- yield extractRejectedList(this.userTokenGroup, list);
312
- yield extractRejectedList(this.httpsGroup, list);
313
- // now sort list from newer file to older file
314
- list.sort((a, b) => b.stat.mtime.getTime() - a.stat.mtime.getTime());
315
- const promises = [];
316
- for (const item of list) {
317
- promises.push(readFile(item.filename, "utf8"));
330
+ }
331
+ // OPC Unified Architecture, Part 12 42 Release 1.04:
332
+ //
333
+ // UpdateCertificate is used to update a Certificate for a Server.
334
+ // There are the following three use cases for this Method:
335
+ //
336
+ // - The new Certificate was created based on a signing request created with the Method
337
+ // In this case there is no privateKey provided.
338
+ // - A new privateKey and Certificate was created outside the Server and both are updated
339
+ // with this Method.
340
+ // - A new Certificate was created and signed with the information from the old Certificate.
341
+ // In this case there is no privateKey provided.
342
+ // The Server shall do all normal integrity checks on the Certificate and all of the issuer
343
+ // Certificates. If errors occur the BadSecurityChecksFailed error is returned.
344
+ // todo : all normal integrity check on the certificate
345
+ const certInfo = (0, node_opcua_crypto_1.exploreCertificate)(certificate);
346
+ const now = new Date();
347
+ if (certInfo.tbsCertificate.validity.notBefore.getTime() > now.getTime()) {
348
+ // certificate is not yet valid
349
+ warningLog("Certificate is not yet valid : not before ", certInfo.tbsCertificate.validity.notBefore.toISOString(), "now = ", now.toISOString());
350
+ return { statusCode: node_opcua_basic_types_1.StatusCodes.BadSecurityChecksFailed };
351
+ }
352
+ if (certInfo.tbsCertificate.validity.notAfter.getTime() < now.getTime()) {
353
+ // certificate is already out of date
354
+ warningLog("Certificate is already out of date : not after ", certInfo.tbsCertificate.validity.notAfter.toISOString(), "now = ", now.toISOString());
355
+ return { statusCode: node_opcua_basic_types_1.StatusCodes.BadSecurityChecksFailed };
356
+ }
357
+ // If the Server returns applyChangesRequired=FALSE then it is indicating that it is able to
358
+ // satisfy the requirements specified for the ApplyChanges Method.
359
+ debugLog(" updateCertificate ", (0, node_opcua_crypto_1.makeSHA1Thumbprint)(certificate).toString("hex"));
360
+ if (!privateKeyFormat || !privateKey) {
361
+ // first of all we need to find the future private key;
362
+ // this one may have been created during the creation of the certificate signing request
363
+ // but is not active yet
364
+ const privateKey1 = (0, node_opcua_crypto_1.readPrivateKey)(this._tmpCertificateManager ? this._tmpCertificateManager.privateKey : certificateManager.privateKey);
365
+ // The Server shall report an error if the public key does not match the existing Certificate and
366
+ // the privateKey was not provided.
367
+ // privateKey is not provided, so check that the public key matches the existing certificate
368
+ if (!(0, node_opcua_crypto_1.certificateMatchesPrivateKey)(certificate, privateKey1)) {
369
+ // certificate doesn't match privateKey
370
+ warningLog("certificate doesn't match privateKey");
371
+ /* debug code */
372
+ const certificatePEM = (0, node_opcua_crypto_1.toPem)(certificate, "CERTIFICATE");
373
+ //xx const privateKeyPEM = toPem(privateKeyDER, "RSA PRIVATE KEY");
374
+ //xx const initialBuffer = Buffer.from("Lorem Ipsum");
375
+ //xx const encryptedBuffer = publicEncrypt_long(initialBuffer, certificatePEM, 256, 11);
376
+ //xx const decryptedBuffer = privateDecrypt_long(encryptedBuffer, privateKeyPEM, 256);
377
+ return { statusCode: node_opcua_basic_types_1.StatusCodes.BadSecurityChecksFailed };
318
378
  }
319
- const certificatesPEM = yield Promise.all(promises);
320
- const certificates = certificatesPEM.map(node_opcua_crypto_1.convertPEMtoDER);
379
+ // a new certificate is provided for us,
380
+ // we keep our private key
381
+ // we do this in two stages
382
+ await preInstallCertificate(this);
321
383
  return {
322
- certificates,
323
384
  statusCode: node_opcua_basic_types_1.StatusCodes.Good
324
385
  };
325
- });
326
- }
327
- // eslint-disable-next-line max-statements
328
- updateCertificate(certificateGroupId, certificateTypeId, certificate, issuerCertificates, privateKeyFormat, privateKey) {
329
- return __awaiter(this, void 0, void 0, function* () {
330
- // Result Code Description
331
- // BadInvalidArgument The certificateTypeId or certificateGroupId is not valid.
332
- // BadCertificateInvalid The Certificate is invalid or the format is not supported.
333
- // BadNotSupported The Private Key is invalid or the format is not supported.
334
- // BadUserAccessDenied The current user does not have the rights required.
335
- // BadSecurityChecksFailed Some failure occurred verifying the integrity of the Certificate.
336
- const certificateManager = this.getCertificateManager(certificateGroupId);
337
- if (!certificateManager) {
338
- debugLog(" cannot find group ", certificateGroupId);
339
- return {
340
- statusCode: node_opcua_basic_types_1.StatusCodes.BadInvalidArgument
341
- };
342
- }
343
- function preInstallCertificate(self) {
344
- return __awaiter(this, void 0, void 0, function* () {
345
- const certFolder = path.join(certificateManager.rootDir, "own/certs");
346
- const certificateFileDER = path.join(certFolder, `_pending_certificate${fileCounter++}.der`);
347
- const certificateFilePEM = path.join(certFolder, `_pending_certificate${fileCounter++}.pem`);
348
- yield writeFile(certificateFileDER, certificate, "binary");
349
- yield writeFile(certificateFilePEM, (0, node_opcua_crypto_1.toPem)(certificate, "CERTIFICATE"));
350
- const destDER = path.join(certFolder, "certificate.der");
351
- const destPEM = path.join(certFolder, "certificate.pem");
352
- // put existing file in security by backing them up
353
- self.addPendingTask(() => moveFileWithBackup(certificateFileDER, destDER));
354
- self.addPendingTask(() => moveFileWithBackup(certificateFilePEM, destPEM));
355
- });
386
+ }
387
+ else if (privateKey) {
388
+ // a private key has been provided by the caller !
389
+ if (!privateKeyFormat) {
390
+ warningLog("the privateKeyFormat must be specified " + privateKeyFormat);
391
+ return { statusCode: node_opcua_basic_types_1.StatusCodes.BadNotSupported };
356
392
  }
357
- function preInstallPrivateKey(self) {
358
- return __awaiter(this, void 0, void 0, function* () {
359
- (0, node_opcua_assert_1.assert)(privateKeyFormat.toUpperCase() === "PEM");
360
- const ownPrivateFolder = path.join(certificateManager.rootDir, "own/private");
361
- const privateKeyFilePEM = path.join(ownPrivateFolder, `_pending_private_key${fileCounter++}.pem`);
362
- if (privateKey) {
363
- const privateKey1 = (0, node_opcua_crypto_1.coercePEMorDerToPrivateKey)(privateKey);
364
- const privateKeyPEM = yield (0, node_opcua_crypto_1.coercePrivateKeyPem)(privateKey1);
365
- yield writeFile(privateKeyFilePEM, privateKeyPEM, "utf-8");
366
- self.addPendingTask(() => moveFileWithBackup(privateKeyFilePEM, certificateManager.privateKey));
367
- }
368
- });
393
+ if (privateKeyFormat !== "PEM" && privateKeyFormat !== "PFX") {
394
+ warningLog(" the private key format is invalid privateKeyFormat =" + privateKeyFormat);
395
+ return { statusCode: node_opcua_basic_types_1.StatusCodes.BadNotSupported };
369
396
  }
370
- // OPC Unified Architecture, Part 12 42 Release 1.04:
371
- //
372
- // UpdateCertificate is used to update a Certificate for a Server.
373
- // There are the following three use cases for this Method:
374
- //
375
- // - The new Certificate was created based on a signing request created with the Method
376
- // In this case there is no privateKey provided.
377
- // - A new privateKey and Certificate was created outside the Server and both are updated
378
- // with this Method.
379
- // - A new Certificate was created and signed with the information from the old Certificate.
380
- // In this case there is no privateKey provided.
381
- // The Server shall do all normal integrity checks on the Certificate and all of the issuer
382
- // Certificates. If errors occur the BadSecurityChecksFailed error is returned.
383
- // todo : all normal integrity check on the certificate
384
- const certInfo = (0, node_opcua_crypto_1.exploreCertificate)(certificate);
385
- const now = new Date();
386
- if (certInfo.tbsCertificate.validity.notBefore.getTime() > now.getTime()) {
387
- // certificate is not yet valid
388
- warningLog("Certificate is not yet valid : not before ", certInfo.tbsCertificate.validity.notBefore.toISOString(), "now = ", now.toISOString());
389
- return { statusCode: node_opcua_basic_types_1.StatusCodes.BadSecurityChecksFailed };
397
+ if (privateKeyFormat !== "PEM") {
398
+ warningLog("in NodeOPCUA we only support PEM for the moment privateKeyFormat =" + privateKeyFormat);
399
+ return { statusCode: node_opcua_basic_types_1.StatusCodes.BadNotSupported };
390
400
  }
391
- if (certInfo.tbsCertificate.validity.notAfter.getTime() < now.getTime()) {
392
- // certificate is already out of date
393
- warningLog("Certificate is already out of date : not after ", certInfo.tbsCertificate.validity.notAfter.toISOString(), "now = ", now.toISOString());
394
- return { statusCode: node_opcua_basic_types_1.StatusCodes.BadSecurityChecksFailed };
395
- }
396
- // If the Server returns applyChangesRequired=FALSE then it is indicating that it is able to
397
- // satisfy the requirements specified for the ApplyChanges Method.
398
- debugLog(" updateCertificate ", (0, node_opcua_crypto_1.makeSHA1Thumbprint)(certificate).toString("hex"));
399
- if (!privateKeyFormat || !privateKey) {
400
- // first of all we need to find the future private key;
401
- // this one may have been created during the creation of the certificate signing request
402
- // but is not active yet
403
- const privateKey1 = (0, node_opcua_crypto_1.readPrivateKey)(this._tmpCertificateManager ? this._tmpCertificateManager.privateKey : certificateManager.privateKey);
404
- // The Server shall report an error if the public key does not match the existing Certificate and
405
- // the privateKey was not provided.
406
- // privateKey is not provided, so check that the public key matches the existing certificate
407
- if (!(0, node_opcua_crypto_1.certificateMatchesPrivateKey)(certificate, privateKey1)) {
408
- // certificate doesn't match privateKey
409
- warningLog("certificate doesn't match privateKey");
410
- /* debug code */
411
- const certificatePEM = (0, node_opcua_crypto_1.toPem)(certificate, "CERTIFICATE");
412
- //xx const privateKeyPEM = toPem(privateKeyDER, "RSA PRIVATE KEY");
413
- //xx const initialBuffer = Buffer.from("Lorem Ipsum");
414
- //xx const encryptedBuffer = publicEncrypt_long(initialBuffer, certificatePEM, 256, 11);
415
- //xx const decryptedBuffer = privateDecrypt_long(encryptedBuffer, privateKeyPEM, 256);
416
- return { statusCode: node_opcua_basic_types_1.StatusCodes.BadSecurityChecksFailed };
401
+ let privateKey1;
402
+ if (privateKey && (privateKey instanceof Buffer || typeof privateKey === "string")) {
403
+ if (privateKey instanceof Buffer) {
404
+ (0, node_opcua_assert_1.assert)(privateKeyFormat === "PEM");
405
+ privateKey = privateKey.toString("utf-8");
417
406
  }
418
- // a new certificate is provided for us,
419
- // we keep our private key
420
- // we do this in two stages
421
- yield preInstallCertificate(this);
422
- return {
423
- statusCode: node_opcua_basic_types_1.StatusCodes.Good
424
- };
407
+ privateKey1 = (0, node_opcua_crypto_1.coercePEMorDerToPrivateKey)(privateKey);
425
408
  }
426
- else if (privateKey) {
427
- // a private key has been provided by the caller !
428
- if (!privateKeyFormat) {
429
- warningLog("the privateKeyFormat must be specified " + privateKeyFormat);
430
- return { statusCode: node_opcua_basic_types_1.StatusCodes.BadNotSupported };
431
- }
432
- if (privateKeyFormat !== "PEM" && privateKeyFormat !== "PFX") {
433
- warningLog(" the private key format is invalid privateKeyFormat =" + privateKeyFormat);
434
- return { statusCode: node_opcua_basic_types_1.StatusCodes.BadNotSupported };
435
- }
436
- if (privateKeyFormat !== "PEM") {
437
- warningLog("in NodeOPCUA we only support PEM for the moment privateKeyFormat =" + privateKeyFormat);
438
- return { statusCode: node_opcua_basic_types_1.StatusCodes.BadNotSupported };
439
- }
440
- let privateKey1;
441
- if (privateKey && (privateKey instanceof Buffer || typeof privateKey === "string")) {
442
- if (privateKey instanceof Buffer) {
443
- (0, node_opcua_assert_1.assert)(privateKeyFormat === "PEM");
444
- privateKey = privateKey.toString("utf-8");
445
- }
446
- privateKey1 = (0, node_opcua_crypto_1.coercePEMorDerToPrivateKey)(privateKey);
447
- }
448
- if (!privateKey1) {
449
- return { statusCode: node_opcua_basic_types_1.StatusCodes.BadNotSupported };
450
- }
451
- // privateKey is provided, so check that the public key matches provided private key
452
- if (!(0, node_opcua_crypto_1.certificateMatchesPrivateKey)(certificate, privateKey1)) {
453
- // certificate doesn't match privateKey
454
- warningLog("certificate doesn't match privateKey");
455
- return { statusCode: node_opcua_basic_types_1.StatusCodes.BadSecurityChecksFailed };
456
- }
457
- yield preInstallPrivateKey(this);
458
- yield preInstallCertificate(this);
459
- return {
460
- statusCode: node_opcua_basic_types_1.StatusCodes.Good
461
- };
409
+ if (!privateKey1) {
410
+ return { statusCode: node_opcua_basic_types_1.StatusCodes.BadNotSupported };
462
411
  }
463
- else {
464
- // todo !
465
- return {
466
- statusCode: node_opcua_basic_types_1.StatusCodes.BadNotSupported
467
- };
412
+ // privateKey is provided, so check that the public key matches provided private key
413
+ if (!(0, node_opcua_crypto_1.certificateMatchesPrivateKey)(certificate, privateKey1)) {
414
+ // certificate doesn't match privateKey
415
+ warningLog("certificate doesn't match privateKey");
416
+ return { statusCode: node_opcua_basic_types_1.StatusCodes.BadSecurityChecksFailed };
468
417
  }
469
- });
418
+ await preInstallPrivateKey(this);
419
+ await preInstallCertificate(this);
420
+ return {
421
+ statusCode: node_opcua_basic_types_1.StatusCodes.Good
422
+ };
423
+ }
424
+ else {
425
+ // todo !
426
+ return {
427
+ statusCode: node_opcua_basic_types_1.StatusCodes.BadNotSupported
428
+ };
429
+ }
470
430
  }
471
- applyChanges() {
472
- return __awaiter(this, void 0, void 0, function* () {
473
- // ApplyChanges is used to tell the Server to apply any security changes.
474
- // This Method should only be called if a previous call to a Method that changed the
475
- // configuration returns applyChangesRequired=true.
476
- //
477
- // If the Server Certificate has changed, Secure Channels using the old Certificate will
478
- // eventually be interrupted.
479
- this.emit("CertificateAboutToChange", this.$$actionQueue);
480
- yield this.flushActionQueue();
481
- try {
482
- yield this.applyPendingTasks();
483
- }
484
- catch (err) {
485
- debugLog("err ", err);
486
- return node_opcua_basic_types_1.StatusCodes.BadInternalError;
487
- }
488
- this.emit("CertificateChanged", this.$$actionQueue);
489
- yield this.flushActionQueue();
490
- // The only leeway the Server has is with the timing.
491
- // In the best case, the Server can close the TransportConnections for the affected Endpoints and leave any
492
- // Subscriptions intact. This should appear no different than a network interruption from the
493
- // perspective of the Client. The Client should be prepared to deal with Certificate changes
494
- // during its reconnect logic. In the worst case, a full shutdown which affects all connected
495
- // Clients will be necessary. In the latter case, the Server shall advertise its intent to interrupt
496
- // connections by setting the SecondsTillShutdown and ShutdownReason Properties in the
497
- // ServerStatus Variable.
498
- // If the Secure Channel being used to call this Method will be affected by the Certificate change
499
- // then the Server shall introduce a delay long enough to allow the caller to receive a reply.
500
- return node_opcua_basic_types_1.StatusCodes.Good;
501
- });
431
+ async applyChanges() {
432
+ // ApplyChanges is used to tell the Server to apply any security changes.
433
+ // This Method should only be called if a previous call to a Method that changed the
434
+ // configuration returns applyChangesRequired=true.
435
+ //
436
+ // If the Server Certificate has changed, Secure Channels using the old Certificate will
437
+ // eventually be interrupted.
438
+ this.emit("CertificateAboutToChange", this.$$actionQueue);
439
+ await this.flushActionQueue();
440
+ try {
441
+ await this.applyPendingTasks();
442
+ }
443
+ catch (err) {
444
+ debugLog("err ", err);
445
+ return node_opcua_basic_types_1.StatusCodes.BadInternalError;
446
+ }
447
+ this.emit("CertificateChanged", this.$$actionQueue);
448
+ await this.flushActionQueue();
449
+ // The only leeway the Server has is with the timing.
450
+ // In the best case, the Server can close the TransportConnections for the affected Endpoints and leave any
451
+ // Subscriptions intact. This should appear no different than a network interruption from the
452
+ // perspective of the Client. The Client should be prepared to deal with Certificate changes
453
+ // during its reconnect logic. In the worst case, a full shutdown which affects all connected
454
+ // Clients will be necessary. In the latter case, the Server shall advertise its intent to interrupt
455
+ // connections by setting the SecondsTillShutdown and ShutdownReason Properties in the
456
+ // ServerStatus Variable.
457
+ // If the Secure Channel being used to call this Method will be affected by the Certificate change
458
+ // then the Server shall introduce a delay long enough to allow the caller to receive a reply.
459
+ return node_opcua_basic_types_1.StatusCodes.Good;
502
460
  }
503
461
  getCertificateManager(certificateGroupId) {
504
462
  const groupName = findCertificateGroupName(certificateGroupId);
@@ -507,47 +465,30 @@ class PushCertificateManagerServerImpl extends events_1.EventEmitter {
507
465
  addPendingTask(functor) {
508
466
  this._pendingTasks.push(functor);
509
467
  }
510
- applyPendingTasks() {
511
- var _a, e_1, _b, _c;
512
- return __awaiter(this, void 0, void 0, function* () {
513
- debugLog("start applyPendingTasks");
514
- const promises = [];
515
- const t = this._pendingTasks.splice(0);
516
- if (false) {
517
- try {
518
- // node 10.2 and above
519
- for (var _d = true, t_1 = __asyncValues(t), t_1_1; t_1_1 = yield t_1.next(), _a = t_1_1.done, !_a; _d = true) {
520
- _c = t_1_1.value;
521
- _d = false;
522
- const task = _c;
523
- yield task();
524
- }
525
- }
526
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
527
- finally {
528
- try {
529
- if (!_d && !_a && (_b = t_1.return)) yield _b.call(t_1);
530
- }
531
- finally { if (e_1) throw e_1.error; }
532
- }
468
+ async applyPendingTasks() {
469
+ debugLog("start applyPendingTasks");
470
+ const promises = [];
471
+ const t = this._pendingTasks.splice(0);
472
+ if (false) {
473
+ // node 10.2 and above
474
+ for await (const task of t) {
475
+ await task();
533
476
  }
534
- else {
535
- while (t.length) {
536
- const task = t.shift();
537
- yield task();
538
- }
477
+ }
478
+ else {
479
+ while (t.length) {
480
+ const task = t.shift();
481
+ await task();
539
482
  }
540
- yield Promise.all(promises);
541
- debugLog("end applyPendingTasks");
542
- });
483
+ }
484
+ await Promise.all(promises);
485
+ debugLog("end applyPendingTasks");
543
486
  }
544
- flushActionQueue() {
545
- return __awaiter(this, void 0, void 0, function* () {
546
- while (this.$$actionQueue.length) {
547
- const first = this.$$actionQueue.pop();
548
- yield first();
549
- }
550
- });
487
+ async flushActionQueue() {
488
+ while (this.$$actionQueue.length) {
489
+ const first = this.$$actionQueue.pop();
490
+ await first();
491
+ }
551
492
  }
552
493
  }
553
494
  exports.PushCertificateManagerServerImpl = PushCertificateManagerServerImpl;