Java 结合验证PKCS#7签名所需的所有任务
我已经为这个问题绞尽脑汁20个小时了,我可能错过了一些简单的事情。然而,我已经到了需要帮助的地步。我已经阅读了几十篇关于如何处理问题不同部分的解释,但我不知道如何将它们结合在一起 我有一个DER编码的PKCS#7数字签名。签名符合RFC 3852(加密消息语法)。对于我的项目,我需要一步一步地完成验证签名所需的每一个步骤,并能够判断验证失败的步骤。我正在Java中使用BouncyCastle 据我所知,验证数字签名需要六个基本步骤Java 结合验证PKCS#7签名所需的所有任务,java,cryptography,digital-signature,bouncycastle,Java,Cryptography,Digital Signature,Bouncycastle,我已经为这个问题绞尽脑汁20个小时了,我可能错过了一些简单的事情。然而,我已经到了需要帮助的地步。我已经阅读了几十篇关于如何处理问题不同部分的解释,但我不知道如何将它们结合在一起 我有一个DER编码的PKCS#7数字签名。签名符合RFC 3852(加密消息语法)。对于我的项目,我需要一步一步地完成验证签名所需的每一个步骤,并能够判断验证失败的步骤。我正在Java中使用BouncyCastle 据我所知,验证数字签名需要六个基本步骤 验证根证书是否为受信任的证书 验证从根证书到签名证书的证书链 验
CMSSignedData s = ...
byte[] contentDigest = ...
Store certStore = s.getCertificates();
Store crlStore = s.getCRLs();
SignerInformationStore signers = s.getSignerInfos();
Collection c = signers.getSigners();
Iterator it = c.iterator();
while (it.hasNext())
{
SignerInformation signer = (SignerInformation)it.next();
Collection certCollection = certStore.getMatches(signer.getSID());
Iterator certIt = certCollection.iterator();
X509CertificateHolder cert = (X509CertificateHolder)certIt.next();
assertEquals(true, signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider(BC).build(cert)));
if (contentDigest != null)
{
assertTrue(MessageDigest.isEqual(contentDigest, signer.getContentDigest()));
}
}
Collection certColl = certStore.getMatches(null);
Collection crlColl = crlStore.getMatches(null);
assertEquals(certColl.size(), s.getCertificates().getMatches(null).size());
assertEquals(crlColl.size(), s.getCRLs().getMatches(null).size());
CMS签名数据验证中最复杂的部分是X.509验证部分。对于签名数据中的每个签名者,步骤如下: 1。查找签名者证书
SignerInformation signerInfo = (SignerInformation)it.next();
Collection certCollection = certStore.getMatches(signerInfo.getSID());
Iterator certIt = certCollection.iterator();
X509CertificateHolder signerCertificateHolder = (X509CertificateHolder)certIt.next();
我假设这里只有一个匹配的证书
2。查找从签名者证书到受信任根证书的证书链
SignerInformation signerInfo = (SignerInformation)it.next();
Collection certCollection = certStore.getMatches(signerInfo.getSID());
Iterator certIt = certCollection.iterator();
X509CertificateHolder signerCertificateHolder = (X509CertificateHolder)certIt.next();
在这里,您要检查存储中的证书
,以查找证书链。使用主题DN/颁发者DN和主题密钥标识符/权限密钥标识符匹配项来构建该链
3。验证链
这一步是对链中的每个证书进行递归验证。对于每个证书,从根证书正下方的证书开始,您需要检查:
KeyStore trustAnchors = getTrustAnchors();
X509CertSelector target = new X509CertSelector();
target.setCertificate(signerCertificate);
PKIXBuilderParameters params = new PKIXBuilderParameters(anchors, target);
CertStoreParameters additionalCerts = new CollectionCertStoreParameters(allOtherCerts)
params.addCertStore(CertStore.getInstance("Collection", additionalCerts));
CertStoreParameters revocationObjects = new CollectionCertStoreParameters(allCRLs);
params.addCertStore(CertStore.getInstance("Collection", revocationObjects));
CertPathBuilder builder = CertPathBuilder.getInstance("PKIX");
PKIXCertPathBuilderResult r = (PKIXCertPathBuilderResult) builder.build(params);
/* if the build method returns without exception, the certificate chain is valid */
为了可读性,我省略了对象在java(x).crypto
和Bouncycastle类型之间的转换
4。使用公钥验证SignerInfo签名
JcaSimpleSignerInfoVerifierBuilder builder = new JcaSimpleSignerInfoVerifierBuilder();
SignerInformationVerifier verifier = builder.build(signerCertificateHolder);
assertTrue(signerInfo.verify(verifier));
5。验证文档摘要是否与签名摘要匹配
byte[] contentDigest = computeDigest(originalDoc, signerInfo.getDigestAlgOID());
assertArrayEquals(contentDigest, signer.getContentDigest());
将OCSP检查添加到列表中。如果要彻底检查,请将crl和OCSP响应签名的检查也添加到列表中。