diff --git a/CHANGELOG.md b/CHANGELOG.md index a3f1aa1..fc4c355 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -37,7 +37,9 @@ reader of v0.11 opens these capsules, and this one opens those of v0.11. spaces in a row; the authority of each seal in the lines of F6, with the warning that nobody checks who issued it; the holder by `givenName` and `surname` before the `commonName`, which in the certificates of the FNMT - carries the NIF; the profile of the certificate field by field; object + carries the NIF, when both have text that is not empty, and the issuer by + its `commonName` or, without one that has text, its `organizationName`; + the profile of the certificate field by field; object identifiers by their bytes, repeated elements of a SET OF and the edge cases of the token; the addresses and the padding of the locator; and the errata of §44.1, §55.2, §64, §67 and §76. The CDDL fixes the sizes of the locator. diff --git a/docs/traceability.md b/docs/traceability.md index 7a00806..3851e44 100644 --- a/docs/traceability.md +++ b/docs/traceability.md @@ -51,7 +51,7 @@ the same. A case of §64 that is not in the repository yet is marked | 29.5 | Paths: R1 and R8 in layer 3; R2 to R6c, R4b and R10 for each entry, then R7 and R9 over the tree, in layer 4; the key of R7; errors that name the rule and the character, never the text | `internal/pathrule` (`CheckPath`, `CheckTree`, `Key`, `NFD`, `Fold`, `Error`) | `pathrule.TestCheckPath`, `TestCheckTree`, `TestKey`, `TestNFD`; `testdata/vectors/paths.json` and `path_fold.json` (`internal/testkit.PathVectors`, `PathFoldVectors`, `TestFormat3VectorFiles`); the path mutations of §64 | | 29.5.1 | Tables: Unicode 18.0.0 and the 15 WindowsBestFit tables, pinned by their SHA-256, never the Unicode functions of the platform | `internal/pathrule/gen`, which checks the 19 pinned files in `.cache` and writes `tables.go`; `pathrule.UnicodeVersion`, `TablesDigest` | `pathrule.TestTablesDigest`, `TestProperties`; NFD and folding compared with `golang.org/x/text` outside this module | | 29.6 | Text of the comment and of the declared author: no control but TAB and LF in the comment, no bidirectional control, separator, byte order mark or noncharacter, the invisibles rule with R4b for each line, no space at the ends of the author; the writer turns CR LF and a lone CR into LF | `pathrule.CheckComment`, `CheckAuthor`; `capsule.EncryptFiles` (`newHead`) | `pathrule.TestTexts`; `testdata/vectors/head_schema.json`; `capsule.TestEncryptFilesRoundTrip`, `TestEncryptFilesRejects` | -| 29.7 | Verdicts X, F0 to F6 and S0 to S5, for each part the first row of the table that holds, with the texts of the table; the name of a certificate between « and », shown when it meets the rules of the declared author, has at most 64 code points and no two spaces in a row, and its SHA-256 otherwise; the holder by `givenName` and `surname` before `commonName`, the issuer by `commonName` or `organizationName`; after F6, a line for each required signer with the authority of its seal, and «DateKeys no comprueba quién emitió los sellos.» when one says before the date; a foreign signer apart, with its result in Spanish; before the date only by a valid seal with t + accuracy < round_time, with its warning; an mtime later than a valid seal shown as an inconsistency (SHOULD); the presentation: the verdicts first and last, the labels of the text of the creator, TABs expanded, pieces of at most W − 3 columns behind `│ ` with the width counted by excess, the lines of the verdicts in rows of at most W − 3 columns, broken at the last space that fits, each row after the first behind ` ↳ `, and warnings of risky names | `capsule.Verdict`, `Verdict.Text`, `Verdicts.Lines`, `Verdicts.SealedAt`, `Detail`, `SignerLine` (`quoted`, `instant`, `resultText`), `holderText`, `MaxNameLen`; `internal/cms` `Cert.Holder`, `Cert.IssuerName`; `capsule.Open` step 17.6 (`newSecurityContext`, `openBody`), `OpenOptions.AuthorKeys` (F3), `OpenOptions.Accept` (the verdicts before step 18); `cmd/datekeys.present` (`writeVerdicts`, `rows`, `contMark`, `writeCreator`, `pieces`, `expandTabs`, `outputWidth`, `termWidth`, `risks`) | `capsule.TestSecurityVerdicts`, `TestEvaluateSecurityIn` (the lines of F3 and F4), `TestEvaluateCMS` (the lines of F6 with the authority of each seal and the warning, a late seal without it, a foreign signer), `TestEvaluateSeal` (the line of S4), `TestIssuerTextFiltered`, `TestCMSVectors`; the lines of the records of the fixtures (`capsule.TestConformanceFixtures`) and of `testdata/vectors/security.json` (`internal/testkit.TestFormat3VectorFiles`); `cmd/datekeys.TestRows`, `TestPresent`, `TestMTimeAfterSeal`, `TestAuthorSignRoundTrip`, `TestEncryptDecryptRoundTrip`, `TestDecryptFormat3Fixtures`; the names of §64 of v0.12 (two spaces, more than 64 code points, ESC, U+202E, a byte order mark, `givenName` and `surname` with a NIF in `commonName`, an issuer without text): `security_cms.json` | +| 29.7 | Verdicts X, F0 to F6 and S0 to S5, for each part the first row of the table that holds, with the texts of the table; the name of a certificate between « and », shown when it meets the rules of the declared author, has at most 64 code points and no two spaces in a row, and its SHA-256 otherwise; the holder by `givenName` and `surname` before `commonName` when both have text that is not empty, the issuer by `commonName` or, without one that has text, `organizationName`; after F6, a line for each required signer with the authority of its seal, and «DateKeys no comprueba quién emitió los sellos.» when one says before the date; a foreign signer apart, with its result in Spanish; before the date only by a valid seal with t + accuracy < round_time, with its warning; an mtime later than a valid seal shown as an inconsistency (SHOULD); the presentation: the verdicts first and last, the labels of the text of the creator, TABs expanded, pieces of at most W − 3 columns behind `│ ` with the width counted by excess, the lines of the verdicts in rows of at most W − 3 columns, broken at the last space that fits, each row after the first behind ` ↳ `, and warnings of risky names | `capsule.Verdict`, `Verdict.Text`, `Verdicts.Lines`, `Verdicts.SealedAt`, `Detail`, `SignerLine` (`quoted`, `instant`, `resultText`), `holderText`, `MaxNameLen`; `internal/cms` `Cert.Holder`, `Cert.IssuerName`; `capsule.Open` step 17.6 (`newSecurityContext`, `openBody`), `OpenOptions.AuthorKeys` (F3), `OpenOptions.Accept` (the verdicts before step 18); `cmd/datekeys.present` (`writeVerdicts`, `rows`, `contMark`, `writeCreator`, `pieces`, `expandTabs`, `outputWidth`, `termWidth`, `risks`) | `capsule.TestSecurityVerdicts`, `TestEvaluateSecurityIn` (the lines of F3 and F4), `TestEvaluateCMS` (the lines of F6 with the authority of each seal and the warning, a late seal without it, a foreign signer), `TestEvaluateSeal` (the line of S4), `TestIssuerTextFiltered`, `TestCMSVectors`; the lines of the records of the fixtures (`capsule.TestConformanceFixtures`) and of `testdata/vectors/security.json` (`internal/testkit.TestFormat3VectorFiles`); `cmd/datekeys.TestRows`, `TestPresent`, `TestMTimeAfterSeal`, `TestAuthorSignRoundTrip`, `TestEncryptDecryptRoundTrip`, `TestDecryptFormat3Fixtures`; the names of §64 of v0.12 (two spaces, more than 64 code points, ESC, U+202E, a byte order mark, `givenName` and `surname` with a NIF in `commonName`, an issuer without text): `security_cms.json` | | 29.8 | Author signature, what is signed: `payload_commit`; `CONTROL_SIG`, the control with `payload_commit` in place of `I_PAYLOAD` and L at zero; `control_commit`, `head_digest`, `signers_digest`, and `AUTHOR_MESSAGE`, ASCII of 99 bytes, with its code of 8 characters; never the area or the padding, so the area can grow after signing; every value recomputed from the opened capsule | `capsule.PayloadCommit`, `ControlCommit`, `HeadDigest`, `SignersDigest`, `AuthorMessage`, `AuthorMessagePrefix`, `AuthorMessageSize`, `AuthorCode`; `capsule.Open` step 17.6 (`newSecurityContext`); the writer signs once the control is final, in the `prepare` that `EncryptFiles` gives `sealer.write` (`sealer.security`) | `capsule.TestAuthorMessage` (99 bytes, the code, `control_commit` without L and with `I_PAYLOAD`), `TestSignedFixtureVerdicts` (another control or head: F2), `TestAreaChosenAfterSigning` (signed once); `TestConformanceFixtures` (`checkSignature3`: the commitments, `AUTHOR_MESSAGE` and its code in the records of `format3_signed`, `format3_signed_cms` and `format3_sealed`); mutations *the signature of alg 1 transplanted to another capsule …*, *the area widened to 64 KiB after signing …* | | 29.9 | Signature with a key of one's own, `alg` 1: Ed25519 of `AUTHOR_MESSAGE`; a key or a signature of another length is F1; valid only with A canonical and not of small order, `sig[63] & 0xE0` = 0, S < ℓ and the equation without the cofactor, F2 otherwise; F4, or F3 with a key the person saved | `internal/ed25519strict` (`Verify`, `Canonical`, `SmallOrder`, `SmallOrderPoints`, `OnCurve`), around `crypto/ed25519`; `capsule.evaluateSignature`; `EncryptOptions.AuthorKey`, the interface `capsule.AuthorKey` | `ed25519strict.TestVectors`, `TestVerifyRejectsWhatStdlibAccepts`, `TestCanonical`, `TestSmallOrderTable`, `TestOnCurve`; `testdata/vectors/ed25519_strict.json`, the cases of «Taming the many EdDSAs» (`internal/testkit.Ed25519StrictVectors`); `capsule.TestEvaluateSecurityIn`, `TestEncryptFilesSigned`, `TestEncryptFilesSignatureChecked`, `TestSignedFixtureVerdicts`; fixture `format3_signed`, whose signature `TestConformanceFixtures` makes again from its seed; mutations *a signature of alg 1 that does not verify …* and those of `alg` 1 of the list of v0.11: altered, removed, made again with another key, transplanted, a key of 31 bytes and a signature of 65 | | 29.10 | Signature with certificates, `alg` 2: a detached CMS signature with the CAdES profile; `SIGNERS`, 1 to 16 SHA-256 of certificates in strictly ascending order; the form in its order (F1), with the version of a `SignerInfo` by its `sid`, attributes counted by attribute, a `signing-certificate` beside the v2 that decides nothing, an `ESSCertIDv2` with SHA-256 written, the parameters of PSS, object identifiers compared by the bytes of their DER and a SET OF that repeats an element; the closed table of algorithms; the profile of the certificate field by field, its key RSA with NULL parameters and an odd modulus, or EC uncompressed on P-256, P-384 or P-521; the result of each required signer in its order: absent, not verifiable, invalid (a key of another scheme than the algorithm included), without seal, invalid seal, out of validity, valid; F2, F5 or F6; no key 3; never who issued a certificate or whether it was revoked | `internal/der` (`Check`, `Split`, `Content`, `SetOfSorted`, `ParseTime`); `internal/cms` (`ParseSignature`, `SignedData`, `SignerInfo`, `SignerInfo.Check`, `ParseCert`, `Cert`, `Cert.ValidAt`, `ErrForm`, `ErrAlgorithm`), with the standard library only; `capsule.EncodeSigners`, `decodeSigners`, `MaxSigners`, `evaluateCMS`, `signerLine`; `EncryptOptions.CMSSigner`, the interface `capsule.CMSSigner`; `internal/cms/cmstest`, which makes certificates, signatures and tokens for the tests | `cms.TestSignatureAlgorithms` (RSA PKCS #1 v1.5 and PSS, SHA-256 to SHA-512, ECDSA on P-256, P-384 and P-521, a `sid` by `subjectKeyIdentifier`), `TestCoSignature`, `TestSignatureNotVerifiable`, `TestSignatureForm`, `TestSignatureStrictness`; `der.TestCheck`, `TestSetOfSorted`, `TestDepth`, `TestParseTime`, `TestSplit`; `capsule.TestEvaluateCMS` (a required signer absent, without seal, a key 3 beside it, another head, `SIGNERS` out of order or empty), `TestEncodeSigners`, `TestEncryptFilesCMSAndSeal`, `TestCMSVectors` (`testdata/vectors/security_cms.json`); fixture `format3_signed_cms`; the cases of `alg` 2 of §64 of v0.12 (a certificate out of validity with a valid TSA, the profile of the certificate, identifiers, repetitions, keys of another scheme or compressed): `security_cms.json` | diff --git a/spec/DateKeys_Protocol_Specification_v0.12.md b/spec/DateKeys_Protocol_Specification_v0.12.md index ecf3f66..551b5ca 100644 --- a/spec/DateKeys_Protocol_Specification_v0.12.md +++ b/spec/DateKeys_Protocol_Specification_v0.12.md @@ -1329,7 +1329,7 @@ El SDK oficial MUST usar los textos de esta tabla. Otra implementación MUST usa En los textos, ‹etiqueta› es la que la persona dio a una clave guardada (§29.12), y ‹t›, el instante del sello en UTC, en la forma de RFC 3339, con su fracción de segundo si la tiene. ‹titulares› son los nombres de los titulares de los certificados de los firmantes exigidos, y ‹TSA›, el del titular del certificado de la autoridad de sellado, cada uno entre « y » (U+00AB y U+00BB), y varios, separados por una coma y un espacio: así se ve dónde empieza y dónde acaba lo que escribió quien hizo el certificado. -El nombre de un certificado se toma de su `subject` con el perfil de §29.10: su `givenName` y su `surname`, separados por un espacio, si tiene uno de cada, y si no, su `commonName`; nunca su `serialNumber`, y el `commonName` va detrás porque puede llevar el identificador nacional de la persona. Se muestra si cumple las reglas del autor declarado de §29.6, tiene como mucho 64 puntos de código y no lleva dos espacios seguidos; si no, o si el certificado no da un nombre, se muestra el SHA-256 del certificado en hexadecimal. +El nombre de un certificado se toma de su `subject` con el perfil de §29.10: su `givenName` y su `surname`, separados por un espacio, si tiene uno de cada y los dos tienen texto (§29.10) no vacío, y si no, su `commonName`; nunca su `serialNumber`, y el `commonName` va detrás porque puede llevar el identificador nacional de la persona. Se muestra si cumple las reglas del autor declarado de §29.6, tiene como mucho 64 puntos de código y no lleva dos espacios seguidos; si no, o si el certificado no da un nombre, se muestra el SHA-256 del certificado en hexadecimal. Con F6, el lector MUST mostrar además, tras su línea, una por cada firmante exigido, en el orden de `SIGNERS`: @@ -1337,7 +1337,7 @@ Con F6, el lector MUST mostrar además, tras su línea, una por cada firmante ex «‹titular›» (emisor según su certificado: «‹emisor›»), sellado por «‹TSA›» el ‹t›, antes de la fecha de apertura. ``` -con «no antes de la fecha de apertura» si t más su precisión no es anterior a round_time. ‹emisor› es el `commonName` del emisor que dice el certificado, o si no tiene, su `organizationName`, con las reglas de un titular; si no hay, o las incumple, el SHA-256 de su nombre, el DER de su `Name`, en hexadecimal. Si alguna de esas líneas dice «antes de la fecha de apertura», el lector MUST añadir después la línea ` DateKeys no comprueba quién emitió los sellos.`. Un `SignerInfo` cuyo certificado no está entre los exigidos se muestra aparte, con su resultado, y no cuenta (§29.10): +con «no antes de la fecha de apertura» si t más su precisión no es anterior a round_time. ‹emisor› es el `commonName` del emisor que dice el certificado, o si no tiene uno con texto (§29.10), su `organizationName`, con las reglas de un titular; si no hay, o las incumple, el SHA-256 de su nombre, el DER de su `Name`, en hexadecimal. Si alguna de esas líneas dice «antes de la fecha de apertura», el lector MUST añadir después la línea ` DateKeys no comprueba quién emitió los sellos.`. Un `SignerInfo` cuyo certificado no está entre los exigidos se muestra aparte, con su resultado, y no cuenta (§29.10): ```text Otro firmante, «‹titular›»: ‹resultado›. No cuenta. @@ -4117,10 +4117,10 @@ La v0.12 corrige lo que encontró la revisión de la implementación de la v0.11 - Caso: quien abre una cápsula puede rehacer el área con su certificado y su propia autoridad de sellado (§7.9), y la línea de F6 decía «antes de la fecha de apertura» sin más. - Pruebas previstas: `format3_signed_cms` (§67). 3. **El titular sin su identificador** (§29.7, §55.2). - - Cambio: el titular es su `givenName` y su `surname` antes que su `commonName`. - - Motivo: el `commonName` de un certificado de persona física de la FNMT es «APELLIDOS NOMBRE - NIF», y §55.2 promete el nombre sin el `serialNumber`. - - Caso: un certificado con el `givenName` «JUAN», el `surname` «ESPAÑOL ESPAÑOL» y el `commonName` «ESPAÑOL ESPAÑOL JUAN - 12345678Z» se mostraba con el NIF. - - Pruebas previstas: `security_cms.json`. + - Cambio: el titular es su `givenName` y su `surname` antes que su `commonName`, si tiene uno de cada y los dos tienen texto no vacío; el emisor es su `commonName`, o si no tiene uno con texto, su `organizationName`. + - Motivo: el `commonName` de un certificado de persona física de la FNMT es «APELLIDOS NOMBRE - NIF», y §55.2 promete el nombre sin el `serialNumber`. El texto no decía qué pasaba con un atributo sin texto: la implementación de referencia lo trataba como ausente, y una que siguiera el texto podía mostrar otro nombre. + - Caso: un certificado con el `givenName` «JUAN», el `surname` «ESPAÑOL ESPAÑOL» y el `commonName` «ESPAÑOL ESPAÑOL JUAN - 12345678Z» se mostraba con el NIF. Con un `givenName` vacío, repetido o en un `VisibleString`, la referencia muestra el `commonName`. + - Pruebas previstas: `security_cms.json` y las del titular y el emisor de `internal/cms` (`cert_test.go`). 4. **El perfil del certificado** (§29.10). - Cambio: un lector lee un certificado campo a campo, con el perfil de §29.10, y no con lo que acepte su biblioteca; un certificado que lo incumple no decide nada salvo que lo nombre un `SignerInfo`; la clave EC va sin comprimir, y la RSA con un módulo impar. - Motivo: «con sus propias reglas (RFC 5280)» dejaba a cada implementación lo que aceptaba: la de referencia y la de TypeScript daban veredictos distintos a unos 1 600 certificados de un diferencial.