在 Java 中验证 PKCS#7 证书
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3166159/
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
Verifying PKCS#7 certificates in Java
提问by hudolejev
Need some help with crypto routines in Java.
需要一些有关 Java 加密例程的帮助。
Given a PKCS#7 signature, I want to verify all certificates it contains against a trusted store. I assume that all certificates contained in signature are in the correct order to form a valid certificate path (or chain, whatever), so that
给定 PKCS#7 签名,我想根据受信任的存储验证它包含的所有证书。我假设签名中包含的所有证书都以正确的顺序形成有效的证书路径(或链,无论如何),以便
- topmost (#0) is a signing certificate;
- next one (#1) is an intermediate certificate, used to sign #0;
- next one (#2) is another intermediate certificate, used to sign #1;
- and so on.
- topmost (#0) 是签名证书;
- 下一个(#1)是中间证书,用于签署#0;
- 下一个(#2)是另一个中间证书,用于签署#1;
- 等等。
The last certificate (#N) is signed by CA.
最后一个证书 (#N) 由 CA 签署。
That's what I've managed to hack so far:
到目前为止,这就是我设法破解的:
// Exception handling skipped for readability
//byte[] signature = ...
pkcs7 = new PKCS7(signature); // `sun.security.pkcs.PKCS7;`
// *** Checking some PKCS#7 parameters here
X509Certificate prevCert = null; // Previous certificate we've found
X509Certificate[] certs = pkcs7.getCertificates(); // `java.security.cert.X509Certificate`
for (int i = 0; i < certs.length; i++) {
// *** Checking certificate validity period here
if (cert != null) {
// Verify previous certificate in chain against this one
prevCert.verify(certs[i].getPublicKey());
}
prevCert = certs[i];
}
//String keyStorePath = ...
KeyStore keyStore = KeyStore.getInstance("JKS"); // `java.security.KeyStore`
keyStore.load(new FileInputStream(keyStorePath), null);
// Get trusted VeriSign class 1 certificate
Certificate caCert = keyStore.getCertificate("verisignclass1ca"); // `java.security.cert.Certificate`
// Verify last certificate against trusted certificate
cert.verify(caCert.getPublicKey());
So the question is -- how can this be done using standard Java classes like CertPathand friends? I have a strong feeling I'm re-inventing a bicycle. Or, if someone has an example with BouncyCastle library, that would also be fine.
所以问题是——如何使用像CertPath朋友这样的标准 Java 类来做到这一点?我有一种强烈的感觉,我正在重新发明一辆自行车。或者,如果有人有 BouncyCastle 库的示例,那也很好。
Bonus question: how to verify a certificate against a trusted store so that root certificate is selected automatically?
额外问题:如何根据受信任的存储验证证书以便自动选择根证书?
回答by hudolejev
Found the solution myself. So, here's how one can extract and validate a certificate chain against the trusted store (exception handling skipped for readability):
自己找到了解决办法。因此,这里是如何针对受信任的存储提取和验证证书链(为了可读性而跳过异常处理):
CertificateFactory cf = CertificateFactory.getInstance("X.509");
// Get ContentInfo
//byte[] signature = ... // PKCS#7 signature bytes
InputStream signatureIn = new ByteArrayInputStream(signature);
DERObject obj = new ASN1InputStream(signatureIn).readObject();
ContentInfo contentInfo = ContentInfo.getInstance(obj);
// Extract certificates
SignedData signedData = SignedData.getInstance(contentInfo.getContent());
Enumeration certificates = signedData.getCertificates().getObjects();
// Build certificate path
List certList = new ArrayList();
while (certificates.hasMoreElements()) {
DERObject certObj = (DERObject) certificates.nextElement();
InputStream in = new ByteArrayInputStream(certObj.getDEREncoded());
certList.add(cf.generateCertificate(in));
}
CertPath certPath = cf.generateCertPath(certList);
// Load key store
//String keyStorePath = ...
KeyStore keyStore = KeyStore.getInstance("JKS");
keyStore.load(new FileInputStream(keyStorePath), null);
// Set validation parameters
PKIXParameters params = new PKIXParameters(keyStore);
params.setRevocationEnabled(false); // to avoid exception on empty CRL
// Validate certificate path
CertPathValidator validator = CertPathValidator.getInstance("PKIX");
CertPathValidatorResult result = validator.validate(certPath, params);
validate()will throw an exception if validation fails.
validate()如果验证失败将抛出异常。
Docs: ASN1Set, ContentInfo, SignedData. All other exotic names and related docs can be found in java.security.cert.
文档:ASN1Set, ContentInfo, SignedData. 所有其他外来名称和相关文档都可以在java.security.cert.
No SUN-dependencies here, only BouncyCastle provider libraryis needed.
这里没有 SUN 依赖,只需要BouncyCastle 提供程序库。
Thisquestion (and especially an answer) may help too.
这个问题(尤其是答案)也可能有所帮助。
回答by President James K. Polk
You want CertificateFactory. The last example in the javadocs do exactly what you want.
你想要CertificateFactory。javadocs 中的最后一个示例完全符合您的要求。

