Documentation Index
Fetch the complete documentation index at: https://mintlify.com/Eseperio/verifactu-php/llms.txt
Use this file to discover all available pages before exploring further.
XmlSignerService applies a XAdES Enveloped digital signature to an XML document using the taxpayer’s digital certificate. AEAT requires every VERI*FACTU SOAP submission to carry a valid ds:Signature element, produced with the RSA-SHA256 algorithm and an Exclusive C14N canonicalisation method.
Namespace: eseperio\verifactu\services\XmlSignerService
Requires: robrichards/xmlseclibs ^3.0 (declared as a Composer dependency).
What is XAdES Enveloped signing?
XAdES (XML Advanced Electronic Signatures) is a family of W3C-based XML digital signature formats. The Enveloped variant means the<ds:Signature> element is inserted inside the signed XML document — the signature and the signed content travel together in one XML tree.
AEAT mandates this approach for VERI*FACTU because:
- The signed content is the invoice record (
RegistroAltaor the fullRegFactuSistemaFacturacionwrapper), not an external reference. - The signature must survive SOAP envelope processing without being detached.
- The
ds:Signaturereferences the root element via a URI and includes theenveloped-signaturetransform so the signing algorithm can exclude the signature block itself from the digest.
XMLDSig with RSA-SHA256 and EXC-C14N canonicalisation) and embeds the signing certificate’s public key in the ds:KeyInfo / ds:X509Data block.
Method
signXml(string $xmlString, string $certPath, string $certPassword): string|false
Loads the certificate and private key from the specified file, applies an XAdES Enveloped signature to the XML, and returns the signed XML string.
A well-formed XML string to sign. The
<ds:Signature> element will be appended as the last child of the document’s root element.Absolute path to the digital certificate file. Supported formats:
.pfx/.p12— PKCS#12 bundle (certificate + private key)..pem— PEM file containing both anX.509certificate block and a private key block.
Password for the certificate. Pass an empty string
'' for unprotected PEM files.<?xml ...?> declaration. Returns false if signing fails (in practice, exceptions are thrown before this case is reached).
Throws:
\RuntimeException—robrichards/xmlseclibslibrary not found; certificate or key loading failure.\Exception— The input string is not valid XML.
Signing algorithm details
| Property | Value |
|---|---|
| Signature algorithm | RSA-SHA256 (XMLSecurityKey::RSA_SHA256) |
| Canonicalisation | Exclusive C14N (XMLSecurityDSig::EXC_C14N) |
| Digest method | SHA-256 (XMLSecurityDSig::SHA256) |
| Transform | enveloped-signature (http://www.w3.org/2000/09/xmldsig#enveloped-signature) |
| Key info | ds:X509Certificate (PEM, base64-encoded) + ds:X509SubjectName |
| Signature placement | Appended as last child of the XML root element |
When the library calls this automatically
XmlSignerService::signXml() is invoked internally in two places:
VerifactuService::registerInvoice() — signs the RegistroAlta DOM document before it is wrapped inside the RegFactuSistemaFacturacion structure. The signature therefore covers only the invoice record element.
VerifactuService::cancelInvoice() — signs the fully-wrapped RegFactuSistemaFacturacion XML (after the RegistroAnulacion is embedded). The signature therefore covers the entire submission envelope.
In both cases the certificate path and password are read from VerifactuService’s global configuration (certPath / certPassword keys). You do not need to manage the signing step yourself.
When to call manually
CallsignXml() directly when you:
- Need to sign XML outside of a
registerInvoice()/cancelInvoice()flow (e.g. event records viaEventDispatcherService). - Are building a custom submission pipeline and want fine-grained control over when signing occurs.
- Need to verify that your certificate produces a valid signature before going to production.
Code examples
Basic manual signing
Signing a PEM certificate
Verifying the certificate works before production
Troubleshooting
xmlseclibs library is required for XML signing
Install the dependency:
Invalid XML provided for signing
The $xmlString argument could not be parsed as XML. Ensure the string is well-formed and UTF-8 encoded before passing it to signXml().
AEAT rejects with error code 100 (La firma de la petición SOAP no es válida)
This means AEAT could not verify the digital signature. Common causes:
- The certificate is not approved for VERI*FACTU (must be an electronic seal or qualified certificate registered with AEAT).
- The certificate is expired — check with
CertificateManagerService::isValid(). - The XML was modified after signing (e.g. whitespace normalisation by an intermediate HTTP layer).
- The certificate is on AEAT’s block list (error code 106).