2017-05-10 113 views
3

仍然是密码学中的一个小白我每天都会遇到简单的事情。今天只是其中的一个。从终端实体获取根证书和中间证书

我想用弹性城堡库在java中验证smime消息,我想我几乎已经知道了,但此时的问题是构建PKIXparameters对象。 比方说,我有以下结构的终端实体X509证书:

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

为了验证消息,我需要首先建立信任链,但我无法弄清楚如何提取的根和中级来自最终实体的证书。

我试图用终端实体根,但它没有工作:

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()); 
} 

得到这个异常:

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

而且顺便说一句,我就可以只使用终端实体证书来验证消息,就好像它是自签名证书一样?

回答

4

我用这个测试使用BouncyCastle 1.56

从最终实体获取发行人证书的一种方法是查找Authority Information Access extension

此扩展可以存在(它不是必须的),并可以包含的URL,以获得发行人的证书(发行者是证书“上方”的当前一个,所以终端实体的发行者是中间,而中间人的发行人是根)。

你可以用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()); 
     } 
    } 
} 

所以,你可以使用此代码与最终实体证书来获得中间。然后你再次使用它来获取根目录。

然后,您将添加到您的TrustAnchor,验证应起作用。


注:但正如我所说,这个扩展是不是强制性的,可能不存在。在这种情况下,getExtensionValue将返回null,而我知道唯一的选择是搜索在谷歌的证书和下载它们(那些证书链通常是公众和不难找)

+1

延长管理局信息访问是很常见的OCSP信息。但我想我从来没有见过这个包含id-ad-caIssuers的扩展的证书。无论如何,很好的答案。 – Egl

+0

@Egl我见过证书,包括id-ad-caIssuers和OCSP(google.com的证书和巴西的PKI最终实体都是很好的例子)。我也看过其中一个证书,不幸的是,似乎CA中没有标准。 –

+0

非常感谢您的回答!你帮了我很多! – revolt

1

顺便说一句,如果我们有出在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); 

热潮,整个证书链已准备就绪