From 621865f5707eaca22d4a0d162a5390b8440f6b40 Mon Sep 17 00:00:00 2001 From: Rasmus Dahlberg Date: Mon, 27 Sep 2021 23:29:05 +0200 Subject: added shard_hint enforcement --- cmd/sigsum_log_go/main.go | 10 ++++++ pkg/instance/endpoint_test.go | 80 ++++++++++++++++++++++++++++--------------- pkg/instance/instance.go | 21 ++++++++---- 3 files changed, 77 insertions(+), 34 deletions(-) diff --git a/cmd/sigsum_log_go/main.go b/cmd/sigsum_log_go/main.go index 786504d..13bb54d 100644 --- a/cmd/sigsum_log_go/main.go +++ b/cmd/sigsum_log_go/main.go @@ -37,6 +37,8 @@ var ( witnesses = flag.String("witnesses", "", "comma-separated list of trusted witness verification keys in hex") maxRange = flag.Int64("max_range", 10, "maximum number of entries that can be retrived in a single request") interval = flag.Duration("interval", time.Second*30, "interval used to rotate the log's cosigned STH") + shardStart = flag.Int64("shard_interval_start", 0, "start of shard interval since the UNIX epoch in seconds") + shardEnd = flag.Int64("shard_interval_end", 0, "end of shard interval since the UNIX epoch in seconds") gitCommit = "unknown" ) @@ -102,6 +104,14 @@ func setupInstanceFromFlags() (*sigsum.Instance, error) { i.MaxRange = *maxRange i.Deadline = *deadline i.Interval = *interval + i.ShardStart = uint64(*shardStart) + if *shardStart < 0 { + return nil, fmt.Errorf("shard start must be larger than zero") + } + i.ShardEnd = uint64(*shardEnd) + if *shardEnd < *shardStart { + return nil, fmt.Errorf("shard end must be larger than shard start") + } i.Witnesses, err = newWitnessMap(*witnesses) if err != nil { return nil, fmt.Errorf("newWitnessMap: %v", err) diff --git a/pkg/instance/endpoint_test.go b/pkg/instance/endpoint_test.go index 95b71d3..20f4ba3 100644 --- a/pkg/instance/endpoint_test.go +++ b/pkg/instance/endpoint_test.go @@ -18,12 +18,14 @@ import ( var ( testWitVK = [types.VerificationKeySize]byte{} testConfig = Config{ - LogID: hex.EncodeToString(types.Hash([]byte("logid"))[:]), - TreeID: 0, - Prefix: "testonly", - MaxRange: 3, - Deadline: 10, - Interval: 10, + LogID: hex.EncodeToString(types.Hash([]byte("logid"))[:]), + TreeID: 0, + Prefix: "testonly", + MaxRange: 3, + Deadline: 10, + Interval: 10, + ShardStart: 10, + ShardEnd: 20, Witnesses: map[[types.HashSize]byte][types.VerificationKeySize]byte{ *types.Hash(testWitVK[:]): testWitVK, }, @@ -58,14 +60,14 @@ func mustHandle(t *testing.T, i Instance, e types.Endpoint) Handler { } func TestAddLeaf(t *testing.T) { - buf := func() io.Reader { + buf := func(shard uint64, sum, sig, vf string) io.Reader { // A valid leaf request that was created manually return bytes.NewBufferString(fmt.Sprintf( - "%s%s%s%s"+"%s%s%s%s"+"%s%s%s%s"+"%s%s%s%s"+"%s%s%s%s", - types.ShardHint, types.Delim, "0", types.EOL, - types.Checksum, types.Delim, "0000000000000000000000000000000000000000000000000000000000000000", types.EOL, - types.Signature, types.Delim, "4cb410a4d48f52f761a7c01abcc28fd71811b84ded5403caed5e21b374f6aac9637cecd36828f17529fd503413d30ab66d7bb37a31dbf09a90d23b9241c45009", types.EOL, - types.VerificationKey, types.Delim, "f2b7a00b625469d32502e06e8b7fad1ef258d4ad0c6cd87b846142ab681957d5", types.EOL, + "%s%s%d%s"+"%s%s%s%s"+"%s%s%s%s"+"%s%s%s%s"+"%s%s%s%s", + types.ShardHint, types.Delim, shard, types.EOL, + types.Checksum, types.Delim, sum, types.EOL, + types.Signature, types.Delim, sig, types.EOL, + types.VerificationKey, types.Delim, vf, types.EOL, types.DomainHint, types.Delim, "example.com", types.EOL, )) } @@ -76,6 +78,7 @@ func TestAddLeaf(t *testing.T) { err error // error from Trillian client wantCode int // HTTP status ok }{ + // XXX introduce helper so that test params are not hardcoded { description: "invalid: bad request (parser error)", ascii: bytes.NewBufferString("key=value\n"), @@ -83,28 +86,51 @@ func TestAddLeaf(t *testing.T) { }, { description: "invalid: bad request (signature error)", - ascii: bytes.NewBufferString(fmt.Sprintf( - "%s%s%s%s"+"%s%s%s%s"+"%s%s%s%s"+"%s%s%s%s"+"%s%s%s%s", - types.ShardHint, types.Delim, "1", types.EOL, - types.Checksum, types.Delim, "1111111111111111111111111111111111111111111111111111111111111111", types.EOL, - types.Signature, types.Delim, "4cb410a4d48f52f761a7c01abcc28fd71811b84ded5403caed5e21b374f6aac9637cecd36828f17529fd503413d30ab66d7bb37a31dbf09a90d23b9241c45009", types.EOL, - types.VerificationKey, types.Delim, "f2b7a00b625469d32502e06e8b7fad1ef258d4ad0c6cd87b846142ab681957d5", types.EOL, - types.DomainHint, types.Delim, "example.com", types.EOL, - )), + ascii: buf(10, + "0000000000000000000000000000000000000000000000000000000000000000", + "11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111", + "f6eef8e94ddf1396682871257e670a1d9b627cf460daade7c36d218b2866befb", + ), + wantCode: http.StatusBadRequest, + }, + { + description: "invalid: bad request (shard hint is before shard start)", + ascii: buf(9, + "0000000000000000000000000000000000000000000000000000000000000000", + "20876ac8bf2c32d0c7f9b51b57f2de2f454c82c6b189ee30d5275361b657299b3e4e4d677646ec2586927a5a015ad349ae1ca4440e1bf6efbec875144d3a4009", + "a70f95f1739834190ec9a2a2fcee8ba8e70eddeb825c9856edfb2d8c5dfda595", + ), + wantCode: http.StatusBadRequest, + }, + { + description: "invalid: bad request (shard hint is before shard start)", + ascii: buf(21, + "0000000000000000000000000000000000000000000000000000000000000000", + "79c14f0ad9ab24ab98fe9d5ff59c3b91348789758aa092c6bfab2ac8890b41fb1d44d985e723184f9de42edb82b5ada14f494a96e361914d5366dd92379a1d04", + "91347ef525e149765225d1341ae2e07ce0f2256a44ae20f04f143f11285c8031", + ), wantCode: http.StatusBadRequest, }, { description: "invalid: backend failure", - ascii: buf(), - expect: true, - err: fmt.Errorf("something went wrong"), - wantCode: http.StatusInternalServerError, + ascii: buf(10, + "0000000000000000000000000000000000000000000000000000000000000000", + "7df253d2578c6c20b90832245ad6f981077454667796b3d507336a89ee878a2eae6b96e6d8de84fe8c1acf4b3aaffd482b657b65d94ed5e6be6320492147f90c", + "f6eef8e94ddf1396682871257e670a1d9b627cf460daade7c36d218b2866befb", + ), + expect: true, + err: fmt.Errorf("something went wrong"), + wantCode: http.StatusInternalServerError, }, { description: "valid", - ascii: buf(), - expect: true, - wantCode: http.StatusOK, + ascii: buf(10, + "0000000000000000000000000000000000000000000000000000000000000000", + "7df253d2578c6c20b90832245ad6f981077454667796b3d507336a89ee878a2eae6b96e6d8de84fe8c1acf4b3aaffd482b657b65d94ed5e6be6320492147f90c", + "f6eef8e94ddf1396682871257e670a1d9b627cf460daade7c36d218b2866befb", + ), + expect: true, + wantCode: http.StatusOK, }, } { // Run deferred functions at the end of each iteration diff --git a/pkg/instance/instance.go b/pkg/instance/instance.go index 809349c..2f5dd4c 100644 --- a/pkg/instance/instance.go +++ b/pkg/instance/instance.go @@ -16,12 +16,14 @@ import ( // Config is a collection of log parameters type Config struct { - LogID string // H(public key), then hex-encoded - TreeID int64 // Merkle tree identifier used by Trillian - Prefix string // The portion between base URL and st/v0 (may be "") - MaxRange int64 // Maximum number of leaves per get-leaves request - Deadline time.Duration // Deadline used for gRPC requests - Interval time.Duration // Cosigning frequency + LogID string // H(public key), then hex-encoded + TreeID int64 // Merkle tree identifier used by Trillian + Prefix string // The portion between base URL and st/v0 (may be "") + MaxRange int64 // Maximum number of leaves per get-leaves request + Deadline time.Duration // Deadline used for gRPC requests + Interval time.Duration // Cosigning frequency + ShardStart uint64 // Shard interval start (num seconds since UNIX epoch) + ShardEnd uint64 // Shard interval end (num seconds since UNIX epoch) // Witnesses map trusted witness identifiers to public verification keys Witnesses map[[types.HashSize]byte][types.VerificationKeySize]byte @@ -102,7 +104,12 @@ func (i *Instance) leafRequestFromHTTP(r *http.Request) (*types.LeafRequest, err if !ed25519.Verify(vk, msg, sig) { return nil, fmt.Errorf("invalid signature") } - // TODO: check shard hint + if req.ShardHint < i.ShardStart { + return nil, fmt.Errorf("invalid shard hint: %d not in [%d, %d]", req.ShardHint, i.ShardStart, i.ShardEnd) + } + if req.ShardHint > i.ShardEnd { + return nil, fmt.Errorf("invalid shard hint: %d not in [%d, %d]", req.ShardHint, i.ShardStart, i.ShardEnd) + } // TODO: check domain hint return &req, nil } -- cgit v1.2.3