node-opcua-pki 2.13.0 → 2.14.2
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/.eslintrc.yml +20 -0
- package/bin/crypto_create_CA.js +3 -1
- package/bin/install_prerequisite.js +1 -0
- package/dist/crypto_create_CA.js +3 -1
- package/dist/crypto_create_CA.js.map +1 -1
- package/dist/misc/hostname.js +1 -2
- package/dist/misc/hostname.js.map +1 -1
- package/dist/misc/install_prerequisite.js +6 -5
- package/dist/misc/install_prerequisite.js.map +1 -1
- package/dist/misc/subject.js +2 -2
- package/dist/misc/subject.js.map +1 -1
- package/dist/pki/certificate_authority.js +5 -3
- package/dist/pki/certificate_authority.js.map +1 -1
- package/dist/pki/certificate_manager.d.ts +8 -0
- package/dist/pki/certificate_manager.js +25 -22
- package/dist/pki/certificate_manager.js.map +1 -1
- package/dist/pki/templates/ca_config_template.cnf.js +3 -3
- package/dist/pki/templates/ca_config_template.cnf.js.map +1 -1
- package/dist/pki/templates/simple_config_template.cnf.js +3 -3
- package/dist/pki/templates/simple_config_template.cnf.js.map +1 -1
- package/dist/pki/toolbox.js +9 -10
- package/dist/pki/toolbox.js.map +1 -1
- package/lib/crypto_create_CA.ts +60 -58
- package/lib/misc/hostname.ts +1 -1
- package/lib/misc/install_prerequisite.ts +4 -3
- package/lib/misc/subject.ts +5 -10
- package/lib/pki/certificate_authority.ts +6 -4
- package/lib/pki/certificate_manager.ts +55 -48
- package/lib/pki/templates/ca_config_template.cnf.ts +3 -3
- package/lib/pki/templates/simple_config_template.cnf.ts +3 -3
- package/lib/pki/toolbox.ts +54 -62
- package/package.json +21 -18
- package/readme.md +36 -33
package/lib/misc/subject.ts
CHANGED
|
@@ -41,7 +41,6 @@ const _keys = {
|
|
|
41
41
|
};
|
|
42
42
|
|
|
43
43
|
export class Subject implements SubjectOptions {
|
|
44
|
-
|
|
45
44
|
public readonly commonName?: string;
|
|
46
45
|
public readonly organization?: string;
|
|
47
46
|
public readonly organizationalUnit?: string;
|
|
@@ -51,8 +50,7 @@ export class Subject implements SubjectOptions {
|
|
|
51
50
|
public readonly domainComponent?: string;
|
|
52
51
|
|
|
53
52
|
constructor(options: SubjectOptions | string) {
|
|
54
|
-
|
|
55
|
-
if (typeof(options) === "string") {
|
|
53
|
+
if (typeof options === "string") {
|
|
56
54
|
options = Subject.parse(options);
|
|
57
55
|
}
|
|
58
56
|
this.commonName = options.commonName;
|
|
@@ -65,9 +63,8 @@ export class Subject implements SubjectOptions {
|
|
|
65
63
|
}
|
|
66
64
|
|
|
67
65
|
public static parse(str: string): SubjectOptions {
|
|
68
|
-
|
|
69
|
-
const
|
|
70
|
-
const options: any = {};
|
|
66
|
+
const elements = str.split(/\/(?=[^/]*?=)/);
|
|
67
|
+
const options: Record<string, unknown> = {};
|
|
71
68
|
|
|
72
69
|
elements.forEach((element: string) => {
|
|
73
70
|
if (element.length === 0) {
|
|
@@ -76,17 +73,16 @@ export class Subject implements SubjectOptions {
|
|
|
76
73
|
const s: string[] = element.split("=");
|
|
77
74
|
|
|
78
75
|
if (s.length !== 2) {
|
|
79
|
-
|
|
76
|
+
throw new Error("invalid format for " + element);
|
|
80
77
|
}
|
|
81
78
|
const longName = (_keys as any)[s[0]];
|
|
82
79
|
const value = s[1];
|
|
83
|
-
options[longName] = Buffer.from(value,"ascii").toString("utf8");
|
|
80
|
+
options[longName] = Buffer.from(value, "ascii").toString("utf8");
|
|
84
81
|
});
|
|
85
82
|
return options as SubjectOptions;
|
|
86
83
|
}
|
|
87
84
|
|
|
88
85
|
public toString() {
|
|
89
|
-
|
|
90
86
|
let tmp = "";
|
|
91
87
|
if (this.country) {
|
|
92
88
|
tmp += "/C=" + this.country;
|
|
@@ -111,5 +107,4 @@ export class Subject implements SubjectOptions {
|
|
|
111
107
|
}
|
|
112
108
|
return tmp;
|
|
113
109
|
}
|
|
114
|
-
|
|
115
110
|
}
|
|
@@ -140,7 +140,7 @@ function construct_CertificateAuthority(certificateAuthority: CertificateAuthori
|
|
|
140
140
|
}
|
|
141
141
|
|
|
142
142
|
// tslint:disable:no-empty
|
|
143
|
-
displayTitle("Create Certificate Authority (CA)", (err?: Error | null) => { });
|
|
143
|
+
displayTitle("Create Certificate Authority (CA)", (err?: Error | null) => { /** */ });
|
|
144
144
|
|
|
145
145
|
const indexFileAttr = path.join(caRootDir, "index.txt.attr");
|
|
146
146
|
if (!fs.existsSync(indexFileAttr)) {
|
|
@@ -148,6 +148,7 @@ function construct_CertificateAuthority(certificateAuthority: CertificateAuthori
|
|
|
148
148
|
}
|
|
149
149
|
|
|
150
150
|
const caConfigFile = certificateAuthority.configFile;
|
|
151
|
+
// eslint-disable-next-line no-constant-condition
|
|
151
152
|
if (1 || !fs.existsSync(caConfigFile)) {
|
|
152
153
|
let data = configurationFileTemplate; // inlineText(configurationFile);
|
|
153
154
|
data = data.replace(/%%ROOT_FOLDER%%/, make_path(caRootDir));
|
|
@@ -156,7 +157,7 @@ function construct_CertificateAuthority(certificateAuthority: CertificateAuthori
|
|
|
156
157
|
}
|
|
157
158
|
|
|
158
159
|
// http://www.akadia.com/services/ssh_test_certificate.html
|
|
159
|
-
const subjectOpt =
|
|
160
|
+
const subjectOpt = " -subj \"" + subject.toString() + "\" ";
|
|
160
161
|
const options = { cwd: caRootDir };
|
|
161
162
|
processAltNames({} as Params);
|
|
162
163
|
|
|
@@ -268,8 +269,8 @@ export class CertificateAuthority {
|
|
|
268
269
|
public readonly subject: Subject;
|
|
269
270
|
|
|
270
271
|
constructor(options: CertificateAuthorityOptions) {
|
|
271
|
-
assert(
|
|
272
|
-
assert(
|
|
272
|
+
assert(Object.prototype.hasOwnProperty.call(options,"location"));
|
|
273
|
+
assert(Object.prototype.hasOwnProperty.call(options,"keySize"));
|
|
273
274
|
this.location = options.location;
|
|
274
275
|
this.keySize = options.keySize || 2048;
|
|
275
276
|
this.subject = new Subject(options.subject || defaultSubject);
|
|
@@ -729,6 +730,7 @@ export class CertificateAuthority {
|
|
|
729
730
|
}
|
|
730
731
|
|
|
731
732
|
// tslint:disable:no-var-requires
|
|
733
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
732
734
|
const thenify = require("thenify");
|
|
733
735
|
const opts = { multiArgs: false };
|
|
734
736
|
CertificateAuthority.prototype.initialize = thenify.withCallback(CertificateAuthority.prototype.initialize, opts);
|
|
@@ -66,7 +66,11 @@ import {
|
|
|
66
66
|
setEnv,
|
|
67
67
|
} from "./toolbox";
|
|
68
68
|
|
|
69
|
-
import { withLock } from "@ster5/global-mutex"
|
|
69
|
+
import { withLock } from "@ster5/global-mutex";
|
|
70
|
+
// tslint:disable:max-line-length
|
|
71
|
+
// tslint:disable:no-var-requires
|
|
72
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
73
|
+
const thenify = require("thenify");
|
|
70
74
|
|
|
71
75
|
type C = ((err?: Error | null, ...args: [any, ...any]) => void) | ((err?: Error | null) => void);
|
|
72
76
|
|
|
@@ -108,6 +112,15 @@ export interface CertificateManagerOptions {
|
|
|
108
112
|
location: string;
|
|
109
113
|
}
|
|
110
114
|
|
|
115
|
+
export interface Callback11<C> {
|
|
116
|
+
(err: null, t: C): void;
|
|
117
|
+
(err: Error): void;
|
|
118
|
+
}
|
|
119
|
+
export interface Callback22 {
|
|
120
|
+
(err?: Error | null): void;
|
|
121
|
+
(err?: Error): void;
|
|
122
|
+
}
|
|
123
|
+
|
|
111
124
|
export interface CreateSelfSignCertificateParam1 extends CreateSelfSignCertificateParam {
|
|
112
125
|
outputFile?: Filename; // default : own/cert/self_signed_certificate.pem
|
|
113
126
|
subject: SubjectOptions | string;
|
|
@@ -197,14 +210,14 @@ export enum CertificateManagerState {
|
|
|
197
210
|
Disposed = 4,
|
|
198
211
|
}
|
|
199
212
|
export class CertificateManager {
|
|
200
|
-
public untrustUnknownCertificate
|
|
213
|
+
public untrustUnknownCertificate = true;
|
|
201
214
|
public state: CertificateManagerState = CertificateManagerState.Uninitialized;
|
|
202
215
|
public folderPoolingInterval = 5000;
|
|
203
216
|
|
|
204
217
|
private readonly keySize: KeySize;
|
|
205
218
|
private readonly location: string;
|
|
206
219
|
private readonly _watchers: fs.FSWatcher[] = [];
|
|
207
|
-
private _readCertificatesCalled
|
|
220
|
+
private _readCertificatesCalled = false;
|
|
208
221
|
private readonly _filenameToHash: { [key: string]: string } = {};
|
|
209
222
|
|
|
210
223
|
private readonly _thumbs: Thumbs = {
|
|
@@ -219,8 +232,8 @@ export class CertificateManager {
|
|
|
219
232
|
|
|
220
233
|
constructor(options: CertificateManagerOptions) {
|
|
221
234
|
options.keySize = options.keySize || 2048;
|
|
222
|
-
assert(
|
|
223
|
-
assert(
|
|
235
|
+
assert(Object.prototype.hasOwnProperty.call(options, "location"));
|
|
236
|
+
assert(Object.prototype.hasOwnProperty.call(options, "keySize"));
|
|
224
237
|
assert(this.state === CertificateManagerState.Uninitialized);
|
|
225
238
|
|
|
226
239
|
this.location = make_path(options.location, "");
|
|
@@ -463,8 +476,8 @@ export class CertificateManager {
|
|
|
463
476
|
// certificate is not active yet
|
|
464
477
|
debugLog(
|
|
465
478
|
chalk.red("certificate is invalid : certificate is not active yet !") +
|
|
466
|
-
|
|
467
|
-
|
|
479
|
+
" not before date =" +
|
|
480
|
+
certificateInfo.notBefore
|
|
468
481
|
);
|
|
469
482
|
isTimeInvalid = true;
|
|
470
483
|
}
|
|
@@ -527,7 +540,6 @@ export class CertificateManager {
|
|
|
527
540
|
public async initialize(): Promise<void>;
|
|
528
541
|
public initialize(callback: (err?: Error) => void): void;
|
|
529
542
|
public initialize(...args: any[]): any {
|
|
530
|
-
|
|
531
543
|
const callback = args[0];
|
|
532
544
|
assert(callback && callback instanceof Function);
|
|
533
545
|
|
|
@@ -535,13 +547,13 @@ export class CertificateManager {
|
|
|
535
547
|
return callback();
|
|
536
548
|
}
|
|
537
549
|
this.state = CertificateManagerState.Initializing;
|
|
538
|
-
return this._initialize((err?: Error) => {
|
|
550
|
+
return this._initialize((err?: Error | null) => {
|
|
539
551
|
this.state = CertificateManagerState.Initialized;
|
|
540
552
|
return callback(err);
|
|
541
553
|
});
|
|
542
554
|
}
|
|
543
|
-
private _initialize(callback:
|
|
544
|
-
assert(this.state = CertificateManagerState.Initializing);
|
|
555
|
+
private _initialize(callback: ErrorCallback): void {
|
|
556
|
+
assert((this.state = CertificateManagerState.Initializing));
|
|
545
557
|
const pkiDir = this.location;
|
|
546
558
|
mkdir(pkiDir);
|
|
547
559
|
mkdir(path.join(pkiDir, "own"));
|
|
@@ -555,7 +567,7 @@ export class CertificateManager {
|
|
|
555
567
|
mkdir(path.join(pkiDir, "issuers"));
|
|
556
568
|
mkdir(path.join(pkiDir, "issuers/certs")); // contains Trusted CA certificates
|
|
557
569
|
mkdir(path.join(pkiDir, "issuers/crl")); // contains CRL of revoked CA certificates
|
|
558
|
-
|
|
570
|
+
|
|
559
571
|
this.withLock((callback) => {
|
|
560
572
|
assert(this.state !== CertificateManagerState.Disposing);
|
|
561
573
|
if (this.state === CertificateManagerState.Disposed) {
|
|
@@ -594,7 +606,7 @@ export class CertificateManager {
|
|
|
594
606
|
this._readCertificates(() => callback());
|
|
595
607
|
}
|
|
596
608
|
});
|
|
597
|
-
}, callback);
|
|
609
|
+
}, callback as ErrorCallback);
|
|
598
610
|
}
|
|
599
611
|
|
|
600
612
|
public async dispose(): Promise<void> {
|
|
@@ -623,12 +635,13 @@ export class CertificateManager {
|
|
|
623
635
|
}
|
|
624
636
|
}
|
|
625
637
|
|
|
626
|
-
private withLock<
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
638
|
+
private withLock<T extends void = void>(action: (callback: Callback22) => void, callback: Callback22): void;
|
|
639
|
+
private withLock<T>(action: (callback: Callback11<T>) => void, callback: Callback11<T>): void;
|
|
640
|
+
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
641
|
+
private withLock(action: Function, callback: Function): void {
|
|
642
|
+
this.withLock2(promisify<any>(action as any))
|
|
643
|
+
.then((t: unknown) => callback(null, t))
|
|
630
644
|
.catch((err) => callback(err));
|
|
631
|
-
|
|
632
645
|
}
|
|
633
646
|
private async withLock2<T>(action: () => Promise<T>): Promise<T> {
|
|
634
647
|
const lockFileName = path.join(this.rootDir, "mutex.lock");
|
|
@@ -644,21 +657,20 @@ export class CertificateManager {
|
|
|
644
657
|
public async createSelfSignedCertificate(params: CreateSelfSignCertificateParam1): Promise<void>;
|
|
645
658
|
public createSelfSignedCertificate(params: CreateSelfSignCertificateParam1, callback: ErrorCallback): void;
|
|
646
659
|
public createSelfSignedCertificate(params: CreateSelfSignCertificateParam1, ...args: any[]): any {
|
|
647
|
-
const callback = args[0];
|
|
648
|
-
const self = this;
|
|
660
|
+
const callback = args[0] as ErrorCallback;
|
|
649
661
|
assert(typeof params.applicationUri === "string", "expecting applicationUri");
|
|
650
|
-
if (!fs.existsSync(
|
|
651
|
-
return callback(new Error("Cannot find private key " +
|
|
662
|
+
if (!fs.existsSync(this.privateKey)) {
|
|
663
|
+
return callback(new Error("Cannot find private key " + this.privateKey));
|
|
652
664
|
}
|
|
653
665
|
|
|
654
|
-
let certificateFilename = path.join(
|
|
666
|
+
let certificateFilename = path.join(this.rootDir, "own/certs/self_signed_certificate.pem");
|
|
655
667
|
certificateFilename = params.outputFile || certificateFilename;
|
|
656
668
|
|
|
657
|
-
const _params =
|
|
658
|
-
_params.rootDir =
|
|
659
|
-
_params.configFile =
|
|
660
|
-
_params.privateKey =
|
|
661
|
-
this.withLock
|
|
669
|
+
const _params = params as unknown as CreateSelfSignCertificateWithConfigParam;
|
|
670
|
+
_params.rootDir = this.rootDir;
|
|
671
|
+
_params.configFile = this.configFile;
|
|
672
|
+
_params.privateKey = this.privateKey;
|
|
673
|
+
this.withLock((callback) => {
|
|
662
674
|
createSelfSignCertificate(certificateFilename, _params, callback);
|
|
663
675
|
}, callback);
|
|
664
676
|
}
|
|
@@ -674,7 +686,7 @@ export class CertificateManager {
|
|
|
674
686
|
): any {
|
|
675
687
|
assert(params);
|
|
676
688
|
const _params = params as CreateSelfSignCertificateWithConfigParam;
|
|
677
|
-
if (
|
|
689
|
+
if (Object.prototype.hasOwnProperty.call(_params, "rootDir")) {
|
|
678
690
|
throw new Error("rootDir should not be specified ");
|
|
679
691
|
}
|
|
680
692
|
assert(typeof callback === "function");
|
|
@@ -685,22 +697,21 @@ export class CertificateManager {
|
|
|
685
697
|
_params.configFile = this.configFile;
|
|
686
698
|
_params.privateKey = this.privateKey;
|
|
687
699
|
|
|
688
|
-
this.withLock((callback) => {
|
|
700
|
+
this.withLock<string>((callback) => {
|
|
689
701
|
// compose a file name for the request
|
|
690
702
|
const now = new Date();
|
|
691
703
|
const today = now.toISOString().slice(0, 10) + "_" + now.getTime();
|
|
692
704
|
const certificateSigningRequestFilename = path.join(this.rootDir, "own/certs", "certificate_" + today + ".csr");
|
|
693
705
|
createCertificateSigningRequest(certificateSigningRequestFilename, _params, (err?: Error) => {
|
|
694
|
-
|
|
706
|
+
if (err) {
|
|
707
|
+
return callback(err);
|
|
708
|
+
}
|
|
709
|
+
return callback(null, certificateSigningRequestFilename);
|
|
695
710
|
});
|
|
696
711
|
}, callback);
|
|
697
712
|
}
|
|
698
713
|
|
|
699
|
-
public async addIssuer(
|
|
700
|
-
certificate: DER,
|
|
701
|
-
validate: boolean = false,
|
|
702
|
-
addInTrustList: boolean = false
|
|
703
|
-
): Promise<VerificationStatus> {
|
|
714
|
+
public async addIssuer(certificate: DER, validate = false, addInTrustList = false): Promise<VerificationStatus> {
|
|
704
715
|
if (validate) {
|
|
705
716
|
const status = await this.verifyCertificate(certificate);
|
|
706
717
|
if (status !== VerificationStatus.Good && status !== VerificationStatus.BadCertificateUntrusted) {
|
|
@@ -826,10 +837,10 @@ export class CertificateManager {
|
|
|
826
837
|
if (err) {
|
|
827
838
|
return callback(err);
|
|
828
839
|
}
|
|
829
|
-
if (this._thumbs.rejected
|
|
840
|
+
if (Object.prototype.hasOwnProperty.call(this._thumbs.rejected, fingerprint)) {
|
|
830
841
|
return callback(null, "rejected");
|
|
831
842
|
}
|
|
832
|
-
if (this._thumbs.trusted
|
|
843
|
+
if (Object.prototype.hasOwnProperty.call(this._thumbs.trusted, fingerprint)) {
|
|
833
844
|
return callback(null, "trusted");
|
|
834
845
|
}
|
|
835
846
|
return callback(null, "unknown");
|
|
@@ -861,8 +872,8 @@ export class CertificateManager {
|
|
|
861
872
|
newStatus === "rejected"
|
|
862
873
|
? this.rejectedFolder
|
|
863
874
|
: newStatus === "trusted"
|
|
864
|
-
|
|
865
|
-
|
|
875
|
+
? this.trustedFolder
|
|
876
|
+
: this.rejectedFolder;
|
|
866
877
|
const certificateDest = path.join(destFolder, path.basename(certificateSrc));
|
|
867
878
|
|
|
868
879
|
debugLog("_moveCertificate1", fingerprint.substr(0, 10), "old name", certificateSrc);
|
|
@@ -911,8 +922,8 @@ export class CertificateManager {
|
|
|
911
922
|
const serialNumber =
|
|
912
923
|
certInfo.tbsCertificate.serialNumber || certInfo.tbsCertificate.extensions?.authorityKeyIdentifier?.serial || "";
|
|
913
924
|
|
|
914
|
-
const
|
|
915
|
-
|
|
925
|
+
const key = certInfo.tbsCertificate.extensions?.authorityKeyIdentifier?.authorityCertIssuerFingerPrint || "<unknown>";
|
|
926
|
+
const crl2 = this._thumbs.crl[key] || null;
|
|
916
927
|
|
|
917
928
|
if (crls.serialNumbers[serialNumber] || (crl2 && crl2.serialNumbers[serialNumber])) {
|
|
918
929
|
return VerificationStatus.BadCertificateRevoked;
|
|
@@ -920,7 +931,7 @@ export class CertificateManager {
|
|
|
920
931
|
return VerificationStatus.Good;
|
|
921
932
|
}
|
|
922
933
|
|
|
923
|
-
private _pending_crl_to_process
|
|
934
|
+
private _pending_crl_to_process = 0;
|
|
924
935
|
private _on_crl_process?: () => void;
|
|
925
936
|
private queue: any[] = [];
|
|
926
937
|
private _on_crl_file_added(index: { [key: string]: CRLData }, filename: string) {
|
|
@@ -1076,8 +1087,7 @@ export class CertificateManager {
|
|
|
1076
1087
|
// make sure that all crls have been processed.
|
|
1077
1088
|
private async waitAndCheckCRLProcessingStatus(): Promise<void> {
|
|
1078
1089
|
return new Promise((resolve, reject) => {
|
|
1079
|
-
|
|
1080
|
-
if (self._pending_crl_to_process === 0) {
|
|
1090
|
+
if (this._pending_crl_to_process === 0) {
|
|
1081
1091
|
setImmediate(resolve);
|
|
1082
1092
|
return;
|
|
1083
1093
|
}
|
|
@@ -1090,9 +1100,6 @@ export class CertificateManager {
|
|
|
1090
1100
|
}
|
|
1091
1101
|
}
|
|
1092
1102
|
|
|
1093
|
-
// tslint:disable:no-var-requires
|
|
1094
|
-
// tslint:disable:max-line-length
|
|
1095
|
-
const thenify = require("thenify");
|
|
1096
1103
|
const opts = { multiArgs: false };
|
|
1097
1104
|
CertificateManager.prototype.rejectCertificate = thenify.withCallback(CertificateManager.prototype.rejectCertificate, opts);
|
|
1098
1105
|
CertificateManager.prototype.trustCertificate = thenify.withCallback(CertificateManager.prototype.trustCertificate, opts);
|
|
@@ -99,14 +99,14 @@ const config =
|
|
|
99
99
|
"keyUsage = nonRepudiation, digitalSignature, keyEncipherment, dataEncipherment, keyAgreement\n" +
|
|
100
100
|
"extendedKeyUsage = critical,serverAuth ,clientAuth\n" +
|
|
101
101
|
"subjectAltName = $ENV::ALTNAME\n" +
|
|
102
|
-
|
|
102
|
+
"nsComment = \"CA Generated by Node-OPCUA Certificate utility using openssl\"\n" +
|
|
103
103
|
"[ v3_ca ]\n" +
|
|
104
104
|
"subjectKeyIdentifier = hash\n" +
|
|
105
105
|
"authorityKeyIdentifier = keyid:always,issuer:always\n" +
|
|
106
106
|
"# authorityKeyIdentifier = keyid\n" +
|
|
107
107
|
"basicConstraints = CA:TRUE\n" +
|
|
108
108
|
"keyUsage = critical, cRLSign, keyCertSign\n" +
|
|
109
|
-
|
|
109
|
+
"nsComment = \"CA Certificate generated by Node-OPCUA Certificate utility using openssl\"\n" +
|
|
110
110
|
"#nsCertType = sslCA, emailCA\n" +
|
|
111
111
|
"#subjectAltName = email:copy\n" +
|
|
112
112
|
"#issuerAltName = issuer:copy\n" +
|
|
@@ -118,7 +118,7 @@ const config =
|
|
|
118
118
|
"basicConstraints = critical, CA:FALSE\n" +
|
|
119
119
|
"keyUsage = nonRepudiation, digitalSignature, keyEncipherment, dataEncipherment, keyAgreement\n" +
|
|
120
120
|
"extendedKeyUsage = critical,serverAuth ,clientAuth\n" +
|
|
121
|
-
|
|
121
|
+
"nsComment = \"Self-signed certificate, generated by NodeOPCUA\"\n" +
|
|
122
122
|
"subjectAltName = $ENV::ALTNAME\n" +
|
|
123
123
|
"\n" +
|
|
124
124
|
"[ crl_ext ]\n" +
|
|
@@ -15,7 +15,7 @@ const config =
|
|
|
15
15
|
"# authorityKeyIdentifier = keyid\n" +
|
|
16
16
|
"basicConstraints = CA:TRUE\n" +
|
|
17
17
|
"keyUsage = critical, cRLSign, keyCertSign\n" +
|
|
18
|
-
|
|
18
|
+
"nsComment = \"Self-signed Certificate for CA generated by Node-OPCUA Certificate utility\"\n" +
|
|
19
19
|
"#nsCertType = sslCA, emailCA\n" +
|
|
20
20
|
"#subjectAltName = email:copy\n" +
|
|
21
21
|
"#issuerAltName = issuer:copy\n" +
|
|
@@ -41,7 +41,7 @@ const config =
|
|
|
41
41
|
"basicConstraints = critical, CA:FALSE\n" +
|
|
42
42
|
"keyUsage = nonRepudiation, digitalSignature, keyEncipherment, dataEncipherment, keyCertSign\n" +
|
|
43
43
|
"extendedKeyUsage = clientAuth,serverAuth \n" +
|
|
44
|
-
|
|
44
|
+
"nsComment = \"certificate generated by Node-OPCUA Certificate utility and signed by a CA\"\n" +
|
|
45
45
|
"subjectAltName = $ENV::ALTNAME\n" +
|
|
46
46
|
"[ v3_selfsigned]\n" +
|
|
47
47
|
"subjectKeyIdentifier = hash\n" +
|
|
@@ -49,7 +49,7 @@ const config =
|
|
|
49
49
|
"basicConstraints = critical, CA:FALSE\n" +
|
|
50
50
|
"keyUsage = nonRepudiation, digitalSignature, keyEncipherment, dataEncipherment, keyCertSign\n" +
|
|
51
51
|
"extendedKeyUsage = clientAuth,serverAuth \n" +
|
|
52
|
-
|
|
52
|
+
"nsComment = \"Self-signed certificate generated by Node-OPCUA Certificate utility\"\n" +
|
|
53
53
|
"subjectAltName = $ENV::ALTNAME\n" +
|
|
54
54
|
"[ req_distinguished_name ]\n" +
|
|
55
55
|
"countryName = Country Name (2 letter code)\n" +
|
package/lib/pki/toolbox.ts
CHANGED
|
@@ -31,7 +31,6 @@ import * as child_process from "child_process";
|
|
|
31
31
|
import * as fs from "fs";
|
|
32
32
|
import * as os from "os";
|
|
33
33
|
import * as path from "path";
|
|
34
|
-
import * as util from "util";
|
|
35
34
|
|
|
36
35
|
import { get_openssl_exec_path } from "../misc/install_prerequisite";
|
|
37
36
|
import { Subject, SubjectOptions } from "../misc/subject";
|
|
@@ -42,18 +41,18 @@ import _simple_config_template from "./templates/simple_config_template.cnf";
|
|
|
42
41
|
const exportedEnvVars: any = {};
|
|
43
42
|
|
|
44
43
|
export function quote(str: string): string {
|
|
45
|
-
return
|
|
44
|
+
return "\"" + str + "\"";
|
|
46
45
|
}
|
|
47
46
|
|
|
48
47
|
// tslint:disable-next-line:variable-name
|
|
49
48
|
export const g_config = {
|
|
50
49
|
opensslVersion: "unset",
|
|
51
|
-
silent: process.env.VERBOSE ?
|
|
50
|
+
silent: process.env.VERBOSE ? !process.env.VERBOSE : true,
|
|
52
51
|
force: false,
|
|
53
52
|
};
|
|
54
53
|
|
|
55
54
|
const doDebug = process.env.NODEOPCUAPKIDEBUG || false;
|
|
56
|
-
const displayError
|
|
55
|
+
const displayError = true;
|
|
57
56
|
const displayDebug = !!process.env.NODEOPCUAPKIDEBUG || false;
|
|
58
57
|
// tslint:disable-next-line:no-empty
|
|
59
58
|
export function debugLog(...args: [any?, ...any[]]) {
|
|
@@ -95,11 +94,10 @@ export function setEnv(varName: string, value: string): void {
|
|
|
95
94
|
if (["RANDFILE"].indexOf(varName) >= 0) {
|
|
96
95
|
process.env[varName] = value;
|
|
97
96
|
}
|
|
98
|
-
|
|
99
97
|
}
|
|
100
98
|
|
|
101
99
|
export function hasEnv(varName: string): boolean {
|
|
102
|
-
return
|
|
100
|
+
return Object.prototype.hasOwnProperty.call(exportedEnvVars, varName);
|
|
103
101
|
}
|
|
104
102
|
|
|
105
103
|
export interface ExecuteOptions {
|
|
@@ -124,7 +122,7 @@ export function execute(cmd: string, options: ExecuteOptions, callback: (err: Er
|
|
|
124
122
|
cmd,
|
|
125
123
|
{
|
|
126
124
|
cwd: options.cwd,
|
|
127
|
-
windowsHide: true
|
|
125
|
+
windowsHide: true,
|
|
128
126
|
},
|
|
129
127
|
(err: child_process.ExecException | null) => {
|
|
130
128
|
// istanbul ignore next
|
|
@@ -174,7 +172,6 @@ export function useRandFile() {
|
|
|
174
172
|
}
|
|
175
173
|
|
|
176
174
|
function openssl_require2DigitYearInDate() {
|
|
177
|
-
|
|
178
175
|
// istanbul ignore next
|
|
179
176
|
if (!g_config.opensslVersion) {
|
|
180
177
|
throw new Error(
|
|
@@ -276,9 +273,7 @@ export function execute_openssl_no_failure(
|
|
|
276
273
|
execute_openssl(cmd, options, (err: Error | null, output?: string) => {
|
|
277
274
|
// istanbul ignore next
|
|
278
275
|
if (err) {
|
|
279
|
-
|
|
280
|
-
console.log(" (ignored error = ERROR : )", err!.message);
|
|
281
|
-
}
|
|
276
|
+
debugLog(" (ignored error = ERROR : )", err!.message);
|
|
282
277
|
}
|
|
283
278
|
callback(null, output);
|
|
284
279
|
});
|
|
@@ -496,7 +491,7 @@ export function createCertificateSigningRequest(
|
|
|
496
491
|
|
|
497
492
|
const subject = params.subject ? new Subject(params.subject).toString() : undefined;
|
|
498
493
|
// process.env.OPENSSL_CONF ="";
|
|
499
|
-
const subjectOptions = subject ?
|
|
494
|
+
const subjectOptions = subject ? " -subj \"" + subject + "\"" : "";
|
|
500
495
|
async.series(
|
|
501
496
|
[
|
|
502
497
|
(callback: (err?: Error) => void) => {
|
|
@@ -505,15 +500,15 @@ export function createCertificateSigningRequest(
|
|
|
505
500
|
(callback: (err?: Error) => void) => {
|
|
506
501
|
execute_openssl(
|
|
507
502
|
"req -new" +
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
503
|
+
" -sha256 " +
|
|
504
|
+
" -batch " +
|
|
505
|
+
" -text " +
|
|
506
|
+
configOption +
|
|
507
|
+
" -key " +
|
|
508
|
+
q(n(params.privateKey!)) +
|
|
509
|
+
subjectOptions +
|
|
510
|
+
" -out " +
|
|
511
|
+
q(n(certificateSigningRequestFilename)),
|
|
517
512
|
options,
|
|
518
513
|
(err: Error | null) => {
|
|
519
514
|
callback(err ? err : undefined);
|
|
@@ -678,13 +673,11 @@ export function createSelfSignCertificate(
|
|
|
678
673
|
params: CreateSelfSignCertificateWithConfigParam,
|
|
679
674
|
callback: (err?: Error | null) => void
|
|
680
675
|
) {
|
|
681
|
-
|
|
682
676
|
ensure_openssl_installed((err) => {
|
|
683
677
|
if (err) {
|
|
684
678
|
return callback(err);
|
|
685
679
|
}
|
|
686
680
|
try {
|
|
687
|
-
|
|
688
681
|
params.purpose = params.purpose || CertificatePurpose.ForApplication;
|
|
689
682
|
assert(params.purpose, "Please provide a Certificate Purpose");
|
|
690
683
|
/**
|
|
@@ -706,7 +699,7 @@ export function createSelfSignCertificate(
|
|
|
706
699
|
processAltNames(params);
|
|
707
700
|
|
|
708
701
|
adjustDate(params);
|
|
709
|
-
assert(
|
|
702
|
+
assert(Object.prototype.hasOwnProperty.call(params, "validity"));
|
|
710
703
|
|
|
711
704
|
let subject = new Subject(params.subject);
|
|
712
705
|
subject = subject.toString();
|
|
@@ -718,15 +711,15 @@ export function createSelfSignCertificate(
|
|
|
718
711
|
|
|
719
712
|
let extension: string;
|
|
720
713
|
switch (params.purpose) {
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
714
|
+
case CertificatePurpose.ForApplication:
|
|
715
|
+
extension = "v3_selfsigned";
|
|
716
|
+
break;
|
|
717
|
+
case CertificatePurpose.ForCertificateAuthority:
|
|
718
|
+
extension = "v3_ca";
|
|
719
|
+
break;
|
|
720
|
+
case CertificatePurpose.ForUserAuthentication:
|
|
721
|
+
default:
|
|
722
|
+
extension = "v3_selfsigned";
|
|
730
723
|
}
|
|
731
724
|
|
|
732
725
|
const tasks = [
|
|
@@ -741,19 +734,19 @@ export function createSelfSignCertificate(
|
|
|
741
734
|
(callback: ErrorCallback) => {
|
|
742
735
|
execute_openssl(
|
|
743
736
|
"req -new" +
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
737
|
+
" -sha256 " +
|
|
738
|
+
" -text " +
|
|
739
|
+
" -extensions " +
|
|
740
|
+
extension +
|
|
741
|
+
" " +
|
|
742
|
+
configOption +
|
|
743
|
+
" -key " +
|
|
744
|
+
q(n(params.privateKey!)) +
|
|
745
|
+
" -out " +
|
|
746
|
+
q(n(certificateRequestFilename)) +
|
|
747
|
+
" -subj \"" +
|
|
748
|
+
subject +
|
|
749
|
+
"\"",
|
|
757
750
|
{},
|
|
758
751
|
callback
|
|
759
752
|
);
|
|
@@ -770,21 +763,21 @@ export function createSelfSignCertificate(
|
|
|
770
763
|
(callback: ErrorCallback) => {
|
|
771
764
|
execute_openssl(
|
|
772
765
|
" x509 -req " +
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
766
|
+
" -days " +
|
|
767
|
+
params.validity +
|
|
768
|
+
" -extensions " +
|
|
769
|
+
extension +
|
|
770
|
+
" " +
|
|
771
|
+
" -extfile " +
|
|
772
|
+
q(n(configFile)) +
|
|
773
|
+
" -in " +
|
|
774
|
+
q(n(certificateRequestFilename)) +
|
|
775
|
+
" -signkey " +
|
|
776
|
+
q(n(params.privateKey!)) +
|
|
777
|
+
" -text " +
|
|
778
|
+
" -out " +
|
|
779
|
+
q(certificate) +
|
|
780
|
+
" -text ",
|
|
788
781
|
{},
|
|
789
782
|
callback
|
|
790
783
|
);
|
|
@@ -800,7 +793,6 @@ export function createSelfSignCertificate(
|
|
|
800
793
|
callback(err as Error);
|
|
801
794
|
}
|
|
802
795
|
});
|
|
803
|
-
|
|
804
796
|
}
|
|
805
797
|
|
|
806
798
|
// tslint:disable-next-line:variable-name
|