node-opcua-pki 3.0.2 → 3.1.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.
Files changed (53) hide show
  1. package/.ignore +6 -6
  2. package/.prettierrc +5 -5
  3. package/LICENSE +22 -22
  4. package/bin/crypto_create_CA.js +0 -0
  5. package/bin/crypto_create_CA_config.example.js +18 -18
  6. package/bin/install_prerequisite.js +9 -9
  7. package/dist/crypto_create_CA.d.ts +2 -2
  8. package/dist/crypto_create_CA.js +897 -897
  9. package/dist/index.d.ts +6 -6
  10. package/dist/index.js +44 -44
  11. package/dist/misc/applicationurn.d.ts +1 -1
  12. package/dist/misc/applicationurn.js +46 -46
  13. package/dist/misc/hostname.d.ts +8 -8
  14. package/dist/misc/hostname.js +102 -102
  15. package/dist/misc/install_prerequisite.d.ts +9 -9
  16. package/dist/misc/install_prerequisite.js +363 -360
  17. package/dist/misc/install_prerequisite.js.map +1 -1
  18. package/dist/misc/subject.d.ts +26 -26
  19. package/dist/misc/subject.js +121 -121
  20. package/dist/pki/certificate_authority.d.ts +61 -61
  21. package/dist/pki/certificate_authority.js +481 -481
  22. package/dist/pki/certificate_manager.d.ts +144 -144
  23. package/dist/pki/certificate_manager.js +883 -883
  24. package/dist/pki/certificate_manager.js.map +1 -1
  25. package/dist/pki/common.d.ts +5 -5
  26. package/dist/pki/common.js +2 -2
  27. package/dist/pki/templates/ca_config_template.cnf.d.ts +2 -2
  28. package/dist/pki/templates/ca_config_template.cnf.js +129 -129
  29. package/dist/pki/templates/simple_config_template.cnf.d.ts +2 -2
  30. package/dist/pki/templates/simple_config_template.cnf.js +75 -75
  31. package/dist/pki/toolbox.d.ts +160 -160
  32. package/dist/pki/toolbox.js +699 -699
  33. package/dist/pki/toolbox_pfx.js +18 -18
  34. package/lib/crypto_create_CA.ts +1135 -1135
  35. package/lib/index.ts +28 -28
  36. package/lib/misc/applicationurn.ts +45 -45
  37. package/lib/misc/hostname.ts +89 -89
  38. package/lib/misc/install_prerequisite.ts +454 -454
  39. package/lib/misc/subject.ts +141 -141
  40. package/lib/pki/certificate_manager.ts +1 -1
  41. package/lib/pki/common.ts +5 -5
  42. package/lib/pki/templates/ca_config_template.cnf.ts +129 -129
  43. package/lib/pki/templates/simple_config_template.cnf.ts +75 -75
  44. package/lib/pki/toolbox_pfx.ts +19 -19
  45. package/package.json +89 -89
  46. package/readme.md +214 -214
  47. package/tsconfig.json +20 -20
  48. package/dist/misc/fs.d.ts +0 -24
  49. package/dist/misc/fs.js +0 -21
  50. package/dist/misc/fs.js.map +0 -1
  51. package/dist/misc/get_default_filesystem.d.ts +0 -2
  52. package/dist/misc/get_default_filesystem.js +0 -9
  53. package/dist/misc/get_default_filesystem.js.map +0 -1
