2011-01-18 11 views
5

Lavoro con il progetto "Nota Fiscal Eletronica" brasiliano, in cui definiscono un modo standard per firmare documenti XML.Come produrre la firma XML senza spazi bianchi e interruzioni di riga in Java?

Recentemente, hanno iniziato a richiedere che non ci siano assolutamente spazi bianchi tra i tag, compresi i tag di firma (*).

Ci capita di utilizzare Apache XMLSignature e non riesco a produrre una firma senza indirizzo.

Se rimuovo gli spazi bianchi dopo la firma, la firma viene interrotta.

Non riesco a cambiare neanche il set di canonicalizzatori/trasformatori, poiché sono predefiniti.

Non sono riuscito a trovare un'opzione o un parametro nell'API XMLSignature per controllare il rientro o gli spazi bianchi.

Di seguito si riporta il codice:

// the element where to insert the signature 
    Element element = ...; 
    X509Certificate cert = ...; 
    PrivateKey privateKey = ...; 

    XMLSignature signer = 
      new XMLSignature(doc, "http://xml-security", 
      XMLSignature.ALGO_ID_SIGNATURE_RSA_SHA1); 

    element.appendChild(signer.getElement()); 

    Transforms transforms = new Transforms(doc); 

    // Define as regras de transformação e canonicalização do documento 
    // XML, necessário para fazer a verificação do parsing e da 
    // assinatura pelos destinatários 
    transforms.addTransform(Transforms.TRANSFORM_ENVELOPED_SIGNATURE); //, xpath.getElementPlusReturns()); 

    transforms.addTransform(Transforms.TRANSFORM_C14N_OMIT_COMMENTS); //,xpath.getElementPlusReturns()); 

    String id = ""; 

    id = ((Element) element.getElementsByTagName("infNFe").item(0)).getAttributeNode("Id").getNodeValue(); 

    signer.addDocument("#" + id, transforms, 
         Constants.ALGO_ID_DIGEST_SHA1); 
    signer.addKeyInfo(cert); 
    signer.sign(privateKey); 

E sotto è la firma risultante (frammento):

