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.
251 lines
19 KiB
251 lines
19 KiB
*Respuesta de Fable y Astra a la consulta [area_firmas_para_revision.md](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](../PLAN_firma_go.md#propuesta-de-fable-y-astra-01-10).*
|
|
|
|
# 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.
|
|
|
|
```text
|
|
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 |
|