Java X509 证书解析和验证

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10043376/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-30 23:22:36  来源:igfitidea点击:

Java X509 Certificate parsing and validating

javavalidationx509certificatepkijce

提问by Driss Amri

I'm trying to process X509 certificates in several steps and running into a couple of problems. I'm new to JCE so I not completely up to date on everything yet.

我正在尝试分几个步骤处理 X509 证书,但遇到了几个问题。我是 JCE 的新手,所以我还没有完全了解所有内容。

We want to be able to parse several different X509 certificates based on different encodings (PEM, DER and PCKS7). I've exported the same certificate from https://belgium.bein PEM and PCKS7 format using FireFox (certificate including chain). I've left couple lines out that are not needed for the questions

我们希望能够根据不同的编码(PEM、DER 和 PCKS7)解析几个不同的 X509 证书。我已经使用 FireFox(包括链的证书)以 PEM 和 PCKS7 格式从https://belgium.be导出了相同的证书。我留下了问题不需要的几行

public List<X509Certificate> parse(FileInputStream fis) {  
    /*
     * Generate a X509 Certificate initialized with the data read from the inputstream. 
     * NOTE: Generation fails when using BufferedInputStream on PKCS7 certificates.
     */
    List<X509Certificate> certificates = null;
      log.debug("Parsing new certificate.");
      certificates = (List<X509Certificate>) cf.generateCertificates(fis);
    return certificates;
  }

This code is working fine aslong as I work with a FileInputStream instead of a BufferedInputStream for PCKS7, which is quite strange already I think? But I can live with it.

只要我使用 FileInputStream 而不是 PCKS7 的 BufferedInputStream ,此代码就可以正常工作,我认为这已经很奇怪了?但我可以忍受它。

The next step is to validate these certificate chains. 1) Check if all certificates have a valid date (easy) 2) Validate certificate chain using OCSP (and fallback to CRL if no OCSP URL is found in the certificate). This is where I'm not completely sure how to handle this.

下一步是验证这些证书链。1) 检查所有证书是否都有有效日期(简单) 2) 使用 OCSP 验证证书链(如果在证书中找不到 OCSP URL,则回退到 CRL)。这是我不完全确定如何处理的地方。

I'm using the Sun JCE, but it seems there is not that much documentation available (in examples) for this?

我正在使用 Sun JCE,但似乎没有太多可用的文档(在示例中)?

I first made a simple implementation that only checks the chain without going through the OCSP/CRL checks.

我首先做了一个简单的实现,只检查链而不通过 OCSP/CRL 检查。

private Boolean validateChain(List<X509Certificate> certificates) {
    PKIXParameters params;
    CertPath certPath;
    CertPathValidator certPathValidator;
    Boolean valid = Boolean.FALSE;

    params = new PKIXParameters(keyStore);
    params.setRevocationEnabled(false);

    certPath = cf.generateCertPath(certificates);
    certPathValidator = CertPathValidator.getInstance("PKIX");

    PKIXCertPathValidatorResult result = (PKIXCertPathValidatorResult)  
    certPathValidator.validate(certPath, params);

      if(null != result) {
        valid = Boolean.TRUE;
      }
    return valid;
 }

This is working fine for my PEM certificate, but not for the PCKS7 certificate (same certifcate, only exported in other format). java.security.cert.CertPathValidatorException: Path does not chain with any of the trust anchors.

这适用于我的 PEM 证书,但不适用于 PCKS7 证书(相同的证书,仅以其他格式导出)。 java.security.cert.CertPathValidatorException:路径不与任何信任锚链接。

The only difference I'm able to see is that the order in which the CertPath is formed is not the same? I was not able to figure out what was going wrong so I left this for now and kept on going with the PEM certificate, but lets call this QUESTION 1 ;)

我能看到的唯一区别是 CertPath 的形成顺序不一样?我无法弄清楚出了什么问题,所以我暂时离开了这个并继续使用 PEM 证书,但让我们称之为问题 1 ;)

What I wanted to implement afterwards was the OCSP checking. Apparently if I enable OCSP using: Security.setProperty("ocsp.enable", "true");and set params.setRevocationEnabled(true);it should be able to find the OCSP URL on its own, but that does not seem to be the case. What is the standard implementation supposed to do (QUESTION 2)? java.security.cert.CertPathValidatorException: Must specify the location of an OCSP Responder

之后我想实现的是OCSP检查。显然,如果我使用以下方法启用 OCSP: Security.setProperty("ocsp.enable", "true"); 并设置 params.setRevocationEnabled(true); 它应该能够自己找到 OCSP URL,但情况似乎并非如此。标准实现应该做什么(问题2)? java.security.cert.CertPathValidatorException:必须指定 OCSP 响应程序的位置

