You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

19 KiB

Respuesta de Fable y Astra a la consulta area_firmas_para_revision.md, copiada tal como la pasó el autor el 1 de octubre de 2026. Las comprobaciones contra la spec y el código, y lo que decide el autor, están en el plan de la firma.

DateKeys formato 3: firma y sello. Propuesta consolidada

1 de octubre de 2026. Propuesta común de Fable y Astra para el autor de DateKeys, tras la consulta «El tamaño del área de firmas y sellos».

Decisión en breve

Proponemos un área fija e igual para todas las cápsulas, con 32 KiB como valor provisional hasta medir, y un compromiso firmado nuevo que no depende del tamaño reservado para las firmas. Es la postura común de Fable y Astra tras la revisión cruzada de la consulta del 1 de octubre.

  • Área: una sola constante para todo escritor de la versión, firme o no. No crece sola.
  • Lo firmado: un único hash sobre datos con significado. Quedan fuera L, AREA_LEN y SEALED_CONTROL_LEN.
  • Firmas: una SignedData CMS con uno o varios firmantes en el hueco actual. Sin listas en la primera versión.
  • Sellos: un solo tipo por cápsula. CAdES-T obligatorio si hay certificado; el hueco de sello, opcional, si no lo hay.
  • Fuera de la cápsula: OpenTimestamps y los resellados, sobre capsule_digest.

El autor ha cerrado estas decisiones:

  • A1 se mantiene. El área es fija para todos y la ampliación expresa es la única excepción. Si algún día A1 deja de importar, el mismo compromiso firmado admite un área variable.
  • 32 KiB como valor provisional. Se implementa como constante del escritor, y la medición la confirma o la mueve.
  • Sello de tiempo obligatorio con certificado, con su coste incluido en esa opción. En las demás cápsulas es opcional.
  • Sin firma del servicio DateKeys en esta entrega.

Ninguno de los dos revisores ha visto la spec ni el código: todo se apoya en lo que afirma el documento de consulta.

Riesgos de un área fija y de un área variable

El área fija arriesga comodidad y bytes; la variable arriesga discreción. Ninguna pone en riesgo el contenido, la fecha ni la validez de la firma.

Riesgo Área fija Área variable
Que la firma no quepa Sí. Hay que ampliar, quitar algo o rechazar No, hasta el techo de 64 KiB
Que el tamaño delate si hay firma No, mientras todo quepa en la reserva Sí: permite inferir o descartar si hay firma y de qué tipo. Con otros datos puede ayudar a acotar al firmante
Peso de las cápsulas Todas crecen, firmadas o no Solo crecen las firmadas
Acierto del tamaño elegido Es una apuesta hasta medir, y puede quedarse corta con el tiempo No hay tamaño que elegir
Techo de 64 KiB de los lectores publicados Se mantiene Se mantiene
  • Quién ve la fuga del área variable: quien conoce el contenido, quien compara cápsulas del mismo autor y quien aportó la plantilla. Quien solo tiene el fichero no separa el área del contenido.
  • La fuga no se apaga con el tamaño. Quien elige el contenido puede ajustarlo al borde de un paso de relleno, y entonces la firma se nota también en cápsulas grandes.
  • El empaquetado deja de estar firmado en los dos casos. Con el compromiso nuevo, quien ya puede abrir la cápsula puede rehacerla con otra área y la firma sigue valiendo. No afecta al contenido, a la fecha ni al autor.
  • Lo que ninguna de las dos evita: que alguien retire una firma después de abrir y que falten pruebas de validación en 2050. Lo tratan el cambio 5 y la sección de evidencias.

Cambios sobre el diseño

Son ocho cambios sobre un diseño que aún no está publicado. Los cambios 1 y 2 reabren el apartado 10, el 5 añade una clave al esquema del área y el resto son reglas del escritor y del verificador.

1. Compromiso firmado sin tamaños

La firma cubre solo datos con significado y se recalcula desde la cápsula, sin almacenarse.

