2012-05-01 22 views
25

Devo inviare un file XML firmato a un'agenzia governativa in Brasile. Il problema è che il digest calcolato il mio codice Java (utilizzando il Java XML Digital Signature API è diverso da quello generato con un altro strumento come XMLSECValore digerito errato per firme xml utilizzando l'API di firma digitale Java XML

Ecco il codice che uso per generare una firma XML per qualche nodo XML:.

private synchronized void sign(XmlObject obj) throws Exception { 
     initKeystore(); 
     XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM"); 
     List<Transform> transformList = new ArrayList<Transform>(); 
     Transform envelopedTransform = fac.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null); 
     Transform c14NTransform = fac.newTransform("http://www.w3.org/TR/2001/REC-xml-c14n-20010315", 
       (TransformParameterSpec) null); 
     transformList.add(envelopedTransform); 
     transformList.add(c14NTransform); 
     Reference ref = fac.newReference("", fac.newDigestMethod(DigestMethod.SHA1, null), 
       Collections.singletonList(fac.newTransform(Transform.ENVELOPED, (TransformParameterSpec) null)), null, 
       null); 
     SignedInfo si = fac.newSignedInfo(
       fac.newCanonicalizationMethod(CanonicalizationMethod.INCLUSIVE, (C14NMethodParameterSpec) null), 
       fac.newSignatureMethod(SignatureMethod.RSA_SHA1, null), Collections.singletonList(ref)); 
     KeyStore ks = KeyStore.getInstance("PKCS12"); 
     ks.load(new FileInputStream(System.getProperty("javax.net.ssl.keyStore")), 
       System.getProperty("javax.net.ssl.keyStorePassword").toCharArray()); 
     KeyStore.PrivateKeyEntry keyEntry = (KeyStore.PrivateKeyEntry) ks.getEntry("entry", 
       new KeyStore.PasswordProtection(System.getProperty("javax.net.ssl.keyStorePassword").toCharArray())); 

     X509Certificate cert = (X509Certificate) keyEntry.getCertificate(); 

     // Create the KeyInfo containing the X509Data. 
     KeyInfoFactory kif = fac.getKeyInfoFactory(); 
     X509Data xd = kif.newX509Data(Collections.singletonList(cert)); 
     KeyInfo ki = kif.newKeyInfo(Collections.singletonList(xd)); 
     // Instantiate the document to be signed. 

     Element el = (Element) obj.getDomNode().getFirstChild(); 
     String id = el.getAttribute("Id"); 

     DOMSignContext dsc = new DOMSignContext(keyEntry.getPrivateKey(), el); 
     // Create the XMLSignature, but don't sign it yet. 
     XMLSignature signature = fac.newXMLSignature(si, ki); 
     // Marshal, generate, and sign the enveloped signature. 
     signature.sign(dsc); 

    } 

Se provo a convalidare il XML generato con xmlsec, ottengo il seguente errore:

$ xmlsec1 --verify consulta.xml 
func=xmlSecOpenSSLEvpDigestVerify:file=digests.c:line=229:obj=sha1:subj=unknown:error=12:invalid data:data and digest do not match 
FAIL 

Ma se provo a firmare lo stesso del file (consult.xml) con xmlsec (utilizzando la stessa chiave privata), quell'errore va te:

xmlsec1 --sign --output doc-signed.xml --privkey-pem cert.pem consulta.xml 

Le differenze tra consult.xml e doc-signed.xml (generato da xmlsec) sono i contenuti delle variabili SignatureValue e DigestValue:

consulta.xml:

<DigestValue>Ajn+tfX7JQc0HPNJ8KbTy7Q2f8I=</DigestValue> 
... 
<SignatureValue>Q1Ys0Rtj8yL2SA2NaQWQPtmNuHKK8q2anPiyLWlH7mOIjwOs0GEcD0WLUM/BZU0Q 
T0kSbDTuJeTR2Ec9wu+hqXXbJ76FpX9/IyHrdyx2hLg0VhB5RRCdyBEuGlmnsFDf 
XCyBotP+ZyEzolbTCN9TjCUnXNDWtFP1YapMxAIA0sth0lTpYgGJd8CSvFlHdFj+ 
ourf8ZGiDmSTkVkKnqDsj8O0ZLmbZfJpH2CBKicX+Ct7MUz2sqVli4XAHs6WXX+E 
HJpbOKthS3WCcpG3Kw4K50yIYGTkTbWCYFxOVsMfiVy4W/Qz15Vxb8chD8LM58Ep 
m/szmvnTAESxv/piDr7hyw==</SignatureValue> 

doc-signed.xml:

<DigestValue>w6xElXJrZw3G86OsNkWav+pcKJo=</DigestValue> 
... 
<SignatureValue>YmUsnlnAY9uLhlfVBLhB8K8ArxMOkOKZJoQ6zgz55ggU6vJCO9+HWJCKQJp6Rvn/w5PCAFY0KJRb 
r6/WhHML0Z+Q6TSuIL8OTvJ3iPoROAK6uy07YAflKOUklqk4uxgfMkR+hWMCyfITJVCVZo/MXmPy 
g7YwmztoSlGH+p6+ND5n2u47Y2k6SpIvw3CUxwAVQkD0Hsj3G58cbUbrFCoyPVGOe4zJ9c1HPsMW 
KzBEFe3QETzPJ8I1B7EEVi5oDvzXE2rMTH4K7zvNGnXpBNGwnSjEOticlqKVP5wyUD7CPwgF1Wgy 
Z0njvlaW3K8YmAY8fc70v/+wSO6Fu+0zj18Xeg==</SignatureValue> 

non voglio postare il resto sia file perché sono uguali e renderebbe questo post ancora più prolisso.

Da quello che posso raccogliere, l'app Web che riceve questo file XML è un'applicazione .NET e calcola un diverso digest di firma che il mio codice Java (molto simile a xmlsec). Qualche idea?

+0

Scusa, ma sei sicuro che l'algoritmo di hash digest sia SHA1? Può essere qualcos'altro e la firma può essere ancora RSA_SHA1 (mentre leggo il tuo codice). – esej

+0

Questo è quello che sto dicendo all'API Java da fare. Una cosa che ho notato è che se salvi il documento xmls in un file, leggo quel file e firma ciò che ho letto, il digest è calcolato correttamente. Quindi penso che forse gli spazi bianchi siano in qualche modo considerati sul lato Java o XMLSEC. Questo risolverebbe il mio problema se avessi bisogno di firmare l'xml solo una volta; il problema è che ho bisogno di farlo almeno due volte ... – Andre

+8

Hai cheched '\ n'? –

risposta

1

Se non è troppo tardi per rispondere:

Si crea 2 trasforma nel codice (envelopedTransform e c14NTransform), ma non li uso.

È possibile creare il riferimento con una sola nuova Trasformata.INVELATA. http://www.w3.org/TR/2001/REC-xml-c14n-20010315 (C14N) la trasformazione non è applicata.

Ora, non so per certo cosa lo standard di sicurezza XML dice che il comportamento dovrebbe essere in questo caso. Forse anche altri strumenti applicano automaticamente la trasformazione C14N.

Sono sicuro che se non si specifica alcuna trasformazione, JDK applicherà almeno una trasformazione C14N.

Cambiare fondamentalmente fac.newReference ("", ...) e passare in TransformList invece di Collections.singletonList().

0

Idealmente l'elemento DigestValue contiene il valore di digest effettivo con base64 nell'API di firma XML Java. Potresti verificare che il tuo valore digest creato da XMLSec sia anche codificato in base64.

Problemi correlati