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

"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;
}