You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
DateKeys/errors.go

100 lines
5.1 KiB

// Package datekeys is the reference Go implementation of the DateKeys Protocol
Implement capsule format 2 of spec v0.9 The reference moves to the DateKeys Protocol Specification v0.9, approved by its author on 29 September 2026. Encrypt writes capsule format 2 only; Open and Inspect read formats 1 and 2, and a format 1 capsule keeps the verdict v0.8.2 gave it. Format 2 (spec §22, §29.1, §31, §39): - VERSION in the PRELUDE is the capsule format, capsule.Format; any other value is ERR_UNSUPPORTED_VERSION at step 2. - CONTROL_CBOR has the schema version of its format. Version 2 adds key 6, payload_length (8 bytes, big-endian, at most L_MAX = 2^53 - 2^46), and key 7, padding (1 bloque256, 2 reforzado); it is 103 bytes without extensions, whatever L. - The payload is the content padded with zeros to P = rule(L). Step 17 checks the length and the zeros, and Open writes only the first L bytes. - INNER_ACCESS_AGE holds exactly 16 X25519 stanzas: 1 to 16 credentials, and a dummy in each slot left, in a uniformly random order. Writer rules (spec §62.1): EncryptOptions.Length is required and the source must deliver exactly that many bytes; recipients that are not canonical or of low order are rejected (agewrap.CheckX25519Recipient); self-checks of the header, the control, INNER_ACCESS_AGE and PAYLOAD_AGE. The CLI measures its input, takes -padding and reports the format. Test data: seven format 2 fixtures, padding vectors checked against math/big, format 2 CBOR vectors, and the mutation corpus in both formats with the 22 cases of the third list of spec §64, built without randomness by sealing the fixtures again with their known keys and nonces. The format 1 fixtures are kept byte for byte and never regenerated; the differential corpus keeps its 1825 cases and adds a block per format 2 fixture. The spec copy loses its "to be implemented" markers, and the READMEs, CHANGELOG, traceability and testdata/README.md follow v0.9. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 week ago
// Specification v0.9 (spec/DateKeys_Protocol_Specification_v0.9.md).
//
// The protocol objects live in subpackages:
//
// - datekey: DateKey resolution and the canonical dk1_ form (spec §14-§19).
// - profile: Provider Profiles and the pinned Quicknet profile (spec §10-§13).
// - provider, provider/drand: release sources and local BLS verification (spec §45-§52).
// - capsule: the DateKeyCap .dkc container (spec §20-§39, §61-§63).
// - accesskey: the DateKeys Access Key .dkk credential (spec §40-§44).
// - extension: the generic extension mechanism (spec §54).
//
// This package holds the normative error catalogue of spec §69. Every protocol
// failure returned by this module wraps exactly one of these sentinels, so
// callers can match them with [errors.Is] and extract the code with [Code].
package datekeys
import "errors"
// Error is a normative DateKeys error (spec §69). Values are compared by
// identity; use [errors.Is] against the exported sentinels.
type Error struct {
code string
}
// Error returns the normative code, for example "ERR_INVALID_MAGIC".
func (e *Error) Error() string { return e.code }
// Code returns the normative code, for example "ERR_INVALID_MAGIC".
func (e *Error) Code() string { return e.code }
// Normative errors, spec §69.
var (
// ErrInvalidMagic: the object does not start with DKC1 or DKK1 (spec §22, §40).
ErrInvalidMagic = &Error{"ERR_INVALID_MAGIC"}
// ErrUnsupportedVersion: an unknown framing or schema version (spec §22, §70).
ErrUnsupportedVersion = &Error{"ERR_UNSUPPORTED_VERSION"}
// ErrInvalidFlags: FLAGS or RESERVED are not zero (spec §22, §40).
ErrInvalidFlags = &Error{"ERR_INVALID_FLAGS"}
// ErrNonCanonicalCBOR: the bytes are not the unique deterministic CBOR
// encoding of a valid instance of the normative schema (spec §58, §58.1).
ErrNonCanonicalCBOR = &Error{"ERR_NON_CANONICAL_CBOR"}
// ErrUnknownProfile: the DateKey names a profile that is not pinned locally (spec §13).
ErrUnknownProfile = &Error{"ERR_UNKNOWN_PROFILE"}
// ErrProfileMismatch: a chain hash or profile does not match the pinned profile (spec §35, §63).
ErrProfileMismatch = &Error{"ERR_PROFILE_MISMATCH"}
// ErrDateKeyInvalid: a DateKey that cannot be decoded or validated (spec §18, §19).
ErrDateKeyInvalid = &Error{"ERR_DATEKEY_INVALID"}
// ErrDateKeyNonCanonical: a valid DateKey in a non-canonical encoding (spec §19).
ErrDateKeyNonCanonical = &Error{"ERR_DATEKEY_NON_CANONICAL"}
// ErrRoundMismatch: a round that differs from the locally resolved one (spec §17, §63).
ErrRoundMismatch = &Error{"ERR_ROUND_MISMATCH"}
// ErrReleaseUnavailable: the release is not published yet or no source delivered it (spec §45-§50).
ErrReleaseUnavailable = &Error{"ERR_RELEASE_UNAVAILABLE"}
// ErrReleaseInvalid: a release that fails local verification (spec §51).
ErrReleaseInvalid = &Error{"ERR_RELEASE_INVALID"}
// ErrAccessRequired: the policy requires an access credential and none was supplied (spec §33).
ErrAccessRequired = &Error{"ERR_ACCESS_REQUIRED"}
// ErrAccessInvalid: the supplied credentials do not open this capsule (spec §33, §38).
ErrAccessInvalid = &Error{"ERR_ACCESS_INVALID"}
// ErrPolicyStructureMismatch: the cryptographic structure does not match the
// declared access policy or the stanza rules of V1 (spec §25, §29, §32, §33, §36).
ErrPolicyStructureMismatch = &Error{"ERR_POLICY_STRUCTURE_MISMATCH"}
// ErrHeaderBinding: header_binding does not match PRELUDE || PUBLIC_HEADER (spec §26).
ErrHeaderBinding = &Error{"ERR_HEADER_BINDING"}
// ErrIntegrity: truncation, corruption or failed authentication of framing or age data (spec §4, §55).
ErrIntegrity = &Error{"ERR_INTEGRITY"}
// ErrExtensionCriticalUnknown: a critical extension this implementation does not know (spec §54).
ErrExtensionCriticalUnknown = &Error{"ERR_EXTENSION_CRITICAL_UNKNOWN"}
// ErrExtensionDataInvalid: a known extension whose data does not follow its
// registered schema. It rejects the object only for a critical extension; a
// noncritical one is reported as unusable (spec §54, §72).
ErrExtensionDataInvalid = &Error{"ERR_EXTENSION_DATA_INVALID"}
// ErrHeadInvalid: the head of a format 3 capsule is well encoded but one
// of its fields breaks its rules: a path, the comment, the declared author
// or the layout of the files (spec §29.4 to §29.6). New in v0.10.
ErrHeadInvalid = &Error{"ERR_HEAD_INVALID"}
)
// All returns every normative error in the order of spec §69.
func All() []*Error {
return []*Error{
ErrInvalidMagic, ErrUnsupportedVersion, ErrInvalidFlags, ErrNonCanonicalCBOR,
ErrUnknownProfile, ErrProfileMismatch, ErrDateKeyInvalid, ErrDateKeyNonCanonical,
ErrRoundMismatch, ErrReleaseUnavailable, ErrReleaseInvalid, ErrAccessRequired,
ErrAccessInvalid, ErrPolicyStructureMismatch, ErrHeaderBinding, ErrIntegrity,
ErrExtensionCriticalUnknown, ErrExtensionDataInvalid, ErrHeadInvalid,
}
}
// Code returns the normative code of the first DateKeys error in err's tree,
// or "" if err does not wrap one.
func Code(err error) string {
var e *Error
if errors.As(err, &e) {
return e.code
}
return ""
}

Powered by TurnKey Linux.