node-opcua-pki 6.11.1 → 6.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/pki.mjs +201 -73
- package/dist/bin/pki.mjs.map +1 -1
- package/dist/index.d.mts +98 -17
- package/dist/index.d.ts +98 -17
- package/dist/index.js +229 -70
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +227 -73
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/bin/pki.mjs
CHANGED
|
@@ -354,38 +354,21 @@ import {
|
|
|
354
354
|
exploreCertificateRevocationList,
|
|
355
355
|
generatePrivateKeyFile,
|
|
356
356
|
makeSHA1Thumbprint,
|
|
357
|
-
|
|
358
|
-
|
|
357
|
+
readCertificateChain,
|
|
358
|
+
readCertificateChainAsync,
|
|
359
359
|
readCertificateRevocationList,
|
|
360
360
|
split_der,
|
|
361
361
|
toPem,
|
|
362
|
-
verifyCertificateChain,
|
|
363
362
|
verifyCertificateSignature
|
|
364
363
|
} from "node-opcua-crypto";
|
|
365
364
|
function getOrComputeInfo(entry) {
|
|
366
365
|
if (!entry.info) {
|
|
367
|
-
entry.info =
|
|
366
|
+
entry.info = exploreCertificate(entry.certificate);
|
|
368
367
|
}
|
|
369
368
|
return entry.info;
|
|
370
369
|
}
|
|
371
|
-
function exploreCertificateCached(certificate) {
|
|
372
|
-
const key = makeSHA1Thumbprint(certificate).toString("hex");
|
|
373
|
-
const cached = _exploreCache.get(key);
|
|
374
|
-
if (cached) {
|
|
375
|
-
_exploreCache.delete(key);
|
|
376
|
-
_exploreCache.set(key, cached);
|
|
377
|
-
return cached;
|
|
378
|
-
}
|
|
379
|
-
const info = exploreCertificate(certificate);
|
|
380
|
-
_exploreCache.set(key, info);
|
|
381
|
-
if (_exploreCache.size > EXPLORE_CACHE_MAX) {
|
|
382
|
-
const oldest = _exploreCache.keys().next().value;
|
|
383
|
-
if (oldest) _exploreCache.delete(oldest);
|
|
384
|
-
}
|
|
385
|
-
return info;
|
|
386
|
-
}
|
|
387
370
|
function makeFingerprint(certificate) {
|
|
388
|
-
const chain = split_der(certificate);
|
|
371
|
+
const chain = Array.isArray(certificate) ? certificate : split_der(certificate);
|
|
389
372
|
return makeSHA1Thumbprint(chain[0]).toString("hex");
|
|
390
373
|
}
|
|
391
374
|
function short(stringToShorten) {
|
|
@@ -394,7 +377,7 @@ function short(stringToShorten) {
|
|
|
394
377
|
function buildIdealCertificateName(certificate) {
|
|
395
378
|
const fingerprint2 = makeFingerprint(certificate);
|
|
396
379
|
try {
|
|
397
|
-
const commonName =
|
|
380
|
+
const commonName = exploreCertificate(certificate).tbsCertificate.subject.commonName || "";
|
|
398
381
|
const sanitizedCommonName = commonName.replace(forbiddenChars, "_");
|
|
399
382
|
return `${sanitizedCommonName}[${fingerprint2}]`;
|
|
400
383
|
} catch (_err) {
|
|
@@ -411,16 +394,36 @@ function isSelfSigned2(info) {
|
|
|
411
394
|
return info.tbsCertificate.extensions?.subjectKeyIdentifier === info.tbsCertificate.extensions?.authorityKeyIdentifier?.keyIdentifier;
|
|
412
395
|
}
|
|
413
396
|
function isSelfSigned3(certificate) {
|
|
414
|
-
const info =
|
|
397
|
+
const info = exploreCertificate(certificate);
|
|
415
398
|
return isSelfSigned2(info);
|
|
416
399
|
}
|
|
400
|
+
function _isIssuerInfo(info) {
|
|
401
|
+
const basicConstraints = info.tbsCertificate.extensions?.basicConstraints;
|
|
402
|
+
if (basicConstraints?.cA) {
|
|
403
|
+
return true;
|
|
404
|
+
}
|
|
405
|
+
const keyUsage = info.tbsCertificate.extensions?.keyUsage;
|
|
406
|
+
if (keyUsage?.keyCertSign) {
|
|
407
|
+
return true;
|
|
408
|
+
}
|
|
409
|
+
return false;
|
|
410
|
+
}
|
|
411
|
+
function isIssuer(certificate) {
|
|
412
|
+
try {
|
|
413
|
+
const info = exploreCertificate(certificate);
|
|
414
|
+
return _isIssuerInfo(info);
|
|
415
|
+
} catch (_err) {
|
|
416
|
+
return false;
|
|
417
|
+
}
|
|
418
|
+
}
|
|
417
419
|
function findIssuerCertificateInChain(certificate, chain) {
|
|
418
|
-
|
|
420
|
+
const firstCertificate = Array.isArray(certificate) ? certificate[0] : certificate;
|
|
421
|
+
if (!firstCertificate) {
|
|
419
422
|
return null;
|
|
420
423
|
}
|
|
421
|
-
const certInfo =
|
|
424
|
+
const certInfo = exploreCertificate(firstCertificate);
|
|
422
425
|
if (isSelfSigned2(certInfo)) {
|
|
423
|
-
return
|
|
426
|
+
return firstCertificate;
|
|
424
427
|
}
|
|
425
428
|
const wantedIssuerKey = certInfo.tbsCertificate.extensions?.authorityKeyIdentifier?.keyIdentifier;
|
|
426
429
|
if (!wantedIssuerKey) {
|
|
@@ -428,7 +431,7 @@ function findIssuerCertificateInChain(certificate, chain) {
|
|
|
428
431
|
return null;
|
|
429
432
|
}
|
|
430
433
|
const potentialIssuers = chain.filter((c) => {
|
|
431
|
-
const info =
|
|
434
|
+
const info = exploreCertificate(c);
|
|
432
435
|
return info.tbsCertificate.extensions && info.tbsCertificate.extensions.subjectKeyIdentifier === wantedIssuerKey;
|
|
433
436
|
});
|
|
434
437
|
if (potentialIssuers.length === 1) {
|
|
@@ -440,7 +443,7 @@ function findIssuerCertificateInChain(certificate, chain) {
|
|
|
440
443
|
}
|
|
441
444
|
return null;
|
|
442
445
|
}
|
|
443
|
-
var configurationFileSimpleTemplate, fsWriteFile,
|
|
446
|
+
var configurationFileSimpleTemplate, fsWriteFile, forbiddenChars, CertificateManager;
|
|
444
447
|
var init_certificate_manager = __esm({
|
|
445
448
|
"packages/node-opcua-pki/lib/pki/certificate_manager.ts"() {
|
|
446
449
|
"use strict";
|
|
@@ -451,8 +454,6 @@ var init_certificate_manager = __esm({
|
|
|
451
454
|
init_simple_config_template_cnf();
|
|
452
455
|
configurationFileSimpleTemplate = simple_config_template_cnf_default;
|
|
453
456
|
fsWriteFile = fs4.promises.writeFile;
|
|
454
|
-
EXPLORE_CACHE_MAX = 8;
|
|
455
|
-
_exploreCache = /* @__PURE__ */ new Map();
|
|
456
457
|
forbiddenChars = /[\x00-\x1F<>:"/\\|?*]/g;
|
|
457
458
|
CertificateManager = class _CertificateManager extends EventEmitter {
|
|
458
459
|
// ── Global instance registry ─────────────────────────────────
|
|
@@ -545,6 +546,7 @@ var init_certificate_manager = __esm({
|
|
|
545
546
|
#readCertificatesCalled = false;
|
|
546
547
|
#filenameToHash = /* @__PURE__ */ new Map();
|
|
547
548
|
#initializingPromise;
|
|
549
|
+
#addCertValidation;
|
|
548
550
|
#thumbs = {
|
|
549
551
|
rejected: /* @__PURE__ */ new Map(),
|
|
550
552
|
trusted: /* @__PURE__ */ new Map(),
|
|
@@ -571,6 +573,13 @@ var init_certificate_manager = __esm({
|
|
|
571
573
|
}
|
|
572
574
|
this.#location = makePath(options.location, "");
|
|
573
575
|
this.keySize = options.keySize;
|
|
576
|
+
const v = options.addCertificateValidationOptions ?? {};
|
|
577
|
+
this.#addCertValidation = {
|
|
578
|
+
acceptExpiredCertificate: v.acceptExpiredCertificate ?? false,
|
|
579
|
+
acceptRevokedCertificate: v.acceptRevokedCertificate ?? false,
|
|
580
|
+
ignoreMissingRevocationList: v.ignoreMissingRevocationList ?? false,
|
|
581
|
+
maxChainLength: v.maxChainLength ?? 5
|
|
582
|
+
};
|
|
574
583
|
mkdirRecursiveSync(options.location);
|
|
575
584
|
if (!fs4.existsSync(this.#location)) {
|
|
576
585
|
throw new Error(`CertificateManager cannot access location ${this.#location}`);
|
|
@@ -661,7 +670,12 @@ var init_certificate_manager = __esm({
|
|
|
661
670
|
* or `"BadCertificateInvalid"` if the certificate cannot be parsed.
|
|
662
671
|
*/
|
|
663
672
|
async isCertificateTrusted(certificate) {
|
|
664
|
-
|
|
673
|
+
let fingerprint2;
|
|
674
|
+
try {
|
|
675
|
+
fingerprint2 = makeFingerprint(certificate);
|
|
676
|
+
} catch (_err) {
|
|
677
|
+
return "BadCertificateInvalid";
|
|
678
|
+
}
|
|
665
679
|
if (this.#thumbs.trusted.has(fingerprint2)) {
|
|
666
680
|
return "Good";
|
|
667
681
|
}
|
|
@@ -681,13 +695,13 @@ var init_certificate_manager = __esm({
|
|
|
681
695
|
}
|
|
682
696
|
return "BadCertificateUntrusted";
|
|
683
697
|
}
|
|
684
|
-
async #innerVerifyCertificateAsync(
|
|
698
|
+
async #innerVerifyCertificateAsync(certificateOrChain, _isIssuer, level, options) {
|
|
685
699
|
if (level >= 5) {
|
|
686
700
|
return "BadSecurityChecksFailed" /* BadSecurityChecksFailed */;
|
|
687
701
|
}
|
|
688
|
-
const chain =
|
|
702
|
+
const chain = Array.isArray(certificateOrChain) ? certificateOrChain : [certificateOrChain];
|
|
689
703
|
debugLog("NB CERTIFICATE IN CHAIN = ", chain.length);
|
|
690
|
-
const info =
|
|
704
|
+
const info = exploreCertificate(chain[0]);
|
|
691
705
|
let hasValidIssuer = false;
|
|
692
706
|
let hasTrustedIssuer = false;
|
|
693
707
|
const hasIssuerKey = info.tbsCertificate.extensions?.authorityKeyIdentifier?.keyIdentifier;
|
|
@@ -724,7 +738,7 @@ var init_certificate_manager = __esm({
|
|
|
724
738
|
return "BadCertificateIssuerRevocationUnknown" /* BadCertificateIssuerRevocationUnknown */;
|
|
725
739
|
}
|
|
726
740
|
if (issuerStatus === "BadCertificateTimeInvalid" /* BadCertificateTimeInvalid */) {
|
|
727
|
-
if (!options
|
|
741
|
+
if (!options?.acceptOutDatedIssuerCertificate) {
|
|
728
742
|
return "BadCertificateIssuerTimeInvalid" /* BadCertificateIssuerTimeInvalid */;
|
|
729
743
|
}
|
|
730
744
|
}
|
|
@@ -734,13 +748,13 @@ var init_certificate_manager = __esm({
|
|
|
734
748
|
if (issuerStatus !== "Good" /* Good */ && issuerStatus !== "BadCertificateUntrusted" /* BadCertificateUntrusted */) {
|
|
735
749
|
return "BadSecurityChecksFailed" /* BadSecurityChecksFailed */;
|
|
736
750
|
}
|
|
737
|
-
const isCertificateSignatureOK = verifyCertificateSignature(
|
|
751
|
+
const isCertificateSignatureOK = verifyCertificateSignature(chain[0], issuerCertificate);
|
|
738
752
|
if (!isCertificateSignatureOK) {
|
|
739
753
|
debugLog(" the certificate was not signed by the issuer as it claim to be ! Danger");
|
|
740
754
|
return "BadSecurityChecksFailed" /* BadSecurityChecksFailed */;
|
|
741
755
|
}
|
|
742
756
|
hasValidIssuer = true;
|
|
743
|
-
let revokedStatus = await this.isCertificateRevoked(
|
|
757
|
+
let revokedStatus = await this.isCertificateRevoked(certificateOrChain);
|
|
744
758
|
if (revokedStatus === "BadCertificateRevocationUnknown" /* BadCertificateRevocationUnknown */) {
|
|
745
759
|
if (options?.ignoreMissingRevocationList) {
|
|
746
760
|
revokedStatus = "Good" /* Good */;
|
|
@@ -760,16 +774,16 @@ var init_certificate_manager = __esm({
|
|
|
760
774
|
return "BadSecurityChecksFailed" /* BadSecurityChecksFailed */;
|
|
761
775
|
}
|
|
762
776
|
} else {
|
|
763
|
-
const isCertificateSignatureOK = verifyCertificateSignature(
|
|
777
|
+
const isCertificateSignatureOK = verifyCertificateSignature(chain[0], chain[0]);
|
|
764
778
|
if (!isCertificateSignatureOK) {
|
|
765
779
|
debugLog("Self-signed Certificate signature is not valid");
|
|
766
780
|
return "BadSecurityChecksFailed" /* BadSecurityChecksFailed */;
|
|
767
781
|
}
|
|
768
|
-
const revokedStatus = await this.isCertificateRevoked(
|
|
782
|
+
const revokedStatus = await this.isCertificateRevoked(certificateOrChain);
|
|
769
783
|
debugLog("revokedStatus of self signed certificate:", revokedStatus);
|
|
770
784
|
}
|
|
771
785
|
}
|
|
772
|
-
const status = await this.#checkRejectedOrTrusted(
|
|
786
|
+
const status = await this.#checkRejectedOrTrusted(certificateOrChain);
|
|
773
787
|
if (status === "rejected") {
|
|
774
788
|
if (!(options.acceptCertificateWithValidIssuerChain && hasValidIssuer && hasTrustedIssuer)) {
|
|
775
789
|
return "BadCertificateUntrusted" /* BadCertificateUntrusted */;
|
|
@@ -777,7 +791,7 @@ var init_certificate_manager = __esm({
|
|
|
777
791
|
}
|
|
778
792
|
const _c2 = chain[1] ? exploreCertificateInfo(chain[1]) : "non";
|
|
779
793
|
debugLog("chain[1] info=", _c2);
|
|
780
|
-
const certificateInfo = exploreCertificateInfo(
|
|
794
|
+
const certificateInfo = exploreCertificateInfo(chain[0]);
|
|
781
795
|
const now = /* @__PURE__ */ new Date();
|
|
782
796
|
let isTimeInvalid = false;
|
|
783
797
|
if (certificateInfo.notBefore.getTime() > now.getTime()) {
|
|
@@ -827,6 +841,16 @@ var init_certificate_manager = __esm({
|
|
|
827
841
|
* @returns the verification status code
|
|
828
842
|
*/
|
|
829
843
|
async verifyCertificateAsync(certificate, options) {
|
|
844
|
+
if (!Array.isArray(certificate)) {
|
|
845
|
+
try {
|
|
846
|
+
const derElements = split_der(certificate);
|
|
847
|
+
for (const element of derElements) {
|
|
848
|
+
exploreCertificateInfo(element);
|
|
849
|
+
}
|
|
850
|
+
} catch (_err) {
|
|
851
|
+
return "BadCertificateInvalid" /* BadCertificateInvalid */;
|
|
852
|
+
}
|
|
853
|
+
}
|
|
830
854
|
const status1 = await this.#innerVerifyCertificateAsync(certificate, false, 0, options);
|
|
831
855
|
return status1;
|
|
832
856
|
}
|
|
@@ -1054,6 +1078,23 @@ var init_certificate_manager = __esm({
|
|
|
1054
1078
|
}
|
|
1055
1079
|
return "Good" /* Good */;
|
|
1056
1080
|
}
|
|
1081
|
+
/**
|
|
1082
|
+
* Add multiple CA (issuer) certificates to the issuers store.
|
|
1083
|
+
* @param certificates - the DER-encoded CA certificates
|
|
1084
|
+
* @param validate - if `true`, verify each certificate before adding
|
|
1085
|
+
* @param addInTrustList - if `true`, also add each certificate to the trusted store
|
|
1086
|
+
* @returns `VerificationStatus.Good` on success
|
|
1087
|
+
*/
|
|
1088
|
+
async addIssuers(certificates, validate = false, addInTrustList = false) {
|
|
1089
|
+
for (const certificate of certificates) {
|
|
1090
|
+
if (!isIssuer(certificate)) {
|
|
1091
|
+
warningLog(`Certificate ${makeFingerprint(certificate)} is not a issuer certificate`);
|
|
1092
|
+
continue;
|
|
1093
|
+
}
|
|
1094
|
+
await this.addIssuer(certificate, validate, addInTrustList);
|
|
1095
|
+
}
|
|
1096
|
+
return "Good" /* Good */;
|
|
1097
|
+
}
|
|
1057
1098
|
/**
|
|
1058
1099
|
* Add a CRL to the certificate manager.
|
|
1059
1100
|
* @param crl - the CRL to add
|
|
@@ -1177,7 +1218,7 @@ var init_certificate_manager = __esm({
|
|
|
1177
1218
|
* @param target - "issuers", "trusted", or "all" (default "all")
|
|
1178
1219
|
*/
|
|
1179
1220
|
async removeRevocationListsForIssuer(issuerCertificate, target = "all") {
|
|
1180
|
-
const issuerInfo =
|
|
1221
|
+
const issuerInfo = exploreCertificate(issuerCertificate);
|
|
1181
1222
|
const issuerFingerprint = issuerInfo.tbsCertificate.subjectFingerPrint;
|
|
1182
1223
|
const processIndex = async (index) => {
|
|
1183
1224
|
const crlData = index.get(issuerFingerprint);
|
|
@@ -1204,41 +1245,125 @@ var init_certificate_manager = __esm({
|
|
|
1204
1245
|
* Validate a certificate (optionally with its chain) and add
|
|
1205
1246
|
* the leaf certificate to the trusted store.
|
|
1206
1247
|
*
|
|
1207
|
-
*
|
|
1208
|
-
* full chain (leaf + issuer certificates concatenated in DER).
|
|
1209
|
-
* Only the leaf certificate is added to the trusted store.
|
|
1248
|
+
* Performs OPC UA Part 4, Table 100 validation:
|
|
1210
1249
|
*
|
|
1211
|
-
*
|
|
1212
|
-
*
|
|
1213
|
-
*
|
|
1250
|
+
* 1. **Certificate Structure** — parse the DER encoding.
|
|
1251
|
+
* 2. **Build Certificate Chain** — walk from the leaf to a
|
|
1252
|
+
* self-signed root CA, using the provided chain and the
|
|
1253
|
+
* issuers store.
|
|
1254
|
+
* 3. **Signature** — verify each certificate's signature
|
|
1255
|
+
* against its issuer.
|
|
1256
|
+
* 4. **Issuer Presence** — every issuer in the chain must
|
|
1257
|
+
* already be registered in the issuers store (per GDS
|
|
1258
|
+
* 7.8.2.6).
|
|
1259
|
+
* 5. **Validity Period** — each certificate must be within
|
|
1260
|
+
* its validity window (overridable via
|
|
1261
|
+
* {@link AddCertificateValidationOptions.acceptExpiredCertificate}).
|
|
1262
|
+
* 6. **Revocation Check** — each certificate is checked
|
|
1263
|
+
* against its issuer's CRL (overridable via
|
|
1264
|
+
* {@link AddCertificateValidationOptions.acceptRevokedCertificate}
|
|
1265
|
+
* and {@link AddCertificateValidationOptions.ignoreMissingRevocationList}).
|
|
1214
1266
|
*
|
|
1215
|
-
*
|
|
1216
|
-
* the leaf certificate will be rejected.
|
|
1267
|
+
* Only the leaf certificate is added to the trusted store.
|
|
1217
1268
|
*
|
|
1218
1269
|
* @param certificateChain - DER-encoded certificate or chain
|
|
1219
1270
|
* @returns `VerificationStatus.Good` on success, or an error
|
|
1220
1271
|
* status indicating why the certificate was rejected.
|
|
1221
1272
|
*/
|
|
1222
1273
|
async addTrustedCertificateFromChain(certificateChain) {
|
|
1223
|
-
const certificates = split_der(certificateChain);
|
|
1224
|
-
const leafCertificate = certificates[0];
|
|
1225
1274
|
try {
|
|
1226
|
-
|
|
1275
|
+
return await this.#addTrustedCertificateFromChainImpl(certificateChain);
|
|
1227
1276
|
} catch (_err) {
|
|
1277
|
+
warningLog("addTrustedCertificateFromChain: unexpected error", _err);
|
|
1228
1278
|
return "BadCertificateInvalid" /* BadCertificateInvalid */;
|
|
1229
1279
|
}
|
|
1230
|
-
|
|
1231
|
-
|
|
1280
|
+
}
|
|
1281
|
+
async #addTrustedCertificateFromChainImpl(certificateChain) {
|
|
1282
|
+
let certificates;
|
|
1283
|
+
try {
|
|
1284
|
+
certificates = Array.isArray(certificateChain) ? certificateChain : split_der(certificateChain);
|
|
1285
|
+
} catch (_err) {
|
|
1286
|
+
return "BadCertificateInvalid" /* BadCertificateInvalid */;
|
|
1287
|
+
}
|
|
1288
|
+
if (certificates.length === 0) {
|
|
1232
1289
|
return "BadCertificateInvalid" /* BadCertificateInvalid */;
|
|
1233
1290
|
}
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1291
|
+
const leafCertificate = certificates[0];
|
|
1292
|
+
const opts = this.#addCertValidation;
|
|
1293
|
+
let leafInfo;
|
|
1294
|
+
try {
|
|
1295
|
+
leafInfo = exploreCertificate(leafCertificate);
|
|
1296
|
+
} catch (_err) {
|
|
1297
|
+
return "BadCertificateInvalid" /* BadCertificateInvalid */;
|
|
1298
|
+
}
|
|
1299
|
+
await this.#scanCertFolder(this.issuersCertFolder, this.#thumbs.issuers.certs);
|
|
1300
|
+
let currentCert = leafCertificate;
|
|
1301
|
+
let currentInfo = leafInfo;
|
|
1302
|
+
let depth = 0;
|
|
1303
|
+
while (true) {
|
|
1304
|
+
depth++;
|
|
1305
|
+
if (depth > opts.maxChainLength) {
|
|
1306
|
+
return "BadSecurityChecksFailed" /* BadSecurityChecksFailed */;
|
|
1307
|
+
}
|
|
1308
|
+
if (!opts.acceptExpiredCertificate) {
|
|
1309
|
+
let certDetails;
|
|
1310
|
+
try {
|
|
1311
|
+
certDetails = exploreCertificateInfo(currentCert);
|
|
1312
|
+
} catch (_err) {
|
|
1313
|
+
return "BadCertificateInvalid" /* BadCertificateInvalid */;
|
|
1314
|
+
}
|
|
1315
|
+
const now = /* @__PURE__ */ new Date();
|
|
1316
|
+
if (certDetails.notBefore.getTime() > now.getTime()) {
|
|
1317
|
+
return "BadCertificateTimeInvalid" /* BadCertificateTimeInvalid */;
|
|
1318
|
+
}
|
|
1319
|
+
if (certDetails.notAfter.getTime() <= now.getTime()) {
|
|
1320
|
+
return depth === 1 ? "BadCertificateTimeInvalid" /* BadCertificateTimeInvalid */ : "BadCertificateIssuerTimeInvalid" /* BadCertificateIssuerTimeInvalid */;
|
|
1321
|
+
}
|
|
1322
|
+
}
|
|
1323
|
+
if (isSelfSigned2(currentInfo)) {
|
|
1324
|
+
try {
|
|
1325
|
+
if (!verifyCertificateSignature(currentCert, currentCert)) {
|
|
1326
|
+
return "BadCertificateInvalid" /* BadCertificateInvalid */;
|
|
1327
|
+
}
|
|
1328
|
+
} catch (_err) {
|
|
1329
|
+
return "BadCertificateInvalid" /* BadCertificateInvalid */;
|
|
1330
|
+
}
|
|
1331
|
+
break;
|
|
1332
|
+
}
|
|
1333
|
+
let issuerCert = await this.findIssuerCertificate(currentCert);
|
|
1334
|
+
if (!issuerCert) {
|
|
1335
|
+
issuerCert = findIssuerCertificateInChain(currentCert, certificates);
|
|
1336
|
+
if (!issuerCert || issuerCert === currentCert) {
|
|
1239
1337
|
return "BadCertificateChainIncomplete" /* BadCertificateChainIncomplete */;
|
|
1240
1338
|
}
|
|
1241
1339
|
}
|
|
1340
|
+
try {
|
|
1341
|
+
if (!verifyCertificateSignature(currentCert, issuerCert)) {
|
|
1342
|
+
return "BadCertificateInvalid" /* BadCertificateInvalid */;
|
|
1343
|
+
}
|
|
1344
|
+
} catch (_err) {
|
|
1345
|
+
return "BadCertificateInvalid" /* BadCertificateInvalid */;
|
|
1346
|
+
}
|
|
1347
|
+
const issuerThumbprint = makeFingerprint(issuerCert);
|
|
1348
|
+
if (!await this.hasIssuer(issuerThumbprint)) {
|
|
1349
|
+
return "BadCertificateChainIncomplete" /* BadCertificateChainIncomplete */;
|
|
1350
|
+
}
|
|
1351
|
+
const revokedStatus = await this.isCertificateRevoked(currentCert, issuerCert);
|
|
1352
|
+
if (revokedStatus === "BadCertificateRevoked" /* BadCertificateRevoked */) {
|
|
1353
|
+
if (!opts.acceptRevokedCertificate) {
|
|
1354
|
+
return "BadCertificateRevoked" /* BadCertificateRevoked */;
|
|
1355
|
+
}
|
|
1356
|
+
} else if (revokedStatus === "BadCertificateRevocationUnknown" /* BadCertificateRevocationUnknown */) {
|
|
1357
|
+
if (!opts.ignoreMissingRevocationList) {
|
|
1358
|
+
return "BadCertificateRevocationUnknown" /* BadCertificateRevocationUnknown */;
|
|
1359
|
+
}
|
|
1360
|
+
}
|
|
1361
|
+
currentCert = issuerCert;
|
|
1362
|
+
try {
|
|
1363
|
+
currentInfo = exploreCertificate(currentCert);
|
|
1364
|
+
} catch (_err) {
|
|
1365
|
+
return "BadCertificateInvalid" /* BadCertificateInvalid */;
|
|
1366
|
+
}
|
|
1242
1367
|
}
|
|
1243
1368
|
await this.trustCertificate(leafCertificate);
|
|
1244
1369
|
return "Good" /* Good */;
|
|
@@ -1283,9 +1408,10 @@ var init_certificate_manager = __esm({
|
|
|
1283
1408
|
*
|
|
1284
1409
|
*/
|
|
1285
1410
|
async findIssuerCertificate(certificate) {
|
|
1286
|
-
const
|
|
1411
|
+
const firstCertificate = Array.isArray(certificate) ? certificate[0] : certificate;
|
|
1412
|
+
const certInfo = exploreCertificate(firstCertificate);
|
|
1287
1413
|
if (isSelfSigned2(certInfo)) {
|
|
1288
|
-
return
|
|
1414
|
+
return firstCertificate;
|
|
1289
1415
|
}
|
|
1290
1416
|
const wantedIssuerKey = certInfo.tbsCertificate.extensions?.authorityKeyIdentifier?.keyIdentifier;
|
|
1291
1417
|
if (!wantedIssuerKey) {
|
|
@@ -1319,7 +1445,8 @@ var init_certificate_manager = __esm({
|
|
|
1319
1445
|
* @private
|
|
1320
1446
|
*/
|
|
1321
1447
|
async #checkRejectedOrTrusted(certificate) {
|
|
1322
|
-
const
|
|
1448
|
+
const firstCertificate = Array.isArray(certificate) ? certificate[0] : certificate;
|
|
1449
|
+
const fingerprint2 = makeFingerprint(firstCertificate);
|
|
1323
1450
|
debugLog("#checkRejectedOrTrusted fingerprint ", short(fingerprint2));
|
|
1324
1451
|
await this.#readCertificates();
|
|
1325
1452
|
if (this.#thumbs.rejected.has(fingerprint2)) {
|
|
@@ -1364,7 +1491,7 @@ var init_certificate_manager = __esm({
|
|
|
1364
1491
|
});
|
|
1365
1492
|
}
|
|
1366
1493
|
#findAssociatedCRLs(issuerCertificate) {
|
|
1367
|
-
const issuerCertificateInfo =
|
|
1494
|
+
const issuerCertificateInfo = exploreCertificate(issuerCertificate);
|
|
1368
1495
|
const key = issuerCertificateInfo.tbsCertificate.subjectFingerPrint;
|
|
1369
1496
|
return this.#thumbs.issuersCrl.get(key) ?? this.#thumbs.crl.get(key) ?? null;
|
|
1370
1497
|
}
|
|
@@ -1385,11 +1512,12 @@ var init_certificate_manager = __esm({
|
|
|
1385
1512
|
* found.
|
|
1386
1513
|
*/
|
|
1387
1514
|
async isCertificateRevoked(certificate, issuerCertificate) {
|
|
1388
|
-
|
|
1515
|
+
const firstCertificate = Array.isArray(certificate) ? certificate[0] : certificate;
|
|
1516
|
+
if (isSelfSigned3(firstCertificate)) {
|
|
1389
1517
|
return "Good" /* Good */;
|
|
1390
1518
|
}
|
|
1391
1519
|
if (!issuerCertificate) {
|
|
1392
|
-
issuerCertificate = await this.findIssuerCertificate(
|
|
1520
|
+
issuerCertificate = await this.findIssuerCertificate(firstCertificate);
|
|
1393
1521
|
}
|
|
1394
1522
|
if (!issuerCertificate) {
|
|
1395
1523
|
return "BadCertificateChainIncomplete" /* BadCertificateChainIncomplete */;
|
|
@@ -1398,7 +1526,7 @@ var init_certificate_manager = __esm({
|
|
|
1398
1526
|
if (!crls) {
|
|
1399
1527
|
return "BadCertificateRevocationUnknown" /* BadCertificateRevocationUnknown */;
|
|
1400
1528
|
}
|
|
1401
|
-
const certInfo =
|
|
1529
|
+
const certInfo = exploreCertificate(firstCertificate);
|
|
1402
1530
|
const serialNumber = certInfo.tbsCertificate.serialNumber || certInfo.tbsCertificate.extensions?.authorityKeyIdentifier?.serial || "";
|
|
1403
1531
|
const key = certInfo.tbsCertificate.extensions?.authorityKeyIdentifier?.authorityCertIssuerFingerPrint || "<unknown>";
|
|
1404
1532
|
const crl2 = this.#thumbs.crl.get(key) ?? null;
|
|
@@ -1517,8 +1645,8 @@ var init_certificate_manager = __esm({
|
|
|
1517
1645
|
try {
|
|
1518
1646
|
const stat = await fs4.promises.stat(filename);
|
|
1519
1647
|
if (!stat.isFile()) continue;
|
|
1520
|
-
const certificate = await
|
|
1521
|
-
const info =
|
|
1648
|
+
const certificate = (await readCertificateChainAsync(filename))[0];
|
|
1649
|
+
const info = exploreCertificate(certificate);
|
|
1522
1650
|
const fingerprint2 = makeFingerprint(certificate);
|
|
1523
1651
|
index.set(fingerprint2, { certificate, filename, info });
|
|
1524
1652
|
this.#filenameToHash.set(filename, fingerprint2);
|
|
@@ -1604,8 +1732,8 @@ var init_certificate_manager = __esm({
|
|
|
1604
1732
|
w.on("add", (filename) => {
|
|
1605
1733
|
debugLog(chalk3.cyan(`add in folder ${folder}`), filename);
|
|
1606
1734
|
try {
|
|
1607
|
-
const certificate =
|
|
1608
|
-
const info =
|
|
1735
|
+
const certificate = readCertificateChain(filename)[0];
|
|
1736
|
+
const info = exploreCertificate(certificate);
|
|
1609
1737
|
const fingerprint2 = makeFingerprint(certificate);
|
|
1610
1738
|
const isNew = !index.has(fingerprint2);
|
|
1611
1739
|
index.set(fingerprint2, { certificate, filename, info });
|
|
@@ -1627,13 +1755,13 @@ var init_certificate_manager = __esm({
|
|
|
1627
1755
|
w.on("change", (changedPath) => {
|
|
1628
1756
|
debugLog(chalk3.cyan(`change in folder ${folder}`), changedPath);
|
|
1629
1757
|
try {
|
|
1630
|
-
const certificate =
|
|
1758
|
+
const certificate = readCertificateChain(changedPath)[0];
|
|
1631
1759
|
const newFingerprint = makeFingerprint(certificate);
|
|
1632
1760
|
const oldHash = this.#filenameToHash.get(changedPath);
|
|
1633
1761
|
if (oldHash && oldHash !== newFingerprint) {
|
|
1634
1762
|
index.delete(oldHash);
|
|
1635
1763
|
}
|
|
1636
|
-
index.set(newFingerprint, { certificate, filename: changedPath, info:
|
|
1764
|
+
index.set(newFingerprint, { certificate, filename: changedPath, info: exploreCertificate(certificate) });
|
|
1637
1765
|
this.#filenameToHash.set(changedPath, newFingerprint);
|
|
1638
1766
|
this.emit("certificateChange", { store, certificate, fingerprint: newFingerprint, filename: changedPath });
|
|
1639
1767
|
} catch (err) {
|