mirror of
https://github.com/containers/podman.git
synced 2025-07-18 01:57:24 +08:00
Update sigstore/rekor after https://github.com/sigstore/rekor/pull/1469
> go get github.com/sigstore/rekor@ad288b385a44bc45d328627679988e2c99cd5e0f > make vendor Signed-off-by: Miloslav Trmač <mitr@redhat.com>
This commit is contained in:
124
vendor/github.com/google/trillian/client/admin.go
generated
vendored
124
vendor/github.com/google/trillian/client/admin.go
generated
vendored
@ -1,124 +0,0 @@
|
||||
// Copyright 2018 Google LLC. 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 client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/google/trillian"
|
||||
"github.com/google/trillian/client/backoff"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"k8s.io/klog/v2"
|
||||
)
|
||||
|
||||
// CreateAndInitTree uses the adminClient and logClient to create the tree
|
||||
// described by req.
|
||||
// If req describes a LOG tree, then this function will also call the InitLog
|
||||
// function using logClient.
|
||||
// Internally, the function will continue to retry failed requests until either
|
||||
// the tree is created (and if necessary, initialised) successfully, or ctx is
|
||||
// cancelled.
|
||||
func CreateAndInitTree(
|
||||
ctx context.Context,
|
||||
req *trillian.CreateTreeRequest,
|
||||
adminClient trillian.TrillianAdminClient,
|
||||
logClient trillian.TrillianLogClient) (*trillian.Tree, error) {
|
||||
b := &backoff.Backoff{
|
||||
Min: 100 * time.Millisecond,
|
||||
Max: 10 * time.Second,
|
||||
Factor: 2,
|
||||
Jitter: true,
|
||||
}
|
||||
|
||||
var tree *trillian.Tree
|
||||
err := b.Retry(ctx, func() error {
|
||||
klog.Info("CreateTree...")
|
||||
var err error
|
||||
tree, err = adminClient.CreateTree(ctx, req)
|
||||
switch code := status.Code(err); code {
|
||||
case codes.Unavailable:
|
||||
klog.Errorf("Admin server unavailable: %v", err)
|
||||
return err
|
||||
case codes.OK:
|
||||
return nil
|
||||
default:
|
||||
klog.Errorf("failed to CreateTree(%+v): %T %v", req, err, err)
|
||||
return err
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch tree.TreeType {
|
||||
case trillian.TreeType_LOG, trillian.TreeType_PREORDERED_LOG:
|
||||
if err := InitLog(ctx, tree, logClient); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
return nil, fmt.Errorf("don't know how or whether to initialise tree type %v", tree.TreeType)
|
||||
}
|
||||
|
||||
return tree, nil
|
||||
}
|
||||
|
||||
// InitLog initialises a freshly created Log tree.
|
||||
func InitLog(ctx context.Context, tree *trillian.Tree, logClient trillian.TrillianLogClient) error {
|
||||
if tree.TreeType != trillian.TreeType_LOG &&
|
||||
tree.TreeType != trillian.TreeType_PREORDERED_LOG {
|
||||
return fmt.Errorf("InitLog called with tree of type %v", tree.TreeType)
|
||||
}
|
||||
|
||||
b := &backoff.Backoff{
|
||||
Min: 100 * time.Millisecond,
|
||||
Max: 10 * time.Second,
|
||||
Factor: 2,
|
||||
Jitter: true,
|
||||
}
|
||||
|
||||
err := b.Retry(ctx, func() error {
|
||||
klog.Infof("Initialising Log %v...", tree.TreeId)
|
||||
req := &trillian.InitLogRequest{LogId: tree.TreeId}
|
||||
resp, err := logClient.InitLog(ctx, req)
|
||||
switch code := status.Code(err); code {
|
||||
case codes.Unavailable:
|
||||
klog.Errorf("Log server unavailable: %v", err)
|
||||
return err
|
||||
case codes.AlreadyExists:
|
||||
klog.Warningf("Bizarrely, the just-created Log (%v) is already initialised!: %v", tree.TreeId, err)
|
||||
return err
|
||||
case codes.OK:
|
||||
klog.Infof("Initialised Log (%v) with new SignedTreeHead:\n%+v",
|
||||
tree.TreeId, resp.Created)
|
||||
return nil
|
||||
default:
|
||||
klog.Errorf("failed to InitLog(%+v): %T %v", req, err, err)
|
||||
return err
|
||||
}
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Wait for log root to become available.
|
||||
return b.Retry(ctx, func() error {
|
||||
_, err := logClient.GetLatestSignedLogRoot(ctx,
|
||||
&trillian.GetLatestSignedLogRootRequest{LogId: tree.TreeId})
|
||||
return err
|
||||
}, codes.FailedPrecondition)
|
||||
}
|
130
vendor/github.com/google/trillian/client/backoff/backoff.go
generated
vendored
130
vendor/github.com/google/trillian/client/backoff/backoff.go
generated
vendored
@ -1,130 +0,0 @@
|
||||
// Copyright 2017 Google LLC. 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 backoff allows retrying an operation with backoff.
|
||||
package backoff
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"time"
|
||||
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// RetriableError explicitly instructs Backoff to retry.
|
||||
type RetriableError string
|
||||
|
||||
// Error returns string representation of the retriable error.
|
||||
func (re RetriableError) Error() string {
|
||||
return string(re)
|
||||
}
|
||||
|
||||
// RetriableErrorf wraps a formatted string into a RetriableError.
|
||||
func RetriableErrorf(format string, a ...interface{}) error {
|
||||
return RetriableError(fmt.Sprintf(format, a...))
|
||||
}
|
||||
|
||||
// Backoff specifies the parameters of the backoff algorithm. Works correctly
|
||||
// if 0 < Min <= Max <= 2^62 (nanosec), and Factor >= 1.
|
||||
type Backoff struct {
|
||||
Min time.Duration // Duration of the first pause.
|
||||
Max time.Duration // Max duration of a pause.
|
||||
Factor float64 // The factor of duration increase between iterations.
|
||||
Jitter bool // Add random noise to pauses.
|
||||
|
||||
delta time.Duration // Current pause duration relative to Min, no jitter.
|
||||
}
|
||||
|
||||
// Duration returns the time to wait on current retry iteration. Every time
|
||||
// Duration is called, the returned value will exponentially increase by Factor
|
||||
// until Backoff.Max. If Jitter is enabled, will add an additional random value
|
||||
// between 0 and the duration, so the result can at most double.
|
||||
func (b *Backoff) Duration() time.Duration {
|
||||
base := b.Min + b.delta
|
||||
pause := base
|
||||
if b.Jitter { // Add a number in the range [0, pause).
|
||||
pause += time.Duration(rand.Int63n(int64(pause)))
|
||||
}
|
||||
|
||||
nextPause := time.Duration(float64(base) * b.Factor)
|
||||
if nextPause > b.Max || nextPause < b.Min { // Multiplication could overflow.
|
||||
nextPause = b.Max
|
||||
}
|
||||
b.delta = nextPause - b.Min
|
||||
|
||||
return pause
|
||||
}
|
||||
|
||||
// Reset sets the internal state back to first retry iteration.
|
||||
func (b *Backoff) Reset() {
|
||||
b.delta = 0
|
||||
}
|
||||
|
||||
// Retry calls a function until it succeeds or the context is done.
|
||||
// It will backoff if the function returns a retryable error.
|
||||
// Once the context is done, retries will end and the most recent error will be returned.
|
||||
// Backoff is not reset by this function.
|
||||
func (b *Backoff) Retry(ctx context.Context, f func() error, retry ...codes.Code) error {
|
||||
// If the context is already done, don't make any attempts to call f.
|
||||
if ctx.Err() != nil {
|
||||
return ctx.Err()
|
||||
}
|
||||
|
||||
// Try calling f while the error is retryable and ctx is not done.
|
||||
for {
|
||||
if err := f(); !IsRetryable(err, retry...) {
|
||||
return err
|
||||
}
|
||||
select {
|
||||
case <-time.After(b.Duration()):
|
||||
case <-ctx.Done():
|
||||
return ctx.Err()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// IsRetryable returns false unless the error is explicitly retriable per
|
||||
// https://godoc.org/google.golang.org/grpc/codes,
|
||||
// or if the error codes is in retry. codes.OK is not retryable.
|
||||
func IsRetryable(err error, retry ...codes.Code) bool {
|
||||
code := status.Code(err)
|
||||
switch code {
|
||||
// Fast path.
|
||||
case codes.OK:
|
||||
return false
|
||||
|
||||
// Debatable cases:
|
||||
case codes.DeadlineExceeded,
|
||||
codes.ResourceExhausted: // Retry with backoff.
|
||||
return true
|
||||
|
||||
// Errors that are explicitly retryable:
|
||||
case codes.Unavailable, // Client can just retry the call.
|
||||
codes.Aborted: // Client can retry the read-modify-write function.
|
||||
return true
|
||||
}
|
||||
|
||||
for _, c := range retry {
|
||||
if code == c {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
// Don't retry for all other errors, unless it is a RetriableError.
|
||||
_, ok := err.(RetriableError)
|
||||
return ok
|
||||
}
|
343
vendor/github.com/google/trillian/client/log_client.go
generated
vendored
343
vendor/github.com/google/trillian/client/log_client.go
generated
vendored
@ -1,343 +0,0 @@
|
||||
// Copyright 2017 Google LLC. 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 client verifies responses from the Trillian log.
|
||||
package client
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/google/trillian"
|
||||
"github.com/google/trillian/client/backoff"
|
||||
"github.com/google/trillian/types"
|
||||
"github.com/transparency-dev/merkle"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// LogClient represents a client for a given Trillian log instance.
|
||||
type LogClient struct {
|
||||
*LogVerifier
|
||||
LogID int64
|
||||
MinMergeDelay time.Duration
|
||||
client trillian.TrillianLogClient
|
||||
root types.LogRootV1
|
||||
rootLock sync.Mutex
|
||||
updateLock sync.Mutex
|
||||
}
|
||||
|
||||
// New returns a new LogClient.
|
||||
func New(logID int64, client trillian.TrillianLogClient, verifier *LogVerifier, root types.LogRootV1) *LogClient {
|
||||
return &LogClient{
|
||||
LogVerifier: verifier,
|
||||
LogID: logID,
|
||||
client: client,
|
||||
root: root,
|
||||
}
|
||||
}
|
||||
|
||||
// NewFromTree creates a new LogClient given a tree config.
|
||||
func NewFromTree(client trillian.TrillianLogClient, config *trillian.Tree, root types.LogRootV1) (*LogClient, error) {
|
||||
verifier, err := NewLogVerifierFromTree(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return New(config.GetTreeId(), client, verifier, root), nil
|
||||
}
|
||||
|
||||
// AddLeaf adds leaf to the append only log.
|
||||
// Blocks and continuously updates the trusted root until a successful inclusion proof
|
||||
// can be retrieved.
|
||||
func (c *LogClient) AddLeaf(ctx context.Context, data []byte) error {
|
||||
if err := c.QueueLeaf(ctx, data); err != nil {
|
||||
return fmt.Errorf("QueueLeaf(): %v", err)
|
||||
}
|
||||
if err := c.WaitForInclusion(ctx, data); err != nil {
|
||||
return fmt.Errorf("WaitForInclusion(): %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ListByIndex returns the requested leaves by index.
|
||||
func (c *LogClient) ListByIndex(ctx context.Context, start, count int64) ([]*trillian.LogLeaf, error) {
|
||||
resp, err := c.client.GetLeavesByRange(ctx,
|
||||
&trillian.GetLeavesByRangeRequest{
|
||||
LogId: c.LogID,
|
||||
StartIndex: start,
|
||||
Count: count,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Verify that we got back the requested leaves.
|
||||
if len(resp.Leaves) < int(count) {
|
||||
return nil, fmt.Errorf("len(Leaves)=%d, want %d", len(resp.Leaves), count)
|
||||
}
|
||||
for i, l := range resp.Leaves {
|
||||
if want := start + int64(i); l.LeafIndex != want {
|
||||
return nil, fmt.Errorf("Leaves[%d].LeafIndex=%d, want %d", i, l.LeafIndex, want)
|
||||
}
|
||||
}
|
||||
|
||||
return resp.Leaves, nil
|
||||
}
|
||||
|
||||
// WaitForRootUpdate repeatedly fetches the latest root until there is an
|
||||
// update, which it then applies, or until ctx times out.
|
||||
func (c *LogClient) WaitForRootUpdate(ctx context.Context) (*types.LogRootV1, error) {
|
||||
b := &backoff.Backoff{
|
||||
Min: 100 * time.Millisecond,
|
||||
Max: 10 * time.Second,
|
||||
Factor: 2,
|
||||
Jitter: true,
|
||||
}
|
||||
|
||||
for {
|
||||
newTrusted, err := c.UpdateRoot(ctx)
|
||||
switch status.Code(err) {
|
||||
case codes.OK:
|
||||
if newTrusted != nil {
|
||||
return newTrusted, nil
|
||||
}
|
||||
case codes.Unavailable, codes.NotFound, codes.FailedPrecondition:
|
||||
// Retry.
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return nil, status.Errorf(codes.DeadlineExceeded, "%v", ctx.Err())
|
||||
case <-time.After(b.Duration()):
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// getAndVerifyLatestRoot fetches and verifies the latest root against a trusted root, seen in the past.
|
||||
// Pass nil for trusted if this is the first time querying this log.
|
||||
func (c *LogClient) getAndVerifyLatestRoot(ctx context.Context, trusted *types.LogRootV1) (*types.LogRootV1, error) {
|
||||
resp, err := c.client.GetLatestSignedLogRoot(ctx,
|
||||
&trillian.GetLatestSignedLogRootRequest{
|
||||
LogId: c.LogID,
|
||||
FirstTreeSize: int64(trusted.TreeSize),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// TODO(gbelvin): Turn on root verification.
|
||||
/*
|
||||
logRoot, err := c.VerifyRoot(&types.LogRootV1{}, resp.GetSignedLogRoot(), nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
*/
|
||||
// TODO(gbelvin): Remove this hack when all implementations store digital signatures.
|
||||
var logRoot types.LogRootV1
|
||||
if err := logRoot.UnmarshalBinary(resp.GetSignedLogRoot().LogRoot); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if trusted.TreeSize > 0 &&
|
||||
logRoot.TreeSize == trusted.TreeSize &&
|
||||
bytes.Equal(logRoot.RootHash, trusted.RootHash) {
|
||||
// Tree has not been updated.
|
||||
return &logRoot, nil
|
||||
}
|
||||
|
||||
// Verify root update if the tree / the latest signed log root isn't empty.
|
||||
if logRoot.TreeSize > 0 {
|
||||
if _, err := c.VerifyRoot(trusted, resp.GetSignedLogRoot(), resp.GetProof().GetHashes()); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return &logRoot, nil
|
||||
}
|
||||
|
||||
// GetRoot returns a copy of the latest trusted root.
|
||||
func (c *LogClient) GetRoot() *types.LogRootV1 {
|
||||
c.rootLock.Lock()
|
||||
defer c.rootLock.Unlock()
|
||||
|
||||
// Copy the internal trusted root in order to prevent clients from modifying it.
|
||||
ret := c.root
|
||||
return &ret
|
||||
}
|
||||
|
||||
// UpdateRoot retrieves the current SignedLogRoot, verifying it against roots this client has
|
||||
// seen in the past, and updating the currently trusted root if the new root verifies, and is
|
||||
// newer than the currently trusted root.
|
||||
func (c *LogClient) UpdateRoot(ctx context.Context) (*types.LogRootV1, error) {
|
||||
// Only one root update should be running at any point in time, because
|
||||
// the update involves a consistency proof from the old value, and if the
|
||||
// old value could change along the way (in another goroutine) then the
|
||||
// result could be inconsistent.
|
||||
//
|
||||
// For example, if the current root is A and two root updates A->B and A->C
|
||||
// happen in parallel, then we might end up with the transitions A->B->C:
|
||||
// cur := A cur := A
|
||||
// getRoot() => B getRoot() => C
|
||||
// proof(A->B) ok proof(A->C) ok
|
||||
// c.root = B
|
||||
// c.root = C
|
||||
// and the last step (B->C) has no proof and so could hide a forked tree.
|
||||
c.updateLock.Lock()
|
||||
defer c.updateLock.Unlock()
|
||||
|
||||
currentlyTrusted := c.GetRoot()
|
||||
newTrusted, err := c.getAndVerifyLatestRoot(ctx, currentlyTrusted)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Lock "rootLock" for the "root" update.
|
||||
c.rootLock.Lock()
|
||||
defer c.rootLock.Unlock()
|
||||
|
||||
if newTrusted.TimestampNanos > currentlyTrusted.TimestampNanos &&
|
||||
newTrusted.TreeSize >= currentlyTrusted.TreeSize {
|
||||
|
||||
// Take a copy of the new trusted root in order to prevent clients from modifying it.
|
||||
c.root = *newTrusted
|
||||
|
||||
return newTrusted, nil
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// WaitForInclusion blocks until the requested data has been verified with an
|
||||
// inclusion proof.
|
||||
//
|
||||
// It will continuously update the root to the latest one available until the
|
||||
// data is found, or an error is returned.
|
||||
//
|
||||
// It is best to call this method with a context that will timeout to avoid
|
||||
// waiting forever.
|
||||
func (c *LogClient) WaitForInclusion(ctx context.Context, data []byte) error {
|
||||
leaf := prepareLeaf(c.hasher, data)
|
||||
|
||||
// If a minimum merge delay has been configured, wait at least that long before
|
||||
// starting to poll
|
||||
if c.MinMergeDelay > 0 {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return status.Errorf(codes.DeadlineExceeded, "%v", ctx.Err())
|
||||
case <-time.After(c.MinMergeDelay):
|
||||
}
|
||||
}
|
||||
|
||||
var root *types.LogRootV1
|
||||
for {
|
||||
root = c.GetRoot()
|
||||
|
||||
// It is illegal to ask for an inclusion proof with TreeSize = 0.
|
||||
if root.TreeSize >= 1 {
|
||||
ok, err := c.getAndVerifyInclusionProof(ctx, leaf.MerkleLeafHash, root)
|
||||
if err != nil && status.Code(err) != codes.NotFound {
|
||||
return err
|
||||
} else if ok {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// If not found or tree is empty, wait for a root update before retrying again.
|
||||
if _, err := c.WaitForRootUpdate(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Retry
|
||||
}
|
||||
}
|
||||
|
||||
func (c *LogClient) getAndVerifyInclusionProof(ctx context.Context, leafHash []byte, sth *types.LogRootV1) (bool, error) {
|
||||
resp, err := c.client.GetInclusionProofByHash(ctx,
|
||||
&trillian.GetInclusionProofByHashRequest{
|
||||
LogId: c.LogID,
|
||||
LeafHash: leafHash,
|
||||
TreeSize: int64(sth.TreeSize),
|
||||
})
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if len(resp.Proof) < 1 {
|
||||
return false, nil
|
||||
}
|
||||
for _, proof := range resp.Proof {
|
||||
if err := c.VerifyInclusionByHash(sth, leafHash, proof); err != nil {
|
||||
return false, fmt.Errorf("VerifyInclusionByHash(): %v", err)
|
||||
}
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// AddSequencedLeaves adds any number of pre-sequenced leaves to the log.
|
||||
// Indexes must be contiguous.
|
||||
func (c *LogClient) AddSequencedLeaves(ctx context.Context, dataByIndex map[int64][]byte) error {
|
||||
if len(dataByIndex) == 0 {
|
||||
return nil
|
||||
}
|
||||
leaves := make([]*trillian.LogLeaf, 0, len(dataByIndex))
|
||||
indexes := make([]int64, 0, len(dataByIndex))
|
||||
for index := range dataByIndex {
|
||||
indexes = append(indexes, index)
|
||||
}
|
||||
sort.Slice(indexes, func(a, b int) bool { return indexes[a] < indexes[b] })
|
||||
|
||||
for i, index := range indexes {
|
||||
// Check index continuity.
|
||||
if want := indexes[0] + int64(i); index != want {
|
||||
return fmt.Errorf("missing index in contiugous index range. got: %v, want: %v", index, want)
|
||||
}
|
||||
leaf := prepareLeaf(c.hasher, dataByIndex[index])
|
||||
leaf.LeafIndex = index
|
||||
leaves = append(leaves, leaf)
|
||||
}
|
||||
resp, err := c.client.AddSequencedLeaves(ctx, &trillian.AddSequencedLeavesRequest{
|
||||
LogId: c.LogID,
|
||||
Leaves: leaves,
|
||||
})
|
||||
for _, leaf := range resp.GetResults() {
|
||||
if s := status.FromProto(leaf.GetStatus()); s.Code() != codes.OK && s.Code() != codes.AlreadyExists {
|
||||
return status.Errorf(s.Code(), "unexpected fail status in AddSequencedLeaves: %+v, err: %v", leaf, s.Message())
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
// QueueLeaf adds a leaf to a Trillian log without blocking.
|
||||
// AlreadyExists is considered a success case by this function.
|
||||
func (c *LogClient) QueueLeaf(ctx context.Context, data []byte) error {
|
||||
leaf := prepareLeaf(c.hasher, data)
|
||||
_, err := c.client.QueueLeaf(ctx, &trillian.QueueLeafRequest{
|
||||
LogId: c.LogID,
|
||||
Leaf: leaf,
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
// prepareLeaf returns a trillian.LogLeaf prepopulated with leaf data and hash.
|
||||
func prepareLeaf(hasher merkle.LogHasher, data []byte) *trillian.LogLeaf {
|
||||
leafHash := hasher.HashLeaf(data)
|
||||
return &trillian.LogLeaf{
|
||||
LeafValue: data,
|
||||
MerkleLeafHash: leafHash,
|
||||
}
|
||||
}
|
91
vendor/github.com/google/trillian/client/log_verifier.go
generated
vendored
91
vendor/github.com/google/trillian/client/log_verifier.go
generated
vendored
@ -1,91 +0,0 @@
|
||||
// Copyright 2017 Google LLC. 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 client
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/google/trillian"
|
||||
"github.com/google/trillian/types"
|
||||
"github.com/transparency-dev/merkle"
|
||||
"github.com/transparency-dev/merkle/proof"
|
||||
"github.com/transparency-dev/merkle/rfc6962"
|
||||
)
|
||||
|
||||
// LogVerifier allows verification of output from Trillian Logs, both regular
|
||||
// and pre-ordered; it is safe for concurrent use (as its contents are fixed
|
||||
// after construction).
|
||||
type LogVerifier struct {
|
||||
// hasher is the hash strategy used to compute nodes in the Merkle tree.
|
||||
hasher merkle.LogHasher
|
||||
}
|
||||
|
||||
// NewLogVerifier returns an object that can verify output from Trillian Logs.
|
||||
func NewLogVerifier(hasher merkle.LogHasher) *LogVerifier {
|
||||
return &LogVerifier{hasher: hasher}
|
||||
}
|
||||
|
||||
// NewLogVerifierFromTree creates a new LogVerifier using the algorithms
|
||||
// specified by a Trillian Tree object.
|
||||
func NewLogVerifierFromTree(config *trillian.Tree) (*LogVerifier, error) {
|
||||
if config == nil {
|
||||
return nil, errors.New("client: NewLogVerifierFromTree(): nil config")
|
||||
}
|
||||
log, pLog := trillian.TreeType_LOG, trillian.TreeType_PREORDERED_LOG
|
||||
if got := config.TreeType; got != log && got != pLog {
|
||||
return nil, fmt.Errorf("client: NewLogVerifierFromTree(): TreeType: %v, want %v or %v", got, log, pLog)
|
||||
}
|
||||
|
||||
return NewLogVerifier(rfc6962.DefaultHasher), nil
|
||||
}
|
||||
|
||||
// VerifyRoot verifies that newRoot is a valid append-only operation from
|
||||
// trusted. If trusted.TreeSize is zero, a consistency proof is not needed.
|
||||
func (c *LogVerifier) VerifyRoot(trusted *types.LogRootV1, newRoot *trillian.SignedLogRoot, consistency [][]byte) (*types.LogRootV1, error) {
|
||||
if trusted == nil {
|
||||
return nil, fmt.Errorf("VerifyRoot() error: trusted == nil")
|
||||
}
|
||||
if newRoot == nil {
|
||||
return nil, fmt.Errorf("VerifyRoot() error: newRoot == nil")
|
||||
}
|
||||
|
||||
var r types.LogRootV1
|
||||
if err := r.UnmarshalBinary(newRoot.LogRoot); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Implicitly trust the first root we get.
|
||||
if trusted.TreeSize != 0 {
|
||||
// Verify consistency proof.
|
||||
if err := proof.VerifyConsistency(c.hasher, trusted.TreeSize, r.TreeSize, consistency, trusted.RootHash, r.RootHash); err != nil {
|
||||
return nil, fmt.Errorf("failed to verify consistency proof from %d->%d %x->%x: %v", trusted.TreeSize, r.TreeSize, trusted.RootHash, r.RootHash, err)
|
||||
}
|
||||
}
|
||||
return &r, nil
|
||||
}
|
||||
|
||||
// VerifyInclusionByHash verifies that the inclusion proof for the given Merkle leafHash
|
||||
// matches the given trusted root.
|
||||
func (c *LogVerifier) VerifyInclusionByHash(trusted *types.LogRootV1, leafHash []byte, pf *trillian.Proof) error {
|
||||
if trusted == nil {
|
||||
return fmt.Errorf("VerifyInclusionByHash() error: trusted == nil")
|
||||
}
|
||||
if pf == nil {
|
||||
return fmt.Errorf("VerifyInclusionByHash() error: proof == nil")
|
||||
}
|
||||
|
||||
return proof.VerifyInclusion(c.hasher, uint64(pf.LeafIndex), trusted.TreeSize, leafHash, pf.Hashes, trusted.RootHash)
|
||||
}
|
Reference in New Issue
Block a user