XADES-EPES Dudas sobre los valores en los DigestValue y SignatureValue

Iniciado por Diabliyo, 15 Marzo 2019, 04:34 AM

0 Miembros y 1 Visitante están viendo este tema.

Diabliyo

Estoy integrando firma digital XADES-EPES en PHP sobre el estándar UBL, he leído bastante sobre el tema y en varios repositorios hacen de distintas formas el firmado, vaya, lo que va dentro de los DiguestValue y SignatureValue dejándome finalmente con la duda de: que información realmente va en esos elementos?.

Para verificar mis avances y llegar al firmado correcto me estoy respaldando en este validador https://tools.chilkat.io/xmlDsigVerify.cshtml y he abierto un repositorio donde comparto mi código en PHP hasta donde lo llevo de avanzado: https://gitlab.com/siegroupmx/xmlsinger

Voy al asunto....

>> Como se generan los DigestValue para las Referencias dentro de SignedInfo ??

Mi procedimiento para esto es simplemente tomar el Nodo (por ejemplo KeyInfo) canonizado a C14N y después lo paso por un Algoritmo (sha1, sha256, etc...), después lo convierto a Base64 y el resultado lo coloco sobre DigestValue..... mi proceso es correcto ???

Ejemplo simple y rápido:

CitarSobra mencionar que en el ejemplo de abajo estoy omitiendo el proceso donde creo la etiqueta Singature y sus elementos internos.

   <?php
    
const XMLDSIGNS'http://www.w3.org/2000/09/xmldsig#';
    
    
$xmlSigned'mixml.xml';
    
$xml= new DOMDocument();
    
$xml->preserveWhiteSpaceFALSE;
    
$xml->formatOutputtrue;
    
$xml->load($xmlSigned);
    
    
$xp= new DOMXPath($xml);
    
$xp->registerNamespace('secdsig'self::XMLDSIGNS);
    
$keyinfo$xp->query('.//secdsig:Signature/secdsig:KeyInfo');
    
    
$hashhash("sha256"$keyinfo->item(0)->C14N(), true);
    
$base64base64_encode($hash);
    echo 
$base64# imprime LcOJdpKtT7sgjbblkmGyYrSUslXMlw0TyCc8SOUBJQM=
    
?>


Y en el XML:

   <ds:Reference URI="#xmldsig-a837805e-9235-a8bb-7ab4-688282608259-keyinfo">
    <ds:Transforms>
    <ds:Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
    </ds:Transforms>
    <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
    <ds:DigestValue>LcOJdpKtT7sgjbblkmGyYrSUslXMlw0TyCc8SOUBJQM=</ds:DigestValue>
   </ds:Reference>
   ....
   ....
   <ds:KeyInfo Id="xmldsig-a837805e-9235-a8bb-7ab4-688282608259-keyinfo">
    ... todas las etiquetas internas....
   </ds:KeyInfo>


>> Como se genera el SignatureValue ???

En mi procedimiento tomo el nodo de SignedInfo canonizado a C14N, los firmo con openssl_sign() y el resultado lo convierto a Base64 y coloco dentro de SignatureValue. Es correcto esto que hago??

Ejemplo rápido:

   <?php
    
const XMLDSIGNS'http://www.w3.org/2000/09/xmldsig#';
    
    
$xmlOut'mixml.xml';
    
$xml= new DOMDocument();
    
$xml->preserveWhiteSpaceFALSE;
    
$xml->formatOutputtrue;
    
$xml->load($xmlOut);
    
    
$xp= new DOMXPath($xml);
    
$xp->registerNamespace('secdsig'self::XMLDSIGNS);
    
    
$si$xp->query('.//secdsig:Signature/secdsig:SignedInfo'); # signedinfo
    
openssl_sign($si->item(0)->C14N(), $signature$this->privateKeyOPENSSL_ALGO_SHA256);
    
$datobase64_encode($signature); # esto va en SignatureValue
    
    
$sv$xp->query('.//secdsig:Signature/secdsig:SignatureValue'); # signaturevalue
    
