github.com/zorawar87/trillian@v1.2.1/client/log_verifier.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
    16  
    17  import (
    18  	"crypto"
    19  	"fmt"
    20  
    21  	"github.com/google/trillian"
    22  	"github.com/google/trillian/crypto/keys/der"
    23  	"github.com/google/trillian/merkle"
    24  	"github.com/google/trillian/merkle/hashers"
    25  	"github.com/google/trillian/trees"
    26  	"github.com/google/trillian/types"
    27  
    28  	tcrypto "github.com/google/trillian/crypto"
    29  )
    30  
    31  // LogVerifier contains state needed to verify output from Trillian Logs
    32  // (regular and pre-ordered ones).
    33  type LogVerifier struct {
    34  	// Hasher is the hash strategy used to compute nodes in the Merkle tree.
    35  	Hasher hashers.LogHasher
    36  	// PubKey verifies the signature on the digest of LogRoot.
    37  	PubKey crypto.PublicKey
    38  	// SigHash computes the digest of LogRoot for signing.
    39  	SigHash crypto.Hash
    40  	v       merkle.LogVerifier
    41  }
    42  
    43  // NewLogVerifier returns an object that can verify output from Trillian Logs.
    44  func NewLogVerifier(hasher hashers.LogHasher, pubKey crypto.PublicKey, sigHash crypto.Hash) *LogVerifier {
    45  	return &LogVerifier{
    46  		Hasher:  hasher,
    47  		PubKey:  pubKey,
    48  		SigHash: sigHash,
    49  		v:       merkle.NewLogVerifier(hasher),
    50  	}
    51  }
    52  
    53  // NewLogVerifierFromTree creates a new LogVerifier using the algorithms
    54  // specified by *trillian.Tree.
    55  func NewLogVerifierFromTree(config *trillian.Tree) (*LogVerifier, error) {
    56  	log, pLog := trillian.TreeType_LOG, trillian.TreeType_PREORDERED_LOG
    57  	if got := config.TreeType; got != log && got != pLog {
    58  		return nil, fmt.Errorf("client: NewLogVerifierFromTree(): TreeType: %v, want %v or %v", got, log, pLog)
    59  	}
    60  
    61  	logHasher, err := hashers.NewLogHasher(config.GetHashStrategy())
    62  	if err != nil {
    63  		return nil, fmt.Errorf("client: NewLogVerifierFromTree(): NewLogHasher(): %v", err)
    64  	}
    65  
    66  	logPubKey, err := der.UnmarshalPublicKey(config.GetPublicKey().GetDer())
    67  	if err != nil {
    68  		return nil, fmt.Errorf("client: NewLogVerifierFromTree(): Failed parsing Log public key: %v", err)
    69  	}
    70  
    71  	sigHash, err := trees.Hash(config)
    72  	if err != nil {
    73  		return nil, fmt.Errorf("client: NewLogVerifierFromTree(): Failed parsing Log signature hash: %v", err)
    74  	}
    75  
    76  	return NewLogVerifier(logHasher, logPubKey, sigHash), nil
    77  }
    78  
    79  // VerifyRoot verifies that newRoot is a valid append-only operation from
    80  // trusted. If trusted.TreeSize is zero, a consistency proof is not needed.
    81  func (c *LogVerifier) VerifyRoot(trusted *types.LogRootV1, newRoot *trillian.SignedLogRoot,
    82  	consistency [][]byte) (*types.LogRootV1, error) {
    83  
    84  	if trusted == nil {
    85  		return nil, fmt.Errorf("VerifyRoot() error: trusted == nil")
    86  	}
    87  	if newRoot == nil {
    88  		return nil, fmt.Errorf("VerifyRoot() error: newRoot == nil")
    89  	}
    90  
    91  	// Verify SignedLogRoot signature.
    92  	r, err := tcrypto.VerifySignedLogRoot(c.PubKey, c.SigHash, newRoot)
    93  	if err != nil {
    94  		return nil, err
    95  	}
    96  
    97  	// Implicitly trust the first root we get.
    98  	if trusted.TreeSize != 0 {
    99  		// Verify consistency proof.
   100  		if err := c.v.VerifyConsistencyProof(
   101  			int64(trusted.TreeSize), int64(r.TreeSize),
   102  			trusted.RootHash, r.RootHash,
   103  			consistency); err != nil {
   104  			return nil, err
   105  		}
   106  	}
   107  	return r, nil
   108  }
   109  
   110  // VerifyInclusionAtIndex verifies that the inclusion proof for data at index
   111  // matches the currently trusted root. The inclusion proof must be requested
   112  // for Root().TreeSize.
   113  func (c *LogVerifier) VerifyInclusionAtIndex(trusted *types.LogRootV1, data []byte, leafIndex int64, proof [][]byte) error {
   114  	if trusted == nil {
   115  		return fmt.Errorf("VerifyInclusionAtIndex() error: trusted == nil")
   116  	}
   117  
   118  	leaf, err := c.BuildLeaf(data)
   119  	if err != nil {
   120  		return err
   121  	}
   122  	return c.v.VerifyInclusionProof(leafIndex, int64(trusted.TreeSize),
   123  		proof, trusted.RootHash, leaf.MerkleLeafHash)
   124  }
   125  
   126  // VerifyInclusionByHash verifies the inclusion proof for data.
   127  func (c *LogVerifier) VerifyInclusionByHash(trusted *types.LogRootV1, leafHash []byte, proof *trillian.Proof) error {
   128  	if trusted == nil {
   129  		return fmt.Errorf("VerifyInclusionByHash() error: trusted == nil")
   130  	}
   131  	if proof == nil {
   132  		return fmt.Errorf("VerifyInclusionByHash() error: proof == nil")
   133  	}
   134  
   135  	return c.v.VerifyInclusionProof(proof.LeafIndex, int64(trusted.TreeSize), proof.Hashes,
   136  		trusted.RootHash, leafHash)
   137  }
   138  
   139  // BuildLeaf runs the leaf hasher over data and builds a leaf.
   140  // TODO(pavelkalinnikov): This can be misleading as it creates a partially
   141  // filled LogLeaf. Consider returning a pair instead, or leafHash only.
   142  func (c *LogVerifier) BuildLeaf(data []byte) (*trillian.LogLeaf, error) {
   143  	leafHash, err := c.Hasher.HashLeaf(data)
   144  	if err != nil {
   145  		return nil, err
   146  	}
   147  	return &trillian.LogLeaf{
   148  		LeafValue:      data,
   149  		MerkleLeafHash: leafHash,
   150  	}, nil
   151  }