我正在使用Xades4J开发一个简单的Java程序,该程序使用XADES签名和验证XML。签名过程似乎工作正常,并生成一个有效的签名XML (尽管我们不需要它上的SignaturePolicyIdentifier部分)。
*选项参数是从joptsimple到解析参数的
这是我的符号功能:
void signXML(OptionSet选项){
KeyingDataProvider kp;try { SignaturePolicyInfoProvider policyInfoProvider = new SignaturePolicyInfoProvider() { public SignaturePolicyBase getSignaturePolicy() { return new SignaturePolicyIdentifierProperty( new ObjectIdentifier("oid:/1.2.4.0.9.4.5", IdentifierType.OIDAsURI, "Policy description"), new ByteArrayInputStream("Test policy input stream".getBytes())) .withLocationUrl("http://www.example.com/policy"); } }; kp = new FileSystemKeyStoreKeyingDataProvider("pkcs12", options.valueOf("certificate").toString(), new FirstCertificateSelector(), new DirectPasswordProvider(options.valueOf("password").toString()), new DirectPasswordProvider(options.valueOf("password").toString()), false); // SignaturePolicyInfoProvider spi = new XadesSigningProfile p = new XadesEpesSigningProfile(kp, policyInfoProvider); p.withBasicSignatureOptionsProvider(new SignatureOptionsProvider()); XadesSigner signer = p.newSigner(); // open file DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setNamespaceAware(true); DocumentBuilder builder = null; builder = factory.newDocumentBuilder(); Document doc1 = builder.parse(new File(options.valueOf("input").toString())); Element elemToSign = doc1.getDocumentElement(); // sign whole document new Enveloped(signer).sign(elemToSign); // save output file Transformer transformer = TransformerFactory.newInstance().newTransformer(); Result output = new StreamResult(new File(options.valueOf("output").toString())); Source input = new DOMSource(doc1); transformer.transform(input, output);} catch (KeyStoreException | ParserConfigurationException | SAXException | IOException | XAdES4jException | TransformerException e) { e.printStackTrace();}}
This is a sample signature that it creates: (Is it normal to have 在base64值的每一行末尾?)
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="xmldsig-f5700b65-334e-4905-96f6-ca6156139686">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
<ds:Reference Id="xmldsig-f5700b65-334e-4905-96f6-ca6156139686-ref0" URI="">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<ds:DigestValue>h20v8PSCwU5ymBKMj5o8scN3FyMfGCmN8OA2bnRHTnI=</ds:DigestValue>
</ds:Reference>
<ds:Reference Type="http://uri.etsi.org/01903#SignedProperties" URI="#xmldsig-f5700b65-334e-4905-96f6-ca6156139686-signedprops">
<ds:Transforms>
<ds:Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
<ds:DigestValue>tEyMfk39qnevJRyLbxQJIGpEBJuCcYRSZNNjm7HfaaA=</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue Id="xmldsig-f5700b65-334e-4905-96f6-ca6156139686-sigvalue">
ZhdQPEz7KwYoLTc72rxqUN2rlMfRGmqHd0MVSEeHRf/kmoqAGAqit5tw6k9k8oFCyuPDS/+DoXHJ
rooMDEMr+cuvbwwDwy77kHT+8JeUuIAamyqP/OByLytxXm/oKHVAraMhHNsGHvhcsYzULHl+n6JB
fhsYeR6rZdksS+QkgeUYohEktodl20/kyug4ymZjbJ7rCtH6+nRRR1nqc8oVT2ZpgfEaPHqWO06V
QURYYkuQEPOsNgFUu+YiWAX9pz94tlsOlLu6efBUP4lDZbCSq75J7nVZonmTbj/+mPl/oxpLCAgG
utWpL1RwyWn454G+Rd/AG3+MLWnbPVVSWUTcNK2gv4S2MVmosGxBnKwA71Zu30S+KaDwoktzZ62X
ViDLMmf6YbTKhiCIZYdjXPXr9QwSOHr+2B5GNUwo/CoOENJY/sXNHiHXxw+d+cyoowN4faJoVb5C
YFT7DACHyRd/d6TGdVEviHToTak+xPIK0HGnLvmkqzpICX8SFuMybur5Tttex4hqJNmXI7XbI9pk
YGLESBvKmzp4O9wLTJdABsLLxZSwU1plagu+5nb8ujIzmngVEHx4yBRprRVr3cBrHKoQBOHAiaGQ
96qUVTFogIX3vxN/1Q8xKDfB99FlzDdqnc2SW5lgYHnkuHHStJhoaCKRraUWVtU1miT/gMES+YM=
</ds:SignatureValue>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate>
MIIFgTCCA2mgAwIBAgIJAPzDOBvbJQYvMA0GCSqGSIb3DQEBCwUAMFcxCzAJBgNVBAYTAkFVMRMw
EQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxEDAO
BgNVBAMMB1Fwcm90ZXgwHhcNMTcxMTI5MDIwMjIyWhcNMTgxMTI5MDIwMjIyWjBXMQswCQYDVQQG
EwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQdHkg
THRkMRAwDgYDVQQDDAdRcHJvdGV4MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAt1+k
sAGGc1kvhs3AjTfIyBRRBb3sB5C+IlGplS1lOpViUsYOZKT/t0u1PWTxWnTNYpEChSg4ECnbaNje
nuyIQct5AS+MMMD2R8SSGGfvlhwr/yypEzcIfsOjFMhnV95Kto0abqLDucOyZotZfbaQQcwK7ATI
/TrumoUX6lRaryeIYBhENRCvmTjcR3ecinL+FSEpEOdXSh0jtHRtoV/HCzHdgNvXXLPD2YkyjY/0
D9rvHmVmKXtRfnLsiNcc2vMuE0XlfBz/WbP+lOpMKpka5F7ocnDeMJ2Tb24tL60M+DS7IYWOJ4wm
Vpb9FsBI3mDZ1AndsTIp5lljLIT7CVvgIvIbCxlOx6vcRxjOhpzNLmCJuMuI2dLtg5qn6q4QoLrE
6LAQZ8Zt9ljK2s33Vc84FZi+nZx6A1enTnLyHjds6BdrzvKLOJeUtLlTbufxNrkQzWSIhI2ZbfhY
Mn4yC1REj4kH30AKD6YkN028TasJDnv30g9n9eSbZ0fq2buT2DawGAA9GP02daaaOyTmBVJMonpi
xSD7lN7iR3zvDUxtjIoOi15XZw+2k28VqkwVdOwo3xkz5zVhSxm7Xv1NHdiUO2AUzvWMdBNMTS2t
0rr31B232UQvuqDHW1ws6em1iA+Lu1X3Z59Mer6Hg2mVclNKSBrYxUSwSv9poZqxXlGH6R0CAwEA
AaNQME4wHQYDVR0OBBYEFNG3ss8QEfGFgyxHpb54iRRNz9BDMB8GA1UdIwQYMBaAFNG3ss8QEfGF
gyxHpb54iRRNz9BDMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggIBACuhTI0prkRc15OI
HGQq+xhHRfbnG3dUEaXuAYhyDbrRXz2urEjIf2vGPIn7hheOrScSbQgblHq/tV1nQTyRsyHCvZlV
aE2+OWCfrQDdrwZKE2N2xC1ALgGTtF+I4lXgy6/9OzNVFnV0oZUnO6PN5cH6SVy+RHpO9Lsr5ndI
YBSuu0Zd7/IsOYY/vWcfJjq3+SnRotgGj0Jf4F7SH74XPz0QkoVKM1z3zGlbF/w8OzJw71yRVkaX
Ld+TDFC6jDFV+kjQ1k8pa4Hjs2Yko2AmNmpOZmMVjRLTdGLdSU/Gt1ewDp5TsEa2y/5u2PcZY/fd
dNaMyH7Qx0SmqvYvgG0C3mSGhhFv6++SaXXmo1lQCDgY9OK975KnQPSIHXeuK7oh/82a2ZhmQau0
B/ISxrjtRJbSHByLefJAkJpRVGowa14Nq/jI/Dvl46LVepTq2eNxbbMmbaW60HMwDS+YfNIwRpRS
n/W1/7mWLQRRP0Mb1/fjZlIZBV83fynZU5BSsoW+LZ8EWXt+VhtC8SWZ3m3ffk3KKqZDKJTih5c1
IFz2veIrHZH6O9n3taU+mVuNC8piuG+GBCBPo7dQwFmGo2zZ9BvSqUdytLniuej1PcPBTkcxfhCN
h5lKWwZCNE5v8RlEd9RbjEC5nAm8kCVvHX5SZivd77Yum8eBMAUQ++M2oNfz
</ds:X509Certificate>
<ds:X509SubjectName>CN=Qprotex,O=Internet Widgits Pty Ltd,ST=Some-State,C=AU</ds:X509SubjectName>
<ds:X509IssuerSerial>
<ds:X509IssuerName>CN=Qprotex,O=Internet Widgits Pty Ltd,ST=Some-State,C=AU</ds:X509IssuerName>
<ds:X509SerialNumber>18213463010308326959</ds:X509SerialNumber>
</ds:X509IssuerSerial>
</ds:X509Data>
<ds:KeyValue>
<ds:RSAKeyValue>
<ds:Modulus>
t1+ksAGGc1kvhs3AjTfIyBRRBb3sB5C+IlGplS1lOpViUsYOZKT/t0u1PWTxWnTNYpEChSg4ECnb
aNjenuyIQct5AS+MMMD2R8SSGGfvlhwr/yypEzcIfsOjFMhnV95Kto0abqLDucOyZotZfbaQQcwK
7ATI/TrumoUX6lRaryeIYBhENRCvmTjcR3ecinL+FSEpEOdXSh0jtHRtoV/HCzHdgNvXXLPD2Yky
jY/0D9rvHmVmKXtRfnLsiNcc2vMuE0XlfBz/WbP+lOpMKpka5F7ocnDeMJ2Tb24tL60M+DS7IYWO
J4wmVpb9FsBI3mDZ1AndsTIp5lljLIT7CVvgIvIbCxlOx6vcRxjOhpzNLmCJuMuI2dLtg5qn6q4Q
oLrE6LAQZ8Zt9ljK2s33Vc84FZi+nZx6A1enTnLyHjds6BdrzvKLOJeUtLlTbufxNrkQzWSIhI2Z
bfhYMn4yC1REj4kH30AKD6YkN028TasJDnv30g9n9eSbZ0fq2buT2DawGAA9GP02daaaOyTmBVJM
onpixSD7lN7iR3zvDUxtjIoOi15XZw+2k28VqkwVdOwo3xkz5zVhSxm7Xv1NHdiUO2AUzvWMdBNM
TS2t0rr31B232UQvuqDHW1ws6em1iA+Lu1X3Z59Mer6Hg2mVclNKSBrYxUSwSv9poZqxXlGH6R0=
</ds:Modulus>
<ds:Exponent>AQAB</ds:Exponent>
</ds:RSAKeyValue>
</ds:KeyValue>
</ds:KeyInfo>
<ds:Object><xades:QualifyingProperties xmlns:xades="http://uri.etsi.org/01903/v1.3.2#" xmlns:xades141="http://uri.etsi.org/01903/v1.4.1#" Target="#xmldsig-f5700b65-334e-4905-96f6-ca6156139686"><xades:SignedProperties Id="xmldsig-f5700b65-334e-4905-96f6-ca6156139686-signedprops"><xades:SignedSignatureProperties><xades:SigningTime>2017-11-30T20:58:18.009-05:00</xades:SigningTime><xades:SigningCertificate><xades:Cert><xades:CertDigest><ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><ds:DigestValue>JkEubWWYvvoh7kOnuAvYeXE4cFamHJ5FOBYt3b3dCj4=</ds:DigestValue></xades:CertDigest><xades:IssuerSerial><ds:X509IssuerName>CN=Qprotex,O=Internet Widgits Pty Ltd,ST=Some-State,C=AU</ds:X509IssuerName><ds:X509SerialNumber>18213463010308326959</ds:X509SerialNumber></xades:IssuerSerial></xades:Cert></xades:SigningCertificate><xades:SignaturePolicyIdentifier><xades:SignaturePolicyId><xades:SigPolicyId><xades:Identifier Qualifier="OIDAsURI">oid:/1.2.4.0.9.4.5</xades:Identifier><xades:Description>Policy description</xades:Description></xades:SigPolicyId><xades:SigPolicyHash><ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/><ds:DigestValue>MaW9PDxJruPHhjBVAMWyrF9zP+kMnNqkoQOUXxDDGAk=</ds:DigestValue></xades:SigPolicyHash><xades:SigPolicyQualifiers><xades:SigPolicyQualifier><xades:SPURI>http://www.example.com/policy</xades:SPURI></xades:SigPolicyQualifier></xades:SigPolicyQualifiers></xades:SignaturePolicyId></xades:SignaturePolicyIdentifier></xades:SignedSignatureProperties></xades:SignedProperties></xades:QualifyingProperties></ds:Object>
</ds:Signature>这是我打印不良XML签名的验证代码。
void verifyXML(OptionSet options) {
try {
File file = new File(options.valueOf("certificate").toString());
FileSystemDirectoryCertStore store = new FileSystemDirectoryCertStore(file.getAbsoluteFile().getParent());
FileInputStream fis = new FileInputStream(options.valueOf("certificate").toString());
KeyStore ks = KeyStore.getInstance("pkcs12");
ks.load(fis, options.valueOf("password").toString().toCharArray());
fis.close();
CertificateValidationProvider provider = new PKIXCertificateValidationProvider(ks, false, store.getStore());
XadesVerifier verifier = new XadesVerificationProfile(provider).newVerifier();
Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new File(options.valueOf("input").toString()));
doc.getDocumentElement().normalize();
Element sig = (Element)doc.getElementsByTagName("ds:Signature").item(0);
PrintWriter out = null;
try {
out = new PrintWriter(options.valueOf("output").toString());
XAdESVerificationResult result = verifier.verify(sig, null);
out.println("true");
} catch (Exception e) {
System.out.println(e.getMessage());
out.println("false");
}
out.close();
} catch (Exception ex) {
System.err.println("Error: " + ex.getMessage());
}如果有人能告诉我问题可能在哪里,我将不胜感激。谢谢!
UPDATE在我检查堆栈跟踪之后发现了以下异常:
xades4j.xml.unmarshalling.UnmarshalException: Bad XML signature
at xades4j.verification.XadesVerifierImpl.verify(XadesVerifierImpl.java:130)
at com.qprotex.Main.verifyXML(Main.java:190)
at com.qprotex.Main.<init>(Main.java:99)
at com.qprotex.Main.main(Main.java:81)
Caused by: org.apache.xml.security.exceptions.XMLSecurityException: Cannot create a null:null from a http://www.w3.org/2000/09/xmldsig#:Signature element我找到了提到相同错误的这个职位,在验证方法中启用factory.setNamespaceAware(true)之后,我得到以下异常:
java.lang.NullPointerException
at xades4j.xml.unmarshalling.FromXmlSignaturePolicyConverter.getLocationUrl(FromXmlSignaturePolicyConverter.java:71)
at xades4j.xml.unmarshalling.FromXmlSignaturePolicyConverter.convertFromObjectTree(FromXmlSignaturePolicyConverter.java:64)
at xades4j.xml.unmarshalling.FromXmlSignaturePolicyConverter.convertFromObjectTree(FromXmlSignaturePolicyConverter.java:1)
at xades4j.xml.unmarshalling.UnmarshallerModule.convertProperties(UnmarshallerModule.java:64)
at xades4j.xml.unmarshalling.DefaultQualifyingPropertiesUnmarshaller.unmarshalProperties(DefaultQualifyingPropertiesUnmarshaller.java:83)
at xades4j.verification.XadesVerifierImpl.verify(XadesVerifierImpl.java:175)
at com.qprotex.Main.verifyXML(Main.java:190)
at com.qprotex.Main.<init>(Main.java:99)
at com.qprotex.Main.main(Main.java:81)UPDATE 2,因为我没有使用SignaturePolicyIdentifier,所以我更改了符号函数,改为使用XadesBesSigningProfile而不是XadesEpesSigningProfile。我现在唯一的问题是,只有当我使用KeyStore.getInstance(“Windows”)时,它才能工作。
这样做是可行的:
KeyStore trustAnchors = KeyStore.getInstance("Windows-ROOT");
trustAnchors.load(null);
CertificateValidationProvider provider = new PKIXCertificateValidationProvider(trustAnchors, false);但是这不起作用,我得到了一个"xades4j.providers.CannotBuildCertificationPathException:信任锚,KeyStore没有可信的证书条目“异常”。
FileInputStream fis = new FileInputStream(options.valueOf("certificate").toString());
KeyStore ks = KeyStore.getInstance("pkcs12");
ks.load(fis, options.valueOf("password").toString().toCharArray());
fis.close();
CertificateValidationProvider provider = new PKIXCertificateValidationProvider(ks, false);发布于 2017-12-03 12:36:08
SignaturePolicyIdentifier,你为什么要使用XAdES?您可以使用XadesBesSigningProfile代替,并生成XAdES-BES签名。withPolicyDocumentProvider在XadesVerificationProfile上进行验证。更新后2:
异常信息似乎很清楚。您的目标也是使用签名证书作为信任锚?keystore上条目的类型需要是“信任锚”。我想您应该添加两个条目:一个带有cert/key (键入“证书”),另一个只有证书(键入“信任锚”)。或者使用单独的密钥存储库。
https://stackoverflow.com/questions/47585633
复制相似问题