Firma digital PDF en C# para España: PAdES, LOPDGDD, TicketBAI y FNMT con IronPDF
En España, la firma de facturas electrónicas no es opcional: la LOPDGDD exige integridad documental a largo plazo, el reglamento eIDAS define qué constitutye una firma electrónica avanzada válida, y TicketBAI impone XAdES sobre los XML de factura en los tres territorios forales del País Vasco — Bizkaia, Gipuzkoa y Araba. Para los PDFs de esas mismas facturas, el estándar aplicable es PAdES con certificado FNMT.
IronPDF implementa PAdES en C# con la clase PdfSignature. Esta guía explica cuándo y por qué aplicar cada estándar de firma en el ecosistema español, con ejemplos de producción para VeriFactu, TicketBAI y archivado conforme a LOPDGDD.
Cómo añadir una firma digital PDF en C# (con cumplimiento para España)
- Instalar biblioteca C# para añadir firma digital a PDF
- Preparar el certificado: FNMT para España, PAdES para archivado conforme a LOPDGDD y eIDAS
- Pasar el certificado y la contraseña a la clase
PdfSignature - Utilizar el método
SignPdfFileoSignpara aplicar la firma al PDF - Verificar el PDF firmado y configurar el archivado según los requisitos de LOPDGDD
Paso 1
1. Obtener IronPDF
Instale IronPDF en su proyecto de Visual Studio. Puede descargarlo desde la descarga de DLL o desde NuGet. Para proyectos de facturación española, asegúrese de tener también un certificado válido — en España, los certificados más habituales son emitidos por la FNMT (Fábrica Nacional de Moneda y Timbre) u otras autoridades de certificación reconocidas por la AEAT.
# Product Installation using NuGet
nuget install IronPdf
# Product Installation using NuGet
nuget install IronPdf
Tutorial de cómo hacerlo
2. El mapa de firmas digitales en la facturación electrónica española
El desarrollador que trabaja con facturación en España se enfrenta a tres marcos normativos simultáneos, cada uno con su propio estándar de firma:
eIDAS y PAdES: la firma del PDF El reglamento eIDAS define los niveles de firma electrónica reconocidos en toda la UE. Para documentos PDF — facturas, contratos, informes — el estándar aplicable bajo eIDAS es PAdES (PDF Advanced Electronic Signatures). Para archivado conforme a la LOPDGDD (Ley Orgánica de Protección de Datos y Garantía de Derechos Digitales), se recomienda PAdES-LTV: incorpora los datos de validación OCSP y los sellos de tiempo necesarios para verificar la firma incluso cuando el certificado original haya expirado, décadas después de la firma.
TicketBAI y XAdES: la firma del XML foral En el País Vasco, TicketBAI exige firmar el fichero XML de cada factura con XAdES antes de enviarlo a la hacienda foral. Las tres haciendas tienen portales y especificaciones propias:
- Bizkaia (
bizkaia.eus) — también gestiona el programa BATUZ - Gipuzkoa (
gipuzkoa.eus) - Araba (
araba.eus)
La firma XAdES se aplica al XML antes de generar el PDF. IronPDF gestiona la firma PAdES del documento PDF resultante; la firma XAdES del XML requiere una biblioteca XML adicional.
VeriFactu y la AEAT
Para el software de facturación sujeto a VeriFactu (Royal Decree-Law 15/2025, obligatorio a partir de 2027), la AEAT exige que cada factura lleve la leyenda VERI*FACTU o Factura verificable en la sede electrónica de la AEAT con su código QR. El PDF generado con esta información puede firmarse con PAdES usando IronPDF para garantizar la integridad del documento archivado.
La FNMT como CA de referencia
La Fábrica Nacional de Moneda y Timbre emite los certificados reconocidos por la AEAT y las haciendas forales. Sus certificados en formato .pfx son el estándar de facto para ISVs de facturación en España.
3. Firmar digitalmente un PDF con IronPDF (aplicación Windows Form)
A continuación se muestra un ejemplo básico de firma digital con x509certificate2 en C#.
Se debe preparar un .pfx file (Formato de Intercambio de Información Personal), que agrupa el certificado con su clave privada. En entornos de producción para facturación española, este fichero corresponde típicamente a un certificado FNMT o equivalente.
El método SignPdfFile(FileName) de la clase PdfSignature aplica la firma digital al PDF.
using System.Drawing;
using System.Windows.Forms;
using IronPdf;
namespace DigitalSign
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, System.EventArgs e)
{
// Open a dialog to select the desired PDF file
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
textBox1.Text = openFileDialog1.FileName; // Display selected PDF path in the textbox
}
}
private void button2_Click(object sender, System.EventArgs e)
{
// Use PdfSignature method to digitally sign the selected PDF
new PdfSignature("Ironpdf.pfx", "123456").SignPdfFile(textBox1.Text);
// Provide user feedback that signing is complete
label3.Text = "Completed!";
label3.BackColor = Color.LightGreen;
label3.ForeColor = Color.Black;
}
}
}
using System.Drawing;
using System.Windows.Forms;
using IronPdf;
namespace DigitalSign
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, System.EventArgs e)
{
// Open a dialog to select the desired PDF file
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
textBox1.Text = openFileDialog1.FileName; // Display selected PDF path in the textbox
}
}
private void button2_Click(object sender, System.EventArgs e)
{
// Use PdfSignature method to digitally sign the selected PDF
new PdfSignature("Ironpdf.pfx", "123456").SignPdfFile(textBox1.Text);
// Provide user feedback that signing is complete
label3.Text = "Completed!";
label3.BackColor = Color.LightGreen;
label3.ForeColor = Color.Black;
}
}
}
Imports System.Drawing
Imports System.Windows.Forms
Imports IronPdf
Namespace DigitalSign
Partial Public Class Form1
Inherits Form
Public Sub New()
InitializeComponent()
End Sub
Private Sub button1_Click(ByVal sender As Object, ByVal e As System.EventArgs)
' Open a dialog to select the desired PDF file
If openFileDialog1.ShowDialog() = System.Windows.Forms.DialogResult.OK Then
textBox1.Text = openFileDialog1.FileName ' Display selected PDF path in the textbox
End If
End Sub
Private Sub button2_Click(ByVal sender As Object, ByVal e As System.EventArgs)
' Use PdfSignature method to digitally sign the selected PDF
Call (New PdfSignature("Ironpdf.pfx", "123456")).SignPdfFile(textBox1.Text)
' Provide user feedback that signing is complete
label3.Text = "Completed!"
label3.BackColor = Color.LightGreen
label3.ForeColor = Color.Black
End Sub
End Class
End Namespace
El código C# anterior representa una aplicación Windows Form donde:
- Un botón abre un cuadro de diálogo para seleccionar el archivo PDF a firmar.
- Un segundo botón aplica la firma digital al PDF seleccionado usando el fichero
.pfxy su contraseña. - Las etiquetas se actualizan para confirmar la finalización del proceso de firma.
4. Firma PAdES para facturación española: ejemplo avanzado
Para aplicaciones de facturación que deben cumplir con VeriFactu o generar documentos archivables bajo LOPDGDD, el flujo de firma requiere más configuración que una firma básica. A continuación se muestra el patrón para producción:
using IronPdf;
using IronPdf.Signing;
using System;
using System.IO;
namespace FirmaFacturasEspana
{
public class ServicioFirmaFacturas
{
// Firma un PDF de factura con PAdES para cumplimiento eIDAS/LOPDGDD
// Certificado recomendado: FNMT Clase 2 CA o equivalente reconocido por AEAT
public static void FirmarFacturaPades(
string rutaPdfFactura,
string rutaCertificadoPfx,
string passwordCert,
string razonFirma = "Factura electrónica conforme eIDAS/LOPDGDD")
{
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
var documento = PdfDocument.FromFile(rutaPdfFactura);
// Configurar la firma PAdES con metadatos de cumplimiento
var firma = new PdfSignature(rutaCertificadoPfx, passwordCert)
{
SigningContact = "facturacion@miempresa.com",
SigningLocation = "España",
SigningReason = razonFirma
};
// Aplicar firma PAdES al PDF
documento.Sign(firma);
string rutaSalida = rutaPdfFactura.Replace(".pdf", "_firmado_pades.pdf");
documento.SaveAs(rutaSalida);
Console.WriteLine($"Factura firmada con PAdES: {rutaSalida}");
}
// Firma en lote para cierres mensuales (VeriFactu / SII)
public static void FirmarLoteFacturas(
string directorioFacturas,
string rutaCertificadoPfx,
string passwordCert)
{
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
// Cargar el certificado una sola vez fuera del bucle — más eficiente
var firma = new PdfSignature(rutaCertificadoPfx, passwordCert)
{
SigningReason = "Lote de facturas — conforme VeriFactu/SII"
};
string[] rutasFacturas = Directory.GetFiles(directorioFacturas, "*.pdf");
foreach (string rutaFactura in rutasFacturas)
{
var doc = PdfDocument.FromFile(rutaFactura);
doc.Sign(firma);
doc.SaveAs(rutaFactura.Replace(".pdf", "_firmado.pdf"));
}
Console.WriteLine($"Lote firmado: {rutasFacturas.Length} facturas procesadas.");
}
}
}
using IronPdf;
using IronPdf.Signing;
using System;
using System.IO;
namespace FirmaFacturasEspana
{
public class ServicioFirmaFacturas
{
// Firma un PDF de factura con PAdES para cumplimiento eIDAS/LOPDGDD
// Certificado recomendado: FNMT Clase 2 CA o equivalente reconocido por AEAT
public static void FirmarFacturaPades(
string rutaPdfFactura,
string rutaCertificadoPfx,
string passwordCert,
string razonFirma = "Factura electrónica conforme eIDAS/LOPDGDD")
{
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
var documento = PdfDocument.FromFile(rutaPdfFactura);
// Configurar la firma PAdES con metadatos de cumplimiento
var firma = new PdfSignature(rutaCertificadoPfx, passwordCert)
{
SigningContact = "facturacion@miempresa.com",
SigningLocation = "España",
SigningReason = razonFirma
};
// Aplicar firma PAdES al PDF
documento.Sign(firma);
string rutaSalida = rutaPdfFactura.Replace(".pdf", "_firmado_pades.pdf");
documento.SaveAs(rutaSalida);
Console.WriteLine($"Factura firmada con PAdES: {rutaSalida}");
}
// Firma en lote para cierres mensuales (VeriFactu / SII)
public static void FirmarLoteFacturas(
string directorioFacturas,
string rutaCertificadoPfx,
string passwordCert)
{
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
// Cargar el certificado una sola vez fuera del bucle — más eficiente
var firma = new PdfSignature(rutaCertificadoPfx, passwordCert)
{
SigningReason = "Lote de facturas — conforme VeriFactu/SII"
};
string[] rutasFacturas = Directory.GetFiles(directorioFacturas, "*.pdf");
foreach (string rutaFactura in rutasFacturas)
{
var doc = PdfDocument.FromFile(rutaFactura);
doc.Sign(firma);
doc.SaveAs(rutaFactura.Replace(".pdf", "_firmado.pdf"));
}
Console.WriteLine($"Lote firmado: {rutasFacturas.Length} facturas procesadas.");
}
}
}
Imports IronPdf
Imports IronPdf.Signing
Imports System
Imports System.IO
Namespace FirmaFacturasEspana
Public Class ServicioFirmaFacturas
' Firma un PDF de factura con PAdES para cumplimiento eIDAS/LOPDGDD
' Certificado recomendado: FNMT Clase 2 CA o equivalente reconocido por AEAT
Public Shared Sub FirmarFacturaPades(rutaPdfFactura As String, rutaCertificadoPfx As String, passwordCert As String, Optional razonFirma As String = "Factura electrónica conforme eIDAS/LOPDGDD")
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY"
Dim documento = PdfDocument.FromFile(rutaPdfFactura)
' Configurar la firma PAdES con metadatos de cumplimiento
Dim firma = New PdfSignature(rutaCertificadoPfx, passwordCert) With {
.SigningContact = "facturacion@miempresa.com",
.SigningLocation = "España",
.SigningReason = razonFirma
}
' Aplicar firma PAdES al PDF
documento.Sign(firma)
Dim rutaSalida As String = rutaPdfFactura.Replace(".pdf", "_firmado_pades.pdf")
documento.SaveAs(rutaSalida)
Console.WriteLine($"Factura firmada con PAdES: {rutaSalida}")
End Sub
' Firma en lote para cierres mensuales (VeriFactu / SII)
Public Shared Sub FirmarLoteFacturas(directorioFacturas As String, rutaCertificadoPfx As String, passwordCert As String)
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY"
' Cargar el certificado una sola vez fuera del bucle — más eficiente
Dim firma = New PdfSignature(rutaCertificadoPfx, passwordCert) With {
.SigningReason = "Lote de facturas — conforme VeriFactu/SII"
}
Dim rutasFacturas As String() = Directory.GetFiles(directorioFacturas, "*.pdf")
For Each rutaFactura As String In rutasFacturas
Dim doc = PdfDocument.FromFile(rutaFactura)
doc.Sign(firma)
doc.SaveAs(rutaFactura.Replace(".pdf", "_firmado.pdf"))
Next
Console.WriteLine($"Lote firmado: {rutasFacturas.Length} facturas procesadas.")
End Sub
End Class
End Namespace
5. Gestión de certificados FNMT en producción
Para entornos de producción que gestionan la firma de facturas bajo VeriFactu o TicketBAI, almacene el certificado .pfx de forma segura — no en el sistema de ficheros del servidor ni en el control de versiones:
// Cargar certificado FNMT desde variable de entorno
// (recomendado para sistemas de facturación certificados VeriFactu)
string certBase64 = Environment.GetEnvironmentVariable("FACTURACION_CERT_PFX")
?? throw new InvalidOperationException("Certificado FNMT no configurado.");
byte[] certBytes = Convert.FromBase64String(certBase64);
string certPassword = Environment.GetEnvironmentVariable("FACTURACION_CERT_PASSWORD")
?? throw new InvalidOperationException("Contraseña del certificado no configurada.");
var firma = new IronPdf.Signing.PdfSignature(certBytes, certPassword)
{
SigningReason = "Factura electrónica — certificado FNMT",
SigningLocation = "España"
};
// Cargar certificado FNMT desde variable de entorno
// (recomendado para sistemas de facturación certificados VeriFactu)
string certBase64 = Environment.GetEnvironmentVariable("FACTURACION_CERT_PFX")
?? throw new InvalidOperationException("Certificado FNMT no configurado.");
byte[] certBytes = Convert.FromBase64String(certBase64);
string certPassword = Environment.GetEnvironmentVariable("FACTURACION_CERT_PASSWORD")
?? throw new InvalidOperationException("Contraseña del certificado no configurada.");
var firma = new IronPdf.Signing.PdfSignature(certBytes, certPassword)
{
SigningReason = "Factura electrónica — certificado FNMT",
SigningLocation = "España"
};
' Cargar certificado FNMT desde variable de entorno
' (recomendado para sistemas de facturación certificados VeriFactu)
Dim certBase64 As String = Environment.GetEnvironmentVariable("FACTURACION_CERT_PFX")
If certBase64 Is Nothing Then Throw New InvalidOperationException("Certificado FNMT no configurado.")
Dim certBytes As Byte() = Convert.FromBase64String(certBase64)
Dim certPassword As String = Environment.GetEnvironmentVariable("FACTURACION_CERT_PASSWORD")
If certPassword Is Nothing Then Throw New InvalidOperationException("Contraseña del certificado no configurada.")
Dim firma = New IronPdf.Signing.PdfSignature(certBytes, certPassword) With {
.SigningReason = "Factura electrónica — certificado FNMT",
.SigningLocation = "España"
}
Este patrón permite rotar el certificado FNMT cuando caduca sin modificar el código: basta con actualizar la variable de entorno y reiniciar el servicio.
6. ¿Qué ocurre si no se firma el PDF de factura?
En el contexto regulatorio español, un PDF de factura sin firma PAdES válida presenta riesgos en tres frentes:
Integridad bajo LOPDGDD: la LOPDGDD exige que los registros de actividad con datos personales mantengan su integridad durante todo el periodo de retención. Un PDF sin firma verificable no acredita que el documento no fue alterado después de su emisión — exposición ante la AEPD en caso de incidencia.
Verificabilidad VeriFactu: aunque VeriFactu no exige explícitamente firma PAdES en el PDF (el control de integridad se realiza mediante la huella encadenada en el XML), el PDF firmado refuerza la cadena de custodia documental exigible ante la AEAT.
Validez ante haciendas forales: en TicketBAI, el PDF es el documento de presentación al cliente. Una firma PAdES válida con certificado FNMT aporta la garantía de autenticidad exigible en los tres territorios forales — Bizkaia, Gipuzkoa y Araba — donde el incumplimiento puede implicar sanciones de la hacienda foral correspondiente.
7. Revisar la firma del documento


