mlocati/ocsp

使用在线证书状态协议(OCSP)查询HTTPS证书撤销状态的库

1.2.0 2023-09-14 15:26 UTC

This package is auto-updated.

Last update: 2024-09-14 18:20:47 UTC


README

Tests Coverage Status Scrutinizer Code Quality Packagist Downloads

在线证书状态协议PHP库

此存储库包含一个PHP库,帮助您通过在线证书状态协议(OCSP)检查HTTPS证书是否已撤销。

此库不需要对系统实用程序(如OpenSSL)的 exec 调用:它是一个纯PHP库。

此库不包含任何网络相关的助手:您必须使用自己的传输库(cURL、Zend HTTP、Guzzle等)。

检查HTTPS证书需要

  • 要检查的证书,格式为PEM(即以 `-----BEGIN CERTIFICATE-----` 开头的文本文件),或DER格式(即二进制文件)
  • 颁发者证书,即提供HTTPS证书的认证机构的证书
  • 由认证机构提供的用于OCSP调用的URL(即所谓的 OCSR Responder URL

从HTTPS URL获取证书和颁发者证书

您可以使用以下代码从HTTPS URL获取HTTPS证书和颁发者证书

$hCurl = curl_init($url);
curl_setopt($hCurl, CURLOPT_RETURNTRANSFER, false);
curl_setopt($hCurl, CURLOPT_CUSTOMREQUEST, 'HEAD');
curl_setopt($hCurl, CURLOPT_NOBODY, true);
curl_setopt($hCurl, CURLOPT_CERTINFO, true);
curl_exec($hCurl);
$certInfo = curl_getinfo($hCurl, CURLINFO_CERTINFO);

$certificate = $certInfo[0]['Cert'];
$issuerCertificate = $certInfo[1]['Cert'];

从证书获取颁发者证书

HTTPS证书通常包含一个URL,您可以在其中找到证书颁发者的证书。

您可以使用以下代码提取此URL,前提是 '/path/to/certificate' 是包含您的HTTPS证书的本地文件的路径

$certificateLoader = new \Ocsp\CertificateLoader();
$certificate = $certificateLoader->fromFile('/path/to/certificate');
$certificateInfo = new \Ocsp\CertificateInfo();
$urlOfIssuerCertificate = $certificateInfo->extractIssuerCertificateUrl($certificate);

此时,$urlOfIssuerCertificate 将包含可以从其中下载颁发者证书的URL(如果它是空字符串,则表示颁发者证书URL未包含在您的证书中)。

获取OCSP Responder URL

为了检查证书是否有效,我们需要知道由颁发证书的机构提供的URL,该URL可以用来检查证书是否已被撤销。

此URL可能包含在HTTPS证书本身中。

要获取它,您可以使用以下代码(前提是 '/path/to/certificate' 是包含您的HTTPS证书的本地文件的路径)

$certificateLoader = new \Ocsp\CertificateLoader();
$certificate = $certificateLoader->fromFile('/path/to/certificate');
$certificateInfo = new \Ocsp\CertificateInfo();
$ocspResponderUrl = $certificateInfo->extractOcspResponderUrl($certificate);

检查证书是否已被撤销

一旦您有了HTTPS证书、颁发者证书和OCSP Responder URL,您就可以检查HTTPS证书是否已被撤销,或者它是否仍然有效。

为此,您必须编写一些代码,如下所示(这里我们使用cURL,但您可以使用任何其他传输库)

$certificateLoader = new \Ocsp\CertificateLoader();
$certificateInfo = new \Ocsp\CertificateInfo();
$ocsp = new \Ocsp\Ocsp();

// Load the HTTPS certificate and the issuer certificate
$certificate = $certificateLoader->fromFile('/path/to/certificate');
$issuerCertificate = $certificateLoader->fromFile('/path/to/issuer/certificate');

// Extract the relevant data from the two certificates
$requestInfo = $certificateInfo->extractRequestInfo($certificate, $issuerCertificate);

// Build the raw body to be sent to the OCSP Responder URL
$requestBody = $ocsp->buildOcspRequestBodySingle($requestInfo);

// Actually call the OCSP Responder URL (here we use cURL, you can use any library you prefer)
$hCurl = curl_init();
curl_setopt($hCurl, CURLOPT_URL, $ocspResponderUrl);
curl_setopt($hCurl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($hCurl, CURLOPT_POST, true);
curl_setopt($hCurl, CURLOPT_HTTPHEADER, ['Content-Type: ' . \Ocsp\Ocsp::OCSP_REQUEST_MEDIATYPE]);
curl_setopt($hCurl, CURLOPT_SAFE_UPLOAD, true);
curl_setopt($hCurl, CURLOPT_POSTFIELDS, $requestBody);
$result = curl_exec($hCurl);
$info = curl_getinfo($hCurl);
if ($info['http_code'] !== 200) {
    throw new \RuntimeException("Whoops, here we'd expect a 200 HTTP code");
}
if ($info['content_type'] !== \Ocsp\Ocsp::OCSP_RESPONSE_MEDIATYPE) {
    throw new \RuntimeException("Whoops, the Content-Type header of the response seems wrong!");
}

// Decode the raw response from the OCSP Responder
$response = $ocsp->decodeOcspResponseSingle($result);

此时,$response 包含 Ocsp\Response 类的实例

  • 如果 $response->isRevoked() === false,则证书未被撤销
  • 如果 $response->isRevoked() === true,则证书已被撤销(您可以通过调用 $response->getRevokedOn() 获取撤销的日期/时间)
  • 在未知状态下,$response->isRevoked() 将返回 null

异常

在加载证书、创建OCSP Responder请求体、分析OCSP Responder响应时可能会出现问题。为了捕获这些错误,您可以在代码中包围 try/catch 语句

try {
    // code
} catch (\Ocsp\Exception\Exception $problem) {
    // handle the error cases
}