github.com/mre-fog/trillianxx@v1.1.2-0.20180615153820-ae375a99d36a/client/log_client.go (about)

     1  // Copyright 2017 Google Inc. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package client verifies responses from the Trillian log.
    16  package client
    17  
    18  import (
    19  	"bytes"
    20  	"context"
    21  	"fmt"
    22  	"sync"
    23  	"time"
    24  
    25  	"github.com/google/trillian"
    26  	"github.com/google/trillian/client/backoff"
    27  	"github.com/google/trillian/types"
    28  	"google.golang.org/grpc/codes"
    29  	"google.golang.org/grpc/status"
    30  )
    31  
    32  // LogClient represents a client for a given Trillian log instance.
    33  type LogClient struct {
    34  	*LogVerifier
    35  	LogID    int64
    36  	client   trillian.TrillianLogClient
    37  	root     types.LogRootV1
    38  	rootLock sync.Mutex
    39  }
    40  
    41  // New returns a new LogClient.
    42  func New(logID int64, client trillian.TrillianLogClient, verifier *LogVerifier) *LogClient {
    43  	return &LogClient{
    44  		LogVerifier: verifier,
    45  		LogID:       logID,
    46  		client:      client,
    47  	}
    48  }
    49  
    50  // NewFromTree creates a new LogClient given a tree config.
    51  func NewFromTree(client trillian.TrillianLogClient, config *trillian.Tree) (*LogClient, error) {
    52  	verifier, err := NewLogVerifierFromTree(config)
    53  	if err != nil {
    54  		return nil, err
    55  	}
    56  
    57  	return New(config.GetTreeId(), client, verifier), nil
    58  }
    59  
    60  // AddSequencedLeafAndWait adds a leaf at a specific index to the log.
    61  // Blocks until it has been included in a signed log root.
    62  func (c *LogClient) AddSequencedLeafAndWait(ctx context.Context, data []byte, index int64) error {
    63  	if err := c.AddSequencedLeaf(ctx, data, index); err != nil {
    64  		return fmt.Errorf("QueueLeaf(): %v", err)
    65  	}
    66  	if err := c.WaitForInclusion(ctx, data); err != nil {
    67  		return fmt.Errorf("WaitForInclusion(): %v", err)
    68  	}
    69  	return nil
    70  }
    71  
    72  // AddLeaf adds leaf to the append only log.
    73  // Blocks until it gets a verifiable response.
    74  func (c *LogClient) AddLeaf(ctx context.Context, data []byte) error {
    75  	if err := c.QueueLeaf(ctx, data); err != nil {
    76  		return fmt.Errorf("QueueLeaf(): %v", err)
    77  	}
    78  	if err := c.WaitForInclusion(ctx, data); err != nil {
    79  		return fmt.Errorf("WaitForInclusion(): %v", err)
    80  	}
    81  	return nil
    82  }
    83  
    84  // GetByIndex returns a single leaf at the requested index.
    85  func (c *LogClient) GetByIndex(ctx context.Context, index int64) (*trillian.LogLeaf, error) {
    86  	resp, err := c.client.GetLeavesByIndex(ctx, &trillian.GetLeavesByIndexRequest{
    87  		LogId:     c.LogID,
    88  		LeafIndex: []int64{index},
    89  	})
    90  	if err != nil {
    91  		return nil, err
    92  	}
    93  	if got, want := len(resp.Leaves), 1; got != want {
    94  		return nil, fmt.Errorf("len(leaves): %v, want %v", got, want)
    95  	}
    96  	return resp.Leaves[0], nil
    97  }
    98  
    99  // ListByIndex returns the requested leaves by index.
   100  func (c *LogClient) ListByIndex(ctx context.Context, start, count int64) ([]*trillian.LogLeaf, error) {
   101  	resp, err := c.client.GetLeavesByRange(ctx,
   102  		&trillian.GetLeavesByRangeRequest{
   103  			LogId:      c.LogID,
   104  			StartIndex: start,
   105  			Count:      count,
   106  		})
   107  	if err != nil {
   108  		return nil, err
   109  	}
   110  	// Verify that we got back the requested leaves.
   111  	if len(resp.Leaves) < int(count) {
   112  		return nil, fmt.Errorf("len(Leaves)=%d, want %d", len(resp.Leaves), count)
   113  	}
   114  	for i, l := range resp.Leaves {
   115  		if want := start + int64(i); l.LeafIndex != want {
   116  			return nil, fmt.Errorf("Leaves[%d].LeafIndex=%d, want %d", i, l.LeafIndex, want)
   117  		}
   118  	}
   119  
   120  	return resp.Leaves, nil
   121  }
   122  
   123  // WaitForRootUpdate repeatedly fetches the Root until the fetched tree size >=
   124  // waitForTreeSize or until ctx times out.
   125  func (c *LogClient) WaitForRootUpdate(ctx context.Context, waitForTreeSize uint64) (*types.LogRootV1, error) {
   126  	b := &backoff.Backoff{
   127  		Min:    100 * time.Millisecond,
   128  		Max:    10 * time.Second,
   129  		Factor: 2,
   130  		Jitter: true,
   131  	}
   132  	for i := 0; ; i++ {
   133  		root, err := c.UpdateRoot(ctx)
   134  		switch x := status.Code(err); x {
   135  		case codes.OK:
   136  			if root.TreeSize >= waitForTreeSize {
   137  				return root, nil
   138  			}
   139  		case codes.Unavailable, codes.NotFound, codes.FailedPrecondition: // Retry.
   140  		default:
   141  			return nil, err
   142  		}
   143  
   144  		select {
   145  		case <-ctx.Done():
   146  			return nil, status.Errorf(codes.DeadlineExceeded, "%v", ctx.Err())
   147  		case <-time.After(b.Duration()):
   148  		}
   149  	}
   150  }
   151  
   152  // getLatestRoot fetches and verifies the latest root against a trusted root, seen in the past.
   153  // Pass nil for trusted if this is the first time querying this log.
   154  func (c *LogClient) getLatestRoot(ctx context.Context, trusted *types.LogRootV1) (*types.LogRootV1, error) {
   155  	resp, err := c.client.GetLatestSignedLogRoot(ctx,
   156  		&trillian.GetLatestSignedLogRootRequest{LogId: c.LogID})
   157  	if err != nil {
   158  		return nil, err
   159  	}
   160  
   161  	// TODO(gbelvin): Turn on root verification.
   162  	/*
   163  		logRoot, err := c.VerifyRoot(&types.LogRootV1{}, resp.GetSignedLogRoot(), nil)
   164  		if err != nil {
   165  			return nil, err
   166  		}
   167  	*/
   168  	// TODO(gbelvin): Remove this hack when all implementations store digital signatures.
   169  	var logRoot types.LogRootV1
   170  	if err := logRoot.UnmarshalBinary(resp.GetSignedLogRoot().LogRoot); err != nil {
   171  		return nil, err
   172  	}
   173  
   174  	if trusted.TreeSize > 0 &&
   175  		logRoot.TreeSize == trusted.TreeSize &&
   176  		bytes.Equal(logRoot.RootHash, trusted.RootHash) {
   177  		// Tree has not been updated.
   178  		return &logRoot, nil
   179  	}
   180  	// Fetch a consistency proof if this isn't the first root we've seen.
   181  	var consistency *trillian.GetConsistencyProofResponse
   182  	if trusted.TreeSize > 0 {
   183  		// Get consistency proof.
   184  		consistency, err = c.client.GetConsistencyProof(ctx,
   185  			&trillian.GetConsistencyProofRequest{
   186  				LogId:          c.LogID,
   187  				FirstTreeSize:  int64(trusted.TreeSize),
   188  				SecondTreeSize: int64(logRoot.TreeSize),
   189  			})
   190  		if err != nil {
   191  			return nil, err
   192  		}
   193  	}
   194  
   195  	// Verify root update if the tree / the latest signed log root isn't empty.
   196  	if logRoot.TreeSize > 0 {
   197  		if _, err := c.VerifyRoot(trusted, resp.GetSignedLogRoot(),
   198  			consistency.GetProof().GetHashes()); err != nil {
   199  			return nil, err
   200  		}
   201  	}
   202  	return &logRoot, nil
   203  }
   204  
   205  // UpdateRoot retrieves the current SignedLogRoot, verifying it against roots this client has
   206  // seen in the past, and updating the currently trusted root if the new root verifies.
   207  func (c *LogClient) UpdateRoot(ctx context.Context) (*types.LogRootV1, error) {
   208  	c.rootLock.Lock()
   209  	defer c.rootLock.Unlock()
   210  
   211  	currentlyTrusted := &c.root
   212  	newTrusted, err := c.getLatestRoot(ctx, currentlyTrusted)
   213  	if err != nil {
   214  		return nil, err
   215  	}
   216  	if newTrusted.TimestampNanos > currentlyTrusted.TimestampNanos &&
   217  		newTrusted.TreeSize >= currentlyTrusted.TreeSize {
   218  		c.root = *newTrusted
   219  	}
   220  	// Copy the internal trusted root in order to prevent clients from modifying it.
   221  	ret := c.root
   222  	return &ret, nil
   223  }
   224  
   225  // WaitForInclusion blocks until the requested data has been verified with an inclusion proof.
   226  // This assumes that the data has already been submitted.
   227  // Best practice is to call this method with a context that will timeout.
   228  func (c *LogClient) WaitForInclusion(ctx context.Context, data []byte) error {
   229  	leaf, err := c.BuildLeaf(data)
   230  	if err != nil {
   231  		return err
   232  	}
   233  
   234  	// Fetch the current Root to improve our chances at a valid inclusion proof.
   235  	// It is illegal to ask for an inclusion proof with TreeSize = 0.
   236  	root, err := c.WaitForRootUpdate(ctx, 1)
   237  	if err != nil {
   238  		return err
   239  	}
   240  	for {
   241  		ok, err := c.getAndVerifyInclusionProof(ctx, leaf.MerkleLeafHash, root)
   242  		if err != nil && status.Code(err) != codes.NotFound {
   243  			return err
   244  		}
   245  		if ok {
   246  			return nil
   247  		}
   248  		// Wait for TreeSize to update.
   249  		if root, err = c.WaitForRootUpdate(ctx, root.TreeSize+1); err != nil {
   250  			return err
   251  		}
   252  		// Retry
   253  	}
   254  }
   255  
   256  // VerifyInclusion updates the log root and ensures that the given leaf data has been included in the log.
   257  func (c *LogClient) VerifyInclusion(ctx context.Context, data []byte) error {
   258  	leaf, err := c.BuildLeaf(data)
   259  	if err != nil {
   260  		return err
   261  	}
   262  	root, err := c.UpdateRoot(ctx)
   263  	if err != nil {
   264  		return fmt.Errorf("UpdateRoot(): %v", err)
   265  	}
   266  	ok, err := c.getAndVerifyInclusionProof(ctx, leaf.MerkleLeafHash, root)
   267  	if err != nil {
   268  		return err
   269  	}
   270  	if !ok {
   271  		return fmt.Errorf("no proof")
   272  	}
   273  	return nil
   274  }
   275  
   276  // GetAndVerifyInclusionAtIndex updates the log root and ensures that the given leaf data has been included in the log at a particular index.
   277  func (c *LogClient) GetAndVerifyInclusionAtIndex(ctx context.Context, data []byte, index int64) error {
   278  	root, err := c.UpdateRoot(ctx)
   279  	if err != nil {
   280  		return fmt.Errorf("UpdateRoot(): %v", err)
   281  	}
   282  	resp, err := c.client.GetInclusionProof(ctx,
   283  		&trillian.GetInclusionProofRequest{
   284  			LogId:     c.LogID,
   285  			LeafIndex: index,
   286  			TreeSize:  int64(root.TreeSize),
   287  		})
   288  	if err != nil {
   289  		return err
   290  	}
   291  	return c.VerifyInclusionAtIndex(root, data, index, resp.Proof.Hashes)
   292  }
   293  
   294  func (c *LogClient) getAndVerifyInclusionProof(ctx context.Context, leafHash []byte, sth *types.LogRootV1) (bool, error) {
   295  	resp, err := c.client.GetInclusionProofByHash(ctx,
   296  		&trillian.GetInclusionProofByHashRequest{
   297  			LogId:    c.LogID,
   298  			LeafHash: leafHash,
   299  			TreeSize: int64(sth.TreeSize),
   300  		})
   301  	if err != nil {
   302  		return false, err
   303  	}
   304  	if len(resp.Proof) < 1 {
   305  		return false, nil
   306  	}
   307  	for _, proof := range resp.Proof {
   308  		if err := c.VerifyInclusionByHash(sth, leafHash, proof); err != nil {
   309  			return false, fmt.Errorf("VerifyInclusionByHash(): %v", err)
   310  		}
   311  	}
   312  	return true, nil
   313  }
   314  
   315  // AddSequencedLeaf adds a leaf at a particular index.
   316  func (c *LogClient) AddSequencedLeaf(ctx context.Context, data []byte, index int64) error {
   317  	leaf, err := c.BuildLeaf(data)
   318  	if err != nil {
   319  		return err
   320  	}
   321  	leaf.LeafIndex = index
   322  
   323  	_, err = c.client.AddSequencedLeaf(ctx, &trillian.AddSequencedLeafRequest{
   324  		LogId: c.LogID,
   325  		Leaf:  leaf,
   326  	})
   327  	return err
   328  }
   329  
   330  // QueueLeaf adds a leaf to a Trillian log without blocking.
   331  // AlreadyExists is considered a success case by this function.
   332  func (c *LogClient) QueueLeaf(ctx context.Context, data []byte) error {
   333  	leaf, err := c.BuildLeaf(data)
   334  	if err != nil {
   335  		return err
   336  	}
   337  
   338  	_, err = c.client.QueueLeaf(ctx, &trillian.QueueLeafRequest{
   339  		LogId: c.LogID,
   340  		Leaf:  leaf,
   341  	})
   342  	return err
   343  }