diff options
author | Matthew Miller <matthew@millerti.me> | 2022-12-15 23:29:31 -0800 |
---|---|---|
committer | Matthew Miller <matthew@millerti.me> | 2022-12-15 23:29:31 -0800 |
commit | d9c4b65d785ceb5358e3a145b0ff860b19ab3937 (patch) | |
tree | f582cc2d945fe91c7ba3a6cdc230d39b80758a7d /packages/server/src | |
parent | 6f3cb6e6aae30b65c4d4e789b3b8aeae9c2b3173 (diff) |
Reduce use of jsrsasign in isCertRevoked()
Diffstat (limited to 'packages/server/src')
-rw-r--r-- | packages/server/src/helpers/isCertRevoked.ts | 86 |
1 files changed, 51 insertions, 35 deletions
diff --git a/packages/server/src/helpers/isCertRevoked.ts b/packages/server/src/helpers/isCertRevoked.ts index 2d7f5d6..bac8356 100644 --- a/packages/server/src/helpers/isCertRevoked.ts +++ b/packages/server/src/helpers/isCertRevoked.ts @@ -1,9 +1,16 @@ -import { X509 } from 'jsrsasign'; import fetch from 'cross-fetch'; import { AsnParser } from '@peculiar/asn1-schema'; -import { CertificateList } from '@peculiar/asn1-x509'; +import { + CertificateList, + Certificate, + AuthorityKeyIdentifier, + id_ce_authorityKeyIdentifier, + SubjectKeyIdentifier, + id_ce_subjectKeyIdentifier, + id_ce_cRLDistributionPoints, + CRLDistributionPoints, +} from '@peculiar/asn1-x509'; -import { convertCertBufferToPEM } from './convertCertBufferToPEM'; import { isoUint8Array } from './iso'; /** @@ -23,31 +30,48 @@ const cacheRevokedCerts: { [certAuthorityKeyID: string]: CAAuthorityInfo } = {}; * * CRL certificate structure referenced from https://tools.ietf.org/html/rfc5280#page-117 */ -export async function isCertRevoked(cert: X509): Promise<boolean> { - const certSerialHex = cert.getSerialNumberHex(); +export async function isCertRevoked(cert: Certificate): Promise<boolean> { + const { extensions } = cert.tbsCertificate; - // Check to see if we've got cached info for the cert's CA - let keyIdentifier: jsrsasign.AuthorityKeyIdentifierResult | jsrsasign.ExtSubjectKeyIdentifier | undefined = undefined; - try { - keyIdentifier = cert.getExtAuthorityKeyIdentifier(); - } catch (err) { - // pass + if (!extensions) { + throw new Error('Certificate had no extensions needed to check for revocation'); } - /** - * We might be dealing with a self-signed root certificate. Check the - * Subject key Identifier extension next. - */ - if (!keyIdentifier) { - try { - keyIdentifier = cert.getExtSubjectKeyIdentifier(); - } catch (err) { - // pass + let extAuthorityKeyID: AuthorityKeyIdentifier | undefined; + let extSubjectKeyID: SubjectKeyIdentifier | undefined; + let extCRLDistributionPoints: CRLDistributionPoints | undefined; + + extensions.forEach((ext) => { + if (ext.extnID === id_ce_authorityKeyIdentifier) { + extAuthorityKeyID = AsnParser.parse(ext.extnValue, AuthorityKeyIdentifier); + } else if (ext.extnID === id_ce_subjectKeyIdentifier) { + extSubjectKeyID = AsnParser.parse(ext.extnValue, SubjectKeyIdentifier); + } else if (ext.extnID === id_ce_cRLDistributionPoints) { + extCRLDistributionPoints = AsnParser.parse(ext.extnValue, CRLDistributionPoints); } + }); + + // Check to see if we've got cached info for the cert's CA + let keyIdentifier: string | undefined = undefined; + + if (extAuthorityKeyID && extAuthorityKeyID.keyIdentifier) { + keyIdentifier = isoUint8Array.toHex( + new Uint8Array(extAuthorityKeyID.keyIdentifier.buffer), + ); + } else if (extSubjectKeyID) { + /** + * We might be dealing with a self-signed root certificate. Check the + * Subject key Identifier extension next. + */ + keyIdentifier = isoUint8Array.toHex( + new Uint8Array(extSubjectKeyID.buffer), + ); } + const certSerialHex = isoUint8Array.toHex(new Uint8Array(cert.tbsCertificate.serialNumber)); + if (keyIdentifier) { - const cached = cacheRevokedCerts[keyIdentifier.kid.hex]; + const cached = cacheRevokedCerts[keyIdentifier]; if (cached) { const now = new Date(); // If there's a nextUpdate then make sure we're before it @@ -57,13 +81,7 @@ export async function isCertRevoked(cert: X509): Promise<boolean> { } } - let crlURL = undefined; - try { - crlURL = cert.getExtCRLDistributionPointsURI(); - } catch (err) { - // Cert probably didn't include any CDP URIs - return false; - } + const crlURL = extCRLDistributionPoints?.[0].distributionPoint?.fullName?.[0].uniformResourceIdentifier; // If no URL is provided then we have nothing to check if (!crlURL) { @@ -71,17 +89,15 @@ export async function isCertRevoked(cert: X509): Promise<boolean> { } // Download and read the CRL - const crlCert = new X509(); + let certListBytes: ArrayBuffer; try { - const respCRL = await fetch(crlURL[0]); - const dataCRL = await respCRL.arrayBuffer(); - const dataPEM = convertCertBufferToPEM(new Uint8Array(dataCRL)); - crlCert.readCertPEM(dataPEM); + const respCRL = await fetch(crlURL); + certListBytes = await respCRL.arrayBuffer(); } catch (err) { return false; } - const data = AsnParser.parse(isoUint8Array.fromHex(crlCert.hex), CertificateList); + const data = AsnParser.parse(certListBytes, CertificateList); const newCached: CAAuthorityInfo = { revokedCerts: [], @@ -104,7 +120,7 @@ export async function isCertRevoked(cert: X509): Promise<boolean> { // Cache the results if (keyIdentifier) { - cacheRevokedCerts[keyIdentifier.kid.hex] = newCached; + cacheRevokedCerts[keyIdentifier] = newCached; } return newCached.revokedCerts.indexOf(certSerialHex) >= 0; |