Ich habe ein Problem, wo ich XML-Dokument signieren und Unterschrift danach validieren und die Validierung vergeht, aber wenn ich Dokument in Byte-Array serialisieren und dann wieder zur Dokument-, Signaturvalidierung deserialisieren schlägt fehl.Xml Dokumentsignatur nicht gültig nach Deserialisierung von Bytearray
Hier sind Methoden zur Validierung und Serialisierung/Deserialisierung:
public class DocumentSigner {
@Override
public byte[] transformToByteArray(Document doc) throws Exception {
TransformerFactory transformerFactory = TransformerFactory
.newInstance();
Transformer transformer = transformerFactory.newTransformer();
ByteArrayOutputStream os = new ByteArrayOutputStream();
transformer.transform(new DOMSource(doc), new StreamResult(os));
return os.toByteArray();
}
private Document byteArrayToXmlDoc(byte[] documentoXml) throws Exception {
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
factory.setIgnoringElementContentWhitespace(true);
DocumentBuilder builder = factory.newDocumentBuilder();
return builder.parse(new ByteArrayInputStream(documentoXml), "UTF-8");
}
@Override
public Boolean validate(byte[] byteArrayDoc, Integer certificatePropertiesId) throws Exception {
Document doc = byteArrayToXmlDoc(byteArrayDoc);
return validate(doc, certificatePropertiesId);
}
public Boolean validate(Document doc, Integer certificatePropertiesId) throws Exception {
NodeList nl = doc.getElementsByTagNameNS(XMLSignature.XMLNS,
"Signature");
if (nl.getLength() == 0) {
throw new Exception("No signature element.");
}
KeyStore ks = KeyStore.getInstance("JKS");
CertificatePropertiesDTO certProp = databaseLogic.getCertificateProperties(certificatePropertiesId);
if (certProp == null || certProp.getCertificatePassword().isEmpty() || certProp.getCertificate() == null){
throw new RuntimeException("No certificate.");
}
ks.load(new ByteArrayInputStream(certProp.getCertificate()), certProp.getCertificatePassword().toCharArray());
KeyStore.PrivateKeyEntry keyEntry = (KeyStore.PrivateKeyEntry) ks.getEntry(ks.aliases().nextElement(), new KeyStore.PasswordProtection(certProp.getCertificatePassword().toCharArray()));
X509Certificate[] certs = (X509Certificate[]) keyEntry.getCertificateChain();
if (certs == null || certs.length == 0) {
throw new RuntimeException("No certificate found.");
}
XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");
DOMValidateContext valContext = new DOMValidateContext(keyEntry.getCertificate().getPublicKey(), nl.item(0));
NodeList els = doc.getElementsByTagNameNS("*", "SignatureProperties");
Element el = (Element) els.item(0);
valContext.setIdAttributeNS(el, null, "Id");
valContext.setDefaultNamespacePrefix("dsig");
valContext.setProperty("javax.xml.crypto.dsig.cacheReference", Boolean.TRUE);
try {
XMLSignature signature2 = fac
.unmarshalXMLSignature(new DOMStructure(nl.item(0)));
boolean coreValidity = signature2.validate(valContext);
// Check core validation status.
if (coreValidity == false) {
log.info("Signature failed core validation");
boolean sv = signature2.getSignatureValue()
.validate(valContext);
log.info("signature validation status: " + sv);
Iterator<?> i = signature2.getSignedInfo().getReferences()
.iterator();
for (int j = 0; i.hasNext(); j++) {
Reference ref = (Reference) i.next();
boolean refValid = ref.validate(valContext);
log.info("ref[" + j + "] validity status: " + refValid);
}
return false;
} else {
log.info("Signature passed core validation");
return true;
}
} catch (Exception ex) {
log.info("EXCEPTION during validation: " + ex.getMessage());
return false;
}
}
public void signDocument(Document doc)
{
....
}
public void writeToDisk(String path, String rac)
{
BufferedWriter writer = null;
try
{
writer = new BufferedWriter(new FileWriter(path));
writer.write(rac);
}
catch (IOException e)
{
}
finally
{
try
{
if (writer != null)
writer.close();
}
catch (IOException e)
{
try {
throw e;
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
}
@Override
public String transformToString(Document doc,
Boolean omitXmlDeclaration) throws Exception {
TransformerFactory transformerFactory = TransformerFactory
.newInstance();
//transformerFactory.setAttribute("indent-number", 4);
Transformer transformer = transformerFactory.newTransformer();
if (omitXmlDeclaration)
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION,
"yes");
// transformer.setOutputProperty(OutputKeys.INDENT, "yes");
// transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
//
StringWriter sw = new StringWriter();
transformer.transform(new DOMSource(doc), new StreamResult(sw));
//String output = sw.getBuffer().toString().replaceAll("\n|\r", "");
return sw.toString();
}
}
Hier ist, wo es geht/versagt:
public void SignAndValidate()
{
...
Document doc = createDocument();
documentSigner.signDocument(doc);
validate(doc, 1);
// OUTPUT:
// Signature passed core validation
byte[] docArr = documentSigner.transformToByteArray(doc);
validate(docArr, 1);
// OUTPUT:
// Signature failed core validation
// signature validation status: false
// ref[0] validity status: false
// ref[1] validity status: true
}
Bei Bedarf I Methoden für die Erstellung/Unterzeichnung Belegs wird aber es ist groß. Hier
ist die Unterzeichnung Methode:
Hier ist ein Teil der Probe XML-Dokument ist, die signiert ist:
<ext:UBLExtension>
<ext:ExtensionContent>
<sig:UBLDocumentSignatures>
<sac:SignatureInformation>
<dsig:Signature xmlns:dsig="http://www.w3.org/2000/09/xmldsig#" Id="data_signature">
<dsig:SignedInfo>
<dsig:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#WithComments"/>
<dsig:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
<dsig:Reference Type="http://www.w3.org/2000/09/xmldsig#SignatureProperties" URI="#idfe5688f4-583f-4a98-b26c-9d651b2f8918">
<dsig:Transforms>
<dsig:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#WithComments"/>
</dsig:Transforms>
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<dsig:DigestValue>iq802IBHl5kVdIMWA5Wlb5hYEoY=</dsig:DigestValue>
</dsig:Reference>
<dsig:Reference URI="">
<dsig:Transforms>
<dsig:Transform Algorithm="http://www.w3.org/2002/06/xmldsig-filter2">
<dsig:XPath Filter="intersect" xmlns:dsig="http://www.w3.org/2002/06/xmldsig-filter2">here()/ancestor::dsig:Signature[1]/../../../../../..//. | here()/ancestor::dsig:Signature[1]/../../../../../..//@* | here()/ancestor::dsig:Signature[1]/../../../../../..//namespace::*</dsig:XPath>
</dsig:Transform>
<dsig:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
<dsig:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#WithComments"/>
</dsig:Transforms>
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/>
<dsig:DigestValue>2jmj7l5rSw0yVb/vlWAYkK/YBwk=</dsig:DigestValue>
</dsig:Reference>
</dsig:SignedInfo>
<dsig:SignatureValue>d+DRc25SXnhxwXJs10A9Hnf1g0gG2bZqqnpTbZvrzp8X3EvtOVr3dBP6Ldc1RMTJYSF+guanlWKn
liaKlu7VbdB+SiQRuAMAZt+9Cnbn0CMlIzt22nRJNzjbeLBpCm7K63jCHGOXsWCW43DI/DYeZwq+
Q2j7WESgOtWLqUO0Jn8=</dsig:SignatureValue>
<dsig:KeyInfo>
<dsig:X509Data>
<dsig:X509Certificate>...</dsig:X509Certificate>
<dsig:X509Certificate>...</dsig:X509Certificate>
</dsig:X509Data>
</dsig:KeyInfo>
<dsig:Object>
<dsig:SignatureProperties Id="idfe5688f4-583f-4a98-b26c-9d651b2f8918">
<dsig:SignatureProperty Target="data_signature">
<PROP_Sig xmlns="http://ns.adobe.com/pdf/2006" type="cabinet">
<M type="text">D:20151130163741+0100</M>
<Name type="text">CN=<CN>,L=<City>,O=<Organization>,C=<Country></Name>
</PROP_Sig>
</dsig:SignatureProperty>
</dsig:SignatureProperties>
</dsig:Object>
</dsig:Signature>
</sac:SignatureInformation>
</sig:UBLDocumentSignatures>
</ext:ExtensionContent>
</ext:UBLExtension>
</ext:UBLExtensions>
Ich verstehe nicht, warum die Validierung sagt Referenz [0] fehlschlägt (derjenige, der auf Element mit id verweist), aber Bezug auf das gesamte Dokument besteht?
Könnten Sie bitte versuchen, 'factory.setIgnoringElementContentWhitespace (true);' in 'byteArrayToXmlDoc' zu entfernen? Es könnte das Problem verursachen. Das Problem ist, dass Ihre XML-Konvertierungen von Byte zu Array keine inverse Operationen sind. – vojta
@vojta Es hat nicht geholfen, die gleiche genaue Ausgabe, Es war wahrscheinlich versehentlich in Code sowieso verlassen, da ich mit verschiedenen Optionen vor dem Posting in der Hoffnung, es würde helfen würde gespielt. – formatc
Bitte senden Sie 'String'-Darstellungen Ihres XML-Dokuments, bevor Sie es in' Byte'-Array konvertieren und nach der Konvertierung in 'Document' in Ihrer' validate (byte [] byteArrayDoc, ...) Methode. Es muss einen sichtbaren Unterschied geben. (XML zu String: http://stackoverflow.com/questions/5456680/xml-document-to-string) – vojta