Firma digital: formato, certificado y política de validación — tres capas que se confunden constantemente
La primera vez que recibí un INVALID que no entendía, pasé tres horas mirando algoritmos y hashes. El certificado era válido, la criptografía cerraba, el hash coincidía. El problema era que el formato del documento no era el que esperaba el validador. Esa tarde me enseñó más sobre firmas digitales que cualquier documentación que había leído antes — no porque fuera compleja, sino porque me mostró que estaba mirando la capa equivocada.
Mi tesis es esta: la mayoría de los errores de validación de firma no son criptográficos. Son de formato o de política de validación. Y confundir esas tres capas no solo te cuesta tiempo — te puede llevar a romper algo que funcionaba bien.
Si trabajás con firmas digitales en Java o en cualquier stack que necesite interoperar con sistemas europeos o regulados, eventualmente vas a recibir un resultado que no entendés. Lo que sigue es el mapa que me hubiera ahorrado esas tres horas.
Las tres capas que hay que separar
Tratar "firma digital" como una sola cosa es el primer error. Son al menos tres capas independientes que pueden fallar por razones completamente distintas.
Capa 1 — El formato del documento firmado
El formato define cómo se empaqueta la firma junto con el documento. Los más comunes en el ecosistema europeo y regulado:
- CAdES (CMS Advanced Electronic Signatures): firma sobre datos binarios arbitrarios, muy común en sistemas de backend.
- XAdES (XML Advanced Electronic Signatures): para documentos XML, con variantes que permiten firmar partes del árbol.
- PAdES (PDF Advanced Electronic Signatures): firma embebida en PDF, con soporte para visibilidad y capas de validación a largo plazo.
- JAdES (JSON Advanced Electronic Signatures): el más nuevo, para flujos basados en JSON.
Cada formato tiene perfiles internos: BES, T, LT, LTA. El perfil T agrega un sello de tiempo. El perfil LT incluye material de revocación (OCSP o CRL). El perfil LTA agrega un sello de tiempo sobre todo el material de validación.
Si generás una firma CAdES-BES y el sistema receptor espera CAdES-LT, el resultado es INVALID aunque la criptografía sea perfecta. El certificado puede estar vigente, el hash puede ser correcto, y aun así el validador rechaza. Eso fue exactamente lo que me pasó esa tarde.
Capa 2 — El certificado
El certificado es la identidad del firmante. Sus problemas más típicos:
- Cadena de confianza incompleta: el certificado del firmante es válido, pero el validador no tiene el certificado raíz en su trust store.
- Revocación: el certificado fue revocado y el validador chequea OCSP o CRL. Si el endpoint de revocación no responde, dependiendo de la política, puede tratarse como error o como advertencia.
-
Key Usage: el certificado no tiene el uso de clave
digitalSignaturehabilitado explícitamente. - Tiempo de firma fuera del período de validez: el certificado expiró entre la creación y la validación, y no hay sello de tiempo que ancle la firma al momento en que era válido.
Capa 3 — La política de validación
Acá es donde más gente se pierde. Una política de validación es un conjunto de reglas que define qué se considera una firma "válida" para un contexto específico. No es universal.
El reglamento eIDAS (Regulation EU 910/2014) define niveles de firma: Simple, Avanzada, Cualificada. Pero la implementación concreta de qué verifica un sistema —qué trust anchors usa, qué respuesta de revocación acepta, si exige sello de tiempo— depende de la política configurada en el validador.
Dos sistemas que implementan eIDAS pueden llegar a resultados distintos sobre la misma firma si tienen políticas de validación distintas. Eso no es un bug: es por diseño. Y es la parte que menos documentación tiene cuando estás debugueando a las 11 de la noche.
Cómo diagnosticar: checklist antes de tocar código criptográfico
Antes de cualquier cambio en algoritmos o claves, pasá por esta secuencia:
1. ¿El validador te devuelve un diagnóstico detallado o solo "INVALID"?
→ Si solo devuelve INVALID, el primer paso es conseguir el reporte completo.
2. ¿El formato del documento coincide con el que espera el receptor?
→ CAdES / XAdES / PAdES / JAdES
→ ¿Qué perfil? BES / T / LT / LTA
3. ¿La cadena de certificados está completa?
→ ¿El trust store del validador incluye la CA raíz del emisor del certificado?
4. ¿El certificado estaba vigente en el momento de la firma?
→ Si no hay sello de tiempo, "momento de la firma" es ambiguo para el validador.
5. ¿El endpoint de revocación (OCSP/CRL) era accesible cuando se validó?
→ Un timeout de OCSP puede ser tratado como revocación desconocida.
6. ¿La política de validación del receptor exige algo que la firma no tiene?
→ ¿Sello de tiempo? ¿Material de revocación embebido? ¿CA específica?
Recién después de pasar estos seis puntos sin encontrar el problema, empezá a mirar criptografía: hash, algoritmo de firma, longitud de clave.
DSS de la Comisión Europea: qué dice y qué no dice
La librería de referencia para este ecosistema es DSS (Digital Signature Service), mantenida por la Comisión Europea. La documentación oficial está en https://ec.europa.eu/digital-building-blocks/DSS/webapp-demo/doc/dss-documentation.html.
DSS soporta los cuatro formatos (CAdES, XAdES, PAdES, JAdES) y sus perfiles. También expone un validador que devuelve un reporte detallado en XML o JSON con diagnóstico por capa. Es Java, open source (LGPL), y es el motor detrás de varios validadores nacionales europeos.
Lo que DSS dice: cómo se estructura cada formato, qué espera cada perfil, y qué verifica el validador en cada paso.
Lo que DSS no dice: qué política de validación es obligatoria para tu caso de uso específico. Eso lo define la regulación local, el contrato con el receptor, o la especificación técnica del sistema que va a consumir la firma. DSS te da la herramienta; la política correcta la tenés que conseguir aparte, y esa parte no está en ningún README.
Un ejemplo reproducible en Java con DSS
Si querés experimentar con validación, DSS tiene un módulo dss-validation que se puede usar standalone. Un flujo típico se ve así:
// Cargar el documento firmado (ejemplo con CAdES)
DSSDocument signedDocument = new FileDocument("documento-firmado.p7s");
// Configurar fuentes de certificados y revocación
CertificateVerifier verifier = new CommonCertificateVerifier();
// Agregar trust store con las CAs raíz que querés aceptar
verifier.setTrustedCertSources(trustedCertificateSource);
// Configurar fuente de OCSP online (opcional, puede ser offline)
verifier.setOcspSource(new OnlineOCSPSource());
// Crear el servicio de validación
DocumentValidator validator = new CMSDocumentValidator(signedDocument);
validator.setCertificateVerifier(verifier);
// Ejecutar la validación con política EIDAS_MODEL por defecto
Reports reports = validator.validateDocument();
// El diagnóstico está en el reporte detallado
DiagnosticData diagnosticData = reports.getDiagnosticData();
SimpleReport simpleReport = reports.getSimpleReport();
// Por firma: indicación, sub-indicación y errores/advertencias
for (String signatureId : simpleReport.getSignatureIdList()) {
System.out.println("Indicación: " + simpleReport.getIndication(signatureId));
System.out.println("Sub-indicación: " + simpleReport.getSubIndication(signatureId));
// Los errores te dicen exactamente qué capa falló
simpleReport.getErrors(signatureId).forEach(System.out::println);
}
Lo importante no es el código en sí —la documentación de DSS lo cubre bien— sino la sub-indicación. Cuando getIndication devuelve INDETERMINATE o INVALID, getSubIndication te dice si el problema es NO_CERTIFICATE_CHAIN_FOUND, REVOKED_NO_POE, SIG_CONSTRAINTS_FAILURE, o alguno de los otros códigos definidos en ETSI EN 319 102-1. Cada uno apunta a una capa distinta. Esos códigos son el diagnóstico real; el INVALID de primer nivel no te dice nada útil.
Los errores que más tiempo cuestan
Error 1: Buscar el problema en el algoritmo cuando es el perfil
Generás una firma CAdES-BES porque es lo mínimo necesario para que la criptografía sea correcta. El sistema receptor espera CAdES-LT porque su política requiere material de revocación embebido. El resultado es INDETERMINATE / NO_POE. El diagnóstico automático apunta a "problema de criptografía". La solución es subir el perfil de firma, no tocar el algoritmo.
Error 2: Asumir que un certificado "vigente" es suficiente
Un certificado puede pasar la verificación de cadena y de revocación pero tener Key Usage que no incluye digitalSignature. En ese caso la firma es técnicamente inválida aunque el certificado esté activo. DSS lo reporta como SIG_CONSTRAINTS_FAILURE con el detalle correspondiente.
Error 3: Ignorar el trust store del validador
Si el validador usa la LOTL (List of Trusted Lists) europea como trust anchor, solo va a reconocer certificados emitidos por CAs que figuren en esa lista. Un certificado perfectamente válido emitido por una CA que no está en la LOTL va a resultar en NO_CERTIFICATE_CHAIN_FOUND. No es un error de la firma: es una incompatibilidad de política o un problema de configuración del validador.
Error 4: Confundir validación técnica con validación legal
DSS puede decirte que una firma es técnicamente TOTAL-PASSED bajo una política dada. Eso no implica que tenga validez legal en una jurisdicción específica. La validez legal de una firma cualificada eIDAS requiere que el certificado sea emitido por un QTSP (Qualified Trust Service Provider) listado en la LOTL. Un validador técnico no reemplaza el análisis legal.
Límites de lo que se puede concluir sin datos reales
Siendo honesto sobre los límites de este análisis:
- No podés determinar la política correcta para un caso específico solo leyendo documentación general. La política la define el receptor o la regulación aplicable, y puede variar entre sistemas que implementan el mismo estándar.
- Los ejemplos de código son ilustrativos, no configuraciones de producción. Una implementación real necesita manejo de errores, configuración de timeouts para OCSP, cache de revocación y decisiones sobre qué hacer cuando los servicios de revocación no responden.
- Las sub-indicaciones de DSS son precisas para lo que DSS verifica, pero si el receptor usa otro validador con otra librería, los resultados pueden diferir. La interoperabilidad entre validadores es un problema abierto en el ecosistema.
- El reglamento eIDAS es europeo. Si trabajás con firmas en otros contextos regulatorios (NIST, PKCS#11 en contextos bancarios latinoamericanos, etc.), las capas son similares pero los detalles de política cambian.
La tabla que uso como primera orientación cuando llega un error:
| Resultado del validador | Primera capa a revisar |
|---|---|
NO_CERTIFICATE_CHAIN_FOUND |
Trust store / certificados intermedios |
REVOKED_NO_POE |
Sello de tiempo / momento de revocación |
SIG_CONSTRAINTS_FAILURE |
Key Usage / perfil de firma requerido |
FORMAT_FAILURE |
Formato del documento (CAdES/XAdES/PAdES/JAdES) |
EXPIRED sin sello de tiempo |
Perfil T o LT para anclar fecha |
HASH_FAILURE |
Recién acá mirar criptografía |
FAQ — Preguntas frecuentes sobre firma digital, formato y validación
¿Cuál es la diferencia práctica entre CAdES, XAdES y PAdES?
El formato depende del tipo de documento. CAdES es para datos binarios arbitrarios (archivos, streams). XAdES es para documentos XML donde puede necesitarse firmar nodos específicos. PAdES es para PDFs con soporte visual y longitud de validez incorporada al estándar. La elección no es libre: la define el sistema que va a recibir y validar la firma.
¿Qué es un perfil LT y por qué importa?
LT (Long-Term) significa que la firma incluye material de revocación embebido (respuestas OCSP o CRLs) al momento de la firma. Esto permite validar la firma en el futuro sin depender de que los endpoints de revocación del momento sigan respondiendo. Es obligatorio en muchos contextos regulados porque las firmas tienen que ser verificables años después de creadas.
¿Por qué un certificado vigente puede resultar en firma inválida?
Porque vigencia y validez para firma son cosas distintas. Un certificado puede estar vigente pero tener Key Usage incorrecto, no estar emitido por una CA en el trust store del validador, o haber sido emitido después del momento de firma registrado. La vigencia del certificado es condición necesaria pero no suficiente.
¿Qué es la LOTL y para qué sirve?
La LOTL (List of Trusted Lists) es un documento XML mantenido por la Comisión Europea que referencia las listas nacionales de proveedores de servicios de confianza cualificados (QTSP) de cada estado miembro. Los validadores que implementan eIDAS la usan como trust anchor. Si el certificado del firmante no proviene de un QTSP listado en la LOTL, la firma puede ser técnicamente correcta pero no cualificada bajo eIDAS. La LOTL está disponible en https://ec.europa.eu/tools/lotl/eu-lotl.xml.
¿Qué significa INDETERMINATE vs INVALID en DSS?
INVALID significa falla definitiva: la criptografía no cierra, el certificado estaba revocado al momento de la firma, o hay una violación de restricciones. INDETERMINATE significa que no se puede determinar la validez con la información disponible — por ejemplo, no hay sello de tiempo para anclar el momento de la firma, o el servicio de revocación no respondió. INDETERMINATE no es sinónimo de inválido: en algunos casos se resuelve agregando material de validación o cambiando la política aplicada.
¿Tiene sentido implementar firma digital sin entender estos tres niveles?
Podés firmar y recibir firmas sin entender estas capas, hasta que algo falla en interoperabilidad o en validación legal. El problema es que cuando falla, el diagnóstico incorrecto —buscar en criptografía cuando el problema es de política— es lo que convierte un fix de diez minutos en tres horas perdidas. Lo sé de primera mano.
Cierre: la capa que hay que revisar primero no es la que parece
Mi postura es clara: el instinto de ir directo a la criptografía cuando una firma falla es comprensible pero casi siempre equivocado. La mayoría de los errores en foros técnicos tienen solución en la capa de formato o de política, no en la capa criptográfica.
Lo que sí compro de DSS y del ecosistema eIDAS es que la separación en capas no es formalidad académica: es una herramienta de diagnóstico. Si sabés qué sub-indicación devuelve el validador, sabés exactamente dónde buscar.
Lo que no compro es que implementar firma digital sea principalmente un problema de elegir el algoritmo correcto. El algoritmo raramente falla. El trust store mal configurado, el perfil de firma incorrecto y la política de validación que nadie leyó son los problemas reales — y ninguno de los tres aparece si solo mirás la criptografía.
El próximo paso concreto si trabajás con esto: configurá DSS en modo standalone, tomá una firma que ya tengas, ejecutá la validación y leé el reporte XML completo. No el simpleReport: el detailedReport. Ahí está el diagnóstico por capa. Si el detailedReport no te dice dónde está el problema, el problema no está donde pensabas.
Si te interesa cómo este tipo de análisis por capas aparece en otros contextos de observabilidad, hay algo similar en OpenTelemetry para Spring Boot: el log dice OK, el trace muestra el problema. La idea de que el indicador de primer nivel oculta el diagnóstico real es un patrón que aparece en varios sistemas.
Fuente original:
- European Commission DSS documentation: https://ec.europa.eu/digital-building-blocks/DSS/webapp-demo/doc/dss-documentation.html
Este artículo fue publicado originalmente en juanchi.dev
Top comments (0)