Spec section 44.1 makes unusable a locator whose round or chain is not that
of its DateKey, and its plaintext is 4096 bytes or a multiple. ParseInfo
checked only the round: it now checks that the chain hash is lower-case
hexadecimal and, for a profile this module pins, the chain of the DateKey;
and that the body after the age header holds a plaintext of 4096 bytes or a
multiple, so that a header without a body is refused. Info.Extension, which
reads what it writes, refuses a DateKey of a profile that is not pinned.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
| 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, the scheme in lower case: `https` with a host of labels of 1 to 63 letters, digits and hyphens that neither start nor end with a hyphen, or a public IP outside the special-purpose blocks of IANA, an IPv4 without leading zeros, a port of 1 to 65535 without leading zeros, no local name in either case, no dot segment, or `ipfs` with a CID v1 of at most 128 characters in canonical 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`; `CheckResolvedIP`, the address a name resolves to, NAT64 included, of v0.13), 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`); `TestResolvedIPVectors` (`testdata/vectors/resolved_ip.json`, `internal/testkit.ResolvedIPVectors`), `TestResolvedIPWellKnownPrefix`; `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 |
| 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, the scheme in lower case: `https` with a host of labels of 1 to 63 letters, digits and hyphens that neither start nor end with a hyphen, or a public IP outside the special-purpose blocks of IANA, an IPv4 without leading zeros, a port of 1 to 65535 without leading zeros, no local name in either case, no dot segment, or `ipfs` with a CID v1 of at most 128 characters in canonical 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`; `CheckResolvedIP`, the address a name resolves to, NAT64 included, of v0.13), 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`, `TestInfoSealedForm` (the round, the chain and the body of the sealed locator), `TestUsableAddresses`, `TestLeastMultiple`, `TestPaddingBoundaries`, `TestLocatorVectors` (`testdata/vectors/locator.json`); `TestResolvedIPVectors` (`testdata/vectors/resolved_ip.json`, `internal/testkit.ResolvedIPVectors`), `TestResolvedIPWellKnownPrefix`; `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) | — |
| 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* |
returnnil,fmt.Errorf("locator: the locator is not an age file with one tlock stanza for round %d, the one of its DateKey: %w",d.Round,datekeys.ErrExtensionDataInvalid)