From e2959d506de6067afe494315c3621b33613b5414 Mon Sep 17 00:00:00 2001 From: Rasmus Dahlberg Date: Mon, 15 Mar 2021 20:18:29 +0100 Subject: added option to run with unregistered namespaces Also a few minor fixes such that server binary starts again. --- instance.go | 11 +++++++--- instance_test.go | 4 ++++ log_parameters.go | 56 ++++++++++++++++++++++++++++---------------------- log_parameters_test.go | 7 ++++--- request.go | 29 ++++++++++++++++++-------- request_test.go | 4 ++-- server/main.go | 24 ++++++++++++---------- 7 files changed, 83 insertions(+), 52 deletions(-) diff --git a/instance.go b/instance.go index 6f1314b..67336f8 100644 --- a/instance.go +++ b/instance.go @@ -41,16 +41,21 @@ type Handler struct { Handler func(context.Context, *Instance, http.ResponseWriter, *http.Request) (int, error) } +// Path returns a path that should be configured for this handler +func (h Handler) Path() string { + return h.Endpoint.Path("", h.Instance.LogParameters.Prefix) +} + // ServeHTTP is part of the http.Handler interface func (a Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { // export prometheus metrics var now time.Time = time.Now() var statusCode int defer func() { - rspcnt.Inc(string(a.Instance.LogParameters.LogIdBytes), string(a.Endpoint), fmt.Sprintf("%d", statusCode)) - latency.Observe(time.Now().Sub(now).Seconds(), string(a.Instance.LogParameters.LogIdBytes), string(a.Endpoint), fmt.Sprintf("%d", statusCode)) + rspcnt.Inc(a.Instance.LogParameters.LogIdStr, string(a.Endpoint), fmt.Sprintf("%d", statusCode)) + latency.Observe(time.Now().Sub(now).Seconds(), a.Instance.LogParameters.LogIdStr, string(a.Endpoint), fmt.Sprintf("%d", statusCode)) }() - reqcnt.Inc(string(a.Instance.LogParameters.LogIdBytes), string(a.Endpoint)) + reqcnt.Inc(a.Instance.LogParameters.LogIdStr, string(a.Endpoint)) ctx, cancel := context.WithDeadline(r.Context(), now.Add(a.Instance.LogParameters.Deadline)) defer cancel() diff --git a/instance_test.go b/instance_test.go index 21ef808..de539a1 100644 --- a/instance_test.go +++ b/instance_test.go @@ -153,3 +153,7 @@ func TestPostHandlersRejectGet(t *testing.T) { }) } } + +// TODO: TestHandlerPath +func TestHandlerPath(t *testing.T) { +} diff --git a/log_parameters.go b/log_parameters.go index 86ac0cc..9c23fa6 100644 --- a/log_parameters.go +++ b/log_parameters.go @@ -12,37 +12,43 @@ import ( // LogParameters is a collection of log parameters type LogParameters struct { - LogId *types.Namespace // log identifier - LogIdBytes []byte // serialized log id - TreeId int64 // used internally by Trillian - Prefix string // e.g., "test" for /test - MaxRange int64 // max entries per get-entries request - Submitters *types.NamespacePool // trusted submitters - Witnesses *types.NamespacePool // trusted witnesses - Deadline time.Duration // gRPC deadline - Interval time.Duration // cosigning sth frequency - HashType crypto.Hash // hash function used by Trillian - Signer crypto.Signer // access to Ed25519 private key + LogId *types.Namespace // log identifier + LogIdBytes []byte // serialized log id + LogIdStr string // serialized log id (hex) + TreeId int64 // used internally by Trillian + Prefix string // e.g., "test" for /test + MaxRange int64 // max entries per get-entries request + SubmitterPolicy bool // if we have a submitter policy (true means that namespaces must be registered) + WitnessPolicy bool // if we have a witness policy (true means that namespaces must be registered) + Submitters *types.NamespacePool // trusted submitters + Witnesses *types.NamespacePool // trusted witnesses + Deadline time.Duration // gRPC deadline + Interval time.Duration // cosigning sth frequency + HashType crypto.Hash // hash function used by Trillian + Signer crypto.Signer // access to Ed25519 private key } // NewLogParameters creates newly initialized log parameters -func NewLogParameters(signer crypto.Signer, logId *types.Namespace, treeId int64, prefix string, submitters, witnesses *types.NamespacePool, maxRange int64, interval, deadline time.Duration) (*LogParameters, error) { +func NewLogParameters(signer crypto.Signer, logId *types.Namespace, treeId int64, prefix string, submitters, witnesses *types.NamespacePool, maxRange int64, interval, deadline time.Duration, submitterPolicy, witnessPolicy bool) (*LogParameters, error) { logIdBytes, err := types.Marshal(*logId) if err != nil { return nil, fmt.Errorf("Marshal failed for log identifier: %v", err) } return &LogParameters{ - LogId: logId, - TreeId: treeId, - Prefix: prefix, - MaxRange: maxRange, - Submitters: submitters, - Witnesses: witnesses, - Deadline: deadline, - Interval: interval, - HashType: crypto.SHA256, - Signer: signer, - LogIdBytes: logIdBytes, + LogId: logId, + LogIdBytes: logIdBytes, + LogIdStr: fmt.Sprintf("%x", logIdBytes), + TreeId: treeId, + Prefix: prefix, + MaxRange: maxRange, + SubmitterPolicy: submitterPolicy, + WitnessPolicy: witnessPolicy, + Submitters: submitters, + Witnesses: witnesses, + Deadline: deadline, + Interval: interval, + HashType: crypto.SHA256, + Signer: signer, }, nil } @@ -56,8 +62,8 @@ func (lp *LogParameters) SignTreeHeadV1(th *types.TreeHeadV1) (*types.StItem, er if err != nil { return nil, fmt.Errorf("Sign failed: %v", err) } - lastSthTimestamp.Set(float64(time.Now().Unix()), string(lp.LogIdBytes)) - lastSthSize.Set(float64(th.TreeSize), string(lp.LogIdBytes)) + lastSthTimestamp.Set(float64(time.Now().Unix()), lp.LogIdStr) + lastSthSize.Set(float64(th.TreeSize), lp.LogIdStr) return &types.StItem{ Format: types.StFormatSignedTreeHeadV1, SignedTreeHeadV1: &types.SignedTreeHeadV1{ diff --git a/log_parameters_test.go b/log_parameters_test.go index cec7674..88e83ad 100644 --- a/log_parameters_test.go +++ b/log_parameters_test.go @@ -15,7 +15,8 @@ import ( // based on the parameters in "github.com/system-transparency/stfe/testdata". // The log's namespace is initialized with testdata.LogEd25519Vk, the submmiter // namespace list is initialized with testdata.SubmmiterEd25519, and the witness -// namespace list is initialized with testdata.WitnessEd25519Vk. +// namespace list is initialized with testdata.WitnessEd25519Vk. The log's +// submitter and witness policies are set to reject unregistered namespace. func newLogParameters(t *testing.T, signer crypto.Signer) *LogParameters { t.Helper() logId := testdata.NewNamespace(t, testdata.Ed25519VkLog) @@ -25,7 +26,7 @@ func newLogParameters(t *testing.T, signer crypto.Signer) *LogParameters { submitPool := testdata.NewNamespacePool(t, []*types.Namespace{ testdata.NewNamespace(t, testdata.Ed25519VkSubmitter), }) - lp, err := NewLogParameters(signer, logId, testdata.TreeId, testdata.Prefix, submitPool, witnessPool, testdata.MaxRange, testdata.Interval, testdata.Deadline) + lp, err := NewLogParameters(signer, logId, testdata.TreeId, testdata.Prefix, submitPool, witnessPool, testdata.MaxRange, testdata.Interval, testdata.Deadline, true, true) if err != nil { t.Fatalf("must create new log parameters: %v", err) } @@ -50,7 +51,7 @@ func TestNewLogParameters(t *testing.T) { logId: testdata.NewNamespace(t, testdata.Ed25519VkLog), }, } { - _, err := NewLogParameters(nil, table.logId, testdata.TreeId, testdata.Prefix, nil, nil, testdata.MaxRange, testdata.Interval, testdata.Deadline) + _, err := NewLogParameters(nil, table.logId, testdata.TreeId, testdata.Prefix, nil, nil, testdata.MaxRange, testdata.Interval, testdata.Deadline, true, true) if got, want := err != nil, table.wantErr; got != want { t.Errorf("got error %v but wanted %v in test %q: %v", got, want, table.description, err) } diff --git a/request.go b/request.go index 5bee672..7c95f34 100644 --- a/request.go +++ b/request.go @@ -19,9 +19,15 @@ func (lp *LogParameters) parseAddEntryV1Request(r *http.Request) (*types.StItem, } // Check that submitter namespace is valid - if namespace, ok := lp.Submitters.Find(&item.SignedChecksumV1.Signature.Namespace); !ok { - return nil, fmt.Errorf("unknown namespace: %v", item.SignedChecksumV1.Signature.Namespace) - } else if msg, err := types.Marshal(item.SignedChecksumV1.Data); err != nil { + namespace := &item.SignedChecksumV1.Signature.Namespace + if lp.SubmitterPolicy { + var ok bool + if namespace, ok = lp.Submitters.Find(namespace); !ok { + return nil, fmt.Errorf("unknown submitter namespace: %v", namespace) + } + } + // Check that namespace signed add-entry request + if msg, err := types.Marshal(item.SignedChecksumV1.Data); err != nil { return nil, fmt.Errorf("Marshal: %v", err) // should never happen } else if err := namespace.Verify(msg, item.SignedChecksumV1.Signature.Signature); err != nil { return nil, fmt.Errorf("Verify: %v", err) @@ -37,13 +43,20 @@ func (lp *LogParameters) parseAddCosignatureV1Request(r *http.Request) (*types.S if item.Format != types.StFormatCosignedTreeHeadV1 { return nil, fmt.Errorf("invalid StItem format: %v", item.Format) } - - // Check that witness namespace is valid if got, want := len(item.CosignedTreeHeadV1.Cosignatures), 1; got != want { return nil, fmt.Errorf("invalid number of cosignatures: %d", got) - } else if namespace, ok := lp.Witnesses.Find(&item.CosignedTreeHeadV1.Cosignatures[0].Namespace); !ok { - return nil, fmt.Errorf("unknown witness: %v", item.CosignedTreeHeadV1.Cosignatures[0].Namespace) - } else if msg, err := types.Marshal(*types.NewSignedTreeHeadV1(&item.CosignedTreeHeadV1.SignedTreeHead.TreeHead, &item.CosignedTreeHeadV1.SignedTreeHead.Signature).SignedTreeHeadV1); err != nil { + } + + // Check that witness namespace is valid + namespace := &item.CosignedTreeHeadV1.Cosignatures[0].Namespace + if lp.WitnessPolicy { + var ok bool + if namespace, ok = lp.Witnesses.Find(namespace); !ok { + return nil, fmt.Errorf("unknown witness namespace: %v", namespace) + } + } + // Check that namespace signed add-cosignature request + if msg, err := types.Marshal(*types.NewSignedTreeHeadV1(&item.CosignedTreeHeadV1.SignedTreeHead.TreeHead, &item.CosignedTreeHeadV1.SignedTreeHead.Signature).SignedTreeHeadV1); err != nil { return nil, fmt.Errorf("Marshal: %v", err) // should never happen } else if err := namespace.Verify(msg, item.CosignedTreeHeadV1.Cosignatures[0].Signature); err != nil { return nil, fmt.Errorf("Verify: %v", err) diff --git a/request_test.go b/request_test.go index b0e5da1..0bf68ad 100644 --- a/request_test.go +++ b/request_test.go @@ -45,7 +45,7 @@ func TestParseAddEntryV1Request(t *testing.T) { { description: "valid", breq: testdata.AddSignedChecksumBuffer(t, testdata.Ed25519SkSubmitter, testdata.Ed25519VkSubmitter), - }, + }, // TODO: add test case that disables submitter policy (i.e., unregistered namespaces are accepted) } { url := EndpointAddEntry.Path("http://example.com", lp.Prefix) req, err := http.NewRequest("POST", url, table.breq) @@ -96,7 +96,7 @@ func TestParseAddCosignatureV1Request(t *testing.T) { { description: "valid", breq: testdata.AddCosignatureBuffer(t, testdata.DefaultSth(t, testdata.Ed25519VkLog), &testdata.Ed25519SkWitness, &testdata.Ed25519VkWitness), - }, + }, // TODO: add test case that disables witness policy (i.e., unregistered namespaces are accepted) } { url := EndpointAddCosignature.Path("http://example.com", lp.Prefix) req, err := http.NewRequest("POST", url, table.breq) diff --git a/server/main.go b/server/main.go index a00758e..d45079b 100644 --- a/server/main.go +++ b/server/main.go @@ -25,16 +25,18 @@ import ( ) var ( - httpEndpoint = flag.String("http_endpoint", "localhost:6965", "host:port specification of where stfe serves clients") - rpcBackend = flag.String("log_rpc_server", "localhost:6962", "host:port specification of where Trillian serves clients") - prefix = flag.String("prefix", "st/v1", "a prefix that proceeds each endpoint path") - trillianID = flag.Int64("trillian_id", 5991359069696313945, "log identifier in the Trillian database") - deadline = flag.Duration("deadline", time.Second*10, "deadline for backend requests") - key = flag.String("key", "8gzezwrU/2eTrO6tEYyLKsoqn5V54URvKIL9cTE7jUYUqXVX4neJvcBq/zpSAYPsZFG1woh0OGBzQbi9UP9MZw==", "base64-encoded Ed25519 signing key") - submitters = flag.String("submitters", "AAEgHOQFUkKNWpjYAhNKTyWCzahlI7RDtf5123kHD2LACj0=,AAEgLqrWb9JwQUTk/SwTNDdMH8aRmy3mbmhwEepO5WSgb+A=", "comma-separated list of trusted submitter namespaces in base64 (default: testdata.Ed25519{Vk,Vk2})") // TODO: update to valid submitter namespaces - witnesses = flag.String("witnesses", "", "comma-separated list of trusted submitter namespaces in base64 (default: none") // TODO: update to valid witness namespaces - maxRange = flag.Int64("max_range", 2, "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") + httpEndpoint = flag.String("http_endpoint", "localhost:6965", "host:port specification of where stfe serves clients") + rpcBackend = flag.String("log_rpc_server", "localhost:6962", "host:port specification of where Trillian serves clients") + prefix = flag.String("prefix", "st/v1", "a prefix that proceeds each endpoint path") + trillianID = flag.Int64("trillian_id", 5991359069696313945, "log identifier in the Trillian database") + deadline = flag.Duration("deadline", time.Second*10, "deadline for backend requests") + key = flag.String("key", "8gzezwrU/2eTrO6tEYyLKsoqn5V54URvKIL9cTE7jUYUqXVX4neJvcBq/zpSAYPsZFG1woh0OGBzQbi9UP9MZw==", "base64-encoded Ed25519 signing key") + submitterPolicy = flag.Bool("submitter_policy", false, "whether there is any submitter namespace policy (default: none, accept unregistered submitter namespaces)") + witnessPolicy = flag.Bool("witness_policy", false, "whether there is any witness namespace policy (default: none, accept unregistered witness namespaces)") + submitters = flag.String("submitters", "", "comma-separated list of trusted submitter namespaces in base64 (default: none)") + witnesses = flag.String("witnesses", "", "comma-separated list of trusted submitter namespaces in base64 (default: none)") + maxRange = flag.Int64("max_range", 2, "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") ) func main() { @@ -118,7 +120,7 @@ func setupInstanceFromFlags() (*stfe.Instance, error) { return nil, fmt.Errorf("NewNamespaceEd25519V1: %v", err) } // Setup log parameters - lp, err := stfe.NewLogParameters(signer, logId, *trillianID, *prefix, submitters, witnesses, *maxRange, *interval, *deadline) + lp, err := stfe.NewLogParameters(signer, logId, *trillianID, *prefix, submitters, witnesses, *maxRange, *interval, *deadline, *submitterPolicy, *witnessPolicy) if err != nil { return nil, fmt.Errorf("NewLogParameters: %v", err) } -- cgit v1.2.3