2015-11-30 5 views
14

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?

+0

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

+0

@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

+0

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

Antwort

2

@formatc Ich habe keine Privilegien zu kommentieren, aber können Sie versuchen, die hexadezimalen Werte in beiden Dateien (signieren und deserialisieren) zu sehen. Ich hatte das selbe Problem, aus irgendeinem Grund wurden in meinem Fall beim Entwerfen der XML einige nicht-visuelle Zeichen vor dem Dokument eingefügt. Sie werden sie nur sehen, wenn Sie HexView oder ein ähnliches Tool verwenden.

Ich konnte diese Zeichen programmgesteuert entfernen und alles ging gut.

+0

Ich habe beide mit Hex-Editor überprüft, sie sind identisch, zumindest auf der Festplatte. Danke für den Vorschlag trotzdem. – formatc

0
  • Seien Sie sicher, dass ihre Array-Zeichen für den Fall, sind sie gleich? Vor der Validierung müssen Sie einige Unterschiede sehen.
  • Auch einige Signture-Techniken können beliebige innere Vorzeichen wie eine GUID verwenden, um sie zu steuern.

Verwenden Utf8 sowohl

0

ich hatte genau das gleiche Problem wie Sie. Unterschrift war gültig, aber Referenzen nicht. Das Problem ist (zumindest in meinem Fall), dass Serialisierung und Deserialisierung den Inhalt des XML beeinflussen können. in meinem Fall hat es geholfen, document.normalizeDocument() vor dem Unterschreiben des Dokuments zu nennen und jetzt validiert die Unterschrift sogar nach Serialisierung/Deserialisierung.

0

In meinem Fall war es der Unterschied im Header-Wert, warum es fehlgeschlagen ist.

Das ursprüngliche XML-Dokument hat und als es geschrieben wurde Header geändert wurde

weshalb Prüfsignaturinformationen versagen.

Entfernen Sie daher die XML-Deklaration beim Analysieren des Dokuments und beim Schreiben des Dokuments.