<Signature xmlns="http://www.w3.org/2000/09/xmldsig#"> 
<SignedInfo> 
<CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/> 
<SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/> 
<Reference URI="#NFe43110189716583000165550010000076011492273645"> 
<Transforms> 
<Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/> 
<Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/> 
</Transforms> 
<DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1"/> 
<DigestValue>fas0ra5uRskQgRHSrIYhEjFEjKQ=</DigestValue> 
</Reference> 
</SignedInfo> 
<SignatureValue> 
2RGltUZy0HfNoiKtVanAeN+JUPyglWDuQNnMudSgA7kESoHBZ/q/GMbc+xMSN1eV8u7+2PxSKl1T 
Zl592FWmCSAkL8pwMujDxJ4iTLU20Hf0dNF7oGcyB+g9GgbipW2udq0kwJLz6HzXUD/Evf/0y+3T 
NtsXeIaA6A29ttD/UEs= 
</SignatureValue> 
<KeyInfo> 
<X509Data> 
<X509Certificate> 
MIIFqTCCBJGgAwIBAgIEQeNSuzANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJicjETMBEGA1UE 
ChMKSUNQLUJyYXNpbDEgMB4GA1UECxMXQ2FpeGEgRWNvbm9taWNhIEZlZGVyYWwxFDASBgNVBAMT 
C0FDIENBSVhBIFBKMB4XDTEwMDYwODE5MjQwNVoXDTExMDYwODE5NTQwNVowgYQxCzAJBgNVBAYT 
AmJyMRMwEQYDVQQKEwpJQ1AtQnJhc2lsMSAwHgYDVQQLExdDYWl4YSBFY29ub21pY2EgRmVkZXJh 
bDEUMBIGA1UECxMLQUMgQ0FJWEEgUEoxKDAmBgNVBAMTH0EgQlVITEVSIFNBIENVUlRVTUU6NDA5 
NDI0OTAwMTAwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOFxgvG35RQWgXec4zVrzoUHolnJ 
fP76rpO2Vo40593W9Gf0WwHt36gVmli0ZeQitFmzFSoE5KhgXQGZg6RpV3WJUFcIrPBHPdqOSfiB 
988kf962P+j8fZ38BNmo7TV9H9hMBkV9bD/QOe73wFDc+rT6/9io++Z+7/wup/3glKntAgMBAAGj 
ggLOMIICyjAOBgNVHQ8BAf8EBAMCBeAwVwYDVR0gBFAwTjBMBgZgTAECAQkwQjBABggrBgEFBQcC 
ARY0aHR0cDovL2ljcC5jYWl4YS5nb3YuYnIvcmVwb3NpdG9yaW8vZHBjYWNjYWl4YXBqLnBkZjAp 
BgNVHSUEIjAgBggrBgEFBQcDAgYIKwYBBQUHAwQGCisGAQQBgjcUAgIwgbYGA1UdEQSBrjCBq4EV 
YnVobGVyQGFidWhsZXIuY29tLmJyoD4GBWBMAQMEoDUEMzE0MDkxOTQ2NDA5NDI0OTAwMTAxMDg0 
NDcwODE3NTAwMDAwODAzMjkyMjM1NlNTUCBSU6AeBgVgTAEDAqAVBBNOQUlSIEJVSExFUiBTQ0hO 
RUNLoBkGBWBMAQMDoBAEDjg5NzE2NTgzMDAwMTY1oBcGBWBMAQMHoA4EDDAwMDAwMDAwMDAwMDCC 
ATIGA1UdHwSCASkwggElMIGuoIGroIGohjJodHRwOi8vaWNwLmNhaXhhLmdvdi5ici9yZXBvc2l0 
b3Jpby9BQ0NBSVhBUEoxLmNybIY0aHR0cDovL2ljcDIuY2FpeGEuZ292LmJyL3JlcG9zaXRvcmlv 
Mi9BQ0NBSVhBUEoxLmNybIY8aHR0cDovL3JlcG9zaXRvcmlvLmljcGJyYXNpbC5nb3YuYnIvbGNy 
L2NhaXhhL0FDQ0FJWEFQSjEuY3JsMHKgcKBupGwwajELMAkGA1UEBhMCYnIxEzARBgNVBAoTCklD 
UC1CcmFzaWwxIDAeBgNVBAsTF0NhaXhhIEVjb25vbWljYSBGZWRlcmFsMRQwEgYDVQQDEwtBQyBD 
QUlYQSBQSjEOMAwGA1UEAxMFQ1JMNDEwHwYDVR0jBBgwFoAUjkAvCv4T1ao5oHZ0htO8fcfx5c8w 
CQYDVR0TBAIwADAZBgkqhkiG9n0HQQAEDDAKGwRWNy4xAwIDqDANBgkqhkiG9w0BAQUFAAOCAQEA 
nZHUvdnZsiCIDjKm1zHehbtuDtDJha4O4FZ03J74Y+AxyAFs/4JED+xUvZ5jFuEsdqgA0V/dxUFy 
Uz/ca10Ievd578GQdGwYl1GFhRtO/SlxeaOEf7eDdGOWXO3VmUA3NmNo0X8RRTIoifnhpDXu7RbN 
5sijyH/uXyRFWX9XH2N0U/r3oJtNKXsvoUlbDrkalgkuLzLKsaEj0TkwisXO3cmMoWGuBpAZC+46 
e4x/2vTqOvYkzZO+O9NLi0YWSYY7OJKiKBjMC6MzdlPM9VTkIwO9WvWEMdbU0/jhO2cMcVMzNZc1 
r6ZmdTDrwqV3elSTkQtJ0RIZNgMJUn+Y8c7Aog== 
</X509Certificate> 
</X509Data> 
</KeyInfo> 
</Signature> 

Avviso i (indesiderati) interruzioni di linea.

Qualsiasi aiuto sarebbe molto apprezzato.

Grazie mille in anticipo.

(*) Chiarimento: la nuova regola vieta gli spazi bianchi (o qualsiasi altro testo) tra tag di soli elementi. Come esempio, questo sarebbe accettati:

<a><b> 
    text 
    inside 
    tag 
</b></a> 

mentre questo sarebbe vietato:

<a> 
<b>text</b> 
</a> 

perché in quest'ultimo caso, gli spazi bianchi (linea-break) sono tra due tag , o, in altre parole, inserito all'interno di un tag solo elemento.

+6

Il problema è che il loro fabbisogno non ha senso da XML e punto di vista XMLDSig. Molto probabilmente hanno commesso qualche errore nel loro codice, e ora invece di confermare l'errore e correggere il codice, vogliono che tutti gli altri si occupino della loro implementazione fallita. –

+0

Sostengo EldoS Corp. di Eugene Mayevski. Ho gestito xml come quello sopra senza problemi. – Bozho

+0

