Skip to content

Commit

Permalink
Merge branch 'master' into f/sig/logroot_proto2
Browse files Browse the repository at this point in the history
* master:
  Move SignedMapRoot fields to MapRootV1 (google#1060)
  • Loading branch information
gdbelvin committed Mar 21, 2018
2 parents d4e2eb6 + 0c12c84 commit 23860e0
Show file tree
Hide file tree
Showing 14 changed files with 371 additions and 403 deletions.
20 changes: 10 additions & 10 deletions client/map_verifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,14 @@ import (
"github.com/google/trillian/merkle"
"github.com/google/trillian/merkle/hashers"
"github.com/google/trillian/trees"
"github.com/google/trillian/types"

tcrypto "github.com/google/trillian/crypto"
)

// MapVerifier verifies protos produced by the Trillian Map.
type MapVerifier struct {
MapID int64
// Hasher is the hash strategy used to compute nodes in the Merkle tree.
Hasher hashers.MapHasher
// PubKey verifies the signature on the digest of MapRoot.
Expand Down Expand Up @@ -59,6 +61,7 @@ func NewMapVerifierFromTree(config *trillian.Tree) (*MapVerifier, error) {
}

return &MapVerifier{
MapID: config.GetTreeId(),
Hasher: mapHasher,
PubKey: mapPubKey,
SigHash: sigHash,
Expand All @@ -70,17 +73,14 @@ func (m *MapVerifier) VerifyMapLeafInclusion(smr *trillian.SignedMapRoot, leafPr
index := leafProof.GetLeaf().GetIndex()
leaf := leafProof.GetLeaf().GetLeafValue()
proof := leafProof.GetInclusion()
expectedRoot := smr.GetRootHash()
mapID := smr.GetMapId()
return merkle.VerifyMapInclusionProof(mapID, index, leaf, expectedRoot, proof, m.Hasher)
root, err := m.VerifySignedMapRoot(smr)
if err != nil {
return err
}
return merkle.VerifyMapInclusionProof(m.MapID, index, leaf, root.RootHash, proof, m.Hasher)
}

// VerifySignedMapRoot verifies the signature on the SignedMapRoot.
func (m *MapVerifier) VerifySignedMapRoot(smr *trillian.SignedMapRoot) error {
// SignedMapRoot contains its own signature. To verify, we need to create a local
// copy of the object and return the object to the state it was in when signed
// by removing the signature from the object.
orig := *smr
orig.Signature = nil // Remove the signature from the object to be verified.
return tcrypto.VerifyObject(m.PubKey, m.SigHash, orig, smr.GetSignature())
func (m *MapVerifier) VerifySignedMapRoot(smr *trillian.SignedMapRoot) (*types.MapRootV1, error) {
return tcrypto.VerifySignedMapRoot(m.PubKey, m.SigHash, smr)
}
38 changes: 17 additions & 21 deletions crypto/signer.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,7 @@ package crypto
import (
"crypto"
"crypto/rand"
"encoding/json"
"fmt"

"github.com/benlaurie/objecthash/go/objecthash"
"github.com/golang/glog"
"github.com/google/trillian"
"github.com/google/trillian/types"
Expand Down Expand Up @@ -67,20 +64,6 @@ func (s *Signer) Sign(data []byte) ([]byte, error) {
return s.Signer.Sign(rand.Reader, digest, s.Hash)
}

// SignObject signs the requested object using ObjectHash.
func (s *Signer) SignObject(obj interface{}) ([]byte, error) {
// TODO(gbelvin): use objecthash.CommonJSONify
j, err := json.Marshal(obj)
if err != nil {
return nil, err
}
hash, err := objecthash.CommonJSONHash(string(j))
if err != nil {
return nil, fmt.Errorf("CommonJSONHash(%s): %v", j, err)
}
return s.Sign(hash[:])
}

// SignLogRoot returns a complete SignedLogRoot (including signature).
func (s *Signer) SignLogRoot(r *types.LogRootV1) (*trillian.SignedLogRoot, error) {
logRoot, err := r.MarshalBinary()
Expand All @@ -105,8 +88,21 @@ func (s *Signer) SignLogRoot(r *types.LogRootV1) (*trillian.SignedLogRoot, error
}, nil
}

// SignMapRoot hashes and signs the supplied (to-be) SignedMapRoot and returns a
// signature. Hashing is performed by github.com/benlaurie/objecthash.
func (s *Signer) SignMapRoot(root *trillian.SignedMapRoot) ([]byte, error) {
return s.SignObject(root)
// SignMapRoot hashes and signs the supplied (to-be) SignedMapRoot and returns a signature.
func (s *Signer) SignMapRoot(r *types.MapRootV1) (*trillian.SignedMapRoot, error) {
rootBytes, err := r.MarshalBinary()
if err != nil {
return nil, err
}

signature, err := s.Sign(rootBytes)
if err != nil {
glog.Warningf("%v: signer failed to sign map root: %v", s.KeyHint, err)
return nil, err
}

return &trillian.SignedMapRoot{
MapRoot: rootBytes,
Signature: signature,
}, nil
}
29 changes: 7 additions & 22 deletions crypto/signer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,10 @@ package crypto

import (
"crypto"
"encoding/json"
"errors"
"testing"

"github.com/benlaurie/objecthash/go/objecthash"
"github.com/golang/mock/gomock"
"github.com/google/trillian"
"github.com/google/trillian/crypto/keys/pem"
"github.com/google/trillian/testonly"
"github.com/google/trillian/types"
Expand Down Expand Up @@ -123,32 +120,20 @@ func TestSignMapRoot(t *testing.T) {
}
signer := NewSigner(0, key, crypto.SHA256)

for _, test := range []struct {
root trillian.SignedMapRoot
}{
{root: trillian.SignedMapRoot{TimestampNanos: 2267709, RootHash: []byte("Islington"), MapRevision: 3}},
for _, root := range []types.MapRootV1{
{TimestampNanos: 2267709, RootHash: []byte("Islington"), Revision: 3},
} {
sig, err := signer.SignMapRoot(&test.root)
smr, err := signer.SignMapRoot(&root)
if err != nil {
t.Errorf("Failed to sign map root: %v", err)
continue
}
if got := len(sig); got == 0 {
if got := len(smr.Signature); got == 0 {
t.Errorf("len(sig): %v, want > 0", got)
}
// Check that the signature is correct
j, err := json.Marshal(test.root)
if err != nil {
t.Errorf("json.Marshal err: %v want nil", err)
continue
}
hash, err := objecthash.CommonJSONHash(string(j))
if err != nil {
t.Errorf("objecthash.CommonJSONHash err: %v want nil", err)
continue
}
if err := Verify(key.Public(), crypto.SHA256, hash[:], sig); err != nil {
t.Errorf("Verify(%v) failed: %v", test.root, err)

if _, err := VerifySignedMapRoot(key.Public(), crypto.SHA256, smr); err != nil {
t.Errorf("Verify(%v) failed: %v", root, err)
}
}
}
21 changes: 10 additions & 11 deletions crypto/verifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,10 @@ import (
"crypto/ecdsa"
"crypto/rsa"
"encoding/asn1"
"encoding/json"
"errors"
"fmt"
"math/big"

"github.com/benlaurie/objecthash/go/objecthash"
"github.com/google/trillian"
"github.com/google/trillian/types"
)
Expand All @@ -44,17 +42,18 @@ func VerifySignedLogRoot(pub crypto.PublicKey, hash crypto.Hash, r *trillian.Sig
return &logRoot, nil
}

// VerifyObject verifies the output of Signer.SignObject.
func VerifyObject(pub crypto.PublicKey, hash crypto.Hash, obj interface{}, sig []byte) error {
j, err := json.Marshal(obj)
if err != nil {
return err
// VerifySignedMapRoot verifies the signature on the SignedMapRoot.
// VerifySignedMapRoot returns MapRootV1 to encourage safe API use.
// It should be the only function available to clients that returns MapRootV1.
func VerifySignedMapRoot(pub crypto.PublicKey, hash crypto.Hash, smr *trillian.SignedMapRoot) (*types.MapRootV1, error) {
if err := Verify(pub, hash, smr.MapRoot, smr.Signature); err != nil {
return nil, err
}
digest, err := objecthash.CommonJSONHash(string(j))
if err != nil {
return fmt.Errorf("CommonJSONHash(%s): %v", j, err)
var root types.MapRootV1
if err := root.UnmarshalBinary(smr.MapRoot); err != nil {
return nil, err
}
return Verify(pub, hash, digest[:], sig)
return &root, nil
}

// Verify cryptographically verifies the output of Signer.
Expand Down
52 changes: 0 additions & 52 deletions crypto/verifier_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,7 @@ import (
"crypto"
"testing"

"github.com/google/trillian"
"github.com/google/trillian/crypto/keys/pem"
"github.com/google/trillian/examples/ct/ctmapper/ctmapperpb"
"github.com/google/trillian/testonly"
)

Expand Down Expand Up @@ -83,53 +81,3 @@ func TestSignVerify(t *testing.T) {
}
}
}

func TestSignVerifyObject(t *testing.T) {
key, err := pem.UnmarshalPrivateKey(testonly.DemoPrivateKey, testonly.DemoPrivateKeyPass)
if err != nil {
t.Fatalf("Failed to open test key, err=%v", err)
}
signer := NewSigner(0, key, crypto.SHA256)

type subfield struct {
c int
}

meta := testonly.MustMarshalAnyNoT(&ctmapperpb.MapperMetadata{})
meta0 := testonly.MustMarshalAnyNoT(&ctmapperpb.MapperMetadata{HighestFullyCompletedSeq: 0})
meta1 := testonly.MustMarshalAnyNoT(&ctmapperpb.MapperMetadata{HighestFullyCompletedSeq: 1})

for _, tc := range []struct {
obj interface{}
}{
{meta},
{meta0},
{meta1},

{&trillian.SignedMapRoot{}},
{&trillian.SignedMapRoot{
MapId: 0xcafe,
}},
{&trillian.SignedMapRoot{Metadata: meta}},
{&trillian.SignedMapRoot{Metadata: meta0}},
{&trillian.SignedMapRoot{Metadata: meta1}},
{struct{ a string }{a: "foo"}},
{struct {
a int
b *subfield
}{a: 1, b: &subfield{c: 0}}},
{struct {
a int
b *subfield
}{a: 1, b: nil}},
} {
sig, err := signer.SignObject(tc.obj)
if err != nil {
t.Errorf("SignObject(%#v): %v", tc.obj, err)
continue
}
if err := VerifyObject(key.Public(), crypto.SHA256, tc.obj, sig); err != nil {
t.Errorf("SignObject(%#v): %v", tc.obj, err)
}
}
}
12 changes: 8 additions & 4 deletions examples/ct/ctmapper/mapper/mapper.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"github.com/google/trillian"
"github.com/google/trillian/examples/ct/ctmapper"
"github.com/google/trillian/examples/ct/ctmapper/ctmapperpb"
"github.com/google/trillian/types"
"google.golang.org/grpc"

pb "github.com/golang/protobuf/proto"
Expand Down Expand Up @@ -81,11 +82,14 @@ func (m *CTMapper) oneMapperRun(ctx context.Context) (bool, error) {
return false, err
}

var mapRoot types.MapRootV1
if err := mapRoot.UnmarshalBinary(getRootResp.GetMapRoot().GetMapRoot()); err != nil {
return false, err
}

mapperMetadata := &ctmapperpb.MapperMetadata{}
if getRootResp.GetMapRoot().Metadata != nil {
if err := proto.Unmarshal(getRootResp.MapRoot.Metadata, mapperMetadata); err != nil {
return false, fmt.Errorf("failed to unmarshal MapRoot.Metadata: %v", err)
}
if err := proto.Unmarshal(mapRoot.Metadata, mapperMetadata); err != nil {
return false, fmt.Errorf("failed to unmarshal MapRoot.Metadata: %v", err)
}

startEntry := mapperMetadata.HighestFullyCompletedSeq + 1
Expand Down
Loading

0 comments on commit 23860e0

Please sign in to comment.