Skip to content

Firma Digital XAdES

Jacobo Cantorna Cigarrán edited this page Sep 17, 2026 · 2 revisions

Firma digital XAdES

SignatureService firma documentos XML con firma electrónica avanzada XAdES, usando la librería EU DSS (Digital Signature Services).

Uso

SignatureService signatureService = new SignatureService(
    "/ruta/al/certificado.p12",
    "contraseñaDelCertificado"
);

byte[] xmlBytes = xmlString.getBytes("UTF-8");
byte[] signedXml = signatureService.signXml(xmlBytes);

⚠️ SignatureService solo expone signXml(byte[]). No existe un método verifySignature(...) en esta clase — si necesitas verificar una firma, tendrás que implementarlo aparte usando las APIs de eu.europa.esig.dss directamente (por ejemplo con SignedDocumentValidator), o abrir un issue si te interesa que se añada al SDK.

Detalles técnicos de la firma generada

signXml(...) produce una firma:

  • Nivel: XAdES_BASELINE_B
  • Empaquetado: ENVELOPED (la firma queda insertada dentro del propio XML)
  • Algoritmo de resumen: SHA256
  • El certificado se carga como Pkcs12SignatureToken (formato .p12/.pfx), usando la primera clave privada disponible en el almacén (token.getKeys().get(0)).

Relación con el envío a la AEAT

Depende del modo con el que se instanció AeatClient (quinto parámetro del constructor, verifactuMode):

  • Modo VERI*FACTU (verifactuMode=true): sendInvoice()/sendAnnulment() no invocan SignatureService internamente. El envío a la AEAT se realiza vía SOAP sobre TLS mutuo usando directamente el certificado .p12 (ver AeatClient.configureSSL()), que es el mecanismo de autenticación que exige el servicio web de la AEAT para VeriFactu. Al ser una remisión síncrona en tiempo real, esa propia comunicación ya aporta la garantía de integridad frente a la AEAT, por lo que la normativa (RD 1007/2023) no exige aquí firma XAdES explícita.
  • Modo NO VERI*FACTU (verifactuMode=false, Requerimiento): sendInvoice()/sendAnnulment() sí invocan SignatureService internamente y de forma obligatoria. El registro se genera, se calcula/encadena su huella exactamente igual que en modo VERI*FACTU, se marshala a XML y se firma con XAdES (SignatureService.signXml) usando el mismo certificado .p12 configurado en AeatClient, sin realizar ninguna llamada SOAP a la AEAT. El XML firmado se devuelve codificado en Base64 en response.get("signedXml"), y es ese documento — no un simple JSON con los campos parseados — el que debes conservar como registro legal, íntegro y accesible ante una posible inspección (ver Encadenamiento y hash para el resto de campos de la respuesta en este modo).

En ambos casos puedes seguir usando SignatureService de forma independiente si necesitas firmar XML por tu cuenta fuera del flujo de sendInvoice/sendAnnulment (por ejemplo, para archivar copias firmadas adicionales).

Ejemplo completo: SignatureExample.java.

Clone this wiki locally