payload_commit = SHA-256("datekeys:dkc3:payload:v1" || 0x00 || I_PAYLOAD)
header_commit  = SHA-256("datekeys:dkc3:header:v1"  || 0x00 || PRELUDE* || PUBLIC_HEADER)
CONTROL_SIG    = CONTROL_CBOR sin L, con I_PAYLOAD -> payload_commit
                 y header_binding -> header_commit
control_commit = SHA-256("datekeys:dkc3:control:v1" || 0x00 || CONTROL_SIG)
head_digest    = SHA-256("datekeys:dkc3:head:v1"    || 0x00 || HEAD_CBOR)
signers_digest = SHA-256("datekeys:dkc3:signers:v1" || 0x00 || REQUIRED_SIGNERS)

AUTHOR_MESSAGE = "datekeys:dkc3:author-signature:v1" || 0x00
              || SHA-256(control_commit || head_digest || signers_digest)    ; 66 B

PRELUDE* = PRELUDE con SEALED_CONTROL_LEN a cero
  • Qué cubre: fecha, política, capsule_id, compromiso de I_PAYLOAD, regla de relleno, extensiones de control, head y lista de firmantes exigidos.
  • Qué deja fuera: L, AREA_LEN, SECURITY_LEN y SEALED_CONTROL_LEN. Los tamaños de los ficheros siguen en el head, y PUBLIC_HEADER_LEN sigue en PRELUDE*.
  • header_binding no cambia y se sigue comprobando al abrir. header_commit es un valor distinto, con nombre propio, que solo sirve para la firma.
  • Por qué: el tamaño del área deja de afectar a la firma y desaparecen los umbrales de CBOR (65 536 y 2³²).
  • Codificación: la spec debe fijar los bytes exactos de CONTROL_SIG y REQUIRED_SIGNERS. Eso incluye la variante determinista de CBOR (RFC 8949), tipos y claves, la lista vacía, el orden, ausente frente a vacío y las extensiones.
  • Condición: un lector estricto. Debe exigir SECURITY_LEN ≤ AREA_LEN antes de interpretar o reservar memoria, L = 12 + AREA_LEN + HEAD_LEN + C, ceros en la parte no utilizada del área y en el relleno, P = regla(L), CBOR sin claves duplicadas y ningún byte sobrante.

Los nombres y los dominios del esquema son orientativos.

2. AUTHOR_MESSAGE con un único hash

El mensaje que sale hacia la aplicación de firma ya no expone head_digest.

  • El problema: hoy head_digest viaja en claro en los 98 bytes. Quien obtenga ese fichero y sospeche de un documento puede confirmar antes de la fecha que la cápsula lo contiene.
  • El arreglo: firmar un solo hash, como ya hace SEAL_SUBJECT. control_commit lo protege mientras I_PAYLOAD siga secreta.
  • Gravedad: de menor a mayor según el contenido. Es mayor si lo sensible es saber cuál de dos documentos va dentro.
  • Flujo web: el mensaje y el .p7s quedan en disco, y el .p7s lleva el certificado del firmante. Pedir que se borren ayuda, pero no alcanza a copias sincronizadas ni a respaldos.

3. Área fija, que no crece sola

Todo escritor de la versión reserva la misma área, haya firma o no. El valor es de 32 KiB, provisional hasta medir.

  1. Antes de pedir el PIN, el escritor estima si firmas, sellos y OCSP caben.
  2. Si no caben, se detiene y pregunta: quitar firmantes o ampliar. Todavía no ha firmado nadie.
  3. Ampliar es una elección expresa del autor y va directa a 64 KiB. Así la fuga se reduce a dos clases de reserva y no da el tamaño de las firmas.
  4. Si la sorpresa llega después del PIN, ampliar conserva las firmas. Quitar un firmante cambia la lista y obliga a firmar de nuevo.
  5. No se descarta nada en silencio, y por encima de 64 KiB se rechaza.
Operación después de firmar ¿Conserva las firmas?
Ampliar el área Sí
Añadir OCSP o sellos en su sitio Sí
Cambiar la lista de firmantes exigidos No: hay que volver a firmar
Retirar una firma exigida sin cambiar la lista Las demás siguen válidas, pero el conjunto queda incompleto

