diff options
Diffstat (limited to 'pkg')
| -rw-r--r-- | pkg/instance/endpoint.go | 4 | ||||
| -rw-r--r-- | pkg/instance/endpoint_test.go | 18 | ||||
| -rw-r--r-- | pkg/mocks/sigsum_state_manager.go | 4 | ||||
| -rw-r--r-- | pkg/state/state_manager.go | 32 | ||||
| -rw-r--r-- | pkg/state/state_manager_test.go | 148 | ||||
| -rw-r--r-- | pkg/types/ascii.go | 66 | ||||
| -rw-r--r-- | pkg/types/ascii_test.go | 34 | ||||
| -rw-r--r-- | pkg/types/trunnel.go | 7 | ||||
| -rw-r--r-- | pkg/types/trunnel_test.go | 4 | ||||
| -rw-r--r-- | pkg/types/types.go | 37 | 
10 files changed, 163 insertions, 191 deletions
| diff --git a/pkg/instance/endpoint.go b/pkg/instance/endpoint.go index ec87303..2387263 100644 --- a/pkg/instance/endpoint.go +++ b/pkg/instance/endpoint.go @@ -58,11 +58,11 @@ func getTreeHeadToSign(ctx context.Context, i *Instance, w http.ResponseWriter,  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) +	cth, err := i.Stateman.Cosigned(ctx)  	if err != nil {  		return http.StatusInternalServerError, err  	} -	if err := sth.MarshalASCII(w); err != nil { +	if err := cth.MarshalASCII(w); err != nil {  		return http.StatusInternalServerError, err  	}  	return http.StatusOK, nil diff --git a/pkg/instance/endpoint_test.go b/pkg/instance/endpoint_test.go index 51ec0f4..95b71d3 100644 --- a/pkg/instance/endpoint_test.go +++ b/pkg/instance/endpoint_test.go @@ -34,10 +34,14 @@ var (  			TreeSize:  0,  			RootHash:  types.Hash(nil),  		}, +		Signature: &[types.SignatureSize]byte{}, +	} +	testCTH = &types.CosignedTreeHead{ +		SignedTreeHead: *testSTH,  		SigIdent: []*types.SigIdent{  			&types.SigIdent{ -				Signature: &[types.SignatureSize]byte{},  				KeyHash:   &[types.HashSize]byte{}, +				Signature: &[types.SignatureSize]byte{},  			},  		},  	} @@ -137,7 +141,7 @@ func TestAddCosignature(t *testing.T) {  	buf := func() io.Reader {  		return bytes.NewBufferString(fmt.Sprintf(  			"%s%s%x%s"+"%s%s%x%s", -			types.Signature, types.Delim, make([]byte, types.SignatureSize), types.EOL, +			types.Cosignature, types.Delim, make([]byte, types.SignatureSize), types.EOL,  			types.KeyHash, types.Delim, *types.Hash(testWitVK[:]), types.EOL,  		))  	} @@ -311,10 +315,10 @@ func TestGetTreeToSign(t *testing.T) {  func TestGetTreeCosigned(t *testing.T) {  	for _, table := range []struct {  		description string -		expect      bool                  // set if a mock answer is expected -		rsp         *types.SignedTreeHead // signed tree head from Trillian client -		err         error                 // error from Trillian client -		wantCode    int                   // HTTP status ok +		expect      bool                    // set if a mock answer is expected +		rsp         *types.CosignedTreeHead // cosigned tree head from Trillian client +		err         error                   // error from Trillian client +		wantCode    int                     // HTTP status ok  	}{  		{  			description: "invalid: backend failure", @@ -325,7 +329,7 @@ func TestGetTreeCosigned(t *testing.T) {  		{  			description: "valid",  			expect:      true, -			rsp:         testSTH, +			rsp:         testCTH,  			wantCode:    http.StatusOK,  		},  	} { diff --git a/pkg/mocks/sigsum_state_manager.go b/pkg/mocks/sigsum_state_manager.go index b999677..594d0a1 100644 --- a/pkg/mocks/sigsum_state_manager.go +++ b/pkg/mocks/sigsum_state_manager.go @@ -50,10 +50,10 @@ func (mr *MockStateManagerMockRecorder) AddCosignature(arg0, arg1, arg2 interfac  }  // Cosigned mocks base method. -func (m *MockStateManager) Cosigned(arg0 context.Context) (*types.SignedTreeHead, error) { +func (m *MockStateManager) Cosigned(arg0 context.Context) (*types.CosignedTreeHead, error) {  	m.ctrl.T.Helper()  	ret := m.ctrl.Call(m, "Cosigned", arg0) -	ret0, _ := ret[0].(*types.SignedTreeHead) +	ret0, _ := ret[0].(*types.CosignedTreeHead)  	ret1, _ := ret[1].(error)  	return ret0, ret1  } diff --git a/pkg/state/state_manager.go b/pkg/state/state_manager.go index 7ddf986..a08fd84 100644 --- a/pkg/state/state_manager.go +++ b/pkg/state/state_manager.go @@ -3,6 +3,7 @@ package state  import (  	"context"  	"crypto" +	"crypto/ed25519"  	"fmt"  	"reflect"  	"sync" @@ -18,7 +19,7 @@ import (  type StateManager interface {  	Latest(context.Context) (*types.SignedTreeHead, error)  	ToSign(context.Context) (*types.SignedTreeHead, error) -	Cosigned(context.Context) (*types.SignedTreeHead, error) +	Cosigned(context.Context) (*types.CosignedTreeHead, error)  	AddCosignature(context.Context, *[types.VerificationKeySize]byte, *[types.SignatureSize]byte) error  	Run(context.Context)  } @@ -33,7 +34,7 @@ type StateManagerSingle struct {  	sync.RWMutex  	// cosigned is the current cosigned tree head that is being served -	cosigned types.SignedTreeHead +	cosigned types.CosignedTreeHead  	// tosign is the current tree head that is being cosigned by witnesses  	tosign types.SignedTreeHead @@ -56,18 +57,19 @@ func NewStateManagerSingle(client trillian.Client, signer crypto.Signer, interva  		return nil, fmt.Errorf("Latest: %v", err)  	} -	sm.cosigned = *sth -	sm.tosign = *sth -	sm.cosignature = map[[types.HashSize]byte]*types.SigIdent{ -		*sth.SigIdent[0].KeyHash: sth.SigIdent[0], // log signature +	sm.cosigned = types.CosignedTreeHead{ +		SignedTreeHead: *sth, +		SigIdent:       []*types.SigIdent{},  	} +	sm.tosign = *sth +	sm.cosignature = map[[types.HashSize]byte]*types.SigIdent{}  	return sm, nil  }  func (sm *StateManagerSingle) Run(ctx context.Context) {  	schedule.Every(ctx, sm.interval, func(ctx context.Context) {  		ictx, _ := context.WithTimeout(ctx, sm.deadline) -		nextTreeHead, err := sm.Latest(ictx) +		nextSTH, err := sm.Latest(ictx)  		if err != nil {  			glog.Warningf("rotate failed: Latest: %v", err)  			return @@ -75,7 +77,7 @@ func (sm *StateManagerSingle) Run(ctx context.Context) {  		sm.Lock()  		defer sm.Unlock() -		sm.rotate(nextTreeHead) +		sm.rotate(nextSTH)  	})  } @@ -84,6 +86,7 @@ func (sm *StateManagerSingle) Latest(ctx context.Context) (*types.SignedTreeHead  	if err != nil {  		return nil, fmt.Errorf("LatestTreeHead: %v", err)  	} +	th.KeyHash = types.Hash(sm.signer.Public().(ed25519.PublicKey)[:])  	sth, err := th.Sign(sm.signer)  	if err != nil {  		return nil, fmt.Errorf("sign: %v", err) @@ -97,9 +100,12 @@ func (sm *StateManagerSingle) ToSign(_ context.Context) (*types.SignedTreeHead,  	return &sm.tosign, nil  } -func (sm *StateManagerSingle) Cosigned(_ context.Context) (*types.SignedTreeHead, error) { +func (sm *StateManagerSingle) Cosigned(_ context.Context) (*types.CosignedTreeHead, error) {  	sm.RLock()  	defer sm.RUnlock() +	if len(sm.cosigned.SigIdent) == 0 { +		return nil, fmt.Errorf("no witness cosignatures available") +	}  	return &sm.cosigned, nil  } @@ -126,7 +132,7 @@ func (sm *StateManagerSingle) AddCosignature(_ context.Context, vk *[types.Verif  // 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 (sm *StateManagerSingle) rotate(next *types.SignedTreeHead) { -	if reflect.DeepEqual(sm.cosigned.TreeHead, sm.tosign.TreeHead) { +	if reflect.DeepEqual(sm.cosigned.SignedTreeHead, sm.tosign) {  		// cosigned and tosign are the same.  So, we need to merge all  		// cosignatures that we already had with the new collected ones.  		for _, sigident := range sm.cosigned.SigIdent { @@ -142,13 +148,11 @@ func (sm *StateManagerSingle) rotate(next *types.SignedTreeHead) {  	}  	// Update cosigned tree head -	sm.cosigned.TreeHead = sm.tosign.TreeHead +	sm.cosigned.SignedTreeHead = sm.tosign  	sm.cosigned.SigIdent = cosignatures  	// Update to-sign tree head  	sm.tosign = *next -	sm.cosignature = map[[types.HashSize]byte]*types.SigIdent{ -		*next.SigIdent[0].KeyHash: next.SigIdent[0], // log signature -	} +	sm.cosignature = map[[types.HashSize]byte]*types.SigIdent{} // TODO: on repeat we might want to not zero this  	glog.V(3).Infof("rotated tree heads")  } diff --git a/pkg/state/state_manager_test.go b/pkg/state/state_manager_test.go index acc2319..6650544 100644 --- a/pkg/state/state_manager_test.go +++ b/pkg/state/state_manager_test.go @@ -23,14 +23,21 @@ var (  		Timestamp: 0,  		TreeSize:  0,  		RootHash:  types.Hash(nil), +		KeyHash:   types.Hash(testPub[:]),  	}  	testSigIdent = &types.SigIdent{  		Signature: testSig,  		KeyHash:   types.Hash(testPub[:]),  	}  	testSTH = &types.SignedTreeHead{ -		TreeHead: *testTH, -		SigIdent: []*types.SigIdent{testSigIdent}, +		TreeHead:  *testTH, +		Signature: testSig, +	} +	testCTH = &types.CosignedTreeHead{ +		SignedTreeHead: *testSTH, +		SigIdent: []*types.SigIdent{ +			testSigIdent, +		},  	}  	testSignerOK  = &mocks.TestSigner{testPub, testSig, nil}  	testSignerErr = &mocks.TestSigner{testPub, testSig, fmt.Errorf("something went wrong")} @@ -72,14 +79,14 @@ func TestNewStateManagerSingle(t *testing.T) {  			if err != nil {  				return  			} -			if got, want := &sm.cosigned, table.wantSth; !reflect.DeepEqual(got, want) { +			if got, want := &sm.cosigned.SignedTreeHead, table.wantSth; !reflect.DeepEqual(got, want) {  				t.Errorf("got cosigned tree head\n\t%v\nbut wanted\n\t%v\nin test %q", got, want, table.description)  			}  			if got, want := &sm.tosign, table.wantSth; !reflect.DeepEqual(got, want) {  				t.Errorf("got tosign tree head\n\t%v\nbut wanted\n\t%v\nin test %q", got, want, table.description)  			}  			// we only have log signature on startup -			if got, want := len(sm.cosignature), 1; got != want { +			if got, want := len(sm.cosignature), 0; got != want {  				t.Errorf("got %d cosignatures but wanted %d in test %q", got, want, table.description)  			}  		}() @@ -157,16 +164,23 @@ func TestToSign(t *testing.T) {  func TestCosigned(t *testing.T) {  	description := "valid"  	sm := StateManagerSingle{ -		cosigned: *testSTH, +		cosigned: *testCTH,  	} -	sth, err := sm.Cosigned(context.Background()) +	cth, err := sm.Cosigned(context.Background())  	if err != nil {  		t.Errorf("Cosigned should not fail with error: %v", err)  		return  	} -	if got, want := sth, testSTH; !reflect.DeepEqual(got, want) { +	if got, want := cth, testCTH; !reflect.DeepEqual(got, want) {  		t.Errorf("got signed tree head\n\t%v\nbut wanted\n\t%v\nin test %q", got, want, description)  	} + +	sm.cosigned.SigIdent = make([]*types.SigIdent, 0) +	cth, err = sm.Cosigned(context.Background()) +	if err == nil { +		t.Errorf("Cosigned should fail without witness cosignatures") +		return +	}  }  func TestAddCosignature(t *testing.T) { @@ -202,15 +216,15 @@ func TestAddCosignature(t *testing.T) {  		},  	} {  		sth, _ := table.th.Sign(testSignerOK) -		logKeyHash := sth.SigIdent[0].KeyHash -		logSigIdent := sth.SigIdent[0] +		cth := &types.CosignedTreeHead{ +			SignedTreeHead: *sth, +			SigIdent:       []*types.SigIdent{}, +		}  		sm := &StateManagerSingle{ -			signer:   testSignerOK, -			cosigned: *sth, -			tosign:   *sth, -			cosignature: map[[types.HashSize]byte]*types.SigIdent{ -				*logKeyHash: logSigIdent, -			}, +			signer:      testSignerOK, +			cosigned:    *cth, +			tosign:      *sth, +			cosignature: map[[types.HashSize]byte]*types.SigIdent{},  		}  		// Prepare witness signature @@ -218,11 +232,13 @@ func TestAddCosignature(t *testing.T) {  		if err != nil {  			t.Fatalf("Sign: %v", err)  		} -		witnessKeyHash := sth.SigIdent[0].KeyHash -		witnessSigIdent := sth.SigIdent[0] +		si := &types.SigIdent{ +			KeyHash:   types.Hash(table.signer.Public().(ed25519.PublicKey)[:]), +			Signature: sth.Signature, +		}  		// Add witness signature -		err = sm.AddCosignature(context.Background(), table.vk, witnessSigIdent.Signature) +		err = sm.AddCosignature(context.Background(), table.vk, si.Signature)  		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)  		} @@ -230,33 +246,24 @@ func TestAddCosignature(t *testing.T) {  			continue  		} -		// We should have two signatures (log + witness) -		if got, want := len(sm.cosignature), 2; got != want { +		// We should have one witness signature +		if got, want := len(sm.cosignature), 1; got != want {  			t.Errorf("got %d cosignatures but wanted %v in test %q", got, want, table.description)  			continue  		} -		// check that log signature is there -		sigident, ok := sm.cosignature[*logKeyHash] -		if !ok { -			t.Errorf("log signature is missing") -			continue -		} -		if got, want := sigident, logSigIdent; !reflect.DeepEqual(got, want) { -			t.Errorf("got log sigident\n\t%v\nbut wanted\n\t%v\nin test %q", got, want, table.description) -		}  		// check that witness signature is there -		sigident, ok = sm.cosignature[*witnessKeyHash] +		sigident, ok := sm.cosignature[*si.KeyHash]  		if !ok {  			t.Errorf("witness signature is missing")  			continue  		} -		if got, want := sigident, witnessSigIdent; !reflect.DeepEqual(got, want) { +		if got, want := si, sigident; !reflect.DeepEqual(got, want) {  			t.Errorf("got witness sigident\n\t%v\nbut wanted\n\t%v\nin test %q", got, want, table.description)  			continue  		}  		// Adding a duplicate signature should give an error -		if err := sm.AddCosignature(context.Background(), table.vk, witnessSigIdent.Signature); err == nil { +		if err := sm.AddCosignature(context.Background(), table.vk, si.Signature); err == nil {  			t.Errorf("duplicate witness signature accepted as valid")  		}  	} @@ -292,81 +299,86 @@ func TestRotate(t *testing.T) {  		{  			description: "tosign tree head repated, but got one new witnes signature",  			before: &StateManagerSingle{ -				cosigned: types.SignedTreeHead{ -					TreeHead: *th0, -					SigIdent: []*types.SigIdent{log, wit1}, +				cosigned: types.CosignedTreeHead{ +					SignedTreeHead: types.SignedTreeHead{ +						TreeHead:  *th0, +						Signature: log.Signature, +					}, +					SigIdent: []*types.SigIdent{wit1},  				},  				tosign: types.SignedTreeHead{ -					TreeHead: *th0, -					SigIdent: []*types.SigIdent{log}, +					TreeHead:  *th0, +					Signature: log.Signature,  				},  				cosignature: map[[types.HashSize]byte]*types.SigIdent{ -					*log.KeyHash:  log,  					*wit2.KeyHash: wit2, // the new witness signature  				},  			},  			next: &types.SignedTreeHead{ -				TreeHead: *th1, -				SigIdent: []*types.SigIdent{log}, +				TreeHead:  *th1, +				Signature: log.Signature,  			},  			after: &StateManagerSingle{ -				cosigned: types.SignedTreeHead{ -					TreeHead: *th0, -					SigIdent: []*types.SigIdent{log, wit1, wit2}, +				cosigned: types.CosignedTreeHead{ +					SignedTreeHead: types.SignedTreeHead{ +						TreeHead:  *th0, +						Signature: log.Signature, +					}, +					SigIdent: []*types.SigIdent{wit1, wit2},  				},  				tosign: types.SignedTreeHead{ -					TreeHead: *th1, -					SigIdent: []*types.SigIdent{log}, -				}, -				cosignature: map[[types.HashSize]byte]*types.SigIdent{ -					*log.KeyHash: log, // after rotate we always have log sig +					TreeHead:  *th1, +					Signature: log.Signature,  				}, +				cosignature: map[[types.HashSize]byte]*types.SigIdent{},  			},  		},  		{  			description: "tosign tree head did not repeat, it got one witness signature",  			before: &StateManagerSingle{ -				cosigned: types.SignedTreeHead{ -					TreeHead: *th0, -					SigIdent: []*types.SigIdent{log, wit1}, +				cosigned: types.CosignedTreeHead{ +					SignedTreeHead: types.SignedTreeHead{ +						TreeHead:  *th0, +						Signature: log.Signature, +					}, +					SigIdent: []*types.SigIdent{wit1},  				},  				tosign: types.SignedTreeHead{ -					TreeHead: *th1, -					SigIdent: []*types.SigIdent{log}, +					TreeHead:  *th1, +					Signature: log.Signature,  				},  				cosignature: map[[types.HashSize]byte]*types.SigIdent{ -					*log.KeyHash:  log, -					*wit2.KeyHash: wit2, // the only witness that signed tosign +					*log.KeyHash: wit2,  				},  			},  			next: &types.SignedTreeHead{ -				TreeHead: *th2, -				SigIdent: []*types.SigIdent{log}, +				TreeHead:  *th2, +				Signature: log.Signature,  			},  			after: &StateManagerSingle{ -				cosigned: types.SignedTreeHead{ -					TreeHead: *th1, -					SigIdent: []*types.SigIdent{log, wit2}, +				cosigned: types.CosignedTreeHead{ +					SignedTreeHead: types.SignedTreeHead{ +						TreeHead:  *th1, +						Signature: log.Signature, +					}, +					SigIdent: []*types.SigIdent{wit2},  				},  				tosign: types.SignedTreeHead{ -					TreeHead: *th2, -					SigIdent: []*types.SigIdent{log}, -				}, -				cosignature: map[[types.HashSize]byte]*types.SigIdent{ -					*log.KeyHash: log, // after rotate we always have log sig +					TreeHead:  *th2, +					Signature: log.Signature,  				}, +				cosignature: map[[types.HashSize]byte]*types.SigIdent{},  			},  		},  	} {  		table.before.rotate(table.next) -		if got, want := table.before.cosigned.TreeHead, table.after.cosigned.TreeHead; !reflect.DeepEqual(got, want) { +		if got, want := table.before.cosigned.SignedTreeHead, table.after.cosigned.SignedTreeHead; !reflect.DeepEqual(got, want) {  			t.Errorf("got cosigned tree head\n\t%v\nbut wanted\n\t%v\nin test %q", got, want, table.description)  		}  		checkWitnessList(t, table.description, table.before.cosigned.SigIdent, table.after.cosigned.SigIdent) -		if got, want := table.before.tosign.TreeHead, table.after.tosign.TreeHead; !reflect.DeepEqual(got, want) { +		if got, want := table.before.tosign, table.after.tosign; !reflect.DeepEqual(got, want) {  			t.Errorf("got tosign tree head\n\t%v\nbut wanted\n\t%v\nin test %q", got, want, table.description)  		} -		checkWitnessList(t, table.description, table.before.tosign.SigIdent, table.after.tosign.SigIdent)  		if got, want := table.before.cosignature, table.after.cosignature; !reflect.DeepEqual(got, want) {  			t.Errorf("got cosignature map\n\t%v\nbut wanted\n\t%v\nin test %q", got, want, table.description)  		} diff --git a/pkg/types/ascii.go b/pkg/types/ascii.go index f0a96ad..72abfcb 100644 --- a/pkg/types/ascii.go +++ b/pkg/types/ascii.go @@ -18,7 +18,7 @@ const (  	// NumField* is the number of unique keys in an incoming ASCII message  	NumFieldLeaf                    = 4 -	NumFieldSignedTreeHead          = 5 +	NumFieldSignedTreeHead          = 4  	NumFieldConsistencyProof        = 3  	NumFieldInclusionProof          = 3  	NumFieldLeavesRequest           = 2 @@ -28,11 +28,11 @@ const (  	NumFieldCosignatureRequest      = 2  	// New leaf keys -	ShardHint            = "shard_hint" -	Checksum             = "checksum" -	Signature            = "signature" -	VerificationKey      = "verification_key" -	DomainHint           = "domain_hint" +	ShardHint       = "shard_hint" +	Checksum        = "checksum" +	Signature       = "signature" +	VerificationKey = "verification_key" +	DomainHint      = "domain_hint"  	// Inclusion proof keys  	LeafHash      = "leaf_hash" @@ -53,8 +53,9 @@ const (  	TreeSize  = "tree_size"  	RootHash  = "root_hash" -	// Signature and signer-identity keys -	KeyHash   = "key_hash" +	// Witness signature-identity keys +	KeyHash     = "key_hash" +	Cosignature = "cosignature"  )  // MessageASCI is a wrapper that manages ASCII key-value pairs @@ -219,19 +220,29 @@ func (sth *SignedTreeHead) MarshalASCII(w io.Writer) error {  	if err := writeASCII(w, RootHash, hex.EncodeToString(sth.RootHash[:])); err != nil {  		return fmt.Errorf("writeASCII: %v", err)  	} -	for _, sigident := range sth.SigIdent { -		if err := sigident.MarshalASCII(w); err != nil { -			return fmt.Errorf("MarshalASCII: %v", err) +	if err := writeASCII(w, Signature, hex.EncodeToString(sth.Signature[:])); err != nil { +		return fmt.Errorf("writeASCII: %v", err) +	} +	return nil +} + +func (cth *CosignedTreeHead) MarshalASCII(w io.Writer) error { +	if err := cth.SignedTreeHead.MarshalASCII(w); err != nil { +		return fmt.Errorf("writeASCII: %v", err) +	} +	for _, si := range cth.SigIdent { +		if err := si.MarshalASCII(w); err != nil { +			return fmt.Errorf("writeASCII: %v", err)  		}  	}  	return nil  }  func (si *SigIdent) MarshalASCII(w io.Writer) error { -	if err := writeASCII(w, Signature, hex.EncodeToString(si.Signature[:])); err != nil { +	if err := writeASCII(w, KeyHash, hex.EncodeToString(si.KeyHash[:])); err != nil {  		return fmt.Errorf("writeASCII: %v", err)  	} -	if err := writeASCII(w, KeyHash, hex.EncodeToString(si.KeyHash[:])); err != nil { +	if err := writeASCII(w, Cosignature, hex.EncodeToString(si.Signature[:])); err != nil {  		return fmt.Errorf("writeASCII: %v", err)  	}  	return nil @@ -280,7 +291,6 @@ func (sth *SignedTreeHead) UnmarshalASCII(r io.Reader) error {  		return fmt.Errorf("NewMessageASCII: %v", err)  	} -	// TreeHead  	if sth.Timestamp, err = msg.GetUint64(Timestamp); err != nil {  		return fmt.Errorf("GetUint64(Timestamp): %v", err)  	} @@ -290,30 +300,8 @@ func (sth *SignedTreeHead) UnmarshalASCII(r io.Reader) error {  	if sth.RootHash, err = msg.GetHash(RootHash); err != nil {  		return fmt.Errorf("GetHash(RootHash): %v", err)  	} - -	// SigIdent -	signatures := msg.GetStrings(Signature) -	if len(signatures) == 0 { -		return fmt.Errorf("no signer") -	} -	keyHashes := msg.GetStrings(KeyHash) -	if len(signatures) != len(keyHashes) { -		return fmt.Errorf("mismatched signature-signer count") -	} -	sth.SigIdent = make([]*SigIdent, 0, len(signatures)) -	for i, n := 0, len(signatures); i < n; i++ { -		var signature [SignatureSize]byte -		if err := decodeHex(signatures[i], signature[:]); err != nil { -			return fmt.Errorf("decodeHex: %v", err) -		} -		var hash [HashSize]byte -		if err := decodeHex(keyHashes[i], hash[:]); err != nil { -			return fmt.Errorf("decodeHex: %v", err) -		} -		sth.SigIdent = append(sth.SigIdent, &SigIdent{ -			Signature: &signature, -			KeyHash:   &hash, -		}) +	if sth.Signature, err = msg.GetSignature(Signature); err != nil { +		return fmt.Errorf("GetHash(RootHash): %v", err)  	}  	return nil  } @@ -401,7 +389,7 @@ func (req *CosignatureRequest) UnmarshalASCII(r io.Reader) error {  		return fmt.Errorf("NewMessageASCII: %v", err)  	} -	if req.Signature, err = msg.GetSignature(Signature); err != nil { +	if req.Signature, err = msg.GetSignature(Cosignature); err != nil {  		return fmt.Errorf("GetSignature: %v", err)  	}  	if req.KeyHash, err = msg.GetHash(KeyHash); err != nil { diff --git a/pkg/types/ascii_test.go b/pkg/types/ascii_test.go index c3f9e98..fc3f486 100644 --- a/pkg/types/ascii_test.go +++ b/pkg/types/ascii_test.go @@ -134,26 +134,14 @@ func TestSignedTreeHeadMarshalASCII(t *testing.T) {  			TreeSize:  456,  			RootHash:  testBuffer32,  		}, -		SigIdent: []*SigIdent{ -			&SigIdent{ -				Signature: testBuffer64, -				KeyHash:   testBuffer32, -			}, -			&SigIdent{ -				Signature: testBuffer64, -				KeyHash:   testBuffer32, -			}, -		}, +		Signature: testBuffer64,  	}  	wantBuf := bytes.NewBufferString(fmt.Sprintf( -		"%s%s%d%s"+"%s%s%d%s"+"%s%s%x%s"+"%s%s%x%s"+"%s%s%x%s"+"%s%s%x%s"+"%s%s%x%s", +		"%s%s%d%s"+"%s%s%d%s"+"%s%s%x%s"+"%s%s%x%s",  		Timestamp, Delim, 123, EOL,  		TreeSize, Delim, 456, EOL,  		RootHash, Delim, testBuffer32[:], EOL,  		Signature, Delim, testBuffer64[:], EOL, -		KeyHash, Delim, testBuffer32[:], EOL, -		Signature, Delim, testBuffer64[:], EOL, -		KeyHash, Delim, testBuffer32[:], EOL,  	))  	buf := bytes.NewBuffer(nil)  	if err := sth.MarshalASCII(buf); err != nil { @@ -236,14 +224,11 @@ func TestSignedTreeHeadUnmarshalASCII(t *testing.T) {  		{  			description: "valid",  			buf: bytes.NewBufferString(fmt.Sprintf( -				"%s%s%d%s"+"%s%s%d%s"+"%s%s%x%s"+"%s%s%x%s"+"%s%s%x%s"+"%s%s%x%s"+"%s%s%x%s", +				"%s%s%d%s"+"%s%s%d%s"+"%s%s%x%s"+"%s%s%x%s",  				Timestamp, Delim, 123, EOL,  				TreeSize, Delim, 456, EOL,  				RootHash, Delim, testBuffer32[:], EOL,  				Signature, Delim, testBuffer64[:], EOL, -				KeyHash, Delim, testBuffer32[:], EOL, -				Signature, Delim, testBuffer64[:], EOL, -				KeyHash, Delim, testBuffer32[:], EOL,  			)),  			wantSth: &SignedTreeHead{  				TreeHead: TreeHead{ @@ -251,16 +236,7 @@ func TestSignedTreeHeadUnmarshalASCII(t *testing.T) {  					TreeSize:  456,  					RootHash:  testBuffer32,  				}, -				SigIdent: []*SigIdent{ -					&SigIdent{ -						Signature: testBuffer64, -						KeyHash:   testBuffer32, -					}, -					&SigIdent{ -						Signature: testBuffer64, -						KeyHash:   testBuffer32, -					}, -				}, +				Signature: testBuffer64,  			},  		},  	} { @@ -436,7 +412,7 @@ func TestCosignatureRequestUnmarshalASCII(t *testing.T) {  			description: "valid",  			buf: bytes.NewBufferString(fmt.Sprintf(  				"%s%s%x%s"+"%s%s%x%s", -				Signature, Delim, testBuffer64[:], EOL, +				Cosignature, Delim, testBuffer64[:], EOL,  				KeyHash, Delim, testBuffer32[:], EOL,  			)),  			wantReq: &CosignatureRequest{ diff --git a/pkg/types/trunnel.go b/pkg/types/trunnel.go index 268f6f7..5350c5b 100644 --- a/pkg/types/trunnel.go +++ b/pkg/types/trunnel.go @@ -10,6 +10,8 @@ const (  	MessageSize = 8 + HashSize  	// LeafSize is the number of bytes in a Trunnel-encoded leaf  	LeafSize = MessageSize + SignatureSize + HashSize +	// TreeHeadSize is the number of bytes in a Trunnel-encoded tree head +	TreeHeadSize = 8 + 8 + HashSize + HashSize  )  // Marshal returns a Trunnel-encoded message @@ -30,10 +32,11 @@ func (l *Leaf) Marshal() []byte {  // Marshal returns a Trunnel-encoded tree head  func (th *TreeHead) Marshal() []byte { -	buf := make([]byte, 8+8+HashSize) +	buf := make([]byte, TreeHeadSize)  	binary.BigEndian.PutUint64(buf[0:8], th.Timestamp)  	binary.BigEndian.PutUint64(buf[8:16], th.TreeSize) -	copy(buf[16:], th.RootHash[:]) +	copy(buf[16:16+HashSize], th.RootHash[:]) +	copy(buf[16+HashSize:], th.KeyHash[:])  	return buf  } diff --git a/pkg/types/trunnel_test.go b/pkg/types/trunnel_test.go index 297578c..a3ae1ba 100644 --- a/pkg/types/trunnel_test.go +++ b/pkg/types/trunnel_test.go @@ -48,16 +48,18 @@ func TestMarshalLeaf(t *testing.T) {  }  func TestMarshalTreeHead(t *testing.T) { -	description := "valid: timestamp 16909060, tree size 72623859790382856, root hash 0x00,0x01,..." +	description := "valid: timestamp 16909060, tree size 72623859790382856, root hash & key hash 0x00,0x01,..."  	th := &TreeHead{  		Timestamp: 16909060,  		TreeSize:  72623859790382856,  		RootHash:  testBuffer32, +		KeyHash:   testBuffer32,  	}  	want := bytes.Join([][]byte{  		[]byte{0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04},  		[]byte{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08},  		testBuffer32[:], +		testBuffer32[:],  	}, nil)  	if got := th.Marshal(); !bytes.Equal(got, want) {  		t.Errorf("got tree head\n\t%v\nbut wanted\n\t%v\nin test %q\n", got, want, description) diff --git a/pkg/types/types.go b/pkg/types/types.go index 96e2b18..bc58c98 100644 --- a/pkg/types/types.go +++ b/pkg/types/types.go @@ -32,78 +32,67 @@ func (e Endpoint) Path(components ...string) string {  	return strings.Join(append(components, string(e)), "/")  } -// Leaf is the log's Merkle tree leaf.  type Leaf struct {  	Message  	SigIdent  } -// Message is composed of a shard hint and a checksum.  The submitter selects -// these values to fit the log's shard interval and the opaque data in question.  type Message struct {  	ShardHint uint64  	Checksum  *[HashSize]byte  } -// SigIdent is composed of a signature-signer pair.  The signature is computed -// over the Trunnel-serialized leaf message.  KeyHash identifies the signer.  type SigIdent struct {  	Signature *[SignatureSize]byte  	KeyHash   *[HashSize]byte  } -// SignedTreeHead is composed of a tree head and a list of signature-signer -// pairs.  Each signature is computed over the Trunnel-serialized tree head.  type SignedTreeHead struct {  	TreeHead +	Signature *[SignatureSize]byte +} + +type CosignedTreeHead struct { +	SignedTreeHead  	SigIdent []*SigIdent  } -// TreeHead is the log's tree head.  type TreeHead struct {  	Timestamp uint64  	TreeSize  uint64  	RootHash  *[HashSize]byte +	KeyHash   *[HashSize]byte  } -// ConsistencyProof is a consistency proof that proves the log's append-only -// property.  type ConsistencyProof struct {  	NewSize uint64  	OldSize uint64  	Path    []*[HashSize]byte  } -// InclusionProof is an inclusion proof that proves a leaf is included in the -// log.  type InclusionProof struct {  	TreeSize  uint64  	LeafIndex uint64  	Path      []*[HashSize]byte  } -// LeafList is a list of leaves  type LeafList []*Leaf -// ConsistencyProofRequest is a get-consistency-proof request  type ConsistencyProofRequest struct {  	NewSize uint64  	OldSize uint64  } -// InclusionProofRequest is a get-proof-by-hash request  type InclusionProofRequest struct {  	LeafHash *[HashSize]byte  	TreeSize uint64  } -// LeavesRequest is a get-leaves request  type LeavesRequest struct {  	StartSize uint64  	EndSize   uint64  } -// LeafRequest is an add-leaf request  type LeafRequest struct {  	Message  	Signature       *[SignatureSize]byte @@ -111,7 +100,6 @@ type LeafRequest struct {  	DomainHint      string  } -// CosignatureRequest is an add-cosignature request  type CosignatureRequest struct {  	SigIdent  } @@ -123,17 +111,12 @@ func (th *TreeHead) Sign(signer crypto.Signer) (*SignedTreeHead, error) {  		return nil, fmt.Errorf("Sign: %v", err)  	} -	sigident := SigIdent{ -		KeyHash:   Hash(signer.Public().(ed25519.PublicKey)[:]), +	sth := &SignedTreeHead{ +		TreeHead:  *th,  		Signature: &[SignatureSize]byte{},  	} -	copy(sigident.Signature[:], sig) -	return &SignedTreeHead{ -		TreeHead: *th, -		SigIdent: []*SigIdent{ -			&sigident, -		}, -	}, nil +	copy(sth.Signature[:], sig) +	return sth, nil  }  // Verify verifies the tree head signature using the log's signature scheme | 
