mirror of https://github.com/ghostfolio/ghostfolio
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
99 lines
3.2 KiB
99 lines
3.2 KiB
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.isCertRevoked = isCertRevoked;
|
|
const x509_1 = require("@peculiar/x509");
|
|
const fetch_js_1 = require("./fetch.js");
|
|
const cacheRevokedCerts = {};
|
|
/**
|
|
* A method to pull a CRL from a certificate and compare its serial number to the list of revoked
|
|
* certificate serial numbers within the CRL.
|
|
*
|
|
* CRL certificate structure referenced from https://tools.ietf.org/html/rfc5280#page-117
|
|
*/
|
|
async function isCertRevoked(cert) {
|
|
const { extensions } = cert;
|
|
if (!extensions) {
|
|
return false;
|
|
}
|
|
let extAuthorityKeyID;
|
|
let extSubjectKeyID;
|
|
let extCRLDistributionPoints;
|
|
extensions.forEach((ext) => {
|
|
if (ext instanceof x509_1.AuthorityKeyIdentifierExtension) {
|
|
extAuthorityKeyID = ext;
|
|
}
|
|
else if (ext instanceof x509_1.SubjectKeyIdentifierExtension) {
|
|
extSubjectKeyID = ext;
|
|
}
|
|
else if (ext instanceof x509_1.CRLDistributionPointsExtension) {
|
|
extCRLDistributionPoints = ext;
|
|
}
|
|
});
|
|
// Check to see if we've got cached info for the cert's CA
|
|
let keyIdentifier = undefined;
|
|
if (extAuthorityKeyID && extAuthorityKeyID.keyId) {
|
|
keyIdentifier = extAuthorityKeyID.keyId;
|
|
}
|
|
else if (extSubjectKeyID) {
|
|
/**
|
|
* We might be dealing with a self-signed root certificate. Check the
|
|
* Subject key Identifier extension next.
|
|
*/
|
|
keyIdentifier = extSubjectKeyID.keyId;
|
|
}
|
|
if (keyIdentifier) {
|
|
const cached = cacheRevokedCerts[keyIdentifier];
|
|
if (cached) {
|
|
const now = new Date();
|
|
// If there's a nextUpdate then make sure we're before it
|
|
if (!cached.nextUpdate || cached.nextUpdate > now) {
|
|
return cached.revokedCerts.indexOf(cert.serialNumber) >= 0;
|
|
}
|
|
}
|
|
}
|
|
const crlURL = extCRLDistributionPoints?.distributionPoints?.[0].distributionPoint?.fullName?.[0]
|
|
.uniformResourceIdentifier;
|
|
// If no URL is provided then we have nothing to check
|
|
if (!crlURL) {
|
|
return false;
|
|
}
|
|
// Download and read the CRL
|
|
let certListBytes;
|
|
try {
|
|
const respCRL = await (0, fetch_js_1.fetch)(crlURL);
|
|
certListBytes = await respCRL.arrayBuffer();
|
|
}
|
|
catch (_err) {
|
|
return false;
|
|
}
|
|
let data;
|
|
try {
|
|
data = new x509_1.X509Crl(certListBytes);
|
|
}
|
|
catch (_err) {
|
|
// Something was malformed with the CRL, so pass
|
|
return false;
|
|
}
|
|
const newCached = {
|
|
revokedCerts: [],
|
|
nextUpdate: undefined,
|
|
};
|
|
// nextUpdate
|
|
if (data.nextUpdate) {
|
|
newCached.nextUpdate = data.nextUpdate;
|
|
}
|
|
// revokedCertificates
|
|
const revokedCerts = data.entries;
|
|
if (revokedCerts) {
|
|
for (const cert of revokedCerts) {
|
|
const revokedHex = cert.serialNumber;
|
|
newCached.revokedCerts.push(revokedHex);
|
|
}
|
|
// Cache the results
|
|
if (keyIdentifier) {
|
|
cacheRevokedCerts[keyIdentifier] = newCached;
|
|
}
|
|
return newCached.revokedCerts.indexOf(cert.serialNumber) >= 0;
|
|
}
|
|
return false;
|
|
}
|
|
|