El tamaño es política del escritor. Puede cambiar en versiones posteriores, pero solo para cápsulas nuevas.

Regla para confirmar los 32 KiB al medir:

  • Un firmante completo (firma, certificado, sello y OCSP) debe caber con un margen de al menos un 25 %. El margen cubre que certificados y sellos cambien de tamaño con los años.
  • Si dos firmantes completos no caben, se mantienen los 32 KiB y ese caso usa la ampliación expresa. No se sube a 64 KiB para todos.
  • Solo se baja a 16 KiB si dos firmantes completos miden menos de 12 KiB.

4. Firma con certificado: una SignedData CMS

alg 2 es una firma CAdES separada sobre AUTHOR_MESSAGE, con uno o varios firmantes (cofirma).

  • Perfil estricto: firma separada, DER, signing-certificate-v2 obligatorio y un máximo de firmantes.
  • Algoritmos: alg 2 identifica el contenedor. Hace falta una política propia para los algoritmos de hash y de firma que lleva dentro.
  • Cadena: el escritor la poda antes de sellar y deja solo el certificado de cada firmante.
  • Sin lista de firmas. Si un día hace falta mezclar tipos, se añade una clave nueva; no se cambia el tipo de la clave 2.

5. Firmantes exigidos

Lo firmado enumera quién debe firmar, y el verificador exige todas esas firmas.

  • Quién va en la lista: todos los firmantes exigidos, también el autor. CMS no ordena a los firmantes, así que no existe un «primer firmante».
  • Por qué todos: si la lista solo exigiera al organismo, alguien podría retirar la firma de la autora y el conjunto seguiría pareciendo completo.
  • Identificación: el SHA-256 del certificado completo en DER. Sin duplicados y en un orden determinista.
  • Ubicación: en el área, no en el control. SEALED_CONTROL_LEN va en claro, y una extensión que solo exista con firmantes los delataría. Es el único dato del área que entra en lo firmado, y necesita una clave nueva en su esquema.
  • Lista vacía: solo en cápsulas sin firma o con Ed25519, que ya vincula su clave por su cuenta.
  • Antes de la primera firma: la lista debe estar cerrada, y eso exige conocer los certificados. Se cumple de tres maneras: seleccionando el certificado en AutoFirma sin firmar (función selectCertificate, si hay integración web), importando el certificado público o con una firma de prueba.
  • Regla del verificador: deben estar todas las firmas de la lista. Un firmante que no figure en ella se muestra aparte y no cuenta.
  • Límite: si se retiran todas las firmas, nada interno lo detecta. Hace falta una expectativa del receptor.

La firma de prueba es la vía práctica mientras el flujo web consista en descargar, firmar fuera y subir el .p7s. Tiene cuatro condiciones:

  • Mensaje propio: identificado como prueba de DateKeys, sin contenido del usuario, sin sello y distinto del que autoriza una cápsula.
  • El tamaño es una estimación. El CMS definitivo crece con el sello y las evidencias. No sustituye la comprobación final ni la política de desbordamiento.
  • La firma real se comprueba. Su certificado debe coincidir con la huella comprometida. Una renovación u otro certificado obligan a reconstruir el compromiso.
  • El certificado es un dato identificativo. Se procesa en el dispositivo y no va a registros ni a analítica.

6. Un solo tipo de sello por cápsula

