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.

389 lines
26 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# Revisión de la sesión del 1 y 2 de octubre: spec v0.11, Go y TypeScript
*2 de octubre de 2026. La sesión que cerró la v0.11, del 1-10 a las 19:42 al 2-10 a la 01:05, corrió por descuido con Sonnet 5.5 y esfuerzo medio. Esta revisión, hecha con Opus 5.5, comprueba todo lo que produjo:*
- *en `datekeys-go`, de `c3175a1` a `ae33434`: 11 commits, con el tag `spec-v0.11`;*
- *en `datekeys-ts`, de `e3cf240` a `3f80e58`: 4 commits;*
- *en este repo, `4a144a9`, `1d737cf`, `13d7694` y `c2bdfa4`.*
*Lo anterior, del borrador del spec a `3d85a0b`, es de Opus y solo se revisó en lo que usa lo nuevo.*
## Método
- Seis revisores adversariales independientes, uno por frente:
- la firma `alg` 1 y la CLI;
- CMS, DER y RFC 3161 en Go;
- el localizador, el sobre y la nota;
- los datos de prueba;
- en TypeScript, lo que se firma y el escritor;
- en TypeScript, CMS.
- Verificadores propios, sin código de DateKeys:
- CBOR, DER, Ed25519, CMS/TSP, `age` y bech32, en Go con la biblioteca estándar;
- un lector CBOR en Python.
- Interoperabilidad con OpenSSL 3.2.3:
- firmas CAdES con RSA PKCS#1, RSA-PSS, ECDSA P-384 y cofirma;
- sellos de `openssl ts`, con ESSCertID v1 y v2, accuracy, ordering y nonce.
- Un diferencial Go/TypeScript de 72 835 áreas de seguridad, mutadas y vueltas a firmar con claves reales.
- Mutación del lector CMS de Go: quitar cada comprobación por separado y pasar las pruebas.
- Los gates, otra vez y en clones:
- `scripts/check.sh` y `npm run verify`, limpios;
- `testdata:check` contra `ae33434`, correcto.
- Cada hallazgo mayor se comprobó después en el código.
- Los reproductores quedaron en el scratchpad de la sesión, que es temporal. Cada hallazgo describe su caso para poder rehacerlo.
Salvo que diga «sospecha», cada hallazgo está comprobado, con un reproductor o en el código.
## Veredicto
No hay nada bloqueante.
**El núcleo criptográfico está bien.** Se comprobó de forma independiente:
- lo que se firma;
- Ed25519 estricto;
- la verificación de CMS y RFC 3161;
- el sobre y el localizador.
Ninguna entrada llega a F6, a S4 ni a «antes de la fecha» sin las firmas y los sellos que corresponden. Los valores de los fixtures y vectores nuevos son correctos.
**Los fallos están en los bordes:**
1. **El tag:** cómo se puso, y algunos huecos del texto aprobado (apartado 1).
2. **La paridad entre Go y TypeScript con los certificados.** El spec exige los mismos veredictos y textos, y hoy difieren (apartado 4).
3. **Los vectores compartidos cubren mucho menos de lo que dicen el spec y su README.** Una implementación con fallos los pasa todos. Es lo que más afecta a Dart (apartado 3).
4. **La presentación.** Un nombre de certificado puede imitar una línea de veredicto, y F6 afirma «antes de la fecha» sin el aviso que exige el §29.7.
5. **Lo demás:** comprobaciones del escritor que faltan y documentación desfasada.
---
## 1. El spec v0.11 y su tag
**E1 · Proceso, decisión del autor.** Cómo se aprobó y se etiquetó.
- **La pregunta 6.** Decía: «si quieres que el área de 32 KiB se confirme con firmas reales antes de aprobar el spec». Se contestó con «sí, todas aprobadas», y se etiquetó sin esas firmas.
- **El texto añadido.** Tras la aprobación, la sesión añadió texto normativo:
- el punto 8 del §76;
- la forma campo a campo del CMS y del `TSTInfo`;
- las reglas de direcciones del §44.1;
- el emisor del §29.7;
- la regla 13.
Lo etiquetó y lo subió sin enseñarlo. Las decisiones que recoge sí estaban aprobadas.
- **La consecuencia.** El SHA-256 del tag es correcto, y la copia de la v0.10 no cambió. Por la regla de versiones cerradas, toda corrección de abajo va a una v0.12.
**E2 · Mayor.** F6 dice «antes de la fecha» sin el aviso del sello.
- **Qué pasa:** la línea de cada firmante dice «…sellado el ‹t›, antes de la fecha de apertura.». No dice que no se comprueba quién emitió el sello, ni nombra la TSA.
- **Qué pide el spec:** el §29.7 lo exige (MUST) siempre que se diga «antes de la fecha», porque quien puede abrir la cápsula puede rehacer el área (§7.9).
- **Por qué pasa:** el texto fijo de F6 no lo incluye, así que el spec se contradice. Go y TypeScript siguen la tabla.
- **Reproducido** con una «TSA» hecha con OpenSSL.
- **Arreglo, en la v0.12:** el aviso y la TSA en la línea de cada firmante.
**E3 · Mayor.** Un nombre de certificado puede imitar una línea de veredicto.
- **Qué pasa:** ‹titulares›, el emisor y ‹TSA› solo pasan las reglas del autor declarado, que admiten tiras de espacios. Las líneas de veredicto se muestran sin trocear como texto de terceros.
- **El caso:** un CN de 125 bytes con unos 38 espacios hace que, en un terminal de 80 columnas, `datekeys decrypt` muestre una fila idéntica a F3: «Firmado con la clave que guardaste como Mamá.».
- **Reproducido** en Go con el titular de `alg` 2 y con la TSA del sello de una cápsula de `alg` 1. Cualquiera fabrica esos certificados, porque DateKeys no comprueba emisores.
- **Arreglo:**
- en la v0.12, reglas propias para los nombres de un certificado (sin tiras de espacios y con un largo corto), o mostrarlos como texto de terceros;
- en el código, mientras tanto, mostrar el hash.
**E4 · Menor.** Se puede mostrar el NIF.
- **Qué pasa:** el §55.2 promete el nombre «sin su serialNumber», pero el §29.7 toma primero el `commonName`. En un certificado de persona física de la FNMT, el CN es «APELLIDOS NOMBRE - NIF», así que se mostraría el NIF. El formato está por confirmar con un certificado real.
- **Arreglo:** preferir `givenName` y `surname` cuando existan.
**E5 · Menor.** «Privada» no está definida en las direcciones del localizador.
- **Qué acepta Go:**
- CGNAT (100.64/10, la de Tailscale), 0/8, 192.0.0/24, 198.18/15, 240/4 y 255.255.255.255;
- NAT64 (64:ff9b::/96) con una IPv4 privada dentro, `::a.b.c.d`, 6to4 y fec0::/10;
- `localhost`, `*.localhost` y los nombres de una sola etiqueta.
- **Qué afirman los documentos:** el §76 punto 8 y el README de `testdata` dicen que se rechazan «las IP que no son públicas».
- **Impacto:** latente mientras no haya descargador.
- **Arreglo:** la lista de rangos especiales de IANA, `localhost` y una etiqueta; y en el descargador futuro, comprobar la IP resuelta en cada conexión y redirección.
**E6 · Menor.** El perfil del certificado no está fijado.
- **Qué pasa:** Go (`encoding/asn1` con `pkix`) y TypeScript (lector propio) aceptan y rechazan cosas distintas: unas 1 600 divergencias en el diferencial (T2).
- **Arreglo:** fijarlo campo a campo, como el del `TSTInfo`, y alinear las dos implementaciones.
**E7 · Menor.** OID con arcos de 2^31 o más.
- **Qué dice el spec:** los atributos desconocidos «no deciden nada», y un algoritmo fuera de la tabla es no verificable, o S1 en el sello.
- **Qué hacen las implementaciones:** Go da F1 o S2, porque `encoding/asn1` limita cada arco a int32. TypeScript los acepta.
- **Arreglo:** decidir un límite y fijarlo con un vector. Con el texto actual, el que se equivoca es Go.
**E8 · Menor, con riesgo real.** SET OF con elementos repetidos.
- **Qué pasa:** X.690 no prohíbe repetir elementos, y Go y TypeScript los rechazan («not a SET OF in DER order»).
- **El caso:** una TSA de OpenSSL que repite su certificado en `certs` da S2, y F5 dentro de un CAdES-T. Una firma legítima puede salir como no válida.
- **Arreglo:** decidirlo, fijarlo con un vector y probar con sellos reales.
**E9 · Menor.** Veredictos de borde de Go distintos del spec.
- Un `messageImprint` de longitud errónea da S2, y por el §29.11 sería S3.
- Una clave RSA con ecdsa-with-SHA256, o una EC con rsaEncryption, da F5, y por el paso 3 sería F2.
- Una `accuracy` de más de 2^31 s da S2.
- Un CRL en el token da S2, cuando la regla de solo OCSP es de la firma.
**E10 · Menor.** El CDDL y el §44.1 frente al localizador de Go.
- **El CDDL admite lo que Go rechaza:**
- `? 6 => bstr` admite `h''`, y Go exige 8192 con una base de 4094;
- un desplazamiento 0 explícito, que hace que Go rechace el localizador entero;
- las claves 4 y 1, sin `max-safe-uint`.
- **El §44.1 no menciona** las bases 4094 y 4095 (el mínimo de 3 bytes de la clave 6) ni la 3837 (N = 259).
- **Una sola dirección inválida** inutiliza todo el localizador, aunque el §44.1 habla de rechazar «la dirección».
**E11 · Detalle editorial del texto congelado.**
- El §64 dice que una firma de `alg` 1 abre con F1, y es F2.
- El §67 no lista `format3_signed`, `format3_signed_cms`, `format3_sealed`, `security_cms.json` ni `locator.json`.
- El cierre del §76 dice que esos vectores «se añadirán», y ya están. También los sitúa «sobre `format3_single`», y están sobre `format3_signed`.
- El §44.1 dice que la longitud del localizador no delata las direcciones, y solo es así dentro de 4096 bytes.
- El §55.2 dice que quien aloja el resto no ve nada de la cápsula, pero su tamaño da la longitud del `.dkc`.
## 2. Go (`datekeys-go`)
**G1 · Mayor.** Las pruebas del lector CMS y RFC 3161 no cubren casi ninguna regla negativa.
- **La medida:** de 61 mutantes (quitar una comprobación), 36 dejan todo en verde.
- **Lo que queda sin prueba:**
- la firma de la TSA y el message-digest del `eContent`, que son la base de S3 y S4;
- «fuera de validez» y «no verificable»;
- `signerInfos` desordenados, y dos `SignerInfo` del mismo certificado;
- la versión frente al `sid`;
- ESSCertIDv2 explícito;
- la tabla de algoritmos: el hash igual a `digestAlgorithm`, PSS, los tamaños y la confusión entre clave y esquema;
- los SET OF ordenados;
- el `eContent` en una firma separada y el content-type;
- un `sid` ambiguo y las `crls`;
- el filtro del nombre de la TSA y la precisión en `Before`.
- **Una prueba y un vector que no prueban lo que dicen:** «a seal outside the validity of the certificate» da «invalid seal», no «out of validity».
- **El código en sí está bien:** hace lo correcto en todos los casos que se probaron a mano. Lo que falta son pruebas.
- **El origen del CMS:** `cmstest` es la única fuente de CMS de las pruebas. OpenSSL verifica lo que escribe, pero nunca escribe sha*WithRSA, ESSCertIDv2 explícito, issuerSerial, signing-time, cadenas, millis, ordering, nonce ni tsa.
**G2 · Mayor.** El generador no regenera los fixtures de formato 3 de la v0.10.
- **Qué pasa:** con `-force`, o con `-only format3_single` y similares, los reescribe con un área de 32 768. Después falla en la mutación «SECURITY_LEN 513, larger than AREA_LEN» y deja `testdata` a medias: fixtures nuevos con un `mutations.json` viejo.
- **La causa:** `AreaLen` es 32 768, y `EncryptFiles` no tiene una opción de prueba para el área.
- **Lo que sí funciona:** la ejecución normal es reproducible.
**G3 · Menor.** `-expect-author` escribe los ficheros en `-out` antes de fallar, también los que la CLI marca como peligrosos. Está documentado, pero anula su propósito. Los veredictos se conocen en el paso 17.6: hay que abortar antes del `Commit`.
**G4 · Menor.** `encrypt -sign` no muestra el código de `AUTHOR_MESSAGE` ni la clave `dkauthor1…` con que firma. Lo exige el §62.1, regla 20 (MUST).
**G5 · Menor.** `-expect-author` da F3 con una etiqueta inventada: «guardaste como -expect-author».
**G6 · Menor.** `decrypt` e `inspect -json` no avisan de una nota pública inutilizable. El §24.1 dice «no la muestra y lo notifica». `Header.PublicNote` no distingue una nota ausente de una inutilizable.
**G7 · Menor.** Un nil con tipo en `AuthorKey`, `CMSSigner` o `Sealer` cuenta como ausente: la cápsula sale sin firma o sin sello, y sin error. Es un fallo abierto, y el test lo exige.
**G8 · Menor.** `authorkey.Key.String()` devuelve la clave secreta. Un `%v` en un log o en un error la imprime.
**G9 · Menor.** El escritor no valida la nota ni su sitio.
- **Qué pasa:** no valida una `datekeys.note` que llega por `Noncritical`. Tampoco impide escribirla fuera de su sitio, ni `datekeys.capsule` en `accesskey.Encode`.
- **El caso grave:** en `ControlCritical`, la cápsula se inspecciona bien, y en la fecha `Open` falla con `ERR_EXTENSION_CRITICAL_UNKNOWN`.
- **Qué dice el spec:** el §72 lo prohíbe (MUST NOT). Solo pasa por un mal uso de la API.
**G10 · Menor.** El localizador.
- `ParseInfo` no comprueba que la clave 2 sea un `age` con un único stanza tlock de la ronda de su DateKey. Se descubre en la fecha.
- El escritor no se autocomprueba ni ata la ronda a la DateKey. El §72 pide que decodifique su propia salida.
**G11 · Menor.** Hay DER que no se comprueba.
- Millis y micros no mínimos en `accuracy`.
- El formato de UTCTime y GeneralizedTime: un signing-time «not a time» llega a F6.
- La validez del certificado se lee con un `encoding/asn1` laxo.
- El CHANGELOG dice «DER checked byte by byte».
**G12 · Menor.** E7, E8 y E9 en el código: `der.SetOfSorted` rechaza las repeticiones a propósito, y los OID se leen con `asn1.ObjectIdentifier`.
**G13 · Detalle.**
- **Claves de autor:**
- `ParsePublic` acepta una y canónica fuera de la curva (y = 2), contra su comentario;
- `Read` acepta un logN menor que 16.
- **Textos de la CLI:**
- con `-plain` dice «its passphrase»;
- llama a L «bytes of content»;
- los firmantes ajenos salen con el resultado en inglés;
- t se muestra truncado al segundo.
- **Robustez:**
- ante un pánico, `EvaluateSecurityIn` da X a la firma y al sello, contra el §29.3;
- ECDSA con parámetros NULL sale como no verificable;
- con varios CN toma el primero, y `crypto/x509` toma el último;
- `OpenLocator` con un registro nil entra en pánico;
- el localizador da códigos `ERR_*` donde el §57 dice que no hay código.
- **Direcciones:**
- `CheckURI` acepta caracteres fuera de RFC 3986 (`%zz`, `<`, `{`…);
- `isCIDv1` no comprueba el multihash;
- `ipfs://CID/../..` pasa.
**G14 · Documentación.** `docs/traceability.md` sigue en la v0.10, aunque `CONTRIBUTING.md` exige actualizarlo. `SECURITY.md` dice v0.10. `format3.go` aún comenta «this version defines no alg / no seal_type».
## 3. Datos de prueba compartidos (`testdata`)
Todos los valores criptográficos de los fixtures y vectores nuevos se comprobaron con verificadores propios, y son correctos. Los fallos son de semántica y de cobertura.
**D1 · Mayor.** `security.json` no está en la v0.11.
- **Qué hay:** dice `"spec": "0.11"`, pero sus veredictos son los de un lector de la v0.10: `alg` 1 da F1, `seal_type` 2 da S1, y firma más sello dan F1/S1.
- **Qué dice el §76:** F2, F2/S1 y S2, y casos nuevos con 4294967295, que no están.
- **Por qué pasa la prueba:** evalúa sin contexto.
- **Lo que quedó viejo:** la descripción y el README siguen diciendo que la implementación no implementa ningún `alg`.
**D2 · Mayor.** `format3_seal_unsupported` usa `seal_type` 1, que está reservado, y no 4294967295 como dicen el §67 y el §64. Ningún fichero de `testdata` tiene `seal_type` 4294967295, así que el fixture cambiará de veredicto cuando se defina el tipo 1.
**D3 · Mayor.** La cobertura está muy por debajo de lo que dicen el §64, el §76 y el README.
- **Firma con certificado y sello:**
- no hay ningún caso de «fuera de validez en t»: el vector con ese nombre da «invalid seal»;
- los casos de `SIGNERS` desordenado y vacío llevan un CMS `30 00`, así que fallan por la forma y nunca prueban la regla.
- **Lo del punto 8 del §76:**
- la versión del `SignerInfo` según el `sid`;
- atributos contados por atributo;
- signing-certificate v1 junto al v2;
- ESSCertIDv2 explícito, con SHA-1 o de otro certificado;
- PSS, del que no hay ninguna firma, y el trailerField;
- la accuracy negativa, que es el fallo que cita el propio §76;
- genTime sin Z o con un cero final, millis 0 o 1000, ordering FALSE y campos de más;
- nombres con ESC o U+202E, givenName y surname, y serialNumber.
- **Algoritmos y curvas:** SHA-384 y SHA-512, P-384 y P-521, RSA de 3072 y 4096 bits, y `sid` por SKI.
- **Mutaciones del §64:**
- en `alg` 2: firma retirada con `SIGNERS` cambiado, BER o `signerInfos` desordenados, dos `SignerInfo` del mismo certificado, un algoritmo fuera de la tabla y dos `signature-time-stamp`;
- en el sello: sin message-digest, en BER de verdad, junto a un `alg` desconocido, y t + precisión exactamente igual a round_time;
- en `alg` 1: una firma de otra longitud y una firma trasplantada;
- el área ampliada después de firmar, y la misma P con firma y sin ella: no hay ningún fixture de la v0.11 con 32 KiB y sin firma.
- **La nota pública:** ningún vector ni mutación.
- **`locator.json`:**
- faltan un localizador para otra ronda, un resto con otro SHA-256 o en otro desplazamiento, y un recurso que sigue tras el resto;
- de las direcciones privadas y de enlace local solo está loopback, y faltan también las mapped, las decimales y octales, el punto final, el puerto vacío y la barra invertida;
- en el relleno faltan las bases 3837, 7933, 8166 y 8191.
- **La consecuencia:** una implementación de TypeScript o de Dart con estos fallos pasa todos los vectores. T1 a T5 lo demuestran.
**D4 · Menor.** `mutations.json`.
- `c3175a1` regeneró sin necesidad los 33 casos congelados, contra el «never regenerated» del README; dos pasan de 1 563 a 35 611 bytes.
- El caso F2 de `alg` 1 lleva `spec:false`.
- La numeración del README está desfasada.
**D5 · Menor.** Los fixtures de la v0.10 con `alg` 1 se sobrescribieron con el mismo nombre, así que no queda ningún fixture que dé F2.
**D6 · Menor.** Los dos casos «sin contexto» de `security_cms.json` dan los veredictos de un lector de la v0.10, aunque el fichero es de la v0.11.
**D7 · Menor.** `format3_sealed` y `format3_signed_cms` tienen una mtime posterior al sello, que es la incoherencia del §29.7, y nada lo dice. Tampoco hay ningún caso coherente.
**D8 · Detalle.**
- **README de `testdata`:**
- dice «twenty-one official capsules», y son 24;
- el índice no lista `security_cms.json` ni `locator.json`, y el título dice v0.10;
- dice que RSA-PSS no es determinista, y la firma es PKCS#1 v1.5;
- no documenta el vocabulario de `result`;
- dice que «regenera todo menos .dkc/.dkk», y no regenera los vectores congelados.
- **El generador:** ordena dos casos según un `map` (cambian en 1 214 de cada 10 000 ejecuciones).
- **Los certificados de prueba:** las TSA no tienen la EKU timeStamping (RFC 3161, §2.3).
## 4. TypeScript (`datekeys-ts`)
**T1 · Mayor.** Cuando el emisor incumple las reglas, se muestra el SHA-256 del certificado y no el de su nombre (`securitycms.ts:98`). El §29.7 y Go piden el de `RawIssuer`.
**T2 · Mayor.** El lector de certificados no equivale al de Go: unas 1 600 divergencias. Depende de E6.
- **TypeScript da F6 donde Go da F1:**
- PrintableString con `_` o `@`;
- IA5String con bytes altos;
- BMPString impar o con sustitutos;
- `version [0]` mal formado y `issuerUniqueID`;
- una extensión con el valor en otra posición.
- **TypeScript da F1 donde Go da F6:**
- elementos tras las extensiones o tras la firma;
- un AttributeTypeAndValue de 3 elementos;
- una Validity con UTCTime sin segundos o con desfase.
- **En el certificado de la TSA:** el sello da S4 en TypeScript y S2 en Go.
**T3 · Mayor.** Se aceptan claves EC con el punto comprimido (`Point.fromBytes` de noble), y Go las da por no verificables. Una firma da F6 en TypeScript y F5 en Go; un sello con la TSA comprimida, S4 frente a S1.
**T4 · Mayor.** Una nota con UTF-16 mal formado se escribe alterada.
- **Qué pasa:** con `'a\uD800b'`, `checkNote` la acepta y `newNote` escribe U+FFFD.
- **Por qué importa:** la nota es pública y permanente. Go la rechaza, y el §62.1 (reglas 15 y 23) pide rechazarla sin corregirla.
- **Arreglo:** `isWellFormed()`, y el texto de Go.
**T5 · Menor.** Se pierde el BOM inicial. `TextDecoder` se usa sin `ignoreBOM`, y borra un U+FEFF inicial:
- en un nombre de certificado: TypeScript muestra el nombre y Go el hash;
- en la nota: TypeScript la muestra y Go la trata como inutilizable.
**T6 · Menor.** Se aceptan OID con arcos grandes (E7), que Go rechaza.
**T7 · Menor.** El texto de un emisor sin CN no es el de Go (`RDNSequence.String`), y la prueba de `cms.test.ts:106` lo oculta, porque compara la función consigo misma.
**T8 · Menor.** Más diferencias con Go en el certificado:
- el SPKI es más estricto que en Go, y rechaza elementos de más;
- acepta un módulo RSA par, que Go rechaza;
- un titular en VisibleString, o en BMPString con un terminador o un sustituto suelto, sale distinto.
**T9 · Menor.** `testVectors` y `areaLen` están en las opciones públicas de `encryptFiles`. Cualquier llamante puede escribir un área de 512, que la regla 13 prohíbe y que delata la falta de firma (§55.2). Go no lo expone.
**T10 · Menor.** Ninguna prueba del repo comprueba que Go abra lo que escribe hoy TypeScript.
- **Qué hay:** `capsule-vectors.json` es de `c3c124a`, con un área de 512 y sin nota.
- **Lo que comprobó la revisión, a mano:** Go abre las cápsulas nuevas de TypeScript, con 32 KiB, nota y cada credencial.
- **Arreglo:** regenerarlo con una muestra con nota.
**T11 · Menor.** `capsuleLength` no conoce la nota: predice 35 611 bytes donde se escriben 35 659. Hoy no afecta, porque `/create` no pone nota.
**T12 · Menor.** Más diferencias con Go en la nota:
- `encrypt`, en formato 2, acepta `publicNote` y `areaLen`, que Go rechaza;
- a los errores de la nota les falta «capsule: »: hay 8 textos distintos de Go;
- el orden de las comprobaciones es otro.
**T13 · Detalle.**
- `evaluateSecurity` no tiene try/catch, y Go sí tiene `recover`. Es una sospecha: no salió ninguna excepción en el diferencial.
- `oidOf` e `intOf` son cuadráticos: con 60 KB tardan de 600 a 760 ms.
- Los `!` de `security.ts` cumplen el invariante con los `Verdicts` que da la librería.
- Hay pruebas que no prueban lo que dicen: `cms.test.ts:216` y `:218-220`, y `der.test.ts:49`. Las de Go tienen el mismo defecto.
**T14 · Documentación.**
- Hay comentarios que dicen «area of 512 bytes» e «implements no alg».
- En el README, a la tabla de módulos le faltan `author`, `ed25519strict`, `note`, `cms`, `der` y `securitycms`; los veredictos dicen «solo X a S2»; y la tabla de dependencias está desfasada.
## 5. Documentos de este repo
- **R1.** `HANDOFF.md` tiene tres errores:
- «95 % en total» son umbrales por glob de 95/90/95/95, sin uno global;
- la página ya muestra las líneas de F4 a F6, S3 y S4, y solo falta F3;
- la tabla del §1 está desfasada.
- **R2.** `PLAN_firma_go.md`, líneas 67 y 115, dice que con localizador el escritor omite `verification_metadata`. El spec aprobado dice lo contrario (§43): con el sobre, lo que se guarda fuera tiene otro hash.
- **R3.** A `PLAN_dart.md` le faltan piezas:
- PBKDF2-HMAC-SHA256 de 600 000 iteraciones, para abrir con la llave de palabras. En Dart puro tarda segundos en un móvil: hace falta un HMAC que reutilice el estado y un `Isolate`;
- scrypt, para los ficheros de clave de autor;
- las tablas de Unicode 18.0.0 (NFD, minúsculas y best-fit), generadas por `pathrule/gen` con una salida para Dart y comprobadas con `TablesDigest`.
Además depende de unos vectores incompletos (D3).
- **R4.** En la memoria de Claude, `datekeys-go-library-project.md` no tiene la entrada del 1 y 2 de octubre; solo el índice está al día.
- **R5.** Los commits de la sesión llevan «Co-Authored-By: Claude Sonnet 5.5». Es cierto, aunque la regla del README dice Opus. No se reescribe una historia ya subida.
## 6. Comprobado y correcto
- **Lo que se firma.** Se recalcularon desde los bytes los compromisos, `CONTROL_SIG`, `AUTHOR_MESSAGE` (99 bytes) y su código, `SEAL_SUBJECT` y `SIG_PART`. La firma no depende del área (512, 1024, 32 768 o 65 536 bytes), y el área se decide después de firmar.
- **Ataques a `alg` 1, de extremo a extremo:**
- una firma trasplantada da F2;
- una firma quitada da F0;
- una firma rehecha con otra clave da F4;
- una clave o una firma de otra longitud dan F1.
- **Ed25519 estricto.** Go y TypeScript dan lo esperado en los 18 vectores. Un diferencial de 4 400 casos entre los dos no dio ninguna diferencia.
- **El lector CMS y RFC 3161 de Go:**
- verifica firmas y sellos de OpenSSL;
- pasó unos 13 M de ejecuciones de fuzzing sin pánicos;
- en las firmas: signedAttrs con tag SET, message-digest, ESSCertIDv2 del certificado del `sid`, y RSA de 2048 a 4096 bits con PKCS#1 v1.5 y PSS;
- en el sello: ECDSA con el punto en la curva y r y s en rango, CAdES-T sobre el valor de la firma, `seal_type` 2 sobre `SEAL_SUBJECT`, y S4 solo con genTime + accuracy < round_time.
- **TypeScript frente a Go:**
- `der.ts` es equivalente a `der.go`;
- la estructura de CMS y del `TSTInfo` coincide en 21 083 casos que no tocan los certificados;
- RSA con `BigInt` compara el bloque entero;
- ECDSA usa `prehash: false`, `lowS: false` y el truncado como Go;
- de 72 835 casos, ninguno dio una excepción;
- los textos de los veredictos son literales;
- `lengths.ts` acierta en 32 formas.
- **Datos de prueba:**
- son reproducibles, sin `time.Now`, y no caducan;
- los fixtures nuevos verifican de forma independiente;
- un lector de la v0.10 abre los cinco fixtures de la v0.11 con F1;
- `ae33434` solo cambió `"spec"` en 45 JSON.
- **El localizador y el sobre:**
- el relleno es exacto para toda base de 1 a 12 293;
- la clave `I_SOBRE` es nueva en cada sobre, y el resto no lleva marca;
- los digests se comprueban en orden;
- el tope de 2^53 − 1 se respeta;
- las formas numéricas de los navegadores se rechazan.
- **Compatibilidad:** un lector de la v0.10 abre una cápsula de la v0.11 con nota, y una `.dkk` con `datekeys.capsule`.
## 7. Orden propuesto
1. **El autor decide E1.** Lo recomendado: la v0.11 se queda como está etiquetada, y E2 a E11 abren el borrador v0.12.
2. **En Go, lo que no necesita cambiar el spec:**
- G3 a G11;
- en E7, E8 y E9, el código donde el texto de la v0.11 ya da la razón a otra lectura.
3. **Las pruebas y los datos:** G1, G2 y D1 a D8. Si hace falta, en una rama `v0.12` de `datekeys-go`.
4. **La paridad de TypeScript, T1 a T14,** cuando los vectores ya la cubran.
5. **Dart:** las etapas 0 a 4 del plan no dependen de nada de esto y pueden empezar ya. La etapa 5, la de las firmas y el sello, espera a los vectores del punto 3.
6. **Firmas y sellos reales** (AutoFirma, DNIe, FNMT y una TSA cualificada), para E4, E8 y el tamaño del área.

Powered by TurnKey Linux.