Skip to content

Commit

Permalink
feat: Add revocation reason
Browse files Browse the repository at this point in the history
  • Loading branch information
timokoessler committed Dec 16, 2023
1 parent bf3cad5 commit efd78b5
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 5 deletions.
21 changes: 21 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,23 @@ export type OCSPStatusConfig = {
enableNonce?: boolean;
};

/**
* The reason why a certificate was revoked.
* https://www.rfc-editor.org/rfc/rfc5280#section-5.3.1
*/
export enum OCSPRevocationReason {
unspecified = 0,
keyCompromise = 1,
caCompromise = 2,
affiliationChanged = 3,
superseded = 4,
cessationOfOperation = 5,
certificateHold = 6,
removeFromCRL = 8,
privilegeWithdrawn = 9,
aACompromise = 10,
}

export type OCSPStatusResponse = {
/**
* Revocation status of the certificate
Expand All @@ -58,6 +75,10 @@ export type OCSPStatusResponse = {
* The time at which the response was produced.
*/
producedAt?: Date;
/**
* The revocation reason. Only available if the status is 'revoked' and the OCSP response contains a revocation reason.
*/
revocationReason?: OCSPRevocationReason;
};

async function downloadIssuerCert(
Expand Down
14 changes: 10 additions & 4 deletions src/ocsp.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { webcrypto } from 'node:crypto';
import { GeneralizedTime, OctetString, UTCTime } from 'asn1js';
import { Constructed, Enumerated, GeneralizedTime, OctetString, UTCTime } from 'asn1js';
import * as pkijs from 'pkijs';
import { OCSPStatusConfig, OCSPStatusResponse } from './index';

Expand Down Expand Up @@ -176,14 +176,20 @@ export async function parseOCSPResponse(
}

if (status === 'revoked' && Array.isArray(singleResponse.certStatus?.valueBlock?.value)) {
for (const v of basicResponse.tbsResponseData.responses[0].certStatus.valueBlock.value) {
for (const v of singleResponse.certStatus.valueBlock.value) {
if (v instanceof GeneralizedTime) {
result.revocationTime = v.toDate();
break;
}
if (v instanceof UTCTime) {
result.revocationTime = v.toDate();
break;
}
if (v instanceof Constructed) {
if (Array.isArray(v.valueBlock.value) && v.valueBlock.value.length === 1) {
const vBlock = v.valueBlock.value[0];
if (vBlock instanceof Enumerated) {
result.revocationReason = vBlock.valueBlock.valueDec;
}
}
}
}
}
Expand Down
5 changes: 4 additions & 1 deletion test/le-revoked.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { X509Certificate } from 'crypto';
import { getCertStatus, getCertURLs } from '../src/index';
import { getCertStatus, getCertURLs, OCSPRevocationReason } from '../src/index';
import { readCertFile } from './test-helper';

let cert: string;
Expand All @@ -14,6 +14,7 @@ test('Check revoked Lets Encrypt cert', async () => {
const result = await getCertStatus(cert);
expect(result.status).toBe('revoked');
expect(result.revocationTime?.getTime()).toBe(1702737476000);
expect(result.revocationReason).toBe(OCSPRevocationReason.superseded);
});

test('Get OCSP and issuer URLs', async () => {
Expand Down Expand Up @@ -44,10 +45,12 @@ test('Set ca manually', async () => {
});
expect(result.status).toBe('revoked');
expect(result.revocationTime?.getTime()).toBe(1702737476000);
expect(result.revocationReason).toBe(OCSPRevocationReason.superseded);
});

test('Pass X509Certificate object', async () => {
const result = await getCertStatus(new X509Certificate(cert));
expect(result.status).toBe('revoked');
expect(result.revocationTime?.getTime()).toBe(1702737476000);
expect(result.revocationReason).toBe(OCSPRevocationReason.superseded);
});

0 comments on commit efd78b5

Please sign in to comment.