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/accesskey/precedence_test.go

62 lines
2.7 KiB

Spec v0.8.2 refinements: error precedence, trust model, strict order Approved refinements, each recorded with its reproducible case in the §76 v0.8.2 subsection: - §69.1: layered error model with normative precedence (frame, type tag and version, CBOR profile and CDDL, then fields with their own code in ascending key order; across steps the §63 order decides), with a scope paragraph for the optional steps 5, 6 and 8. - §55.1: normative trust table per section (who can write it, from which step it is bound, what it never proves); §72: security-relevant claims go in CONTROL_CBOR or under a signature, .dkk data is advisory. - §31/§54: extension arrays in strictly ascending unsigned byte order of extension_id (one rule for order and uniqueness). - Gaps a second implementation needed: §28.1 malformed age headers, §15/§19 latest unlock time and dk1_ reading rules, §22/§23/§57 length lower bounds, §63 step 8 tlock argument comparison and step 9 order, §12.1 profile validation with the drand chain-hash formula, §74 table of implementation limits. Reference alignment: .dkk errors only at step 9.a (new OpenOptions.AccessKeyFile, used by the CLI), CR/LF in dk1_ is ERR_DATEKEY_INVALID, BODY_LEN 0 is ERR_INTEGRITY, nil identities are not credentials, and AccessIdentity tries every identity on every stanza so its verdict does not depend on their order. dk1.json gains three vectors; every other testdata file is byte-identical. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 weeks ago
package accesskey_test
import (
"bytes"
"errors"
"testing"
datekeys "g.activething.com/go/DateKeys"
"g.activething.com/go/DateKeys/accesskey"
"g.activething.com/go/DateKeys/internal/cbortest"
)
// Spec §40, §57, §69.1: a .dkk reports the code of its first failing layer:
// the frame (magic, framing version, FLAGS and RESERVED, BODY_LEN in 1 to
// 16 MiB, the body present and nothing after it), then the type tag and the
// schema version, then the CDDL, and last access_type and access_material
// (keys 4 and 5), whose own code is ERR_ACCESS_INVALID. A field of the wrong
// CBOR type breaks the CDDL (layer 3), not its own rule.
func TestDecodePrecedence(t *testing.T) {
good, _ := loadDKK(t, "time_and_key_portable")
w, err := cbortest.UnmarshalMap(good[accesskey.PreludeSize:])
if err != nil {
t.Fatal(err)
}
with := func(edit func(m map[uint64]any)) []byte {
m := map[uint64]any{}
for k, v := range w {
m[k] = v
}
edit(m)
b, err := cbortest.Marshal(m)
if err != nil {
t.Fatal(err)
}
return frame(b)
}
set := func(b []byte, i int, v byte) []byte { c := bytes.Clone(b); c[i] = v; return c }
malformed := frame([]byte{0xff})
a := map[uint64]any{0: "org.example.a", 1: uint64(1)}
for _, tc := range []struct {
name string
in []byte
want error
}{
{"BODY_LEN 0", frame(nil), datekeys.ErrIntegrity},
{"BODY_LEN 0 and FLAGS 1", set(frame(nil), 5, 1), datekeys.ErrInvalidFlags},
{"FLAGS 1 and a malformed body", set(malformed, 5, 1), datekeys.ErrInvalidFlags},
{"data after a malformed body", append(bytes.Clone(malformed), 0), datekeys.ErrIntegrity},
{"type tag of another schema and version 2", with(func(m map[uint64]any) { m[0], m[1] = "datekeycap", uint64(2) }), datekeys.ErrNonCanonicalCBOR},
{"version 2, unknown key and unknown access_type", with(func(m map[uint64]any) { m[1], m[9], m[4] = uint64(2), "x", "mlkem768" }), datekeys.ErrUnsupportedVersion},
{"unknown key and unknown access_type", with(func(m map[uint64]any) { m[9], m[4] = "x", "mlkem768" }), datekeys.ErrNonCanonicalCBOR},
{"extension_id in both arrays and short material", with(func(m map[uint64]any) { m[7], m[8], m[5] = []any{a}, []any{a}, make([]byte, 31) }), datekeys.ErrNonCanonicalCBOR},
{"access_type of another CBOR type", with(func(m map[uint64]any) { m[4] = uint64(1) }), datekeys.ErrNonCanonicalCBOR},
{"access_material of another CBOR type", with(func(m map[uint64]any) { m[5] = "material" }), datekeys.ErrNonCanonicalCBOR},
{"unknown access_type and short material", with(func(m map[uint64]any) { m[4], m[5] = "mlkem768", make([]byte, 31) }), datekeys.ErrAccessInvalid},
} {
if _, err := accesskey.Decode(bytes.NewReader(tc.in)); !errors.Is(err, tc.want) {
t.Errorf("%s: got %v, want %v", tc.name, err, tc.want)
}
}
}

Powered by TurnKey Linux.