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.
- package/.ignore +6 -6
- package/.prettierrc +5 -5
- package/LICENSE +22 -22
- package/bin/crypto_create_CA.js +0 -0
- package/bin/crypto_create_CA_config.example.js +18 -18
- package/bin/install_prerequisite.js +9 -9
- package/dist/crypto_create_CA.d.ts +2 -2
- package/dist/crypto_create_CA.js +897 -897
- package/dist/index.d.ts +6 -6
- package/dist/index.js +44 -44
- package/dist/misc/applicationurn.d.ts +1 -1
- package/dist/misc/applicationurn.js +46 -46
- package/dist/misc/hostname.d.ts +8 -8
- package/dist/misc/hostname.js +102 -102
- package/dist/misc/install_prerequisite.d.ts +9 -9
- package/dist/misc/install_prerequisite.js +363 -360
- package/dist/misc/install_prerequisite.js.map +1 -1
- package/dist/misc/subject.d.ts +26 -26
- package/dist/misc/subject.js +121 -121
- package/dist/pki/certificate_authority.d.ts +61 -61
- package/dist/pki/certificate_authority.js +481 -481
- package/dist/pki/certificate_manager.d.ts +144 -144
- package/dist/pki/certificate_manager.js +883 -883
- package/dist/pki/certificate_manager.js.map +1 -1
- package/dist/pki/common.d.ts +5 -5
- package/dist/pki/common.js +2 -2
- package/dist/pki/templates/ca_config_template.cnf.d.ts +2 -2
- package/dist/pki/templates/ca_config_template.cnf.js +129 -129
- package/dist/pki/templates/simple_config_template.cnf.d.ts +2 -2
- package/dist/pki/templates/simple_config_template.cnf.js +75 -75
- package/dist/pki/toolbox.d.ts +160 -160
- package/dist/pki/toolbox.js +699 -699
- package/dist/pki/toolbox_pfx.js +18 -18
- package/lib/crypto_create_CA.ts +1135 -1135
- package/lib/index.ts +28 -28
- package/lib/misc/applicationurn.ts +45 -45
- package/lib/misc/hostname.ts +89 -89
- package/lib/misc/install_prerequisite.ts +454 -454
- package/lib/misc/subject.ts +141 -141
- package/lib/pki/certificate_manager.ts +1 -1
- package/lib/pki/common.ts +5 -5
- package/lib/pki/templates/ca_config_template.cnf.ts +129 -129
- package/lib/pki/templates/simple_config_template.cnf.ts +75 -75
- package/lib/pki/toolbox_pfx.ts +19 -19
- package/package.json +89 -89
- package/readme.md +214 -214
- package/tsconfig.json +20 -20
- package/dist/misc/fs.d.ts +0 -24
- package/dist/misc/fs.js +0 -21
- package/dist/misc/fs.js.map +0 -1
- package/dist/misc/get_default_filesystem.d.ts +0 -2
- package/dist/misc/get_default_filesystem.js +0 -9
- package/dist/misc/get_default_filesystem.js.map +0 -1
package/dist/crypto_create_CA.js
CHANGED
|
@@ -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
|