@@ -1,898 +1,898 @@
1
- "use strict";
2
- /* eslint-disable @typescript-eslint/no-unused-vars */
3
- // ---------------------------------------------------------------------------------------------------------------------
4
- // node-opcua
5
- // ---------------------------------------------------------------------------------------------------------------------
6
- // Copyright (c) 2014-2022 - Etienne Rossignon - etienne.rossignon (at) gadz.org
7
- // Copyright (c) 2022 - Sterfive.com
8
- // ---------------------------------------------------------------------------------------------------------------------
9
- //
10
- // This project is licensed under the terms of the MIT license.
11
- //
12
- // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
13
- // documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
14
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
15
- // permit persons to whom the Software is furnished to do so, subject to the following conditions:
16
- //
17
- // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
18
- // Software.
19
- //
20
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
21
- // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
22
- // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23
- // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
- // ---------------------------------------------------------------------------------------------------------------------
25
- // Error.stackTraceLimit = Infinity;
26
- // tslint:disable:variable-name
27
- // tslint:disable:no-console
28
- // tslint:disable:object-literal-sort-keys
29
- // tslint:disable:no-shadowed-variable
30
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
31
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
32
- return new (P || (P = Promise))(function (resolve, reject) {
33
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
34
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
35
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
36
- step((generator = generator.apply(thisArg, _arguments || [])).next());
37
- });
38
- };
39
- Object.defineProperty(exports, "__esModule", { value: true });
40
- exports.main = void 0;
41
- const assert = require("assert");
42
- const chalk = require("chalk");
43
- const rimraf = require("rimraf");
44
- const fs = require("fs");
45
- const path = require("path");
46
- const os = require("os");
47
- const util_1 = require("util");
48
- const applicationurn_1 = require("./misc/applicationurn");
49
- const hostname_1 = require("./misc/hostname");
50
- const subject_1 = require("./misc/subject");
51
- const certificate_authority_1 = require("./pki/certificate_authority");
52
- const certificate_manager_1 = require("./pki/certificate_manager");
53
- const toolbox_1 = require("./pki/toolbox");
54
- // see https://github.com/yargs/yargs/issues/781
55
- const commands = require("yargs");
56
- // eslint-disable-next-line @typescript-eslint/no-var-requires
57
- const { hideBin } = require("yargs/helpers");
58
- // eslint-disable-next-line @typescript-eslint/no-var-requires
59
- const argv = require("yargs/yargs")(hideBin(process.argv));
60
- const epilog = "Copyright (c) sterfive - node-opcua - 2017-2022";
61
- // ------------------------------------------------- some useful dates
62
- function get_offset_date(date, nbDays) {
63
- const d = new Date(date.getTime());
64
- d.setDate(d.getDate() + nbDays);
65
- return d;
66
- }
67
- const today = new Date();
68
- const yesterday = get_offset_date(today, -1);
69
- const two_years_ago = get_offset_date(today, -2 * 365);
70
- const next_year = get_offset_date(today, 365);
71
- let gLocalConfig = {};
72
- let g_certificateAuthority; // the Certificate Authority
73
- /***
74
- *
75
- *
76
- * prerequisites :
77
- * g_config.CAFolder : the folder of the CA
78
- */
79
- function construct_CertificateAuthority(subject) {
80
- return __awaiter(this, void 0, void 0, function* () {
81
- // verify that g_config file has been loaded
82
- assert(typeof gLocalConfig.CAFolder === "string", "expecting a CAFolder in config");
83
- assert(typeof gLocalConfig.keySize === "number", "expecting a keySize in config");
84
- if (!g_certificateAuthority) {
85
- g_certificateAuthority = new certificate_authority_1.CertificateAuthority({
86
- keySize: gLocalConfig.keySize,
87
- location: gLocalConfig.CAFolder,
88
- subject,
89
- });
90
- yield g_certificateAuthority.initialize();
91
- }
92
- });
93
- }
94
- let certificateManager; // the Certificate Manager
95
- /***
96
- *
97
- *
98
- * prerequisites :
99
- * g_config.PKIFolder : the folder of the PKI
100
- */
101
- function construct_CertificateManager() {
102
- return __awaiter(this, void 0, void 0, function* () {
103
- assert(typeof gLocalConfig.PKIFolder === "string", "expecting a PKIFolder in config");
104
- if (!certificateManager) {
105
- certificateManager = new certificate_manager_1.CertificateManager({
106
- keySize: gLocalConfig.keySize,
107
- location: gLocalConfig.PKIFolder,
108
- });
109
- yield certificateManager.initialize();
110
- }
111
- });
112
- }
113
- function displayConfig(config) {
114
- function w(str, l) {
115
- return (str + " ").substring(0, l);
116
- }
117
- console.log(chalk.yellow(" configuration = "));
118
- for (const [key, value] of Object.entries(config)) {
119
- console.log(" " + chalk.yellow(w(key, 30)) + " : " + chalk.cyan(value.toString()));
120
- }
121
- }
122
- function default_template_content() {
123
- // istanbul ignore next
124
- if (process.pkg && process.pkg.entrypoint) {
125
- // we are using PKG compiled package !
126
- // console.log("___filename", __filename);
127
- // console.log("__dirname", __dirname);
128
- // console.log("process.pkg.entrypoint", (process as any).pkg.entrypoint);
129
- const a = fs.readFileSync(path.join(__dirname, "../../bin/crypto_create_CA_config.example.js"), "utf8");
130
- console.log(a);
131
- return a;
132
- }
133
- function find_default_config_template() {
134
- const rootFolder = find_module_root_folder();
135
- let default_config_template = path.join(rootFolder, "bin", path.basename(__filename, ".js") + "_config.example.js");
136
- if (!fs.existsSync(default_config_template)) {
137
- default_config_template = path.join(__dirname, "..", path.basename(__filename, ".js") + "_config.example.js");
138
- if (!fs.existsSync(default_config_template)) {
139
- default_config_template = path.join(__dirname, "../bin/" + path.basename(__filename, ".js") + "_config.example.js");
140
- }
141
- }
142
- return default_config_template;
143
- }
144
- const default_config_template = find_default_config_template();
145
- assert(fs.existsSync(default_config_template));
146
- const default_config_template_content = fs.readFileSync(default_config_template, "utf8");
147
- return default_config_template_content;
148
- }
149
- /**
150
- *
151
- */
152
- function find_module_root_folder() {
153
- let rootFolder = path.join(__dirname);
154
- for (let i = 0; i < 4; i++) {
155
- if (fs.existsSync(path.join(rootFolder, "package.json"))) {
156
- return rootFolder;
157
- }
158
- rootFolder = path.join(rootFolder, "..");
159
- }
160
- assert(fs.existsSync(path.join(rootFolder, "package.json")), "root folder must have a package.json file");
161
- return rootFolder;
162
- }
163
- /* eslint complexity:off, max-statements:off */
164
- function readConfiguration(argv) {
165
- return __awaiter(this, void 0, void 0, function* () {
166
- if (argv.silent) {
167
- toolbox_1.g_config.silent = true;
168
- }
169
- else {
170
- toolbox_1.g_config.silent = false;
171
- }
172
- const fqdn = yield (0, hostname_1.extractFullyQualifiedDomainName)();
173
- const hostname = os.hostname();
174
- let certificateDir;
175
- function performSubstitution(str) {
176
- str = str.replace("{CWD}", process.cwd());
177
- if (certificateDir) {
178
- str = str.replace("{root}", certificateDir);
179
- }
180
- if (gLocalConfig && gLocalConfig.PKIFolder) {
181
- str = str.replace("{PKIFolder}", gLocalConfig.PKIFolder);
182
- }
183
- str = str.replace("{hostname}", hostname);
184
- str = str.replace("%FQDN%", fqdn);
185
- return str;
186
- }
187
- function prepare(file) {
188
- const tmp = path.resolve(performSubstitution(file));
189
- return (0, toolbox_1.make_path)(tmp);
190
- }
191
- // ------------------------------------------------------------------------------------------------------------
192
- certificateDir = argv.root;
193
- assert(typeof certificateDir === "string");
194
- certificateDir = prepare(certificateDir);
195
- (0, toolbox_1.mkdir)(certificateDir);
196
- assert(fs.existsSync(certificateDir));
197
- // ------------------------------------------------------------------------------------------------------------
198
- const default_config = path.join(certificateDir, "config.js");
199
- if (!fs.existsSync(default_config)) {
200
- // copy
201
- (0, toolbox_1.debugLog)(chalk.yellow(" Creating default g_config file "), chalk.cyan(default_config));
202
- const default_config_template_content = default_template_content();
203
- fs.writeFileSync(default_config, default_config_template_content);
204
- }
205
- else {
206
- (0, toolbox_1.debugLog)(chalk.yellow(" using g_config file "), chalk.cyan(default_config));
207
- }
208
- if (!fs.existsSync(default_config)) {
209
- console.log(chalk.redBright(" cannot find config file ", default_config));
210
- }
211
- // see http://stackoverflow.com/questions/94445/using-openssl-what-does-unable-to-write-random-state-mean
212
- // set random file to be random.rnd in the same folder as the g_config file
213
- const defaultRandomFile = path.join(path.dirname(default_config), "random.rnd");
214
- (0, toolbox_1.setEnv)("RANDFILE", defaultRandomFile);
215
- /* eslint global-require: 0*/
216
- gLocalConfig = require(default_config);
217
- gLocalConfig.subject = new subject_1.Subject(gLocalConfig.subject || "");
218
- // if subject is provided on the command line , it has hight priority
219
- if (argv.subject) {
220
- gLocalConfig.subject = new subject_1.Subject(argv.subject);
221
- }
222
- // istanbul ignore next
223
- if (!gLocalConfig.subject.commonName) {
224
- throw new Error("subject must have a Common Name");
225
- }
226
- gLocalConfig.certificateDir = certificateDir;
227
- // ------------------------------------------------------------------------------------------------------------
228
- let CAFolder = argv.CAFolder || path.join(certificateDir, "CA");
229
- CAFolder = prepare(CAFolder);
230
- gLocalConfig.CAFolder = CAFolder;
231
- // ------------------------------------------------------------------------------------------------------------
232
- gLocalConfig.PKIFolder = path.join(gLocalConfig.certificateDir, "PKI");
233
- if (argv.PKIFolder) {
234
- gLocalConfig.PKIFolder = prepare(argv.PKIFolder);
235
- }
236
- gLocalConfig.PKIFolder = prepare(gLocalConfig.PKIFolder);
237
- if (argv.privateKey) {
238
- gLocalConfig.privateKey = prepare(argv.privateKey);
239
- }
240
- if (argv.applicationUri) {
241
- gLocalConfig.applicationUri = performSubstitution(argv.applicationUri);
242
- }
243
- if (argv.output) {
244
- gLocalConfig.outputFile = argv.output;
245
- }
246
- gLocalConfig.altNames = [];
247
- if (argv.altNames) {
248
- gLocalConfig.altNames = argv.altNames.split(";");
249
- }
250
- gLocalConfig.dns = [(0, hostname_1.getFullyQualifiedDomainName)()];
251
- if (argv.dns) {
252
- gLocalConfig.dns = argv.dns.split(",").map(performSubstitution);
253
- }
254
- gLocalConfig.ip = [];
255
- if (argv.ip) {
256
- gLocalConfig.ip = argv.ip.split(",");
257
- }
258
- if (argv.keySize) {
259
- const v = argv.keySize;
260
- if (v !== 1024 && v !== 2048 && v !== 3072 && v !== 4096) {
261
- throw new Error("invalid keysize specified " + v + " should be 1024,2048,3072 or 4096");
262
- }
263
- gLocalConfig.keySize = argv.keySize;
264
- }
265
- if (argv.validity) {
266
- gLocalConfig.validity = argv.validity;
267
- }
268
- // xx displayConfig(g_config);
269
- // ------------------------------------------------------------------------------------------------------------
270
- });
271
- }
272
- function add_standard_option(options, optionName) {
273
- switch (optionName) {
274
- case "root":
275
- options.root = {
276
- alias: "r",
277
- type: "string",
278
- default: "{CWD}/certificates",
279
- describe: "the location of the Certificate folder",
280
- };
281
- break;
282
- case "CAFolder":
283
- options.CAFolder = {
284
- alias: "c",
285
- type: "string",
286
- default: "{root}/CA",
287
- describe: "the location of the Certificate Authority folder",
288
- };
289
- break;
290
- case "PKIFolder":
291
- options.PKIFolder = {
292
- type: "string",
293
- default: "{root}/PKI",
294
- describe: "the location of the Public Key Infrastructure",
295
- };
296
- break;
297
- case "silent":
298
- options.silent = {
299
- alias: "s",
300
- type: "boolean",
301
- default: false,
302
- describe: "minimize output",
303
- };
304
- break;
305
- case "privateKey":
306
- options.privateKey = {
307
- alias: "p",
308
- type: "string",
309
- default: "{PKIFolder}/own/private_key.pem",
310
- describe: "the private key to use to generate certificate",
311
- };
312
- break;
313
- case "keySize":
314
- options.keySize = {
315
- alias: ["k", "keyLength"],
316
- type: "number",
317
- default: 2048,
318
- describe: "the private key size in bits (1024|2048|3072|4096)",
319
- };
320
- break;
321
- default:
322
- throw Error("Unknown option " + optionName);
323
- }
324
- }
325
- function on_completion(err, done) {
326
- assert(typeof done === "function", "expecting function");
327
- // istanbul ignore next
328
- if (err) {
329
- console.log(chalk.redBright("ERROR : ") + err.message);
330
- }
331
- done();
332
- }
333
- function createDefaultCertificate(base_name, prefix, key_length, applicationUri, dev) {
334
- return __awaiter(this, void 0, void 0, function* () {
335
- // possible key length in bits
336
- assert(key_length === 1024 || key_length === 2048 || key_length === 3072 || key_length === 4096);
337
- const private_key_file = (0, toolbox_1.make_path)(base_name, prefix + "key_" + key_length + ".pem");
338
- const public_key_file = (0, toolbox_1.make_path)(base_name, prefix + "public_key_" + key_length + ".pub");
339
- const certificate_file = (0, toolbox_1.make_path)(base_name, prefix + "cert_" + key_length + ".pem");
340
- const certificate_file_outofdate = (0, toolbox_1.make_path)(base_name, prefix + "cert_" + key_length + "_outofdate.pem");
341
- const certificate_file_not_active_yet = (0, toolbox_1.make_path)(base_name, prefix + "cert_" + key_length + "_not_active_yet.pem");
342
- const certificate_revoked = (0, toolbox_1.make_path)(base_name, prefix + "cert_" + key_length + "_revoked.pem");
343
- const self_signed_certificate_file = (0, toolbox_1.make_path)(base_name, prefix + "selfsigned_cert_" + key_length + ".pem");
344
- const fqdn = (0, hostname_1.getFullyQualifiedDomainName)();
345
- const hostname = os.hostname();
346
- const dns = [
347
- // for conformance reason, localhost shall not be present in the DNS field of COP
348
- // ***FORBIDEN** "localhost",
349
- (0, hostname_1.getFullyQualifiedDomainName)(),
350
- ];
351
- if (hostname !== fqdn) {
352
- dns.push(hostname);
353
- }
354
- const ip = [];
355
- function createCertificateIfNotExist(certificate, private_key, applicationUri, startDate, validity) {
356
- return __awaiter(this, void 0, void 0, function* () {
357
- // istanbul ignore next
358
- if (fs.existsSync(certificate)) {
359
- console.log(chalk.yellow(" certificate"), chalk.cyan(certificate), chalk.yellow(" already exists => skipping"));
360
- return "";
361
- }
362
- else {
363
- return yield createCertificate(certificate, private_key, applicationUri, startDate, validity);
364
- }
365
- });
366
- }
367
- function createCertificate(certificate, privateKey, applicationUri, startDate, validity) {
368
- return __awaiter(this, void 0, void 0, function* () {
369
- const certificateSigningRequestFile = certificate + ".csr";
370
- const configFile = (0, toolbox_1.make_path)(base_name, "../certificates/PKI/own/openssl.cnf");
371
- const dns = [os.hostname()];
372
- const ip = ["127.0.0.1"];
373
- const params = {
374
- applicationUri,
375
- privateKey,
376
- rootDir: ".",
377
- configFile,
378
- dns,
379
- ip,
380
- };
381
- // create CSR
382
- yield (0, util_1.promisify)(toolbox_1.createCertificateSigningRequest)(certificateSigningRequestFile, params);
383
- return yield g_certificateAuthority.signCertificateRequest(certificate, certificateSigningRequestFile, {
384
- applicationUri,
385
- dns,
386
- ip,
387
- startDate,
388
- validity,
389
- });
390
- });
391
- }
392
- function createSelfSignedCertificate(certificate, private_key, applicationUri, startDate, validity) {
393
- return __awaiter(this, void 0, void 0, function* () {
394
- yield g_certificateAuthority.createSelfSignedCertificate(certificate, private_key, {
395
- applicationUri,
396
- dns,
397
- ip,
398
- startDate,
399
- validity,
400
- });
401
- });
402
- }
403
- function revoke_certificate(certificate) {
404
- return __awaiter(this, void 0, void 0, function* () {
405
- yield g_certificateAuthority.revokeCertificate(certificate, {});
406
- });
407
- }
408
- function createPrivateKeyIfNotExist(privateKey, keyLength) {
409
- return __awaiter(this, void 0, void 0, function* () {
410
- if (fs.existsSync(privateKey)) {
411
- console.log(chalk.yellow(" privateKey"), chalk.cyan(privateKey), chalk.yellow(" already exists => skipping"));
412
- return;
413
- }
414
- else {
415
- yield (0, util_1.promisify)(toolbox_1.createPrivateKey)(privateKey, keyLength);
416
- }
417
- });
418
- }
419
- (0, toolbox_1.displaySubtitle)(" create private key :" + private_key_file);
420
- yield createPrivateKeyIfNotExist(private_key_file, key_length);
421
- (0, toolbox_1.displaySubtitle)(" extract public key " + public_key_file + " from private key ");
422
- yield (0, util_1.promisify)(toolbox_1.getPublicKeyFromPrivateKey)(private_key_file, public_key_file);
423
- (0, toolbox_1.displaySubtitle)(" create Certificate " + certificate_file);
424
- yield createCertificateIfNotExist(certificate_file, private_key_file, applicationUri, yesterday, 365);
425
- (0, toolbox_1.displaySubtitle)(" create self signed Certificate " + self_signed_certificate_file);
426
- if (fs.existsSync(self_signed_certificate_file)) {
427
- // self_signed certificate already exists
428
- return;
429
- }
430
- yield createSelfSignedCertificate(self_signed_certificate_file, private_key_file, applicationUri, yesterday, 365);
431
- if (dev) {
432
- yield createCertificateIfNotExist(certificate_file_outofdate, private_key_file, applicationUri, two_years_ago, 365);
433
- yield createCertificateIfNotExist(certificate_file_not_active_yet, private_key_file, applicationUri, next_year, 365);
434
- if (!fs.existsSync(certificate_revoked)) {
435
- // self_signed certificate already exists
436
- const certificate = yield createCertificateIfNotExist(certificate_revoked, private_key_file, applicationUri + "Revoked", // make sure we used a uniq URI here
437
- yesterday, 365);
438
- console.log(" certificate to revoke => ", certificate);
439
- revoke_certificate(certificate_revoked);
440
- }
441
- }
442
- });
443
- }
444
- // tslint:disable-next-line:no-empty
445
- let done = (err) => {
446
- /** */
447
- };
448
- function wrap(func) {
449
- return __awaiter(this, void 0, void 0, function* () {
450
- try {
451
- yield func();
452
- }
453
- catch (err) {
454
- on_completion(err, () => {
455
- /** */
456
- });
457
- }
458
- });
459
- }
460
- function create_default_certificates(dev) {
461
- return __awaiter(this, void 0, void 0, function* () {
462
- assert(gLocalConfig);
463
- const base_name = gLocalConfig.certificateDir || "";
464
- assert(fs.existsSync(base_name));
465
- let clientURN;
466
- let serverURN;
467
- let discoveryServerURN;
468
- wrap(() => __awaiter(this, void 0, void 0, function* () {
469
- yield (0, hostname_1.extractFullyQualifiedDomainName)();
470
- const hostname = os.hostname();
471
- const fqdn = (0, hostname_1.getFullyQualifiedDomainName)();
472
- console.log(chalk.yellow(" hostname = "), chalk.cyan(hostname));
473
- console.log(chalk.yellow(" fqdn = "), chalk.cyan(fqdn));
474
- clientURN = (0, applicationurn_1.makeApplicationUrn)(hostname, "NodeOPCUA-Client");
475
- serverURN = (0, applicationurn_1.makeApplicationUrn)(hostname, "NodeOPCUA-Server");
476
- discoveryServerURN = (0, applicationurn_1.makeApplicationUrn)(hostname, "NodeOPCUA-DiscoveryServer");
477
- (0, toolbox_1.displayTitle)("Create Application Certificate for Server & its private key");
478
- yield createDefaultCertificate(base_name, "client_", 1024, clientURN, dev);
479
- yield createDefaultCertificate(base_name, "client_", 2048, clientURN, dev);
480
- yield createDefaultCertificate(base_name, "client_", 3072, clientURN, dev);
481
- yield createDefaultCertificate(base_name, "client_", 4096, clientURN, dev);
482
- (0, toolbox_1.displayTitle)("Create Application Certificate for Client & its private key");
483
- yield createDefaultCertificate(base_name, "server_", 1024, serverURN, dev);
484
- yield createDefaultCertificate(base_name, "server_", 2048, serverURN, dev);
485
- yield createDefaultCertificate(base_name, "server_", 3072, serverURN, dev);
486
- yield createDefaultCertificate(base_name, "server_", 4096, serverURN, dev);
487
- (0, toolbox_1.displayTitle)("Create Application Certificate for DiscoveryServer & its private key");
488
- yield createDefaultCertificate(base_name, "discoveryServer_", 1024, discoveryServerURN, dev);
489
- yield createDefaultCertificate(base_name, "discoveryServer_", 2048, discoveryServerURN, dev);
490
- yield createDefaultCertificate(base_name, "discoveryServer_", 3072, discoveryServerURN, dev);
491
- yield createDefaultCertificate(base_name, "discoveryServer_", 4096, discoveryServerURN, dev);
492
- }));
493
- });
494
- }
495
- function createDefaultCertificates(dev) {
496
- return __awaiter(this, void 0, void 0, function* () {
497
- yield construct_CertificateAuthority("");
498
- yield construct_CertificateManager();
499
- yield create_default_certificates(dev);
500
- });
501
- }
502
- assert(typeof done === "function");
503
- argv
504
- .strict()
505
- .wrap(132)
506
- .command("demo", "create default certificate for node-opcua demos", (yargs) => {
507
- const options = {};
508
- options.dev = {
509
- type: "boolean",
510
- describe: "create all sort of fancy certificates for dev testing purposes",
511
- };
512
- options.clean = {
513
- type: "boolean",
514
- describe: "Purge existing directory [use with care!]",
515
- };
516
- add_standard_option(options, "silent");
517
- add_standard_option(options, "root");
518
- const local_argv = yargs
519
- .strict()
520
- .wrap(132)
521
- .options(options)
522
- .usage("$0 demo [--dev] [--silent] [--clean]")
523
- .example("$0 demo --dev", "create a set of demo certificates")
524
- .help("help").argv;
525
- return local_argv;
526
- }, (local_argv) => {
527
- wrap(() => __awaiter(void 0, void 0, void 0, function* () {
528
- yield (0, util_1.promisify)(toolbox_1.ensure_openssl_installed)();
529
- (0, toolbox_1.displayChapter)("Create Demo certificates");
530
- (0, toolbox_1.displayTitle)("reading configuration");
531
- yield readConfiguration(local_argv);
532
- if (local_argv.clean) {
533
- (0, toolbox_1.displayTitle)("Cleaning old certificates");
534
- assert(gLocalConfig);
535
- const certificateDir = gLocalConfig.certificateDir || "";
536
- yield (0, util_1.promisify)(rimraf)(certificateDir + "/*.pem*");
537
- yield (0, util_1.promisify)(rimraf)(certificateDir + "/*.pub*");
538
- yield (0, util_1.promisify)(toolbox_1.mkdir)(certificateDir);
539
- }
540
- (0, toolbox_1.displayTitle)("create certificates");
541
- yield createDefaultCertificates(local_argv.dev);
542
- (0, toolbox_1.displayChapter)("Demo certificates CREATED");
543
- }));
544
- })
545
- .command("createCA", "create a Certificate Authority",
546
- /* builder*/ (yargs) => {
547
- const options = {
548
- subject: {
549
- default: certificate_authority_1.defaultSubject,
550
- type: "string",
551
- describe: "the CA certificate subject",
552
- },
553
- };
554
- add_standard_option(options, "root");
555
- add_standard_option(options, "CAFolder");
556
- add_standard_option(options, "keySize");
557
- add_standard_option(options, "silent");
558
- const local_argv = yargs.strict().wrap(132).options(options).help("help").epilog(epilog).argv;
559
- return local_argv;
560
- },
561
- /*handler*/ (local_argv) => {
562
- wrap(() => __awaiter(void 0, void 0, void 0, function* () {
563
- yield (0, util_1.promisify)(toolbox_1.ensure_openssl_installed)();
564
- yield readConfiguration(local_argv);
565
- yield construct_CertificateAuthority(local_argv.subject);
566
- }));
567
- })
568
- .command("createPKI", "create a Public Key Infrastructure", (yargs) => {
569
- const options = {};
570
- add_standard_option(options, "root");
571
- add_standard_option(options, "PKIFolder");
572
- add_standard_option(options, "keySize");
573
- add_standard_option(options, "silent");
574
- return yargs.strict().wrap(132).options(options).help("help").epilog(epilog).argv;
575
- }, (local_argv) => {
576
- wrap(() => __awaiter(void 0, void 0, void 0, function* () {
577
- yield readConfiguration(local_argv);
578
- yield construct_CertificateManager();
579
- }));
580
- })
581
- // ----------------------------------------------- certificate
582
- .command("certificate", "create a new certificate", (yargs) => {
583
- const options = {
584
- applicationUri: {
585
- alias: "a",
586
- demand: true,
587
- describe: "the application URI",
588
- default: "urn:{hostname}:Node-OPCUA-Server",
589
- type: "string",
590
- },
591
- output: {
592
- default: "my_certificate.pem",
593
- alias: "o",
594
- demand: true,
595
- describe: "the name of the generated certificate =>",
596
- type: "string",
597
- },
598
- selfSigned: {
599
- alias: "s",
600
- default: false,
601
- type: "boolean",
602
- describe: "if true, certificate will be self-signed",
603
- },
604
- validity: {
605
- alias: "v",
606
- default: null,
607
- type: "number",
608
- describe: "the certificate validity in days",
609
- },
610
- dns: {
611
- default: "{hostname}",
612
- type: "string",
613
- describe: "the list of valid domain name (comma separated)",
614
- },
615
- ip: {
616
- default: "",
617
- type: "string",
618
- describe: "the list of valid IPs (comma separated)",
619
- },
620
- subject: {
621
- default: "",
622
- type: "string",
623
- describe: "the certificate subject ( for instance C=FR/ST=Centre/L=Orleans/O=SomeOrganization/CN=Hello )",
624
- },
625
- };
626
- add_standard_option(options, "silent");
627
- add_standard_option(options, "root");
628
- add_standard_option(options, "CAFolder");
629
- add_standard_option(options, "PKIFolder");
630
- add_standard_option(options, "privateKey");
631
- return yargs.strict().wrap(132).options(options).help("help").epilog(epilog).argv;
632
- }, (local_argv) => {
633
- function command_certificate(local_argv) {
634
- return __awaiter(this, void 0, void 0, function* () {
635
- assert(typeof done === "function");
636
- const selfSigned = !!local_argv.selfSigned;
637
- if (!selfSigned) {
638
- yield command_full_certificate(local_argv);
639
- }
640
- else {
641
- yield command_selfsigned_certificate(local_argv);
642
- }
643
- });
644
- }
645
- function command_selfsigned_certificate(local_argv) {
646
- return __awaiter(this, void 0, void 0, function* () {
647
- const fqdn = yield (0, hostname_1.extractFullyQualifiedDomainName)();
648
- yield readConfiguration(local_argv);
649
- yield construct_CertificateManager();
650
- (0, toolbox_1.displaySubtitle)(" create self signed Certificate " + gLocalConfig.outputFile);
651
- let subject = local_argv.subject && local_argv.subject.length > 1
652
- ? new subject_1.Subject(local_argv.subject)
653
- : gLocalConfig.subject || "";
654
- subject = JSON.parse(JSON.stringify(subject));
655
- const params = {
656
- applicationUri: gLocalConfig.applicationUri || "",
657
- dns: gLocalConfig.dns || [],
658
- ip: gLocalConfig.ip || [],
659
- outputFile: gLocalConfig.outputFile || "self_signed_certificate.pem",
660
- startDate: gLocalConfig.startDate || new Date(),
661
- subject,
662
- validity: gLocalConfig.validity || 365,
663
- };
664
- yield (0, util_1.promisify)(certificateManager.createSelfSignedCertificate).call(certificateManager, params);
665
- });
666
- }
667
- function command_full_certificate(local_argv) {
668
- return __awaiter(this, void 0, void 0, function* () {
669
- yield readConfiguration(local_argv);
670
- yield construct_CertificateManager();
671
- yield construct_CertificateAuthority("");
672
- assert(fs.existsSync(gLocalConfig.CAFolder || ""), " CA folder must exist");
673
- gLocalConfig.privateKey = undefined; // use PKI private key
674
- // create a Certificate Request from the certificate Manager
675
- gLocalConfig.subject =
676
- local_argv.subject && local_argv.subject.length > 1 ? local_argv.subject : gLocalConfig.subject;
677
- const csr_file = yield (0, util_1.promisify)(certificateManager.createCertificateRequest).call(certificateManager, gLocalConfig);
678
- if (!csr_file) {
679
- return;
680
- }
681
- console.log(" csr_file = ", csr_file);
682
- const certificate = csr_file.replace(".csr", ".pem");
683
- if (fs.existsSync(certificate)) {
684
- throw new Error(" File " + certificate + " already exist");
685
- }
686
- yield (0, util_1.promisify)(g_certificateAuthority.signCertificateRequest).call(g_certificateAuthority, certificate, csr_file, gLocalConfig);
687
- assert(typeof gLocalConfig.outputFile === "string");
688
- fs.writeFileSync(gLocalConfig.outputFile || "", fs.readFileSync(certificate, "ascii"));
689
- });
690
- }
691
- wrap(() => __awaiter(void 0, void 0, void 0, function* () { return yield command_certificate(local_argv); }));
692
- })
693
- // ----------------------------------------------- revoke
694
- .command("revoke <certificateFile>", "revoke a existing certificate", (yargs) => {
695
- const options = {};
696
- add_standard_option(options, "root");
697
- add_standard_option(options, "CAFolder");
698
- yargs.strict().wrap(132).help("help").usage("$0 revoke my_certificate.pem").options(options).epilog(epilog);
699
- return yargs;
700
- }, (local_argv) => {
701
- function revoke_certificate(certificate, callback) {
702
- g_certificateAuthority.revokeCertificate(certificate, {}, callback);
703
- }
704
- wrap(() => __awaiter(void 0, void 0, void 0, function* () {
705
- // example : node bin\crypto_create_CA.js revoke my_certificate.pem
706
- const certificate = path.resolve(local_argv.certificateFile);
707
- console.log(chalk.yellow(" Certificate to revoke : "), chalk.cyan(certificate));
708
- if (!fs.existsSync(certificate)) {
709
- throw new Error("cannot find certificate to revoke " + certificate);
710
- }
711
- yield readConfiguration(local_argv);
712
- yield construct_CertificateAuthority("");
713
- yield (0, util_1.promisify)(revoke_certificate)(certificate);
714
- console.log("done ... ");
715
- console.log(" crl = ", g_certificateAuthority.revocationList);
716
- console.log("\nyou should now publish the new Certificate Revocation List");
717
- }));
718
- })
719
- .command("csr", "create a certificate signing request", (yargs) => {
720
- const options = {
721
- applicationUri: {
722
- alias: "a",
723
- // demand: true,
724
- describe: "the application URI",
725
- default: "urn:{hostname}:Node-OPCUA-Server",
726
- type: "string",
727
- },
728
- output: {
729
- default: "my_certificate_signing_request.csr",
730
- alias: "o",
731
- // demand: true,
732
- describe: "the name of the generated signing_request",
733
- type: "string",
734
- },
735
- dns: {
736
- default: "{hostname}",
737
- type: "string",
738
- describe: "the list of valid domain name (comma separated)",
739
- },
740
- ip: {
741
- default: "",
742
- type: "string",
743
- describe: "the list of valid IPs (comma separated)",
744
- },
745
- subject: {
746
- default: "/CN=Certificate",
747
- type: "string",
748
- describe: "the certificate subject ( for instance /C=FR/ST=Centre/L=Orleans/O=SomeOrganization/CN=Hello )",
749
- },
750
- };
751
- add_standard_option(options, "silent");
752
- add_standard_option(options, "root");
753
- add_standard_option(options, "PKIFolder");
754
- add_standard_option(options, "privateKey");
755
- return yargs.strict().wrap(132).options(options).help("help").epilog(epilog).argv;
756
- }, (local_argv) => {
757
- wrap(() => __awaiter(void 0, void 0, void 0, function* () {
758
- yield readConfiguration(local_argv);
759
- if (!fs.existsSync(gLocalConfig.PKIFolder || "")) {
760
- console.log("PKI folder must exist");
761
- }
762
- yield construct_CertificateManager();
763
- if (!gLocalConfig.outputFile || fs.existsSync(gLocalConfig.outputFile)) {
764
- throw new Error(" File " + gLocalConfig.outputFile + " already exist");
765
- }
766
- gLocalConfig.privateKey = undefined; // use PKI private key
767
- // create a Certificate Request from the certificate Manager
768
- gLocalConfig.subject =
769
- local_argv.subject && local_argv.subject.length > 1 ? local_argv.subject : gLocalConfig.subject;
770
- const internal_csr_file = yield (0, util_1.promisify)(certificateManager.createCertificateRequest).call(certificateManager, gLocalConfig);
771
- if (!internal_csr_file) {
772
- return;
773
- }
774
- if (!gLocalConfig.outputFile) {
775
- console.log("please specify a output file");
776
- return;
777
- }
778
- const csr = yield fs.promises.readFile(internal_csr_file, "utf-8");
779
- fs.writeFileSync(gLocalConfig.outputFile || "", csr, "utf-8");
780
- console.log("Subject = ", gLocalConfig.subject);
781
- console.log("applicationUri = ", gLocalConfig.applicationUri);
782
- console.log("altNames = ", gLocalConfig.altNames);
783
- console.log("dns = ", gLocalConfig.dns);
784
- console.log("ip = ", gLocalConfig.ip);
785
- console.log("CSR file = ", gLocalConfig.outputFile);
786
- }));
787
- })
788
- .command("sign", "validate a certificate signing request and generate a certificate", (yargs) => {
789
- const options = {
790
- csr: {
791
- alias: "i",
792
- default: "my_certificate_signing_request.csr",
793
- type: "string",
794
- demandOption: true,
795
- description: "the csr"
796
- },
797
- output: {
798
- default: "my_certificate.pem",
799
- alias: "o",
800
- demand: true,
801
- describe: "the name of the generated certificate",
802
- type: "string",
803
- },
804
- validity: {
805
- alias: "v",
806
- default: 365,
807
- type: "number",
808
- describe: "the certificate validity in days",
809
- },
810
- };
811
- add_standard_option(options, "silent");
812
- add_standard_option(options, "root");
813
- add_standard_option(options, "CAFolder");
814
- return yargs.strict().wrap(132).options(options).help("help").epilog(epilog).argv;
815
- }, (local_argv) => {
816
- wrap(() => __awaiter(void 0, void 0, void 0, function* () {
817
- /** */
818
- yield readConfiguration(local_argv);
819
- if (!fs.existsSync(gLocalConfig.CAFolder || "")) {
820
- throw new Error("CA folder must exist:" + gLocalConfig.CAFolder);
821
- }
822
- yield construct_CertificateAuthority("");
823
- const csr_file = path.resolve(local_argv.csr || "");
824
- if (!fs.existsSync(csr_file)) {
825
- throw new Error("Certificate signing request doesn't exist: " + csr_file);
826
- }
827
- const certificate = path.resolve(local_argv.output || csr_file.replace(".csr", ".pem"));
828
- if (fs.existsSync(certificate)) {
829
- throw new Error(" File " + certificate + " already exist");
830
- }
831
- yield (0, util_1.promisify)(g_certificateAuthority.signCertificateRequest).call(g_certificateAuthority, certificate, csr_file, gLocalConfig);
832
- assert(typeof gLocalConfig.outputFile === "string");
833
- fs.writeFileSync(gLocalConfig.outputFile || "", fs.readFileSync(certificate, "ascii"));
834
- }));
835
- })
836
- .command("dump <certificateFile>", "display a certificate", () => {
837
- /** */
838
- }, (yargs) => {
839
- wrap(() => __awaiter(void 0, void 0, void 0, function* () {
840
- const data = yield (0, util_1.promisify)(toolbox_1.dumpCertificate)(yargs.certificateFile);
841
- console.log(data);
842
- }));
843
- })
844
- .command("toder <pemCertificate>", "convert a certificate to a DER format with finger print", () => {
845
- /** */
846
- }, (yargs) => {
847
- wrap(() => __awaiter(void 0, void 0, void 0, function* () {
848
- yield (0, util_1.promisify)(toolbox_1.toDer)(argv.pemCertificate);
849
- }));
850
- })
851
- .command("fingerprint <certificateFile>", "print the certificate fingerprint", () => {
852
- /** */
853
- }, (local_argv) => {
854
- wrap(() => __awaiter(void 0, void 0, void 0, function* () {
855
- const certificate = local_argv.certificateFile;
856
- const data = yield (0, util_1.promisify)(toolbox_1.fingerprint)(certificate);
857
- if (!data)
858
- return;
859
- const s = data.split("=")[1].split(":").join("").trim();
860
- console.log(s);
861
- }));
862
- })
863
- .command("$0", "help", (yargs) => {
864
- console.log("--help for help");
865
- return yargs;
866
- })
867
- .epilog(epilog)
868
- .help("help")
869
- .strict().argv;
870
- function main(argumentsList, _done) {
871
- if (_done) {
872
- done = _done;
873
- }
874
- commands.parse(argumentsList, (err, g_argv) => {
875
- // istanbul ignore next
876
- if (err) {
877
- console.log(" err = ", err);
878
- console.log(" use --help for more info");
879
- setImmediate(() => {
880
- commands.showHelp();
881
- done(err);
882
- });
883
- }
884
- else {
885
- if (g_argv.help) {
886
- setImmediate(() => {
887
- commands.showHelp();
888
- done();
889
- });
890
- }
891
- else {
892
- done();
893
- }
894
- }
895
- });
896
- }
897
- exports.main = main;
1
+ "use strict";
2
+ /* eslint-disable @typescript-eslint/no-unused-vars */
3
+ // ---------------------------------------------------------------------------------------------------------------------
4
+ // node-opcua
5
+ // ---------------------------------------------------------------------------------------------------------------------
6
+ // Copyright (c) 2014-2022 - Etienne Rossignon - etienne.rossignon (at) gadz.org
7
+ // Copyright (c) 2022 - Sterfive.com
8
+ // ---------------------------------------------------------------------------------------------------------------------
9
+ //
10
+ // This project is licensed under the terms of the MIT license.
11
+ //
12
+ // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
13
+ // documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
14
+ // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
15
+ // permit persons to whom the Software is furnished to do so, subject to the following conditions:
16
+ //
17
+ // The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
18
+ // Software.
19
+ //
20
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
21
+ // WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
22
+ // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23
+ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
+ // ---------------------------------------------------------------------------------------------------------------------
25
+ // Error.stackTraceLimit = Infinity;
26
+ // tslint:disable:variable-name
27
+ // tslint:disable:no-console
28
+ // tslint:disable:object-literal-sort-keys
29
+ // tslint:disable:no-shadowed-variable
30
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
31
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
32
+ return new (P || (P = Promise))(function (resolve, reject) {
33
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
34
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
35
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
36
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
37
+ });
38
+ };
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ exports.main = void 0;
41
+ const assert = require("assert");
42
+ const chalk = require("chalk");
43
+ const rimraf = require("rimraf");
44
+ const fs = require("fs");
45
+ const path = require("path");
46
+ const os = require("os");
47
+ const util_1 = require("util");
48
+ const applicationurn_1 = require("./misc/applicationurn");
49
+ const hostname_1 = require("./misc/hostname");
50
+ const subject_1 = require("./misc/subject");
51
+ const certificate_authority_1 = require("./pki/certificate_authority");
52
+ const certificate_manager_1 = require("./pki/certificate_manager");
53
+ const toolbox_1 = require("./pki/toolbox");
54
+ // see https://github.com/yargs/yargs/issues/781
55
+ const commands = require("yargs");
56
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
57
+ const { hideBin } = require("yargs/helpers");
58
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
59
+ const argv = require("yargs/yargs")(hideBin(process.argv));
60
+ const epilog = "Copyright (c) sterfive - node-opcua - 2017-2022";
61
+ // ------------------------------------------------- some useful dates
62
+ function get_offset_date(date, nbDays) {
63
+ const d = new Date(date.getTime());
64
+ d.setDate(d.getDate() + nbDays);
65
+ return d;
66
+ }
67
+ const today = new Date();
68
+ const yesterday = get_offset_date(today, -1);
69
+ const two_years_ago = get_offset_date(today, -2 * 365);
70
+ const next_year = get_offset_date(today, 365);
71
+ let gLocalConfig = {};
72
+ let g_certificateAuthority; // the Certificate Authority
73
+ /***
74
+ *
75
+ *
76
+ * prerequisites :
77
+ * g_config.CAFolder : the folder of the CA
78
+ */
79
+ function construct_CertificateAuthority(subject) {
80
+ return __awaiter(this, void 0, void 0, function* () {
81
+ // verify that g_config file has been loaded
82
+ assert(typeof gLocalConfig.CAFolder === "string", "expecting a CAFolder in config");
83
+ assert(typeof gLocalConfig.keySize === "number", "expecting a keySize in config");
84
+ if (!g_certificateAuthority) {
85
+ g_certificateAuthority = new certificate_authority_1.CertificateAuthority({
86
+ keySize: gLocalConfig.keySize,
87
+ location: gLocalConfig.CAFolder,
88
+ subject,
89
+ });
90
+ yield g_certificateAuthority.initialize();
91
+ }
92
+ });
93
+ }
94
+ let certificateManager; // the Certificate Manager
95
+ /***
96
+ *
97
+ *
98
+ * prerequisites :
99
+ * g_config.PKIFolder : the folder of the PKI
100
+ */
101
+ function construct_CertificateManager() {
102
+ return __awaiter(this, void 0, void 0, function* () {
103
+ assert(typeof gLocalConfig.PKIFolder === "string", "expecting a PKIFolder in config");
104
+ if (!certificateManager) {
105
+ certificateManager = new certificate_manager_1.CertificateManager({
106
+ keySize: gLocalConfig.keySize,
107
+ location: gLocalConfig.PKIFolder,
108
+ });
109
+ yield certificateManager.initialize();
110
+ }
111
+ });
112
+ }
113
+ function displayConfig(config) {
114
+ function w(str, l) {
115
+ return (str + " ").substring(0, l);
116
+ }
117
+ console.log(chalk.yellow(" configuration = "));
118
+ for (const [key, value] of Object.entries(config)) {
119
+ console.log(" " + chalk.yellow(w(key, 30)) + " : " + chalk.cyan(value.toString()));
120
+ }
121
+ }
122
+ function default_template_content() {
123
+ // istanbul ignore next
124
+ if (process.pkg && process.pkg.entrypoint) {
125
+ // we are using PKG compiled package !
126
+ // console.log("___filename", __filename);
127
+ // console.log("__dirname", __dirname);
128
+ // console.log("process.pkg.entrypoint", (process as any).pkg.entrypoint);
129
+ const a = fs.readFileSync(path.join(__dirname, "../../bin/crypto_create_CA_config.example.js"), "utf8");
130
+ console.log(a);
131
+ return a;
132
+ }
133
+ function find_default_config_template() {
134
+ const rootFolder = find_module_root_folder();
135
+ let default_config_template = path.join(rootFolder, "bin", path.basename(__filename, ".js") + "_config.example.js");
136
+ if (!fs.existsSync(default_config_template)) {
137
+ default_config_template = path.join(__dirname, "..", path.basename(__filename, ".js") + "_config.example.js");
138
+ if (!fs.existsSync(default_config_template)) {
139
+ default_config_template = path.join(__dirname, "../bin/" + path.basename(__filename, ".js") + "_config.example.js");
140
+ }
141
+ }
142
+ return default_config_template;
143
+ }
144
+ const default_config_template = find_default_config_template();
145
+ assert(fs.existsSync(default_config_template));
146
+ const default_config_template_content = fs.readFileSync(default_config_template, "utf8");
147
+ return default_config_template_content;
148
+ }
149
+ /**
150
+ *
151
+ */
152
+ function find_module_root_folder() {
153
+ let rootFolder = path.join(__dirname);
154
+ for (let i = 0; i < 4; i++) {
155
+ if (fs.existsSync(path.join(rootFolder, "package.json"))) {
156
+ return rootFolder;
157
+ }
158
+ rootFolder = path.join(rootFolder, "..");
159
+ }
160
+ assert(fs.existsSync(path.join(rootFolder, "package.json")), "root folder must have a package.json file");
161
+ return rootFolder;
162
+ }
163
+ /* eslint complexity:off, max-statements:off */
164
+ function readConfiguration(argv) {
165
+ return __awaiter(this, void 0, void 0, function* () {
166
+ if (argv.silent) {
167
+ toolbox_1.g_config.silent = true;
168
+ }
169
+ else {
170
+ toolbox_1.g_config.silent = false;
171
+ }
172
+ const fqdn = yield (0, hostname_1.extractFullyQualifiedDomainName)();
173
+ const hostname = os.hostname();
174
+ let certificateDir;
175
+ function performSubstitution(str) {
176
+ str = str.replace("{CWD}", process.cwd());
177
+ if (certificateDir) {
178
+ str = str.replace("{root}", certificateDir);
179
+ }
180
+ if (gLocalConfig && gLocalConfig.PKIFolder) {
181
+ str = str.replace("{PKIFolder}", gLocalConfig.PKIFolder);
182
+ }
183
+ str = str.replace("{hostname}", hostname);
184
+ str = str.replace("%FQDN%", fqdn);
185
+ return str;
186
+ }
187
+ function prepare(file) {
188
+ const tmp = path.resolve(performSubstitution(file));
189
+ return (0, toolbox_1.make_path)(tmp);
190
+ }
191
+ // ------------------------------------------------------------------------------------------------------------
192
+ certificateDir = argv.root;
193
+ assert(typeof certificateDir === "string");
194
+ certificateDir = prepare(certificateDir);
195
+ (0, toolbox_1.mkdir)(certificateDir);
196
+ assert(fs.existsSync(certificateDir));
197
+ // ------------------------------------------------------------------------------------------------------------
198
+ const default_config = path.join(certificateDir, "config.js");
199
+ if (!fs.existsSync(default_config)) {
200
+ // copy
201
+ (0, toolbox_1.debugLog)(chalk.yellow(" Creating default g_config file "), chalk.cyan(default_config));
202
+ const default_config_template_content = default_template_content();
203
+ fs.writeFileSync(default_config, default_config_template_content);
204
+ }
205
+ else {
206
+ (0, toolbox_1.debugLog)(chalk.yellow(" using g_config file "), chalk.cyan(default_config));
207
+ }
208
+ if (!fs.existsSync(default_config)) {
209
+ console.log(chalk.redBright(" cannot find config file ", default_config));
210
+ }
211
+ // see http://stackoverflow.com/questions/94445/using-openssl-what-does-unable-to-write-random-state-mean
212
+ // set random file to be random.rnd in the same folder as the g_config file
213
+ const defaultRandomFile = path.join(path.dirname(default_config), "random.rnd");
214
+ (0, toolbox_1.setEnv)("RANDFILE", defaultRandomFile);
215
+ /* eslint global-require: 0*/
216
+ gLocalConfig = require(default_config);
217
+ gLocalConfig.subject = new subject_1.Subject(gLocalConfig.subject || "");
218
+ // if subject is provided on the command line , it has hight priority
219
+ if (argv.subject) {
220
+ gLocalConfig.subject = new subject_1.Subject(argv.subject);
221
+ }
222
+ // istanbul ignore next
223
+ if (!gLocalConfig.subject.commonName) {
224
+ throw new Error("subject must have a Common Name");
225
+ }
226
+ gLocalConfig.certificateDir = certificateDir;
227
+ // ------------------------------------------------------------------------------------------------------------
228
+ let CAFolder = argv.CAFolder || path.join(certificateDir, "CA");
229
+ CAFolder = prepare(CAFolder);
230
+ gLocalConfig.CAFolder = CAFolder;
231
+ // ------------------------------------------------------------------------------------------------------------
232
+ gLocalConfig.PKIFolder = path.join(gLocalConfig.certificateDir, "PKI");
233
+ if (argv.PKIFolder) {
234
+ gLocalConfig.PKIFolder = prepare(argv.PKIFolder);
235
+ }
236
+ gLocalConfig.PKIFolder = prepare(gLocalConfig.PKIFolder);
237
+ if (argv.privateKey) {
238
+ gLocalConfig.privateKey = prepare(argv.privateKey);
239
+ }
240
+ if (argv.applicationUri) {
241
+ gLocalConfig.applicationUri = performSubstitution(argv.applicationUri);
242
+ }
243
+ if (argv.output) {
244
+ gLocalConfig.outputFile = argv.output;
245
+ }
246
+ gLocalConfig.altNames = [];
247
+ if (argv.altNames) {
248
+ gLocalConfig.altNames = argv.altNames.split(";");
249
+ }
250
+ gLocalConfig.dns = [(0, hostname_1.getFullyQualifiedDomainName)()];
251
+ if (argv.dns) {
252
+ gLocalConfig.dns = argv.dns.split(",").map(performSubstitution);
253
+ }
254
+ gLocalConfig.ip = [];
255
+ if (argv.ip) {
256
+ gLocalConfig.ip = argv.ip.split(",");
257
+ }
258
+ if (argv.keySize) {
259
+ const v = argv.keySize;
260
+ if (v !== 1024 && v !== 2048 && v !== 3072 && v !== 4096) {
261
+ throw new Error("invalid keysize specified " + v + " should be 1024,2048,3072 or 4096");
262
+ }
263
+ gLocalConfig.keySize = argv.keySize;
264
+ }
265
+ if (argv.validity) {
266
+ gLocalConfig.validity = argv.validity;
267
+ }
268
+ // xx displayConfig(g_config);
269
+ // ------------------------------------------------------------------------------------------------------------
270
+ });
271
+ }
272
+ function add_standard_option(options, optionName) {
273
+ switch (optionName) {
274
+ case "root":
275
+ options.root = {
276
+ alias: "r",
277
+ type: "string",
278
+ default: "{CWD}/certificates",
279
+ describe: "the location of the Certificate folder",
280
+ };
281
+ break;
282
+ case "CAFolder":
283
+ options.CAFolder = {
284
+ alias: "c",
285
+ type: "string",
286
+ default: "{root}/CA",
287
+ describe: "the location of the Certificate Authority folder",
288
+ };
289
+ break;
290
+ case "PKIFolder":
291
+ options.PKIFolder = {
292
+ type: "string",
293
+ default: "{root}/PKI",
294
+ describe: "the location of the Public Key Infrastructure",
295
+ };
296
+ break;
297
+ case "silent":
298
+ options.silent = {
299
+ alias: "s",
300
+ type: "boolean",
301
+ default: false,
302
+ describe: "minimize output",
303
+ };
304
+ break;
305
+ case "privateKey":
306
+ options.privateKey = {
307
+ alias: "p",
308
+ type: "string",
309
+ default: "{PKIFolder}/own/private_key.pem",
310
+ describe: "the private key to use to generate certificate",
311
+ };
312
+ break;
313
+ case "keySize":
314
+ options.keySize = {
315
+ alias: ["k", "keyLength"],
316
+ type: "number",
317
+ default: 2048,
318
+ describe: "the private key size in bits (1024|2048|3072|4096)",
319
+ };
320
+ break;
321
+ default:
322
+ throw Error("Unknown option " + optionName);
323
+ }
324
+ }
325
+ function on_completion(err, done) {
326
+ assert(typeof done === "function", "expecting function");
327
+ // istanbul ignore next
328
+ if (err) {
329
+ console.log(chalk.redBright("ERROR : ") + err.message);
330
+ }
331
+ done();
332
+ }
333
+ function createDefaultCertificate(base_name, prefix, key_length, applicationUri, dev) {
334
+ return __awaiter(this, void 0, void 0, function* () {
335
+ // possible key length in bits
336
+ assert(key_length === 1024 || key_length === 2048 || key_length === 3072 || key_length === 4096);
337
+ const private_key_file = (0, toolbox_1.make_path)(base_name, prefix + "key_" + key_length + ".pem");
338
+ const public_key_file = (0, toolbox_1.make_path)(base_name, prefix + "public_key_" + key_length + ".pub");
339
+ const certificate_file = (0, toolbox_1.make_path)(base_name, prefix + "cert_" + key_length + ".pem");
340
+ const certificate_file_outofdate = (0, toolbox_1.make_path)(base_name, prefix + "cert_" + key_length + "_outofdate.pem");
341
+ const certificate_file_not_active_yet = (0, toolbox_1.make_path)(base_name, prefix + "cert_" + key_length + "_not_active_yet.pem");
342
+ const certificate_revoked = (0, toolbox_1.make_path)(base_name, prefix + "cert_" + key_length + "_revoked.pem");
343
+ const self_signed_certificate_file = (0, toolbox_1.make_path)(base_name, prefix + "selfsigned_cert_" + key_length + ".pem");
344
+ const fqdn = (0, hostname_1.getFullyQualifiedDomainName)();
345
+ const hostname = os.hostname();
346
+ const dns = [
347
+ // for conformance reason, localhost shall not be present in the DNS field of COP
348
+ // ***FORBIDEN** "localhost",
349
+ (0, hostname_1.getFullyQualifiedDomainName)(),
350
+ ];
351
+ if (hostname !== fqdn) {
352
+ dns.push(hostname);
353
+ }
354
+ const ip = [];
355
+ function createCertificateIfNotExist(certificate, private_key, applicationUri, startDate, validity) {
356
+ return __awaiter(this, void 0, void 0, function* () {
357
+ // istanbul ignore next
358
+ if (fs.existsSync(certificate)) {
359
+ console.log(chalk.yellow(" certificate"), chalk.cyan(certificate), chalk.yellow(" already exists => skipping"));
360
+ return "";
361
+ }
362
+ else {
363
+ return yield createCertificate(certificate, private_key, applicationUri, startDate, validity);
364
+ }
365
+ });
366
+ }
367
+ function createCertificate(certificate, privateKey, applicationUri, startDate, validity) {
368
+ return __awaiter(this, void 0, void 0, function* () {
369
+ const certificateSigningRequestFile = certificate + ".csr";
370
+ const configFile = (0, toolbox_1.make_path)(base_name, "../certificates/PKI/own/openssl.cnf");
371
+ const dns = [os.hostname()];
372
+ const ip = ["127.0.0.1"];
373
+ const params = {
374
+ applicationUri,
375
+ privateKey,
376
+ rootDir: ".",
377
+ configFile,
378
+ dns,
379
+ ip,
380
+ };
381
+ // create CSR
382
+ yield (0, util_1.promisify)(toolbox_1.createCertificateSigningRequest)(certificateSigningRequestFile, params);
383
+ return yield g_certificateAuthority.signCertificateRequest(certificate, certificateSigningRequestFile, {
384
+ applicationUri,
385
+ dns,
386
+ ip,
387
+ startDate,
388
+ validity,
389
+ });
390
+ });
391
+ }
392
+ function createSelfSignedCertificate(certificate, private_key, applicationUri, startDate, validity) {
393
+ return __awaiter(this, void 0, void 0, function* () {
394
+ yield g_certificateAuthority.createSelfSignedCertificate(certificate, private_key, {
395
+ applicationUri,
396
+ dns,
397
+ ip,
398
+ startDate,
399
+ validity,
400
+ });
401
+ });
402
+ }
403
+ function revoke_certificate(certificate) {
404
+ return __awaiter(this, void 0, void 0, function* () {
405
+ yield g_certificateAuthority.revokeCertificate(certificate, {});
406
+ });
407
+ }
408
+ function createPrivateKeyIfNotExist(privateKey, keyLength) {
409
+ return __awaiter(this, void 0, void 0, function* () {
410
+ if (fs.existsSync(privateKey)) {
411
+ console.log(chalk.yellow(" privateKey"), chalk.cyan(privateKey), chalk.yellow(" already exists => skipping"));
412
+ return;
413
+ }
414
+ else {
415
+ yield (0, util_1.promisify)(toolbox_1.createPrivateKey)(privateKey, keyLength);
416
+ }
417
+ });
418
+ }
419
+ (0, toolbox_1.displaySubtitle)(" create private key :" + private_key_file);
420
+ yield createPrivateKeyIfNotExist(private_key_file, key_length);
421
+ (0, toolbox_1.displaySubtitle)(" extract public key " + public_key_file + " from private key ");
422
+ yield (0, util_1.promisify)(toolbox_1.getPublicKeyFromPrivateKey)(private_key_file, public_key_file);
423
+ (0, toolbox_1.displaySubtitle)(" create Certificate " + certificate_file);
424
+ yield createCertificateIfNotExist(certificate_file, private_key_file, applicationUri, yesterday, 365);
425
+ (0, toolbox_1.displaySubtitle)(" create self signed Certificate " + self_signed_certificate_file);
426
+ if (fs.existsSync(self_signed_certificate_file)) {
427
+ // self_signed certificate already exists
428
+ return;
429
+ }
430
+ yield createSelfSignedCertificate(self_signed_certificate_file, private_key_file, applicationUri, yesterday, 365);
431
+ if (dev) {
432
+ yield createCertificateIfNotExist(certificate_file_outofdate, private_key_file, applicationUri, two_years_ago, 365);
433
+ yield createCertificateIfNotExist(certificate_file_not_active_yet, private_key_file, applicationUri, next_year, 365);
434
+ if (!fs.existsSync(certificate_revoked)) {
435
+ // self_signed certificate already exists
436
+ const certificate = yield createCertificateIfNotExist(certificate_revoked, private_key_file, applicationUri + "Revoked", // make sure we used a uniq URI here
437
+ yesterday, 365);
438
+ console.log(" certificate to revoke => ", certificate);
439
+ revoke_certificate(certificate_revoked);
440
+ }
441
+ }
442
+ });
443
+ }
444
+ // tslint:disable-next-line:no-empty
445
+ let done = (err) => {
446
+ /** */
447
+ };
448
+ function wrap(func) {
449
+ return __awaiter(this, void 0, void 0, function* () {
450
+ try {
451
+ yield func();
452
+ }
453
+ catch (err) {
454
+ on_completion(err, () => {
455
+ /** */
456
+ });
457
+ }
458
+ });
459
+ }
460
+ function create_default_certificates(dev) {
461
+ return __awaiter(this, void 0, void 0, function* () {
462
+ assert(gLocalConfig);
463
+ const base_name = gLocalConfig.certificateDir || "";
464
+ assert(fs.existsSync(base_name));
465
+ let clientURN;
466
+ let serverURN;
467
+ let discoveryServerURN;
468
+ wrap(() => __awaiter(this, void 0, void 0, function* () {
469
+ yield (0, hostname_1.extractFullyQualifiedDomainName)();
470
+ const hostname = os.hostname();
471
+ const fqdn = (0, hostname_1.getFullyQualifiedDomainName)();
472
+ console.log(chalk.yellow(" hostname = "), chalk.cyan(hostname));
473
+ console.log(chalk.yellow(" fqdn = "), chalk.cyan(fqdn));
474
+ clientURN = (0, applicationurn_1.makeApplicationUrn)(hostname, "NodeOPCUA-Client");
475
+ serverURN = (0, applicationurn_1.makeApplicationUrn)(hostname, "NodeOPCUA-Server");
476
+ discoveryServerURN = (0, applicationurn_1.makeApplicationUrn)(hostname, "NodeOPCUA-DiscoveryServer");
477
+ (0, toolbox_1.displayTitle)("Create Application Certificate for Server & its private key");
478
+ yield createDefaultCertificate(base_name, "client_", 1024, clientURN, dev);
479
+ yield createDefaultCertificate(base_name, "client_", 2048, clientURN, dev);
480
+ yield createDefaultCertificate(base_name, "client_", 3072, clientURN, dev);
481
+ yield createDefaultCertificate(base_name, "client_", 4096, clientURN, dev);
482
+ (0, toolbox_1.displayTitle)("Create Application Certificate for Client & its private key");
483
+ yield createDefaultCertificate(base_name, "server_", 1024, serverURN, dev);
484
+ yield createDefaultCertificate(base_name, "server_", 2048, serverURN, dev);
485
+ yield createDefaultCertificate(base_name, "server_", 3072, serverURN, dev);
486
+ yield createDefaultCertificate(base_name, "server_", 4096, serverURN, dev);
487
+ (0, toolbox_1.displayTitle)("Create Application Certificate for DiscoveryServer & its private key");
488
+ yield createDefaultCertificate(base_name, "discoveryServer_", 1024, discoveryServerURN, dev);
489
+ yield createDefaultCertificate(base_name, "discoveryServer_", 2048, discoveryServerURN, dev);
490
+ yield createDefaultCertificate(base_name, "discoveryServer_", 3072, discoveryServerURN, dev);
491
+ yield createDefaultCertificate(base_name, "discoveryServer_", 4096, discoveryServerURN, dev);
492
+ }));
493
+ });
494
+ }
495
+ function createDefaultCertificates(dev) {
496
+ return __awaiter(this, void 0, void 0, function* () {
497
+ yield construct_CertificateAuthority("");
498
+ yield construct_CertificateManager();
499
+ yield create_default_certificates(dev);
500
+ });
501
+ }
502
+ assert(typeof done === "function");
503
+ argv
504
+ .strict()
505
+ .wrap(132)
506
+ .command("demo", "create default certificate for node-opcua demos", (yargs) => {
507
+ const options = {};
508
+ options.dev = {
509
+ type: "boolean",
510
+ describe: "create all sort of fancy certificates for dev testing purposes",
511
+ };
512
+ options.clean = {
513
+ type: "boolean",
514
+ describe: "Purge existing directory [use with care!]",
515
+ };
516
+ add_standard_option(options, "silent");
517
+ add_standard_option(options, "root");
518
+ const local_argv = yargs
519
+ .strict()
520
+ .wrap(132)
521
+ .options(options)
522
+ .usage("$0 demo [--dev] [--silent] [--clean]")
523
+ .example("$0 demo --dev", "create a set of demo certificates")
524
+ .help("help").argv;
525
+ return local_argv;
526
+ }, (local_argv) => {
527
+ wrap(() => __awaiter(void 0, void 0, void 0, function* () {
528
+ yield (0, util_1.promisify)(toolbox_1.ensure_openssl_installed)();
529
+ (0, toolbox_1.displayChapter)("Create Demo certificates");
530
+ (0, toolbox_1.displayTitle)("reading configuration");
531
+ yield readConfiguration(local_argv);
532
+ if (local_argv.clean) {
533
+ (0, toolbox_1.displayTitle)("Cleaning old certificates");
534
+ assert(gLocalConfig);
535
+ const certificateDir = gLocalConfig.certificateDir || "";
536
+ yield (0, util_1.promisify)(rimraf)(certificateDir + "/*.pem*");
537
+ yield (0, util_1.promisify)(rimraf)(certificateDir + "/*.pub*");
538
+ yield (0, util_1.promisify)(toolbox_1.mkdir)(certificateDir);
539
+ }
540
+ (0, toolbox_1.displayTitle)("create certificates");
541
+ yield createDefaultCertificates(local_argv.dev);
542
+ (0, toolbox_1.displayChapter)("Demo certificates CREATED");
543
+ }));
544
+ })
545
+ .command("createCA", "create a Certificate Authority",
546
+ /* builder*/ (yargs) => {
547
+ const options = {
548
+ subject: {
549
+ default: certificate_authority_1.defaultSubject,
550
+ type: "string",
551
+ describe: "the CA certificate subject",
552
+ },
553
+ };
554
+ add_standard_option(options, "root");
555
+ add_standard_option(options, "CAFolder");
556
+ add_standard_option(options, "keySize");
557
+ add_standard_option(options, "silent");
558
+ const local_argv = yargs.strict().wrap(132).options(options).help("help").epilog(epilog).argv;
559
+ return local_argv;
560
+ },
561
+ /*handler*/ (local_argv) => {
562
+ wrap(() => __awaiter(void 0, void 0, void 0, function* () {
563
+ yield (0, util_1.promisify)(toolbox_1.ensure_openssl_installed)();
564
+ yield readConfiguration(local_argv);
565
+ yield construct_CertificateAuthority(local_argv.subject);
566
+ }));
567
+ })
568
+ .command("createPKI", "create a Public Key Infrastructure", (yargs) => {
569
+ const options = {};
570
+ add_standard_option(options, "root");
571
+ add_standard_option(options, "PKIFolder");
572
+ add_standard_option(options, "keySize");
573
+ add_standard_option(options, "silent");
574
+ return yargs.strict().wrap(132).options(options).help("help").epilog(epilog).argv;
575
+ }, (local_argv) => {
576
+ wrap(() => __awaiter(void 0, void 0, void 0, function* () {
577
+ yield readConfiguration(local_argv);
578
+ yield construct_CertificateManager();
579
+ }));
580
+ })
581
+ // ----------------------------------------------- certificate
582
+ .command("certificate", "create a new certificate", (yargs) => {
583
+ const options = {
584
+ applicationUri: {
585
+ alias: "a",
586
+ demand: true,
587
+ describe: "the application URI",
588
+ default: "urn:{hostname}:Node-OPCUA-Server",
589
+ type: "string",
590
+ },
591
+ output: {
592
+ default: "my_certificate.pem",
593
+ alias: "o",
594
+ demand: true,
595
+ describe: "the name of the generated certificate =>",
596
+ type: "string",
597
+ },
598
+ selfSigned: {
599
+ alias: "s",
600
+ default: false,
601
+ type: "boolean",
602
+ describe: "if true, certificate will be self-signed",
603
+ },
604
+ validity: {
605
+ alias: "v",
606
+ default: null,
607
+ type: "number",
608
+ describe: "the certificate validity in days",
609
+ },
610
+ dns: {
611
+ default: "{hostname}",
612
+ type: "string",
613
+ describe: "the list of valid domain name (comma separated)",
614
+ },
615
+ ip: {
616
+ default: "",
617
+ type: "string",
618
+ describe: "the list of valid IPs (comma separated)",
619
+ },
620
+ subject: {
621
+ default: "",
622
+ type: "string",
623
+ describe: "the certificate subject ( for instance C=FR/ST=Centre/L=Orleans/O=SomeOrganization/CN=Hello )",
624
+ },
625
+ };
626
+ add_standard_option(options, "silent");
627
+ add_standard_option(options, "root");
628
+ add_standard_option(options, "CAFolder");
629
+ add_standard_option(options, "PKIFolder");
630
+ add_standard_option(options, "privateKey");
631
+ return yargs.strict().wrap(132).options(options).help("help").epilog(epilog).argv;
632
+ }, (local_argv) => {
633
+ function command_certificate(local_argv) {
634
+ return __awaiter(this, void 0, void 0, function* () {
635
+ assert(typeof done === "function");
636
+ const selfSigned = !!local_argv.selfSigned;
637
+ if (!selfSigned) {
638
+ yield command_full_certificate(local_argv);
639
+ }
640
+ else {
641
+ yield command_selfsigned_certificate(local_argv);
642
+ }
643
+ });
644
+ }
645
+ function command_selfsigned_certificate(local_argv) {
646
+ return __awaiter(this, void 0, void 0, function* () {
647
+ const fqdn = yield (0, hostname_1.extractFullyQualifiedDomainName)();
648
+ yield readConfiguration(local_argv);
649
+ yield construct_CertificateManager();
650
+ (0, toolbox_1.displaySubtitle)(" create self signed Certificate " + gLocalConfig.outputFile);
651
+ let subject = local_argv.subject && local_argv.subject.length > 1
652
+ ? new subject_1.Subject(local_argv.subject)
653
+ : gLocalConfig.subject || "";
654
+ subject = JSON.parse(JSON.stringify(subject));
655
+ const params = {
656
+ applicationUri: gLocalConfig.applicationUri || "",
657
+ dns: gLocalConfig.dns || [],
658
+ ip: gLocalConfig.ip || [],
659
+ outputFile: gLocalConfig.outputFile || "self_signed_certificate.pem",
660
+ startDate: gLocalConfig.startDate || new Date(),
661
+ subject,
662
+ validity: gLocalConfig.validity || 365,
663
+ };
664
+ yield (0, util_1.promisify)(certificateManager.createSelfSignedCertificate).call(certificateManager, params);
665
+ });
666
+ }
667
+ function command_full_certificate(local_argv) {
668
+ return __awaiter(this, void 0, void 0, function* () {
669
+ yield readConfiguration(local_argv);
670
+ yield construct_CertificateManager();
671
+ yield construct_CertificateAuthority("");
672
+ assert(fs.existsSync(gLocalConfig.CAFolder || ""), " CA folder must exist");
673
+ gLocalConfig.privateKey = undefined; // use PKI private key
674
+ // create a Certificate Request from the certificate Manager
675
+ gLocalConfig.subject =
676
+ local_argv.subject && local_argv.subject.length > 1 ? local_argv.subject : gLocalConfig.subject;
677
+ const csr_file = yield (0, util_1.promisify)(certificateManager.createCertificateRequest).call(certificateManager, gLocalConfig);
678
+ if (!csr_file) {
679
+ return;
680
+ }
681
+ console.log(" csr_file = ", csr_file);
682
+ const certificate = csr_file.replace(".csr", ".pem");
683
+ if (fs.existsSync(certificate)) {
684
+ throw new Error(" File " + certificate + " already exist");
685
+ }
686
+ yield (0, util_1.promisify)(g_certificateAuthority.signCertificateRequest).call(g_certificateAuthority, certificate, csr_file, gLocalConfig);
687
+ assert(typeof gLocalConfig.outputFile === "string");
688
+ fs.writeFileSync(gLocalConfig.outputFile || "", fs.readFileSync(certificate, "ascii"));
689
+ });
690
+ }
691
+ wrap(() => __awaiter(void 0, void 0, void 0, function* () { return yield command_certificate(local_argv); }));
692
+ })
693
+ // ----------------------------------------------- revoke
694
+ .command("revoke <certificateFile>", "revoke a existing certificate", (yargs) => {
695
+ const options = {};
696
+ add_standard_option(options, "root");
697
+ add_standard_option(options, "CAFolder");
698
+ yargs.strict().wrap(132).help("help").usage("$0 revoke my_certificate.pem").options(options).epilog(epilog);
699
+ return yargs;
700
+ }, (local_argv) => {
701
+ function revoke_certificate(certificate, callback) {
702
+ g_certificateAuthority.revokeCertificate(certificate, {}, callback);
703
+ }
704
+ wrap(() => __awaiter(void 0, void 0, void 0, function* () {
705
+ // example : node bin\crypto_create_CA.js revoke my_certificate.pem
706
+ const certificate = path.resolve(local_argv.certificateFile);
707
+ console.log(chalk.yellow(" Certificate to revoke : "), chalk.cyan(certificate));
708
+ if (!fs.existsSync(certificate)) {
709
+ throw new Error("cannot find certificate to revoke " + certificate);
710
+ }
711
+ yield readConfiguration(local_argv);
712
+ yield construct_CertificateAuthority("");
713
+ yield (0, util_1.promisify)(revoke_certificate)(certificate);
714
+ console.log("done ... ");
715
+ console.log(" crl = ", g_certificateAuthority.revocationList);
716
+ console.log("\nyou should now publish the new Certificate Revocation List");
717
+ }));
718
+ })
719
+ .command("csr", "create a certificate signing request", (yargs) => {
720
+ const options = {
721
+ applicationUri: {
722
+ alias: "a",
723
+ // demand: true,
724
+ describe: "the application URI",
725
+ default: "urn:{hostname}:Node-OPCUA-Server",
726
+ type: "string",
727
+ },
728
+ output: {
729
+ default: "my_certificate_signing_request.csr",
730
+ alias: "o",
731
+ // demand: true,
732
+ describe: "the name of the generated signing_request",
733
+ type: "string",
734
+ },
735
+ dns: {
736
+ default: "{hostname}",
737
+ type: "string",
738
+ describe: "the list of valid domain name (comma separated)",
739
+ },
740
+ ip: {
741
+ default: "",
742
+ type: "string",
743
+ describe: "the list of valid IPs (comma separated)",
744
+ },
745
+ subject: {
746
+ default: "/CN=Certificate",
747
+ type: "string",
748
+ describe: "the certificate subject ( for instance /C=FR/ST=Centre/L=Orleans/O=SomeOrganization/CN=Hello )",
749
+ },
750
+ };
751
+ add_standard_option(options, "silent");
752
+ add_standard_option(options, "root");
753
+ add_standard_option(options, "PKIFolder");
754
+ add_standard_option(options, "privateKey");
755
+ return yargs.strict().wrap(132).options(options).help("help").epilog(epilog).argv;
756
+ }, (local_argv) => {
757
+ wrap(() => __awaiter(void 0, void 0, void 0, function* () {
758
+ yield readConfiguration(local_argv);
759
+ if (!fs.existsSync(gLocalConfig.PKIFolder || "")) {
760
+ console.log("PKI folder must exist");
761
+ }
762
+ yield construct_CertificateManager();
763
+ if (!gLocalConfig.outputFile || fs.existsSync(gLocalConfig.outputFile)) {
764
+ throw new Error(" File " + gLocalConfig.outputFile + " already exist");
765
+ }
766
+ gLocalConfig.privateKey = undefined; // use PKI private key
767
+ // create a Certificate Request from the certificate Manager
768
+ gLocalConfig.subject =
769
+ local_argv.subject && local_argv.subject.length > 1 ? local_argv.subject : gLocalConfig.subject;
770
+ const internal_csr_file = yield (0, util_1.promisify)(certificateManager.createCertificateRequest).call(certificateManager, gLocalConfig);
771
+ if (!internal_csr_file) {
772
+ return;
773
+ }
774
+ if (!gLocalConfig.outputFile) {
775
+ console.log("please specify a output file");
776
+ return;
777
+ }
778
+ const csr = yield fs.promises.readFile(internal_csr_file, "utf-8");
779
+ fs.writeFileSync(gLocalConfig.outputFile || "", csr, "utf-8");
780
+ console.log("Subject = ", gLocalConfig.subject);
781
+ console.log("applicationUri = ", gLocalConfig.applicationUri);
782
+ console.log("altNames = ", gLocalConfig.altNames);
783
+ console.log("dns = ", gLocalConfig.dns);
784
+ console.log("ip = ", gLocalConfig.ip);
785
+ console.log("CSR file = ", gLocalConfig.outputFile);
786
+ }));
787
+ })
788
+ .command("sign", "validate a certificate signing request and generate a certificate", (yargs) => {
789
+ const options = {
790
+ csr: {
791
+ alias: "i",
792
+ default: "my_certificate_signing_request.csr",
793
+ type: "string",
794
+ demandOption: true,
795
+ description: "the csr"
796
+ },
797
+ output: {
798
+ default: "my_certificate.pem",
799
+ alias: "o",
800
+ demand: true,
801
+ describe: "the name of the generated certificate",
802
+ type: "string",
803
+ },
804
+ validity: {
805
+ alias: "v",
806
+ default: 365,
807
+ type: "number",
808
+ describe: "the certificate validity in days",
809
+ },
810
+ };
811
+ add_standard_option(options, "silent");
812
+ add_standard_option(options, "root");
813
+ add_standard_option(options, "CAFolder");
814
+ return yargs.strict().wrap(132).options(options).help("help").epilog(epilog).argv;
815
+ }, (local_argv) => {
816
+ wrap(() => __awaiter(void 0, void 0, void 0, function* () {
817
+ /** */
818
+ yield readConfiguration(local_argv);
819
+ if (!fs.existsSync(gLocalConfig.CAFolder || "")) {
820
+ throw new Error("CA folder must exist:" + gLocalConfig.CAFolder);
821
+ }
822
+ yield construct_CertificateAuthority("");
823
+ const csr_file = path.resolve(local_argv.csr || "");
824
+ if (!fs.existsSync(csr_file)) {
825
+ throw new Error("Certificate signing request doesn't exist: " + csr_file);
826
+ }
827
+ const certificate = path.resolve(local_argv.output || csr_file.replace(".csr", ".pem"));
828
+ if (fs.existsSync(certificate)) {
829
+ throw new Error(" File " + certificate + " already exist");
830
+ }
831
+ yield (0, util_1.promisify)(g_certificateAuthority.signCertificateRequest).call(g_certificateAuthority, certificate, csr_file, gLocalConfig);
832
+ assert(typeof gLocalConfig.outputFile === "string");
833
+ fs.writeFileSync(gLocalConfig.outputFile || "", fs.readFileSync(certificate, "ascii"));
834
+ }));
835
+ })
836
+ .command("dump <certificateFile>", "display a certificate", () => {
837
+ /** */
838
+ }, (yargs) => {
839
+ wrap(() => __awaiter(void 0, void 0, void 0, function* () {
840
+ const data = yield (0, util_1.promisify)(toolbox_1.dumpCertificate)(yargs.certificateFile);
841
+ console.log(data);
842
+ }));
843
+ })
844
+ .command("toder <pemCertificate>", "convert a certificate to a DER format with finger print", () => {
845
+ /** */
846
+ }, (yargs) => {
847
+ wrap(() => __awaiter(void 0, void 0, void 0, function* () {
848
+ yield (0, util_1.promisify)(toolbox_1.toDer)(argv.pemCertificate);
849
+ }));
850
+ })
851
+ .command("fingerprint <certificateFile>", "print the certificate fingerprint", () => {
852
+ /** */
853
+ }, (local_argv) => {
854
+ wrap(() => __awaiter(void 0, void 0, void 0, function* () {
855
+ const certificate = local_argv.certificateFile;
856
+ const data = yield (0, util_1.promisify)(toolbox_1.fingerprint)(certificate);
857
+ if (!data)
858
+ return;
859
+ const s = data.split("=")[1].split(":").join("").trim();
860
+ console.log(s);
861
+ }));
862
+ })
863
+ .command("$0", "help", (yargs) => {
864
+ console.log("--help for help");
865
+ return yargs;
866
+ })
867
+ .epilog(epilog)
868
+ .help("help")
869
+ .strict().argv;
870
+ function main(argumentsList, _done) {
871
+ if (_done) {
872
+ done = _done;
873
+ }
874
+ commands.parse(argumentsList, (err, g_argv) => {
875
+ // istanbul ignore next
876
+ if (err) {
877
+ console.log(" err = ", err);
878
+ console.log(" use --help for more info");
879
+ setImmediate(() => {
880
+ commands.showHelp();
881
+ done(err);
882
+ });
883
+ }
884
+ else {
885
+ if (g_argv.help) {
886
+ setImmediate(() => {
887
+ commands.showHelp();
888
+ done();
889
+ });
890
+ }
891
+ else {
892
+ done();
893
+ }
894
+ }
895
+ });
896
+ }
897
+ exports.main = main;
898
898
  //# sourceMappingURL=crypto_create_CA.js.map