Going past this, I found a way to retrieve the OCSP url from the certificate using AuthorityInfoAccessExtension and such.

过去,我找到了一种使用 AuthorityInfoAccessExtension 等从证书中检索 OCSP url 的方法。

But after setting the OCSP url manually in the ocsp.url property, I'm getting an java.security.cert.CertPathValidatorException: OCSP response error: UNAUTHORIZED

但是在 ocsp.url 属性中手动设置 OCSP url 后,我收到了java.security.cert.CertPathValidatorException: OCSP response error: UNAUTHORIZED

It seems like I'm missing a lot of necessary steps while alot of online references say setting the ocsp.enableproperty should be all you need to do?

似乎我错过了很多必要的步骤,而很多在线参考资料都说设置ocsp.enable属性应该是您需要做的全部?

Perhaps any of you whizkids cant guide me through the process a little bit? Show me where I'm completely wrong :)

也许你们中的任何一个神童都不能指导我完成这个过程?告诉我我完全错的地方:)

The next step would be implementing CRL checks if no OCSP was found, if anyone could point out any example or show me some documentation on this it would also be much appreciated!

如果没有找到 OCSP,下一步将实施 CRL 检查,如果有人能指出任何示例或向我展示一些关于此的文档,也将不胜感激!

Thanks!

谢谢!

EDIT:Since it's not picking up the properties on its own, I've been trying to set all the properties myself using the following:

编辑:由于它没有自行获取属性,我一直在尝试使用以下方法自己设置所有属性:

    // Activate OCSP
        Security.setProperty("ocsp.enable", "true");
        // Activate CRLDP -- no idea what this is
        Security.setProperty("com.sun.security.enableCRLDP", "true");

        X509Certificate target = (X509Certificate) certPath.getCertificates().get(0);
        Security.setProperty("ocsp.responderURL","http://ocsp.pki.belgium.be/");
        Security.setProperty("ocsp.responderCertIssuerName", target.getIssuerX500Principal().getName());
        Security.setProperty("ocsp.responderCertSubjectName", target.getSubjectX500Principal().getName());
        Security.setProperty("ocsp.responderCertSerialNumber", target.getSerialNumber().toString(16));

Which gives an exception: java.security.cert.CertPathValidatorException: Cannot find the responder's certificate (set using the OCSP security properties).

这给出了一个例外:java.security.cert.CertPathValidatorException:找不到响应者的证书(使用 OCSP 安全属性设置)。

回答by Driss Amri

For future reference I'll post the answer to my own question (partly atleast)

为了将来参考,我将发布我自己问题的答案(至少部分)

OCSP and CRL checks are implemented in the standard Java implementation already and there is no need for custom code or other providers (BC, ..). They are disabled by default.

OCSP 和 CRL 检查已经在标准 Java 实现中实现,不需要自定义代码或其他提供程序(BC,..)。默认情况下它们是禁用的。

To enable this, you have to atleast set two parameters:

要启用此功能,您必须至少设置两个参数:

(PKIXParameters or PKIXParameterBuilder) params.setRevocationEnabled(true);
Security.setProperty("ocsp.enable", "true");

This will activate OCSP checking when you are trying to validate the certificate path (PKIXCertPathValidatorResult.validate()).

当您尝试验证证书路径 (PKIXCertPathValidatorResult.validate()) 时,这将激活 OCSP 检查。

When you want to add the fallback check for CRL if no OCSP is available, add an aditional property:

如果您想在没有 OCSP 可用的情况下为 CRL 添加回退检查,请添加一个附加属性:

System.setProperty("com.sun.security.enableCRLDP", "true");

A lot of my problems are happening due to the fact that I have to support different certificate formats (PKCS7, PEM). My implementation works fine for PEM, but since PKCS7 does NOT save ordering of the certificates in the chain it is a bit harder (http://bugs.sun.com/view_bug.do?bug_id=6238093)

由于我必须支持不同的证书格式(PKCS7、PEM),我的很多问题都发生了。我的实现适用于 PEM,但由于 PKCS7 不保存链中证书的顺序,所以有点难(http://bugs.sun.com/view_bug.do?bug_id=6238093

X509CertSelector targetConstraints = new X509CertSelector();

targetConstraints.setCertificate(certificates.get(0));
// Here's the issue for PKCS7 certificates since they are not ordered,
// but I havent figured out how I can see what the target certificate
// (lowest level) is in the incoming certificates..

PKIXBuilderParameters params = new PKIXBuilderParameters(anchors, targetConstraints);   

Hope this will be useful remarks for other people as well, perhaps someone can shed a light on how to find the target certificate in an unordered PKCS7 list?

希望这对其他人也有用,也许有人可以阐明如何在无序的 PKCS7 列表中找到目标证书?