Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/eclipxe13/CfdiUtils/llms.txt

Use this file to discover all available pages before exploring further.

Mexican digital tax invoices are signed with an X.509 certificate issued by the SAT. The CfdiUtils\Certificado\Certificado class loads these certificate files, parses them with PHP’s OpenSSL extension, and exposes all the fields you need — RFC, serial number, validity dates, public key — through a clean getter API. The class accepts both PEM format (plain Base64 text with -----BEGIN CERTIFICATE----- headers) and DER/CER binary format. When given a CER binary file, the class converts it to PEM internally before parsing; your code does not need to handle the conversion.

Available Getters

Once a certificate is loaded, the following methods are available:
MethodReturn typeDescription
getRfc()stringRFC (Registro Federal de Contribuyentes) embedded in the certificate’s subject
getName(bool $trimSuffix = false)stringRazón Social (business name) from the certificate subject; pass true to strip the régimen de capital suffix
getNameWithoutRegimenCapitalSuffix()stringBusiness name with common capital regime suffixes removed (e.g. “SA DE CV”)
getCertificateName()stringFull certificate name string as returned by OpenSSL
getSerial()stringSerial number in ASCII format — this is the value required by the NoCertificado attribute in CFDI
getSerialObject()SerialNumberA cloned SerialNumber object for converting between ASCII, hexadecimal, and decimal formats
getValidFrom()intUnix timestamp from which the certificate is valid
getValidTo()intUnix timestamp until which the certificate is valid
getPubkey()stringPublic key in PEM format
getPemContents()stringFull PEM representation of the certificate
getPemContentsOneLine()stringPEM certificate body as a single line (useful for embedding in CFDI XML)
getFilename()stringThe file path used when loading (empty string if loaded from raw contents)

Load a Certificate

Instantiate Certificado with the path to a CER or PEM file:
<?php
use CfdiUtils\Certificado\Certificado;

// Load from a binary CER file (DER format — converted to PEM internally)
$cerFile = '/certificates/EKU9003173C9.cer';
$certificate = new Certificado($cerFile);

echo $certificate->getRfc();      // 'EKU9003173C9'
echo $certificate->getName();     // 'ESCUELA KEMPER URGATE SA DE CV'
echo $certificate->getSerial();   // '30001000000300023708'
echo date('Y-m-d', $certificate->getValidFrom()); // '2019-09-24'
echo date('Y-m-d', $certificate->getValidTo());   // '2023-09-23'
You can also pass the raw PEM string content directly as the constructor argument (the constructor detects whether the value is a path or raw content).

Verify a Signature

verify() checks that a given binary signature over a data string is valid according to this certificate’s public key. This is exactly the operation used when validating the CFDI sello against the Cadena de Origen.
<?php
public function verify(string $data, string $signature, int $algorithm = OPENSSL_ALGO_SHA256): bool
data
string
required
The plaintext data that was signed (e.g., the Cadena de Origen string).
signature
string
required
The raw binary signature to verify (decode from Base64 before passing).
algorithm
int
default:"OPENSSL_ALGO_SHA256"
The OpenSSL digest algorithm constant. CFDI uses OPENSSL_ALGO_SHA256.
<?php
$cadenaOrigen = '||4.0|2024-01-15T10:00:00|...||'; // generated by DOMBuilder
$selloBase64  = $cfdiNode['Sello'];                  // from the CFDI XML attribute
$sello        = base64_decode($selloBase64);

$isValid = $certificate->verify($cadenaOrigen, $sello);
echo $isValid ? 'Sello válido' : 'Sello inválido';

Check That a Private Key Belongs to This Certificate

belongsTo() uses OpenSSL to confirm that a given PEM private key file is the cryptographic counterpart of this certificate’s public key. Use this before signing to make sure the key and certificate are a matching pair.
<?php
public function belongsTo(string $pemKeyFile, string $passPhrase = ''): bool
pemKeyFile
string
required
Absolute path to a PEM-format private key file. The private key must already be in PEM format — convert from KEY (PKCS#8 DER) first if needed.
passPhrase
string
default:"\"\""
Optional passphrase for an encrypted PEM key.
<?php
$certificate = new \CfdiUtils\Certificado\Certificado('/certs/EKU9003173C9.cer');
$pemKeyPath  = '/certs/EKU9003173C9.key.pem';

if ($certificate->belongsTo($pemKeyPath)) {
    echo 'La llave privada corresponde al certificado';
} else {
    echo 'La llave privada NO corresponde al certificado';
}
To convert a SAT KEY file to PEM before use:
openssl pkcs8 -inform DER -in EKU9003173C9.key -out EKU9003173C9.key.pem

Serial Number Formats

The SAT requires the ASCII representation of the serial number in the NoCertificado attribute, but you may need hexadecimal or decimal for logging or other systems. Obtain a SerialNumber object with getSerialObject():
<?php
$serial = $certificate->getSerialObject(); // returns a clone — SerialNumber is mutable

echo $serial->asAscii();        // '30001000000300023708'  (same as getSerial())
echo $serial->getHexadecimal(); // '3330303031303030303030333030303233373038'
echo $serial->asDecimal();      // '292233162870206001759766198425879490508935868472'
getSerialObject() returns a clone, not the internal instance, because SerialNumber is mutable. Future versions of CfdiUtils will make SerialNumber immutable and return the internal instance directly.

NodeCertificado: Extract a Certificate from a CFDI Node

When reading an existing CFDI, the certificate is embedded in the cfdi:Comprobante@Certificado attribute as Base64. CfdiUtils\Certificado\NodeCertificado extracts, decodes, and optionally saves it.
MethodDescription
extract(): stringReads Certificado attribute from the node and decodes it from Base64
save(string $filename): voidWrites the extracted binary certificate to a file
obtain(): CertificadoDecodes the certificate from the Certificado attribute and returns a loaded Certificado instance
<?php
use CfdiUtils\Certificado\NodeCertificado;
use CfdiUtils\Nodes\XmlNodeUtils;

// Load the CFDI XML and parse into a Node tree
$cfdiNode = XmlNodeUtils::nodeFromXmlString(
    file_get_contents('/cfdis/FE-00012847.xml')
);

// Extract the certificate embedded in the CFDI
$certificate = (new NodeCertificado($cfdiNode))->obtain();

echo $certificate->getRfc();    // 'EKU9003173C9'
echo $certificate->getSerial(); // '30001000000300023708'

Working with OpenSSL Command-Line Tools

The following commands are useful for inspecting and converting SAT certificate and key files outside of PHP:
# View certificate details (dates, subject, serial, public key)
openssl x509 -nameopt utf8,sep_multiline,lname -inform DER -noout \
  -dates -serial -subject -fingerprint -pubkey -in EKU9003173C9.cer

# Convert private key from DER (KEY) to PEM
openssl pkcs8 -inform DER -in EKU9003173C9.key -out EKU9003173C9.key.pem

# Add a passphrase to a PEM private key
openssl rsa -in EKU9003173C9.key.pem -des3 -out EKU9003173C9_password.key.pem

# Convert certificate from DER (CER) to PEM
openssl x509 -inform DER -outform PEM -in EKU9003173C9.cer -pubkey -out EKU9003173C9.cer.pem

Build docs developers (and LLMs) love