如何检查 X509 证书是否已在 Java 中被吊销?

How do I check if an X509 certificate has been revoked in Java?

为此,我到处搜索,并在其他社区询问,我不断被转发到讨论规范的 oracle 文档。然而,该文档更多地涵盖了方法的命名和整体架构,并没有真正提出一种方法来讨论如何实际编写一些代码来检查 x509 证书是否被撤销。

也许这个问题超出了我的理解范围?但是,如果有人能帮我提供一个片段,我将不胜感激,我已经为此苦苦思索了大约一个星期。

每个 CA 都会发布它已吊销的证书列表。 此列表包括证书的序列号和吊销日期

按照以下步骤获取证书撤销列表 (CRL) 的 url

  • 打开证书
  • 转到详细信息选项卡并在详细信息列表中找到字段 "CRL Distribution Point"

它将向您显示类似这样的值

[1]CRL 分发点 分发点名称: 全名: URL=mscrl.microsoft.com/pki/mscorp/crl/msitwww2.crl URL=crl.microsoft.com/pki/mscorp/crl/msitwww2.crl

因此在您的代码中您需要下载这些文件并检查其中的证书序列号以查看它是否已被吊销

在下面找到它的示例代码

public class CertVerification {


    public static void main(String[] args) throws Exception {

        String certificatePath = "C:\Users\user1\Desktop\test.cer";

        CertificateFactory cf = CertificateFactory.getInstance("X509");

        X509Certificate certificate = null;
        X509CRLEntry revokedCertificate = null;
        X509CRL crl = null;

        certificate = (X509Certificate) cf.generateCertificate(new FileInputStream(new File(certificatePath)));

        URL url = new URL("http://<someUrl from certificate>.crl");
        URLConnection connection = url.openConnection();

        try(DataInputStream inStream = new DataInputStream(connection.getInputStream())){

            crl = (X509CRL)cf.generateCRL(inStream);
        }

        revokedCertificate = crl.getRevokedCertificate(certificate.getSerialNumber());

        if(revokedCertificate !=null){
            System.out.println("Revoked");
        }
        else{
            System.out.println("Valid");
        }

    }


}

请看

这些列表会定期更新

你也可以从证书中得到这些吊销URL,我刚刚举了一个例子

这只是一个基本示例,让您先行一步

更新

我找到了这个示例class来检查证书,它还验证了证书的 CA 和证书链颁发的 CRL,因此您也不需要提供 CRL url

https://svn.cesecore.eu/svn/ejbca/branches/Branch_3_2_3_utf8/ejbca/doc/samples/ValidateCertUseCRL.java

证书颁发机构使用在线证书服务协议 (OCSP) 和证书吊销列表 (CRL) 发布证书的状态。

检查证书的吊销涉及几个步骤:

  1. 从 X509 证书中包含的 AIA 扩展中提取 CRL 分发点和 OCSP url

  2. 下载 CRL 并检查是否包含证书的序列号。验证 CRL 的签名证书并确保受信任(信任库中的根 CA)

  3. 在线查询OCSP服务发送序列号和发行者以获取状态。检查 OCSP 响应的签名并确保签名证书是可信的(您的信任库中的根 CA)。

  4. 如果证书存在于 CRL 中或 OCSP 状态被撤销,则证书被撤销。建议使用 OCSP 而不是 CRL,但通常会同时查询这两种服务,因为可能会出现故障。

如您所见,这个过程一点也不简单。检查证书是否有效可能包括多次调用 OCSP 服务、下载证书链、验证 CRL 和 OCSP 响应的签名证书的签名,最后验证 CA 是否可信

所以如果你不打算考虑所有这些因素,我建议不要直接使用Java本地方法

您可以使用 BouncyCastle 来管理 CRL 和查询 OCSP,但更好的决定是使用 SD-DSS 框架(它也使用 BouncyCastle),它很好地封装了所有这些东西。

Github SD-DSS: https://github.com/esig/dss 文档:http://dss.nowina.lu/doc/dss-documentation.html


例子

验证证书检查吊销的完整示例。如果只想检查撤销,则省略加载可信源和中间体的步骤

//Load the certification chain, including the intemediate certificates and the trusted root.    
CertificateToken issuerCert = DSSUtils.loadCertificate("/trusted.crt");
CommonTrustedCertificateSource trustedCertificateSource = new CommonTrustedCertificateSource();
trustedCertificateSource.addCertificate(issuerCert);

CommonCertificateSource adjunctCertificateSource = new CommonCertificateSource();
CertificateToken intermediateCert = DSSUtils.loadCertificate("/intermediate.cer");
adjunctCertificateSource.addCertificate(intermediateCert);

//Load the certificate to verify
CertificateToken toValidateX509Certificate = DSSUtils.loadCertificate("/toValidate.crt");
CertificateToken toValidateCertificateToken = adjunctCertificateSource.addCertificate(toValidateX509Certificate);

//Configure the certificate verifier using the trust store and the intermediate certificates
//OnlineOCSPSource and OnlineCRLSource will invoke the OCSP service and CRL
//distribution point extracting the URL  from the certificate
CertificateVerifier certificateVerifier = new CommonCertificateVerifier();
certificateVerifier.setTrustedCertSource(trustedCertificateSource);
certificateVerifier.setAdjunctCertSource(adjunctCertificateSource);     
certificateVerifier.setCrlSource(new OnlineCRLSource());
certificateVerifier.setOcspSource(new OnlineOCSPSource());

//Perform validation 
CertificatePool validationPool = certificateVerifier.createValidationPool();
SignatureValidationContext validationContext = new SignatureValidationContext(validationPool);
validationContext.addCertificateTokenForVerification(toValidateCertificateToken);
validationContext.validate();

//Get revocation status
Boolean isRevoked = toValidateCertificateToken.isRevoked();
RevocationToken revocationToken = toValidateCertificateToken.getRevocationToken();