diff --git a/locator/fuzz_test.go b/locator/fuzz_test.go new file mode 100644 index 0000000..81f3171 --- /dev/null +++ b/locator/fuzz_test.go @@ -0,0 +1,73 @@ +package locator_test + +import ( + "bytes" + "encoding/hex" + "testing" + + "g.activething.com/go/DateKeys/extension" + "g.activething.com/go/DateKeys/internal/testkit" + "g.activething.com/go/DateKeys/locator" +) + +// FuzzUnmarshal reads the plaintext of a locator: it never panics, and what +// it accepts is canonical, so that encoding it again gives the same bytes. +func FuzzUnmarshal(f *testing.F) { + var v testkit.LocatorVectorFile + if err := testkit.ReadJSON("../testdata/vectors/locator.json", &v); err != nil { + f.Fatal(err) + } + if b, err := hex.DecodeString(v.Plaintext); err == nil { + f.Add(b) + } + f.Add([]byte{0xa0}) + f.Fuzz(func(t *testing.T, b []byte) { + l, err := locator.Unmarshal(b) + if err != nil { + return + } + for _, a := range l.Usable() { + if locator.CheckURI(a.URI) != nil || a.Host() == "" { + t.Fatalf("a usable address %q that the rules refuse", a.URI) + } + } + }) +} + +// FuzzParseInfo reads the data of datekeys.capsule: it never panics, and its +// only normative code is ERR_EXTENSION_DATA_INVALID (spec §54, §57). +func FuzzParseInfo(f *testing.F) { + var v testkit.LocatorVectorFile + if err := testkit.ReadJSON("../testdata/vectors/locator.json", &v); err != nil { + f.Fatal(err) + } + if b, err := hex.DecodeString(v.Extension); err == nil { + f.Add(b) + } + f.Fuzz(func(t *testing.T, b []byte) { + _, err := locator.ParseInfo(extension.Extension{ID: extension.CapsuleID, Version: 1, Data: b}) + if err != nil && !bytes.Contains([]byte(err.Error()), []byte("ERR_EXTENSION_DATA_INVALID")) { + t.Fatalf("an error without its code: %v", err) + } + }) +} + +// FuzzCheckURI checks an address: it never panics, and a host that it shows +// is in the address as it is written, with no decoding. +func FuzzCheckURI(f *testing.F) { + var v testkit.LocatorVectorFile + if err := testkit.ReadJSON("../testdata/vectors/locator.json", &v); err != nil { + f.Fatal(err) + } + for _, c := range v.URICases { + f.Add(c.URI) + } + f.Fuzz(func(t *testing.T, uri string) { + if locator.CheckURI(uri) != nil { + return + } + if h := (locator.Address{URI: uri}).Host(); h == "" || !bytes.Contains([]byte(uri), []byte(h)) { + t.Fatalf("%q: host %q", uri, h) + } + }) +} diff --git a/scripts/fuzz.sh b/scripts/fuzz.sh index dbcf2b0..7ed3cb7 100644 --- a/scripts/fuzz.sh +++ b/scripts/fuzz.sh @@ -28,6 +28,9 @@ targets=( "./capsule FuzzDecodeHead" "./capsule FuzzEvaluateSecurity" "./internal/pathrule FuzzCheckPath" + "./locator FuzzUnmarshal" + "./locator FuzzParseInfo" + "./locator FuzzCheckURI" "./capsule FuzzInspect" "./capsule FuzzEncodeImpliesDecode" )