Giter Site home page Giter Site logo

credentials's Introduction

phpcfdi/credentials

Source Code Packagist PHP Version Support Discord Latest Version Software License Build Status Reliability Maintainability Code Coverage Violations Total Downloads

Library to use eFirma (fiel) and CSD (sellos) from SAT

🇺🇸 The documentation of this project is in spanish as this is the natural language for intended audience.

🇲🇽 La documentación del proyecto está en español porque ese es el lenguaje principal de los usuarios.

Esta librería ha sido creada para poder trabajar con los archivos CSD y FIEL del SAT. De esta forma, se simplifica el proceso de firmar, verificar firma y obtener datos particulares del archivo de certificado así como de la llave pública.

  • El CSD (Certificado de Sello Digital) es utilizado para firmar Comprobantes Fiscales Digitales.

  • La FIEL (o eFirma) es utilizada para firmar electrónicamente documentos (generalmente usando XML-SEC) y está reconocida por el gobierno mexicano como una manera de firma legal de una persona física o moral.

Con esta librería no es necesario convertir los archivos generados por el SAT a otro formato, se pueden utilizar tal y como el SAT los entrega.

Instalación

Usa composer

composer require phpcfdi/credentials

Ejemplo básico de uso

<?php declare(strict_types=1);

$cerFile = 'fiel/certificado.cer';
$pemKeyFile = 'fiel/private-key.key';
$passPhrase = '12345678a'; // contraseña para abrir la llave privada

$fiel = PhpCfdi\Credentials\Credential::openFiles($cerFile, $pemKeyFile, $passPhrase);

$sourceString = 'texto a firmar';
// alias de privateKey/sign/verify
$signature = $fiel->sign($sourceString);
echo base64_encode($signature), PHP_EOL;

// alias de certificado/publicKey/verify
$verify = $fiel->verify($sourceString, $signature);
var_dump($verify); // bool(true)

// objeto certificado
$certificado = $fiel->certificate();
echo $certificado->rfc(), PHP_EOL; // el RFC del certificado
echo $certificado->legalName(), PHP_EOL; // el nombre del propietario del certificado
echo $certificado->branchName(), PHP_EOL; // el nombre de la sucursal (en CSD, en FIEL está vacía)
echo $certificado->serialNumber()->bytes(), PHP_EOL; // número de serie del certificado

Acerca de los archivos de certificado y llave privada

Los archivos de certificado vienen en formato X.509 DER y los de llave privada en formato PKCS#8 DER. Ambos formatos no se pueden interpretar directamente en PHP (con ext-openssl), sin embargo, sí lo pueden hacer en el formato compatible PEM.

Esta librería tiene la capacidad de hacer esta conversión internamente (sin openssl), pues solo consiste en codificar a base64, en renglones de 64 caracteres y con cabeceras específicas para certificado y llave privada.

De esta forma, para usar el certificado AAA010101AAA.cer o la llave privada AAA010101AAA.key provistos por el SAT, no es necesario convertirlos con openssl y la librería los detectará correctamente.

Crear un objeto de certificado Certificate

El objeto Certificate no se creará si contiene datos no válidos.

El SAT entrega el certificado en formato X.509 DER, por lo que internamente se puede convertir a X.509 PEM. También es frecuente usar el formato X.509 DER base64, por ejemplo, en el atributo Comprobante@Certificado o en las firmas XML, por este motivo, los formatos soportados para crear un objeto Certificate son X.509 DER, X.509 DER base64 y X.509 PEM.

  • Para abrir usando un archivo local: $certificate = Certificate::openFile($filename);
  • Para abrir usando una cadena de caracteres: $certificate = new Certificate($content);
    • Si $content es un certificado en formato X.509 PEM con cabeceras ese se utiliza.
    • Si $content está totalmente en base64, se interpreta como X.509 DER base64 y se formatea a X.509 PEM
    • En otro caso, se interpreta como formato X.509 DER, por lo que se formatea a X.509 PEM.

Crear un objeto de llave privada PrivateKey

El objeto PrivateKey no se creará si contiene datos no válidos.

En SAT entrega la llave en formato PKCS#8 DER, por lo que internamente se puede convertir a PKCS#8 PEM (con la misma contraseña) y usarla desde PHP.

