惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Spread Privacy
Spread Privacy
P
Palo Alto Networks Blog
P
Proofpoint News Feed
AI
AI
Help Net Security
Help Net Security
S
Securelist
T
Troy Hunt's Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
C
Cisco Blogs
Scott Helme
Scott Helme
Hacker News - Newest:
Hacker News - Newest: "LLM"
Vercel News
Vercel News
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
B
Blog
GbyAI
GbyAI
Recent Commits to openclaw:main
Recent Commits to openclaw:main
D
Darknet – Hacking Tools, Hacker News & Cyber Security
P
Proofpoint News Feed
S
Security Affairs
Cisco Talos Blog
Cisco Talos Blog
AWS News Blog
AWS News Blog
T
Tenable Blog
H
Help Net Security
NISL@THU
NISL@THU
F
Fortinet All Blogs
博客园_首页
G
GRAHAM CLULEY
L
LINUX DO - 最新话题
P
Privacy International News Feed
G
Google Developers Blog
博客园 - Franky
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Security Archives - TechRepublic
Security Archives - TechRepublic
The Register - Security
The Register - Security
L
LangChain Blog
aimingoo的专栏
aimingoo的专栏
T
Tor Project blog
P
Privacy & Cybersecurity Law Blog
量子位
C
Cyber Attacks, Cyber Crime and Cyber Security
Forbes - Security
Forbes - Security
S
Secure Thoughts
Simon Willison's Weblog
Simon Willison's Weblog
D
Docker
Recorded Future
Recorded Future
博客园 - 三生石上(FineUI控件)
L
Lohrmann on Cybersecurity
T
Tailwind CSS Blog

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
Firma digital: formato, certificado y política de validación — tres capas que se confunden constantemente
Juan Torchia · 2026-05-29 · via DEV Community

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 digitalSignature habilitado 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:


Este artículo fue publicado originalmente en juanchi.dev