2017-05-10 162 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); 

熱潮,整個證書鏈已準備就緒