Skip to content
This repository has been archived by the owner on Oct 11, 2024. It is now read-only.

Commit

Permalink
Merge branch 'master' into test
Browse files Browse the repository at this point in the history
* master:
  Cache go mod download (#1325)
  Extract log tracking into separate package  (#1317)
  • Loading branch information
gdbelvin committed Jul 18, 2019
2 parents 0971ab5 + a34e14b commit 6de7b87
Show file tree
Hide file tree
Showing 14 changed files with 360 additions and 111 deletions.
5 changes: 4 additions & 1 deletion cmd/keytransparency-monitor/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
FROM golang:1.12 as build

WORKDIR /go/src/github.com/google/keytransparency
COPY . .
COPY go.mod go.sum ./

ENV GO111MODULE=on
RUN go mod download
COPY . .

RUN go get -tags="mysql" ./cmd/keytransparency-monitor

FROM gcr.io/distroless/base
Expand Down
5 changes: 4 additions & 1 deletion cmd/keytransparency-sequencer/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
FROM golang:1.12 as build

WORKDIR /go/src/github.com/google/keytransparency
COPY . .
COPY go.mod go.sum ./

ENV GO111MODULE=on
RUN go mod download
COPY . .

RUN go get -tags="mysql" ./cmd/keytransparency-sequencer

FROM gcr.io/distroless/base
Expand Down
5 changes: 4 additions & 1 deletion cmd/keytransparency-server/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
FROM golang:1.12 as build

WORKDIR /go/src/github.com/google/keytransparency
COPY . .
COPY go.mod go.sum ./

ENV GO111MODULE=on
RUN go mod download
COPY . .

RUN go get -tags="mysql" ./cmd/keytransparency-server

FROM gcr.io/distroless/base
Expand Down
8 changes: 3 additions & 5 deletions core/client/batch_get_and_verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,22 +100,20 @@ func (c *Client) BatchVerifyGetUserIndex(ctx context.Context, userIDs []string)
// TODO(gbelvin): Verify that the returned map root is indeed the latest map root.
func (c *Client) BatchVerifiedGetUser(ctx context.Context, userIDs []string) (
*types.MapRootV1, map[string]*pb.MapLeaf, error) {
c.trustedLock.Lock()
defer c.trustedLock.Unlock()
logReq := c.LastVerifiedLogRoot()
resp, err := c.cli.BatchGetUser(ctx, &pb.BatchGetUserRequest{
DirectoryId: c.DirectoryID,
UserIds: userIDs,
LastVerifiedTreeSize: int64(c.trusted.TreeSize),
LastVerifiedTreeSize: logReq.TreeSize,
})
if err != nil {
return nil, nil, err
}

lr, err := c.VerifyLogRoot(c.trusted, resp.Revision.GetLatestLogRoot())
lr, err := c.VerifyLogRoot(logReq, resp.Revision.GetLatestLogRoot())
if err != nil {
return nil, nil, err
}
c.updateTrusted(lr)
smr, err := c.VerifyMapRevision(lr, resp.Revision.GetMapRoot())
if err != nil {
return nil, nil, err
Expand Down
28 changes: 5 additions & 23 deletions core/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import (
"io/ioutil"
"log"
"sort"
"sync"
"time"

"github.com/google/keytransparency/core/client/verifier"
Expand Down Expand Up @@ -69,22 +68,21 @@ var (

// VerifierInterface is used to verify specific outputs from Key Transparency.
type VerifierInterface interface {
verifier.LogTracker
// Index computes the index of a userID from a VRF proof, obtained from the server.
Index(vrfProof []byte, directoryID, userID string) ([]byte, error)
// VerifyMapLeaf verifies everything about a MapLeaf.
VerifyMapLeaf(directoryID, userID string, in *pb.MapLeaf, smr *types.MapRootV1) error
// VerifyLogRoot verifies that revision.LogRoot is consistent with the last trusted SignedLogRoot.
VerifyLogRoot(trusted types.LogRootV1, slr *pb.LogRoot) (*types.LogRootV1, error)
// VerifyMapRevision verifies that the map revision is correctly signed and included in the log.
VerifyMapRevision(lr *types.LogRootV1, smr *pb.MapRoot) (*types.MapRootV1, error)
// VerifyMapLeaf verifies everything about a MapLeaf.
VerifyMapLeaf(directoryID, userID string, in *pb.MapLeaf, smr *types.MapRootV1) error
//
// Pair Verifiers
//

// VerifyGetUser verifies the request and response to the GetUser API.
VerifyGetUser(trusted types.LogRootV1, req *pb.GetUserRequest, resp *pb.GetUserResponse) error
VerifyGetUser(logReq *pb.LogRootRequest, req *pb.GetUserRequest, resp *pb.GetUserResponse) error
// VerifyBatchGetUser verifies the request and response to the BatchGetUser API.
VerifyBatchGetUser(trusted types.LogRootV1, req *pb.BatchGetUserRequest, resp *pb.BatchGetUserResponse) error
VerifyBatchGetUser(logReq *pb.LogRootRequest, req *pb.BatchGetUserRequest, resp *pb.BatchGetUserResponse) error
}

// ReduceMutationFn takes all the mutations for an index and an auxiliary input
Expand Down Expand Up @@ -113,8 +111,6 @@ type Client struct {
DirectoryID string
reduce ReduceMutationFn
RetryDelay time.Duration
trusted types.LogRootV1
trustedLock sync.Mutex
}

// NewFromConfig creates a new client from a config
Expand Down Expand Up @@ -145,20 +141,6 @@ func New(ktClient pb.KeyTransparencyClient,
}
}

// updateTrusted sets the local reference for the latest SignedLogRoot if
// newTrusted is correctly signed and newer than the current stored root.
// updateTrusted should be called while c.trustedLock has been acquired.
func (c *Client) updateTrusted(newTrusted *types.LogRootV1) {
if newTrusted.TimestampNanos <= c.trusted.TimestampNanos ||
newTrusted.TreeSize < c.trusted.TreeSize {
// Valid root, but it's older than the one we currently have.
return
}
c.trusted = *newTrusted
glog.Infof("Trusted root updated to TreeSize %v", c.trusted.TreeSize)
Vlog.Printf("✓ Log root updated.")
}

// GetUser returns an entry if it exists, and nil if it does not.
func (c *Client) GetUser(ctx context.Context, userID string, opts ...grpc.CallOption) (
*types.MapRootV1, []byte, error) {
Expand Down
16 changes: 10 additions & 6 deletions core/client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -307,23 +307,27 @@ func (f *fakeVerifier) Index(vrfProof []byte, directoryID, userID string) ([]byt
return make([]byte, 32), nil
}

func (f *fakeVerifier) VerifyMapLeaf(directoryID, userID string,
in *pb.MapLeaf, smr *types.MapRootV1) error {
return nil
func (f *fakeVerifier) LastVerifiedLogRoot() *pb.LogRootRequest {
return &pb.LogRootRequest{}
}

func (f *fakeVerifier) VerifyLogRoot(trusted types.LogRootV1, slr *pb.LogRoot) (*types.LogRootV1, error) {
func (f *fakeVerifier) VerifyLogRoot(req *pb.LogRootRequest, slr *pb.LogRoot) (*types.LogRootV1, error) {
return &types.LogRootV1{}, nil
}

func (f *fakeVerifier) VerifyMapRevision(logRoot *types.LogRootV1, smr *pb.MapRoot) (*types.MapRootV1, error) {
return &types.MapRootV1{Revision: uint64(smr.MapRoot.MapRoot[0])}, nil
}

func (f *fakeVerifier) VerifyGetUser(trusted types.LogRootV1, req *pb.GetUserRequest, resp *pb.GetUserResponse) error {
func (f *fakeVerifier) VerifyMapLeaf(directoryID, userID string,
in *pb.MapLeaf, smr *types.MapRootV1) error {
return nil
}

func (f *fakeVerifier) VerifyGetUser(logReq *pb.LogRootRequest, req *pb.GetUserRequest, resp *pb.GetUserResponse) error {
return nil
}

func (f *fakeVerifier) VerifyBatchGetUser(trusted types.LogRootV1, req *pb.BatchGetUserRequest, resp *pb.BatchGetUserResponse) error {
func (f *fakeVerifier) VerifyBatchGetUser(logReq *pb.LogRootRequest, req *pb.BatchGetUserRequest, resp *pb.BatchGetUserResponse) error {
return nil
}
41 changes: 15 additions & 26 deletions core/client/get_and_verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,21 @@ import (

// VerifiedGetUser fetches and verifies the results of GetUser.
func (c *Client) VerifiedGetUser(ctx context.Context, userID string) (*types.MapRootV1, *pb.MapLeaf, error) {
c.trustedLock.Lock()
defer c.trustedLock.Unlock()
logReq := c.LastVerifiedLogRoot()
req := &pb.GetUserRequest{
DirectoryId: c.DirectoryID,
UserId: userID,
LastVerifiedTreeSize: int64(c.trusted.TreeSize),
LastVerifiedTreeSize: logReq.TreeSize,
}
resp, err := c.cli.GetUser(ctx, req)
if err != nil {
return nil, nil, err
}

lr, err := c.VerifyLogRoot(c.trusted, resp.Revision.GetLatestLogRoot())
lr, err := c.VerifyLogRoot(logReq, resp.Revision.GetLatestLogRoot())
if err != nil {
return nil, nil, err
}
c.updateTrusted(lr)
mr, err := c.VerifyMapRevision(lr, resp.Revision.GetMapRoot())
if err != nil {
return nil, nil, err
Expand All @@ -58,23 +56,19 @@ func (c *Client) VerifiedGetUser(ctx context.Context, userID string) (*types.Map
// It also verifies the consistency from the last seen revision.
// Returns the latest log root and the latest map root.
func (c *Client) VerifiedGetLatestRevision(ctx context.Context) (*types.LogRootV1, *types.MapRootV1, error) {
// Only one method should attempt to update the trusted root at time.
c.trustedLock.Lock()
defer c.trustedLock.Unlock()

logReq := c.LastVerifiedLogRoot()
resp, err := c.cli.GetLatestRevision(ctx, &pb.GetLatestRevisionRequest{
DirectoryId: c.DirectoryID,
LastVerifiedTreeSize: int64(c.trusted.TreeSize),
LastVerifiedTreeSize: logReq.TreeSize,
})
if err != nil {
return nil, nil, err
}

lr, err := c.VerifyLogRoot(c.trusted, resp.GetLatestLogRoot())
lr, err := c.VerifyLogRoot(logReq, resp.GetLatestLogRoot())
if err != nil {
return nil, nil, err
}
c.updateTrusted(lr)
mr, err := c.VerifyMapRevision(lr, resp.GetMapRoot())
if err != nil {
return nil, nil, err
Expand All @@ -96,24 +90,21 @@ func (c *Client) VerifiedGetLatestRevision(ctx context.Context) (*types.LogRootV
// It also verifies the consistency of the latest log root against the last seen log root.
// Returns the requested map root.
func (c *Client) VerifiedGetRevision(ctx context.Context, revision int64) (*types.MapRootV1, error) {
// Only one method should attempt to update the trusted root at time.
c.trustedLock.Lock()
defer c.trustedLock.Unlock()

resp, err := c.cli.GetRevision(ctx, &pb.GetRevisionRequest{
logReq := c.LastVerifiedLogRoot()
req := &pb.GetRevisionRequest{
DirectoryId: c.DirectoryID,
Revision: revision,
LastVerifiedTreeSize: int64(c.trusted.TreeSize),
})
LastVerifiedTreeSize: logReq.TreeSize,
}
resp, err := c.cli.GetRevision(ctx, req)
if err != nil {
return nil, err
}

lr, err := c.VerifyLogRoot(c.trusted, resp.GetLatestLogRoot())
lr, err := c.VerifyLogRoot(logReq, resp.GetLatestLogRoot())
if err != nil {
return nil, err
}
c.updateTrusted(lr)
mr, err := c.VerifyMapRevision(lr, resp.GetMapRoot())
if err != nil {
return nil, err
Expand All @@ -125,12 +116,11 @@ func (c *Client) VerifiedGetRevision(ctx context.Context, revision int64) (*type
// VerifiedListHistory performs one list history operation, verifies and returns the results.
func (c *Client) VerifiedListHistory(ctx context.Context, userID string, start int64, count int32) (
map[*types.MapRootV1][]byte, int64, error) {
c.trustedLock.Lock()
defer c.trustedLock.Unlock()
logReq := c.LastVerifiedLogRoot()
resp, err := c.cli.ListEntryHistory(ctx, &pb.ListEntryHistoryRequest{
DirectoryId: c.DirectoryID,
UserId: userID,
LastVerifiedTreeSize: int64(c.trusted.TreeSize),
LastVerifiedTreeSize: logReq.TreeSize,
Start: start,
PageSize: count,
})
Expand All @@ -144,11 +134,10 @@ func (c *Client) VerifiedListHistory(ctx context.Context, userID string, start i
profiles := make(map[*types.MapRootV1][]byte)
for _, v := range resp.GetValues() {
if lr == nil {
lr, err = c.VerifyLogRoot(c.trusted, v.GetRevision().GetLatestLogRoot())
lr, err = c.VerifyLogRoot(logReq, v.GetRevision().GetLatestLogRoot())
if err != nil {
return nil, 0, err
}
c.updateTrusted(lr)
}
mr, err := c.VerifyMapRevision(lr, v.GetRevision().GetMapRoot())
if err != nil {
Expand Down
114 changes: 114 additions & 0 deletions core/client/tracker/tracker.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// Copyright 2019 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Package tracker tracks log roots and verifies consistency proofs between them.
package tracker

import (
"sync"

"github.com/golang/glog"
"github.com/golang/protobuf/proto"
"github.com/google/trillian/types"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"

pb "github.com/google/keytransparency/core/api/v1/keytransparency_go_proto"
tpb "github.com/google/trillian"
)

// UpdateTrustedPredicate returns a bool indicating whether the local reference
// for the latest SignedLogRoot should be updated.
type UpdateTrustedPredicate func(cntRoot, newRoot types.LogRootV1) bool

// LogRootVerifier verifies a Trillian Log Root.
type LogRootVerifier interface {
// VerifyRoot checks the signature of newRoot and the consistency proof if trusted.TreeSize != 0.
VerifyRoot(trusted *types.LogRootV1, newRoot *tpb.SignedLogRoot, proof [][]byte) (*types.LogRootV1, error)
}

// LogTracker tracks a series of consistent log roots.
type LogTracker struct {
trusted types.LogRootV1
v LogRootVerifier
updateTrusted UpdateTrustedPredicate
mu sync.RWMutex
}

// New creates a log tracker from no trusted root.
func New(lv LogRootVerifier) *LogTracker {
return NewFromSaved(lv, types.LogRootV1{})
}

// NewFromSaved creates a log tracker from a previously saved trusted root.
func NewFromSaved(lv LogRootVerifier, lr types.LogRootV1) *LogTracker {
return &LogTracker{v: lv, trusted: lr, updateTrusted: isNewer}
}

// LastVerifiedLogRoot retrieves the tree size of the latest log root.
func (l *LogTracker) LastVerifiedLogRoot() *pb.LogRootRequest {
l.mu.RLock()
defer l.mu.RUnlock()
return l.logRootRequest()
}

func (l *LogTracker) logRootRequest() *pb.LogRootRequest {
return &pb.LogRootRequest{
TreeSize: int64(l.trusted.TreeSize),
RootHash: l.trusted.RootHash,
}
}

// VerifyLogRoot verifies root and updates the trusted root if it is newer.
// state must be equal to the most recent value from LastVerifiedLogRoot().
// If two clients race to VerifyLogRoot at the same time, if one of them updates the root, the other will fail.
func (l *LogTracker) VerifyLogRoot(state *pb.LogRootRequest, root *pb.LogRoot) (*types.LogRootV1, error) {
l.mu.Lock()
defer l.mu.Unlock()
if want := l.logRootRequest(); !proto.Equal(state, want) {
glog.Warningf("logtracker: unexpected logRootRequest: %v, want %v", state, want)
return nil, status.Errorf(codes.InvalidArgument, "out of order VerifyLogRoot(%v, _), want %v", state, want)
}

logRoot, err := l.v.VerifyRoot(&l.trusted,
root.GetLogRoot(),
root.GetLogConsistency())
if err != nil {
return nil, err
}
if l.updateTrusted(l.trusted, *logRoot) {
l.trusted = *logRoot
glog.Infof("Trusted root updated to TreeSize %v", l.trusted.TreeSize)
}
return logRoot, nil
}

// SetUpdatePredicate allows relying parties to have finer grained control over when the trusted root is updated.
// It is legal to set the predicate at any time, but it makes the most sense to do so before any other calls.
func (l *LogTracker) SetUpdatePredicate(f UpdateTrustedPredicate) {
l.updateTrusted = f
}

// isNewer returns true when newRoot is newer than cntRoot.
func isNewer(cntRoot, newRoot types.LogRootV1) bool {
if newRoot.TreeSize > cntRoot.TreeSize {
return true
}
if newRoot.TreeSize == cntRoot.TreeSize &&
newRoot.TimestampNanos > cntRoot.TimestampNanos {
return true
}
// The new root is older or smaller than the one we currently have.
return false
}
Loading

0 comments on commit 6de7b87

Please sign in to comment.