Pregunta:
Fecha: 25-01-2025 11:34:22
(En Español)
Valor de la firma (SignatureValue) diferente del calculado por el PKI.
<?php
$xmlString = trim('<?xml version="1.0" encoding="UTF-8"?>');
$xmlString .= trim('<rDE xmlns="http://ekuatia.set.gov.py/sifen/xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://ekuatia.set.gov.py/sifen/xsd siRecepDE_v150.xsd">');
$xmlString .= trim(' <dVerFor>150</dVerFor>');
$xmlString .= trim(' <DE Id="01801139171001001000012322025012410783739924">');
$xmlString .= trim(' <dDVId>4</dDVId>');
$xmlString .= trim(' <dFecFirma>2025-01-25T08:51:28</dFecFirma>');
$xmlString .= trim(' <dSisFact>1</dSisFact>');
$xmlString .= trim(' <gOpeDE>');
$xmlString .= trim(' <iTipEmi>1</iTipEmi>');
$xmlString .= trim(' <dDesTipEmi>Normal</dDesTipEmi>');
$xmlString .= trim(' <dCodSeg>078373992</dCodSeg>');
$xmlString .= trim(' <dInfoEmi>Info fiscal</dInfoEmi>');
$xmlString .= trim(' </gOpeDE>');
$xmlString .= trim(' <gTimb>');
$xmlString .= trim(' <iTiDE>1</iTiDE>');
$xmlString .= trim(' <dDesTiDE>Factura electrónica</dDesTiDE>');
$xmlString .= trim(' <dNumTim>80113917</dNumTim>');
$xmlString .= trim(' <dEst>001</dEst>');
$xmlString .= trim(' <dPunExp>001</dPunExp>');
$xmlString .= trim(' <dNumDoc>0000127</dNumDoc>');
$xmlString .= trim(' <dFeIniT>2025-01-14</dFeIniT>');
$xmlString .= trim(' </gTimb>');
$xmlString .= trim(' <gDatGralOpe>');
$xmlString .= trim(' <dFeEmiDE>2025-01-25T08:51:28</dFeEmiDE>');
$xmlString .= trim(' <gOpeCom>');
$xmlString .= trim(' <iTipTra>1</iTipTra>');
$xmlString .= trim(' <dDesTipTra>Venta de mercadería</dDesTipTra>');
$xmlString .= trim(' <iTImp>1</iTImp>');
$xmlString .= trim(' <dDesTImp>IVA</dDesTImp>');
$xmlString .= trim(' <cMoneOpe>PYG</cMoneOpe>');
$xmlString .= trim(' <dDesMoneOpe>Guarani</dDesMoneOpe>');
$xmlString .= trim(' <gOblAfe>');
$xmlString .= trim(' <cOblAfe>211</cOblAfe>');
$xmlString .= trim(' <dDesOblAfe>IMPUESTO AL VALOR AGREGADO - GRAVADAS Y EXONERADAS - EXPORTADORES</dDesOblAfe>');
$xmlString .= trim(' </gOblAfe>');
$xmlString .= trim(' </gOpeCom>');
$xmlString .= trim(' <gEmis>');
$xmlString .= trim(' <dRucEm>80113917</dRucEm>');
$xmlString .= trim(' <dDVEmi>1</dDVEmi>');
$xmlString .= trim(' <iTipCont>2</iTipCont>');
$xmlString .= trim(' <dNomEmi>xxxxxxxxxxx</dNomEmi>');
$xmlString .= trim(' <dDirEmi>JUAN ESCURRA Y TTE VERA - EDIFICIO MATRISA</dDirEmi>');
$xmlString .= trim(' <dNumCas>0</dNumCas>');
$xmlString .= trim(' <cDepEmi>1</cDepEmi>');
$xmlString .= trim(' <dDesDepEmi>CAPITAL</dDesDepEmi>');
$xmlString .= trim(' <cDisEmi>1</cDisEmi>');
$xmlString .= trim(' <dDesDisEmi>ASUNCION (DISTRITO)</dDesDisEmi>');
$xmlString .= trim(' <cCiuEmi>1</cCiuEmi>');
$xmlString .= trim(' <dDesCiuEmi>ASUNCION (DISTRITO)</dDesCiuEmi>');
$xmlString .= trim(' <dTelEmi>0985938400</dTelEmi>');
$xmlString .= trim(' <dEmailE>cdearrascaeta@barloventoservicios.com</dEmailE>');
$xmlString .= trim(' <gActEco>');
$xmlString .= trim(' <cActEco>70209</cActEco>');
$xmlString .= trim(' <dDesActEco>OTRAS ACTIVIDADES DE ADMINISTRACION Y CONSULTORA DE ADMINISTRACION DE EMPRESAS N.C.P.</dDesActEco>');
$xmlString .= trim(' </gActEco>');
$xmlString .= trim(' </gEmis>');
$xmlString .= trim(' <gDatRec>');
$xmlString .= trim(' <iNatRec>1</iNatRec>');
$xmlString .= trim(' <iTiOpe>1</iTiOpe>');
$xmlString .= trim(' <cPaisRec>PRY</cPaisRec>');
$xmlString .= trim(' <dDesPaisRe>Paraguay</dDesPaisRe>');
$xmlString .= trim(' <iTiContRec>1</iTiContRec>');
$xmlString .= trim(' <dRucRec>4700177</dRucRec>');
$xmlString .= trim(' <dDVRec>1</dDVRec>');
$xmlString .= trim(' <dNomRec>MARTIN ROJAS</dNomRec>');
$xmlString .= trim(' <dDirRec>-</dDirRec>');
$xmlString .= trim(' <dNumCasRec>0</dNumCasRec>');
$xmlString .= trim(' <cDepRec>6</cDepRec>');
$xmlString .= trim(' <dDesDepRec>CAAGUAZU</dDesDepRec>');
$xmlString .= trim(' <cDisRec>62</cDisRec>');
$xmlString .= trim(' <dDesDisRec>CAAGUAZU</dDesDisRec>');
$xmlString .= trim(' <cCiuRec>2988</cCiuRec>');
$xmlString .= trim(' <dDesCiuRec>CAAGUAZU</dDesCiuRec>');
$xmlString .= trim(' <dTelRec>0986743969</dTelRec>');
$xmlString .= trim(' <dEmailRec>tecnologiasciencias@gmail.com</dEmailRec>');
$xmlString .= trim(' <dCodCliente>000045616</dCodCliente>');
$xmlString .= trim(' </gDatRec>');
$xmlString .= trim(' </gDatGralOpe>');
$xmlString .= trim(' <gDtipDE>');
$xmlString .= trim(' <gCamFE>');
$xmlString .= trim(' <iIndPres>1</iIndPres>');
$xmlString .= trim(' <dDesIndPres>Operación presencial</dDesIndPres>');
$xmlString .= trim(' </gCamFE>');
$xmlString .= trim(' <gCamCond>');
$xmlString .= trim(' <iCondOpe>1</iCondOpe>');
$xmlString .= trim(' <dDCondOpe>Contado</dDCondOpe>');
$xmlString .= trim(' <gPaConEIni>');
$xmlString .= trim(' <iTiPago>1</iTiPago>');
$xmlString .= trim(' <dDesTiPag>Efectivo</dDesTiPag>');
$xmlString .= trim(' <dMonTiPag>750000</dMonTiPag>');
$xmlString .= trim(' <cMoneTiPag>PYG</cMoneTiPag>');
$xmlString .= trim(' <dDMoneTiPag>Guarani</dDMoneTiPag>');
$xmlString .= trim(' </gPaConEIni>');
$xmlString .= trim(' </gCamCond>');
$xmlString .= trim(' <gCamItem>');
$xmlString .= trim(' <dCodInt>21106</dCodInt>');
$xmlString .= trim(' <dDesProSer>INODORO CELITE LIKE KIT C/ CAJA TAPA CONEXION FIJADOR Y ANILLO PERGAMON COMPLETO</dDesProSer>');
$xmlString .= trim(' <cUniMed>77</cUniMed>');
$xmlString .= trim(' <dDesUniMed>UNI</dDesUniMed>');
$xmlString .= trim(' <dCantProSer>1</dCantProSer>');
$xmlString .= trim(' <gValorItem>');
$xmlString .= trim(' <dPUniProSer>750000.00</dPUniProSer>');
$xmlString .= trim(' <dTotBruOpeItem>750000.00</dTotBruOpeItem>');
$xmlString .= trim(' <gValorRestaItem>');
$xmlString .= trim(' <dTotOpeItem>750000.00</dTotOpeItem>');
$xmlString .= trim(' </gValorRestaItem>');
$xmlString .= trim(' </gValorItem>');
$xmlString .= trim(' <gCamIVA>');
$xmlString .= trim(' <iAfecIVA>1</iAfecIVA>');
$xmlString .= trim(' <dDesAfecIVA>Gravado IVA</dDesAfecIVA>');
$xmlString .= trim(' <dPropIVA>100</dPropIVA>');
$xmlString .= trim(' <dTasaIVA>10</dTasaIVA>');
$xmlString .= trim(' <dBasGravIVA>681818.18</dBasGravIVA>');
$xmlString .= trim(' <dLiqIVAItem>68181.82</dLiqIVAItem>');
$xmlString .= trim(' <dBasExe>0.00</dBasExe>');
$xmlString .= trim(' </gCamIVA>');
$xmlString .= trim(' </gCamItem>');
$xmlString .= trim(' </gDtipDE>');
$xmlString .= trim(' <gTotSub>');
$xmlString .= trim(' <dSubExe>0.00</dSubExe>');
$xmlString .= trim(' <dSubExo>0</dSubExo>');
$xmlString .= trim(' <dSub5>0.00</dSub5>');
$xmlString .= trim(' <dSub10>750000.00</dSub10>');
$xmlString .= trim(' <dTotOpe>750000.00</dTotOpe>');
$xmlString .= trim(' <dTotDesc>0.00</dTotDesc>');
$xmlString .= trim(' <dTotDescGlotem>0.00</dTotDescGlotem>');
$xmlString .= trim(' <dTotAntItem>0</dTotAntItem>');
$xmlString .= trim(' <dTotAnt>0</dTotAnt>');
$xmlString .= trim(' <dPorcDescTotal>0.00</dPorcDescTotal>');
$xmlString .= trim(' <dDescTotal>0.00</dDescTotal>');
$xmlString .= trim(' <dAnticipo>0</dAnticipo>');
$xmlString .= trim(' <dRedon>0</dRedon>');
$xmlString .= trim(' <dTotGralOpe>750000.00</dTotGralOpe>');
$xmlString .= trim(' <dIVA5>0.00</dIVA5>');
$xmlString .= trim(' <dIVA10>68181.82</dIVA10>');
$xmlString .= trim(' <dTotIVA>68181.82</dTotIVA>');
$xmlString .= trim(' <dBaseGrav5>0.00</dBaseGrav5>');
$xmlString .= trim(' <dBaseGrav10>681818.18</dBaseGrav10>');
$xmlString .= trim(' <dTBasGraIVA>681818.18</dTBasGraIVA>');
$xmlString .= trim(' </gTotSub>');
$xmlString .= trim(' </DE>');
$xmlString .= trim('</rDE>');
*/
print_r($xmlString);
// Archivos necesarios
$pfxFile = 'firma_digital.pfx'; // Certificado PFX
$password = 'xxxxxxxxx'; // Contraseña del PFX
$cdc = '01801139171001001000012322025012410783739924';
// Leer el archivo PFX
$pfxContent = file_get_contents($pfxFile);
$pfxData = [];
if (!openssl_pkcs12_read($pfxContent, $pfxData, $password)) {
die("No se pudo leer el archivo PFX.");
}
// Clave privada y certificado extraídos
$privateKey = $pfxData['pkey'];
$publicCert = $pfxData['cert'];
// Cargar el XML
$doc = new DOMDocument();
if (!$doc->loadXML($xmlString)) {
die("No se pudo cargar el XML desde el string.");
}
// Seleccionar el nodo específico a firmar (cambiar la ruta XPath según tus necesidades)
$xpath = new DOMXPath($doc);
$xpath->registerNamespace('sifen', 'http://ekuatia.set.gov.py/sifen/xsd');
$nodoAFirmar = $xpath->query("//sifen:DE[@Id='01801139171001001000012322025012410783739924']")->item(0);
if (!$nodoAFirmar) {
die("No se encontró el nodo a firmar.");
}
// Verificar si el nodo tiene un atributo ID, si no, agregar uno
/*if (!$nodoAFirmar->hasAttribute('ID')) {
$nodoAFirmar->setAttribute('ID', $cdc);
}*/
// Crear el elemento <Signature>
$signatureElement = $doc->createElement('Signature');
$signatureElement->setAttribute('xmlns', 'http://www.w3.org/2000/09/xmldsig#');
// Crear <SignedInfo>
$signedInfoElement = $doc->createElement('SignedInfo');
// Crear <CanonicalizationMethod>
$canonicalizationMethodElement = $doc->createElement('CanonicalizationMethod');
$canonicalizationMethodElement->setAttribute('Algorithm', 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315');
$signedInfoElement->appendChild($canonicalizationMethodElement);
// Crear <SignatureMethod>
$signatureMethodElement = $doc->createElement('SignatureMethod');
$signatureMethodElement->setAttribute('Algorithm', 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256');
$signedInfoElement->appendChild($signatureMethodElement);
// Crear <Reference>
$referenceElement = $doc->createElement('Reference');
$referenceElement->setAttribute('URI', '#'.$cdc);
// Crear <Transforms>
$transformsElement = $doc->createElement('Transforms');
// Agregar Transformaciones
$transformEnveloped = $doc->createElement('Transform');
$transformEnveloped->setAttribute('Algorithm', 'http://www.w3.org/2000/09/xmldsig#enveloped-signature');
$transformsElement->appendChild($transformEnveloped);
$transformC14N = $doc->createElement('Transform');
$transformC14N->setAttribute('Algorithm', 'http://www.w3.org/2001/10/xml-exc-c14n#');
$transformsElement->appendChild($transformC14N);
$referenceElement->appendChild($transformsElement);
// Crear <DigestMethod>
$digestMethodElement = $doc->createElement('DigestMethod');
$digestMethodElement->setAttribute('Algorithm', 'http://www.w3.org/2001/04/xmlenc#sha256');
$referenceElement->appendChild($digestMethodElement);
// Crear <DigestValue>
$canonicalXML = $nodoAFirmar->C14N(true, false); // Canonicalizar el contenido del nodo
$digestValue = base64_encode(hash('sha256', $canonicalXML, true));
$digestValueElement = $doc->createElement('DigestValue', $digestValue);
$referenceElement->appendChild($digestValueElement);
$signedInfoElement->appendChild($referenceElement);
$signatureElement->appendChild($signedInfoElement);
// Crear la firma digital signature value
$signedInfoCanonical = $signedInfoElement->C14N(); // Canonicalizar SignedInfo
openssl_sign($signedInfoCanonical, $rawSignature, $privateKey, OPENSSL_ALGO_SHA256);
$signatureValue = base64_encode($rawSignature);
// Crear <SignatureValue>
$signatureValueElement = $doc->createElement('SignatureValue', $signatureValue);
$signatureElement->appendChild($signatureValueElement);
// Crear <KeyInfo>
$keyInfoElement = $doc->createElement('KeyInfo');
$cleanCert = trim(str_replace(
["-----BEGIN CERTIFICATE-----", "-----END CERTIFICATE-----"],
'',
$publicCert
));
$x509DataElement = $doc->createElement('X509Data');
$x509CertificateElement = $doc->createElement('X509Certificate', $cleanCert);
$x509DataElement->appendChild($x509CertificateElement);
$keyInfoElement->appendChild($x509DataElement);
$signatureElement->appendChild($keyInfoElement);
// Agregar <Signature> al documento
//$nodoAFirmar->appendChild($signatureElement);
$doc->documentElement->appendChild($signatureElement);
// Guardar el XML firmado
$doc->save('documento_firmado.xml');
echo "El XML se ha firmado correctamente y se guardó como 'documento_firmado.xml'.";
Votos: 0 - Respuestas: 4 - Vistas: 4 Compartir en: Google Facebook Twitter LinkedIn Link
tengo problemas al firmar un doxumento xml con un certificado pfx[No resuelta]
necesito firmar un documento en xml con cerificado pfx ( siempre me sale el error )Valor de la firma (SignatureValue) diferente del calculado por el PKI.
<?php
$xmlString = trim('<?xml version="1.0" encoding="UTF-8"?>');
$xmlString .= trim('<rDE xmlns="http://ekuatia.set.gov.py/sifen/xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://ekuatia.set.gov.py/sifen/xsd siRecepDE_v150.xsd">');
$xmlString .= trim(' <dVerFor>150</dVerFor>');
$xmlString .= trim(' <DE Id="01801139171001001000012322025012410783739924">');
$xmlString .= trim(' <dDVId>4</dDVId>');
$xmlString .= trim(' <dFecFirma>2025-01-25T08:51:28</dFecFirma>');
$xmlString .= trim(' <dSisFact>1</dSisFact>');
$xmlString .= trim(' <gOpeDE>');
$xmlString .= trim(' <iTipEmi>1</iTipEmi>');
$xmlString .= trim(' <dDesTipEmi>Normal</dDesTipEmi>');
$xmlString .= trim(' <dCodSeg>078373992</dCodSeg>');
$xmlString .= trim(' <dInfoEmi>Info fiscal</dInfoEmi>');
$xmlString .= trim(' </gOpeDE>');
$xmlString .= trim(' <gTimb>');
$xmlString .= trim(' <iTiDE>1</iTiDE>');
$xmlString .= trim(' <dDesTiDE>Factura electrónica</dDesTiDE>');
$xmlString .= trim(' <dNumTim>80113917</dNumTim>');
$xmlString .= trim(' <dEst>001</dEst>');
$xmlString .= trim(' <dPunExp>001</dPunExp>');
$xmlString .= trim(' <dNumDoc>0000127</dNumDoc>');
$xmlString .= trim(' <dFeIniT>2025-01-14</dFeIniT>');
$xmlString .= trim(' </gTimb>');
$xmlString .= trim(' <gDatGralOpe>');
$xmlString .= trim(' <dFeEmiDE>2025-01-25T08:51:28</dFeEmiDE>');
$xmlString .= trim(' <gOpeCom>');
$xmlString .= trim(' <iTipTra>1</iTipTra>');
$xmlString .= trim(' <dDesTipTra>Venta de mercadería</dDesTipTra>');
$xmlString .= trim(' <iTImp>1</iTImp>');
$xmlString .= trim(' <dDesTImp>IVA</dDesTImp>');
$xmlString .= trim(' <cMoneOpe>PYG</cMoneOpe>');
$xmlString .= trim(' <dDesMoneOpe>Guarani</dDesMoneOpe>');
$xmlString .= trim(' <gOblAfe>');
$xmlString .= trim(' <cOblAfe>211</cOblAfe>');
$xmlString .= trim(' <dDesOblAfe>IMPUESTO AL VALOR AGREGADO - GRAVADAS Y EXONERADAS - EXPORTADORES</dDesOblAfe>');
$xmlString .= trim(' </gOblAfe>');
$xmlString .= trim(' </gOpeCom>');
$xmlString .= trim(' <gEmis>');
$xmlString .= trim(' <dRucEm>80113917</dRucEm>');
$xmlString .= trim(' <dDVEmi>1</dDVEmi>');
$xmlString .= trim(' <iTipCont>2</iTipCont>');
$xmlString .= trim(' <dNomEmi>xxxxxxxxxxx</dNomEmi>');
$xmlString .= trim(' <dDirEmi>JUAN ESCURRA Y TTE VERA - EDIFICIO MATRISA</dDirEmi>');
$xmlString .= trim(' <dNumCas>0</dNumCas>');
$xmlString .= trim(' <cDepEmi>1</cDepEmi>');
$xmlString .= trim(' <dDesDepEmi>CAPITAL</dDesDepEmi>');
$xmlString .= trim(' <cDisEmi>1</cDisEmi>');
$xmlString .= trim(' <dDesDisEmi>ASUNCION (DISTRITO)</dDesDisEmi>');
$xmlString .= trim(' <cCiuEmi>1</cCiuEmi>');
$xmlString .= trim(' <dDesCiuEmi>ASUNCION (DISTRITO)</dDesCiuEmi>');
$xmlString .= trim(' <dTelEmi>0985938400</dTelEmi>');
$xmlString .= trim(' <dEmailE>cdearrascaeta@barloventoservicios.com</dEmailE>');
$xmlString .= trim(' <gActEco>');
$xmlString .= trim(' <cActEco>70209</cActEco>');
$xmlString .= trim(' <dDesActEco>OTRAS ACTIVIDADES DE ADMINISTRACION Y CONSULTORA DE ADMINISTRACION DE EMPRESAS N.C.P.</dDesActEco>');
$xmlString .= trim(' </gActEco>');
$xmlString .= trim(' </gEmis>');
$xmlString .= trim(' <gDatRec>');
$xmlString .= trim(' <iNatRec>1</iNatRec>');
$xmlString .= trim(' <iTiOpe>1</iTiOpe>');
$xmlString .= trim(' <cPaisRec>PRY</cPaisRec>');
$xmlString .= trim(' <dDesPaisRe>Paraguay</dDesPaisRe>');
$xmlString .= trim(' <iTiContRec>1</iTiContRec>');
$xmlString .= trim(' <dRucRec>4700177</dRucRec>');
$xmlString .= trim(' <dDVRec>1</dDVRec>');
$xmlString .= trim(' <dNomRec>MARTIN ROJAS</dNomRec>');
$xmlString .= trim(' <dDirRec>-</dDirRec>');
$xmlString .= trim(' <dNumCasRec>0</dNumCasRec>');
$xmlString .= trim(' <cDepRec>6</cDepRec>');
$xmlString .= trim(' <dDesDepRec>CAAGUAZU</dDesDepRec>');
$xmlString .= trim(' <cDisRec>62</cDisRec>');
$xmlString .= trim(' <dDesDisRec>CAAGUAZU</dDesDisRec>');
$xmlString .= trim(' <cCiuRec>2988</cCiuRec>');
$xmlString .= trim(' <dDesCiuRec>CAAGUAZU</dDesCiuRec>');
$xmlString .= trim(' <dTelRec>0986743969</dTelRec>');
$xmlString .= trim(' <dEmailRec>tecnologiasciencias@gmail.com</dEmailRec>');
$xmlString .= trim(' <dCodCliente>000045616</dCodCliente>');
$xmlString .= trim(' </gDatRec>');
$xmlString .= trim(' </gDatGralOpe>');
$xmlString .= trim(' <gDtipDE>');
$xmlString .= trim(' <gCamFE>');
$xmlString .= trim(' <iIndPres>1</iIndPres>');
$xmlString .= trim(' <dDesIndPres>Operación presencial</dDesIndPres>');
$xmlString .= trim(' </gCamFE>');
$xmlString .= trim(' <gCamCond>');
$xmlString .= trim(' <iCondOpe>1</iCondOpe>');
$xmlString .= trim(' <dDCondOpe>Contado</dDCondOpe>');
$xmlString .= trim(' <gPaConEIni>');
$xmlString .= trim(' <iTiPago>1</iTiPago>');
$xmlString .= trim(' <dDesTiPag>Efectivo</dDesTiPag>');
$xmlString .= trim(' <dMonTiPag>750000</dMonTiPag>');
$xmlString .= trim(' <cMoneTiPag>PYG</cMoneTiPag>');
$xmlString .= trim(' <dDMoneTiPag>Guarani</dDMoneTiPag>');
$xmlString .= trim(' </gPaConEIni>');
$xmlString .= trim(' </gCamCond>');
$xmlString .= trim(' <gCamItem>');
$xmlString .= trim(' <dCodInt>21106</dCodInt>');
$xmlString .= trim(' <dDesProSer>INODORO CELITE LIKE KIT C/ CAJA TAPA CONEXION FIJADOR Y ANILLO PERGAMON COMPLETO</dDesProSer>');
$xmlString .= trim(' <cUniMed>77</cUniMed>');
$xmlString .= trim(' <dDesUniMed>UNI</dDesUniMed>');
$xmlString .= trim(' <dCantProSer>1</dCantProSer>');
$xmlString .= trim(' <gValorItem>');
$xmlString .= trim(' <dPUniProSer>750000.00</dPUniProSer>');
$xmlString .= trim(' <dTotBruOpeItem>750000.00</dTotBruOpeItem>');
$xmlString .= trim(' <gValorRestaItem>');
$xmlString .= trim(' <dTotOpeItem>750000.00</dTotOpeItem>');
$xmlString .= trim(' </gValorRestaItem>');
$xmlString .= trim(' </gValorItem>');
$xmlString .= trim(' <gCamIVA>');
$xmlString .= trim(' <iAfecIVA>1</iAfecIVA>');
$xmlString .= trim(' <dDesAfecIVA>Gravado IVA</dDesAfecIVA>');
$xmlString .= trim(' <dPropIVA>100</dPropIVA>');
$xmlString .= trim(' <dTasaIVA>10</dTasaIVA>');
$xmlString .= trim(' <dBasGravIVA>681818.18</dBasGravIVA>');
$xmlString .= trim(' <dLiqIVAItem>68181.82</dLiqIVAItem>');
$xmlString .= trim(' <dBasExe>0.00</dBasExe>');
$xmlString .= trim(' </gCamIVA>');
$xmlString .= trim(' </gCamItem>');
$xmlString .= trim(' </gDtipDE>');
$xmlString .= trim(' <gTotSub>');
$xmlString .= trim(' <dSubExe>0.00</dSubExe>');
$xmlString .= trim(' <dSubExo>0</dSubExo>');
$xmlString .= trim(' <dSub5>0.00</dSub5>');
$xmlString .= trim(' <dSub10>750000.00</dSub10>');
$xmlString .= trim(' <dTotOpe>750000.00</dTotOpe>');
$xmlString .= trim(' <dTotDesc>0.00</dTotDesc>');
$xmlString .= trim(' <dTotDescGlotem>0.00</dTotDescGlotem>');
$xmlString .= trim(' <dTotAntItem>0</dTotAntItem>');
$xmlString .= trim(' <dTotAnt>0</dTotAnt>');
$xmlString .= trim(' <dPorcDescTotal>0.00</dPorcDescTotal>');
$xmlString .= trim(' <dDescTotal>0.00</dDescTotal>');
$xmlString .= trim(' <dAnticipo>0</dAnticipo>');
$xmlString .= trim(' <dRedon>0</dRedon>');
$xmlString .= trim(' <dTotGralOpe>750000.00</dTotGralOpe>');
$xmlString .= trim(' <dIVA5>0.00</dIVA5>');
$xmlString .= trim(' <dIVA10>68181.82</dIVA10>');
$xmlString .= trim(' <dTotIVA>68181.82</dTotIVA>');
$xmlString .= trim(' <dBaseGrav5>0.00</dBaseGrav5>');
$xmlString .= trim(' <dBaseGrav10>681818.18</dBaseGrav10>');
$xmlString .= trim(' <dTBasGraIVA>681818.18</dTBasGraIVA>');
$xmlString .= trim(' </gTotSub>');
$xmlString .= trim(' </DE>');
$xmlString .= trim('</rDE>');
*/
print_r($xmlString);
// Archivos necesarios
$pfxFile = 'firma_digital.pfx'; // Certificado PFX
$password = 'xxxxxxxxx'; // Contraseña del PFX
$cdc = '01801139171001001000012322025012410783739924';
// Leer el archivo PFX
$pfxContent = file_get_contents($pfxFile);
$pfxData = [];
if (!openssl_pkcs12_read($pfxContent, $pfxData, $password)) {
die("No se pudo leer el archivo PFX.");
}
// Clave privada y certificado extraídos
$privateKey = $pfxData['pkey'];
$publicCert = $pfxData['cert'];
// Cargar el XML
$doc = new DOMDocument();
if (!$doc->loadXML($xmlString)) {
die("No se pudo cargar el XML desde el string.");
}
// Seleccionar el nodo específico a firmar (cambiar la ruta XPath según tus necesidades)
$xpath = new DOMXPath($doc);
$xpath->registerNamespace('sifen', 'http://ekuatia.set.gov.py/sifen/xsd');
$nodoAFirmar = $xpath->query("//sifen:DE[@Id='01801139171001001000012322025012410783739924']")->item(0);
if (!$nodoAFirmar) {
die("No se encontró el nodo a firmar.");
}
// Verificar si el nodo tiene un atributo ID, si no, agregar uno
/*if (!$nodoAFirmar->hasAttribute('ID')) {
$nodoAFirmar->setAttribute('ID', $cdc);
}*/
// Crear el elemento <Signature>
$signatureElement = $doc->createElement('Signature');
$signatureElement->setAttribute('xmlns', 'http://www.w3.org/2000/09/xmldsig#');
// Crear <SignedInfo>
$signedInfoElement = $doc->createElement('SignedInfo');
// Crear <CanonicalizationMethod>
$canonicalizationMethodElement = $doc->createElement('CanonicalizationMethod');
$canonicalizationMethodElement->setAttribute('Algorithm', 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315');
$signedInfoElement->appendChild($canonicalizationMethodElement);
// Crear <SignatureMethod>
$signatureMethodElement = $doc->createElement('SignatureMethod');
$signatureMethodElement->setAttribute('Algorithm', 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256');
$signedInfoElement->appendChild($signatureMethodElement);
// Crear <Reference>
$referenceElement = $doc->createElement('Reference');
$referenceElement->setAttribute('URI', '#'.$cdc);
// Crear <Transforms>
$transformsElement = $doc->createElement('Transforms');
// Agregar Transformaciones
$transformEnveloped = $doc->createElement('Transform');
$transformEnveloped->setAttribute('Algorithm', 'http://www.w3.org/2000/09/xmldsig#enveloped-signature');
$transformsElement->appendChild($transformEnveloped);
$transformC14N = $doc->createElement('Transform');
$transformC14N->setAttribute('Algorithm', 'http://www.w3.org/2001/10/xml-exc-c14n#');
$transformsElement->appendChild($transformC14N);
$referenceElement->appendChild($transformsElement);
// Crear <DigestMethod>
$digestMethodElement = $doc->createElement('DigestMethod');
$digestMethodElement->setAttribute('Algorithm', 'http://www.w3.org/2001/04/xmlenc#sha256');
$referenceElement->appendChild($digestMethodElement);
// Crear <DigestValue>
$canonicalXML = $nodoAFirmar->C14N(true, false); // Canonicalizar el contenido del nodo
$digestValue = base64_encode(hash('sha256', $canonicalXML, true));
$digestValueElement = $doc->createElement('DigestValue', $digestValue);
$referenceElement->appendChild($digestValueElement);
$signedInfoElement->appendChild($referenceElement);
$signatureElement->appendChild($signedInfoElement);
// Crear la firma digital signature value
$signedInfoCanonical = $signedInfoElement->C14N(); // Canonicalizar SignedInfo
openssl_sign($signedInfoCanonical, $rawSignature, $privateKey, OPENSSL_ALGO_SHA256);
$signatureValue = base64_encode($rawSignature);
// Crear <SignatureValue>
$signatureValueElement = $doc->createElement('SignatureValue', $signatureValue);
$signatureElement->appendChild($signatureValueElement);
// Crear <KeyInfo>
$keyInfoElement = $doc->createElement('KeyInfo');
$cleanCert = trim(str_replace(
["-----BEGIN CERTIFICATE-----", "-----END CERTIFICATE-----"],
'',
$publicCert
));
$x509DataElement = $doc->createElement('X509Data');
$x509CertificateElement = $doc->createElement('X509Certificate', $cleanCert);
$x509DataElement->appendChild($x509CertificateElement);
$keyInfoElement->appendChild($x509DataElement);
$signatureElement->appendChild($keyInfoElement);
// Agregar <Signature> al documento
//$nodoAFirmar->appendChild($signatureElement);
$doc->documentElement->appendChild($signatureElement);
// Guardar el XML firmado
$doc->save('documento_firmado.xml');
echo "El XML se ha firmado correctamente y se guardó como 'documento_firmado.xml'.";
Votos: 0 - Respuestas: 4 - Vistas: 4 Compartir en: Google Facebook Twitter LinkedIn Link
Respuestas:
-
Fecha: 27-01-2025 22:00:53 Hola Martin:
No llego a ver cuál es el error que estás obteniendo. Tal vez si pudieras resaltar el código usando el tag sería más fácil de leer tu mensaje.
En todo caso lo que te recomiendo, para empezar, es que uses la clase SimpleXMLElement en lugar de string para armar el XML.
Es muy similar al DOMDocument que ya estás usando y seguro te ahorrará problemas.
¿Podrías comentar cuál es exactamente el mensaje de error que ves? Votos: 0 - Link respuesta -
Fecha: 28-01-2025 02:02:49 hola mauro gracias por tu buena predisposicion para ayudarme, te esplico lo que hago tengo ciertos datos en una base de datos, tomo esos datos y los voy colocando en el lugar correspondinte, luego lo firmo y como resultado me da documento_firmado.xml ( en esta doreccion valido el xml https://ekuatia.set.gov.py/prevalidador/validacion ) por ultimo al validarlo siempre da el error
VALOR DE LA FIRMA ( SIGNATURE VALUE ) DIFERENTE DEL CALCULADO POR EL PKI
tambien te comento que no se usar la libreria SIMPLEXMLELEMENT tal ves si tuviera un ejemplo o algo asi intentaria hacerlo ( si quieres puedes hacer correr el codigo en php y luego validarlo en la direccion que te indique hay veras el error que te mencione ) Votos: 0 - Link respuesta -
Fecha: 28-01-2025 03:09:19 el valor del signature value esta mal calculado Votos: 0 - Link respuesta
-
Fecha: 28-01-2025 22:03:42 Ya veo. Bueno, veamos, respecto de la clase SimpleXMLElement, la documentación oficial es esta, la idea es que, en lugar de ir concatenando un string, armás un objeto y le vas agregando nodos.
En tu caso sería algo así como:
<?php $xml = new SimpleXMLElement('<rde xmlns="http://ekuatia.set.gov.py/sifen/xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://ekuatia.set.gov.py/sifen/xsd siRecepDE_v150.xsd"/>'); $xml->addChild("dVerFor", "150"); echo $xml->asXML();
Hay varios ejemplos acá.
Por el lado del cálculo del valor de la firma, ¿podrías indicar en tu código dónde se realiza dicho cálculo? Habría que mirar qué puede estar pasando o si hay algún problema específico del servidor con el que te estás conectando. Votos: 0 - Link respuesta
Para participar activamente de la comunidad primero debes autenticarte, ingresa al sistema.Iniciar Sesión