Cápsula Sello Qué cubre
Con certificado CAdES-T dentro del CMS, uno por firmante El valor de la firma, según la regla estándar
Sin firma o con Ed25519 (sello opcional) El hueco de sello (seal_type 1 o 2) SEAL_SUBJECT
  • CAdES-T es obligatorio en el perfil con certificado, uno por firmante. Es un atributo no firmado y se puede retirar, así que el verificador debe detectar su ausencia.
  • Por qué: la cápsula se abre más tarde, y hay que poder acreditar que la firma existía mientras el certificado era válido. La caducidad no rompe la firma; sin sello falta esa prueba.
  • Sin otro PIN: si la TSA falla, se reintenta durante la sesión sin volver a firmar.
  • No se da por terminada una cápsula con certificado y sin sello.
  • Petición mínima: a la TSA solo va la huella del valor de firma, no el documento ni el certificado. La conexión y la cuenta sí dejan metadatos.
  • Qué TSA: el perfil exige un sello RFC 3161. Si debe ser cualificado es decisión de producto, y el veredicto debe indicarlo.
  • No son intercambiables. Un token sobre SEAL_SUBJECT no es un CAdES-T, y cada uno tiene su verificación.
  • SIG_PART solo se define para dos casos: una constante cuando no hay firma y, con Ed25519, un hash con dominio propio del algoritmo, la clave pública y la firma.
  • seal_type 3 (OpenTimestamps) queda reservado y sin implementar dentro.

7. Veredictos

Abrir y validar son cosas distintas: una firma nunca impide abrir, pero «se abre» no significa «está verificada».

  • Cada firma tiene su veredicto: válida según la política, incorrecta o no verificable (algoritmo desconocido o faltan evidencias).
  • La cápsula tiene un resultado de conjunto: sin firma, cumple el perfil o no lo cumple. No lo cumple si falta un firmante o un sello exigidos, aunque las firmas presentes sean correctas.
  • «Firmado antes de la fecha» solo se dice de quien tenga un sello anterior a la ronda. Quien puede abrir la cápsula puede rehacer el área.
  • Firma externa sobre capsule_digest: acredita ese fichero cifrado, no que el firmante conociera el contenido. La interfaz no debe llamarla igual que una firma interna.

8. Nueva redacción de A1

Quien tiene el .dkc antes de la fecha no puede saber si lleva firma o sello, mientras la cápsula esté dentro de la reserva común. Una cápsula que el autor amplía expresamente queda fuera de esta garantía.

La fuga aceptada del área de 512 bytes desaparece en las cápsulas de la versión nueva.

La garantía se limita al .dkc: no cubre los archivos externos ni el tráfico hacia los servicios. Depende además de confirmar que ninguna otra longitud visible cambia al activar firmas o sellos.

Evidencias: dentro, fuera y cuándo

Las evidencias se capturan al firmar, se guarden donde se guarden: «fuera» no significa «después de la fecha».

Evidencia Dónde Por qué ahí
Firma y certificado de cada firmante Dentro Identifican al firmante
Sello de la firma (CAdES-T) Dentro Lo entienden los validadores estándar
OCSP de cada firmante Dentro Lleva el número de serie del certificado
Cadenas, listas de las autoridades y certificados de la TSA Fuera, capturados ese día Son iguales para cualquier usuario de esa autoridad
OpenTimestamps del .dkc Fuera Se completa horas después y se verifica con el cliente estándar
Sello cualificado del .dkc, si se quiere Fuera Acredita ese fichero exacto sin revelar lo de dentro
Resellados de archivo Fuera Se añaden durante décadas, con la cápsula cerrada
  • OCSP: debe ser aplicable al momento de la firma. No vale cualquier respuesta cercana.
  • La tabla no es exhaustiva. Hay que conservar lo necesario para validar las cadenas del firmante, de la TSA y de quien firma las respuestas OCSP, según el perfil.
  • El material común no debe delatar la firma. Si la app solo lo guarda en cápsulas firmadas, la fuga de A1 reaparece ahí. Propuesta sin contrastar con la spec: guardarlo siempre, haya firma o no.
  • Los sellos de fuera conservan lo que hay dentro, pero no suplen una evidencia que nunca se guardó.
  • OpenTimestamps no caduca con ningún certificado. Hay que completar la prueba y guardarla. Revela que ese fichero se selló y cuándo, no su contenido.
  • Resellado (RFC 4998): el sello se renueva antes de que caduque el anterior. Antes de que el hash deje de ser seguro, se renueva con otro que cubra el .dkc original y las evidencias anteriores.
  • Nada se descarta en silencio. Si una evidencia no cabe, se conserva en otro sitio o se declara la garantía que se pierde.

