/** * Acción para firmar un XML * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl) * @version 2015-11-09 */ public function firmar_xml() { if (isset($_POST['submit'])) { $xml = file_get_contents($_FILES['xml']['tmp_name']); // obtener nombre del tag y del ID $XML = new \sasco\LibreDTE\XML(); $XML->loadXML($xml); foreach ($XML->documentElement->childNodes as $child) { if ($child instanceof \DOMElement) { $tag = $child->tagName; $id = $child->getAttribute('ID'); break; } } // firmar $Firma = new \sasco\LibreDTE\FirmaElectronica(['file' => $_FILES['firma']['tmp_name'], 'pass' => $_POST['contrasenia']]); $xmlSigned = $Firma->signXML($xml, $id, $tag); // entregar datos ob_end_clean(); header('Content-Type: application/xml; charset=' . $XML->encoding); header('Content-Length: ' . strlen($xmlSigned)); header('Content-Disposition: attachement; filename="' . $id . '_firmado.xml"'); print $xmlSigned; exit; } }
/** * Recurso de la API que permite validar el TED (timbre electrónico) * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl) * @version 2015-09-19 */ public function _api_verificar_ted_POST() { // verificar si se pasaron credenciales de un usuario $User = $this->Api->getAuthUser(); if (is_string($User)) { $this->Api->send($User, 401); } // obtener TED $TED = base64_decode($this->Api->data); if (strpos($TED, '<?xml') !== 0) { $TED = '<?xml version="1.0" encoding="ISO-8859-1"?>' . "\n" . $TED; } // crear xml con el ted y obtener datos en arreglo $xml = new \sasco\LibreDTE\XML(); $xml->loadXML($TED); $datos = $xml->toArray(); // verificar firma del ted $DD = $xml->getFlattened('/TED/DD'); $FRMT = $datos['TED']['FRMT']; $pub_key = \sasco\LibreDTE\FirmaElectronica::getFromModulusExponent($datos['TED']['DD']['CAF']['DA']['RSAPK']['M'], $datos['TED']['DD']['CAF']['DA']['RSAPK']['E']); if (openssl_verify($DD, base64_decode($FRMT), $pub_key, OPENSSL_ALGO_SHA1) !== 1) { $this->Api->send('Firma del timbre incorrecta', 500); } // verificar que datos del timbre correspondan con datos del CAF if ($datos['TED']['DD']['RE'] != $datos['TED']['DD']['CAF']['DA']['RE']) { $this->Api->send('RUT del timbre no corresponde con RUT del CAF', 500); } if ($datos['TED']['DD']['TD'] != $datos['TED']['DD']['CAF']['DA']['TD']) { $this->Api->send('Tipo de DTE del timbre no corresponde con tipo de DTE del CAF', 500); } if ($datos['TED']['DD']['F'] < $datos['TED']['DD']['CAF']['DA']['RNG']['D'] or $datos['TED']['DD']['F'] > $datos['TED']['DD']['CAF']['DA']['RNG']['H']) { $this->Api->send('Folio del DTE del timbre fuera del rango del CAF', 500); } // definir si se consultará en certificación o producción define('_LibreDTE_CERTIFICACION_', $datos['TED']['DD']['CAF']['DA']['IDK'] == 100); // crear objeto firma $Firma = new \sasco\LibreDTE\FirmaElectronica(); // obtener token $token = \sasco\LibreDTE\Sii\Autenticacion::getToken($Firma); if (!$token) { return $this->Api->send(\sasco\LibreDTE\Log::readAll(), 500); } // verificar estado del DTE con el SII list($RutConsultante, $DvConsultante) = explode('-', $Firma->getID()); list($RutCompania, $DvCompania) = explode('-', $datos['TED']['DD']['RE']); list($RutReceptor, $DvReceptor) = explode('-', $datos['TED']['DD']['RR']); list($a, $m, $d) = explode('-', $datos['TED']['DD']['FE']); $xml = \sasco\LibreDTE\Sii::request('QueryEstDte', 'getEstDte', ['RutConsultante' => $RutConsultante, 'DvConsultante' => $DvConsultante, 'RutCompania' => $RutCompania, 'DvCompania' => $DvCompania, 'RutReceptor' => $RutReceptor, 'DvReceptor' => $DvReceptor, 'TipoDte' => $datos['TED']['DD']['TD'], 'FolioDte' => $datos['TED']['DD']['F'], 'FechaEmisionDte' => $d . $m . $a, 'MontoDte' => $datos['TED']['DD']['MNT'], 'token' => $token]); if ($xml === false) { return $this->Api->send(\sasco\LibreDTE\Log::readAll(), 500); } return (array) $xml->xpath('/SII:RESPUESTA/SII:RESP_HDR')[0]; }
/** * Método que indica si la firma del DTE es o no válida * @return =true si la firma del DTE es válida, =null si no se pudo determinar * @warning No se está verificando el valor del DigestValue del documento (sólo la firma de ese DigestValue) * @author Esteban De La Fuente Rubio, DeLaF (esteban[at]sasco.cl) * @version 2015-09-08 */ public function checkFirma() { if (!$this->xml) { return null; } // obtener firma $Signature = $this->xml->documentElement->getElementsByTagName('Signature')->item(0); // preparar documento a validar $D = $this->xml->documentElement->getElementsByTagName('Documento')->item(0); $Documento = new \sasco\LibreDTE\XML(); $Documento->loadXML($D->C14N()); $Documento->documentElement->removeAttributeNS('http://www.w3.org/2001/XMLSchema-instance', 'xsi'); $Documento->documentElement->removeAttributeNS('http://www.sii.cl/SiiDte', ''); $SignedInfo = new \sasco\LibreDTE\XML(); $SignedInfo->loadXML($Signature->getElementsByTagName('SignedInfo')->item(0)->C14N()); $SignedInfo->documentElement->removeAttributeNS('http://www.w3.org/2001/XMLSchema-instance', 'xsi'); $DigestValue = $Signature->getElementsByTagName('DigestValue')->item(0)->nodeValue; $SignatureValue = $Signature->getElementsByTagName('SignatureValue')->item(0)->nodeValue; $X509Certificate = $Signature->getElementsByTagName('X509Certificate')->item(0)->nodeValue; $X509Certificate = '-----BEGIN CERTIFICATE-----' . "\n" . wordwrap(trim($X509Certificate), 64, "\n", true) . "\n" . '-----END CERTIFICATE----- '; $valid = openssl_verify($SignedInfo->C14N(), base64_decode($SignatureValue), $X509Certificate) === 1 ? true : false; return $valid; //return $valid and $DigestValue===base64_encode(sha1($Documento->C14N(), true)); }
echo 'Verificando SetDTE:', "\n"; echo ' Digest SetDTE: ', base64_encode(sha1($SetDTE, true)), "\n"; echo ' Digest SignedInfo: ', base64_encode(sha1($SignedInfo->C14N(), true)), "\n"; echo ' Digest SignedInfo: ', bin2hex(sha1($SignedInfo->C14N(), true)), "\n"; echo ' Digest SetDTE valido: ', $DigestValue === base64_encode(sha1($SetDTE, true)) ? 'si' : 'no', "\n"; echo ' Digest SignedInfo valido: ', $valid ? 'si' : 'no', "\n\n"; // verificar firma de documentos $i = 0; $documentos = $XML->documentElement->getElementsByTagName('Documento'); foreach ($documentos as $D) { $Documento = new \sasco\LibreDTE\XML(); $Documento->loadXML($D->C14N()); $Documento->documentElement->removeAttributeNS('http://www.w3.org/2001/XMLSchema-instance', 'xsi'); $Documento->documentElement->removeAttributeNS('http://www.sii.cl/SiiDte', ''); $SignedInfo = new \sasco\LibreDTE\XML(); $SignedInfo->loadXML($Signatures->item($i)->getElementsByTagName('SignedInfo')->item(0)->C14N()); $SignedInfo->documentElement->removeAttributeNS('http://www.w3.org/2001/XMLSchema-instance', 'xsi'); $DigestValue = $Signatures->item($i)->getElementsByTagName('DigestValue')->item(0)->nodeValue; $SignatureValue = $Signatures->item($i)->getElementsByTagName('SignatureValue')->item(0)->nodeValue; $X509Certificate = $Signatures->item($i)->getElementsByTagName('X509Certificate')->item(0)->nodeValue; $X509Certificate = '-----BEGIN CERTIFICATE-----' . "\n" . wordwrap(trim($X509Certificate), 64, "\n", true) . "\n" . '-----END CERTIFICATE----- '; //$pub_key = openssl_pkey_get_details(openssl_pkey_get_public($X509Certificate))['key']; /*$pub_key = getPublicKey( $Signatures->item($i)->getElementsByTagName('Modulus')->item(0)->nodeValue, $Signatures->item($i)->getElementsByTagName('Exponent')->item(0)->nodeValue );*/ $valid = openssl_verify($SignedInfo->C14N(), base64_decode($SignatureValue), $X509Certificate) === 1 ? true : false; echo 'Verificando Documento:', "\n"; echo ' Digest Documento: ', base64_encode(sha1($Documento->C14N(), true)), "\n"; echo ' Digest SignedInfo: ', base64_encode(sha1($SignedInfo->C14N(), true)), "\n"; echo ' Digest Documento valido: ', $DigestValue === base64_encode(sha1($Documento->C14N(), true)) ? 'si' : 'no', "\n";