6.9 KiB
Plan: firma de autor en Go (spec v0.11, entrega 2 del formato 3)
1 de octubre de 2026. El autor pidió poder firmar cápsulas («no tengo opción de meter firmas en la página») y dio el visto bueno a empezar por el spec y Go. La base es la parte 2 del diseño del formato 3 (apartados 10 a 15), ya revisada. Se hace en la rama v0.11 de datekeys-go, que ya tiene la llave de palabras (5b3d2d4).
Por qué primero el spec y Go
- El spec es el contrato: dice qué bytes se firman, cómo se verifica una firma y qué ve quien abre. Lo que no está en el spec no puede comprobarlo otra implementación.
- Go es la implementación de referencia: escribe los vectores y las cápsulas de prueba que después tiene que reproducir TypeScript byte a byte, como en el formato 3.
- La página va después, con su propio plan, y reutiliza esas pruebas.
Pasos
| Paso | Contenido | Resultado |
|---|---|---|
| 0 | Borrador del spec v0.11: qué se firma (AUTHOR_MESSAGE), Ed25519 estricto, las claves dkauthor1…, los veredictos de la firma, la llave de palabras y la nota pública |
Texto para que lo apruebe el autor |
| 1 | ed25519strict: la verificación estricta, con código propio para lo que ed25519.Verify de Go acepta de más |
Los casos de «Taming the many EdDSAs» en ed25519_strict.json |
| 2 | authorkey: generar la clave, escribirla como dkauthor1… y DKAUTHOR-SECRET-KEY-1…, y guardarla en un fichero cifrado con contraseña (age scrypt, logN 16) |
Pruebas de ida y vuelta y de errores |
| 3 | Firmar en el escritor: payload_commit, control_commit, head_digest y la firma en el área de seguridad, verificada antes de escribir |
Una cápsula firmada que abre un lector de la v0.10, que muestra F1 |
| 4 | Verificar en el lector: los veredictos de la firma, y la comparación con la clave que se espera | Firmas válidas, alteradas, quitadas, rehechas y trasplantadas |
| 5 | CLI: author keygen, author public, encrypt -sign y decrypt -expect-author |
Prueba de ida y vuelta con la CLI |
| 6 | Datos de prueba: el fixture format3_signed, statements.json y las mutaciones de la firma |
Lo que comprobará TypeScript |
| 7 | Documentación, check.sh, revisión adversarial y, con permiso del autor, el tag spec-v0.11 |
Rama lista |
Queda para después la verificación por un tercero (statement export|verify, apartado 13), que no hace falta para firmar y comprobar firmas.
Cambio tras hablar con el autor (01-10)
El autor quiere que se sepa quién firma: con un certificado reconocido (FNMT, DNIe), firmado fuera de la página con su aplicación de firma.
- Dos tipos de firma.
alg1, con una clave propia Ed25519 (dkauthor1…), como en el diseño.alg2, una firma CAdES separada, la que produce AutoFirma, con el certificado X.509 de la persona: la página da elAUTHOR_MESSAGEcomo fichero, la persona lo firma fuera y carga la firma. - Escritura en dos tiempos. El escritor prepara la cápsula (sorteos, head y compromisos), devuelve
AUTHOR_MESSAGE, espera la firma y entonces escribe. Los secretos solo viven en memoria entre los dos tiempos. - Área mayor. 512 bytes no caben una firma CAdES con su cadena. La v0.11 fija un área mayor, por ejemplo 16 KiB, la misma para toda cápsula, firmada o no (§29.2, hallazgo 5).
- Verificación. DateKeys comprueba la firma y enseña el titular del certificado. La validez legal (cadena de confianza, revocación) la dan VALIDe o AutoFirma, a los que la página exporta la firma y el mensaje.
- Sello de tiempo RFC 3161 de una autoridad cualificada (
seal_type2), dentro de la firma (CAdES-T) o pedido aparte, en lugar del servicio propio de la entrega 3.
Las aplicaciones (01-10)
DateKeys tendrá aplicación móvil, de escritorio (macOS, Windows y Linux), de línea de órdenes y la web. Todas escriben y leen la misma cápsula firmada. Lo que cambia es cómo consigue cada una la firma con certificado:
| Aplicación | Cómo firma con certificado |
|---|---|
| Web | Fuera, con la aplicación de firma de la persona (AutoFirma), y carga la firma |
| Escritorio | Con el certificado del sistema o de la tarjeta: almacén de Windows, llavero de macOS, PKCS#11 en Linux |
| Móvil | Con el certificado importado en la app, o con el DNIe por NFC |
| CLI | Con un fichero .p12 o la tarjeta (PKCS#11) |
Por eso:
- la API del escritor, en Go y en TypeScript, trabaja en dos tiempos, preparar y escribir con la firma, con un firmante que aporta cada aplicación;
- la firma con certificado es CMS/CAdES estándar (
SignedDataseparado sobreAUTHOR_MESSAGE), que todas esas plataformas producen de serie; - la librería de Go sirve para la CLI, el escritorio y el móvil (compilada para Android e iOS), y la de TypeScript para la web.
Decisiones del autor
- Dónde se guarda la clave secreta de autor. El diseño propone un fichero cifrado con contraseña. Como con la llave de palabras, podría poder guardarse también como palabras. Pero a diferencia de esa llave, la clave de autor es una sola para todas tus cápsulas, así que unas palabras flojas la exponen todas a la vez. Recomendación: fichero cifrado y, como alternativa, 12 palabras generadas al azar, nunca elegidas por la persona.
- Una sola firma por cápsula. El diseño deja un único hueco de firma, ampliable más adelante sin cambiar el formato. Recomendación: así.
Otras novedades de la v0.11 (01-10)
- Nota pública. Un texto corto que se ve antes de la fecha, para saber qué es cada cápsula: una extensión no crítica de
PUBLIC_HEADER, registrada en §72, de hasta 1 KiB y con las reglas de texto de §29.6. Un lector de la v0.10 la ignora y abre la cápsula igual.- Antes de la fecha no está comprobada: cualquiera puede fabricar una cápsula con la nota que quiera. La página y la CLI la muestran como nota de quien la creó, sin comprobar.
- Al abrir,
header_bindingla ata a la cápsula, y la firma la cubre a través decontrol_commit. Cambiarla después rompe la cápsula.
- La nota y la fecha, también en la
.dkk, como pidió el autor, en una extensión no crítica (§44), para reconocer una llave suelta.- Es informativa, porque nada la ata a la cápsula. La
.dkkse empareja con su cápsula porcapsule_idycapsule_digest, que ya escriben Go y TypeScript, nunca por la nota. - Si la cápsula y la llave traen notas distintas, manda la de la cápsula y se avisa de la diferencia.
- Es informativa, porque nada la ata a la cápsula. La
- Código: en Go, las dos extensiones y
-noteen la CLI, con el paso 5; en la página, con su propio plan. - Ficheros fuera de la cápsula, propuesta pendiente de que el autor la confirme. Cada fichero iría dentro, como hoy, o fuera (IPFS, Drive, una URL), cifrado con la misma clave, con su hash, su tamaño y sus direcciones en una extensión crítica del head. Sus riesgos: que el fichero dure, que se pueda borrar antes de la fecha, que el cifrado quede público y que la web no pueda descargarlo de cualquier sitio.