A décadas, el eslabón débil es el cierre y no la firma: que drand siga publicando y que BLS12-381 y X25519 aguanten, porque no resisten a un ordenador cuántico.

Fuera de la primera entrega

Seis cosas se dejan para después, por alcance y no porque sean malas ideas.

  • Borradores cifrados en disco, para que un organismo firme días después dentro de la cápsula. Dejan el contenido e I_PAYLOAD en reposo y piden decidir la custodia de claves. Mientras tanto, un organismo solo firma dentro si lo hace en la misma sesión.
  • Listas generales de firmas y de sellos.
  • Roles y umbrales de firmantes. La lista de firmantes exigidos basta por ahora.
  • OpenTimestamps dentro de la cápsula.
  • Un anexo cifrado con tlock para la misma ronda, para organismos que firmen después y deban seguir ocultos hasta la fecha.
  • Firma del servicio DateKeys. Aporta poco mientras no certifique algo propio, como una organización verificada. seal_type 1 sigue reservado para ese día.

Pendiente de medir y de comprobar

Los 32 KiB son provisionales hasta medir, y varias afirmaciones dependen de la spec y del código, que no hemos visto.

Medir

  • Firma CAdES con FNMT persona física, representante, DNIe y sello de entidad, con y sin cadena.
  • Token de dos autoridades de sellado cualificadas.
  • Respuesta OCSP de cada autoridad.
  • Las combinaciones completas previstas: dos firmantes, sus sellos, las evidencias y la estructura CBOR final.
  • Con esas medidas, confirmar o mover los 32 KiB según la regla del cambio 3.

Comprobar en la spec y el código

  • Que los lectores Go y TypeScript cumplen la condición de lector estricto del cambio 1.
  • Fijar la codificación exacta de CONTROL_SIG y REQUIRED_SIGNERS, con vectores de prueba comunes a Go y TypeScript.
  • Asignar la clave de REQUIRED_SIGNERS en el área y comprobar qué hacen los lectores v0.10 con un área no vacía y con claves que no conocen.
  • Si el control sellado lleva relleno propio. De eso depende dónde va la lista de firmantes exigidos.
  • Que ninguna otra longitud visible del .dkc cambia al activar firmas o sellos.
  • Qué versiones de AutoFirma permiten seleccionar el certificado sin firmar, si se integra en la web.
  • Escribir el argumento de que un .dkc solo admite un contenido: la MAC de cabecera de age y el resultado único de tlock (RFC 4998, apartado 6).

Comprobar en lo que se promete

  • «Firma cualificada» solo con dispositivo cualificado, como el DNIe. Un .p12 no lo es.
  • «Sin confiar en ningún servidor» necesita precisión: depende de que no se comprometa un umbral de drand.
  • El coste de cada sello depende del contrato con la TSA. No dar por hecha una tarifa por operación.

Casos de prueba antes de publicar

Diez casos cubren los cambios; Astra propuso los cuatro primeros y los tres últimos.

Caso Resultado esperado
L cruza 65 536 o 2³² al cambiar el área AUTHOR_MESSAGE no cambia
Se retira la firma de un organismo exigido y se rehace la cápsula El conjunto no cumple el perfil
Se añaden sello y OCSP durante la preparación Las firmas ya hechas siguen siendo válidas
Un lector v0.10 abre una cápsula firmada Abre, y no la presenta como verificada
El área se amplía a 64 KiB después de firmar La firma sigue valiendo sin un segundo PIN
El mismo contenido con firma y sin firma, dentro de la reserva La misma P
Alguien tiene AUTHOR_MESSAGE y un documento candidato No puede confirmar que la cápsula lo contiene
Se retira la firma del autor y se mantienen las demás El conjunto no cumple el perfil
Se retira una firma y se cambia la lista para ocultarlo Las firmas restantes dejan de validar
Se retira un sello CAdES-T exigido La firma sigue siendo correcta, pero el perfil no se cumple

Powered by TurnKey Linux.