aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRasmus Dahlberg <rasmus.dahlberg@kau.se>2021-06-06 15:59:35 +0200
committerRasmus Dahlberg <rasmus.dahlberg@kau.se>2021-06-06 15:59:35 +0200
commit47bacfd5c5d22470340e0823c4ad37b45914b68e (patch)
tree0984b55ced1e537e8d1d681c77157f1a47e47cdc
parent0285454c34b0b3003bc8ede3e304b843ad949be8 (diff)
started using the refactored packages in siglog server
-rw-r--r--client/client.go242
-rw-r--r--client/cmd/add-entry/main.go52
-rwxr-xr-xclient/cmd/example.sh49
-rw-r--r--client/cmd/get-consistency-proof/main.go70
-rw-r--r--client/cmd/get-entries/main.go83
-rw-r--r--client/cmd/get-proof-by-hash/main.go66
-rw-r--r--client/cmd/get-sth/main.go35
-rw-r--r--client/flag.go55
-rw-r--r--client/verify.go52
-rw-r--r--cmd/siglog_server/.gitignore (renamed from server/.gitignore)0
-rw-r--r--cmd/siglog_server/README.md (renamed from server/README.md)0
-rw-r--r--cmd/siglog_server/main.go (renamed from server/main.go)91
-rw-r--r--cmd/tmp/README.md2
-rw-r--r--cmd/tmp/cosign/main.go (renamed from client/cmd/cosign/main.go)2
-rw-r--r--cmd/tmp/keygen/main.go (renamed from client/cmd/keygen/main.go)0
-rw-r--r--cmd/tmp/submit/main.go (renamed from client/cmd/submit/main.go)3
-rw-r--r--doc.go3
-rw-r--r--endpoint.go163
-rw-r--r--go.sum3
-rw-r--r--instance.go75
-rw-r--r--log_parameters.go47
-rw-r--r--log_parameters_test.go99
-rw-r--r--pkg/instance/endpoint.go122
-rw-r--r--pkg/instance/endpoint_test.go (renamed from endpoint_test.go)9
-rw-r--r--pkg/instance/instance.go90
-rw-r--r--pkg/instance/instance_test.go (renamed from instance_test.go)7
-rw-r--r--pkg/instance/metric.go (renamed from metric.go)0
-rw-r--r--pkg/instance/request.go (renamed from request.go)36
-rw-r--r--pkg/instance/request_test.go (renamed from request_test.go)4
-rw-r--r--pkg/mocks/crypto.go (renamed from mocks/crypto.go)0
-rw-r--r--pkg/mocks/stfe.go (renamed from mocks/stfe.go)2
-rw-r--r--pkg/mocks/trillian.go (renamed from mocks/trillian.go)0
-rw-r--r--pkg/state/state_manager.go (renamed from state/state_manager.go)6
-rw-r--r--pkg/state/state_manager_test.go (renamed from state/state_manager_test.go)6
-rw-r--r--pkg/trillian/client.go (renamed from trillian/client.go)2
-rw-r--r--pkg/trillian/client_test.go (renamed from trillian/client_test.go)4
-rw-r--r--pkg/trillian/util.go (renamed from trillian/util.go)2
-rw-r--r--pkg/types/ascii.go (renamed from types/ascii.go)0
-rw-r--r--pkg/types/ascii_test.go (renamed from types/ascii_test.go)0
-rw-r--r--pkg/types/trunnel.go (renamed from types/trunnel.go)0
-rw-r--r--pkg/types/trunnel_test.go (renamed from types/trunnel_test.go)0
-rw-r--r--pkg/types/types.go (renamed from types/types.go)0
-rw-r--r--pkg/types/types_test.go (renamed from types/types_test.go)0
-rw-r--r--pkg/types/util.go (renamed from types/util.go)0
-rw-r--r--sth.go143
-rw-r--r--sth_test.go466
-rw-r--r--testdata/data.go287
-rw-r--r--trillian.go125
-rw-r--r--trillian_test.go282
-rw-r--r--util.go27
-rw-r--r--util_test.go17
51 files changed, 307 insertions, 2522 deletions
diff --git a/client/client.go b/client/client.go
deleted file mode 100644
index ba81f4d..0000000
--- a/client/client.go
+++ /dev/null
@@ -1,242 +0,0 @@
-package client
-
-import (
- "bytes"
- "context"
- "crypto"
- "fmt"
-
- "io/ioutil"
- "net/http"
-
- "github.com/golang/glog"
- "github.com/google/trillian/merkle/rfc6962"
- "github.com/system-transparency/stfe"
- "github.com/system-transparency/stfe/types"
- "golang.org/x/net/context/ctxhttp"
-)
-
-// Descriptor is a log descriptor
-type Descriptor struct {
- Namespace *types.Namespace // log identifier is a namespace
- Url string // log url, e.g., http://example.com/st/v1
-}
-
-// Client is a log client
-type Client struct {
- HttpClient *http.Client
- Signer crypto.Signer // client's private identity
- Namespace *types.Namespace // client's public identity
- Log *Descriptor // log's public identity
-}
-
-// GetLatestSth fetches and verifies the signature of the most recent STH.
-// Outputs the resulting STH.
-func (c *Client) GetLatestSth(ctx context.Context) (*types.StItem, error) {
- url := stfe.EndpointGetLatestSth.Path(c.Log.Url)
- req, err := http.NewRequest("GET", url, nil)
- if err != nil {
- return nil, fmt.Errorf("failed creating http request: %v", err)
- }
- glog.V(3).Infof("created http request: %s %s", req.Method, req.URL)
-
- item, err := c.doRequestWithStItemResponse(ctx, req)
- if err != nil {
- return nil, err
- }
- if got, want := item.Format, types.StFormatSignedTreeHeadV1; got != want {
- return nil, fmt.Errorf("unexpected StItem format: %v", got)
- }
- if err := VerifySignedTreeHeadV1(c.Log.Namespace, item); err != nil {
- return nil, fmt.Errorf("signature verification failed: %v", err)
- }
- glog.V(3).Infof("verified sth")
- return item, nil
-}
-
-// GetProofByHash fetches and verifies an inclusion proof for a leaf hash
-// against an STH. Outputs the resulting proof.
-func (c *Client) GetProofByHash(ctx context.Context, leafHash []byte, sth *types.StItem) (*types.StItem, error) {
- if err := VerifySignedTreeHeadV1(c.Log.Namespace, sth); err != nil {
- return nil, fmt.Errorf("invalid sth: %v", err)
- }
- glog.V(3).Infof("verified sth")
- params := types.GetProofByHashV1{
- TreeSize: sth.SignedTreeHeadV1.TreeHead.TreeSize,
- }
- copy(params.Hash[:], leafHash)
- buf, err := types.Marshal(params)
- if err != nil {
- return nil, fmt.Errorf("req: Marshal: %v", err)
- }
-
- url := stfe.EndpointGetProofByHash.Path(c.Log.Url)
- req, err := http.NewRequest("POST", url, bytes.NewBuffer(buf))
- if err != nil {
- return nil, fmt.Errorf("failed creating http request: %v", err)
- }
- req.Header.Set("Content-Type", "application/octet-stream")
- glog.V(3).Infof("created http request: %s %s", req.Method, req.URL)
-
- item, err := c.doRequestWithStItemResponse(ctx, req)
- if err != nil {
- return nil, fmt.Errorf("doRequestWithStItemResponse: %v", err)
- }
- if got, want := item.Format, types.StFormatInclusionProofV1; got != want {
- return nil, fmt.Errorf("unexpected StItem format: %v", item.Format)
- }
- if err := VerifyInclusionProofV1(item, sth, params.Hash[:]); err != nil {
- return nil, fmt.Errorf("invalid inclusion proof: %v", err)
- }
- glog.V(3).Infof("verified inclusion proof")
- return item, nil
-}
-
-// GetConsistencyProof fetches and verifies a consistency proof betweeen two
-// STHs. Outputs the resulting proof.
-func (c *Client) GetConsistencyProof(ctx context.Context, sth1, sth2 *types.StItem) (*types.StItem, error) {
- if err := VerifySignedTreeHeadV1(c.Log.Namespace, sth1); err != nil {
- return nil, fmt.Errorf("invalid first sth: %v", err)
- }
- if err := VerifySignedTreeHeadV1(c.Log.Namespace, sth2); err != nil {
- return nil, fmt.Errorf("invalid second sth: %v", err)
- }
- glog.V(3).Infof("verified sths")
- buf, err := types.Marshal(types.GetConsistencyProofV1{
- First: sth1.SignedTreeHeadV1.TreeHead.TreeSize,
- Second: sth2.SignedTreeHeadV1.TreeHead.TreeSize,
- })
- if err != nil {
- return nil, fmt.Errorf("req: Marshal: %v", err)
- }
-
- url := stfe.EndpointGetConsistencyProof.Path(c.Log.Url)
- req, err := http.NewRequest("POST", url, bytes.NewBuffer(buf))
- if err != nil {
- return nil, fmt.Errorf("failed creating http request: %v", err)
- }
- req.Header.Set("Content-Type", "application/octet-stream")
- glog.V(3).Infof("created http request: %s %s", req.Method, req.URL)
-
- item, err := c.doRequestWithStItemResponse(ctx, req)
- if err != nil {
- return nil, fmt.Errorf("doRequestWithStItemResponse: %v", err)
- }
- if got, want := item.Format, types.StFormatConsistencyProofV1; got != want {
- return nil, fmt.Errorf("unexpected StItem format: %v", item.Format)
- }
- if err := VerifyConsistencyProofV1(item, sth1, sth2); err != nil {
- return nil, fmt.Errorf("invalid inclusion proof: %v", err)
- }
- glog.V(3).Infof("verified inclusion proof")
- return item, nil
-}
-
-// AddEntry signs and submits a checksum_v1 entry to the log. Outputs the
-// resulting leaf-hash on success.
-func (c *Client) AddEntry(ctx context.Context, data *types.ChecksumV1) ([]byte, error) {
- msg, err := types.Marshal(*data)
- if err != nil {
- return nil, fmt.Errorf("failed marshaling ChecksumV1: %v", err)
- }
- sig, err := c.Signer.Sign(nil, msg, crypto.Hash(0))
- if err != nil {
- return nil, fmt.Errorf("failed signing ChecksumV1: %v", err)
- }
- leaf, err := types.Marshal(*types.NewSignedChecksumV1(data, &types.SignatureV1{
- Namespace: *c.Namespace,
- Signature: sig,
- }))
- if err != nil {
- return nil, fmt.Errorf("failed marshaling SignedChecksumV1: %v", err)
- }
- glog.V(3).Infof("signed checksum entry for identifier %q", string(data.Identifier))
-
- url := stfe.EndpointAddEntry.Path(c.Log.Url)
- req, err := http.NewRequest("POST", url, bytes.NewBuffer(leaf))
- if err != nil {
- return nil, fmt.Errorf("failed creating http request: %v", err)
- }
- req.Header.Set("Content-Type", "application/octet-stream")
- glog.V(3).Infof("created http request: %s %s", req.Method, req.URL)
-
- if rsp, err := c.doRequest(ctx, req); err != nil {
- return nil, fmt.Errorf("doRequest: %v", err)
- } else if len(rsp) != 0 {
- return nil, fmt.Errorf("extra data: %v", err)
- }
- glog.V(3).Infof("add-entry succeded")
- return rfc6962.DefaultHasher.HashLeaf(leaf), nil
-}
-
-// GetEntries fetches a range of entries from the log, verifying that they are
-// of type signed_checksum_v1 but nothing more than that. Outputs the resulting
-// range that may be truncated by the log if [start,end] is too large.
-func (c *Client) GetEntries(ctx context.Context, start, end uint64) ([]*types.StItem, error) {
- buf, err := types.Marshal(types.GetEntriesV1{
- Start: start,
- End: end,
- })
- if err != nil {
- return nil, fmt.Errorf("Marshal: %v", err)
- }
- url := stfe.EndpointGetEntries.Path(c.Log.Url)
- req, err := http.NewRequest("POST", url, bytes.NewBuffer(buf))
- if err != nil {
- return nil, fmt.Errorf("failed creating http request: %v", err)
- }
- req.Header.Set("Content-Type", "application/octet-stream")
- glog.V(3).Infof("created http request: %s %s", req.Method, req.URL)
- glog.V(3).Infof("request data: start(%d), end(%d)", start, end)
-
- body, err := c.doRequest(ctx, req)
- if err != nil {
- return nil, fmt.Errorf("doRequest: %v", err)
- }
- var list types.StItemList
- if err := types.Unmarshal(body, &list); err != nil {
- return nil, fmt.Errorf("Unmarshal: %v", err)
- }
- ret := make([]*types.StItem, 0, len(list.Items))
- for i, _ := range list.Items {
- item := list.Items[i]
- if got, want := item.Format, types.StFormatSignedChecksumV1; got != want {
- return nil, fmt.Errorf("unexpected StItem format: %v", got)
- }
- ret = append(ret, &item)
- }
- return ret, nil
-}
-
-// doRequest sends an HTTP request and outputs the raw body
-func (c *Client) doRequest(ctx context.Context, req *http.Request) ([]byte, error) {
- rsp, err := ctxhttp.Do(ctx, c.HttpClient, req)
- if err != nil {
- return nil, fmt.Errorf("no response: %v", err)
- }
- defer rsp.Body.Close()
- if got, want := rsp.StatusCode, http.StatusOK; got != want {
- return nil, fmt.Errorf("bad http status: %v", got)
- }
- body, err := ioutil.ReadAll(rsp.Body)
- if err != nil {
- return nil, fmt.Errorf("cannot read body: %v", err)
- }
- return body, nil
-}
-
-//
-// doRequestWithStItemResponse sends an HTTP request and returns a decoded
-// StItem that the resulting HTTP response contained json:ed and marshaled
-func (c *Client) doRequestWithStItemResponse(ctx context.Context, req *http.Request) (*types.StItem, error) {
- body, err := c.doRequest(ctx, req)
- if err != nil {
- return nil, err
- }
- var item types.StItem
- if err := types.Unmarshal(body, &item); err != nil {
- return nil, fmt.Errorf("failed decoding StItem: %v", err)
- }
- glog.V(9).Infof("got StItem: %v", item)
- return &item, nil
-}
diff --git a/client/cmd/add-entry/main.go b/client/cmd/add-entry/main.go
deleted file mode 100644
index a29d01f..0000000
--- a/client/cmd/add-entry/main.go
+++ /dev/null
@@ -1,52 +0,0 @@
-package main
-
-import (
- "context"
- "flag"
- "fmt"
-
- "encoding/base64"
-
- "github.com/golang/glog"
- "github.com/system-transparency/stfe/client"
- "github.com/system-transparency/stfe/types"
-)
-
-var (
- identifier = flag.String("identifier", "", "checksum identifier")
- checksum = flag.String("checksum", "", "base64-encoded checksum")
-)
-
-func main() {
- flag.Parse()
- defer glog.Flush()
-
- client, err := client.NewClientFromFlags()
- if err != nil {
- glog.Errorf("NewClientFromFlags: %v", err)
- return
- }
- data, err := NewChecksumV1FromFlags()
- if err != nil {
- glog.Errorf("NewChecksumV1FromFlags: %v", err)
- return
- }
- leafHash, err := client.AddEntry(context.Background(), data)
- if err != nil {
- glog.Errorf("AddEntry: %v", err)
- return
- }
- fmt.Println("leaf hash:", base64.StdEncoding.EncodeToString(leafHash))
-}
-
-func NewChecksumV1FromFlags() (*types.ChecksumV1, error) {
- var err error
- data := types.ChecksumV1{
- Identifier: []byte(*identifier),
- }
- data.Checksum, err = base64.StdEncoding.DecodeString(*checksum)
- if err != nil {
- return nil, fmt.Errorf("entry_checksum: DecodeString: %v", err)
- }
- return &data, nil
-}
diff --git a/client/cmd/example.sh b/client/cmd/example.sh
deleted file mode 100755
index d790712..0000000
--- a/client/cmd/example.sh
+++ /dev/null
@@ -1,49 +0,0 @@
-#!/bin/bash
-set -eu
-
-log_url=http://tlog-poc.system-transparency.org:4780/st/v1
-log_id=AAG+ZW+UesWdMFytUGkp28csBcziomSB3U2vvkAW55MVZQ==
-tmpdir=$(mktemp -dt stfe.XXXXXXXX)
-cp $0 $tmpdir/
-cd $tmpdir
-
-commonargs="--log_id $log_id --log_url $log_url" # --logtostderr -v 3
-pause="sleep 1"
-
-echo "arguments used:"
-echo $commonargs
-echo ""
-
-echo "fetching sth..."
-get-sth $commonargs | tee sth1.output
-echo "" && $pause
-
-echo "adding an entry..."
-add-entry $commonargs \
- --identifier "example.sh v0.0.1-$(cat /dev/urandom | base64 | head -c 10)" \
- --checksum $(sha256sum "$0") | tee add-entry.output
-echo "" && $pause
-
-echo "fetching another sth..."
-get-sth $commonargs | tee sth2.output
-echo "" && $pause
-
-echo "verifying inclusion..."
-get-proof-by-hash $commonargs \
- --leaf_hash $(cat add-entry.output | awk '{print $3}') \
- --sth $(cat sth2.output | awk '{print $2}')
-echo "" && $pause
-
-echo "verifying consistency..."
-get-consistency-proof $commonargs \
- --first $(cat sth1.output | awk '{print $2}') \
- --second $(cat sth2.output | awk '{print $2}')
-echo "" && $pause
-
-echo "fetching the log's first entry..."
-get-entries $commonargs --start 0 --end 0
-echo ""
-
-rm *.output $0
-cd
-rmdir $tmpdir
diff --git a/client/cmd/get-consistency-proof/main.go b/client/cmd/get-consistency-proof/main.go
deleted file mode 100644
index bb8a7a6..0000000
--- a/client/cmd/get-consistency-proof/main.go
+++ /dev/null
@@ -1,70 +0,0 @@
-package main
-
-import (
- "context"
- "flag"
- "fmt"
-
- "encoding/base64"
-
- "github.com/golang/glog"
- "github.com/system-transparency/stfe/client"
- "github.com/system-transparency/stfe/types"
-)
-
-var (
- first = flag.String("first", "", "base64-encoded sth")
- second = flag.String("second", "", "base64-encoded sth")
-)
-
-func main() {
- flag.Parse()
- defer glog.Flush()
-
- client, err := client.NewClientFromFlags()
- if err != nil {
- glog.Errorf("NewClientFromFlags: %v", err)
- return
- }
- sth1, sth2, err := newParamsFromFlags()
- if err != nil {
- glog.Errorf("NewRequestFromFlags: %v", err)
- return
- }
-
- proof, err := client.GetConsistencyProof(context.Background(), sth1, sth2)
- if err != nil {
- glog.Errorf("GetConsistencyProof: %v", err)
- return
- }
- serialized, err := types.Marshal(*proof)
- if err != nil {
- glog.Errorf("Marshal: %v", err)
- return
- }
- fmt.Println("proof:", base64.StdEncoding.EncodeToString(serialized))
-}
-
-func newParamsFromFlags() (*types.StItem, *types.StItem, error) {
- sth1, err := decodeSthStr(*first)
- if err != nil {
- return nil, nil, fmt.Errorf("first: decodeSthStr: %v", err)
- }
- sth2, err := decodeSthStr(*second)
- if err != nil {
- return nil, nil, fmt.Errorf("second: decodeSthStr: %v", err)
- }
- return sth1, sth2, nil
-}
-
-func decodeSthStr(sthStr string) (*types.StItem, error) {
- serialized, err := base64.StdEncoding.DecodeString(sthStr)
- if err != nil {
- return nil, fmt.Errorf("DecodeString: %v", err)
- }
- var item types.StItem
- if err = types.Unmarshal(serialized, &item); err != nil {
- return nil, fmt.Errorf("Unmarshal: %v", err)
- }
- return &item, nil
-}
diff --git a/client/cmd/get-entries/main.go b/client/cmd/get-entries/main.go
deleted file mode 100644
index f32fdbf..0000000
--- a/client/cmd/get-entries/main.go
+++ /dev/null
@@ -1,83 +0,0 @@
-package main
-
-import (
- "context"
- "flag"
- "fmt"
-
- "encoding/base64"
-
- "github.com/golang/glog"
- "github.com/google/trillian/merkle/rfc6962"
- "github.com/system-transparency/stfe/client"
- "github.com/system-transparency/stfe/types"
-)
-
-var (
- start = flag.Uint64("start", 0, "inclusive start index to download")
- end = flag.Uint64("end", 0, "inclusive stop index to download")
-)
-
-func main() {
- flag.Parse()
- defer glog.Flush()
-
- client, err := client.NewClientFromFlags()
- if err != nil {
- glog.Errorf("NewClientFromFlags: %v", err)
- return
- }
- items, err := getRange(client, *start, *end)
- if err != nil {
- glog.Errorf("getRange: %v", err)
- return
- }
- if err := printRange(items); err != nil {
- glog.Errorf("printRange: %v", err)
- return
- }
-}
-
-func getRange(client *client.Client, start, end uint64) ([]*types.StItem, error) {
- items := make([]*types.StItem, 0, end-start+1)
- for len(items) != cap(items) {
- rsp, err := client.GetEntries(context.Background(), start, end)
- if err != nil {
- return nil, fmt.Errorf("fetching entries failed: %v", err)
- }
- items = append(items, rsp...)
- start += uint64(len(rsp))
- }
- return items, nil
-}
-
-func printRange(items []*types.StItem) error {
- for i, item := range items {
- var status string
- msg, err := types.Marshal(item.SignedChecksumV1.Data)
- if err != nil {
- return fmt.Errorf("Marshal data failed: %v", err)
- }
- sig := item.SignedChecksumV1.Signature.Signature
- namespace := &item.SignedChecksumV1.Signature.Namespace
- if err := namespace.Verify(msg, sig); err != nil {
- status = "unverified signature"
- } else {
- status = "verified signature"
- }
- serializedNamespace, err := types.Marshal(*namespace)
- if err != nil {
- return fmt.Errorf("Marshal namespace failed: %v", err)
- }
- serializedLeaf, err := types.Marshal(*item)
- if err != nil {
- return fmt.Errorf("Marshal item on index %d: %v", *start+uint64(i), err)
- }
- fmt.Printf("Index(%d) - %s\n", *start+uint64(i), status)
- fmt.Printf("-> Namespace: %s\n", base64.StdEncoding.EncodeToString(serializedNamespace))
- fmt.Printf("-> Identifier: %s\n", string(item.SignedChecksumV1.Data.Identifier))
- fmt.Printf("-> Checksum: %s\n", base64.StdEncoding.EncodeToString(item.SignedChecksumV1.Data.Checksum))
- fmt.Printf("-> Leaf hash: %s\n", base64.StdEncoding.EncodeToString(rfc6962.DefaultHasher.HashLeaf(serializedLeaf)))
- }
- return nil
-}
diff --git a/client/cmd/get-proof-by-hash/main.go b/client/cmd/get-proof-by-hash/main.go
deleted file mode 100644
index 1f4f304..0000000
--- a/client/cmd/get-proof-by-hash/main.go
+++ /dev/null
@@ -1,66 +0,0 @@
-package main
-
-import (
- "context"
- "flag"
- "fmt"
-
- "encoding/base64"
-
- "github.com/golang/glog"
- "github.com/system-transparency/stfe/client"
- "github.com/system-transparency/stfe/types"
-)
-
-var (
- sthStr = flag.String("sth", "", "base64-encoded StItem of type StFormatSignedTreeHeadV1 (default: fetch new sth)")
- leafHashStr = flag.String("leaf_hash", "", "base64-encoded leaf hash")
-)
-
-func main() {
- flag.Parse()
- defer glog.Flush()
-
- client, err := client.NewClientFromFlags()
- if err != nil {
- glog.Errorf("NewClientFromFlags: %v", err)
- return
- }
- leafHash, sth, err := newParamsFromFlags(client)
- if err != nil {
- glog.Errorf("NewRequestFromFlags: %v", err)
- return
- }
-
- proof, err := client.GetProofByHash(context.Background(), leafHash, sth)
- if err != nil {
- glog.Errorf("GetProofByHash: %v", err)
- return
- }
- serialized, err := types.Marshal(*proof)
- if err != nil {
- glog.Errorf("Marshal: %v", err)
- }
- fmt.Println("proof:", base64.StdEncoding.EncodeToString(serialized))
-}
-
-func newParamsFromFlags(client *client.Client) ([]byte, *types.StItem, error) {
- serialized, err := base64.StdEncoding.DecodeString(*sthStr)
- if err != nil {
- return nil, nil, fmt.Errorf("sth: DecodeString: %v", err)
- }
- var item types.StItem
- if err = types.Unmarshal(serialized, &item); err != nil {
- return nil, nil, fmt.Errorf("sth: Unmarshal: %v", err)
- } else if got, want := item.Format, types.StFormatSignedTreeHeadV1; got != want {
- return nil, nil, fmt.Errorf("unexpected StItem format: %v", got)
- }
- leafHash, err := base64.StdEncoding.DecodeString(*leafHashStr)
- if err != nil {
- return nil, nil, fmt.Errorf("leaf_hash: DecodeString: %v", err)
- } else if got, want := len(leafHash), 32; got != want {
- return nil, nil, fmt.Errorf("leaf_hash: unexpected size: %v", got)
- }
- glog.V(3).Infof("created request parameters TreeSize(%d) and LeafHash(%s)", item.SignedTreeHeadV1.TreeHead.TreeSize, *leafHashStr)
- return leafHash, &item, nil
-}
diff --git a/client/cmd/get-sth/main.go b/client/cmd/get-sth/main.go
deleted file mode 100644
index 6b23b06..0000000
--- a/client/cmd/get-sth/main.go
+++ /dev/null
@@ -1,35 +0,0 @@
-package main
-
-import (
- "context"
- "flag"
- "fmt"
-
- "encoding/base64"
-
- "github.com/golang/glog"
- "github.com/system-transparency/stfe/client"
- "github.com/system-transparency/stfe/types"
-)
-
-func main() {
- flag.Parse()
- defer glog.Flush()
-
- client, err := client.NewClientFromFlags()
- if err != nil {
- glog.Errorf("NewClientFromFlags: %v", err)
- return
- }
- sth, err := client.GetLatestSth(context.Background())
- if err != nil {
- glog.Errorf("GetLatestSth: %v", err)
- return
- }
- serialized, err := types.Marshal(*sth)
- if err != nil {
- glog.Errorf("Marshal: %v", err)
- return
- }
- fmt.Println("sth:", base64.StdEncoding.EncodeToString(serialized))
-}
diff --git a/client/flag.go b/client/flag.go
deleted file mode 100644
index 8ba7a10..0000000
--- a/client/flag.go
+++ /dev/null
@@ -1,55 +0,0 @@
-package client
-
-import (
- "flag"
- "fmt"
-
- "crypto/ed25519"
- "encoding/base64"
- "net/http"
-
- "github.com/system-transparency/stfe/types"
-)
-
-var (
- logId = flag.String("log_id", "AAG+ZW+UesWdMFytUGkp28csBcziomSB3U2vvkAW55MVZQ==", "base64-encoded log identifier")
- logUrl = flag.String("log_url", "http://tlog-poc.system-transparency.org:4780/st/v1", "log url")
- ed25519_sk = flag.String("ed25519_sk", "d8i6nud7PS1vdO0sIk9H+W0nyxbM63Y3/mSeUPRafWaFh8iH8QXvL7NaAYn2RZPrnEey+FdpmTYXE47OFO70eg==", "base64-encoded ed25519 signing key")
-)
-
-func NewClientFromFlags() (*Client, error) {
- var err error
- c := Client{
- HttpClient: &http.Client{},
- }
- if len(*ed25519_sk) != 0 {
- sk, err := base64.StdEncoding.DecodeString(*ed25519_sk)
- if err != nil {
- return nil, fmt.Errorf("ed25519_sk: DecodeString: %v", err)
- }
- c.Signer = ed25519.PrivateKey(sk)
- c.Namespace, err = types.NewNamespaceEd25519V1([]byte(ed25519.PrivateKey(sk).Public().(ed25519.PublicKey)))
- if err != nil {
- return nil, fmt.Errorf("ed25519_vk: NewNamespaceEd25519V1: %v", err)
- }
- }
- if c.Log, err = NewDescriptorFromFlags(); err != nil {
- return nil, fmt.Errorf("NewDescriptorFromFlags: %v", err)
- }
- return &c, nil
-}
-
-func NewDescriptorFromFlags() (*Descriptor, error) {
- b, err := base64.StdEncoding.DecodeString(*logId)
- if err != nil {
- return nil, fmt.Errorf("LogId: DecodeString: %v", err)
- }
- var namespace types.Namespace
- if err := types.Unmarshal(b, &namespace); err != nil {
- return nil, fmt.Errorf("LogId: Unmarshal: %v", err)
- }
- return &Descriptor{
- Namespace: &namespace,
- Url: *logUrl,
- }, nil
-}
diff --git a/client/verify.go b/client/verify.go
deleted file mode 100644
index c95828c..0000000
--- a/client/verify.go
+++ /dev/null
@@ -1,52 +0,0 @@
-package client
-
-import (
- "fmt"
- "reflect"
-
- "github.com/google/trillian/merkle"
- "github.com/google/trillian/merkle/rfc6962"
- "github.com/system-transparency/stfe/types"
-)
-
-func VerifySignedTreeHeadV1(namespace *types.Namespace, sth *types.StItem) error {
- if got, want := &sth.SignedTreeHeadV1.Signature.Namespace, namespace; !reflect.DeepEqual(got, want) {
- return fmt.Errorf("unexpected log id: %v", want)
- }
- th, err := types.Marshal(sth.SignedTreeHeadV1.TreeHead)
- if err != nil {
- return fmt.Errorf("Marshal: %v", err)
- }
- if err := namespace.Verify(th, sth.SignedTreeHeadV1.Signature.Signature); err != nil {
- return fmt.Errorf("Verify: %v", err)
- }
- return nil
-}
-
-func VerifyConsistencyProofV1(proof, first, second *types.StItem) error {
- path := make([][]byte, 0, len(proof.ConsistencyProofV1.ConsistencyPath))
- for _, nh := range proof.ConsistencyProofV1.ConsistencyPath {
- path = append(path, nh.Data)
- }
- return merkle.NewLogVerifier(rfc6962.DefaultHasher).VerifyConsistencyProof(
- int64(proof.ConsistencyProofV1.TreeSize1),
- int64(proof.ConsistencyProofV1.TreeSize2),
- first.SignedTreeHeadV1.TreeHead.RootHash.Data,
- second.SignedTreeHeadV1.TreeHead.RootHash.Data,
- path,
- )
-}
-
-func VerifyInclusionProofV1(proof, sth *types.StItem, leafHash []byte) error {
- path := make([][]byte, 0, len(proof.InclusionProofV1.InclusionPath))
- for _, nh := range proof.InclusionProofV1.InclusionPath {
- path = append(path, nh.Data)
- }
- return merkle.NewLogVerifier(rfc6962.DefaultHasher).VerifyInclusionProof(
- int64(proof.InclusionProofV1.LeafIndex),
- int64(proof.InclusionProofV1.TreeSize),
- path,
- sth.SignedTreeHeadV1.TreeHead.RootHash.Data,
- leafHash,
- )
-}
diff --git a/server/.gitignore b/cmd/siglog_server/.gitignore
index 254defd..254defd 100644
--- a/server/.gitignore
+++ b/cmd/siglog_server/.gitignore
diff --git a/server/README.md b/cmd/siglog_server/README.md
index 71bb3ac..71bb3ac 100644
--- a/server/README.md
+++ b/cmd/siglog_server/README.md
diff --git a/server/main.go b/cmd/siglog_server/main.go
index 1fecb43..368b0a7 100644
--- a/server/main.go
+++ b/cmd/siglog_server/main.go
@@ -19,15 +19,17 @@ import (
"github.com/golang/glog"
"github.com/google/trillian"
"github.com/prometheus/client_golang/prometheus/promhttp"
- "github.com/system-transparency/stfe"
- "github.com/system-transparency/stfe/types"
+ stfe "github.com/system-transparency/stfe/pkg/instance"
+ "github.com/system-transparency/stfe/pkg/state"
+ trillianWrapper "github.com/system-transparency/stfe/pkg/trillian"
+ "github.com/system-transparency/stfe/pkg/types"
"google.golang.org/grpc"
)
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/v0", "a prefix that proceeds each endpoint path")
+ prefix = flag.String("prefix", "", "a prefix that proceeds /st/v0/<endpoint>")
trillianID = flag.Int64("trillian_id", 0, "log identifier in the Trillian database")
deadline = flag.Duration("deadline", time.Second*10, "deadline for backend requests")
key = flag.String("key", "", "hex-encoded Ed25519 signing key")
@@ -53,13 +55,13 @@ func main() {
return
}
- glog.V(3).Infof("spawning SthSource")
+ glog.V(3).Infof("spawning state manager")
go func() {
wg.Add(1)
defer wg.Done()
- instance.SthSource.Run(ctx)
- glog.Errorf("SthSource shutdown")
- cancel() // must have SthSource running
+ instance.Stateman.Run(ctx)
+ glog.Errorf("state manager shutdown")
+ cancel() // must have state manager running
}()
glog.V(3).Infof("spawning await")
@@ -83,53 +85,62 @@ func main() {
// SetupInstance sets up a new STFE instance from flags
func setupInstanceFromFlags() (*stfe.Instance, error) {
- // Trillian gRPC connection
- dialOpts := []grpc.DialOption{grpc.WithInsecure(), grpc.WithBlock(), grpc.WithTimeout(*deadline)}
- conn, err := grpc.Dial(*rpcBackend, dialOpts...)
+ var i stfe.Instance
+ var err error
+
+ // Setup log configuration
+ i.Signer, i.LogID, err = newLogIdentity(*key)
if err != nil {
- return nil, fmt.Errorf("Dial: %v", err)
+ return nil, fmt.Errorf("newLogIdentity: %v", err)
}
- client := trillian.NewTrillianLogClient(conn)
- // HTTP multiplexer
- mux := http.NewServeMux()
- http.Handle("/", mux)
- // Prometheus metrics
- glog.V(3).Infof("Adding prometheus handler on path: /metrics")
- http.Handle("/metrics", promhttp.Handler())
- // Trusted witnesses
- witnesses, err := newWitnessMap(*witnesses)
+ i.TreeID = *trillianID
+ i.Prefix = *prefix
+ i.MaxRange = *maxRange
+ i.Deadline = *deadline
+ i.Interval = *interval
+ i.Witnesses, err = newWitnessMap(*witnesses)
if err != nil {
return nil, fmt.Errorf("newWitnessMap: %v", err)
}
- // Secret signing key
- sk, err := hex.DecodeString(*key)
+
+ // Setup log client
+ dialOpts := []grpc.DialOption{grpc.WithInsecure(), grpc.WithBlock(), grpc.WithTimeout(i.Deadline)}
+ conn, err := grpc.Dial(*rpcBackend, dialOpts...)
if err != nil {
- return nil, fmt.Errorf("sk: DecodeString: %v", err)
+ return nil, fmt.Errorf("Dial: %v", err)
}
- // Setup log parameters
- lp := &stfe.LogParameters{
- LogId: hex.EncodeToString([]byte(ed25519.PrivateKey(sk).Public().(ed25519.PublicKey))),
- TreeId: *trillianID,
- Prefix: *prefix,
- MaxRange: *maxRange,
- Deadline: *deadline,
- Interval: *interval,
- HashType: crypto.SHA256,
- Signer: ed25519.PrivateKey(sk),
- Witnesses: witnesses,
+ i.Client = &trillianWrapper.TrillianClient{
+ TreeID: i.TreeID,
+ GRPC: trillian.NewTrillianLogClient(conn),
}
- // Setup STH source
- source, err := stfe.NewActiveSthSource(client, lp)
+
+ // Setup state manager
+ i.Stateman, err = state.NewStateManagerSingle(i.Client, i.Signer, i.Interval, i.Deadline)
if err != nil {
- return nil, fmt.Errorf("NewActiveSthSource: %v", err)
+ return nil, fmt.Errorf("NewStateManager: %v", err)
}
- // Setup log instance
- i := &stfe.Instance{client, lp, source}
+
+ // Register HTTP endpoints
+ mux := http.NewServeMux()
+ http.Handle("/", mux)
for _, handler := range i.Handlers() {
glog.V(3).Infof("adding handler: %s", handler.Path())
mux.Handle(handler.Path(), handler)
}
- return i, nil
+ glog.V(3).Infof("Adding prometheus handler on path: /metrics")
+ http.Handle("/metrics", promhttp.Handler())
+
+ return &i, nil
+}
+
+func newLogIdentity(key string) (crypto.Signer, string, error) {
+ buf, err := hex.DecodeString(key)
+ if err != nil {
+ return nil, "", fmt.Errorf("DecodeString: %v", err)
+ }
+ sk := crypto.Signer(ed25519.PrivateKey(buf))
+ vk := sk.Public().(ed25519.PublicKey)
+ return sk, hex.EncodeToString([]byte(vk[:])), nil
}
// newWitnessMap creates a new map of trusted witnesses
diff --git a/cmd/tmp/README.md b/cmd/tmp/README.md
new file mode 100644
index 0000000..30d5317
--- /dev/null
+++ b/cmd/tmp/README.md
@@ -0,0 +1,2 @@
+# Warning
+These basic commands will be moved or replaced by proper tooling.
diff --git a/client/cmd/cosign/main.go b/cmd/tmp/cosign/main.go
index e86842b..a51f17d 100644
--- a/client/cmd/cosign/main.go
+++ b/cmd/tmp/cosign/main.go
@@ -9,7 +9,7 @@ import (
"log"
"net/http"
- "github.com/system-transparency/stfe/types"
+ "github.com/system-transparency/stfe/pkg/types"
)
var (
diff --git a/client/cmd/keygen/main.go b/cmd/tmp/keygen/main.go
index c1c1b58..c1c1b58 100644
--- a/client/cmd/keygen/main.go
+++ b/cmd/tmp/keygen/main.go
diff --git a/client/cmd/submit/main.go b/cmd/tmp/submit/main.go
index 36c7271..3dcaa97 100644
--- a/client/cmd/submit/main.go
+++ b/cmd/tmp/submit/main.go
@@ -6,7 +6,8 @@ import (
"crypto/ed25519"
"crypto/rand"
"fmt"
- "github.com/system-transparency/stfe/types"
+
+ "github.com/system-transparency/stfe/pkg/types"
)
func main() {
diff --git a/doc.go b/doc.go
deleted file mode 100644
index 4e86552..0000000
--- a/doc.go
+++ /dev/null
@@ -1,3 +0,0 @@
-// Package stfe implements a System Transparency Front-End (STFE) personality
-// for the Trillian log server gRPC API.
-package stfe
diff --git a/endpoint.go b/endpoint.go
deleted file mode 100644
index 9be55b4..0000000
--- a/endpoint.go
+++ /dev/null
@@ -1,163 +0,0 @@
-package stfe
-
-import (
- "context"
- "crypto/ed25519"
- "fmt"
- "net/http"
-
- "github.com/golang/glog"
- "github.com/google/trillian"
- "github.com/system-transparency/stfe/types"
-)
-
-func addEntry(ctx context.Context, i *Instance, w http.ResponseWriter, r *http.Request) (int, error) {
- glog.V(3).Info("handling add-entry request")
- leaf, err := i.LogParameters.parseAddEntryV1Request(r)
- if err != nil {
- return http.StatusBadRequest, fmt.Errorf("parseAddEntryV1Request: %v", err)
- }
- trsp, err := i.Client.QueueLeaf(ctx, &trillian.QueueLeafRequest{
- LogId: i.LogParameters.TreeId,
- Leaf: &trillian.LogLeaf{
- LeafValue: leaf.Marshal(),
- ExtraData: nil,
- },
- })
- if errInner := checkQueueLeaf(trsp, err); errInner != nil {
- return http.StatusInternalServerError, fmt.Errorf("bad QueueLeafResponse: %v", errInner)
- }
- return http.StatusOK, nil
-}
-
-func addCosignature(ctx context.Context, i *Instance, w http.ResponseWriter, r *http.Request) (int, error) {
- glog.V(3).Info("handling add-cosignature request")
- req, err := i.LogParameters.parseAddCosignatureRequest(r)
- if err != nil {
- return http.StatusBadRequest, fmt.Errorf("parseAddCosignatureRequest: %v", err)
- }
- vk := i.LogParameters.Witnesses[*req.KeyHash]
- if err := i.SthSource.AddCosignature(ctx, ed25519.PublicKey(vk[:]), req.Signature); err != nil {
- return http.StatusBadRequest, fmt.Errorf("AddCosignature: %v", err)
- }
- return http.StatusOK, nil
-}
-
-func getLatestSth(ctx context.Context, i *Instance, w http.ResponseWriter, _ *http.Request) (int, error) {
- glog.V(3).Info("handling get-latest-sth request")
- sth, err := i.SthSource.Latest(ctx)
- if err != nil {
- return http.StatusInternalServerError, fmt.Errorf("Latest: %v", err)
- }
- if err := sth.MarshalASCII(w); err != nil {
- return http.StatusInternalServerError, fmt.Errorf("MarshalASCII: %v", err)
- }
- return http.StatusOK, nil
-}
-
-func getStableSth(ctx context.Context, i *Instance, w http.ResponseWriter, _ *http.Request) (int, error) {
- glog.V(3).Info("handling get-stable-sth request")
- sth, err := i.SthSource.Stable(ctx)
- if err != nil {
- return http.StatusInternalServerError, fmt.Errorf("Latest: %v", err)
- }
- if err := sth.MarshalASCII(w); err != nil {
- return http.StatusInternalServerError, fmt.Errorf("MarshalASCII: %v", err)
- }
- return http.StatusOK, nil
-}
-
-func getCosignedSth(ctx context.Context, i *Instance, w http.ResponseWriter, _ *http.Request) (int, error) {
- glog.V(3).Info("handling get-cosigned-sth request")
- sth, err := i.SthSource.Cosigned(ctx)
- if err != nil {
- return http.StatusInternalServerError, fmt.Errorf("Cosigned: %v", err)
- }
- if err := sth.MarshalASCII(w); err != nil {
- return http.StatusInternalServerError, fmt.Errorf("MarshalASCII: %v", err)
- }
- return http.StatusOK, nil
-}
-
-func getConsistencyProof(ctx context.Context, i *Instance, w http.ResponseWriter, r *http.Request) (int, error) {
- glog.V(3).Info("handling get-consistency-proof request")
- req, err := i.LogParameters.parseGetConsistencyProofRequest(r)
- if err != nil {
- return http.StatusBadRequest, err
- }
-
- trsp, err := i.Client.GetConsistencyProof(ctx, &trillian.GetConsistencyProofRequest{
- LogId: i.LogParameters.TreeId,
- FirstTreeSize: int64(req.OldSize),
- SecondTreeSize: int64(req.NewSize),
- })
- if errInner := checkGetConsistencyProof(i.LogParameters, trsp, err); errInner != nil {
- return http.StatusInternalServerError, fmt.Errorf("bad GetConsistencyProofResponse: %v", errInner)
- }
-
- proof := &types.ConsistencyProof{
- NewSize: req.NewSize,
- OldSize: req.OldSize,
- Path: NodePathFromHashes(trsp.Proof.Hashes),
- }
- if err := proof.MarshalASCII(w); err != nil {
- return http.StatusInternalServerError, fmt.Errorf("MarshalASCII: %v", err)
- }
- return http.StatusOK, nil
-}
-
-func getProofByHash(ctx context.Context, i *Instance, w http.ResponseWriter, r *http.Request) (int, error) {
- glog.V(3).Info("handling get-proof-by-hash request")
- req, err := i.LogParameters.parseGetProofByHashRequest(r)
- if err != nil {
- return http.StatusBadRequest, err
- }
-
- trsp, err := i.Client.GetInclusionProofByHash(ctx, &trillian.GetInclusionProofByHashRequest{
- LogId: i.LogParameters.TreeId,
- LeafHash: req.LeafHash[:],
- TreeSize: int64(req.TreeSize),
- OrderBySequence: true,
- })
- if errInner := checkGetInclusionProofByHash(i.LogParameters, trsp, err); errInner != nil {
- return http.StatusInternalServerError, fmt.Errorf("bad GetInclusionProofByHashResponse: %v", errInner)
- }
-
- proof := &types.InclusionProof{
- TreeSize: req.TreeSize,
- LeafIndex: uint64(trsp.Proof[0].LeafIndex),
- Path: NodePathFromHashes(trsp.Proof[0].Hashes),
- }
- if err := proof.MarshalASCII(w); err != nil {
- return http.StatusInternalServerError, fmt.Errorf("MarshalASCII: %v", err)
- }
- return http.StatusOK, nil
-}
-
-func getEntries(ctx context.Context, i *Instance, w http.ResponseWriter, r *http.Request) (int, error) {
- glog.V(3).Info("handling get-entries request")
- req, err := i.LogParameters.parseGetEntriesRequest(r)
- if err != nil {
- return http.StatusBadRequest, err
- }
-
- trsp, err := i.Client.GetLeavesByRange(ctx, &trillian.GetLeavesByRangeRequest{
- LogId: i.LogParameters.TreeId,
- StartIndex: int64(req.StartSize),
- Count: int64(req.EndSize-req.StartSize) + 1,
- })
- if errInner := checkGetLeavesByRange(req, trsp, err); errInner != nil {
- return http.StatusInternalServerError, fmt.Errorf("checkGetLeavesByRangeResponse: %v", errInner) // there is one StatusBadRequest in here tho..
- }
-
- for _, serialized := range trsp.Leaves {
- var leaf types.Leaf
- if err := leaf.Unmarshal(serialized.LeafValue); err != nil {
- return http.StatusInternalServerError, fmt.Errorf("Unmarshal: %v", err)
- }
- if err := leaf.MarshalASCII(w); err != nil {
- return http.StatusInternalServerError, fmt.Errorf("MarshalASCII: %v", err)
- }
- }
- return http.StatusOK, nil
-}
diff --git a/go.sum b/go.sum
index 68617e4..839df30 100644
--- a/go.sum
+++ b/go.sum
@@ -181,6 +181,7 @@ github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
@@ -461,6 +462,7 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@@ -645,6 +647,7 @@ golang.org/x/tools v0.0.0-20200630154851-b2d8b0336632/go.mod h1:EkVYQZoAsY45+roY
golang.org/x/tools v0.0.0-20200706234117-b22de6825cf7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
diff --git a/instance.go b/instance.go
deleted file mode 100644
index 4425770..0000000
--- a/instance.go
+++ /dev/null
@@ -1,75 +0,0 @@
-package stfe
-
-import (
- "context"
- "fmt"
- "time"
-
- "net/http"
-
- "github.com/golang/glog"
- "github.com/google/trillian"
- "github.com/system-transparency/stfe/types"
-)
-
-// Instance is an instance of the system transparency front-end
-type Instance struct {
- Client trillian.TrillianLogClient
- LogParameters *LogParameters
- SthSource SthSource
-}
-
-// Handlers returns a list of STFE handlers
-func (i *Instance) Handlers() []Handler {
- return []Handler{
- Handler{Instance: i, Handler: addEntry, Endpoint: types.EndpointAddLeaf, Method: http.MethodPost},
- Handler{Instance: i, Handler: addCosignature, Endpoint: types.EndpointAddCosignature, Method: http.MethodPost},
- Handler{Instance: i, Handler: getLatestSth, Endpoint: types.EndpointGetTreeHeadLatest, Method: http.MethodGet},
- Handler{Instance: i, Handler: getStableSth, Endpoint: types.EndpointGetTreeHeadToSign, Method: http.MethodGet},
- Handler{Instance: i, Handler: getCosignedSth, Endpoint: types.EndpointGetTreeHeadCosigned, Method: http.MethodGet},
- Handler{Instance: i, Handler: getProofByHash, Endpoint: types.EndpointGetProofByHash, Method: http.MethodPost},
- Handler{Instance: i, Handler: getConsistencyProof, Endpoint: types.EndpointGetConsistencyProof, Method: http.MethodPost},
- Handler{Instance: i, Handler: getEntries, Endpoint: types.EndpointGetLeaves, Method: http.MethodPost},
- }
-}
-
-// Handler implements the http.Handler interface, and contains a reference
-// to an STFE server instance as well as a function that uses it.
-type Handler struct {
- Instance *Instance
- Endpoint types.Endpoint
- Method string
- 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(a.Instance.LogParameters.LogId, string(a.Endpoint), fmt.Sprintf("%d", statusCode))
- latency.Observe(time.Now().Sub(now).Seconds(), a.Instance.LogParameters.LogId, string(a.Endpoint), fmt.Sprintf("%d", statusCode))
- }()
- reqcnt.Inc(a.Instance.LogParameters.LogId, string(a.Endpoint))
-
- ctx, cancel := context.WithDeadline(r.Context(), now.Add(a.Instance.LogParameters.Deadline))
- defer cancel()
-
- if r.Method != a.Method {
- glog.Warningf("%s/%s: got HTTP %s, wanted HTTP %s", a.Instance.LogParameters.Prefix, string(a.Endpoint), r.Method, a.Method)
- http.Error(w, "", http.StatusMethodNotAllowed)
- return
- }
-
- statusCode, err := a.Handler(ctx, a.Instance, w, r)
- if err != nil {
- glog.Warningf("handler error %s/%s: %v", a.Instance.LogParameters.Prefix, a.Endpoint, err)
- http.Error(w, fmt.Sprintf("%s%s%s%s", "Error", types.Delim, err.Error(), types.EOL), statusCode)
- }
-}
diff --git a/log_parameters.go b/log_parameters.go
deleted file mode 100644
index aceff3e..0000000
--- a/log_parameters.go
+++ /dev/null
@@ -1,47 +0,0 @@
-package stfe
-
-import (
- "crypto"
- "crypto/ed25519"
- "fmt"
- "time"
-
- "github.com/system-transparency/stfe/types"
-)
-
-// LogParameters is a collection of log parameters
-type LogParameters struct {
- LogId 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
- 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
-
- // Witnesses map trusted witness identifiers to public verification keys
- Witnesses map[[types.HashSize]byte][types.VerificationKeySize]byte
-}
-
-// Sign signs a tree head
-func (lp *LogParameters) Sign(th *types.TreeHead) (*types.SignedTreeHead, error) {
- sig, err := lp.Signer.Sign(nil, th.Marshal(), crypto.Hash(0))
- if err != nil {
- return nil, fmt.Errorf("Sign failed: %v", err)
- }
- lastSthTimestamp.Set(float64(time.Now().Unix()), lp.LogId)
- lastSthSize.Set(float64(th.TreeSize), lp.LogId)
-
- sigident := types.SigIdent{
- KeyHash: types.Hash(lp.Signer.Public().(ed25519.PublicKey)[:]),
- Signature: &[types.SignatureSize]byte{},
- }
- copy(sigident.Signature[:], sig)
- return &types.SignedTreeHead{
- TreeHead: *th,
- SigIdent: []*types.SigIdent{
- &sigident,
- },
- }, nil
-}
diff --git a/log_parameters_test.go b/log_parameters_test.go
deleted file mode 100644
index 88e83ad..0000000
--- a/log_parameters_test.go
+++ /dev/null
@@ -1,99 +0,0 @@
-package stfe
-
-import (
- "crypto"
- "fmt"
- "reflect"
- "testing"
-
- cttestdata "github.com/google/certificate-transparency-go/trillian/testdata"
- "github.com/system-transparency/stfe/testdata"
- "github.com/system-transparency/stfe/types"
-)
-
-// newLogParameters must create new log parameters with an optional log signer
-// 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. 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)
- witnessPool := testdata.NewNamespacePool(t, []*types.Namespace{
- testdata.NewNamespace(t, testdata.Ed25519VkWitness),
- })
- 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, true, true)
- if err != nil {
- t.Fatalf("must create new log parameters: %v", err)
- }
- return lp
-}
-
-func TestNewLogParameters(t *testing.T) {
- for _, table := range []struct {
- description string
- logId *types.Namespace
- wantErr bool
- }{
- {
- description: "invalid: cannot marshal log id",
- logId: &types.Namespace{
- Format: types.NamespaceFormatReserved,
- },
- wantErr: true,
- },
- {
- description: "valid",
- logId: testdata.NewNamespace(t, testdata.Ed25519VkLog),
- },
- } {
- _, 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)
- }
- }
-}
-
-func TestSignTreeHeadV1(t *testing.T) {
- for _, table := range []struct {
- description string
- th *types.TreeHeadV1
- signer crypto.Signer
- wantErr bool
- wantSth *types.StItem
- }{
- {
- description: "invalid: marshal failure",
- th: types.NewTreeHeadV1(testdata.Timestamp, testdata.TreeSize, nil, testdata.Extension),
- wantErr: true,
- },
- {
- description: "invalid: signature failure",
- th: types.NewTreeHeadV1(testdata.Timestamp, testdata.TreeSize, testdata.NodeHash, testdata.Extension),
- signer: cttestdata.NewSignerWithErr(nil, fmt.Errorf("signer failed")),
- wantErr: true,
- },
- {
- description: "valid",
- th: testdata.DefaultTh(t),
- signer: cttestdata.NewSignerWithFixedSig(nil, testdata.Signature),
- wantSth: testdata.DefaultSth(t, testdata.Ed25519VkLog),
- },
- } {
- sth, err := newLogParameters(t, table.signer).SignTreeHeadV1(table.th)
- 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)
- }
- if err != nil {
- continue
- }
-
- if got, want := sth, table.wantSth; !reflect.DeepEqual(got, want) {
- t.Errorf("got \n%v\n\tbut wanted\n%v\n\tin test %q", got, want, table.description)
- }
- }
-}
diff --git a/pkg/instance/endpoint.go b/pkg/instance/endpoint.go
new file mode 100644
index 0000000..5085c49
--- /dev/null
+++ b/pkg/instance/endpoint.go
@@ -0,0 +1,122 @@
+package stfe
+
+import (
+ "context"
+ "net/http"
+
+ "github.com/golang/glog"
+)
+
+func addLeaf(ctx context.Context, i *Instance, w http.ResponseWriter, r *http.Request) (int, error) {
+ glog.V(3).Info("handling add-entry request")
+ req, err := i.leafRequestFromHTTP(r)
+ if err != nil {
+ return http.StatusBadRequest, err
+ }
+ if err := i.Client.AddLeaf(ctx, req); err != nil {
+ return http.StatusInternalServerError, err
+ }
+ return http.StatusOK, nil
+}
+
+func addCosignature(ctx context.Context, i *Instance, w http.ResponseWriter, r *http.Request) (int, error) {
+ glog.V(3).Info("handling add-cosignature request")
+ req, err := i.cosignatureRequestFromHTTP(r)
+ if err != nil {
+ return http.StatusBadRequest, err
+ }
+ vk := i.Witnesses[*req.KeyHash]
+ if err := i.Stateman.AddCosignature(ctx, &vk, req.Signature); err != nil {
+ return http.StatusBadRequest, err
+ }
+ return http.StatusOK, nil
+}
+
+func getTreeHeadLatest(ctx context.Context, i *Instance, w http.ResponseWriter, _ *http.Request) (int, error) {
+ glog.V(3).Info("handling get-tree-head-latest request")
+ sth, err := i.Stateman.Latest(ctx)
+ if err != nil {
+ return http.StatusInternalServerError, err
+ }
+ if err := sth.MarshalASCII(w); err != nil {
+ return http.StatusInternalServerError, err
+ }
+ return http.StatusOK, nil
+}
+
+func getTreeHeadToSign(ctx context.Context, i *Instance, w http.ResponseWriter, _ *http.Request) (int, error) {
+ glog.V(3).Info("handling get-tree-head-to-sign request")
+ sth, err := i.Stateman.ToSign(ctx)
+ if err != nil {
+ return http.StatusInternalServerError, err
+ }
+ if err := sth.MarshalASCII(w); err != nil {
+ return http.StatusInternalServerError, err
+ }
+ return http.StatusOK, nil
+}
+
+func getTreeHeadCosigned(ctx context.Context, i *Instance, w http.ResponseWriter, _ *http.Request) (int, error) {
+ glog.V(3).Info("handling get-tree-head-cosigned request")
+ sth, err := i.Stateman.Cosigned(ctx)
+ if err != nil {
+ return http.StatusInternalServerError, err
+ }
+ if err := sth.MarshalASCII(w); err != nil {
+ return http.StatusInternalServerError, err
+ }
+ return http.StatusOK, nil
+}
+
+func getConsistencyProof(ctx context.Context, i *Instance, w http.ResponseWriter, r *http.Request) (int, error) {
+ glog.V(3).Info("handling get-consistency-proof request")
+ req, err := i.consistencyProofRequestFromHTTP(r)
+ if err != nil {
+ return http.StatusBadRequest, err
+ }
+
+ proof, err := i.Client.GetConsistencyProof(ctx, req)
+ if err != nil {
+ return http.StatusInternalServerError, err
+ }
+ if err := proof.MarshalASCII(w); err != nil {
+ return http.StatusInternalServerError, err
+ }
+ return http.StatusOK, nil
+}
+
+func getInclusionProof(ctx context.Context, i *Instance, w http.ResponseWriter, r *http.Request) (int, error) {
+ glog.V(3).Info("handling get-proof-by-hash request")
+ req, err := i.inclusionProofRequestFromHTTP(r)
+ if err != nil {
+ return http.StatusBadRequest, err
+ }
+
+ proof, err := i.Client.GetInclusionProof(ctx, req)
+ if err != nil {
+ return http.StatusInternalServerError, err
+ }
+ if err := proof.MarshalASCII(w); err != nil {
+ return http.StatusInternalServerError, err
+ }
+ return http.StatusOK, nil
+}
+
+func getLeaves(ctx context.Context, i *Instance, w http.ResponseWriter, r *http.Request) (int, error) {
+ glog.V(3).Info("handling get-leaves request")
+ req, err := i.leavesRequestFromHTTP(r)
+ if err != nil {
+ return http.StatusBadRequest, err
+ }
+
+ leaves, err := i.Client.GetLeaves(ctx, req)
+ if err != nil {
+ return http.StatusInternalServerError, err
+ }
+ for _, leaf := range *leaves {
+ if err := leaf.MarshalASCII(w); err != nil {
+ return http.StatusInternalServerError, err
+ }
+ }
+ return http.StatusOK, nil
+}
diff --git a/endpoint_test.go b/pkg/instance/endpoint_test.go
index e515635..8511b8d 100644
--- a/endpoint_test.go
+++ b/pkg/instance/endpoint_test.go
@@ -4,17 +4,16 @@ import (
"bytes"
"context"
"fmt"
- "reflect"
- "testing"
-
"net/http"
"net/http/httptest"
+ "reflect"
+ "testing"
"github.com/golang/mock/gomock"
cttestdata "github.com/google/certificate-transparency-go/trillian/testdata"
"github.com/google/trillian"
- "github.com/system-transparency/stfe/testdata"
- "github.com/system-transparency/stfe/types"
+ "github.com/system-transparency/stfe/pkg/testdata"
+ "github.com/system-transparency/stfe/pkg/types"
)
func TestEndpointAddEntry(t *testing.T) {
diff --git a/pkg/instance/instance.go b/pkg/instance/instance.go
new file mode 100644
index 0000000..3441a0a
--- /dev/null
+++ b/pkg/instance/instance.go
@@ -0,0 +1,90 @@
+package stfe
+
+import (
+ "context"
+ "crypto"
+ "fmt"
+ "net/http"
+ "time"
+
+ "github.com/golang/glog"
+ "github.com/system-transparency/stfe/pkg/state"
+ "github.com/system-transparency/stfe/pkg/trillian"
+ "github.com/system-transparency/stfe/pkg/types"
+)
+
+// 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
+
+ // Witnesses map trusted witness identifiers to public verification keys
+ Witnesses map[[types.HashSize]byte][types.VerificationKeySize]byte
+}
+
+// Instance is an instance of the log's front-end
+type Instance struct {
+ Config // configuration parameters
+ Client trillian.Client // provides access to the Trillian backend
+ Signer crypto.Signer // provides access to Ed25519 private key
+ Stateman state.StateManager // coordinates access to (co)signed tree heads
+}
+
+// Handler implements the http.Handler interface, and contains a reference
+// to an STFE server instance as well as a function that uses it.
+type Handler struct {
+ Instance *Instance
+ Endpoint types.Endpoint
+ Method string
+ Handler func(context.Context, *Instance, http.ResponseWriter, *http.Request) (int, error)
+}
+
+// Handlers returns a list of STFE handlers
+func (i *Instance) Handlers() []Handler {
+ return []Handler{
+ Handler{Instance: i, Handler: addLeaf, Endpoint: types.EndpointAddLeaf, Method: http.MethodPost},
+ Handler{Instance: i, Handler: addCosignature, Endpoint: types.EndpointAddCosignature, Method: http.MethodPost},
+ Handler{Instance: i, Handler: getTreeHeadLatest, Endpoint: types.EndpointGetTreeHeadLatest, Method: http.MethodGet},
+ Handler{Instance: i, Handler: getTreeHeadToSign, Endpoint: types.EndpointGetTreeHeadToSign, Method: http.MethodGet},
+ Handler{Instance: i, Handler: getTreeHeadCosigned, Endpoint: types.EndpointGetTreeHeadCosigned, Method: http.MethodGet},
+ Handler{Instance: i, Handler: getConsistencyProof, Endpoint: types.EndpointGetConsistencyProof, Method: http.MethodPost},
+ Handler{Instance: i, Handler: getInclusionProof, Endpoint: types.EndpointGetProofByHash, Method: http.MethodPost},
+ Handler{Instance: i, Handler: getLeaves, Endpoint: types.EndpointGetLeaves, Method: http.MethodPost},
+ }
+}
+
+// Path returns a path that should be configured for this handler
+func (h Handler) Path() string {
+ return h.Endpoint.Path(h.Instance.Prefix, "st", "v0")
+}
+
+// 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(a.Instance.LogID, string(a.Endpoint), fmt.Sprintf("%d", statusCode))
+ latency.Observe(time.Now().Sub(now).Seconds(), a.Instance.LogID, string(a.Endpoint), fmt.Sprintf("%d", statusCode))
+ }()
+ reqcnt.Inc(a.Instance.LogID, string(a.Endpoint))
+
+ ctx, cancel := context.WithDeadline(r.Context(), now.Add(a.Instance.Deadline))
+ defer cancel()
+
+ if r.Method != a.Method {
+ glog.Warningf("%s/%s: got HTTP %s, wanted HTTP %s", a.Instance.Prefix, string(a.Endpoint), r.Method, a.Method)
+ http.Error(w, "", http.StatusMethodNotAllowed)
+ return
+ }
+
+ statusCode, err := a.Handler(ctx, a.Instance, w, r)
+ if err != nil {
+ glog.Warningf("handler error %s/%s: %v", a.Instance.Prefix, a.Endpoint, err)
+ http.Error(w, fmt.Sprintf("%s%s%s%s", "Error", types.Delim, err.Error(), types.EOL), statusCode)
+ }
+}
diff --git a/instance_test.go b/pkg/instance/instance_test.go
index de539a1..a7a3d8a 100644
--- a/instance_test.go
+++ b/pkg/instance/instance_test.go
@@ -2,15 +2,14 @@ package stfe
import (
"crypto"
- "testing"
-
"net/http"
"net/http/httptest"
+ "testing"
"github.com/golang/mock/gomock"
"github.com/google/certificate-transparency-go/trillian/mockclient"
- "github.com/system-transparency/stfe/testdata"
- "github.com/system-transparency/stfe/types"
+ "github.com/system-transparency/stfe/pkg/testdata"
+ "github.com/system-transparency/stfe/pkg/types"
)
type testInstance struct {
diff --git a/metric.go b/pkg/instance/metric.go
index 7e3e8b2..7e3e8b2 100644
--- a/metric.go
+++ b/pkg/instance/metric.go
diff --git a/request.go b/pkg/instance/request.go
index 763d9ed..7475b26 100644
--- a/request.go
+++ b/pkg/instance/request.go
@@ -1,46 +1,42 @@
package stfe
import (
- "fmt"
-
"crypto/ed25519"
+ "fmt"
"net/http"
- "github.com/system-transparency/stfe/types"
+ "github.com/system-transparency/stfe/pkg/types"
)
-func (lp *LogParameters) parseAddEntryV1Request(r *http.Request) (*types.Leaf, error) {
+func (i *Instance) leafRequestFromHTTP(r *http.Request) (*types.LeafRequest, error) {
var req types.LeafRequest
if err := req.UnmarshalASCII(r.Body); err != nil {
return nil, fmt.Errorf("UnmarshalASCII: %v", err)
}
- if pub, msg, sig := ed25519.PublicKey(req.VerificationKey[:]), req.Message.Marshal(), req.Signature[:]; !ed25519.Verify(pub, msg, sig) {
- return nil, fmt.Errorf("Invalid signature")
+ vk := ed25519.PublicKey(req.VerificationKey[:])
+ msg := req.Message.Marshal()
+ sig := req.Signature[:]
+ if !ed25519.Verify(vk, msg, sig) {
+ return nil, fmt.Errorf("invalid signature")
}
// TODO: check shard hint
// TODO: check domain hint
- return &types.Leaf{
- Message: req.Message,
- SigIdent: types.SigIdent{
- Signature: req.Signature,
- KeyHash: types.Hash(req.VerificationKey[:]),
- },
- }, nil
+ return &req, nil
}
-func (lp *LogParameters) parseAddCosignatureRequest(r *http.Request) (*types.CosignatureRequest, error) {
+func (i *Instance) cosignatureRequestFromHTTP(r *http.Request) (*types.CosignatureRequest, error) {
var req types.CosignatureRequest
if err := req.UnmarshalASCII(r.Body); err != nil {
return nil, fmt.Errorf("unpackOctetPost: %v", err)
}
- if _, ok := lp.Witnesses[*req.KeyHash]; !ok {
+ if _, ok := i.Witnesses[*req.KeyHash]; !ok {
return nil, fmt.Errorf("Unknown witness: %x", req.KeyHash)
}
return &req, nil
}
-func (lp *LogParameters) parseGetConsistencyProofRequest(r *http.Request) (*types.ConsistencyProofRequest, error) {
+func (i *Instance) consistencyProofRequestFromHTTP(r *http.Request) (*types.ConsistencyProofRequest, error) {
var req types.ConsistencyProofRequest
if err := req.UnmarshalASCII(r.Body); err != nil {
return nil, fmt.Errorf("UnmarshalASCII: %v", err)
@@ -54,7 +50,7 @@ func (lp *LogParameters) parseGetConsistencyProofRequest(r *http.Request) (*type
return &req, nil
}
-func (lp *LogParameters) parseGetProofByHashRequest(r *http.Request) (*types.InclusionProofRequest, error) {
+func (i *Instance) inclusionProofRequestFromHTTP(r *http.Request) (*types.InclusionProofRequest, error) {
var req types.InclusionProofRequest
if err := req.UnmarshalASCII(r.Body); err != nil {
return nil, fmt.Errorf("UnmarshalASCII: %v", err)
@@ -65,7 +61,7 @@ func (lp *LogParameters) parseGetProofByHashRequest(r *http.Request) (*types.Inc
return &req, nil
}
-func (lp *LogParameters) parseGetEntriesRequest(r *http.Request) (*types.LeavesRequest, error) {
+func (i *Instance) leavesRequestFromHTTP(r *http.Request) (*types.LeavesRequest, error) {
var req types.LeavesRequest
if err := req.UnmarshalASCII(r.Body); err != nil {
return nil, fmt.Errorf("UnmarshalASCII: %v", err)
@@ -74,8 +70,8 @@ func (lp *LogParameters) parseGetEntriesRequest(r *http.Request) (*types.LeavesR
if req.StartSize > req.EndSize {
return nil, fmt.Errorf("StartSize(%d) must be less than or equal to EndSize(%d)", req.StartSize, req.EndSize)
}
- if req.EndSize-req.StartSize+1 > uint64(lp.MaxRange) {
- req.EndSize = req.StartSize + uint64(lp.MaxRange) - 1
+ if req.EndSize-req.StartSize+1 > uint64(i.MaxRange) {
+ req.EndSize = req.StartSize + uint64(i.MaxRange) - 1
}
return &req, nil
}
diff --git a/request_test.go b/pkg/instance/request_test.go
index 102c56f..0a5a908 100644
--- a/request_test.go
+++ b/pkg/instance/request_test.go
@@ -9,8 +9,8 @@ import (
"net/http"
- "github.com/system-transparency/stfe/testdata"
- "github.com/system-transparency/stfe/types"
+ "github.com/system-transparency/stfe/pkg/testdata"
+ "github.com/system-transparency/stfe/pkg/types"
)
func TestParseAddEntryV1Request(t *testing.T) {
diff --git a/mocks/crypto.go b/pkg/mocks/crypto.go
index 87c883a..87c883a 100644
--- a/mocks/crypto.go
+++ b/pkg/mocks/crypto.go
diff --git a/mocks/stfe.go b/pkg/mocks/stfe.go
index e0fe7a9..def5bc6 100644
--- a/mocks/stfe.go
+++ b/pkg/mocks/stfe.go
@@ -9,7 +9,7 @@ import (
reflect "reflect"
gomock "github.com/golang/mock/gomock"
- types "github.com/system-transparency/stfe/types"
+ types "github.com/system-transparency/stfe/pkg/types"
)
// MockClient is a mock of Client interface.
diff --git a/mocks/trillian.go b/pkg/mocks/trillian.go
index 8aa3a58..8aa3a58 100644
--- a/mocks/trillian.go
+++ b/pkg/mocks/trillian.go
diff --git a/state/state_manager.go b/pkg/state/state_manager.go
index 3199e61..dfa73f4 100644
--- a/state/state_manager.go
+++ b/pkg/state/state_manager.go
@@ -1,4 +1,4 @@
-package stfe
+package state
import (
"context"
@@ -10,8 +10,8 @@ import (
"github.com/golang/glog"
"github.com/google/certificate-transparency-go/schedule"
- "github.com/system-transparency/stfe/trillian"
- "github.com/system-transparency/stfe/types"
+ "github.com/system-transparency/stfe/pkg/trillian"
+ "github.com/system-transparency/stfe/pkg/types"
)
// StateManager coordinates access to the log's tree heads and (co)signatures
diff --git a/state/state_manager_test.go b/pkg/state/state_manager_test.go
index 348074c..08990cc 100644
--- a/state/state_manager_test.go
+++ b/pkg/state/state_manager_test.go
@@ -1,4 +1,4 @@
-package stfe
+package state
import (
"bytes"
@@ -12,8 +12,8 @@ import (
"time"
"github.com/golang/mock/gomock"
- "github.com/system-transparency/stfe/mocks"
- "github.com/system-transparency/stfe/types"
+ "github.com/system-transparency/stfe/pkg/mocks"
+ "github.com/system-transparency/stfe/pkg/types"
)
var (
diff --git a/trillian/client.go b/pkg/trillian/client.go
index 9ea6a4a..9523e56 100644
--- a/trillian/client.go
+++ b/pkg/trillian/client.go
@@ -7,7 +7,7 @@ import (
"github.com/golang/glog"
"github.com/google/trillian"
ttypes "github.com/google/trillian/types"
- "github.com/system-transparency/stfe/types"
+ "github.com/system-transparency/stfe/pkg/types"
"google.golang.org/grpc/codes"
)
diff --git a/trillian/client_test.go b/pkg/trillian/client_test.go
index e9f1ff5..6b3d881 100644
--- a/trillian/client_test.go
+++ b/pkg/trillian/client_test.go
@@ -9,8 +9,8 @@ import (
"github.com/golang/mock/gomock"
"github.com/google/trillian"
ttypes "github.com/google/trillian/types"
- "github.com/system-transparency/stfe/mocks"
- "github.com/system-transparency/stfe/types"
+ "github.com/system-transparency/stfe/pkg/mocks"
+ "github.com/system-transparency/stfe/pkg/types"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
diff --git a/trillian/util.go b/pkg/trillian/util.go
index 87e64b6..4cf31fb 100644
--- a/trillian/util.go
+++ b/pkg/trillian/util.go
@@ -4,7 +4,7 @@ import (
"fmt"
trillian "github.com/google/trillian/types"
- siglog "github.com/system-transparency/stfe/types"
+ siglog "github.com/system-transparency/stfe/pkg/types"
)
func treeHeadFromLogRoot(lr *trillian.LogRootV1) *siglog.TreeHead {
diff --git a/types/ascii.go b/pkg/types/ascii.go
index d27d79b..d27d79b 100644
--- a/types/ascii.go
+++ b/pkg/types/ascii.go
diff --git a/types/ascii_test.go b/pkg/types/ascii_test.go
index 92732f9..92732f9 100644
--- a/types/ascii_test.go
+++ b/pkg/types/ascii_test.go
diff --git a/types/trunnel.go b/pkg/types/trunnel.go
index 268f6f7..268f6f7 100644
--- a/types/trunnel.go
+++ b/pkg/types/trunnel.go
diff --git a/types/trunnel_test.go b/pkg/types/trunnel_test.go
index 297578c..297578c 100644
--- a/types/trunnel_test.go
+++ b/pkg/types/trunnel_test.go
diff --git a/types/types.go b/pkg/types/types.go
index 9ca7db8..9ca7db8 100644
--- a/types/types.go
+++ b/pkg/types/types.go
diff --git a/types/types_test.go b/pkg/types/types_test.go
index da89c59..da89c59 100644
--- a/types/types_test.go
+++ b/pkg/types/types_test.go
diff --git a/types/util.go b/pkg/types/util.go
index 3cd7dfa..3cd7dfa 100644
--- a/types/util.go
+++ b/pkg/types/util.go
diff --git a/sth.go b/sth.go
deleted file mode 100644
index 1399241..0000000
--- a/sth.go
+++ /dev/null
@@ -1,143 +0,0 @@
-package stfe
-
-import (
- "context"
- "crypto/ed25519"
- "fmt"
- "reflect"
- "sync"
-
- "github.com/golang/glog"
- "github.com/google/certificate-transparency-go/schedule"
- "github.com/google/trillian"
- ttypes "github.com/google/trillian/types"
- "github.com/system-transparency/stfe/types"
-)
-
-// SthSource provides access to the log's (co)signed tree heads
-type SthSource interface {
- Latest(context.Context) (*types.SignedTreeHead, error)
- Stable(context.Context) (*types.SignedTreeHead, error)
- Cosigned(context.Context) (*types.SignedTreeHead, error)
- AddCosignature(context.Context, ed25519.PublicKey, *[types.SignatureSize]byte) error
- Run(context.Context)
-}
-
-// ActiveSthSource implements the SthSource interface for an STFE instance that
-// accepts new logging requests, i.e., the log is running in read+write mode.
-type ActiveSthSource struct {
- client trillian.TrillianLogClient
- logParameters *LogParameters
- sync.RWMutex
-
- // cosigned is the current cosigned tree head that is served
- cosigned types.SignedTreeHead
-
- // tosign is the current tree head that is being cosigned
- tosign types.SignedTreeHead
-
- // cosignature keeps track of all collected cosignatures for tosign
- cosignature map[[types.HashSize]byte]*types.SigIdent
-}
-
-func NewActiveSthSource(cli trillian.TrillianLogClient, lp *LogParameters) (*ActiveSthSource, error) {
- s := ActiveSthSource{
- client: cli,
- logParameters: lp,
- }
-
- ctx, _ := context.WithTimeout(context.Background(), lp.Deadline)
- sth, err := s.Latest(ctx)
- if err != nil {
- return nil, fmt.Errorf("Latest: %v", err)
- }
-
- s.cosigned = *sth
- s.tosign = *sth
- s.cosignature = make(map[[types.HashSize]byte]*types.SigIdent)
- return &s, nil
-}
-
-func (s *ActiveSthSource) Run(ctx context.Context) {
- schedule.Every(ctx, s.logParameters.Interval, func(ctx context.Context) {
- // get the next stable sth
- ictx, _ := context.WithTimeout(ctx, s.logParameters.Deadline)
- sth, err := s.Latest(ictx)
- if err != nil {
- glog.Warningf("cannot rotate without new sth: Latest: %v", err)
- return
- }
- // rotate
- s.Lock()
- defer s.Unlock()
- s.rotate(sth)
- })
-}
-
-func (s *ActiveSthSource) Latest(ctx context.Context) (*types.SignedTreeHead, error) {
- trsp, err := s.client.GetLatestSignedLogRoot(ctx, &trillian.GetLatestSignedLogRootRequest{
- LogId: s.logParameters.TreeId,
- })
- var lr ttypes.LogRootV1
- if errInner := checkGetLatestSignedLogRoot(s.logParameters, trsp, err, &lr); errInner != nil {
- return nil, fmt.Errorf("invalid signed log root response: %v", errInner)
- }
- return s.logParameters.Sign(NewTreeHeadFromLogRoot(&lr))
-}
-
-func (s *ActiveSthSource) Stable(_ context.Context) (*types.SignedTreeHead, error) {
- s.RLock()
- defer s.RUnlock()
- return &s.tosign, nil
-}
-
-func (s *ActiveSthSource) Cosigned(_ context.Context) (*types.SignedTreeHead, error) {
- s.RLock()
- defer s.RUnlock()
- return &s.cosigned, nil
-}
-
-func (s *ActiveSthSource) AddCosignature(_ context.Context, vk ed25519.PublicKey, sig *[types.SignatureSize]byte) error {
- s.Lock()
- defer s.Unlock()
-
- if msg := s.tosign.TreeHead.Marshal(); !ed25519.Verify(vk, msg, sig[:]) {
- return fmt.Errorf("Invalid signature for tree head with timestamp: %d", s.tosign.TreeHead.Timestamp)
- }
- witness := types.Hash(vk[:])
- if _, ok := s.cosignature[*witness]; ok {
- glog.V(3).Infof("received cosignature again (duplicate)")
- return nil // duplicate
- }
- s.cosignature[*witness] = &types.SigIdent{
- Signature: sig,
- KeyHash: witness,
- }
- glog.V(3).Infof("accepted new cosignature")
- return nil
-}
-
-// rotate rotates the log's cosigned and stable STH. The caller must aquire the
-// source's read-write lock if there are concurrent reads and/or writes.
-func (s *ActiveSthSource) rotate(next *types.SignedTreeHead) {
- if reflect.DeepEqual(s.cosigned.TreeHead, s.tosign.TreeHead) {
- for _, sigident := range s.cosigned.SigIdent[1:] { // skip log sigident
- if _, ok := s.cosignature[*sigident.KeyHash]; !ok {
- s.cosignature[*sigident.KeyHash] = sigident
- }
- }
- }
- var cosignatures []*types.SigIdent
- for _, sigident := range s.cosignature {
- cosignatures = append(cosignatures, sigident)
- } // cosignatures contains all cosignatures, even if repeated tree head
-
- // Update cosigned tree head
- s.cosigned.TreeHead = s.tosign.TreeHead
- s.cosigned.SigIdent = append(s.tosign.SigIdent, cosignatures...)
-
- // Update to-sign tree head
- s.tosign = *next
- s.cosignature = make(map[[types.HashSize]byte]*types.SigIdent)
- glog.V(3).Infof("rotated sth")
-}
diff --git a/sth_test.go b/sth_test.go
deleted file mode 100644
index 0942ea1..0000000
--- a/sth_test.go
+++ /dev/null
@@ -1,466 +0,0 @@
-package stfe
-
-import (
- "context"
- "crypto"
- "fmt"
- "reflect"
- "testing"
-
- "github.com/golang/mock/gomock"
- cttestdata "github.com/google/certificate-transparency-go/trillian/testdata"
- "github.com/google/trillian"
- "github.com/system-transparency/stfe/testdata"
- "github.com/system-transparency/stfe/types"
-)
-
-func TestNewActiveSthSource(t *testing.T) {
- for _, table := range []struct {
- description string
- signer crypto.Signer
- trsp *trillian.GetLatestSignedLogRootResponse
- terr error
- wantErr bool
- wantCosi *types.StItem // current cosigned sth
- wantStable *types.StItem // next stable sth that signatures are collected for
- }{
- {
- description: "invalid: no Trillian response",
- signer: cttestdata.NewSignerWithFixedSig(nil, testdata.Signature),
- terr: fmt.Errorf("internal server error"),
- wantErr: true,
- },
- {
- description: "valid",
- signer: cttestdata.NewSignerWithFixedSig(nil, testdata.Signature),
- trsp: testdata.DefaultTSlr(t),
- wantCosi: testdata.DefaultCosth(t, testdata.Ed25519VkLog, nil),
- wantStable: testdata.DefaultCosth(t, testdata.Ed25519VkLog, nil),
- },
- } {
- func() { // run deferred functions at the end of each iteration
- ti := newTestInstance(t, table.signer)
- defer ti.ctrl.Finish()
- ti.client.EXPECT().GetLatestSignedLogRoot(newDeadlineMatcher(), gomock.Any()).Return(table.trsp, table.terr)
- source, err := NewActiveSthSource(ti.client, ti.instance.LogParameters)
- 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)
- }
- if err != nil {
- return
- }
-
- if got, want := source.currCosth, table.wantCosi; !reflect.DeepEqual(got, want) {
- t.Errorf("got cosigned sth\n%v\n\tbut wanted\n%v\n\tin test %q", got, want, table.description)
- }
- if got, want := source.nextCosth, table.wantStable; !reflect.DeepEqual(got, want) {
- t.Errorf("got stable sth\n%v\n\tbut wanted\n%v\n\tin test %q", got, want, table.description)
- }
- cosignatureFrom := make(map[[types.NamespaceFingerprintSize]byte]bool)
- for _, cosig := range table.wantStable.CosignedTreeHeadV1.Cosignatures {
- cosignatureFrom[testdata.Fingerprint(t, &cosig.Namespace)] = true
- }
- if got, want := source.cosignatureFrom, cosignatureFrom; !reflect.DeepEqual(got, want) {
- if got == nil {
- t.Errorf("got uninitialized witness map\n%v\n\tbut wanted\n%v\n\tin test %q", nil, want, table.description)
- } else {
- t.Errorf("got witness map\n%v\n\t but wanted\n%v\n\tin test %q", got, want, table.description)
- }
- }
- }()
- }
-}
-
-func TestLatest(t *testing.T) {
- for _, table := range []struct {
- description string
- signer crypto.Signer
- trsp *trillian.GetLatestSignedLogRootResponse
- terr error
- wantErr bool
- wantRsp *types.StItem
- }{
- {
- description: "invalid: no Trillian response",
- signer: cttestdata.NewSignerWithFixedSig(nil, testdata.Signature),
- terr: fmt.Errorf("internal server error"),
- wantErr: true,
- },
- {
- description: "invalid: no signature",
- signer: cttestdata.NewSignerWithErr(nil, fmt.Errorf("signing failed")),
- terr: fmt.Errorf("internal server error"),
- wantErr: true,
- },
- {
- description: "valid",
- signer: cttestdata.NewSignerWithFixedSig(nil, testdata.Signature),
- trsp: testdata.DefaultTSlr(t),
- wantRsp: testdata.DefaultSth(t, testdata.Ed25519VkLog),
- },
- } {
- func() { // run deferred functions at the end of each iteration
- ti := newTestInstance(t, table.signer)
- defer ti.ctrl.Finish()
- ti.client.EXPECT().GetLatestSignedLogRoot(gomock.Any(), gomock.Any()).Return(table.trsp, table.terr) // no deadline matcher because context is set by the caller of Latest(), i.e., this test on the line below
- sth, err := ti.instance.SthSource.Latest(context.Background())
- 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)
- }
- if err != nil {
- return
- }
- if got, want := sth, table.wantRsp; !reflect.DeepEqual(got, want) {
- t.Errorf("got\n%v\n\tbut wanted\n%v\n\t in test %q", got, want, table.description)
- }
- }()
- }
-}
-
-func TestStable(t *testing.T) {
- for _, table := range []struct {
- description string
- source SthSource
- wantRsp *types.StItem
- wantErr bool
- }{
- {
- description: "invalid: no stable sth",
- source: &ActiveSthSource{},
- wantErr: true,
- },
- {
- description: "valid",
- source: &ActiveSthSource{
- nextCosth: testdata.DefaultCosth(t, testdata.Ed25519VkLog, nil),
- },
- wantRsp: testdata.DefaultSth(t, testdata.Ed25519VkLog),
- },
- } {
- sth, err := table.source.Stable(context.Background())
- 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)
- }
- if err != nil {
- continue
- }
- if got, want := sth, table.wantRsp; !reflect.DeepEqual(got, want) {
- t.Errorf("got\n%v\n\t but wanted\n%v\n\t in test %q", got, want, table.description)
- }
- }
-}
-
-func TestCosigned(t *testing.T) {
- for _, table := range []struct {
- description string
- source SthSource
- wantRsp *types.StItem
- wantErr bool
- }{
- {
- description: "invalid: no cosigned sth: nil",
- source: &ActiveSthSource{},
- wantErr: true,
- },
- {
- description: "valid",
- source: &ActiveSthSource{
- currCosth: testdata.DefaultCosth(t, testdata.Ed25519VkLog, [][32]byte{testdata.Ed25519VkWitness}),
- },
- wantRsp: testdata.DefaultCosth(t, testdata.Ed25519VkLog, [][32]byte{testdata.Ed25519VkWitness}),
- },
- } {
- cosi, err := table.source.Cosigned(context.Background())
- 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)
- }
- if err != nil {
- continue
- }
- if got, want := cosi, table.wantRsp; !reflect.DeepEqual(got, want) {
- t.Errorf("got\n%v\n\tbut wanted\n%v\n\tin test %q", got, want, table.description)
- }
- }
-}
-
-func TestAddCosignature(t *testing.T) {
- for _, table := range []struct {
- description string
- source *ActiveSthSource
- req *types.StItem
- wantWit []*types.Namespace
- wantErr bool
- }{
- {
- description: "invalid: cosignature must target the stable sth",
- source: &ActiveSthSource{
- nextCosth: testdata.DefaultCosth(t, testdata.Ed25519VkLog, nil),
- cosignatureFrom: make(map[[types.NamespaceFingerprintSize]byte]bool),
- },
- req: testdata.DefaultCosth(t, testdata.Ed25519VkLog2, [][32]byte{testdata.Ed25519VkWitness}),
- wantErr: true,
- },
- {
- description: "valid: adding duplicate into a pool of cosignatures",
- source: &ActiveSthSource{
- nextCosth: testdata.DefaultCosth(t, testdata.Ed25519VkLog, [][32]byte{testdata.Ed25519VkWitness}),
- cosignatureFrom: map[[types.NamespaceFingerprintSize]byte]bool{
- testdata.Fingerprint(t, testdata.NewNamespace(t, testdata.Ed25519VkWitness)): true,
- },
- },
- req: testdata.DefaultCosth(t, testdata.Ed25519VkLog, [][32]byte{testdata.Ed25519VkWitness}),
- wantWit: []*types.Namespace{testdata.NewNamespace(t, testdata.Ed25519VkWitness)},
- },
- {
- description: "valid: adding into an empty pool of cosignatures",
- source: &ActiveSthSource{
- nextCosth: testdata.DefaultCosth(t, testdata.Ed25519VkLog, nil),
- cosignatureFrom: make(map[[types.NamespaceFingerprintSize]byte]bool),
- },
- req: testdata.DefaultCosth(t, testdata.Ed25519VkLog, [][32]byte{testdata.Ed25519VkWitness}),
- wantWit: []*types.Namespace{testdata.NewNamespace(t, testdata.Ed25519VkWitness)},
- },
- {
- description: "valid: adding into a pool of cosignatures",
- source: &ActiveSthSource{
- nextCosth: testdata.DefaultCosth(t, testdata.Ed25519VkLog, [][32]byte{testdata.Ed25519VkWitness}),
- cosignatureFrom: map[[types.NamespaceFingerprintSize]byte]bool{
- testdata.Fingerprint(t, testdata.NewNamespace(t, testdata.Ed25519VkWitness)): true,
- },
- },
- req: testdata.DefaultCosth(t, testdata.Ed25519VkLog, [][32]byte{testdata.Ed25519VkWitness2}),
- wantWit: []*types.Namespace{testdata.NewNamespace(t, testdata.Ed25519VkWitness), testdata.NewNamespace(t, testdata.Ed25519VkWitness2)},
- },
- } {
- err := table.source.AddCosignature(context.Background(), table.req)
- 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)
- }
- if err != nil {
- continue
- }
-
- // Check that the next cosigned sth is updated
- var sigs []types.SignatureV1
- for _, wit := range table.wantWit {
- sigs = append(sigs, types.SignatureV1{
- Namespace: *wit,
- Signature: testdata.Signature,
- })
- }
- if got, want := table.source.nextCosth, types.NewCosignedTreeHeadV1(testdata.DefaultSth(t, testdata.Ed25519VkLog).SignedTreeHeadV1, sigs); !reflect.DeepEqual(got, want) {
- t.Errorf("got\n%v\n\tbut wanted\n%v\n\tin test %q", got, want, table.description)
- }
- // Check that the map tracking witness signatures is updated
- if got, want := len(table.source.cosignatureFrom), len(table.wantWit); got != want {
- t.Errorf("witness map got %d cosignatures but wanted %d in test %q", got, want, table.description)
- } else {
- for _, wit := range table.wantWit {
- if _, ok := table.source.cosignatureFrom[testdata.Fingerprint(t, wit)]; !ok {
- t.Errorf("missing signature from witness %X in test %q", testdata.Fingerprint(t, wit), table.description)
- }
- }
- }
- }
-}
-
-func TestRotate(t *testing.T) {
- // distinct sths
- sth1 := testdata.DefaultSth(t, testdata.Ed25519VkLog)
- sth2 := testdata.DefaultSth(t, testdata.Ed25519VkLog2)
- sth3 := testdata.DefaultSth(t, testdata.Ed25519VkLog3)
- // distinct witnesses
- wit1 := testdata.NewNamespace(t, testdata.Ed25519VkWitness)
- wit2 := testdata.NewNamespace(t, testdata.Ed25519VkWitness2)
- wit3 := testdata.NewNamespace(t, testdata.Ed25519VkWitness3)
- for _, table := range []struct {
- description string
- source *ActiveSthSource
- fixedSth *types.StItem
- wantCurrSth *types.StItem
- wantNextSth *types.StItem
- wantWit []*types.Namespace
- }{
- {
- description: "not repeated cosigned and not repeated stable",
- source: &ActiveSthSource{
- currCosth: types.NewCosignedTreeHeadV1(sth1.SignedTreeHeadV1, nil),
- nextCosth: types.NewCosignedTreeHeadV1(sth2.SignedTreeHeadV1, []types.SignatureV1{
- types.SignatureV1{
- Namespace: *wit1,
- Signature: testdata.Signature,
- },
- }),
- cosignatureFrom: map[[types.NamespaceFingerprintSize]byte]bool{
- testdata.Fingerprint(t, wit1): true,
- },
- },
- fixedSth: sth3,
- wantCurrSth: types.NewCosignedTreeHeadV1(sth2.SignedTreeHeadV1, []types.SignatureV1{
- types.SignatureV1{
- Namespace: *wit1,
- Signature: testdata.Signature,
- },
- }),
- wantNextSth: types.NewCosignedTreeHeadV1(sth3.SignedTreeHeadV1, nil),
- wantWit: nil, // no cosignatures for the next stable sth yet
- },
- {
- description: "not repeated cosigned and repeated stable",
- source: &ActiveSthSource{
- currCosth: types.NewCosignedTreeHeadV1(sth1.SignedTreeHeadV1, nil),
- nextCosth: types.NewCosignedTreeHeadV1(sth2.SignedTreeHeadV1, []types.SignatureV1{
- types.SignatureV1{
- Namespace: *wit1,
- Signature: testdata.Signature,
- },
- }),
- cosignatureFrom: map[[types.NamespaceFingerprintSize]byte]bool{
- testdata.Fingerprint(t, wit1): true,
- },
- },
- fixedSth: sth2,
- wantCurrSth: types.NewCosignedTreeHeadV1(sth2.SignedTreeHeadV1, []types.SignatureV1{
- types.SignatureV1{
- Namespace: *wit1,
- Signature: testdata.Signature,
- },
- }),
- wantNextSth: types.NewCosignedTreeHeadV1(sth2.SignedTreeHeadV1, []types.SignatureV1{
- types.SignatureV1{
- Namespace: *wit1,
- Signature: testdata.Signature,
- },
- }),
- wantWit: []*types.Namespace{wit1},
- },
- {
- description: "repeated cosigned and not repeated stable",
- source: &ActiveSthSource{
- currCosth: types.NewCosignedTreeHeadV1(sth1.SignedTreeHeadV1, []types.SignatureV1{
- types.SignatureV1{
- Namespace: *wit1,
- Signature: testdata.Signature,
- },
- types.SignatureV1{
- Namespace: *wit2,
- Signature: testdata.Signature,
- },
- }),
- nextCosth: types.NewCosignedTreeHeadV1(sth1.SignedTreeHeadV1, []types.SignatureV1{
- types.SignatureV1{
- Namespace: *wit2,
- Signature: testdata.Signature,
- },
- types.SignatureV1{
- Namespace: *wit3,
- Signature: testdata.Signature,
- },
- }),
- cosignatureFrom: map[[types.NamespaceFingerprintSize]byte]bool{
- testdata.Fingerprint(t, wit2): true,
- testdata.Fingerprint(t, wit3): true,
- },
- },
- fixedSth: sth3,
- wantCurrSth: types.NewCosignedTreeHeadV1(sth1.SignedTreeHeadV1, []types.SignatureV1{
- types.SignatureV1{
- Namespace: *wit2,
- Signature: testdata.Signature,
- },
- types.SignatureV1{
- Namespace: *wit3,
- Signature: testdata.Signature,
- },
- types.SignatureV1{
- Namespace: *wit1,
- Signature: testdata.Signature,
- },
- }),
- wantNextSth: types.NewCosignedTreeHeadV1(sth3.SignedTreeHeadV1, nil),
- wantWit: nil, // no cosignatures for the next stable sth yet
- },
- {
- description: "repeated cosigned and repeated stable",
- source: &ActiveSthSource{
- currCosth: types.NewCosignedTreeHeadV1(sth1.SignedTreeHeadV1, []types.SignatureV1{
- types.SignatureV1{
- Namespace: *wit1,
- Signature: testdata.Signature,
- },
- types.SignatureV1{
- Namespace: *wit2,
- Signature: testdata.Signature,
- },
- }),
- nextCosth: types.NewCosignedTreeHeadV1(sth1.SignedTreeHeadV1, []types.SignatureV1{
- types.SignatureV1{
- Namespace: *wit2,
- Signature: testdata.Signature,
- },
- types.SignatureV1{
- Namespace: *wit3,
- Signature: testdata.Signature,
- },
- }),
- cosignatureFrom: map[[types.NamespaceFingerprintSize]byte]bool{
- testdata.Fingerprint(t, wit2): true,
- testdata.Fingerprint(t, wit3): true,
- },
- },
- fixedSth: sth1,
- wantCurrSth: types.NewCosignedTreeHeadV1(sth1.SignedTreeHeadV1, []types.SignatureV1{
- types.SignatureV1{
- Namespace: *wit2,
- Signature: testdata.Signature,
- },
- types.SignatureV1{
- Namespace: *wit3,
- Signature: testdata.Signature,
- },
- types.SignatureV1{
- Namespace: *wit1,
- Signature: testdata.Signature,
- },
- }),
- wantNextSth: types.NewCosignedTreeHeadV1(sth1.SignedTreeHeadV1, []types.SignatureV1{
- types.SignatureV1{
- Namespace: *wit2,
- Signature: testdata.Signature,
- },
- types.SignatureV1{
- Namespace: *wit3,
- Signature: testdata.Signature,
- },
- types.SignatureV1{
- Namespace: *wit1,
- Signature: testdata.Signature,
- },
- }),
- wantWit: []*types.Namespace{wit1, wit2, wit3},
- },
- } {
- table.source.rotate(table.fixedSth)
- if got, want := table.source.currCosth, table.wantCurrSth; !reflect.DeepEqual(got, want) {
- t.Errorf("got currCosth\n%v\n\tbut wanted \n%v\n\tin test %q", got, want, table.description)
- }
- if got, want := table.source.nextCosth, table.wantNextSth; !reflect.DeepEqual(got, want) {
- t.Errorf("got nextCosth\n%v\n\tbut wanted\n%v\n\tin test %q", got, want, table.description)
- }
- if got, want := len(table.source.cosignatureFrom), len(table.wantWit); got != want {
- t.Errorf("witness map got %d cosignatures but wanted %d in test %q", got, want, table.description)
- } else {
- for _, wit := range table.wantWit {
- if _, ok := table.source.cosignatureFrom[testdata.Fingerprint(t, wit)]; !ok {
- t.Errorf("missing signature from witness %X in test %q", testdata.Fingerprint(t, wit), table.description)
- }
- }
- }
- // check that adding cosignatures to stable will not effect cosigned sth
- wantLen := len(table.source.currCosth.CosignedTreeHeadV1.Cosignatures)
- table.source.nextCosth.CosignedTreeHeadV1.Cosignatures = append(table.source.nextCosth.CosignedTreeHeadV1.Cosignatures, types.SignatureV1{Namespace: *wit1, Signature: testdata.Signature})
- if gotLen := len(table.source.currCosth.CosignedTreeHeadV1.Cosignatures); gotLen != wantLen {
- t.Errorf("adding cosignatures to the stable sth modifies the fixated cosigned sth in test %q", table.description)
- }
- }
-}
diff --git a/testdata/data.go b/testdata/data.go
deleted file mode 100644
index ac958e5..0000000
--- a/testdata/data.go
+++ /dev/null
@@ -1,287 +0,0 @@
-package testdata
-
-import (
- "bytes"
- "testing"
- "time"
-
- "crypto/ed25519"
-
- "github.com/google/trillian"
- ttypes "github.com/google/trillian/types"
- "github.com/system-transparency/stfe/types"
- "google.golang.org/grpc/codes"
- "google.golang.org/grpc/status"
-)
-
-var (
- Ed25519VkLog = [32]byte{}
- Ed25519VkLog2 = [32]byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}
- Ed25519VkLog3 = [32]byte{2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}
- //Ed25519VkWitness = [32]byte{3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3}
- // Ed25519VkWitness2 = [32]byte{4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4}
- Ed25519VkWitness3 = [32]byte{5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5}
- //Ed25519VkSubmitter = [32]byte{6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6}
-
- TreeId = int64(0)
- Prefix = "test"
- MaxRange = int64(3)
- Interval = time.Second * 10
- Deadline = time.Second * 5
-
- Timestamp = uint64(0)
- TreeSize = uint64(0)
- Extension = make([]byte, 0)
- NodeHash = make([]byte, 32)
- Signature = make([]byte, 64)
- Identifier = []byte("foobar-1.2.3")
- Checksum = make([]byte, 32)
- Index = int64(0)
- HashPath = [][]byte{
- NodeHash,
- }
- NodePath = []types.NodeHash{
- types.NodeHash{NodeHash},
- }
- LeafHash = [32]byte{}
-
- // TODO: make these unique and load more pretty maybe
- Ed25519SkWitness = [64]byte{230, 122, 195, 152, 194, 195, 147, 153, 80, 120, 153, 79, 102, 27, 52, 187, 136, 218, 150, 234, 107, 9, 167, 4, 92, 21, 11, 113, 42, 29, 129, 69, 75, 60, 249, 150, 229, 93, 75, 32, 103, 126, 244, 37, 53, 182, 68, 82, 249, 109, 49, 94, 10, 19, 146, 244, 58, 191, 169, 107, 78, 37, 45, 210}
- Ed25519VkWitness = [32]byte{75, 60, 249, 150, 229, 93, 75, 32, 103, 126, 244, 37, 53, 182, 68, 82, 249, 109, 49, 94, 10, 19, 146, 244, 58, 191, 169, 107, 78, 37, 45, 210}
-
- Ed25519SkWitness2 = [64]byte{98, 65, 92, 117, 33, 167, 138, 36, 252, 147, 87, 173, 44, 62, 17, 66, 126, 70, 218, 87, 91, 148, 64, 194, 241, 248, 62, 90, 140, 122, 234, 76, 144, 6, 250, 185, 37, 217, 77, 201, 180, 42, 81, 37, 165, 27, 22, 32, 25, 8, 156, 228, 78, 207, 208, 18, 91, 77, 189, 51, 112, 31, 237, 6}
- Ed25519VkWitness2 = [32]byte{144, 6, 250, 185, 37, 217, 77, 201, 180, 42, 81, 37, 165, 27, 22, 32, 25, 8, 156, 228, 78, 207, 208, 18, 91, 77, 189, 51, 112, 31, 237, 6}
-
- Ed25519SkSubmitter = [64]byte{230, 122, 195, 152, 194, 195, 147, 153, 80, 120, 153, 79, 102, 27, 52, 187, 136, 218, 150, 234, 107, 9, 167, 4, 92, 21, 11, 113, 42, 29, 129, 69, 75, 60, 249, 150, 229, 93, 75, 32, 103, 126, 244, 37, 53, 182, 68, 82, 249, 109, 49, 94, 10, 19, 146, 244, 58, 191, 169, 107, 78, 37, 45, 210}
- Ed25519VkSubmitter = [32]byte{75, 60, 249, 150, 229, 93, 75, 32, 103, 126, 244, 37, 53, 182, 68, 82, 249, 109, 49, 94, 10, 19, 146, 244, 58, 191, 169, 107, 78, 37, 45, 210}
- Ed25519SkSubmitter2 = [64]byte{98, 65, 92, 117, 33, 167, 138, 36, 252, 147, 87, 173, 44, 62, 17, 66, 126, 70, 218, 87, 91, 148, 64, 194, 241, 248, 62, 90, 140, 122, 234, 76, 144, 6, 250, 185, 37, 217, 77, 201, 180, 42, 81, 37, 165, 27, 22, 32, 25, 8, 156, 228, 78, 207, 208, 18, 91, 77, 189, 51, 112, 31, 237, 6}
- Ed25519VkSubmitter2 = [32]byte{144, 6, 250, 185, 37, 217, 77, 201, 180, 42, 81, 37, 165, 27, 22, 32, 25, 8, 156, 228, 78, 207, 208, 18, 91, 77, 189, 51, 112, 31, 237, 6}
-)
-
-// TODO: reorder and docdoc where need be
-//
-// Helpers that must create default values for different STFE types
-//
-
-func DefaultCosth(t *testing.T, logVk [32]byte, witVk [][32]byte) *types.StItem {
- t.Helper()
- cosigs := make([]types.SignatureV1, 0)
- for _, vk := range witVk {
- cosigs = append(cosigs, types.SignatureV1{*NewNamespace(t, vk), Signature})
- }
- return types.NewCosignedTreeHeadV1(DefaultSth(t, logVk).SignedTreeHeadV1, cosigs)
-}
-
-func DefaultSth(t *testing.T, vk [32]byte) *types.StItem {
- t.Helper()
- return types.NewSignedTreeHeadV1(DefaultTh(t), DefaultSig(t, vk))
-}
-
-func DefaultSignedChecksum(t *testing.T, vk [32]byte) *types.StItem {
- t.Helper()
- return types.NewSignedChecksumV1(DefaultChecksum(t), DefaultSig(t, vk))
-}
-
-func DefaultTh(t *testing.T) *types.TreeHeadV1 {
- t.Helper()
- return types.NewTreeHeadV1(Timestamp, TreeSize, NodeHash, Extension)
-}
-
-func DefaultSig(t *testing.T, vk [32]byte) *types.SignatureV1 {
- t.Helper()
- return &types.SignatureV1{*NewNamespace(t, vk), Signature}
-}
-
-func DefaultChecksum(t *testing.T) *types.ChecksumV1 {
- t.Helper()
- return &types.ChecksumV1{Identifier, Checksum}
-}
-
-func AddCosignatureBuffer(t *testing.T, sth *types.StItem, sk *[64]byte, vk *[32]byte) *bytes.Buffer {
- t.Helper()
- var cosigs []types.SignatureV1
- if vk != nil {
- cosigs = []types.SignatureV1{
- types.SignatureV1{
- Namespace: *NewNamespace(t, *vk),
- Signature: ed25519.Sign(ed25519.PrivateKey((*sk)[:]), marshal(t, *sth.SignedTreeHeadV1)),
- },
- }
- }
- return bytes.NewBuffer(marshal(t, *types.NewCosignedTreeHeadV1(sth.SignedTreeHeadV1, cosigs)))
-}
-
-func AddSignedChecksumBuffer(t *testing.T, sk [64]byte, vk [32]byte) *bytes.Buffer {
- t.Helper()
- data := DefaultChecksum(t)
- return bytes.NewBuffer(marshal(t, *types.NewSignedChecksumV1(
- data,
- &types.SignatureV1{
- Namespace: *NewNamespace(t, vk),
- Signature: ed25519.Sign(ed25519.PrivateKey(sk[:]), marshal(t, *data)),
- },
- )))
-}
-
-func NewNamespacePool(t *testing.T, namespaces []*types.Namespace) *types.NamespacePool {
- pool, err := types.NewNamespacePool(namespaces)
- if err != nil {
- t.Fatalf("must make namespace pool: %v", err)
- }
- return pool
-}
-
-func NewNamespace(t *testing.T, vk [32]byte) *types.Namespace {
- namespace, err := types.NewNamespaceEd25519V1(vk[:])
- if err != nil {
- t.Fatalf("must make Ed25519V1 namespace: %v", err)
- }
- return namespace
-}
-
-//
-// Helpers that must create default values for different Trillian types
-//
-
-// DefaultTLr creates a default Trillian log root
-func DefaultTLr(t *testing.T) *ttypes.LogRootV1 {
- t.Helper()
- return Tlr(t, TreeSize, Timestamp, NodeHash)
-}
-
-// Tlr creates a Trillian log root
-func Tlr(t *testing.T, size, timestamp uint64, hash []byte) *ttypes.LogRootV1 {
- t.Helper()
- return &ttypes.LogRootV1{
- TreeSize: size,
- RootHash: hash,
- TimestampNanos: timestamp,
- Revision: 0, // not used by stfe
- Metadata: nil, // not used by stfe
- }
-}
-
-// DefaultTSlr creates a default Trillian signed log root
-func DefaultTSlr(t *testing.T) *trillian.GetLatestSignedLogRootResponse {
- t.Helper()
- return Tslr(t, DefaultTLr(t))
-}
-
-// Tslr creates a Trillian signed log root
-func Tslr(t *testing.T, lr *ttypes.LogRootV1) *trillian.GetLatestSignedLogRootResponse {
- t.Helper()
- b, err := lr.MarshalBinary()
- if err != nil {
- t.Fatalf("must marshal Trillian log root: %v", err)
- }
- return &trillian.GetLatestSignedLogRootResponse{
- SignedLogRoot: &trillian.SignedLogRoot{
- KeyHint: nil, // not used by stfe
- LogRoot: b,
- LogRootSignature: nil, // not used by stfe
- },
- Proof: nil, // not used by stfe
- }
-}
-
-// DefaultTQlr creates a default Trillian queue leaf response
-func DefaultTQlr(t *testing.T, withDupCode bool) *trillian.QueueLeafResponse {
- t.Helper()
- s := status.New(codes.OK, "ok").Proto()
- if withDupCode {
- s = status.New(codes.AlreadyExists, "duplicate").Proto()
- }
- return &trillian.QueueLeafResponse{
- QueuedLeaf: &trillian.QueuedLogLeaf{
- Leaf: &trillian.LogLeaf{
- MerkleLeafHash: nil, // not used by stfe
- LeafValue: marshal(t, *DefaultSignedChecksum(t, Ed25519VkSubmitter)),
- ExtraData: nil, // not used by stfe
- LeafIndex: 0, // not applicable (log is not pre-ordered)
- LeafIdentityHash: nil, // not used by stfe
- },
- Status: s,
- },
- }
-}
-
-// DefaultTglbrr creates a default Trillian get leaves by range response
-func DefaultTGlbrr(t *testing.T, start, end int64) *trillian.GetLeavesByRangeResponse {
- t.Helper()
- leaves := make([]*trillian.LogLeaf, 0, end-start+1)
- for i, n := start, end+1; i < n; i++ {
- leaves = append(leaves, &trillian.LogLeaf{
- MerkleLeafHash: nil, // not usedb y stfe
- LeafValue: marshal(t, *DefaultSignedChecksum(t, Ed25519VkSubmitter)),
- ExtraData: nil, // not used by stfe
- LeafIndex: i,
- LeafIdentityHash: nil, // not used by stfe
- })
- }
- return &trillian.GetLeavesByRangeResponse{
- Leaves: leaves,
- SignedLogRoot: Tslr(t, Tlr(t, uint64(end)+1, Timestamp, NodeHash)).SignedLogRoot,
- }
-}
-
-func DefaultStItemList(t *testing.T, start, end uint64) *types.StItemList {
- items := make([]types.StItem, 0, end-start+1)
- for i, n := start, end+1; i < n; i++ {
- items = append(items, *DefaultSignedChecksum(t, Ed25519VkSubmitter))
- }
- return &types.StItemList{items}
-}
-
-// DefaultTGipbhr creates a default Trillian get inclusion proof by hash response
-func DefaultTGipbhr(t *testing.T) *trillian.GetInclusionProofByHashResponse {
- t.Helper()
- return &trillian.GetInclusionProofByHashResponse{
- Proof: []*trillian.Proof{
- &trillian.Proof{
- LeafIndex: Index,
- Hashes: HashPath,
- },
- },
- SignedLogRoot: nil, // not used by stfe
- }
-}
-
-func DefaultInclusionProof(t *testing.T, size uint64) *types.StItem {
- return types.NewInclusionProofV1(NewNamespace(t, Ed25519VkLog), size, uint64(Index), NodePath)
-}
-
-// DefaultTGcpr creates a default Trillian get consistency proof response
-func DefaultTGcpr(t *testing.T) *trillian.GetConsistencyProofResponse {
- t.Helper()
- return &trillian.GetConsistencyProofResponse{
- Proof: &trillian.Proof{
- LeafIndex: 0, // not applicable for consistency proofs
- Hashes: HashPath,
- },
- SignedLogRoot: nil, // not used by stfe
- }
-}
-
-func DefaultConsistencyProof(t *testing.T, first, second uint64) *types.StItem {
- return types.NewConsistencyProofV1(NewNamespace(t, Ed25519VkLog), first, second, NodePath)
-}
-
-//
-// Other helpers
-//
-
-func Fingerprint(t *testing.T, namespace *types.Namespace) [types.NamespaceFingerprintSize]byte {
- fpr, err := namespace.Fingerprint()
- if err != nil {
- t.Fatalf("must have namespace fingerprint: %v", err)
- }
- return *fpr
-}
-
-func marshal(t *testing.T, i interface{}) []byte {
- b, err := types.Marshal(i)
- if err != nil {
- t.Fatalf("must marshal interface: %v", err)
- }
- return b
-}
diff --git a/trillian.go b/trillian.go
deleted file mode 100644
index f358d4d..0000000
--- a/trillian.go
+++ /dev/null
@@ -1,125 +0,0 @@
-package stfe
-
-import (
- "fmt"
-
- "github.com/golang/glog"
- "github.com/google/trillian"
- "github.com/google/trillian/types"
- stfetypes "github.com/system-transparency/stfe/types"
- "google.golang.org/grpc/codes"
-)
-
-func checkQueueLeaf(rsp *trillian.QueueLeafResponse, err error) error {
- if err != nil {
- return fmt.Errorf("Trillian error: %v", err)
- }
- if rsp == nil {
- return fmt.Errorf("Trillian error: empty response")
- }
- if rsp.QueuedLeaf == nil {
- return fmt.Errorf("Trillian error: empty QueuedLeaf")
- }
- if codes.Code(rsp.QueuedLeaf.GetStatus().GetCode()) == codes.AlreadyExists {
- glog.V(3).Infof("queued leaf is a duplicate => %X", rsp.QueuedLeaf.Leaf.LeafValue)
- }
- return nil
-}
-
-func checkGetLeavesByRange(req *stfetypes.LeavesRequest, rsp *trillian.GetLeavesByRangeResponse, err error) error {
- if err != nil {
- return fmt.Errorf("Trillian Error: %v", err)
- }
- if rsp == nil {
- return fmt.Errorf("Trillian error: empty response")
- }
- if rsp.SignedLogRoot == nil {
- return fmt.Errorf("Trillian error: no signed log root")
- }
- if rsp.SignedLogRoot.LogRoot == nil {
- return fmt.Errorf("Trillian error: no log root")
- }
- if len(rsp.Leaves) == 0 {
- return fmt.Errorf("Trillian error: no leaves")
- }
- if len(rsp.Leaves) > int(req.EndSize-req.StartSize+1) {
- return fmt.Errorf("too many leaves: %d for [%d,%d]", len(rsp.Leaves), req.StartSize, req.EndSize)
- }
-
- // Ensure that a bad start parameter results in an error
- var lr types.LogRootV1
- if err := lr.UnmarshalBinary(rsp.SignedLogRoot.LogRoot); err != nil {
- return fmt.Errorf("cannot unmarshal log root: %v", err)
- }
- if uint64(req.StartSize) >= lr.TreeSize {
- return fmt.Errorf("invalid start(%d): tree size is %d", req.StartSize, lr.TreeSize)
- }
-
- // Ensure that we got and return expected leaf indices
- for i, leaf := range rsp.Leaves {
- if got, want := leaf.LeafIndex, int64(req.StartSize+uint64(i)); got != want {
- return fmt.Errorf("invalid leaf index(%d): wanted %d", got, want)
- }
- }
- return nil
-}
-
-func checkGetInclusionProofByHash(lp *LogParameters, rsp *trillian.GetInclusionProofByHashResponse, err error) error {
- if err != nil {
- return fmt.Errorf("Trillian Error: %v", err)
- }
- if rsp == nil {
- return fmt.Errorf("Trillian error: empty response")
- }
- if len(rsp.Proof) == 0 {
- return fmt.Errorf("Trillian error: no proofs")
- }
- if rsp.Proof[0] == nil {
- return fmt.Errorf("Trillian error: no proof")
- }
- return checkHashPath(lp.HashType.Size(), rsp.Proof[0].Hashes)
-}
-
-func checkGetConsistencyProof(lp *LogParameters, rsp *trillian.GetConsistencyProofResponse, err error) error {
- if err != nil {
- return fmt.Errorf("Trillian Error: %v", err)
- }
- if rsp == nil {
- return fmt.Errorf("Trillian error: empty response")
- }
- if rsp.Proof == nil {
- return fmt.Errorf("Trillian error: no proof")
- }
- return checkHashPath(lp.HashType.Size(), rsp.Proof.Hashes)
-}
-
-func checkGetLatestSignedLogRoot(lp *LogParameters, rsp *trillian.GetLatestSignedLogRootResponse, err error, out *types.LogRootV1) error {
- if err != nil {
- return fmt.Errorf("Trillian Error: %v", err)
- }
- if rsp == nil {
- return fmt.Errorf("Trillian error: empty response")
- }
- if rsp.SignedLogRoot == nil {
- return fmt.Errorf("Trillian error: no signed log root")
- }
- if rsp.SignedLogRoot.LogRoot == nil {
- return fmt.Errorf("Trillian error: no log root")
- }
- if err := out.UnmarshalBinary(rsp.SignedLogRoot.LogRoot); err != nil {
- return fmt.Errorf("cannot unmarshal log root: %v", err)
- }
- if len(out.RootHash) != lp.HashType.Size() {
- return fmt.Errorf("invalid root hash: %v", out.RootHash)
- }
- return nil
-}
-
-func checkHashPath(hashSize int, path [][]byte) error {
- for _, hash := range path {
- if len(hash) != hashSize {
- return fmt.Errorf("invalid proof: %v", path)
- }
- }
- return nil
-}
diff --git a/trillian_test.go b/trillian_test.go
deleted file mode 100644
index 1b0c923..0000000
--- a/trillian_test.go
+++ /dev/null
@@ -1,282 +0,0 @@
-package stfe
-
-import (
- "fmt"
- "testing"
-
- "github.com/google/trillian"
- ttypes "github.com/google/trillian/types"
- "github.com/system-transparency/stfe/testdata"
- "github.com/system-transparency/stfe/types"
-)
-
-func TestCheckQueueLeaf(t *testing.T) {
- for _, table := range []struct {
- description string
- rsp *trillian.QueueLeafResponse
- err error
- wantErr bool
- }{
- {
- description: "invalid: no Trillian response: error",
- err: fmt.Errorf("backend error"),
- wantErr: true,
- },
- {
- description: "invalid: no Trillian response: nil",
- wantErr: true,
- },
- {
- description: "invalid: no Trillian response: empty",
- rsp: &trillian.QueueLeafResponse{},
- wantErr: true,
- },
- {
- description: "valid: gRPC status: duplicate",
- rsp: testdata.DefaultTQlr(t, true),
- },
- {
- description: "valid: gRPC status: ok",
- rsp: testdata.DefaultTQlr(t, false),
- },
- } {
- err := checkQueueLeaf(table.rsp, table.err)
- if got, want := err != nil, table.wantErr; got != want {
- t.Errorf("got error %v but wanted %v in test %q", got, want, table.description)
- }
- }
-}
-
-func TestCheckGetLeavesByRange(t *testing.T) {
- for _, table := range []struct {
- description string
- req *types.GetEntriesV1
- rsp *trillian.GetLeavesByRangeResponse
- err error
- wantErr bool
- }{
- {
- description: "invalid: no Trillian response: error",
- req: &types.GetEntriesV1{Start: 0, End: 1},
- err: fmt.Errorf("backend error"),
- wantErr: true,
- },
- {
- description: "invalid: no Trillian response: nil",
- req: &types.GetEntriesV1{Start: 0, End: 1},
- wantErr: true,
- },
- {
- description: "invalid: bad Trillian response: no leaves",
- req: &types.GetEntriesV1{Start: 0, End: 1},
- rsp: func(rsp *trillian.GetLeavesByRangeResponse) *trillian.GetLeavesByRangeResponse {
- rsp.Leaves = nil
- return rsp
- }(testdata.DefaultTGlbrr(t, 0, 1)),
- wantErr: true,
- },
- {
- description: "invalid: bad Trillian response: no signed log root",
- req: &types.GetEntriesV1{Start: 0, End: 1},
- rsp: func(rsp *trillian.GetLeavesByRangeResponse) *trillian.GetLeavesByRangeResponse {
- rsp.SignedLogRoot = nil
- return rsp
- }(testdata.DefaultTGlbrr(t, 0, 1)),
- wantErr: true,
- },
- {
- description: "invalid: bad Trillian response: no log root",
- req: &types.GetEntriesV1{Start: 0, End: 1},
- rsp: func(rsp *trillian.GetLeavesByRangeResponse) *trillian.GetLeavesByRangeResponse {
- rsp.SignedLogRoot.LogRoot = nil
- return rsp
- }(testdata.DefaultTGlbrr(t, 0, 1)),
- wantErr: true,
- },
- {
- description: "invalid: bad Trillian response: truncated log root",
- req: &types.GetEntriesV1{Start: 0, End: 1},
- rsp: func(rsp *trillian.GetLeavesByRangeResponse) *trillian.GetLeavesByRangeResponse {
- rsp.SignedLogRoot.LogRoot = rsp.SignedLogRoot.LogRoot[1:]
- return rsp
- }(testdata.DefaultTGlbrr(t, 0, 1)),
- wantErr: true,
- },
- {
- description: "invalid: bad Trillian response: too many leaves",
- req: &types.GetEntriesV1{Start: 0, End: 1},
- rsp: testdata.DefaultTGlbrr(t, 0, 2),
- wantErr: true,
- },
- {
- description: "invalid: bad Trillian response: start is not a valid index",
- req: &types.GetEntriesV1{Start: 10, End: 10},
- rsp: testdata.DefaultTGlbrr(t, 9, 9),
- wantErr: true,
- },
- {
- description: "invalid: bad Trillian response: invalid leaf indices",
- req: &types.GetEntriesV1{Start: 10, End: 11},
- rsp: testdata.DefaultTGlbrr(t, 11, 12),
- wantErr: true,
- },
- {
- description: "valid",
- req: &types.GetEntriesV1{Start: 10, End: 20},
- rsp: testdata.DefaultTGlbrr(t, 10, 20),
- },
- } {
- err := checkGetLeavesByRange(table.req, table.rsp, table.err)
- if got, want := err != nil, table.wantErr; got != want {
- t.Errorf("got error %v but wanted %v in test %q", got, want, table.description)
- }
- }
-}
-
-func TestCheckGetInclusionProofByHash(t *testing.T) {
- for _, table := range []struct {
- description string
- rsp *trillian.GetInclusionProofByHashResponse
- err error
- wantErr bool
- }{
- {
- description: "invalid: no Trillian response: error",
- err: fmt.Errorf("backend failure"),
- wantErr: true,
- },
- {
- description: "invalid: no Trillian response: nil",
- wantErr: true,
- },
- {
- description: "invalid: bad Trillian response: no proofs",
- rsp: &trillian.GetInclusionProofByHashResponse{},
- wantErr: true,
- },
- {
- description: "bad response: no proof",
- rsp: func(rsp *trillian.GetInclusionProofByHashResponse) *trillian.GetInclusionProofByHashResponse {
- rsp.Proof[0] = nil
- return rsp
- }(testdata.DefaultTGipbhr(t)),
- wantErr: true,
- },
- {
- description: "bad response: proof with invalid node hash",
- rsp: func(rsp *trillian.GetInclusionProofByHashResponse) *trillian.GetInclusionProofByHashResponse {
- rsp.Proof[0].Hashes = append(rsp.Proof[0].Hashes, make([]byte, 0))
- return rsp
- }(testdata.DefaultTGipbhr(t)),
- wantErr: true,
- },
- {
- description: "valid",
- rsp: testdata.DefaultTGipbhr(t),
- },
- } {
- err := checkGetInclusionProofByHash(newLogParameters(t, nil), table.rsp, table.err)
- if got, want := err != nil, table.wantErr; got != want {
- t.Errorf("got error %v but wanted %v in test %q", got, want, table.description)
- }
- }
-}
-
-func TestCheckGetConsistencyProof(t *testing.T) {
- for _, table := range []struct {
- description string
- rsp *trillian.GetConsistencyProofResponse
- err error
- wantErr bool
- }{
- {
- description: "invalid: no Trillian response: error",
- err: fmt.Errorf("backend failure"),
- wantErr: true,
- },
- {
- description: "invalid: no Trillian response: nil",
- wantErr: true,
- },
- {
- description: "invalid: bad Trillian response: no proof",
- rsp: &trillian.GetConsistencyProofResponse{},
- wantErr: true,
- },
- {
- description: "invalid: bad Trillian response: proof with invalid node hash",
- rsp: func(rsp *trillian.GetConsistencyProofResponse) *trillian.GetConsistencyProofResponse {
- rsp.Proof.Hashes = append(rsp.Proof.Hashes, make([]byte, 0))
- return rsp
- }(testdata.DefaultTGcpr(t)),
- wantErr: true,
- },
- {
- description: "valid",
- rsp: testdata.DefaultTGcpr(t),
- },
- } {
- err := checkGetConsistencyProof(newLogParameters(t, nil), table.rsp, table.err)
- if got, want := err != nil, table.wantErr; got != want {
- t.Errorf("got error %v but wanted %v in test %q", got, want, table.description)
- }
- }
-}
-
-func TestCheckGetLatestSignedLogRoot(t *testing.T) {
- for _, table := range []struct {
- description string
- rsp *trillian.GetLatestSignedLogRootResponse
- err error
- wantErr bool
- }{
- {
- description: "invalid: no Trillian response: error",
- err: fmt.Errorf("backend failure"),
- wantErr: true,
- },
- {
- description: "invalid: no Trillian response: nil",
- wantErr: true,
- },
- {
- description: "invalid: bad Trillian response: no signed log root",
- rsp: func(rsp *trillian.GetLatestSignedLogRootResponse) *trillian.GetLatestSignedLogRootResponse {
- rsp.SignedLogRoot = nil
- return rsp
- }(testdata.DefaultTSlr(t)),
- wantErr: true,
- },
- {
- description: "invalid: bad Trillian response: no log root",
- rsp: func(rsp *trillian.GetLatestSignedLogRootResponse) *trillian.GetLatestSignedLogRootResponse {
- rsp.SignedLogRoot.LogRoot = nil
- return rsp
- }(testdata.DefaultTSlr(t)),
- wantErr: true,
- },
- {
- description: "invalid: bad Trillian response: truncated log root",
- rsp: func(rsp *trillian.GetLatestSignedLogRootResponse) *trillian.GetLatestSignedLogRootResponse {
- rsp.SignedLogRoot.LogRoot = rsp.SignedLogRoot.LogRoot[1:]
- return rsp
- }(testdata.DefaultTSlr(t)),
- wantErr: true,
- },
- {
- description: "invalid: bad Trillian response: truncated root hash",
- rsp: testdata.Tslr(t, testdata.Tlr(t, testdata.TreeSize, testdata.Timestamp, make([]byte, 31))),
- wantErr: true,
- },
- {
- description: "valid",
- rsp: testdata.DefaultTSlr(t),
- },
- } {
- var lr ttypes.LogRootV1
- err := checkGetLatestSignedLogRoot(newLogParameters(t, nil), table.rsp, table.err, &lr)
- if got, want := err != nil, table.wantErr; got != want {
- t.Errorf("got error %v but wanted %v in test %q", got, want, table.description)
- }
- }
-}
diff --git a/util.go b/util.go
deleted file mode 100644
index a8c918e..0000000
--- a/util.go
+++ /dev/null
@@ -1,27 +0,0 @@
-package stfe
-
-import (
- ttypes "github.com/google/trillian/types"
- "github.com/system-transparency/stfe/types"
-)
-
-func NewTreeHeadFromLogRoot(lr *ttypes.LogRootV1) *types.TreeHead {
- var hash [types.HashSize]byte
- th := types.TreeHead{
- Timestamp: uint64(lr.TimestampNanos / 1000 / 1000 / 1000),
- TreeSize: uint64(lr.TreeSize),
- RootHash: &hash,
- }
- copy(th.RootHash[:], lr.RootHash)
- return &th
-}
-
-func NodePathFromHashes(hashes [][]byte) []*[types.HashSize]byte {
- var path []*[types.HashSize]byte
- for _, hash := range hashes {
- var h [types.HashSize]byte
- copy(h[:], hash)
- path = append(path, &h)
- }
- return path
-}
diff --git a/util_test.go b/util_test.go
deleted file mode 100644
index b40a672..0000000
--- a/util_test.go
+++ /dev/null
@@ -1,17 +0,0 @@
-package stfe
-
-import (
- "testing"
-)
-
-// TODO: TestNewTreeHeadV1FromLogRoot
-func TestNewTreeHeadV1FromLogRoot(t *testing.T) {
-}
-
-// TODO: TestNewNodePathFromHashPath
-func TestNewNodePathFromHashPath(t *testing.T) {
-}
-
-// TODO: TestStItemListFromLeaves
-func TestStItemListFromLeaves(t *testing.T) {
-}