xmlsignature xmldsig validate validar the signedinfo online firma java xml digital-signature xmlsec

java - validate - xmldsig



Valor de resumen incorrecto para firmas xml utilizando Java XML Digital Signature API (2)

Necesito enviar un archivo XML firmado a una agencia gubernamental en Brasil. El problema es que el compendio calculado por mi código Java (el uso de la API de firma digital XML de Java es diferente del generado con otra herramienta como XMLSEC .

Aquí está el código que uso para generar una firma XML para algunos nodos 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); }

Si intento validar el XML generado con xmlsec, obtengo el siguiente error:

$ 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

Pero si intento firmar el mismo archivo (consult.xml) con xmlsec (usando la misma clave privada), ese error desaparece:

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

Las diferencias entre consult.xml y doc-signed.xml (generado por xmlsec) son los contenidos de las etiquetas SignatureValue y 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>

No publicaré el resto de ninguno de los archivos porque son iguales y harían esta publicación aún más detallada.

De lo que puedo recopilar, la aplicación web que recibe este archivo XML es una aplicación .NET y calcula un resumen de firma diferente que mi código Java (al igual que xmlsec). ¿Algunas ideas?


Idealmente, el elemento DigestValue contiene el valor de compendio real codificado en base64 en la API de firma XML de Java. ¿Podría verificar que su valor de resumen creado a partir de XMLSec también está codificado en base64?


Si no es demasiado tarde para responder:

Crea 2 Transformaciones en el código (envelopedTransform y c14NTransform), pero no las usas.

Se crea la referencia con una sola transformación nueva. http://www.w3.org/TR/2001/REC-xml-c14n-20010315 (C14N) no se aplica la transformación.

Ahora, no estoy seguro de lo que dice el estándar de seguridad XML que dice que el comportamiento debería ser en este caso. Quizás otras herramientas también apliquen automáticamente la transformación C14N.

Estoy seguro de que si NO especifica ninguna transformación, JDK aplicará al menos la transformación C14N.

Básicamente, cambie esa fac.newReference ("", ...) y pase transformList en ella en lugar de Collections.singletonList ().