Un PDF firmado con IronPDF y certificado FNMT puede verificarse en Adobe Acrobat Reader o en cualquier visor compatible con firmas digitales. Para el ecosistema español, la verificación debe ser posible desde los sistemas de la AEAT, las plataformas de las haciendas forales del País Vasco y los gestores documentales de las Administraciones Públicas que reciben facturas Facturae a través de FACe.
La firma PAdES también es verificable mediante el Servicio de Validación de Firma de la @firma (plataforma del Ministerio de Asuntos Económicos), garantizando la interoperabilidad con los sistemas de las AAPP.
IronPDF simplifica la implementación de firma digital PAdES en C# para el ecosistema español. Además de la firma conforme a PAdES/eIDAS/LOPDGDD, IronPDF permite renderizar documentos PDF en imágenes, extraer texto, generar PDFs con código QR AEAT para facturas VeriFactu, aplicar contraseñas de seguridad, marcas de agua y gestionar formularios PDF programáticamente.
Acceso rápido a la biblioteca
Referencia API
Lea la documentación de IronPDF y la lista completa de funciones, incluyendo PdfSignature para firma PAdES conforme a eIDAS.
Referencia APIPreguntas Frecuentes
¿Qué estándar de firma se usa para PDFs en el ecosistema de facturación español?
Para PDFs, se utiliza PAdES (PDF Advanced Electronic Signatures), el estándar bajo eIDAS para documentos PDF. Para archivado a largo plazo conforme a LOPDGDD, se recomienda PAdES-LTV (Long-Term Validation). IronPDF aplica PAdES mediante la clase PdfSignature con un certificado FNMT o equivalente reconocido por la AEAT.
¿Para qué sirve XAdES en el ecosistema español y cómo se relaciona con IronPDF?
XAdES (XML Advanced Electronic Signatures) se usa para firmar los ficheros XML de TicketBAI antes de enviarlos a las haciendas forales del País Vasco (Bizkaia, Gipuzkoa, Araba). IronPDF gestiona la firma PAdES del PDF de presentación generado tras el registro del XML TicketBAI firmado. Los dos estándares son complementarios: XAdES para el XML, PAdES para el PDF.
¿Qué certificado se usa para firmar PDFs de facturas en España?
El certificado más habitual en el ecosistema empresarial español es el emitido por la FNMT (Fábrica Nacional de Moneda y Timbre). Sus certificados en formato .pfx son reconocidos por la AEAT, las haciendas forales del País Vasco y las Administraciones Públicas que reciben facturas Facturae. Para entornos de prueba, la AEAT ofrece certificados de test en su sede electrónica.
¿Cómo se firma en lote para VeriFactu o el SII con IronPDF?
Se instancia PdfSignature una sola vez fuera del bucle de procesamiento (con el certificado FNMT ya cargado) y se aplica a cada PDF del lote con Sign(). Este patrón es más eficiente que recargar el certificado por cada factura y es el recomendado para cierres mensuales del SII o lotes VeriFactu.