Sostengono di aver dichiarato questa regola per ridurre il traffico di rete (che in realtà è enorme), dal momento che alcuni software includevano quantità abusive di spazi vuoti di indentazione. Sono in grado di verificare la firma con successo. C'è questa altra (non correlata e nuova) regola applicata che incorre nel rifiuto del messaggio. Sono d'accordo, tuttavia, che non dovrebbero imporre questa restrizione sulla parte della firma. –

risposta

7

È possibile semplicemente impostare -Dorg.apache.xml.security.ignoreLineBreaks = true per disabilitare '\ n' nella generazione XML. original mail

bug description

+0

Non ho potuto testare questa soluzione, dal momento in cui hai risposto, avevo già applicato una soluzione alternativa scegliendo un'altra API di firma. Ma ho esaminato i collegamenti e questa sembra essere esattamente la soluzione semplice e molto meno traumatica che stavo cercando di rispetto. –

+0

Collegamenti non funzionanti –

3

i blocchi di firma codificano le informazioni binarie come Base64, che deve seguire alcune formazioni comprese le interruzioni di riga (vedere http://en.wikipedia.org/wiki/Base64). Quindi non puoi semplicemente rimuoverli senza alterare le informazioni.

un modo migliore per ridurre il traffico di rete, è utilizzare la comedia prima di inviare i dati.

+0

+1, ottima risposta. L'articolo di wikipedia afferma che c'è una lunghezza massima della linea e un separatore di riga. Utilizzare la compressione è il modo giusto per risolvere questo problema. – Bozho

+0

La nuova regola proibisce gli spazi bianchi solo tra i tag. Il testo all'interno di un tag foglia (come le informazioni codificate Base64) può contenere spazi bianchi. Aggiornerò la domanda per chiarire questo. –

+0

Quindi ci manca senza pretese. In questo caso puoi farlo funzionare (vedi la mia altra risposta). – lweller

2

Fortunatamente XMLSignature is opensource, quindi suppongo che dovrete ottenere il codice sorgente e hackerarlo da soli.

Probabilmente la vostra soluzione aiuterà gli altri in futuro, quindi creare una patch e inviarla al progetto.

Buona fortuna!

:) :)

0

XML Firma segni parte di un documento XML inizia con un dato elemento (cioè una sottostruttura ad albero DOM) dopo che è normalizzata con un algoritmo C14N. L'algoritmo C14N standard che usi mantiene le interruzioni di riga e gli spazi bianchi (vedi http://www.w3.org/TR/xml-c14n#Example-WhitespaceInContent).

