diff options
| -rw-r--r-- | instance.go | 11 | ||||
| -rw-r--r-- | instance_test.go | 4 | ||||
| -rw-r--r-- | log_parameters.go | 56 | ||||
| -rw-r--r-- | log_parameters_test.go | 7 | ||||
| -rw-r--r-- | request.go | 29 | ||||
| -rw-r--r-- | request_test.go | 4 | ||||
| -rw-r--r-- | 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 <base>/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 <base>/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)  		} @@ -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)  	} | 
