简体   繁体   English

从终端实体获取根证书和中间证书

[英]Getting root and intermediate certificates from an end-entity

still being a noob in cryptography I stumble upon simple things every day. 我仍然是密码学的一个菜鸟我每天偶然发现简单的事情。 And today is just one of those days. 而今天只是其中的一天。

I want to validate smime messages in java with the bouncy castle library, and I think I almost figured it out, but the problem at this moment is the building of the PKIXparameters object. 我想用弹性城堡库验证java中的smime消息,我想我几乎把它想出来了,但此时的问题是构建PKIXparameters对象。 Let's say, I have an end-entity x509certificate with the following structure: 比方说,我有一个具有以下结构的终端实体x509certificate:

root certificate
 +->intermediate certificate
    +->end-entity certificate

In order to validate message I need to build a chain of trust first, but I cannot figure out how to extract a root and intermediate certificates from the end-entity. 为了验证消息,我需要首先建立一个信任链,但我无法弄清楚如何从最终实体中提取根证书和中间证书。

I tried to use end-entity as root but it didn't work: 我试图以root身份使用end-entity,但它不起作用:

InputStream isCert = GetFISCertificate();

List list = new ArrayList();
X509Certificate rootCert = (X509Certificate) certificateFactory.generateCertificate(isCert);
list.add(rootCert);
CollectionCertStoreParameters params = new CollectionCertStoreParameters(list);
CertStore store = CertStore.getInstance("Collection", params, BC);

//create cert path
List certChain = new ArrayList();
certChain.add(rootCert);
CertPath certPath = certificateFactory.generateCertPath(certChain);
Set trust = Collections.singleton(new TrustAnchor(rootCert, null));

//validation
CertPathValidator certPathValidator = CertPathValidator.getInstance("PKIX", BC);
PKIXParameters pKIXParameters = new PKIXParameters(trust);
pKIXParameters.addCertStore(store);
pKIXParameters.setDate(new Date());
try {
CertPathValidatorResult result = certPathValidator.validate(certPath, pKIXParameters);
System.out.println("certificate path validated");

} catch (CertPathValidatorException e) {
System.out.println("validation failed on certificate number " + e.getIndex() + ", details: " + e.getMessage());
}

Got this exception: 得到这个例外:

validation failed on certificate number -1, details: Trust anchor for certification path not found.

And btw, can I just use only the end-entity certificate to validate messages, as if it were the self-signed certificate? 顺便说一句,我可以只使用最终实体证书来验证消息,就好像它是自签名证书一样吗?

I've used BouncyCastle 1.56 for this test. 我已经使用BouncyCastle 1.56进行此测试。

One way to get the issuer's certificate from the end entity is to look for the Authority Information Access extension . 从终端实体获取颁发者证书的一种方法是查找授权信息访问扩展

This extension may be present (it's not mandatory) and may contain the URL to get the issuer's certificate ( issuer is the certificate "above" the current one, so the end entity's issuer is the intermediate, and the intermediate's issuer is the root). 此扩展可能存在(它不是强制性的)并且可能包含获取颁发者证书的URL( 发行者是“当前”以上的证书,因此最终实体的发行者是中间人,中间人的发行者是根证书)。

You can get this extension value with BouncyCastle: 您可以使用BouncyCastle获取此扩展值:

import java.security.cert.X509Certificate;
import org.bouncycastle.asn1.x509.AccessDescription;
import org.bouncycastle.asn1.x509.AuthorityInformationAccess;
import org.bouncycastle.asn1.x509.Extension;
import org.bouncycastle.asn1.x509.GeneralName;
import org.bouncycastle.asn1.x509.X509ObjectIdentifiers;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.x509.extension.X509ExtensionUtil;

X509Certificate cert = // end entity certificate

// get Authority Information Access extension (will be null if extension is not present)
byte[] extVal = cert.getExtensionValue(Extension.authorityInfoAccess.getId());
AuthorityInformationAccess aia = AuthorityInformationAccess.getInstance(X509ExtensionUtil.fromExtensionValue(extVal));

// check if there is a URL to issuer's certificate
AccessDescription[] descriptions = aia.getAccessDescriptions();
for (AccessDescription ad : descriptions) {
    // check if it's a URL to issuer's certificate
    if (ad.getAccessMethod().equals(X509ObjectIdentifiers.id_ad_caIssuers)) {
        GeneralName location = ad.getAccessLocation();
        if (location.getTagNo() == GeneralName.uniformResourceIdentifier) {
            String issuerUrl = location.getName().toString();
            // http URL to issuer (test in your browser to see if it's a valid certificate)
            // you can use java.net.URL.openStream() to create a InputStream and create
            // the certificate with your CertificateFactory
            URL url = new URL(issuerUrl);
            X509Certificate issuer = (X509Certificate) certificateFactory.generateCertificate(url.openStream());
        }
    }
}

So you can use this code with the end entity certificate to get the intermediate. 因此,您可以将此代码与最终实体证书一起使用以获取中间体。 Then you use it again with the intermediate to get the root. 然后再用中间体来获取根。

Then you add the root to your TrustAnchor and the validation should work. 然后将添加到TrustAnchor ,验证应该有效。


Note: But as I said, this extension is not mandatory and may not be present. 注意:但正如我所说,此扩展名不是强制性的,可能不存在。 In this case, getExtensionValue will return null , and the only alternative that I know is to search for the certificates in google and download them (those certificate chains are usually public and not hard to find) 在这种情况下, getExtensionValue将返回null ,我知道的唯一替代方法是在google中搜索证书并下载它们(这些证书链通常是公共的,不难找到)

btw, if we have out certificate installed in windows, everything is much simpler: 顺便说一句,如果我们在Windows中安装了证书,一切都会简单得多:

KeyStore ks = KeyStore.getInstance("Windows-MY");
ks.load(null, null);
String alias = "your alias";
ArrayList<X509Certificate> certsChain = new ArrayList<>();
if (ks.isCertificateEntry(alias)) {
    Certificate[] chain = ks.getCertificateChain(alias);
    System.out.println("Chain length: " + chain.length);
        for(Certificate c : chain) certsChain.add((X509Certificate)c);
}

Collections.reverse(certsChain);
certsChain.forEach(MainClass::printDBG);

boom, and the whole certificates chain is ready 繁荣,整个证书链已准备就绪

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM