; DateKeys Protocol Specification v0.9 (working draft) - CBOR schemas (RFC ; 8610 CDDL). ; ; Normative companion of spec/DateKeys_Protocol_Specification_v0.9.md. The ; reference implementation g.activething.com/go/DateKeys still implements ; v0.8.2, whose schemas are in tag spec-v0.8.2. These schemas include both ; control versions: 1, of capsule format 1 (v0.8.2), and 2, of format 2. ; ; Encoding rules that CDDL cannot express (spec section 58, 58.1): ; - Every structure uses the CBOR profile of the protocol (spec section 58): ; Deterministic CBOR (RFC 8949 section 4.2.1) restricted to major types 0, ; 2, 3, 4 and 5, with unsigned integer map keys in strictly ascending ; order, shortest-form integers and lengths, definite lengths only and ; valid UTF-8 text. Negative integers, tags, floats, simple values ; (including null) and indefinite lengths are rejected. ; - A decoder re-encodes what it decoded and rejects any byte difference ; (ERR_NON_CANONICAL_CBOR). ; - A semantically absent optional field is omitted. Empty arrays, empty ; maps, null, "" and h'' never stand for absence; the .size and non-empty ; constraints below make those forms invalid. ; - Maps are closed: keys not listed here are rejected. New semantics go in ; extensions (spec section 54). ; - The elements of each extension array are in strictly ascending order of ; the UTF-8 bytes of extension_id (spec section 54): bytes compared as ; unsigned integers, the first differing byte decides and a proper prefix ; sorts first; never UTF-16 code units, case folding, Unicode ; normalization or a locale collation. U+FF61 (ef bd a1) sorts before ; U+10000 (f0 90 80 80). The strict order also forbids a repeated ; extension_id within an array, and no extension_id appears in both ; arrays of one object, so an extension_id appears at most once per ; object. ; - A violation of a normative rule of this schema, including .size, ; integer ranges and the 64-extension maximum, is ERR_NON_CANONICAL_CBOR ; unless spec section 57 names a more specific error (schema version, ; compact_datekey, access_type and access_material, Provider Profile ; names and public key). Those rules are checked with the fields, after ; the rest of this schema; here a field needs only the CBOR type of its ; rule, and another type is ERR_NON_CANONICAL_CBOR. The implementation ; limits marked below are not normative; spec section 74 lists them, ; with the limits of the reference outside this schema, and an ; implementation that applies them uses the same mapping. ; - The schema version of a control (key 1) is the one spec section 22 ; assigns to the format of its capsule, the VERSION of the PRELUDE: ; control-v1 only in format 1, control-v2 only in format 2. A decoder ; picks the rule by the format, and another version is ; ERR_UNSUPPORTED_VERSION, read before the rest of the schema (spec ; section 69.1, layer 2). CDDL cannot express that link. ; - payload-length holds L as an unsigned 64-bit big-endian integer in ; exactly 8 bytes, whatever its value, and a decoder reads all 8 bytes; ; the value is at most max-payload-length (spec section 29.1, 31). A ; larger value is ERR_NON_CANONICAL_CBOR, like any rule of this schema. ; - When bytes break several rules, the code is the one of the first ; failing layer (spec section 69.1): frame, then type tag and schema ; version (keys 0 and 1; for a control, the version of its capsule ; format), then this schema, then the fields with codes of their own in ; ascending key order. ; Spec section 11 and 12. Spec section 12.1 adds the rules a profile must ; follow to be pinned (ERR_UNKNOWN_PROFILE), among them period at most 2^32-1 ; and a public key that is the canonical encoding (spec section 12.2) of a ; point of the key group of the scheme, 48 or 96 bytes, other than the point ; at infinity, and the chain-hash self-check, SHA-256(uint32_be(period) || ; int64_be(genesis_time) || public_key || genesis_seed || network), network ; left out when it is "default" (ERR_PROFILE_MISMATCH). provider-profile = { 0 => "datekeys-provider-profile", 1 => 1, 2 => profile-id, 3 => name, ; provider, "drand" 4 => name, ; provider network identifier, "quicknet" 5 => bstr .size 32, ; chain_hash 6 => public-key, ; group public key 7 => period, ; seconds; spec section 11: 1..max-safe-uint 8 => 0..max-safe-uint, ; genesis_time, Unix seconds 9 => name, ; scheme, "bls-unchained-g1-rfc9380" 10 => bstr .size 32, ; genesis_seed } ; Spec section 24. Stored as exact bytes after the 16-byte PRELUDE and covered ; by header_binding = SHA-256(PRELUDE || PUBLIC_HEADER). The same header, ; schema version 1, in both capsule formats. public-header = { 0 => "datekeycap", 1 => 1, 2 => capsule-id, 3 => compact-datekey, ; the only source of the profile 4 => access-policy, ? 5 => extensions, ; critical_extensions ? 6 => extensions, ; noncritical_extensions } ; Spec section 31. Sealed inside OUTER_TIME_AGE (time_only) or inside ; INNER_ACCESS_AGE inside OUTER_TIME_AGE (time_and_key). control = control-v1 / control-v2 ; Capsule format 1 (v0.8.2). control-v1 = { 0 => "datekeys-control", 1 => 1, 2 => bstr .size 32, ; header_binding 3 => bstr .size 32, ; payload_identity, raw X25519 identity I_PAYLOAD ? 4 => extensions, ; critical_extensions ? 5 => extensions, ; noncritical_extensions } ; Capsule format 2 (v0.9). 103 bytes without extensions. control-v2 = { 0 => "datekeys-control", 1 => 2, 2 => bstr .size 32, ; header_binding 3 => bstr .size 32, ; payload_identity, raw X25519 identity I_PAYLOAD ? 4 => extensions, ; critical_extensions ? 5 => extensions, ; noncritical_extensions 6 => payload-length, ; payload_length, L, the length of the content (spec section 29.1) 7 => padding-scheme, ; padding, the code of the padding rule of PAYLOAD_AGE (spec section 29.1) } ; Fixed width, so that the length of CONTROL_CBOR, visible in ; SEALED_CONTROL_LEN, never depends on L (spec section 55.2). Value at most ; max-payload-length (see the rules above). L = 0 is 48 0000000000000000. payload-length = bstr .size 8 ; No code stands for "no padding" (spec section 29.1). padding-scheme = &(bloque256: 1, reforzado: 2) ; 2^53 - 2^46: the largest L whose padded length P stays within ; max-safe-uint under both padding rules (spec section 29.1). max-payload-length = 8936830510563328 ; Spec section 41. BODY_CBOR of a .dkk, after the 12-byte DKK1 prelude. access-key-body = { 0 => "datekeys-access-key", 1 => 1, 2 => bstr .size 16, ; credential_id 3 => capsule-id, 4 => access-type, 5 => access-material, ? 6 => verification-metadata, ? 7 => extensions, ; critical_extensions ? 8 => extensions, ; noncritical_extensions } ; Spec section 43. Present only when it holds a digest: never an empty map. verification-metadata = { 0 => bstr .size 32, ; capsule_digest = SHA-256(exact .dkc bytes) } ; Spec section 31 and 54. extensions = [1*64 extension] extension = { 0 => extension-id, 1 => extension-version, ? 2 => extension-data, } extension-version = uint .le 4294967295 ; Opaque bytes: the base protocol never decodes or validates the content, and ; an extension without data omits key 2. The effective bound is the frame of ; the containing object (spec section 57); 67108864 bytes (64 MiB) is the ; largest frame, SEALED_CONTROL. Each registered extension declares its own ; maximum (spec section 72). extension-data = bstr .size (1..67108864) capsule-id = bstr .size 16 access-policy = &(time_only: 0, time_and_key: 1) access-type = "x25519" access-material = bstr .size 32 ; for access-type "x25519" ; 2^53-1: every unsigned integer of the protocol is exact as an IEEE 754 ; double (spec section 58). max-safe-uint = 9007199254740991 ; Names of the Provider Profile (spec section 12.1): the alphabets are ; normative, the maximum lengths of 128 and 64 bytes are implementation ; limits of the reference (spec section 74). A violation is ; ERR_UNKNOWN_PROFILE (spec section 57). profile-id also bounds the network ; of a dk1_ DateKey (ERR_DATEKEY_INVALID there), whose canonical JSON has no ; escapes (spec section 18). profile-id = tstr .regexp "[a-z0-9][a-z0-9:._-]{0,127}" name = tstr .regexp "[a-z0-9][a-z0-9._-]{0,63}" ; Spec section 31: at least 1 byte of valid UTF-8, normative; at most 256 ; bytes, an implementation limit of the reference (spec section 74). extension-id = tstr .size (1..256) ; Implementation limits of the reference implementation, listed in spec ; section 74, which leaves definitive field limits open. public-key = bstr .size (1..1024) ; spec section 12.1: 48 or 96 bytes by scheme period = 1..86400 ; at most one day; spec section 11: 1..max-safe-uint ; Spec section 18 and 19: "dk1_" + unpadded Base64URL of the canonical JSON ; {"version":1,"network":,"round":}, round in 1..2^53-1. ; Spec section 15 further bounds the round time of the round to ; 9999-12-31T23:59:59Z under the pinned profile (step 7 of section 63). A ; violation is ERR_DATEKEY_INVALID or ERR_DATEKEY_NON_CANONICAL (spec section ; 19), checked with the fields, not ERR_NON_CANONICAL_CBOR. compact-datekey = tstr .regexp "dk1_[A-Za-z0-9_-]+"