github.com/mre-fog/trillianxx@v1.1.2-0.20180615153820-ae375a99d36a/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 }