验证签名时出错:SigningCertificate 属性 包含一个或多个不属于证书路径的证书
Error when verifying signature: SigningCertificate property contains one or more certificates that are not part of the certification path
我正在使用 xades4j 并且在尝试验证签名时遇到此异常:
xades4j.verification.SigningCertificateCertsNotInCertPathException: Verification failed for property 'SigningCertificate': SigningCertificate property contains one or more certificates that are not part of the certification path.
这是我要签名的代码:
public File sign(final X509Certificate x509, final PrivateKey priv, final Element elemToSign, final Document doc, final String fileName, final com.softexpert.crypto.document.Document document, List<X509Certificate> chain) throws Exception {
final KeyingDataProvider kp = new SEDirectKeyingDataProvider(x509, priv, chain);
XadesSigningProfile profile = new XadesBesSigningProfile(kp);
final SESignaturePropertiesProvider propProv = this.getPropertiesProvider(document);
profile = profile.withSignaturePropertiesProvider(propProv);
profile = profile.withAlgorithmsProvider(AlgorithmsProvider.class);
profile = profile.withTimeStampTokenProvider(TimeStampTokenProvider.class);
final SignerBES signer = (SignerBES) profile.newSigner();
final IndividualDataObjsTimeStampProperty dataObjsTimeStamp = new IndividualDataObjsTimeStampProperty();
final DataObjectDesc obj = new EnvelopedXmlObject(elemToSign.getFirstChild()).withDataObjectTimeStamp(dataObjsTimeStamp);
AllDataObjsCommitmentTypeProperty commitment = null;
if (document.isProofOfOrigin() != null && document.isProofOfOrigin()) {
commitment = AllDataObjsCommitmentTypeProperty.proofOfOrigin();
} else {
commitment = AllDataObjsCommitmentTypeProperty.proofOfReceipt();
}
SignedDataObjects dataObjs = new SignedDataObjects(obj).withCommitmentType(commitment);
dataObjs = dataObjs.withDataObjectsTimeStamp();
signer.sign(dataObjs, elemToSign);
return this.outputDocument(doc, fileName);
}
private SESignaturePropertiesProvider getPropertiesProvider(com.softexpert.crypto.document.Document document) {
SESignaturePropertiesProvider propertiesProvider = new SESignaturePropertiesProvider();
if (document.getRole() != null) {
final SignerRoleProperty signerRole = new SignerRoleProperty().withClaimedRole(document.getRole());
propertiesProvider.setSignerRole(signerRole);
}
final SigningTimeProperty signingTime = new SigningTimeProperty();
propertiesProvider.setSigningTime(signingTime);
if (document.getLocalityName() != null && document.getCountry() != null) {
final SignatureProductionPlaceProperty signatureProductionPlaceProperty = new SignatureProductionPlaceProperty(document.getLocalityName(), document.getCountry());
propertiesProvider.setSignatureProductionPlaceProperty(signatureProductionPlaceProperty);
}
return propertiesProvider;
}
private File outputDocument(final Document doc, String fileName) throws Exception {
if (!fileName.endsWith(".dsg")) {
fileName += ".dsg";
}
FileOutputStream out = null;
File f = null;
try {
final TransformerFactory tf = TransformerFactory.newInstance();
f = new File(fileName);
if (!f.exists()) {
new File(f.getParent()).mkdirs();
f.createNewFile();
}
out = new FileOutputStream(f);
tf.newTransformer().transform(new DOMSource(doc), new StreamResult(out));
} finally {
if(out != null) {
try {
out.close();
} catch(IOException e) {}
}
}
return f;
}
这是我要验证的代码:
try {
final org.w3c.dom.Document doc = this.getDomDocument();
doc.getDocumentElement().normalize();
// Find Signature element
final NodeList nl = doc.getElementsByTagNameNS(javax.xml.crypto.dsig.XMLSignature.XMLNS, "Signature");
final CertStore crls = ... // get CRLS
final CertStore certs = ... // get intermediate certs
final KeyStore ks = ... // get KS from Windows-ROOT
final PKIXCertificateValidationProvider cvp = new PKIXCertificateValidationProvider(ks, false, certs, crls);
final XadesVerificationProfile p = new XadesVerificationProfile(cvp);
p.withTimeStampTokenVerifier(SETimeStampTokenProvider.class);
final Element signatureElemntNode = (Element) nl.item(0);
final XadesVerifier verifier = p.newVerifier();
XAdESVerificationResult verificationResult = verifier.verify(signatureElemntNode, null); // exception is thrown here
}
我已经搜索过这个错误,但找不到任何帮助我的东西。我该如何解决这个错误?
提前致谢。
如错误消息所述,您的 SigningCertificate
属性 可能拥有不属于证书链的证书。此规则在 XAdES 规范中定义。
关于签名操作:
- 您 return 从您的自定义
SEDirectKeyingDataProvider
的 getSigningCertificateChain
方法获得什么证书?
SigningCertificate
属性 的最后 XML 的证书元素是什么?
returned 证书应该都是歌唱证书链的一部分,但您不需要 return 完整链。您甚至可以 return 一个仅包含签名证书的列表,只要您使所有中间证书都可用于验证(您似乎正在这样做)。如果这样做,SigningCertificate
属性 的验证应该通过。
基于,我对我的代码做了一点改动:
签名:我没有使用整个证书链进行签名,而是只使用了签名证书,因此 SEDirectKeyingDataProvider.getSigningCertificateChain()
returns 只有签名证书).通过这种方法,我的 xml 现在只有一个 属性 <SigningCertificate>
而不是整个链。
验证:使用我在上面评论过的方法,我在验证证书时遇到了问题:在我的 xml 中,仅引用了签名证书属性 <ds:X509Certificate>
,让我无法验证整条链。为了解决这个问题,我不得不在 after 调用 XAdESVerificationResult result = verifier.verify(signatureElemntNode, null);
:
后使用这段代码
for(X509Certificate cert : chain) {
result.getSignature().addKeyInfo(cert);
}
使用此代码,链的每个证书都由 属性 <ds:X509Certificate>
引用,我可以获得整个链以验证它是否值得信赖。
我正在使用 xades4j 并且在尝试验证签名时遇到此异常:
xades4j.verification.SigningCertificateCertsNotInCertPathException: Verification failed for property 'SigningCertificate': SigningCertificate property contains one or more certificates that are not part of the certification path.
这是我要签名的代码:
public File sign(final X509Certificate x509, final PrivateKey priv, final Element elemToSign, final Document doc, final String fileName, final com.softexpert.crypto.document.Document document, List<X509Certificate> chain) throws Exception {
final KeyingDataProvider kp = new SEDirectKeyingDataProvider(x509, priv, chain);
XadesSigningProfile profile = new XadesBesSigningProfile(kp);
final SESignaturePropertiesProvider propProv = this.getPropertiesProvider(document);
profile = profile.withSignaturePropertiesProvider(propProv);
profile = profile.withAlgorithmsProvider(AlgorithmsProvider.class);
profile = profile.withTimeStampTokenProvider(TimeStampTokenProvider.class);
final SignerBES signer = (SignerBES) profile.newSigner();
final IndividualDataObjsTimeStampProperty dataObjsTimeStamp = new IndividualDataObjsTimeStampProperty();
final DataObjectDesc obj = new EnvelopedXmlObject(elemToSign.getFirstChild()).withDataObjectTimeStamp(dataObjsTimeStamp);
AllDataObjsCommitmentTypeProperty commitment = null;
if (document.isProofOfOrigin() != null && document.isProofOfOrigin()) {
commitment = AllDataObjsCommitmentTypeProperty.proofOfOrigin();
} else {
commitment = AllDataObjsCommitmentTypeProperty.proofOfReceipt();
}
SignedDataObjects dataObjs = new SignedDataObjects(obj).withCommitmentType(commitment);
dataObjs = dataObjs.withDataObjectsTimeStamp();
signer.sign(dataObjs, elemToSign);
return this.outputDocument(doc, fileName);
}
private SESignaturePropertiesProvider getPropertiesProvider(com.softexpert.crypto.document.Document document) {
SESignaturePropertiesProvider propertiesProvider = new SESignaturePropertiesProvider();
if (document.getRole() != null) {
final SignerRoleProperty signerRole = new SignerRoleProperty().withClaimedRole(document.getRole());
propertiesProvider.setSignerRole(signerRole);
}
final SigningTimeProperty signingTime = new SigningTimeProperty();
propertiesProvider.setSigningTime(signingTime);
if (document.getLocalityName() != null && document.getCountry() != null) {
final SignatureProductionPlaceProperty signatureProductionPlaceProperty = new SignatureProductionPlaceProperty(document.getLocalityName(), document.getCountry());
propertiesProvider.setSignatureProductionPlaceProperty(signatureProductionPlaceProperty);
}
return propertiesProvider;
}
private File outputDocument(final Document doc, String fileName) throws Exception {
if (!fileName.endsWith(".dsg")) {
fileName += ".dsg";
}
FileOutputStream out = null;
File f = null;
try {
final TransformerFactory tf = TransformerFactory.newInstance();
f = new File(fileName);
if (!f.exists()) {
new File(f.getParent()).mkdirs();
f.createNewFile();
}
out = new FileOutputStream(f);
tf.newTransformer().transform(new DOMSource(doc), new StreamResult(out));
} finally {
if(out != null) {
try {
out.close();
} catch(IOException e) {}
}
}
return f;
}
这是我要验证的代码:
try {
final org.w3c.dom.Document doc = this.getDomDocument();
doc.getDocumentElement().normalize();
// Find Signature element
final NodeList nl = doc.getElementsByTagNameNS(javax.xml.crypto.dsig.XMLSignature.XMLNS, "Signature");
final CertStore crls = ... // get CRLS
final CertStore certs = ... // get intermediate certs
final KeyStore ks = ... // get KS from Windows-ROOT
final PKIXCertificateValidationProvider cvp = new PKIXCertificateValidationProvider(ks, false, certs, crls);
final XadesVerificationProfile p = new XadesVerificationProfile(cvp);
p.withTimeStampTokenVerifier(SETimeStampTokenProvider.class);
final Element signatureElemntNode = (Element) nl.item(0);
final XadesVerifier verifier = p.newVerifier();
XAdESVerificationResult verificationResult = verifier.verify(signatureElemntNode, null); // exception is thrown here
}
我已经搜索过这个错误,但找不到任何帮助我的东西。我该如何解决这个错误?
提前致谢。
如错误消息所述,您的 SigningCertificate
属性 可能拥有不属于证书链的证书。此规则在 XAdES 规范中定义。
关于签名操作:
- 您 return 从您的自定义
SEDirectKeyingDataProvider
的getSigningCertificateChain
方法获得什么证书? SigningCertificate
属性 的最后 XML 的证书元素是什么?
returned 证书应该都是歌唱证书链的一部分,但您不需要 return 完整链。您甚至可以 return 一个仅包含签名证书的列表,只要您使所有中间证书都可用于验证(您似乎正在这样做)。如果这样做,SigningCertificate
属性 的验证应该通过。
基于
签名:我没有使用整个证书链进行签名,而是只使用了签名证书,因此 SEDirectKeyingDataProvider.getSigningCertificateChain()
returns 只有签名证书).通过这种方法,我的 xml 现在只有一个 属性 <SigningCertificate>
而不是整个链。
验证:使用我在上面评论过的方法,我在验证证书时遇到了问题:在我的 xml 中,仅引用了签名证书属性 <ds:X509Certificate>
,让我无法验证整条链。为了解决这个问题,我不得不在 after 调用 XAdESVerificationResult result = verifier.verify(signatureElemntNode, null);
:
for(X509Certificate cert : chain) {
result.getSignature().addKeyInfo(cert);
}
使用此代码,链的每个证书都由 属性 <ds:X509Certificate>
引用,我可以获得整个链以验证它是否值得信赖。