Così tutti interruzioni di riga nella parte firmata del documento originale (compreso tra l'ultima tag dei dati e il tag <Signature> e tra </Signature> e il tag di chiusura successiva) * devono essere conservati in modo da non alterare la firma . La linea si rompe e gli spazi nell'elemento Signature non sono importanti e possono essere rimossi senza alterare la firma.

Ecco un esempio:

<root id="signedpart"> 
    <data> 
    ... 
    </data> 
    <Signature xmlns="http://www.w3.org/2000/09/xmldsig#"> 
    <SignedInfo> 
     <Reference URI="#signedpart"> 
      ... 
     </Reference> 
    </SignedInfo> 
    </Signature> 
</root> 

Ecco le possibili opzioni:

  1. definire il proprio algoritmo di C14N che rimuoverà gli spazi e le interruzioni di riga da esso auto. Vorrei scoraggiare questo come l'altro lato deve anche utilizzare questo algoritmo C14N non standard.

  2. linea di rimuovere le interruzioni uno spazi da voi XML prima firmarlo (e rimuovere potenzialmente spazi firma in seguito)

con l'esempio questo vi darà il seguente codice XML firmato:

<root id="signedpart"><data>...</data><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"> 
    <SignedInfo> 
     <Reference URI="#signedpart"> 
      ... 
     </Reference> 
    </SignedInfo> 
    </Signature></root> 

e dopo aver rimosso gli spazi nella firma

<root id="signedpart"><data>...</data><Signature xmlns="http://www.w3.org/2000/09/xmldsig#"><SignedInfo><Reference URI="#signedpart">...</Reference></SignedInfo></Signature></root> 
+0

Opzione 1. Non sono autorizzato a farlo, dal momento che i canonicalizzatori e le trasformazioni sono predefiniti e non possono essere modificati. –

+0

Opzione 2. Se rimuovo gli spazi dalla firma in seguito, la firma inevitabilmente si rompe. Penso che l'unico modo sia quello di produrre la firma direttamente senza interruzioni di riga. –

+0

L'ho testato da solo (con apache xmlsec 1.4.4) e rimuovendo interruzioni di linea e spazi ** tra ** tag di firma non lo altera. – lweller

1

Ho trovato una soluzione (vergognosa).

Tuttavia, non è la soluzione prevista: sostituzione dell'API di apache con l'API javax.xml.crypto.

Ecco il codice modificato:

// the element where to insert the signature 
Element element = ...; 
X509Certificate cert = ...; 
PrivateKey privateKey = ...; 
// Create a DOM XMLSignatureFactory that will be used to 
// generate the enveloped signature. 
XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM"); 

// Create a Reference to the enveloped document (in this case, 
// you are signing the whole document, so a URI of "" signifies 
// that, and also specify the SHA1 digest algorithm and 
// the ENVELOPED Transform. 
List<Transform> transformList = new ArrayList<Transform>(); 
TransformParameterSpec tps = null; 
Transform envelopedTransform; 
try { 
    envelopedTransform = fac.newTransform(Transform.ENVELOPED, 
      tps); 
    Transform c14NTransform = fac.newTransform(
      "http://www.w3.org/TR/2001/REC-xml-c14n-20010315", tps); 

    transformList.add(envelopedTransform); 
    transformList.add(c14NTransform); 
} catch (NoSuchAlgorithmException e) { 
    throw new RuntimeException("Erro inesperado: " + e.getMessage(), e); 
} catch (InvalidAlgorithmParameterException e) { 
    throw new RuntimeException("Erro inesperado: " + e.getMessage(), e); 
} 

// Create the KeyInfo containing the X509Data. 
KeyInfoFactory kif = fac.getKeyInfoFactory(); 
List<Serializable> x509Content = new ArrayList<Serializable>(); 
x509Content.add(cert); 
javax.xml.crypto.dsig.keyinfo.X509Data xd = kif.newX509Data(x509Content); 
KeyInfo ki = kif.newKeyInfo(Collections.singletonList(xd)); 

// Obtem elemento do documento a ser assinado, será criado uma 
// REFERENCE para o mesmo 
Element el = (Element) element.getElementsByTagName(subTag).item(0); 
String id = el.getAttribute("Id"); 

// Create a DOM XMLSignatureFactory that will be used to 
// generate the enveloped signature. 

Reference ref; 
javax.xml.crypto.dsig.SignedInfo si; 
try { 
    ref = fac.newReference("#" + id, fac.newDigestMethod(
      DigestMethod.SHA1, null), transformList, null, null); 

    // Create the SignedInfo. 
    si = fac.newSignedInfo(fac.newCanonicalizationMethod(
      CanonicalizationMethod.INCLUSIVE, 
      (C14NMethodParameterSpec) null), fac.newSignatureMethod(SignatureMethod.RSA_SHA1, null), 
      Collections.singletonList(ref)); 
} catch (NoSuchAlgorithmException e) { 
    throw new RuntimeException("Erro inesperado: " + e.getMessage(), e); 
} catch (InvalidAlgorithmParameterException e) { 
    throw new RuntimeException("Erro inesperado: " + e.getMessage(), e); 
} 

// Create the XMLSignature, but don't sign it yet. 
javax.xml.crypto.dsig.XMLSignature signature = fac.newXMLSignature(si, ki); 

// Marshal, generate, and sign the enveloped signature. 
// Create a DOMSignContext and specify the RSA PrivateKey and 
// location of the resulting XMLSignature's parent element. 
DOMSignContext dsc = new DOMSignContext(privateKey, element); 
signature.sign(dsc); 

Questa API produce la firma, senza spazi bianchi tra i tag a tutti.

Ancora piacerebbe vedere una soluzione per l'API di apache, poiché questo codice era già molto maturo, e non vorremmo rischiare tanto quanto modificare l'intera implementazione della firma.

0

Abbiamo solo bisogno di impostare il valore "vero" per il parametro "ignoreLineBreaks", causa' il valore predefinito è falso e questo permette alle API firma per aggiungere interruzioni di linea

ecco il codice per evitare o rimuovere interruzioni di riga

Field f = XMLUtils.class.getDeclaredField("ignoreLineBreaks"); 
f.setAccessible(true); 
f.set(null, Boolean.TRUE); 

poi, ci possiamo fare in modo che il nuovo valore è vero con la prossima linea di codice

System.err.println(XMLUtils.ignoreLineBreaks()); 

Ho avuto lo stesso problema e questo ha funzionato per me.

0

Si può provare:

System.setProperty("org.apache.xml.security.ignoreLineBreaks", "true");