- testdata/README.md: the files of v0.11 and of the draft, the spec
label 0.11 until the approval, 26 fixtures with format3_unsigned and
format3_note, security.json in its context with lines, security_cms.json
without the cases of no context, note.json, the new parts of
locator.json, and the corpus of 218 cases, 178 of the spec, with the
eight of the list of v0.11. The release of round 1000 is in the records
and in mutations.json, not in quicknet_rounds.json.
- docs/traceability.md: the cases of section 64 that security_cms.json
and locator.json now hold are no longer pending.
- CHANGELOG: security_cms.json and locator.json under the test data of
the draft, instead of pending.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@ -51,11 +51,11 @@ 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 | 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.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.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,withitswarning;anmtimelaterthanavalidsealshownasaninconsistency(SHOULD);thepresentation:theverdictsfirstandlast,thelabelsofthetextofthecreator,TABsexpanded,piecesofatmostW−3columnsbehind`│ `withthewidthcountedbyexcess,thelinesoftheverdictsinrowsofatmostW−3columns,brokenatthelastspacethatfits,eachrowafterthefirstbehind` ↳ `,andwarningsofriskynames|`capsule.Verdict`,`Verdict.Text`,`Verdicts.Lines`,`Verdicts.SealedAt`,`Detail`,`SignerLine`(`quoted`,`instant`,`resultText`),`holderText`,`MaxNameLen`;`internal/cms``Cert.Holder`,`Cert.IssuerName`;`capsule.Open`step17.6(`newSecurityContext`,`openBody`),`OpenOptions.AuthorKeys`(F3),`OpenOptions.Accept`(theverdictsbeforestep18);`cmd/datekeys.present`(`writeVerdicts`,`rows`,`contMark`,`writeCreator`,`pieces`,`expandTabs`,`outputWidth`,`termWidth`,`risks`)|`capsule.TestSecurityVerdicts`,`TestEvaluateSecurityIn`(thelinesofF3andF4),`TestEvaluateCMS`(thelinesofF6withtheauthorityofeachsealandthewarning,alatesealwithoutit,aforeignsigner),`TestEvaluateSeal`(thelineofS4),`TestIssuerTextFiltered`,`TestCMSVectors`;thelinesoftherecordsofthefixtures(`capsule.TestConformanceFixtures`)andof`testdata/vectors/security.json`(`internal/testkit.TestFormat3VectorFiles`);`cmd/datekeys.TestRows`,`TestPresent`,`TestMTimeAfterSeal`,`TestAuthorSignRoundTrip`,`TestEncryptDecryptRoundTrip`,`TestDecryptFormat3Fixtures`;thenamesof§64ofv0.12(twospaces,morethan64codepoints,ESC,U+202E,abyteordermark,`givenName`and`surname`withaNIFin`commonName`,anissuerwithouttext):`security_cms.json`,*pending*|
| 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,withitswarning;anmtimelaterthanavalidsealshownasaninconsistency(SHOULD);thepresentation:theverdictsfirstandlast,thelabelsofthetextofthecreator,TABsexpanded,piecesofatmostW−3columnsbehind`│ `withthewidthcountedbyexcess,thelinesoftheverdictsinrowsofatmostW−3columns,brokenatthelastspacethatfits,eachrowafterthefirstbehind` ↳ `,andwarningsofriskynames|`capsule.Verdict`,`Verdict.Text`,`Verdicts.Lines`,`Verdicts.SealedAt`,`Detail`,`SignerLine`(`quoted`,`instant`,`resultText`),`holderText`,`MaxNameLen`;`internal/cms``Cert.Holder`,`Cert.IssuerName`;`capsule.Open`step17.6(`newSecurityContext`,`openBody`),`OpenOptions.AuthorKeys`(F3),`OpenOptions.Accept`(theverdictsbeforestep18);`cmd/datekeys.present`(`writeVerdicts`,`rows`,`contMark`,`writeCreator`,`pieces`,`expandTabs`,`outputWidth`,`termWidth`,`risks`)|`capsule.TestSecurityVerdicts`,`TestEvaluateSecurityIn`(thelinesofF3andF4),`TestEvaluateCMS`(thelinesofF6withtheauthorityofeachsealandthewarning,alatesealwithoutit,aforeignsigner),`TestEvaluateSeal`(thelineofS4),`TestIssuerTextFiltered`,`TestCMSVectors`;thelinesoftherecordsofthefixtures(`capsule.TestConformanceFixtures`)andof`testdata/vectors/security.json`(`internal/testkit.TestFormat3VectorFiles`);`cmd/datekeys.TestRows`,`TestPresent`,`TestMTimeAfterSeal`,`TestAuthorSignRoundTrip`,`TestEncryptDecryptRoundTrip`,`TestDecryptFormat3Fixtures`;thenamesof§64ofv0.12(twospaces,morethan64codepoints,ESC,U+202E,abyteordermark,`givenName`and`surname`withaNIFin`commonName`,anissuerwithouttext):`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.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.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`, *pending* |
| 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` |
| 29.11 | Time seal, RFC 3161: the CAdES-T of each signer of `alg` 2, over its signature value, or `seal_type` 2 in key 3, over `SEAL_SUBJECT`, without a signature or with `alg` 1; `SIG_PART`; the profile of the token in its order: the form (S2), with the `TSTInfo` in DER field by field, `genTime` in UTC with Z, `accuracy` of 0 to 2³¹ − 1 seconds and minimal millis and micros, `ordering` only TRUE, nothing after the last field, and `crls` deciding nothing; the algorithms (S1); the verification (S3), a `messageImprint` of another length included; S4 when t + accuracy <round_time,S5otherwise|`internal/cms`(`ParseToken`,`Token`,`Token.Check`,`Token.ImprintIsSHA256`,`parseTSTInfo`,`parseAccuracy`);`capsule.SigPart`,`SealSubject`,`SealTypeRFC3161`,`evaluateSeal`,`signerLine`;`EncryptOptions.Sealer`,theinterface`capsule.Sealer`|`cms.TestTokenOverSignature`,`TestTokenFailures`,`TestTSTInfoStrict`(anegativeaccuracy,millisof0,a`genTime`withanoffsetoratrailingzero,`ordering`FALSEwritten,afieldafterthelast);`capsule.TestEvaluateSeal`,`TestEncryptFilesCMSAndSeal`,`TestCMSVectors`;fixture`format3_sealed`;thecasesof`seal_type`2of§64ofv0.12:`security_cms.json`,*pending*|
| 29.11 | Time seal, RFC 3161: the CAdES-T of each signer of `alg` 2, over its signature value, or `seal_type` 2 in key 3, over `SEAL_SUBJECT`, without a signature or with `alg` 1; `SIG_PART`; the profile of the token in its order: the form (S2), with the `TSTInfo` in DER field by field, `genTime` in UTC with Z, `accuracy` of 0 to 2³¹ − 1 seconds and minimal millis and micros, `ordering` only TRUE, nothing after the last field, and `crls` deciding nothing; the algorithms (S1); the verification (S3), a `messageImprint` of another length included; S4 when t + accuracy <round_time,S5otherwise|`internal/cms`(`ParseToken`,`Token`,`Token.Check`,`Token.ImprintIsSHA256`,`parseTSTInfo`,`parseAccuracy`);`capsule.SigPart`,`SealSubject`,`SealTypeRFC3161`,`evaluateSeal`,`signerLine`;`EncryptOptions.Sealer`,theinterface`capsule.Sealer`|`cms.TestTokenOverSignature`,`TestTokenFailures`,`TestTSTInfoStrict`(anegativeaccuracy,millisof0,a`genTime`withanoffsetoratrailingzero,`ordering`FALSEwritten,afieldafterthelast);`capsule.TestEvaluateSeal`,`TestEncryptFilesCMSAndSeal`,`TestCMSVectors`;fixture`format3_sealed`;thecasesof`seal_type`2of§64ofv0.12:`security_cms.json`|
| 29.12 | Author keys of `alg` 1: a seed of Ed25519; the public key `dkauthor1…`, 67 characters in lower case, and the secret key `DKAUTHOR-SECRET-KEY-1…`, 79 in upper case, refused in another case, length or prefix, or with padding bits that are not zero; a public key canonical, a point of the curve and not of small order; a file of a secret key encrypted with age and a passphrase, scrypt of logN 16; a key that the person saved gives F3 with her label | `authorkey` (`Generate`, `NewFromSeed`, `Key.Public`, `Key.Sign`, `Key.Secret`, `Key.String` and `Key.GoString`, which hide the secret key, `Key.Clear`, `PublicString`, `ParsePublic`, `ParseSecret`, `Marshal`, `Encrypt`, `Read`, `WorkFactor`); `capsule.OpenOptions.AuthorKeys`; `cmd/datekeys`: `author keygen` and `author public` (`authorKeygen`, `authorPublic`, `loadAuthorKey`, `readPass`: the passphrase from a file or the standard input), `encrypt -sign` (`announced`), `decrypt -expect-author` | `authorkey.TestStrings` (a printed key never shows its secret), `TestParseRejects` (y = 2, off the curve), `TestFiles`; `ed25519strict.TestOnCurve`; `capsule.TestEncryptFilesSigned` (F3 with the key saved); `cmd/datekeys.TestAuthorSignRoundTrip` |
| 29.12 | Author keys of `alg` 1: a seed of Ed25519; the public key `dkauthor1…`, 67 characters in lower case, and the secret key `DKAUTHOR-SECRET-KEY-1…`, 79 in upper case, refused in another case, length or prefix, or with padding bits that are not zero; a public key canonical, a point of the curve and not of small order; a file of a secret key encrypted with age and a passphrase, scrypt of logN 16; a key that the person saved gives F3 with her label | `authorkey` (`Generate`, `NewFromSeed`, `Key.Public`, `Key.Sign`, `Key.Secret`, `Key.String` and `Key.GoString`, which hide the secret key, `Key.Clear`, `PublicString`, `ParsePublic`, `ParseSecret`, `Marshal`, `Encrypt`, `Read`, `WorkFactor`); `capsule.OpenOptions.AuthorKeys`; `cmd/datekeys`: `author keygen` and `author public` (`authorKeygen`, `authorPublic`, `loadAuthorKey`, `readPass`: the passphrase from a file or the standard input), `encrypt -sign` (`announced`), `decrypt -expect-author` | `authorkey.TestStrings` (a printed key never shows its secret), `TestParseRejects` (y = 2, off the curve), `TestFiles`; `ed25519strict.TestOnCurve`; `capsule.TestEncryptFilesSigned` (F3 with the key saved); `cmd/datekeys.TestAuthorSignRoundTrip` |
| 30 | PAYLOAD_AGE is a complete age file | `filippo.io/age` public API only | `capsule.TestInteropAgeOpensPayload` (`-tags interop`, official `age` CLI) |
| 30 | PAYLOAD_AGE is a complete age file | `filippo.io/age` public API only | `capsule.TestInteropAgeOpensPayload` (`-tags interop`, official `age` CLI) |
| 30.1 | CONTROL_CBOR ↔ PAYLOAD_AGE binding; in format 2, L and the code fix the length and the padding of the plaintext, which adds determinism, not authenticity | `agewrap.PayloadIdentity` | mutations *SEALED_CONTROL_A + PAYLOAD_AGE_B*, *padding code 2 changed to 1, with L = 78000*, *payload_length L - 1, the last byte of the content not zero*; `capsule.TestTrustModel` (another L of the same P); `agewrap.TestPayloadIdentityStrictness` |
| 30.1 | CONTROL_CBOR ↔ PAYLOAD_AGE binding; in format 2, L and the code fix the length and the padding of the plaintext, which adds determinism, not authenticity | `agewrap.PayloadIdentity` | mutations *SEALED_CONTROL_A + PAYLOAD_AGE_B*, *padding code 2 changed to 1, with L = 78000*, *payload_length L - 1, the last byte of the content not zero*; `capsule.TestTrustModel` (another L of the same P); `agewrap.TestPayloadIdentityStrictness` |
@ -75,7 +75,7 @@ the same. A case of §64 that is not in the repository yet is marked
| 44.1 | The extension `datekeys.capsule` of a `.dkk`, noncritical: the note, the DateKey and an optional locator, an age file with one tlock stanza for the round of that DateKey, unusable for another round or chain; its plaintext, 1 to 8 addresses, `I_SOBRE`, the header of the envelope, the digest and the size of the rest, `capsule_digest` and a zero padding of at least one byte, of exactly 4096 bytes or the least multiple that holds it; the envelope, the `.dkc` in age split into the header and a rest without a mark, alone or inside a host at an offset; the addresses, ASCII of RFC 3986, read without decoding: `https` with a host of letters, digits and hyphens or a public IP outside the special-purpose blocks of IANA, no local name, no dot segment, or `ipfs` with a CID v1 in base32; a reader rejects each address that breaks them and uses the others; the rest and the `.dkc` checked by their digests; a writer never writes a rejected address and decodes what it writes | `locator` (`Info`, `Info.Extension`, `ParseInfo`, `Info.OpenLocator`, `Standard`; `Locator`, `Locator.Marshal`, `Unmarshal`, `Locator.Usable`, `PlaintextLength`, `Block`, `MaxAddresses`, `MaxURILen`, `MaxHeaderLen`; `Seal`, `Open`; `NewEnvelope`, `Locator.OpenEnvelope`, `Hide`, `Locator.RestIn`; `Address`, `Address.Host`, `CheckURI`), which downloads nothing; `extension.CapsuleID`, `extension.Standard` (`ValidateCapsule`); `accesskey.AccessKey.MarshalBody` (`extension.CheckWrite`); `spec/datekeys.cddl` (`capsule-locator`, `capsule-address`) | `locator.TestEnvelope`, `TestLocatorPlaintext`, `TestAddresses` (the blocks of IANA, NAT64, mapped and 6to4 addresses, local names, characters outside RFC 3986, dot segments, CIDs that do not decode), `TestSealedLocator` (another round or release: unusable), `TestInfo`, `TestUsableAddresses`, `TestLeastMultiple`, `TestPaddingBoundaries`, `TestLocatorVectors` (`testdata/vectors/locator.json`); `capsule.TestRegisteredExtensionsWhereRegistered` (never in a capsule); the cases of §64 of v0.11 and v0.12 for `datekeys.capsule`that `locator.json` lacks: *pending* |
| 44.1 | The extension `datekeys.capsule` of a `.dkk`, noncritical: the note, the DateKey and an optional locator, an age file with one tlock stanza for the round of that DateKey, unusable for another round or chain; its plaintext, 1 to 8 addresses, `I_SOBRE`, the header of the envelope, the digest and the size of the rest, `capsule_digest` and a zero padding of at least one byte, of exactly 4096 bytes or the least multiple that holds it; the envelope, the `.dkc` in age split into the header and a rest without a mark, alone or inside a host at an offset; the addresses, ASCII of RFC 3986, read without decoding: `https` with a host of letters, digits and hyphens or a public IP outside the special-purpose blocks of IANA, no local name, no dot segment, or `ipfs` with a CID v1 in base32; a reader rejects each address that breaks them and uses the others; the rest and the `.dkc` checked by their digests; a writer never writes a rejected address and decodes what it writes | `locator` (`Info`, `Info.Extension`, `ParseInfo`, `Info.OpenLocator`, `Standard`; `Locator`, `Locator.Marshal`, `Unmarshal`, `Locator.Usable`, `PlaintextLength`, `Block`, `MaxAddresses`, `MaxURILen`, `MaxHeaderLen`; `Seal`, `Open`; `NewEnvelope`, `Locator.OpenEnvelope`, `Hide`, `Locator.RestIn`; `Address`, `Address.Host`, `CheckURI`), which downloads nothing; `extension.CapsuleID`, `extension.Standard` (`ValidateCapsule`); `accesskey.AccessKey.MarshalBody` (`extension.CheckWrite`); `spec/datekeys.cddl` (`capsule-locator`, `capsule-address`) | `locator.TestEnvelope`, `TestLocatorPlaintext`, `TestAddresses` (the blocks of IANA, NAT64, mapped and 6to4 addresses, local names, characters outside RFC 3986, dot segments, CIDs that do not decode), `TestSealedLocator` (another round or release: unusable), `TestInfo`, `TestUsableAddresses`, `TestLeastMultiple`, `TestPaddingBoundaries`, `TestLocatorVectors` (`testdata/vectors/locator.json`); `capsule.TestRegisteredExtensionsWhereRegistered` (never in a capsule); the cases of §64 of v0.11 and v0.12 for `datekeys.capsule`in `locator.json`: the addresses, a locator with a rejected address and a usable one, the resources of the rest, the data of the extension and the plaintexts of the locator |
| 45 | Release API | `provider.ReleaseSource` interface only (server out of scope, plan §2) | — |
| 45 | Release API | `provider.ReleaseSource` interface only (server out of scope, plan §2) | — |
| 46 | Release Queue | out of scope (server) | — |
| 46 | Release Queue | out of scope (server) | — |
| 47 | Release Cache | every release is verified again: `capsule.Open` step 10 and `agewrap.TimeIdentity` | mutations *release of another round* |
| 47 | Release Cache | every release is verified again: `capsule.Open` step 10 and `agewrap.TimeIdentity` | mutations *release of another round* |
@ -99,7 +99,7 @@ the same. A case of §64 that is not in the repository yet is marked
| 62 | `time_and_key` encryption flow, format 3: 16 recipients, and the SEALED_CONTROL_LEN of an INNER_ACCESS_AGE of 16 stanzas | `capsule.EncryptFiles` | `capsule.TestEncryptFilesTimeAndKey`, `TestEncryptRoundTripBothPolicies`, `TestPortableKeysAreNeverReused`, `TestSealedControlLength` |
| 62 | `time_and_key` encryption flow, format 3: 16 recipients, and the SEALED_CONTROL_LEN of an INNER_ACCESS_AGE of 16 stanzas | `capsule.EncryptFiles` | `capsule.TestEncryptFilesTimeAndKey`, `TestEncryptRoundTripBothPolicies`, `TestPortableKeysAreNeverReused`, `TestSealedControlLength` |
| 62.1 | Writer rules: format 3 only, formats 1 and 2 being written only by a generator of test vectors; an instant after the clock of the writer; from 1 to 16 credentials, none twice, canonical and not of low order; dummies and a random order; `capsule_id`, `I_PAYLOAD`, `I_ACCESS`, `credential_id`, dummies and order from a CSPRNG, `I_PAYLOAD` and dummies never reused or derived; L known before sealing, at most L_MAX, code 1 or 2; SEALED_CONTROL_LEN exact, measured by a provisional seal and checked; limits; on error, the output is discarded; in format 3, the area of 32768 bytes, signed or not, and 65536 only when the creator widens it once the signatures are made, without signing again for it, a capsule refused when they do not fit, `SECURITY_CBOR` always and empty without a signature or a seal, another area or `SECURITY_CBOR` only from a generator of test vectors (rule 13), a head with a fresh salt, a file or a comment, the order of R8, the layout and the SHA-256 of what is written, at most 16 MiB, paths and texts refused with the rule and the character, the mtime taken at load and omitted out of range, the three CBOR objects decoded with the rules of the reader (MUST), and files that must not change between the two readings; with a signature or a seal, each verified with the rules of the reader before writing, never one that gives F1, F2, F5, S1, S2 or S3 (rule 19), `AUTHOR_MESSAGE` given as text and its code shown before each signature, `SIGNERS` closed before the first (rule 20), a CAdES-T for each signer of `alg` 2 (rule 21), the seal of `seal_type` 2 over `SEAL_SUBJECT` after the signature (rule 22), and no secret on disk while waiting for them (rule 25); the public note only when asked for, with the rules of the declared author and a warning (rule 23); the rules of §38.1 for a key of words, and for a `.dkk` with a locator the rest stored before the `.dkk` is written (rule 24). SHOULD: code 2 by default, self-checks, wiping | `capsule.EncryptFiles` (`newHead`, `readSource`, `selfCheckHead`) and `capsule.Encrypt`, through their sealer (`EncryptOptions.Padding`, `accessRecipients`, `fillSlots`, `copyExactly`, `selfCheckHeader`, `selfCheckControl`, `selfCheckInner`, `selfCheckPayload`); `agewrap.CheckX25519Recipient`; `EncryptOptions.TestVectors` for `Encrypt` of format 2, and `internal/testkit.Build`, generators of test vectors (§70); in format 3, `capsule.AreaLen`, `LargeAreaLen` and `EncryptOptions.LargeArea`, the area decided by `EncryptFiles`, in the `prepare` that it gives `sealer.write`, once `sealer.security` has signed and sealed and checked both with `EvaluateSecurityIn` (rules 13, 19, 21 and 22), `EncryptOptions.AuthorKey`, `CMSSigner` and `Sealer`, a typed nil in one of them an error (`newSealer`, `isNil`), nothing written to `dst` before they return and the control and `I_PAYLOAD` kept in memory (rule 25); `EncryptOptions.TestAreaLen`, with `TestVectors`, the area of 512 bytes of the fixtures of v0.10 (rule 13); `EncryptOptions.PublicNote` and `extension.CheckWrite` (rule 23, §72); `EncryptOptions.Words` and `wordkey.Check`, and `locator.NewEnvelope`, `Locator.Marshal` and `Info.Extension` (rule 24); `cmd/datekeys`: `announced` (rule 20) and the warning of `-note` (rule 23) | `capsule.TestEncryptFilesRejects`, `TestEncryptFilesChangedFile`, `TestEncryptIsForTestVectors`, `TestEncryptFilesHeadCritical`, `TestEncryptRejectsInvalidOptions`, `TestCredentialBounds`, `TestEncryptSourceLength`, `TestEncryptSelfCheck`, `TestSealedControlLength`, `TestPayloadIdentityReuse`, `TestStanzaOrderIsUniform`, `TestDummyRecipients`, `TestPortableKeysAreNeverReused`; `cmd/datekeys.TestEncryptRefusesPaths`; rules 13 and 19 to 25: `capsule.TestEncryptFilesSigned`, `TestEncryptFilesSignatureChecked` (nothing written), `TestEncryptFilesCMSAndSeal` (a signature without a required signer, or without seals, is not written), `TestAreaChosenAfterSigning` (the area widened once signed, signing once; without a signature, 32 KiB with `LargeArea`), `TestWriterOptionsChecked`, `TestPublicNoteRules`, `TestRegisteredExtensionsWhereRegistered`, `TestEncryptFilesWords`; `wordkey.TestCheck`; `locator.TestUsableAddresses`, `TestInfo`; `cmd/datekeys.TestAuthorSignRoundTrip` (the key and the code before the signature), `TestPublicNoteCLI`, `TestKeyOfWords`; rule 25 has no test of its own |
| 62.1 | Writer rules: format 3 only, formats 1 and 2 being written only by a generator of test vectors; an instant after the clock of the writer; from 1 to 16 credentials, none twice, canonical and not of low order; dummies and a random order; `capsule_id`, `I_PAYLOAD`, `I_ACCESS`, `credential_id`, dummies and order from a CSPRNG, `I_PAYLOAD` and dummies never reused or derived; L known before sealing, at most L_MAX, code 1 or 2; SEALED_CONTROL_LEN exact, measured by a provisional seal and checked; limits; on error, the output is discarded; in format 3, the area of 32768 bytes, signed or not, and 65536 only when the creator widens it once the signatures are made, without signing again for it, a capsule refused when they do not fit, `SECURITY_CBOR` always and empty without a signature or a seal, another area or `SECURITY_CBOR` only from a generator of test vectors (rule 13), a head with a fresh salt, a file or a comment, the order of R8, the layout and the SHA-256 of what is written, at most 16 MiB, paths and texts refused with the rule and the character, the mtime taken at load and omitted out of range, the three CBOR objects decoded with the rules of the reader (MUST), and files that must not change between the two readings; with a signature or a seal, each verified with the rules of the reader before writing, never one that gives F1, F2, F5, S1, S2 or S3 (rule 19), `AUTHOR_MESSAGE` given as text and its code shown before each signature, `SIGNERS` closed before the first (rule 20), a CAdES-T for each signer of `alg` 2 (rule 21), the seal of `seal_type` 2 over `SEAL_SUBJECT` after the signature (rule 22), and no secret on disk while waiting for them (rule 25); the public note only when asked for, with the rules of the declared author and a warning (rule 23); the rules of §38.1 for a key of words, and for a `.dkk` with a locator the rest stored before the `.dkk` is written (rule 24). SHOULD: code 2 by default, self-checks, wiping | `capsule.EncryptFiles` (`newHead`, `readSource`, `selfCheckHead`) and `capsule.Encrypt`, through their sealer (`EncryptOptions.Padding`, `accessRecipients`, `fillSlots`, `copyExactly`, `selfCheckHeader`, `selfCheckControl`, `selfCheckInner`, `selfCheckPayload`); `agewrap.CheckX25519Recipient`; `EncryptOptions.TestVectors` for `Encrypt` of format 2, and `internal/testkit.Build`, generators of test vectors (§70); in format 3, `capsule.AreaLen`, `LargeAreaLen` and `EncryptOptions.LargeArea`, the area decided by `EncryptFiles`, in the `prepare` that it gives `sealer.write`, once `sealer.security` has signed and sealed and checked both with `EvaluateSecurityIn` (rules 13, 19, 21 and 22), `EncryptOptions.AuthorKey`, `CMSSigner` and `Sealer`, a typed nil in one of them an error (`newSealer`, `isNil`), nothing written to `dst` before they return and the control and `I_PAYLOAD` kept in memory (rule 25); `EncryptOptions.TestAreaLen`, with `TestVectors`, the area of 512 bytes of the fixtures of v0.10 (rule 13); `EncryptOptions.PublicNote` and `extension.CheckWrite` (rule 23, §72); `EncryptOptions.Words` and `wordkey.Check`, and `locator.NewEnvelope`, `Locator.Marshal` and `Info.Extension` (rule 24); `cmd/datekeys`: `announced` (rule 20) and the warning of `-note` (rule 23) | `capsule.TestEncryptFilesRejects`, `TestEncryptFilesChangedFile`, `TestEncryptIsForTestVectors`, `TestEncryptFilesHeadCritical`, `TestEncryptRejectsInvalidOptions`, `TestCredentialBounds`, `TestEncryptSourceLength`, `TestEncryptSelfCheck`, `TestSealedControlLength`, `TestPayloadIdentityReuse`, `TestStanzaOrderIsUniform`, `TestDummyRecipients`, `TestPortableKeysAreNeverReused`; `cmd/datekeys.TestEncryptRefusesPaths`; rules 13 and 19 to 25: `capsule.TestEncryptFilesSigned`, `TestEncryptFilesSignatureChecked` (nothing written), `TestEncryptFilesCMSAndSeal` (a signature without a required signer, or without seals, is not written), `TestAreaChosenAfterSigning` (the area widened once signed, signing once; without a signature, 32 KiB with `LargeArea`), `TestWriterOptionsChecked`, `TestPublicNoteRules`, `TestRegisteredExtensionsWhereRegistered`, `TestEncryptFilesWords`; `wordkey.TestCheck`; `locator.TestUsableAddresses`, `TestInfo`; `cmd/datekeys.TestAuthorSignRoundTrip` (the key and the code before the signature), `TestPublicNoteCLI`, `TestKeyOfWords`; rule 25 has no test of its own |
| 63 | Decryption flow; step 2 accepts the formats 1, 2 and 3, and the steps after it apply the rules of the format: in formats 2 and 3, 16 stanzas at step 12, a control of schema version 2 at step 14, L, the code and P at step 16, a plaintext of P bytes with a zero padding at step 17 (`ERR_INTEGRITY` whenever it is found), the first L bytes at step 18; in format 3, step 17 in its substeps, a failure of age or a plaintext whose length is not P prevailing and a code other than `ERR_INTEGRITY` reported only after reading to EOF, and a caller without a `Sink` stopped right after step 2; steps 4 and 14 validate critical extensions (unknown, then invalid data); step 5 reads SEALED_CONTROL, a MUST (`ERR_INTEGRITY`), and SHOULD inspect its age header; step 8 argument rules; step 9 order: the `.dkk` as an object (decoded there when still encoded), its `capsule_id` and `capsule_digest`, credentials (nil identities are none) before the clock, round time, request, and nothing of the credentials under `time_only`; a network source verifies each response with the rules of step 10 and discards the invalid ones (none valid: `ERR_RELEASE_UNAVAILABLE`, step 9), and any failure of a source is `ERR_RELEASE_UNAVAILABLE` alone, whatever code its error carries; step 10: round, then signature, a canonical point other than the identity (§12.2), the codes of a release supplied directly; step 11: the tlock stanza body `U \|\| V \|\| W` of \|U\| + 32 bytes (128 in Quicknet), U canonical and not the identity, the IBE check r·G == U, every failure `ERR_INTEGRITY`, H2, H3 and H4 those of drand/kyber `encrypt/ibe`, H2 over the element of GT serialized in the order of kilic/bls12-381 (c1 before c0 at every level of the tower), with the frozen vector H2(e(G1, G2)) = `cb87319f24560b5231579a09ad79f12e`; the codes of the identities at steps 11, 13 (malformed X25519 stanza `ERR_INTEGRITY`, an identity that unwraps two stanzas `ERR_POLICY_STRUCTURE_MISMATCH` whatever the order, none `ERR_ACCESS_INVALID`) and 17; step 15 `ERR_HEADER_BINDING` | `capsule.Inspect` (steps 1–8), `capsule.Open` (steps 9–18; `openBody`, `drain`, `ErrSinkRequired`; `OpenOptions.AccessKeyFile`, `checkAccessKey`, `checkCapsuleDigest`), the `provider.ReleaseSource` contract, `provider/drand.Client` and `capsule.sourceFailure` (step 9), `tlock.TimeUnlock` with the kyber-bls12381 pairing (step 11), MUST rules inside `agewrap` identities (`AccessIdentity` tries every identity on every stanza; `TimeIdentity` checks the length of the tlock stanza body and U before `tlock.TimeUnlock`); no error copies the text of an error of age, tlock, kyber or drand (`agewrap`, `capsule.classify`), since kyber's IBE error carries the candidate plaintext and r; `cmd/datekeys` hands the `.dkk` over encoded; `datekeys inspect -json` rendered by `internal/inspectview` | `capsule.TestConformanceFixtures` (stage by stage), `TestOpen3`, `TestOpen3Substeps`, `TestFormatDispatch`, `TestFormatRelabel`, `TestPaddingChecksAtStep17`, `TestTlockFailureDiagnosticsCarryNoSecrets`, `TestPlaintextWriterFailureKeepsItsText`, `TestAccessKeyCheckOrder`, `TestAccessKeyFileAtStep9`, `TestPrecedenceAcrossSteps`, `TestControlCriticalBeforeHeaderBinding`, `TestReleaseFromANetworkSource`, `TestReleaseSourceErrorsAtStep9`, `agewrap.TestAccessIdentityStrictness`, `TestMalformedX25519Stanzas`, `TestTlockH2Vector` (`testdata/vectors/tlock_ibe.json`, generated by `internal/testkit.IBEVectors`, and step 11 recomputed with H2 and H4 against the file key tlock unwraps), `cmd/datekeys.TestDecryptAccessKeyOrder`, `TestMutationCorpus`, `TestInspectDifferentialCorpus` (`testdata/vectors/inspect_differential.json`: 5110 deterministic mutations of 14 fixtures, two of them of format 3, the 1825 of the format 1 ones first with the verdict of steps 1–8, generated by `internal/testkit.InspectDifferential`); `cmd/datekeys.TestInspectJSONGoldens` (`testdata/fixtures/*.inspect.json`) |
| 63 | Decryption flow; step 2 accepts the formats 1, 2 and 3, and the steps after it apply the rules of the format: in formats 2 and 3, 16 stanzas at step 12, a control of schema version 2 at step 14, L, the code and P at step 16, a plaintext of P bytes with a zero padding at step 17 (`ERR_INTEGRITY` whenever it is found), the first L bytes at step 18; in format 3, step 17 in its substeps, a failure of age or a plaintext whose length is not P prevailing and a code other than `ERR_INTEGRITY` reported only after reading to EOF, and a caller without a `Sink` stopped right after step 2; steps 4 and 14 validate critical extensions (unknown, then invalid data); step 5 reads SEALED_CONTROL, a MUST (`ERR_INTEGRITY`), and SHOULD inspect its age header; step 8 argument rules; step 9 order: the `.dkk` as an object (decoded there when still encoded), its `capsule_id` and `capsule_digest`, credentials (nil identities are none) before the clock, round time, request, and nothing of the credentials under `time_only`; a network source verifies each response with the rules of step 10 and discards the invalid ones (none valid: `ERR_RELEASE_UNAVAILABLE`, step 9), and any failure of a source is `ERR_RELEASE_UNAVAILABLE` alone, whatever code its error carries; step 10: round, then signature, a canonical point other than the identity (§12.2), the codes of a release supplied directly; step 11: the tlock stanza body `U \|\| V \|\| W` of \|U\| + 32 bytes (128 in Quicknet), U canonical and not the identity, the IBE check r·G == U, every failure `ERR_INTEGRITY`, H2, H3 and H4 those of drand/kyber `encrypt/ibe`, H2 over the element of GT serialized in the order of kilic/bls12-381 (c1 before c0 at every level of the tower), with the frozen vector H2(e(G1, G2)) = `cb87319f24560b5231579a09ad79f12e`; the codes of the identities at steps 11, 13 (malformed X25519 stanza `ERR_INTEGRITY`, an identity that unwraps two stanzas `ERR_POLICY_STRUCTURE_MISMATCH` whatever the order, none `ERR_ACCESS_INVALID`) and 17; step 15 `ERR_HEADER_BINDING` | `capsule.Inspect` (steps 1–8), `capsule.Open` (steps 9–18; `openBody`, `drain`, `ErrSinkRequired`; `OpenOptions.AccessKeyFile`, `checkAccessKey`, `checkCapsuleDigest`), the `provider.ReleaseSource` contract, `provider/drand.Client` and `capsule.sourceFailure` (step 9), `tlock.TimeUnlock` with the kyber-bls12381 pairing (step 11), MUST rules inside `agewrap` identities (`AccessIdentity` tries every identity on every stanza; `TimeIdentity` checks the length of the tlock stanza body and U before `tlock.TimeUnlock`); no error copies the text of an error of age, tlock, kyber or drand (`agewrap`, `capsule.classify`), since kyber's IBE error carries the candidate plaintext and r; `cmd/datekeys` hands the `.dkk` over encoded; `datekeys inspect -json` rendered by `internal/inspectview` | `capsule.TestConformanceFixtures` (stage by stage), `TestOpen3`, `TestOpen3Substeps`, `TestFormatDispatch`, `TestFormatRelabel`, `TestPaddingChecksAtStep17`, `TestTlockFailureDiagnosticsCarryNoSecrets`, `TestPlaintextWriterFailureKeepsItsText`, `TestAccessKeyCheckOrder`, `TestAccessKeyFileAtStep9`, `TestPrecedenceAcrossSteps`, `TestControlCriticalBeforeHeaderBinding`, `TestReleaseFromANetworkSource`, `TestReleaseSourceErrorsAtStep9`, `agewrap.TestAccessIdentityStrictness`, `TestMalformedX25519Stanzas`, `TestTlockH2Vector` (`testdata/vectors/tlock_ibe.json`, generated by `internal/testkit.IBEVectors`, and step 11 recomputed with H2 and H4 against the file key tlock unwraps), `cmd/datekeys.TestDecryptAccessKeyOrder`, `TestMutationCorpus`, `TestInspectDifferentialCorpus` (`testdata/vectors/inspect_differential.json`: 5110 deterministic mutations of 14 fixtures, two of them of format 3, the 1825 of the format 1 ones first with the verdict of steps 1–8, generated by `internal/testkit.InspectDifferential`); `cmd/datekeys.TestInspectJSONGoldens` (`testdata/fixtures/*.inspect.json`) |
| 64 | Mandatory mutation tests: the first two lists in the three formats, the list of format 2 in format 2, and that of format 3, four of whose cases open with their verdicts, F2 for a signature of `alg` 1 that does not verify among them; the lists of v0.11 and v0.12: the signature of `alg` 1 and of `alg` 2, the area widened after signing, the seal, `alg` and `seal_type` 4294967295, the same P with a signature and without, the public note, the key of words and `datekeys.capsule` | `internal/testkit.Mutations` (the corpus: `specMutations` for each format, `furtherMutations`, `format2Mutations`, `format3Mutations` with `LoadedFixture.WithBody`, among them those of the list of v0.11 from `format3_signed`, `format3_unsigned` and `format3_note`, `signed1`), `internal/testkit.MutationCorpus` (its export); the cases of formats 2 and 3 derived without randomness, by sealing the fixtures again with their known file keys and nonces (`internal/testkit/reseal.go`, `mutations3.go`), exported as edits of their fixture (`internal/testkit.Splice`); the cases of `alg` 2, `seal_type` 2 and `datekeys.capsule`, vectors of `security_cms.json` and `locator.json`, frozen once written (`internal/testkit/genfixtures`, `frozenVectors`) | `capsule.TestMutationCorpus`: the 178 listed mutations, 33 in each format, the 23 of the list of format 2, the 48 of that of format 3 and 8 of that of v0.11 (`internal/testkit.SpecMutationsPerFormat`, `Format2SpecMutations`, `Format3SpecMutations`, `V011SpecMutations`), plus 40 more, built afresh; `capsule.TestExportedMutationCorpus`: `testdata/vectors/mutations.json`, the same 218 cases as frozen data (capsule, `.dkk`, identities, recorded release, clock, registry, known extensions), replayed with the recorded error and step, or the recorded verdicts; `capsule.TestPointMutationsChangeOnlyTheEncoding`: the ten point mutations keep a valid header MAC, and a decoder that reduces coordinates modulo p opens the c0 + p and x + p cases; `internal/testkit.TestResealReproducesFixtures`, `TestFixedX25519Stanza`; the cases of the lists of v0.11 and v0.12 outside the corpus: `ed25519strict.TestVectors` (`ed25519_strict.json`), `capsule.TestCMSVectors` (`security_cms.json`), `locator.TestLocatorVectors` (`locator.json`), `wordkey.TestKeyVector`, `TestNormalize` and `TestCheck`, `testdata/vectors/note.json`, and the same P of the fixtures `format3_unsigned` and `format3_signed` (`capsule.TestConformanceFixtures`); those of `alg` 2, `seal_type` 2 and `datekeys.capsule` of the list of v0.12, and the ones of v0.11 that`security_cms.json` and `locator.json` lack: *pending* |
| 64 | Mandatory mutation tests: the first two lists in the three formats, the list of format 2 in format 2, and that of format 3, four of whose cases open with their verdicts, F2 for a signature of `alg` 1 that does not verify among them; the lists of v0.11 and v0.12: the signature of `alg` 1 and of `alg` 2, the area widened after signing, the seal, `alg` and `seal_type` 4294967295, the same P with a signature and without, the public note, the key of words and `datekeys.capsule` | `internal/testkit.Mutations` (the corpus: `specMutations` for each format, `furtherMutations`, `format2Mutations`, `format3Mutations` with `LoadedFixture.WithBody`, among them those of the list of v0.11 from `format3_signed`, `format3_unsigned` and `format3_note`, `signed1`), `internal/testkit.MutationCorpus` (its export); the cases of formats 2 and 3 derived without randomness, by sealing the fixtures again with their known file keys and nonces (`internal/testkit/reseal.go`, `mutations3.go`), exported as edits of their fixture (`internal/testkit.Splice`); the cases of `alg` 2, `seal_type` 2 and `datekeys.capsule`, vectors of `security_cms.json` and `locator.json`, frozen once written (`internal/testkit/genfixtures`, `frozenVectors`) | `capsule.TestMutationCorpus`: the 178 listed mutations, 33 in each format, the 23 of the list of format 2, the 48 of that of format 3 and 8 of that of v0.11 (`internal/testkit.SpecMutationsPerFormat`, `Format2SpecMutations`, `Format3SpecMutations`, `V011SpecMutations`), plus 40 more, built afresh; `capsule.TestExportedMutationCorpus`: `testdata/vectors/mutations.json`, the same 218 cases as frozen data (capsule, `.dkk`, identities, recorded release, clock, registry, known extensions), replayed with the recorded error and step, or the recorded verdicts; `capsule.TestPointMutationsChangeOnlyTheEncoding`: the ten point mutations keep a valid header MAC, and a decoder that reduces coordinates modulo p opens the c0 + p and x + p cases; `internal/testkit.TestResealReproducesFixtures`, `TestFixedX25519Stanza`; the cases of the lists of v0.11 and v0.12 outside the corpus: `ed25519strict.TestVectors` (`ed25519_strict.json`), `capsule.TestCMSVectors` (`security_cms.json`), `locator.TestLocatorVectors` (`locator.json`), `wordkey.TestKeyVector`, `TestNormalize` and `TestCheck`, `testdata/vectors/note.json`, and the same P of the fixtures `format3_unsigned` and `format3_signed` (`capsule.TestConformanceFixtures`); those of `alg` 2, `seal_type` 2 and `datekeys.capsule` of the lists of v0.11 and v0.12, in`security_cms.json` and `locator.json` |
| 67 | `.dkc` vectors: the format 1 fixtures of v0.8.2, kept for compatibility, and format 2 fixtures for both policies, both codes, L = 0, one, several and 16 credentials, and extensions; the format 3 fixtures: one file, a tree, a comment alone, both codes, `time_and_key` with a portable key, an area of 1024 bytes, security of version 2, a signature of `alg` 4294967295 and that with a seal of `seal_type` 4294967295, the area of 32 KiB without a signature, a signature of `alg` 1, that with a seal of `seal_type` 2 and a file whose mtime is later than the seal, and a signature of `alg` 2 of two signers, ECDSA P-256 and RSA 2048, each with its CAdES-T; the records give the format, L, the code, P and the stanza each credential opens, and in format 3 the head, security, each file and the verdicts with their lines, and for a signature or a seal the commitments, `AUTHOR_MESSAGE` and its code, the key or `SIGNERS` and the certificates, the result of each signer, `SEAL_SUBJECT` and the token; the padding vectors, and those of paths, keys of R7, heads, security, `security_cms.json`, `ed25519_strict.json`, `note.json` and `locator.json` | `testdata/fixtures/*.dkc` + `*.json`, `internal/testkit/genfixtures`, which never regenerates a format 1 fixture, gives the five fixtures that `EncryptFiles` wrote in v0.10 their area of 512 bytes (`EncryptOptions.TestAreaLen`) and recomputes the derived fields of every record; `format3_note`, with a public note, for the mutations of §64; the frozen `datekeys inspect -json` output of each, `*.inspect.json`; `testdata/vectors/padding.json`; `security_cms.json` and `locator.json`, frozen once written (`frozenVectors`); formats in `testdata/README.md` | `capsule.TestConformanceFixtures` (`checkBody3`, `checkSignature3`), `TestPaddingAcrossChunks` (a capsule generated at run time), `TestCMSVectors`; `locator.TestLocatorVectors`; `ed25519strict.TestVectors`; `internal/testkit.TestFormat3VectorFiles`, `TestVectorFilesAreCurrent`; `cmd/datekeys.TestInspectJSONGoldens`, `TestDecryptFixtures`, `TestDecryptFormat3Fixtures`, `TestMTimeAfterSeal` |
| 67 | `.dkc` vectors: the format 1 fixtures of v0.8.2, kept for compatibility, and format 2 fixtures for both policies, both codes, L = 0, one, several and 16 credentials, and extensions; the format 3 fixtures: one file, a tree, a comment alone, both codes, `time_and_key` with a portable key, an area of 1024 bytes, security of version 2, a signature of `alg` 4294967295 and that with a seal of `seal_type` 4294967295, the area of 32 KiB without a signature, a signature of `alg` 1, that with a seal of `seal_type` 2 and a file whose mtime is later than the seal, and a signature of `alg` 2 of two signers, ECDSA P-256 and RSA 2048, each with its CAdES-T; the records give the format, L, the code, P and the stanza each credential opens, and in format 3 the head, security, each file and the verdicts with their lines, and for a signature or a seal the commitments, `AUTHOR_MESSAGE` and its code, the key or `SIGNERS` and the certificates, the result of each signer, `SEAL_SUBJECT` and the token; the padding vectors, and those of paths, keys of R7, heads, security, `security_cms.json`, `ed25519_strict.json`, `note.json` and `locator.json` | `testdata/fixtures/*.dkc` + `*.json`, `internal/testkit/genfixtures`, which never regenerates a format 1 fixture, gives the five fixtures that `EncryptFiles` wrote in v0.10 their area of 512 bytes (`EncryptOptions.TestAreaLen`) and recomputes the derived fields of every record; `format3_note`, with a public note, for the mutations of §64; the frozen `datekeys inspect -json` output of each, `*.inspect.json`; `testdata/vectors/padding.json`; `security_cms.json` and `locator.json`, frozen once written (`frozenVectors`); formats in `testdata/README.md` | `capsule.TestConformanceFixtures` (`checkBody3`, `checkSignature3`), `TestPaddingAcrossChunks` (a capsule generated at run time), `TestCMSVectors`; `locator.TestLocatorVectors`; `ed25519strict.TestVectors`; `internal/testkit.TestFormat3VectorFiles`, `TestVectorFilesAreCurrent`; `cmd/datekeys.TestInspectJSONGoldens`, `TestDecryptFixtures`, `TestDecryptFormat3Fixtures`, `TestMTimeAfterSeal` |
@ -111,7 +111,7 @@ the same. A case of §64 that is not in the repository yet is marked
| 72 | Extension registry and registration rules, among them the objects and arrays where each extension may appear, and an encoder never writes one elsewhere; the encoder decodes its own output before sealing; security-relevant claims in CONTROL_CBOR or under a signature extension, `.dkk` extension data advisory; the registered extensions, `datekeys.note` in the noncritical array of PUBLIC_HEADER and `datekeys.capsule` in the noncritical array of a `.dkk`, both informative | `extension.Registry`, `extension.Set`, `extension.DataValidator`, `extension.Placement` (optional: a `Registry` without it knows its extensions in every object and array); `extension.Standard`, the registry of the extensions of the specification (`NoteID`, `CapsuleID`), and `locator.Standard`, which validates the data of `datekeys.capsule`; `extension.CheckWrite`, which the writers of capsules and `.dkk` files apply with `extension.Standard` (`capsule.newSealer`, `accesskey.AccessKey.MarshalBody`); self-checks in `capsule.Encrypt`, `capsule.EncryptFiles`, `accesskey.MarshalBody` and `locator.Info.Extension`; these writers take no `Registry`: the application writes each extension of its own only where it is registered | `capsule.TestKnownCriticalExtensions`, `TestUnusableNoncriticalExtensions`, `TestExtensionPlacement`, `TestNestedDataSealsAndOpens`, `TestRegisteredExtensionsWhereRegistered`, `TestPublicNoteRules`, `FuzzEncodeImpliesDecode`; `extension.TestPlacement`, `TestCheckWrite`; `locator.TestInfo` |
| 72 | Extension registry and registration rules, among them the objects and arrays where each extension may appear, and an encoder never writes one elsewhere; the encoder decodes its own output before sealing; security-relevant claims in CONTROL_CBOR or under a signature extension, `.dkk` extension data advisory; the registered extensions, `datekeys.note` in the noncritical array of PUBLIC_HEADER and `datekeys.capsule` in the noncritical array of a `.dkk`, both informative | `extension.Registry`, `extension.Set`, `extension.DataValidator`, `extension.Placement` (optional: a `Registry` without it knows its extensions in every object and array); `extension.Standard`, the registry of the extensions of the specification (`NoteID`, `CapsuleID`), and `locator.Standard`, which validates the data of `datekeys.capsule`; `extension.CheckWrite`, which the writers of capsules and `.dkk` files apply with `extension.Standard` (`capsule.newSealer`, `accesskey.AccessKey.MarshalBody`); self-checks in `capsule.Encrypt`, `capsule.EncryptFiles`, `accesskey.MarshalBody` and `locator.Info.Extension`; these writers take no `Registry`: the application writes each extension of its own only where it is registered | `capsule.TestKnownCriticalExtensions`, `TestUnusableNoncriticalExtensions`, `TestExtensionPlacement`, `TestNestedDataSealsAndOpens`, `TestRegisteredExtensionsWhereRegistered`, `TestPublicNoteRules`, `FuzzEncodeImpliesDecode`; `extension.TestPlacement`, `TestCheckWrite`; `locator.TestInfo` |
| 74 | Provisional aspects; the implementation limits of the reference (name lengths, `public_key`, `period`, maximum `extension_id` length, `dk1_` length, age parser limits, `ERR_POLICY_STRUCTURE_MISMATCH` for INNER_ACCESS_AGE) | `profile.ValidID`, `validName`, `maxPublicKeyLen`, `maxPeriod`; `extension.MaxIDLen`; `datekey.MaxEncodedLen`; `filippo.io/age` | `profile.TestValidateRejectsTamperedProfiles`, `TestIntegerRanges`; `extension.TestNew`; the vectors of `cbor.json` named after the implementation limit |
| 74 | Provisional aspects; the implementation limits of the reference (name lengths, `public_key`, `period`, maximum `extension_id` length, `dk1_` length, age parser limits, `ERR_POLICY_STRUCTURE_MISMATCH` for INNER_ACCESS_AGE) | `profile.ValidID`, `validName`, `maxPublicKeyLen`, `maxPeriod`; `extension.MaxIDLen`; `datekey.MaxEncodedLen`; `filippo.io/age` | `profile.TestValidateRejectsTamperedProfiles`, `TestIntegerRanges`; `extension.TestNew`; the vectors of `cbor.json` named after the implementation limit |
| 75 | Blocking requirements before v1.0 | items 1–9 and 11 above, with fixtures and mutations in the three formats; item 10 (external review) pending | — |
| 75 | Blocking requirements before v1.0 | items 1–9 and 11 above, with fixtures and mutations in the three formats; item 10 (external review) pending | — |
| 76 | Change policy; the normative changes of v0.8.2: the extension change and its reproducible cases; the refinements and theirs; the amendment on point canonicality and its case (a second implementation on `tlock-js` and `@noble/curves` 1.9.7 accepted U with c0 + p and a signature with x + p); the corrections of the formal review (an invalid release from a network source, the objects and arrays of each extension, the serialization of GT in H2) and their cases, and those of its second round (the encoder rule of §72, the codes of step 10 in §17 and §51 for a release supplied directly, one code for any failure of a source at step 9); the normative changes of v0.9, capsule format 2, and their cases; those of v0.10, capsule format 3, and theirs; those of v0.11, the area of 32 KiB, what is signed, the signatures of `alg` 1 and 2, the seal of `seal_type` 2, the key of words, the public note and `datekeys.capsule`, and theirs; and those of the draft v0.12, which change no format: the names of certificates and the seal of each signer of F6 in the verdicts, the holder without its identifier, the profile of the certificate, identifiers, repetitions and edge cases, the addresses and the padding of the locator, errata, and the vectors of v0.11 | `extension`, `codec`, fixture `time_only_extensions` regenerated; refinements: the order of `capsule.checkAccessKey`, `BODY_LEN` 0 in `accesskey.Decode`, CR and LF and invalid UTF-8 in `datekey.Parse`, the `.dkk` decoded at step 9.a (`OpenOptions.AccessKeyFile`, the CLI), nil identities in `capsule.Open`, every identity tried in `agewrap.AccessIdentity`, `profile.NewRegistry` through `Decode`, `Profile.Validate` rule 1 first; four new `dk1.json` vectors; corrections: `extension.Placement` and the object-aware checks, the `provider.ReleaseSource` contract, `testdata/vectors/tlock_ibe.json`; second round: the error of `provider/drand.Client` and of step 9 in `capsule.Open`; v0.9: rows 22, 29, 29.1, 31, 33, 36, 37, 39, 55.2, 56, 57, 61, 62, 62.1, 63 and 70; v0.10: rows 22, 23, 29 to 29.7, 31, 56, 57, 61 to 64 and 67 to 70; v0.11: rows 24.1, 29.2, 29.3, 29.7 to 29.12, 38.1, 44.1, 62.1, 64, 67, 70 and 72; v0.12: rows 29.3, 29.7, 29.10, 29.11, 44.1, 64, 67 and 70, and the sizes of the locator in `spec/datekeys.cddl` | case 2: `extension.TestNew`; case 3: `capsule.TestNaNKeyedDataHasOneVerdict`; case 4: `capsule.TestExtensionFixtureData`; case 5: `capsule.TestNestedDataSealsAndOpens`; case 6: `capsule.TestHugeExtensionArraysAreRejected`, `extension.TestCheckDisjointIsLinear`; refinements: the tests of rows 12.1, 15, 17, 19, 22, 28.1, 35, 36, 40, 51, 55.1, 63 and 69.1, and `extension.TestOrderIsUnsignedBytewise`; amendment: the tests of rows 12.2 and 64; corrections: `capsule.TestReleaseFromANetworkSource`, `TestExtensionPlacement`, `extension.TestPlacement`, `agewrap.TestTlockH2Vector`; second round: `capsule.TestReleaseSourceErrorsAtStep9`, `TestExtensionPlacement` (the noncritical array of a `.dkk`), `drand.TestFetchErrorHasOneCode`, `TestUnavailabilityAndCancellation`, `datekeys.TestCode`; v0.9: the tests that §76 names for each change, in rows 22, 29.1, 31, 37, 39, 55.2, 57, 62.1, 64 and 70; v0.10: those of the rows it changed; v0.11: those of the rows it added and changed; v0.12: changes 1 and 2, `capsule.TestEvaluateCMS`, `TestIssuerTextFiltered`, `cmd/datekeys.TestRows` and the record of `format3_signed_cms`; change 5, `der.TestSetOfSorted`, `TestCheck` and `cms.TestTSTInfoStrict`; changes 6 and 7, `locator.TestAddresses`, `TestUsableAddresses`, `TestLeastMultiple` and `TestPaddingBoundaries`; change 9, `testdata/vectors/security.json` and the fixture `format3_seal_unsupported`; the cases of changes 1 and 3 to 7 in `security_cms.json` and `locator.json`: *pending* |
| 76 | Change policy; the normative changes of v0.8.2: the extension change and its reproducible cases; the refinements and theirs; the amendment on point canonicality and its case (a second implementation on `tlock-js` and `@noble/curves` 1.9.7 accepted U with c0 + p and a signature with x + p); the corrections of the formal review (an invalid release from a network source, the objects and arrays of each extension, the serialization of GT in H2) and their cases, and those of its second round (the encoder rule of §72, the codes of step 10 in §17 and §51 for a release supplied directly, one code for any failure of a source at step 9); the normative changes of v0.9, capsule format 2, and their cases; those of v0.10, capsule format 3, and theirs; those of v0.11, the area of 32 KiB, what is signed, the signatures of `alg` 1 and 2, the seal of `seal_type` 2, the key of words, the public note and `datekeys.capsule`, and theirs; and those of the draft v0.12, which change no format: the names of certificates and the seal of each signer of F6 in the verdicts, the holder without its identifier, the profile of the certificate, identifiers, repetitions and edge cases, the addresses and the padding of the locator, errata, and the vectors of v0.11 | `extension`, `codec`, fixture `time_only_extensions` regenerated; refinements: the order of `capsule.checkAccessKey`, `BODY_LEN` 0 in `accesskey.Decode`, CR and LF and invalid UTF-8 in `datekey.Parse`, the `.dkk` decoded at step 9.a (`OpenOptions.AccessKeyFile`, the CLI), nil identities in `capsule.Open`, every identity tried in `agewrap.AccessIdentity`, `profile.NewRegistry` through `Decode`, `Profile.Validate` rule 1 first; four new `dk1.json` vectors; corrections: `extension.Placement` and the object-aware checks, the `provider.ReleaseSource` contract, `testdata/vectors/tlock_ibe.json`; second round: the error of `provider/drand.Client` and of step 9 in `capsule.Open`; v0.9: rows 22, 29, 29.1, 31, 33, 36, 37, 39, 55.2, 56, 57, 61, 62, 62.1, 63 and 70; v0.10: rows 22, 23, 29 to 29.7, 31, 56, 57, 61 to 64 and 67 to 70; v0.11: rows 24.1, 29.2, 29.3, 29.7 to 29.12, 38.1, 44.1, 62.1, 64, 67, 70 and 72; v0.12: rows 29.3, 29.7, 29.10, 29.11, 44.1, 64, 67 and 70, and the sizes of the locator in `spec/datekeys.cddl` | case 2: `extension.TestNew`; case 3: `capsule.TestNaNKeyedDataHasOneVerdict`; case 4: `capsule.TestExtensionFixtureData`; case 5: `capsule.TestNestedDataSealsAndOpens`; case 6: `capsule.TestHugeExtensionArraysAreRejected`, `extension.TestCheckDisjointIsLinear`; refinements: the tests of rows 12.1, 15, 17, 19, 22, 28.1, 35, 36, 40, 51, 55.1, 63 and 69.1, and `extension.TestOrderIsUnsignedBytewise`; amendment: the tests of rows 12.2 and 64; corrections: `capsule.TestReleaseFromANetworkSource`, `TestExtensionPlacement`, `extension.TestPlacement`, `agewrap.TestTlockH2Vector`; second round: `capsule.TestReleaseSourceErrorsAtStep9`, `TestExtensionPlacement` (the noncritical array of a `.dkk`), `drand.TestFetchErrorHasOneCode`, `TestUnavailabilityAndCancellation`, `datekeys.TestCode`; v0.9: the tests that §76 names for each change, in rows 22, 29.1, 31, 37, 39, 55.2, 57, 62.1, 64 and 70; v0.10: those of the rows it changed; v0.11: those of the rows it added and changed; v0.12: changes 1 and 2, `capsule.TestEvaluateCMS`, `TestIssuerTextFiltered`, `cmd/datekeys.TestRows` and the record of `format3_signed_cms`; change 5, `der.TestSetOfSorted`, `TestCheck` and `cms.TestTSTInfoStrict`; changes 6 and 7, `locator.TestAddresses`, `TestUsableAddresses`, `TestLeastMultiple` and `TestPaddingBoundaries`; change 9, `testdata/vectors/security.json` and the fixture `format3_seal_unsupported`; the cases of changes 1 and 3 to 5 in `security_cms.json`, and those of changes 6 and 7 in `locator.json` (`TestLocatorVectors`) |
Official vectors, fixtures and corpora of the DateKeys Protocol Specification
Official vectors, fixtures and corpora of the DateKeys Protocol Specification
v0.10, generated by the reference implementation. Another implementation
v0.11 and of the draft v0.12, generated by the reference implementation.
consumes them as they are: this file documents every format, so that no Go code
Another implementation consumes them as they are: this file documents every
has to be read. The rules that decide each verdict are in the specification;
format, so that no Go code has to be read. The rules that decide each verdict
this file points to them, and states only what belongs to the files
are in the specification; this file points to them, and states only what
themselves.
belongs to the files themselves.
```
```
go run ./internal/testkit/genfixtures -out testdata
go run ./internal/testkit/genfixtures -out testdata
```
```
regenerates everything except the `.dkc` and `.dkk` fixtures, which are
regenerates everything except the `.dkc` and `.dkk` fixtures, which are
generated once and frozen (spec §67). The records of each fixture
generated once and frozen (spec §67), and the vectors `security_cms.json` and
(`<name>.json`, `<name>.dkk.json`, `<name>.inspect.json`) are recomputed from
`locator.json`, frozen too because they hold randomness: delete one of them
its frozen bytes, so the fixtures of v0.8.2 and v0.9 carry `"spec": "0.10"` and
to make it again. The records of each fixture (`<name>.json`,
the fields added since. The local gate (`scripts/check.sh`) and CI run it and
`<name>.dkk.json`, `<name>.inspect.json`) are recomputed from its frozen bytes,
fail if any committed file changes: every file below is exactly what the
so the fixtures of v0.8.2, v0.9 and v0.10 carry `"spec": "0.11"` and the fields
implementation computes today.
added since. The local gate (`scripts/check.sh`) and CI run it and fail if any
committed file changes: every file below is exactly what the implementation
computes today.
The `spec` field of every file is `"0.11"`, the version this module declares,
until the author approves the draft v0.12. What the draft changes, the texts
of the verdicts of a certificate and of a seal, the profile of a certificate
and the rules of the addresses and of the padding of a locator, is already in
the files: the verdicts and the lines of `security.json`, `security_cms.json`
and `mutations.json`, and the cases of `locator.json`, are those of the draft.
Conventions for every file:
Conventions for every file:
@ -43,16 +52,19 @@ Conventions for every file:
| `vectors/paths.json` | the paths of a format 3 head: the rules of one entry, and those of the paths of a head | §29.5 |
| `vectors/paths.json` | the paths of a format 3 head: the rules of one entry, and those of the paths of a head | §29.5 |
| `vectors/path_fold.json` | the key of R7 of segments, and their NFD | §29.5, §29.5.1 |
| `vectors/path_fold.json` | the key of R7 of segments, and their NFD | §29.5, §29.5.1 |
| `vectors/head_schema.json` | heads of format 3 and the result of decoding them | §29.4 to §29.6, §69.1 |
| `vectors/head_schema.json` | heads of format 3 and the result of decoding them | §29.4 to §29.6, §69.1 |
| `vectors/security.json` | security areas of format 3 and their verdicts | §29.3, §29.7 |
| `vectors/security.json` | security areas of format 3 in the context of a capsule, their verdicts and the lines that show them | §29.3, §29.7, §29.9 |
| `vectors/ed25519_strict.json` | Ed25519 signatures and the result of the strict profile of the author signature | v0.11 §29.9 |
| `vectors/security_cms.json` | security areas with a signature of `alg` 2 or a seal of `seal_type` 2, each with its context, verdicts, results and lines | §29.7, §29.10, §29.11 |
| `vectors/mutations.json` | the mutation corpus: the 169 mutations of §64 and further cases | §63, §64 |
| `vectors/ed25519_strict.json` | Ed25519 signatures and the result of the strict profile of the author signature | §29.9 |
| `vectors/note.json` | the data of the public note and the result of its rules | §24.1, §29.6 |
| `vectors/locator.json` | the extension `datekeys.capsule` of a `.dkk`, its envelope and its locator, and what a reader rejects and uses of them | §44.1, §64 |
| `vectors/mutations.json` | the mutation corpus: the 178 mutations of §64 and further cases | §63, §64 |
| `vectors/inspect_differential.json` | 5110 mutations of fourteen fixtures with the verdict of steps 1 to 8 | §63 |
| `vectors/inspect_differential.json` | 5110 mutations of fourteen fixtures with the verdict of steps 1 to 8 | §63 |
| `fixtures/<name>.dkc`, `<name>.json` | official capsules and every intermediate value | §67 |
| `fixtures/<name>.dkc`, `<name>.json` | official capsules and every intermediate value | §67 |
| `fixtures/<name>.dkk`, `<name>.dkk.json` | official access keys | §68 |
| `fixtures/<name>.dkk`, `<name>.dkk.json` | official access keys | §68 |
| `fixtures/<name>.plaintext` | the content of each capsule: what the reader delivers in formats 1 and 2, without the padding of format 2, and in format 3 BODY, whose files its record lays out | §67 |
| `fixtures/<name>.plaintext` | the content of each capsule: what the reader delivers in formats 1 and 2, without the padding of format 2, and in format 3 BODY, whose files its record lays out | §67 |
| `fixtures/<name>.inspect.json` | the exact output of `datekeys inspect -json` for each `.dkc` | §63 |
| `fixtures/<name>.inspect.json` | the exact output of `datekeys inspect -json` for each `.dkc` | §63 |
There are twenty-one official capsules. Five are in format 1, the fixtures of
There are twenty-six official capsules. Five are in format 1, the fixtures of
v0.8.2, kept for compatibility: `time_only`, `time_only_extensions`,
v0.8.2, kept for compatibility: `time_only`, `time_only_extensions`,
`time_and_key_portable`, `time_and_key_recipients` and `empty_payload`. Seven
`time_and_key_portable`, `time_and_key_recipients` and `empty_payload`. Seven
are in format 2, the fixtures of v0.9, kept for compatibility too:
are in format 2, the fixtures of v0.9, kept for compatibility too:
@ -73,7 +85,7 @@ extension and a noncritical CONTROL_CBOR extension. The release that opens each
capsule, a published Quicknet signature, is in its `<name>.json`, so they all
capsule, a published Quicknet signature, is in its `<name>.json`, so they all
decrypt offline.
decrypt offline.
Twelve are in format 3. Their plaintext file is BODY, L bytes: the frame, the
Fourteen are in format 3. Their plaintext file is BODY, L bytes: the frame, the
security area, the head and the files (spec §29.2).
security area, the head and the files (spec §29.2).
| Fixture | Policy | Files | Comment | L | Padding code | P | Area | Verdicts |
| Fixture | Policy | Files | Comment | L | Padding code | P | Area | Verdicts |
@ -87,27 +99,39 @@ security area, the head and the files (spec §29.2).
"vectors": [ { "name": "a signature of alg 4294967295, reserved for tests", "hex": "a300…", "signature": "F1", "seal": "S0", "lines": ["No se ha comprobado ninguna firma: trátala como no firmada."] } ]
}
```
```
X stands for both, when the outer map fails its layer 2 or 3: key 2 that is
X stands for both, when the outer map fails its layer 2 or 3: key 2 that is
not a byte string, or an empty one, an unknown key 4, a byte more after the
not a byte string, or an empty one, an unknown key 4, a byte more after the
map, version 2, another type tag, keys out of order, an array. Otherwise the
map, version 2, another type tag, keys out of order, an array. Otherwise the
signature and the seal are evaluated apart, and the first row of the table of
signature and the seal are evaluated apart, and the first row of the table of
§29.7 that holds decides: `alg` 0, an empty key or content that is not CBOR
§29.7 that holds decides:
give F1 with the seal intact, and a seal that breaks its schema gives S2 even
with an unknown `seal_type`, which is read only from a seal that meets it.
- an empty area, as a writer without a signer writes it: F0 and S0;
- a signature of `alg` 1 that verifies over the context: F4, and one that
does not: F2;
- `alg` 0 or 4294967295, an empty key, or content that is not CBOR or has a
byte more: F1, with the seal intact;
- a seal of `seal_type` 1, 3 or 4294967295: S1; one of `seal_type` 0, one that
breaks its schema, even with an unknown `seal_type`, which is read only from
a seal that meets it, and one of `seal_type` 2 whose token is not DER: S2.
`lines` are the verdicts as §29.7 words them, which an implementation writes
byte for byte. The valid signatures of `alg` 2 and seals of `seal_type` 2 are
in `security_cms.json`.
## `vectors/security_cms.json`
## `vectors/security_cms.json`
Security areas with an author signature of `alg` 2, a CMS signature with
Security areas with an author signature of `alg` 2, a CMS signature with
certificates, or a time seal of `seal_type` 2, an RFC 3161 token, each with
certificates, or a time seal of `seal_type` 2, an RFC 3161 token: 135 cases,
the context of its capsule and the verdicts of spec v0.11 §29.7, §29.10 and
each with the context of its capsule, the verdicts, the result of each signer
§29.11. They complete `security.json`, whose areas have no valid signature or
and the lines of the draft v0.12, §29.7, §29.10 and §29.11. They complete
seal. The file is frozen: the certificates and the tokens are made once, with
`security.json`, whose areas have no valid signature or seal of these kinds.
test keys, so a second implementation reads them and must reach the same
The file is frozen: the certificates and the tokens are made once, with test
verdicts. Delete the file to make it again.
keys, so a second implementation reads them and must reach the same verdicts
and write the same lines. Delete the file to make it again.
```json
```json
{ "name": "alg 2: a required signer is absent", "security_cbor": "a4…",
{ "name": "alg 2: a required signer is absent: F5", "security_cbor": "a3…",
with a signer who is not required; F5 for an absent signer, no seal, a seal
`out of validity` or `not verifiable`), the `seal_time` of its CAdES-T when
from before the certificate was valid and a key 3 beside the signature; F2 in
it has one, and `before_round_time`, whether that time plus its accuracy
the context of another head; F1 for SIGNERS out of order or empty, a signature
precedes the round time.
that is not a CMS, and the lack of a context; and, over an `alg` 1 signature,
- `seal_holder` and `seal_time`: the authority and the time of a valid seal
the seals S4, S5 (also when the accuracy reaches the round time), S3 (another
of key 3.
subject, an authority expired at its time), S2 (a TSTInfo of version 2, not
- `lines`: the verdicts as the official SDK shows them (§29.7), byte for byte:
DER), S1 (a SHA-384 imprint) and a seal over a capsule without a signature.
the names between « and », the line of each signer with its authority, the
warning that DateKeys does not check who issued the seals, and the times in
RFC 3339 with the fraction of the token.
A time is in RFC 3339, with the fraction of the token when it has one. The
cases follow each row of §29.7 and each item of the lists of §64 for v0.11
and v0.12: F6 with two signers, after the round time, with a signer who is not
required and with 16 signers; F5 for an absent signer, a withdrawn CAdES-T, no
seal, a certificate out of validity and keys outside the table; F2 in the
context of another head and for a message-digest of another message; F1 for
SIGNERS that break its rule beside a valid CMS, BER, two SignerInfo of one
certificate, the version against the `sid`, two content-type attributes, the
ESSCertIDv2 and the certificate of the signer; every hash and curve of the
table, RSASSA-PSS with and without `trailerField`, an attribute with an arc of
2^31 and a certificate twice; the names of the holder and of the issuer in
each string type and against each rule, `givenName` and `surname` before a
`commonName` with its NIF included; and, over an `alg` 1 signature, the seals
S1 to S5 at the edges of the token: its accuracy, its `genTime`, `ordering`,
a field after the last, the imprint, `crls` and the authority.
## `vectors/locator.json`
## `vectors/locator.json`
The extension `datekeys.capsule` of a `.dkk` and what it points to (spec
The extension `datekeys.capsule` of a `.dkk` and what it points to (spec
v0.11, §44.1): a `.dkc` of patterned bytes in an envelope of age whose header
§44.1): a `.dkc` of patterned bytes in an envelope of age whose header
(`envelope_header`) goes in the locator and whose `rest`, without a mark, is
(`envelope_header`) goes in the locator and whose `rest`, without a mark, is
hidden in a `host` file at `host_offset`; the locator sealed with tlock for
hidden in a `host` file at `host_offset`; the locator sealed with tlock for
round 1000 (`locator_sealed`), with its plaintext of 4096 bytes
round 1000 (`locator_sealed`), with its plaintext of 4096 bytes
(`locator_plaintext`) and its fields; and the data of the extension
(`locator_plaintext`) and its fields; and the data of the extension
(`extension_data`), with the note `note` and the DateKey `datekey`. A reader
(`extension_data`), with the note `note` and the DateKey `datekey`. A reader
opens the locator with the release of round 1000 (`quicknet_rounds.json`),
opens the locator with the release of round 1000, which `mutations.json` and
finds the rest in the host, checks `rest_size`, `rest_digest` and
the records of the fixtures of that round give, finds the rest in the host,
`capsule_digest`, and gets the `.dkc` back. The file is frozen: the envelope
checks `rest_size`, `rest_digest` and `capsule_digest`, and gets the `.dkc`
and the locator hold randomness.
back. The file is frozen: the envelope and the locators hold randomness.
`padding_cases` give the length of the plaintext of the locator for the length
On the same envelope, the cases of §64, each checked against the reference
of its CBOR without the padding of key 6: the least multiple of 4096 that key 6
when the file is made:
can fill exactly, which skips a multiple where the CBOR length of key 6 jumps
(a base of 4070 gives 8192). `uri_cases` give the verdict of the rules of §44.1
- `padding_cases`: the length of the plaintext of a locator for `base`, the
on an address: the scheme `https` or `ipfs`, the raw ASCII authority with no
length of its CBOR without key 6: the least multiple of 4096 that holds it,
percent sign or userinfo, a host of letters, digits and hyphens or a public IP
or the next one when key 6 cannot complete it, because 1, 2, 26 or 259
literal, and a port from 1 to 65535.
bytes are missing (§44.1). Among them the bases 3837, 4070, 4094 and 4095,
which give 8192, those of the next multiple, which give 12288, and their
neighbours.
- `uri_cases`: an address and whether the rules of §44.1 accept it (`ok`):
the scheme, the authority without a percent sign, userinfo or a backslash,
the port, each character outside RFC 3986 and a percent sign without two
hexadecimal digits, the "." and ".." segments, written or with `%2e`, in the
path but not in the query or the fragment, the first and the last address
of each IPv4 block of §44.1 with the public addresses next to them, the
IPv6 blocks and the addresses that hold an IPv4 one, the names that only a
machine or a local network resolves, a last segment that is numeric or
starts with `0x`, and base32 that is not a CID v1.
- `mixed`: a second locator of the envelope, sealed for round 1000 too. Of its
`addresses`, a reader rejects the first two, an `http` one and one of NAT64
that leads to 127.0.0.1, and uses the third (`usable`), which finds the rest
in `host`: the locator reads all the same. A writer never writes it.
- `rest_cases`: a `resource` as a reader downloads it, the `offset` that an
address gives, and whether the rest read there opens the envelope (`opens`):
the rest alone, the host with bytes after the rest, of which only
`rest_size` bytes from the offset are read, a byte of the rest changed, an
offset that is not its own, and a rest cut short.
- `extension_cases`: data of `datekeys.capsule` and whether a reader can use
it (`ok`): without a locator, and unusable, with only
`ERR_EXTENSION_DATA_INVALID`, for a locator sealed for round 1001 beside a
DateKey of round 1000, a locator that is not an age file or is empty, no
DateKey or one that is not canonical, a note that breaks its rules and a
key 3.
- `plaintext_cases`: plaintexts of a locator of the envelope, each with the
defect that its name says or none, and whether a reader reads them (`ok`).
The bases 4094, 4070 and 3837 completed to 4096 with an empty key 6 or with
its length not in its shortest form, against the 8192 bytes of the base
4094 (§76 of v0.12, change 7); eight addresses and nine, none, an empty one
and one of 1025 bytes, which make the whole locator unreadable, an offset of
0 written, an offset and a `resto_size` of 2^53; two blocks where one
suffices, padding that is not zeros, a byte less and a byte more. An
address that breaks the rules of §44.1 does not make a locator unreadable:
that is `mixed`.
## `vectors/note.json`
The data of the public note, `datekeys.note` version 1 in the noncritical
array of PUBLIC_HEADER (spec §24.1): text in UTF-8, from 1 to 1024 bytes, that
meets the rules of the declared author of §29.6. A writer writes a note only
when its `result` is `ok`; a reader shows it only then, and otherwise treats
the note as unusable, never the capsule (§54), and says so.
```json
{ "name": "a bidi override", "data": "61e280ae62", "result": "ERR_EXTENSION_DATA_INVALID", "detail": "a public note that breaks the rules of text: text: bidirectional control U+202E" }
```
`detail` is the text of the rule that a note breaks, without the code, as the
reference words it. Among the cases: letters that are not ASCII and an emoji,
an emoji with VS16, 1024 bytes, accepted; no byte, 1025 bytes, a tab, a line
feed, a space at either end, U+202E, U+200B, a byte order mark, a
noncharacter, a byte that is not UTF-8 and the UTF-8 of a lone surrogate,
refused.
## `vectors/ed25519_strict.json`
## `vectors/ed25519_strict.json`
Ed25519 signatures, in hexadecimal, and whether the strict profile of the
Ed25519 signatures, in hexadecimal, and whether the strict profile of the
author signature accepts them (spec v0.11, §29.9): the equation of RFC 8032
author signature accepts them (spec §29.9): the equation of RFC 8032
without the cofactor, A and R canonical, S below ℓ and A not of small order.
without the cofactor, A and R canonical, S below ℓ and A not of small order.
They follow the cases of «Taming the many EdDSAs»: S + ℓ, the top bits of S, a
They follow the cases of «Taming the many EdDSAs»: S + ℓ, the top bits of S, a
non-canonical R, the eight points of small order as A, non-canonical
non-canonical R, the eight points of small order as A, non-canonical
@ -504,15 +619,16 @@ reading flow (`capsule.Open`, §63) must fail.
```
```
- `name`: unique, stable.
- `name`: unique, stable.
- `spec`: true for the 169 mutations listed in spec §64, false for the further
- `spec`: true for the 178 mutations listed in spec §64, false for the further
cases of the reference. The cases come in this order: the 33 mutations of
cases of the reference. The cases come in this order: the 33 mutations of
the first two lists of §64 on the format 1 fixtures (cases 1 to 33), 32
the first two lists of §64 on the format 1 fixtures (cases 1 to 33), 32
further cases (34 to 65), the same 33 mutations on the format 2 fixtures,
further cases (34 to 65), the same 33 mutations on the format 2 fixtures,
named "format 2: …" (66 to 98), the 23 of the list of format 2 (99 to 121),
named "format 2: …" (66 to 98), the 23 of the list of format 2 (99 to 121),
5 further cases (122 to 126), the same 33 on the format 3 fixtures, named
5 further cases (122 to 126), the same 33 on the format 3 fixtures, named
"format 3: …" (127 to 159), the 47 of the list of format 3 (160 to 206),
"format 3: …" (127 to 159), the 48 of the list of format 3 (160 to 207), the
and 3 further cases (207 to 209). A line of the lists of §64 with several
8 of the list of v0.11 that a capsule can hold (208 to 215), and 3 further
values, such as "AREA_LEN 0, 511, 513 o 66048", is one case for each.
cases (216 to 218). A line of the lists of §64 with several values, such as
"AREA_LEN 0, 511, 513 o 66048", is one case for each.
- `dkc`: the capsule, as edits of a fixture (see above). The reader gets it as a
- `dkc`: the capsule, as edits of a fixture (see above). The reader gets it as a
seekable file, so that the `capsule_digest` of an offered `.dkk` is checked
seekable file, so that the `capsule_digest` of an offered `.dkk` is checked
before any release request (spec §63 step 9.a).
before any release request (spec §63 step 9.a).
@ -551,8 +667,8 @@ reading flow (`capsule.Open`, §63) must fail.
- `error`, `step`: the expected code and the step of §63 that fails. For a
- `error`, `step`: the expected code and the step of §63 that fails. For a
capsule that opens, `error` is `ok`, `step` is 0 and `verdicts` holds the
capsule that opens, `error` is `ok`, `step` is 0 and `verdicts` holds the
verdicts of its security area, `signature` and `seal`, with the `lines`
verdicts of its security area, `signature` and `seal`, with the `lines`
that show them (spec §29.7): the three cases of security of the list of
that show them (spec §29.7): the four cases of security of the list of
format 3.
format 3, and seven of the list of v0.11.
Every case reproduces offline: the recorded release stands in for the network.
Every case reproduces offline: the recorded release stands in for the network.
A reader that implements only steps 1 to 8 can replay every case whose `step` is
A reader that implements only steps 1 to 8 can replay every case whose `step` is
@ -631,7 +747,7 @@ that.
### Format 3: its list of §64
### Format 3: its list of §64
The 47 cases of the list of format 3 of §64 test what format 3 adds, all at
The 48 cases of the list of format 3 of §64 test what format 3 adds, all at
step 17 but the first:
step 17 but the first:
- `VERSION` 2 on a format 3 capsule, at step 14 (`VERSION` 4 is
- `VERSION` 2 on a format 3 capsule, at step 14 (`VERSION` 4 is
@ -649,8 +765,10 @@ step 17 but the first:
is not zero is `ERR_HEAD_INVALID`, but with the next STREAM chunk corrupt,
is not zero is `ERR_HEAD_INVALID`, but with the next STREAM chunk corrupt,
or with PAYLOAD_AGE cut right after the chunk that holds the head, it is
or with PAYLOAD_AGE cut right after the chunk that holds the head, it is
`ERR_INTEGRITY`;
`ERR_INTEGRITY`;
- three cases of security that open, without a code, with the verdicts X,
- four cases of security that open, without a code, with the verdicts X,
F1 and S1.
F1, F2 and S1: a security map of version 2, a signature of `alg`
4294967295, a signature of `alg` 1 that does not verify and a seal of
`seal_type` 4294967295.
They derive from `format3_single`, and the two that need a head followed by
They derive from `format3_single`, and the two that need a head followed by
another chunk from `format3_tree`. What a case changes in BODY is sealed again
another chunk from `format3_tree`. What a case changes in BODY is sealed again
@ -663,6 +781,23 @@ file. The three
further cases relabel format 3 as 1, and a `time_and_key` capsule as 2 with
further cases relabel format 3 as 1, and a `time_and_key` capsule as 2 with
its identity and with its `.dkk`.
its identity and with its `.dkk`.
### Signature, seal and note: the list of v0.11
Eight cases of the list of v0.11 of §64 change a capsule; the rest of that
list is in `ed25519_strict.json`, `security_cms.json`, `note.json` and
`locator.json`, and in the fixtures `format3_unsigned` and `format3_signed`,
which have the same P. Seven open with their verdicts:
- on `format3_signed`, the signature of `alg` 1 altered (F2), removed (F0),
made again with another key (F4, with the key of that signature), with a
key of 31 bytes or a signature of 65 bytes (F1), and the area widened from
32 KiB to 64 KiB after signing, which leaves the signature valid and
`AUTHOR_MESSAGE` unchanged (F4);
- the signature of `format3_signed` transplanted to `format3_unsigned` (F2).
The eighth changes the public note in the PUBLIC_HEADER of `format3_note`:
`ERR_HEADER_BINDING` at step 15.
## The checks of steps 1 to 8
## The checks of steps 1 to 8
`mutations.json` and `inspect_differential.json` follow the rules of the
`mutations.json` and `inspect_differential.json` follow the rules of the
@ -777,8 +912,8 @@ at least `step`, `name`, `ok` and `error`, and every other field.
files in BODY, 12 + `AREA_LEN` + `HEAD_LEN`, `files`, each with its `path`,
files in BODY, 12 + `AREA_LEN` + `HEAD_LEN`, `files`, each with its `path`,
`size`, `start`, `end`, `sha256` and `mtime` when it has one, its bytes
`size`, `start`, `end`, `sha256` and `mtime` when it has one, its bytes
being those of BODY from `content_offset + start` to `content_offset +
being those of BODY from `content_offset + start` to `content_offset +
end`, and `verdicts`, with `signature`, `seal` and the `lines` that show
end`, and `verdicts`, with `signature`, `seal`, the `lines` that show
them.
them and, with F4, the `author_key`.
- `fixtures/<name>.dkk.json`: for each `.dkk`, its SHA-256, `credential_id`,
- `fixtures/<name>.dkk.json`: for each `.dkk`, its SHA-256, `credential_id`,
`capsule_id`, `access_type`, `access_material` (a test secret),
`capsule_id`, `access_type`, `access_material` (a test secret),
`capsule_digest`, extensions and the capsule it opens.
`capsule_digest`, extensions and the capsule it opens.