如何使用 pkijs 解码和验证 TypeScript 中的 OCSP 响应以进行证书验证

问题描述 投票:0回答:1

目标

我们的目标是确定证书是否良好或是否已被吊销。 为了实现这一目标,我们使用 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) {
    // Convert hexadecimal strings into bytes (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. Create OCSP Request with PKI.js
    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. Encode OCSP request
    const encodedOcspReq = request.toSchema(true).toBER(false);

    // 3. OCSP API Call with Axios
    const response: any = await Axios.post<ArrayBuffer>(ocspRequest.responderURL, encodedOcspReq,
      {
        headers: {
          'Content-Type': 'application/ocsp-request',
        },
      },
    );

    // 4. Convert response to ASN1
    const ocspResponseBuffer = Buffer.from(ocspResponse.data);
    const rawOcspResponseBuffer = new Uint8Array(ocspResponseBuffer.buffer);
    const asn1 = asn1js.fromBER(rawOcspResponseBuffer.buffer);

    // 5. Error occurred in PKI.JS OCSPResponse Class
    const decodedOcspResponse = new OCSPResponse({ schema: asn1.result });
}

上述代码的步骤

  1. 首先,我们借助 PKI.js 和 ASN1.js 包填写请求。
  2. 在将 OCSP 请求发送到 OCSP API 调用之前对其进行编码。
  3. 我们成功收到带有编码数据的响应
  4. 将编码的 OCSP 响应数据转换为 ASN1
  5. 尝试解码并访问信息以获取证书状态

错误描述

第5步,PKI端出现错误,错误信息如下:

Object's schema was not verified against input data for OCSPResponse

由于证书安全根本不是我们的专业领域,尽管我们努力进行研究,但我们无法确定错误可能在哪里以及如何纠正它。

预先感谢您的帮助。

node.js typescript security certificate ocsp
1个回答
0
投票

您遇到的错误消息“未根据 OCSPResponse 的输入数据验证对象的架构”表明 OCSP 响应的预期架构与收到的实际数据之间存在不匹配。这通常意味着接收到的数据不符合预期的 ASN.1 模式。

以下步骤可帮助您排除故障并可能解决此问题:

  1. 验证响应内容类型: 确保从服务器收到的 OCSP 响应的内容类型与预期的内容类型匹配。在代码中,您在发出 OCSP 请求时将“Content-Type”标头设置为“application/ocsp-request”。确保服务器使用正确的“Content-Type”标头进行响应,对于 OCSP 响应,该标头应为“application/ocsp-response”。

    示例:

    headers: {
      'Content-Type': 'application/ocsp-response',
    },
    
  2. 检查 OCSP 响应编码: OCSP 响应采用 DER 编码。确保您收到的响应是 DER 编码且未损坏。如果不是 DER 编码,您可能需要以不同的方式处理解码。

    示例:

    const ocspResponseBuffer = Buffer.from(response.data, 'binary');
    
  3. 确保响应数据完整: 验证您是否收到来自服务器的完整 OCSP 响应。它应该包括所有必要的组件,例如响应状态、响应字节和响应数据。不完整的响应可能会导致架构验证问题。

  4. 检查可能的网络错误: 确保传输过程中不存在导致数据损坏的网络相关问题。您可以添加错误处理来检查网络错误,例如超时或连接问题。

    示例:

    try {
      const response = await Axios.post<ArrayBuffer>(ocspRequest.responderURL, encodedOcspReq, {
        headers: {
          'Content-Type': 'application/ocsp-request',
        },
      });
      // Handle the response here
    } catch (error) {
      console.error('Network error:', error);
      // Handle the error gracefully
    }
    
  5. 验证 ASN.1 架构: 确保用于解码 OCSP 响应的 ASN.1 架构与从服务器收到的响应的结构相匹配。您可以参考 PKI.js 文档来确认预期的结构。

  6. 记录和调试: 在代码的各个阶段添加日志记录语句以检查数据并确定架构和数据之间可能发生不匹配的位置。这可以帮助查明问题。

通过系统地检查这些要点并调试代码,您应该能够识别错误来源并进行必要的更正,以成功解码 OCSP 响应并确定证书状态。

© www.soinside.com 2019 - 2024. All rights reserved.