Foro de elhacker.net

Programación => PHP => Mensaje iniciado por: Diabliyo en 15 Marzo 2019, 04:34 am



Título: XADES-EPES Dudas sobre los valores en los DigestValue y SignatureValue
Publicado por: Diabliyo en 15 Marzo 2019, 04:34 am
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:

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

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

Y en el XML:

Código:
    <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:

Código:
    <?php
    const XMLDSIGNS= 'http://www.w3.org/2000/09/xmldsig#';
    
    $xmlOut= 'mixml.xml';
    $xml= new DOMDocument();
    $xml->preserveWhiteSpace= FALSE;
    $xml->formatOutput= true;
    $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->privateKey, OPENSSL_ALGO_SHA256);
    $dato= base64_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:

Código:
    <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 (https://gitlab.com/siegroupmx/xmlsinger/blob/master/examples/ejemplo_out.xml)

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

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

Clave: persona_juridica_pruebas


Título: Re: XADES-EPES Dudas sobre los valores en los DigestValue y SignatureValue
Publicado por: Diabliyo en 19 Marzo 2019, 16:44 pm
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:

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

Correcto:

Código:
	$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 !


Título: Re: XADES-EPES Dudas sobre los valores en los DigestValue y SignatureValue
Publicado por: bilbur en 18 Noviembre 2019, 16:53 pm
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


Título: Re: XADES-EPES Dudas sobre los valores en los DigestValue y SignatureValue
Publicado por: guidoalcon en 24 Agosto 2022, 16:30 pm
Hola amigo ,no puedo acceder al repositorio. sera que me puedes compartir.