$sv->item(0)->nodeValue$dato;
    
?>


Y el SignatureValue dentro del XML esta:

   <ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#" Id="xmldsig-bfcdf0f0-2655-b952-9c85-77493d9f241f">
    <ds:SignedInfo>
    <ds:CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
    <ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
    <ds:Reference Id="xmldsig-bfcdf0f0-2655-b952-9c85-77493d9f241f-ref0" URI="">
    <ds:Transforms>
    <ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
    </ds:Transforms>
    <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
    <ds:DigestValue>KWOvQ3tWaygQXkkvfI6s9UO0azjQgc0YGp9JANDXYis=</ds:DigestValue>
    </ds:Reference>
    <ds:Reference URI="#xmldsig-a837805e-9235-a8bb-7ab4-688282608259-keyinfo">
    <ds:Transforms>
    <ds:Transform Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
    </ds:Transforms>
    <ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
    <ds:DigestValue>LcOJdpKtT7sgjbblkmGyYrSUslXMlw0TyCc8SOUBJQM=</ds:DigestValue>
    </ds:Reference>
    </ds:SignedInfo>
    <ds:SignatureValue Id="xmldsig-bfcdf0f0-2655-b952-9c85-77493d9f241f-sigvalue">
    ZGcaOhKK3Uzp64T11LHFKAy1eOkKeMpvKNNAeBFapJxbyCr8iQDkGQ2B+VQFYLWZnDneK6Cuc6uDtUw14q4mlYoarlIRVvLlsiQK0OmFrdWEM4sd62WPP2N0GpUOOh/I/BjggsqNV1OOWG2xutZNbdh4maJzxEbcLuU8SrdPuU6q38bTAw/QJyQ5F4eiRr++28sR9G3yV0nTzkZXR5QNPScdrbwrMtH/vkBx0FfV8ErzubwKyPdvQSbugmLMk8hd7Rnn5SRg8JaxQhCC5TDPC3KOmj5Nh1zHmzATZaRAbP0XNoYsDLnQtmteo5/RL2NHGvHYbP0teUF43nHXu/KAVg==
    </ds:SignatureValue>



>> CONCLUSIÓN

El validador me dice que la Firma esta mal, y que también esta mal el firmado de las referencias :(

Enlace a un ejemplo https://gitlab.com/siegroupmx/xmlsinger/blob/master/examples/ejemplo_out.xml

Certificado: https://gitlab.com/siegroupmx/xmlsinger/blob/master/tmp/certificado.pem

Firma: https://gitlab.com/siegroupmx/xmlsinger/blob/master/tmp/firma.pem

Clave: persona_juridica_pruebas

Diabliyo

Después de 4 días que parecieron "eternos" finalmente solucione mi problema.

El proceso en como realizaba los DigestValue de las Referencias y el SignatureValue son totalmente correctos, el problema radicaba en la Canonización.

Al momento de carga el XML firmado, extraer un nodo y generar la referencia estaba generando una apertura incorrecta lo cual seteaba por defecto la canonización en "preservar espacios" lo cual resultaba un hash distinto al esperado, ya que al momento de declarar el Transform para cada Reference, se indicaba un C14N regular, mas no un C14N-WithComments.

Antes:

$xml= new DOMDocument();
$xml->preserveWhiteSpace= FALSE;
$xml->formatOutput= true;
$xml->load($xmlsrc);
$xmldata= $xml->C14N();


Correcto:

$xml= new DOMDocument();
$xml->formatOutput= true;
$xml->load($xmlsrc);
$xmldata= $xml->C14N();


Este simple detalle me permitió generar el Firmado Xades-Epes sin problemas, ahora todas las tools me marcan "pass/valid" el firmado de las referencias como del SignatureValue.

Saludos !

bilbur

Hola y gracias por tu aporte

He intentado seguir algún guión para implementar la firma xades-epes en PHP y no consigo avanzar

El enlace que pones de ejemplo no fimciona (o no me funciona a mi)

Agradecería si pudieras publicar en ejemplo completo

Gracias por tu tiempo