如何用pkijs在TypeScript中解码验证OCSP响应以校验证书
OCSP请求解码问题及解决方案
目标
我们需要判断证书是否有效或已被吊销,为此使用pkijs包发起OCSP请求,发送与证书相关的关键信息,比如hashAlgorithm、issuerNameHash、issuerKeyHash等(代码见下文)。
问题
成功获取OCSP响应后,响应内容大部分是编码状态,难以直接解读,只能看到少量证书类型相关元素,无法提取更多可读的证书状态信息。
尝试操作
我们调用用于校验证书状态的函数,测试时使用以下硬编码参数:
await checkCertificateWithOcsp({ hashAlgorithm: 'SHA256', issuerKeyHash: '7870177724f6234dccf87a8a43c84551533f831257519f90b12bb8eecae0', issuerNameHash: 'cbe609c06ec9bd944a5d8cf94aee2979d4396fe00f68c6d215e233766514a1', responderURL: 'https://7kravoouwj.execute-api.eu-west-1.amazonaws.com/test/OCSP-Responder', serialNumber: '2', });
对应的函数实现代码:
import * as asn1js from 'asn1js'; import { AlgorithmIdentifier, CertID, Extension, OCSPRequest, OCSPResponse, Request } from 'pkijs'; import Axios from 'axios'; public static async checkCertificateWithOcsp(ocspRequest: OCSPRequestData) { // 将十六进制字符串转换为字节数组(Uint8Array) const issuerNameHashBytes = new Uint8Array(ocspRequest.issuerNameHash.match(/.{1,2}/g).map(byte => parseInt(byte, 16))); const issuerKeyHashBytes = new Uint8Array(ocspRequest.issuerKeyHash.match(/.{1,2}/g).map(byte => parseInt(byte, 16))); const serialNumberBytes = new Uint8Array(ocspRequest.serialNumber.match(/.{1,2}/g).map(byte => parseInt(byte, 16))); // 1. 使用PKI.js构建OCSP请求 const request = new OCSPRequest(); request.tbsRequest.requestList[0] = new Request(); request.tbsRequest.requestExtensions = [ new Extension({ extnID: "1.3.6.1.5.5.7.48.1.2", critical: false, extnValue: new asn1js.OctetString().toBER(), }) ]; request.tbsRequest.requestList[0].reqCert = new CertID({ hashAlgorithm: new AlgorithmIdentifier({ algorithmId: "1.3.14.3.2.26" }), issuerNameHash: new asn1js.OctetString({ valueHex: issuerNameHashBytes }), issuerKeyHash: new asn1js.OctetString({ valueHex: issuerKeyHashBytes }), serialNumber: new asn1js.Integer({ valueHex: serialNumberBytes }), }); // 2. 编码OCSP请求 const encodedOcspReq = request.toSchema(true).toBER(false); // 3. 使用Axios调用OCSP接口 const response: any = await Axios.post<ArrayBuffer>(ocspRequest.responderURL, encodedOcspReq, { headers: { 'Content-Type': 'application/ocsp-request', }, }, ); // 4. 将响应转换为ASN1格式 const ocspResponseBuffer = Buffer.from(ocspResponse.data); const rawOcspResponseBuffer = new Uint8Array(ocspResponseBuffer.buffer); const asn1 = asn1js.fromBER(rawOcspResponseBuffer.buffer); // 5. 尝试解码获取证书状态时触发PKI.js错误 const decodedOcspResponse = new OCSPResponse({ schema: asn1.result }); }
代码步骤说明
- 借助PKI.js和ASN1.js包构建OCSP请求
- 对OCSP请求进行编码,发送至OCSP接口
- 接收包含编码数据的响应
- 将编码的OCSP响应转换为ASN1格式
- 尝试解码响应以获取证书状态信息
错误描述
执行步骤5时,PKI.js抛出错误:Object's schema was not verified against input data for OCSPResponse。
由于对证书安全领域不熟悉,虽已做调研,但仍无法定位错误原因及修复方法。
编辑1:原始响应内容
OCSP服务返回的response.data值如下(包含不可读的编码内容):
0�{ ��t0�p +0�a0�]0�ȡK0I10U V2GRootCA10U Smartlab10 �&���,dV2G10 UDE20230927144339Z0h0f0O0 +�� �nɽ�J]��J�)y�9o�h���3ve�xpw$�#M��z�C�EQS?�WQ���+�����20230927144339Z0*�H�=���2���S�`���̥��0���oN6N8�'��2ř��=O�l,�>>jA���<~�`f}�%�2���S�`���̥��0���oN6N8�'��2ř��=O�l,�>>jA���<~�`f
无法识别该编码类型。
编辑2:解决方案
问题根源在于Axios未指定响应类型,需在请求配置中添加responseType: 'arraybuffer',修改后的代码如下:
const response: any = await Axios.post<ArrayBuffer>(ocspRequest.responderURL, encodedOcspReq, { headers: { 'Content-Type': 'application/ocsp-request', }, responseType: 'arraybuffer', }, );
内容的提问来源于stack exchange,提问作者Namachi
相关产品推荐
相关产品推荐

