online firmar example con certificado xml digital-signature digest xml-signature

firmar - xml signature example



Firma XML: ¿Cómo calcular el valor de resumen? (5)

Tengo un XML como este

<?xml version="1.0" encoding="utf-8"?> <foo> <bar> <value>A</value> </bar> <bar> <value>B</value> </bar> <baz> <value>C</value> </baz><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=""><Transforms><Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" /><Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" /></Transforms><DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" /><DigestValue>WqpRWHxXA0YgH+p3Sxy6hRo1XIk=</DigestValue></Reference></SignedInfo><SignatureValue>EoRk/GhR4UA4D+8AzGPPkeim1dZrlSy88eF73n/T9Lpeq9IxoGRHNUA8FEwuDNJuz3IugC0n2RHQQpQajiYvhlY3XG+z742pgsdMfFE4Pddk4gF1T8CVS1rsF7bjX+FKT/c8B2/C8FNgmfkxDlB/ochtbRvuAGPQGtgJ3h/wjSg=</SignatureValue><KeyInfo><X509Data><X509Certificate>MIIB8zCCAVygAwIBAgIQgfzbrIjhLL9FobStI2ub3zANBgkqhkiG9w0BAQQFADATMREwDwYDVQQDEwhUZXN0ZUFjbjAeFw0wMDAxMDEwMDAwMDBaFw0zNjAxMDEwMDAwMDBaMBMxETAPBgNVBAMTCFRlc3RlQWNuMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDO+yAZ8/qJbhSVH/+2wMmzix3jM/CExb6sTgaiPwe6ylcHgF45zeQDq06OSJZCSns34em/ULINZddDf8z0b9uk/2sOGr1pYqsunLLBvw2FkvWJQDkhx2SzCm8v4xGX2kyXNbjiY/K56oPOMjpayKoAFnnvk7p2iFAxNZK/6lpZ7wIDAQABo0gwRjBEBgNVHQEEPTA7gBCOOHcajwnATYZ0t6w7LVU0oRUwEzERMA8GA1UEAxMIVGVzdGVBY26CEIH826yI4Sy/RaG0rSNrm98wDQYJKoZIhvcNAQEEBQADgYEABL9Qhi6f1Z+/t8oKXBQFx3UUsNF9N2o4k6q1c3CKZYqx2E/in+nARIYRdh5kbeLfomi6GIyVFeXExp8crob3MAzOQMvXf9+ByuezimMPIHDvv0u3kmmeITXfoZrHCDxLoWWlESN1owBfKPqe7JKAuu9ORDC0pUiUfCHWxCoqNos=</X509Certificate></X509Data></KeyInfo></Signature> </foo>

¿Cómo se crea el valor de resumen (WqpRWHxXA0YgH + p3Sxy6hRo1XIk =) en la referencia? Quiero decir, ¿cómo puedo calcular este valor manualmente?


Es muy sencillo, usa openssl en la consola:

openssl dgst -binary -sha1 archivo | openssl enc -base64

Hecho


Esta es una solución JAVA que requiere los siguientes tarros:

  • commons-logging-1.2.jar
  • commons-codec-1.6.jar
  • Saxon-HE-9.4.jar
  • xmlsec-1.3.0.jar

Esta solución utiliza http://www.w3.org/2001/10/xml-exc-c14n# como algoritmo de canonicalización, y usa SHA256 como algoritmo de hashing y codificación base64.

Nota: el document representa el documento XML como un objeto DOM en JAVA.

Ejemplo de código:

// create the transformer in order to transform the document from // DOM Source as a JAVA document class, into a character stream (StreamResult) of // type String writer, in order to be converted to a string later on TransformerFactory tf = new net.sf.saxon.TransformerFactoryImpl(); Transformer transformer = tf.newTransformer(); transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); transformer.setOutputProperty(OutputKeys.METHOD, "xml"); transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); // create the string writer and transform the document to a character stream StringWriter sw = new StringWriter(); transformer.transform(new DOMSource(document), new StreamResult(sw)); String documentAsString = sw.toString(); // initialize the XML security object, which is necessary to run the apache canonicalization com.sun.org.apache.xml.internal.security.Init.init(); // canonicalize the document to a byte array and convert it to string Canonicalizer canon = Canonicalizer.getInstance(Canonicalizer.ALGO_ID_C14N_EXCL_OMIT_COMMENTS); byte canonXmlBytes[] = canon.canonicalize(documentAsString.getBytes()); String canonXmlString = new String(canonXmlBytes); // get instance of the message digest based on the SHA-256 hashing algorithm MessageDigest digest = MessageDigest.getInstance("SHA-256"); // call the digest method passing the byte stream on the text, this directly updates the message // being digested and perform the hashing byte[] hash = digest.digest(canonXmlString.getBytes(StandardCharsets.UTF_8)); // encode the endresult byte hash byte[] encodedBytes = Base64.encodeBase64(hash); return new String(encodedBytes);


Me encontré con esta pregunta cuando intentaba averiguar exactamente lo mismo. Más tarde descubrí cómo hacerlo, así que pensé que publicaría la respuesta aquí.

Las cosas que deben suceder son:

  • canonicalización
  • crear valor de resumen, normalmente SHA1 (pero podría ser SHA256 entre otros)
  • Base64 lo codifica

La parte de canonicalización fue bastante simple, ya que las bibliotecas de Java lo hicieron por mí. Con lo que luché fue con el siguiente bit, la creación del compendio, porque cometí un error fatal en que el compendio de SHA1 que generé fue el SHA1 en forma HEX. SHA1 es de 160 bits, por lo tanto de 20 bytes, pero si genera estos 160 bits en HEX, obtiene 40 caracteres. Si luego lo codifica en base64, obtendrá un valor totalmente erróneo en comparación con lo que debería estar en DigestValue.

En su lugar, debe generar el resumen SHA1 y codificar en base64 la salida de 20 bytes. No intente enviar los 20 bytes a STDOUT ya que es muy poco probable que sea legible (por eso la gente suele generar el equivalente HEX, ya que es legible). En su lugar, solo codifica en base64 los 20 bytes y ese es su DigestValue.


Yo mismo he encontrado exactamente este problema: estaba generando una firma XML en Java y validando en .NET, y la validación siempre fallaba. En mi caso, la causa fue la función ''Imprimir XML a archivo'' XMLWrite.m (sí, en MATLAB *) que fue ''imprimiendo bastante'' el XML, insertando pestañas, espacios y nuevas líneas como mejor le parezca. Como estos son parte del documento, naturalmente la validación falló (también falló en Java). Mirando a tu fuente, esto puede estar sucediéndote. Use un transformador (javax.xml.transform. *) Para serializar su DOM correctamente sin cambiar el contenido.

* ¿Sabías que MATLAB entiende Java también? Simplemente puede escribir sentencias de Java en la consola de intérpretes y se ejecutarán como código m nativo.


This documento debe contener cómo se calcula el valor de resumen.

¡Espero que ayude!