Una vez abierta la llave también se puede cambiar o eliminar la contraseña, creando así un nuevo objeto PrivateKey.

  • Para abrir usando un archivo local: $key = PrivateKey::openFile($filename, $passPhrase);
  • Para abrir usando una cadena de caracteres: $key = new PrivateKey($content, $passPhrase);
    • Si $content es una llave privada en formato PEM (PKCS#8 o PKCS#5) se utiliza.
    • En otro caso, se interpreta como formato PKCS#8 DER, por lo que se formatea a PKCS#8 PEM.

Notas de tratamiento de archivos DER:

  • Al convertir PKCS#8 DER a PKCS#8 PEM se determina si es una llave encriptada si se estableció una contraseña, si no se estableció se tratará como una llave plana (no encriptada).
  • No se sabe reconocer de forma automática si se trata de un archivo PKCS#5 DER por lo que este tipo de llave se deben convertir manualmente antes de intentar abrirlos, su cabecera es RSA PRIVATE KEY.
  • A diferencia de los certificados que pueden interpretar un formato DER base64, la lectura de llave privada no hace esta distinción, si desea trabajar con un formato sin caracteres especiales use PEM.

Para entender más de los formatos de llaves privadas se puede consultar la siguiente liga: https://github.com/kjur/jsrsasign/wiki/Tutorial-for-PKCS5-and-PKCS8-PEM-private-key-formats-differences

Acerca de los números de serie

Los certificados contienen un número de serie expresado en notación hexadecimal, por ejemplo, el número de serie 27 2B se refiere al certificado número 10027 expresado en decimal.

Para el SAT, sin embargo, se reconoce el número de serie no como el estándar en hexadecimal. El SAT pide que el número de serie reflejado sea la expresión hexadecimal convertida a ASCII. Luego entonces, el certificado con número de serie 3330303031303030303030333030303233373038 lo identifica como 30001000000300023708.

Esta práctica del SAT no es estándar, y no es comúnmente observada. Sin embargo, así ha decidido que se interpreten el dato de "número de serie" referido en sus certificados emitidos, por ejemplo en el atributo Comprobante@NoCertificado.

Como ejemplo contrario: En el firmado de documentos XML utilizado en el servicio web de descarga masiva, sí se utiliza la notación decimal (el número hexadecimal convertido a decimal), en lugar de la notación de bytes.

La notación de bytes es problemática porque no todos los caracteres son imprimibles o cuentan una representación gráfica. La notación hexadecimal es ligeramente problemática porque tiene muchas variantes como el uso de mayúsculas y minúsculas o el prefijo 0x. La notación decimal no tiene problema, se trata simplemente de un entero muy grande, tan grande que debe tratarse como una cadena de caracteres.

Espero que en algún futuro el SAT reconsidere y utilice una notación decimal, para referirnos al número de serie.

Leer y exportar archivos PFX

Esta librería soporta obtener el objeto Credential desde un archivo PFX (PKCS #12) y vicerversa.

Para exportar el archivo PFX:

<?php declare(strict_types=1);

use PhpCfdi\Credentials\Pfx\PfxExporter;

$credential = PhpCfdi\Credentials\Credential::openFiles(
  'certificate/certificado.cer',
  'certificate/private-key.key',
  'password'
);

$pfxExporter = new PfxExporter($credential);

// crea el binary string usando la contraseña dada
$pfxContents = $pfxExporter->export('pfx-passphrase');

// guarda el archivo pfx a la ruta local dada usando la contraseña dada
$pfxExporter->exportToFile('credential.pfx', 'pfx-passphrase');

Para leer el archivo PFX y obtener un objeto Credential:

<?php declare(strict_types=1);

use PhpCfdi\Credentials\Pfx\PfxReader;

$pfxReader = new PfxReader();

// crea un objeto Credential dado el contenido de un archivo pfx
$credential = $pfxReader->createCredentialFromContents('contenido-del-archivo', 'pfx-passphrase');

// crea un objeto Credential dada la ruta local de un archivo pfx
$credential = $pfxReader->createCredentialsFromFile('pfxFilePath', 'pfx-passphrase');

Compatibilidad

Esta librería se mantendrá compatible con al menos la versión con soporte activo de PHP más reciente.

También utilizamos Versionado Semántico 2.0.0 por lo que puedes usar esta librería sin temor a romper tu aplicación.

Contribuciones

Las contribuciones con bienvenidas. Por favor lee CONTRIBUTING para más detalles y recuerda revisar el archivo de tareas pendientes TODO y el archivo CHANGELOG.

Copyright and License

The phpcfdi/credentials library is copyright © PhpCfdi and licensed for use under the MIT License (MIT). Please see LICENSE for more information.

credentials's People

Contributors

celli33 avatar eclipxe13 avatar eislasq avatar ircsasw avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

credentials's Issues

Cannot Open Private Key

Que tal, intento utilizar la librería en laravel (lo explico para ser detallado) la cual he logrado adjuntar sin problema, pero al momento de compilar y adjuntar mis archivos no he logrado abrir el archivo .key el cual me ha arrojado el error: "Cannot open private key: error:0D08303A:asn1 encoding routines:asn1_template_noexp_d2i:nested asn1 error". Si alguien tiene alguna solución lo agradecería. Dejo el comentario para registro futuro.
image
image

CADENA FIRMA ELECTRÓNICA.

Estimado @eclipxe13, Estoy en un dilema. Necesito firmar un documento con mi E.Firma y poner el hash arrojado por el método
$certificado->publicKey()->publicKeyContents()), ¿Sabes si esto es lo correcto?.

Agradezco mucho tu apoyo.
Saludos.

Class 'App\Http\Controllers\PhpCfdi\Credentials\Credential' not found

Estoy utilizando Laravel, cuando intento hacer su código "Ejemplo básico de uso". me salta el error
Class 'App\Http\Controllers\PhpCfdi\Credentials\Credential' not found

la linea que me manda el error:
$fiel = PhpCfdi\Credentials\Credential::openFiles($cerFile, $pemKeyFile, $passPhrase);

sera que tengo que utilizar alguna linea en el inicio ejemplo
use PhpCfdi\Credentials\Credential;
y el codigo: $fiel = Credential::openFiles($cerFile, $pemKeyFile, $passPhrase);

pero me tira igual error, alguna sugerencia o tip para utilizar con laravel. se agradece cualquier información. saludos.

feat: soporte para crear pfx desde el certificado y la llave primaria

Algunos Pacs para cancelación en sector primario requieren este archivo para cancelar.
A través de openssl se puede crear el archivo usando:

openssl pkcs12 -export -inkey keyfile.key.pem -in certfile.cer.pem -out file.pfx -passin pass:'password' --passout pass:'password'

Podría ser una buena opción agregar soporte para este tipo de archivos.

load Pkcs8 Key

Hola. Hace falta que el constructor de PrivateKey pueda cargar el contenido del archivo .key tal y como está para no tener que pasarlo primero a .pem

¿Se puede saber si un CFDI está cancelado?

Hola,
Tengo una duda con el Webservice del SAT ¿se puede saber si un CFDI está cancelado?, hasta ahorita la única solución que le he encontrado es una combinación:

  • Webservice del SAT para la extracción masiva de los CFDI's vigentes
  • Web Scraping para obtener las canceladas (semi-automatizada ya que requiere la captura del captcha)

¿Habrá alguna otra forma automatizada de saber si los CFDI's están cancelados?

AYUDA CON FIRMA PFX

Que tal, soy muy nuevo en esto. Necesito firmar algunos documentos con mi efirma, pero la verdad estoy muy perdido. El SAT me entrego mi firma en formato .pfx, y al momento de hacer unas pruebas con esta librería obtengo el siguiente error:

Fatal error: Uncaught UnexpectedValueException: Invalid PKCS#12 contents or wrong passphrase

Mi código es:

declare(strict_types=1);

use PhpCfdi\Credentials\Pfx\PfxReader;

$pfxReader = new PfxReader();
$keyname = "firma.pfx";
$passphrase = "#######";

$credential = $pfxReader->createCredentialFromContents(file_get_contents($keyname), $passphrase);

Ya verifiqué:

  • La contraseña es la correcta.
  • La ubicación del archivo firma es correcta.

No entiendo por qué falla, agradecería mucho la ayuda.

Certificado Fiel o CSD

No sé si esto sea un issue pero saber si un certificado es fiel o no es posible a partir del purpose que es un arreglo en la posición [2][0] que es para que pueden ser usados dichos certificados.

Saludos.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.