mirror of https://github.com/containers/podman.git
364 lines
15 KiB
Protocol Buffer
364 lines
15 KiB
Protocol Buffer
// Copyright 2016 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.
|
|
|
|
syntax = "proto3";
|
|
|
|
package trillian;
|
|
|
|
option go_package = "github.com/google/trillian";
|
|
option java_multiple_files = true;
|
|
option java_outer_classname = "TrillianLogApiProto";
|
|
option java_package = "com.google.trillian.proto";
|
|
|
|
import "google/protobuf/timestamp.proto";
|
|
import "google/rpc/status.proto";
|
|
import "trillian.proto";
|
|
|
|
// The TrillianLog service provides access to an append-only Log data structure
|
|
// as described in the [Verifiable Data
|
|
// Structures](docs/papers/VerifiableDataStructures.pdf) paper.
|
|
//
|
|
// The API supports adding new entries to the Merkle tree for a specific Log
|
|
// instance (identified by its log_id) in two modes:
|
|
// - For a normal log, new leaf entries are queued up for subsequent
|
|
// inclusion in the log, and the leaves are assigned consecutive leaf_index
|
|
// values as part of that integration process.
|
|
// - For a 'pre-ordered log', new entries have an already-defined leaf
|
|
// ordering, and leaves are only integrated into the Merkle tree when a
|
|
// contiguous range of leaves is available.
|
|
//
|
|
// The API also supports read operations to retrieve leaf contents, and to
|
|
// provide cryptographic proofs of leaf inclusion and of the append-only nature
|
|
// of the Log.
|
|
//
|
|
// Each API request also includes a charge_to field, which allows API users
|
|
// to provide quota identifiers that should be "charged" for each API request
|
|
// (and potentially rejected with codes.ResourceExhausted).
|
|
//
|
|
// Various operations on the API also allows for 'server skew', which can occur
|
|
// when different API requests happen to be handled by different server instances
|
|
// that may not all be up to date. An API request that is relative to a specific
|
|
// tree size may reach a server instance that is not yet aware of this tree size;
|
|
// in this case the server will typically return an OK response that contains:
|
|
// - a signed log root that indicates the tree size that it is aware of
|
|
// - an empty response otherwise.
|
|
service TrillianLog {
|
|
// QueueLeaf adds a single leaf to the queue of pending leaves for a normal
|
|
// log.
|
|
rpc QueueLeaf(QueueLeafRequest) returns (QueueLeafResponse) {}
|
|
|
|
// GetInclusionProof returns an inclusion proof for a leaf with a given index
|
|
// in a particular tree.
|
|
//
|
|
// If the requested tree_size is larger than the server is aware of, the
|
|
// response will include the latest known log root and an empty proof.
|
|
rpc GetInclusionProof(GetInclusionProofRequest)
|
|
returns (GetInclusionProofResponse) {}
|
|
|
|
// GetInclusionProofByHash returns an inclusion proof for any leaves that have
|
|
// the given Merkle hash in a particular tree.
|
|
//
|
|
// If any of the leaves that match the given Merkle has have a leaf index that
|
|
// is beyond the requested tree size, the corresponding proof entry will be empty.
|
|
rpc GetInclusionProofByHash(GetInclusionProofByHashRequest)
|
|
returns (GetInclusionProofByHashResponse) {}
|
|
|
|
// GetConsistencyProof returns a consistency proof between different sizes of
|
|
// a particular tree.
|
|
//
|
|
// If the requested tree size is larger than the server is aware of,
|
|
// the response will include the latest known log root and an empty proof.
|
|
rpc GetConsistencyProof(GetConsistencyProofRequest)
|
|
returns (GetConsistencyProofResponse) {}
|
|
|
|
// GetLatestSignedLogRoot returns the latest log root for a given tree,
|
|
// and optionally also includes a consistency proof from an earlier tree size
|
|
// to the new size of the tree.
|
|
//
|
|
// If the earlier tree size is larger than the server is aware of,
|
|
// an InvalidArgument error is returned.
|
|
rpc GetLatestSignedLogRoot(GetLatestSignedLogRootRequest)
|
|
returns (GetLatestSignedLogRootResponse) {}
|
|
|
|
// GetEntryAndProof returns a log leaf and the corresponding inclusion proof
|
|
// to a specified tree size, for a given leaf index in a particular tree.
|
|
//
|
|
// If the requested tree size is unavailable but the leaf is
|
|
// in scope for the current tree, the returned proof will be for the
|
|
// current tree size rather than the requested tree size.
|
|
rpc GetEntryAndProof(GetEntryAndProofRequest)
|
|
returns (GetEntryAndProofResponse) {}
|
|
|
|
// InitLog initializes a particular tree, creating the initial signed log
|
|
// root (which will be of size 0).
|
|
rpc InitLog(InitLogRequest) returns (InitLogResponse) {}
|
|
|
|
|
|
// AddSequencedLeaves adds a batch of leaves with assigned sequence numbers
|
|
// to a pre-ordered log. The indices of the provided leaves must be contiguous.
|
|
rpc AddSequencedLeaves(AddSequencedLeavesRequest)
|
|
returns (AddSequencedLeavesResponse) {}
|
|
|
|
// GetLeavesByRange returns a batch of leaves whose leaf indices are in a
|
|
// sequential range.
|
|
rpc GetLeavesByRange(GetLeavesByRangeRequest)
|
|
returns (GetLeavesByRangeResponse) {}
|
|
}
|
|
|
|
// ChargeTo describes the user(s) associated with the request whose quota should
|
|
// be checked and charged.
|
|
message ChargeTo {
|
|
// user is a list of personality-defined strings.
|
|
// Trillian will treat them as /User/%{user}/... keys when checking and
|
|
// charging quota.
|
|
// If one or more of the specified users has insufficient quota, the
|
|
// request will be denied.
|
|
//
|
|
// As an example, a Certificate Transparency frontend might set the following
|
|
// user strings when sending a QueueLeaf request to the Trillian log:
|
|
// - The requesting IP address.
|
|
// This would limit the number of requests per IP.
|
|
// - The "intermediate-<hash>" for each of the intermediate certificates in
|
|
// the submitted chain.
|
|
// This would have the effect of limiting the rate of submissions under
|
|
// a given intermediate/root.
|
|
repeated string user = 1;
|
|
}
|
|
|
|
message QueueLeafRequest {
|
|
int64 log_id = 1;
|
|
LogLeaf leaf = 2;
|
|
ChargeTo charge_to = 3;
|
|
}
|
|
|
|
message QueueLeafResponse {
|
|
// queued_leaf describes the leaf which is or will be incorporated into the
|
|
// Log. If the submitted leaf was already present in the Log (as indicated by
|
|
// its leaf identity hash), then the returned leaf will be the pre-existing
|
|
// leaf entry rather than the submitted leaf.
|
|
QueuedLogLeaf queued_leaf = 2;
|
|
}
|
|
|
|
message GetInclusionProofRequest {
|
|
int64 log_id = 1;
|
|
int64 leaf_index = 2;
|
|
int64 tree_size = 3;
|
|
ChargeTo charge_to = 4;
|
|
}
|
|
|
|
message GetInclusionProofResponse {
|
|
// The proof field may be empty if the requested tree_size was larger
|
|
// than that available at the server (e.g. because there is skew between
|
|
// server instances, and an earlier client request was processed by a
|
|
// more up-to-date instance). In this case, the signed_log_root
|
|
// field will indicate the tree size that the server is aware of, and
|
|
// the proof field will be empty.
|
|
Proof proof = 2;
|
|
SignedLogRoot signed_log_root = 3;
|
|
}
|
|
|
|
message GetInclusionProofByHashRequest {
|
|
int64 log_id = 1;
|
|
// The leaf hash field provides the Merkle tree hash of the leaf entry
|
|
// to be retrieved.
|
|
bytes leaf_hash = 2;
|
|
int64 tree_size = 3;
|
|
bool order_by_sequence = 4;
|
|
ChargeTo charge_to = 5;
|
|
}
|
|
|
|
message GetInclusionProofByHashResponse {
|
|
// Logs can potentially contain leaves with duplicate hashes so it's possible
|
|
// for this to return multiple proofs. If the leaf index for a particular
|
|
// instance of the requested Merkle leaf hash is beyond the requested tree
|
|
// size, the corresponding proof entry will be missing.
|
|
repeated Proof proof = 2;
|
|
SignedLogRoot signed_log_root = 3;
|
|
}
|
|
|
|
message GetConsistencyProofRequest {
|
|
int64 log_id = 1;
|
|
int64 first_tree_size = 2;
|
|
int64 second_tree_size = 3;
|
|
ChargeTo charge_to = 4;
|
|
}
|
|
|
|
message GetConsistencyProofResponse {
|
|
// The proof field may be empty if the requested tree_size was larger
|
|
// than that available at the server (e.g. because there is skew between
|
|
// server instances, and an earlier client request was processed by a
|
|
// more up-to-date instance). In this case, the signed_log_root
|
|
// field will indicate the tree size that the server is aware of, and
|
|
// the proof field will be empty.
|
|
Proof proof = 2;
|
|
SignedLogRoot signed_log_root = 3;
|
|
}
|
|
|
|
message GetLatestSignedLogRootRequest {
|
|
int64 log_id = 1;
|
|
ChargeTo charge_to = 2;
|
|
// If first_tree_size is non-zero, the response will include a consistency
|
|
// proof between first_tree_size and the new tree size (if not smaller).
|
|
int64 first_tree_size = 3;
|
|
}
|
|
|
|
message GetLatestSignedLogRootResponse {
|
|
SignedLogRoot signed_log_root = 2;
|
|
// proof is filled in with a consistency proof if first_tree_size in
|
|
// GetLatestSignedLogRootRequest is non-zero (and within the tree size
|
|
// available at the server).
|
|
Proof proof = 3;
|
|
}
|
|
|
|
message GetEntryAndProofRequest {
|
|
int64 log_id = 1;
|
|
int64 leaf_index = 2;
|
|
int64 tree_size = 3;
|
|
ChargeTo charge_to = 4;
|
|
}
|
|
|
|
message GetEntryAndProofResponse {
|
|
Proof proof = 2;
|
|
LogLeaf leaf = 3;
|
|
SignedLogRoot signed_log_root = 4;
|
|
}
|
|
|
|
message InitLogRequest {
|
|
int64 log_id = 1;
|
|
ChargeTo charge_to = 2;
|
|
}
|
|
|
|
message InitLogResponse {
|
|
SignedLogRoot created = 1;
|
|
}
|
|
|
|
message AddSequencedLeavesRequest {
|
|
int64 log_id = 1;
|
|
repeated LogLeaf leaves = 2;
|
|
ChargeTo charge_to = 4;
|
|
}
|
|
|
|
message AddSequencedLeavesResponse {
|
|
// Same number and order as in the corresponding request.
|
|
repeated QueuedLogLeaf results = 2;
|
|
}
|
|
|
|
message GetLeavesByRangeRequest {
|
|
int64 log_id = 1;
|
|
int64 start_index = 2;
|
|
int64 count = 3;
|
|
ChargeTo charge_to = 4;
|
|
}
|
|
|
|
message GetLeavesByRangeResponse {
|
|
// Returned log leaves starting from the `start_index` of the request, in
|
|
// order. There may be fewer than `request.count` leaves returned, if the
|
|
// requested range extended beyond the size of the tree or if the server opted
|
|
// to return fewer leaves than requested.
|
|
repeated LogLeaf leaves = 1;
|
|
SignedLogRoot signed_log_root = 2;
|
|
}
|
|
|
|
// QueuedLogLeaf provides the result of submitting an entry to the log.
|
|
// TODO(pavelkalinnikov): Consider renaming it to AddLogLeafResult or the like.
|
|
message QueuedLogLeaf {
|
|
// The leaf as it was stored by Trillian. Empty unless `status.code` is:
|
|
// - `google.rpc.OK`: the `leaf` data is the same as in the request.
|
|
// - `google.rpc.ALREADY_EXISTS` or 'google.rpc.FAILED_PRECONDITION`: the
|
|
// `leaf` is the conflicting one already in the log.
|
|
LogLeaf leaf = 1;
|
|
|
|
// The status of adding the leaf.
|
|
// - `google.rpc.OK`: successfully added.
|
|
// - `google.rpc.ALREADY_EXISTS`: the leaf is a duplicate of an already
|
|
// existing one. Either `leaf_identity_hash` is the same in the `LOG`
|
|
// mode, or `leaf_index` in the `PREORDERED_LOG`.
|
|
// - `google.rpc.FAILED_PRECONDITION`: A conflicting entry is already
|
|
// present in the log, e.g., same `leaf_index` but different `leaf_data`.
|
|
google.rpc.Status status = 2;
|
|
}
|
|
|
|
// LogLeaf describes a leaf in the Log's Merkle tree, corresponding to a single log entry.
|
|
// Each leaf has a unique leaf index in the scope of this tree. Clients submitting new
|
|
// leaf entries should only set the following fields:
|
|
// - leaf_value
|
|
// - extra_data (optionally)
|
|
// - leaf_identity_hash (optionally)
|
|
// - leaf_index (iff the log is a PREORDERED_LOG)
|
|
message LogLeaf {
|
|
// merkle_leaf_hash holds the Merkle leaf hash over leaf_value. This is
|
|
// calculated by the Trillian server when leaves are added to the tree, using
|
|
// the defined hashing algorithm and strategy for the tree; as such, the client
|
|
// does not need to set it on leaf submissions.
|
|
bytes merkle_leaf_hash = 1;
|
|
|
|
// leaf_value holds the data that forms the value of the Merkle tree leaf.
|
|
// The client should set this field on all leaf submissions, and is
|
|
// responsible for ensuring its validity (the Trillian server treats it as an
|
|
// opaque blob).
|
|
bytes leaf_value = 2;
|
|
|
|
// extra_data holds additional data associated with the Merkle tree leaf.
|
|
// The client may set this data on leaf submissions, and the Trillian server
|
|
// will return it on subsequent read operations. However, the contents of
|
|
// this field are not covered by and do not affect the Merkle tree hash
|
|
// calculations.
|
|
bytes extra_data = 3;
|
|
|
|
// leaf_index indicates the index of this leaf in the Merkle tree.
|
|
// This field is returned on all read operations, but should only be
|
|
// set for leaf submissions in PREORDERED_LOG mode (for a normal log
|
|
// the leaf index is assigned by Trillian when the submitted leaf is
|
|
// integrated into the Merkle tree).
|
|
int64 leaf_index = 4;
|
|
|
|
// leaf_identity_hash provides a hash value that indicates the client's
|
|
// concept of which leaf entries should be considered identical.
|
|
//
|
|
// This mechanism allows the client personality to indicate that two leaves
|
|
// should be considered "duplicates" even though their `leaf_value`s differ.
|
|
//
|
|
// If this is not set on leaf submissions, the Trillian server will take its
|
|
// value to be the same as merkle_leaf_hash (and thus only leaves with
|
|
// identical leaf_value contents will be considered identical).
|
|
//
|
|
// For example, in Certificate Transparency each certificate submission is
|
|
// associated with a submission timestamp, but subsequent submissions of the
|
|
// same certificate should be considered identical. This is achieved
|
|
// by setting the leaf identity hash to a hash over (just) the certificate,
|
|
// whereas the Merkle leaf hash encompasses both the certificate and its
|
|
// submission time -- allowing duplicate certificates to be detected.
|
|
//
|
|
//
|
|
// Continuing the CT example, for a CT mirror personality (which must allow
|
|
// dupes since the source log could contain them), the part of the
|
|
// personality which fetches and submits the entries might set
|
|
// `leaf_identity_hash` to `H(leaf_index||cert)`.
|
|
//
|
|
// TODO(pavelkalinnikov): Consider instead using `H(cert)` and allowing
|
|
// identity hash dupes in `PREORDERED_LOG` mode, for it can later be
|
|
// upgraded to `LOG` which will need to correctly detect duplicates with
|
|
// older entries when new ones get queued.
|
|
bytes leaf_identity_hash = 5;
|
|
|
|
// queue_timestamp holds the time at which this leaf was queued for
|
|
// inclusion in the Log, or zero if the entry was submitted without
|
|
// queuing. Clients should not set this field on submissions.
|
|
google.protobuf.Timestamp queue_timestamp = 6;
|
|
|
|
// integrate_timestamp holds the time at which this leaf was integrated into
|
|
// the tree. Clients should not set this field on submissions.
|
|
google.protobuf.Timestamp integrate_timestamp = 7;
|
|
}
|