The SAT (Mexico’s tax authority) delivers digital certificates and private keys in binary DER formats that PHP cannot use directly. TheDocumentation 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.
CfdiUtils\OpenSSL\OpenSSL class bridges that gap: it converts CER certificates and KEY private keys into the PEM format that PHP’s OpenSSL functions require, and provides helpers for reading, protecting, and unprotecting PEM content. It is not a reimplementation of OpenSSL — it orchestrates calls to the external openssl command when native PHP cannot perform the operation.
File Format Overview
Understanding the three file formats you encounter when working with SAT certificates is essential before using any conversion method.CER — X.509 DER Certificate
CER — X.509 DER Certificate
.cer extension from the SAT are X.509 certificates encoded in DER (Distinguished Encoding Rules) — a compact binary format. PHP cannot load a DER certificate directly; it requires the PEM encoding. Converting CER to PEM only requires base64-encoding the raw bytes and wrapping them in the standard -----BEGIN CERTIFICATE----- / -----END CERTIFICATE----- delimiters, so this conversion can be done entirely in PHP without calling the external openssl binary.KEY — PKCS#8 DER Private Key
KEY — PKCS#8 DER Private Key
.key extension from the SAT are private keys encoded in PKCS#8 DER format. Unlike CER files, converting a PKCS#8 DER private key to PEM is not something PHP can do on its own. The external openssl binary must be called to perform this conversion.PEM — Privacy Enhanced Mail Container
PEM — Privacy Enhanced Mail Container
-----BEGIN <TYPE>----- / -----END <TYPE>----- header/footer pair, and the content is base64-encoded (64 characters per line). A single PEM file may contain multiple sections.LF) or Windows (CRLF) line endings. CfdiUtils normalises line endings to PHP_EOL when reading PEM content.CER to PEM Conversion
Because a CER-to-PEM conversion is just base64 encoding plus header/footer text, CfdiUtils provides two paths: a pure-PHP method and anopenssl-backed method. Both produce the same output.
Method reference
derCerConvertPhp(string $derContent): string
derCerConvertPhp(string $derContent): string
-----BEGIN CERTIFICATE----- / -----END CERTIFICATE----- delimiters with base64 content at 64 characters per line..cer (X.509 DER) file.derCerConvert(string $derInFile, string $pemOutFile): void
derCerConvert(string $derInFile, string $pemOutFile): void
openssl binary..cer (X.509 DER) file. Must exist and be non-empty.derCerConvertOut(string $derInFile): string
derCerConvertOut(string $derInFile): string
.cer file.derCerConvertInOut(string $derContents): string
derCerConvertInOut(string $derContents): string
derCerConvertOut, and removes the temp file.KEY to PEM Conversion
Converting a PKCS#8 DER private key requires the externalopenssl binary. Passwords are passed via environment variables (not command-line arguments) to minimise exposure.
Method reference
derKeyConvert(string $derInFile, string $inPassPhrase, string $pemOutFile): void
derKeyConvert(string $derInFile, string $inPassPhrase, string $pemOutFile): void
openssl binary..key (PKCS#8 DER) file.derKeyConvertOut(string $derInFile, string $inPassPhrase): string
derKeyConvertOut(string $derInFile, string $inPassPhrase): string
derKeyProtect(string $derInFile, string $inPassPhrase, string $pemOutFile, string $outPassPhrase): void
derKeyProtect(string $derInFile, string $inPassPhrase, string $pemOutFile, string $outPassPhrase): void
derKeyConvert followed by pemKeyProtect..key (PKCS#8 DER) file.derKeyProtectOut(string $pemInFile, string $inPassPhrase, string $outPassPhrase): string
derKeyProtectOut(string $pemInFile, string $inPassPhrase, string $outPassPhrase): string
derKeyProtect but returns the password-protected PEM content as a string instead of writing a file..key (PKCS#8 DER) file.pemKeyProtect(string $pemInFile, string $inPassPhrase, string $pemOutFile, string $outPassPhrase): void
pemKeyProtect(string $pemInFile, string $inPassPhrase, string $pemOutFile, string $outPassPhrase): void
$outPassPhrase is an empty string, delegates to pemKeyUnprotect to produce an unprotected file. This function is non-deterministic — the same key and password will produce different output on each call.pemKeyProtectOut / pemKeyProtectInOut
pemKeyProtectOut / pemKeyProtectInOut
pemKeyProtectOut(string $pemInFile, string $inPassPhrase, string $outPassPhrase): string — returns the re-encrypted PEM as a string.pemKeyProtectInOut(string $pemContents, string $inPassPhrase, string $outPassPhrase): string — accepts PEM content directly (no input file path needed) and returns the re-encrypted PEM as a string.pemKeyUnprotect(string $pemInFile, string $inPassPhrase, string $pemOutFile): void
pemKeyUnprotect(string $pemInFile, string $inPassPhrase, string $pemOutFile): void
$pemOutFile. Calls the external openssl binary.pemKeyUnprotectOut / pemKeyUnprotectInOut
pemKeyUnprotectOut / pemKeyUnprotectInOut
pemKeyUnprotectOut(string $pemInFile, string $inPassPhrase): string — returns the unprotected PEM as a string.pemKeyUnprotectInOut(string $pemContents, string $inPassPhrase): string — accepts PEM content directly and returns the unprotected PEM as a string.PEM File Reading — PemContainer and PemExtractor
CfdiUtils provides two methods for reading PEM files or strings into a typed PemContainer object. These methods also normalise line endings to PHP_EOL and strip any trailing newline from each section.
PemContainer exposes three section pairs:
| Checker | Accessor | Section header |
|---|---|---|
hasCertificate(): bool | certificate(): string | CERTIFICATE |
hasPublicKey(): bool | publicKey(): string | PUBLIC KEY |
hasPrivateKey(): bool | privateKey(): string | PRIVATE KEY / RSA PRIVATE KEY / ENCRYPTED PRIVATE KEY |
PemExtractor validates that section content contains only Base64 characters ([A-Za-z0-9+/=]) and newlines. Sections that fail this check are silently discarded. It does not verify that the Base64 payload is a valid certificate or key.PemPrivateKey
CfdiUtils\PemPrivateKey\PemPrivateKey is a convenience wrapper around PHP’s openssl_pkey_get_private and openssl_sign for working with private keys that have already been converted to PEM format.
PemPrivateKey method reference
file://-prefixed path or raw PEM content. Throws UnexpectedValueException if no private key section can be found in the given content or file.true on success, false if the passphrase is wrong. Must be called before sign() or belongsTo().true if the key has been successfully opened and has not been closed.$data using the open private key. Returns the raw binary signature string. Throws RuntimeException if the key is not open or signing fails.true if the private key belongs to the certificate given as a PEM string. The key must be open before calling this method — a RuntimeException is thrown if the key has not been opened with open().Constructor and Configuration
openssl executable. When empty the string "openssl" is used, relying on the system PATH.General Rules and Security Notes
Input file validation
Input file validation
OpenSSLException is thrown if any check fails.Output file validation
Output file validation
Password security
Password security
PASSIN, PASSOUT) when invoking openssl, which is the best available mechanism for reducing password exposure on most operating systems.Control characters
Control characters
openssl command may contain control characters other than CR (\r) and LF (\n). This prevents shell injection via crafted file paths or passwords.Exceptions
| Exception | When thrown |
|---|---|
CfdiUtils\OpenSSL\OpenSSLException | General error in any OpenSSL utility method (file checks, empty results, etc.) |
CfdiUtils\OpenSSL\OpenSSLCallerException | The external openssl command exited with a non-zero status. Exposes getCallResponse(): CallResponse with the executed command, stdout, stderr, and exit code. |