Skip to content

Sigstore bundle #2204

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 41 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
a644fe5
Added first draft of .sigstore bundle proposal.
kommendorkapten Aug 26, 2022
3cda2fb
s/Pass/check mark/
kommendorkapten Aug 26, 2022
b39ab7c
Use UTF8 chars for Pass/Fail for easier view.
kommendorkapten Aug 26, 2022
1e490d9
Removed generated files. Added some comments and changed name of two …
kommendorkapten Aug 26, 2022
fe3b80f
Added some comments on verify commands that relates to this proposal.
kommendorkapten Aug 26, 2022
b38719c
Updated readme and added comments to the command line parameters.
kommendorkapten Aug 26, 2022
503e307
Added link to pb
kommendorkapten Aug 26, 2022
5d1f224
Added an example verifier.
kommendorkapten Aug 26, 2022
0b7ca83
Clarified verifiction column
kommendorkapten Aug 26, 2022
897bf16
Merge branch 'sigstore:main' into sigstore_bundle
kommendorkapten Aug 26, 2022
d279ce2
Corrected attribute name in JSON serialization.
kommendorkapten Aug 26, 2022
a8ea540
Merge branch 'sigstore_bundle' of github.com:kommendorkapten/cosign i…
kommendorkapten Aug 26, 2022
583ce52
Added generation of Java classes.
kommendorkapten Sep 14, 2022
32e1906
Updates based of PR feedback. Primarily reorganization of existing fi…
kommendorkapten Sep 14, 2022
a55721c
Updated bundle specification based on reviews.
kommendorkapten Sep 16, 2022
acaa725
Clarified how the signature for the integration proof is created.
kommendorkapten Sep 16, 2022
0b593b8
Clarified that a dsse envelope can contain arbitrary payload types.
kommendorkapten Sep 16, 2022
bf640b3
Some clarifications and better namings.
kommendorkapten Sep 19, 2022
eff48b9
Clarified a comment on key/parameters.
kommendorkapten Sep 19, 2022
e4e2e0f
Tightened up the language on using key-pairs.
kommendorkapten Sep 20, 2022
ae934e9
Changed attribute name dsse to dsse_envelope
kommendorkapten Sep 22, 2022
3f67aa4
Added comment on message hash algorithm verification for RFC3161 time…
kommendorkapten Sep 26, 2022
38e65e7
Changed how version is specified.
kommendorkapten Sep 29, 2022
451ef65
Split bundle.proto into separate packages.
kommendorkapten Sep 29, 2022
80a941f
Changed PEM to DER for certificates.
kommendorkapten Sep 30, 2022
d7f8283
Updated HashAlgorithm with unspecified default value to force marshal…
kommendorkapten Sep 30, 2022
ac71f9f
Updated some comments in the proto-files.
kommendorkapten Sep 30, 2022
837567d
Moved verification material to common.
kommendorkapten Sep 30, 2022
c331886
Changed TSTInfo to TimeStampToken as that's where the signature is kept.
kommendorkapten Sep 30, 2022
1145bf7
Updated proto package names to match existing Sigstore Fulcio names.
kommendorkapten Oct 3, 2022
29f29f2
Added comment on TimeStampToken to contain the TSA's cert chain.
kommendorkapten Oct 4, 2022
e65cf3d
Updated the verification pseudo algorithm to match the updated bundle…
kommendorkapten Oct 11, 2022
e6272eb
Added a textual description of the verification steps.
kommendorkapten Oct 13, 2022
bf0e059
Fixed a malformed html tag.
kommendorkapten Oct 13, 2022
5183873
Formatting fixes
kommendorkapten Oct 13, 2022
0ca43ce
Remove all but the probobuf files. Note that the DSSE protobuf is sti…
kommendorkapten Oct 14, 2022
fcef440
Fixed a comment on RFC3161 timestamps
kommendorkapten Oct 17, 2022
428f611
Made checkpoint and signed_entry_timestamp separate datatypes as prop…
kommendorkapten Oct 17, 2022
6b43994
Made x509 certificate and log id first class messages.
kommendorkapten Oct 17, 2022
44c1a68
Reserv a set of fields number for future types.
kommendorkapten Oct 17, 2022
dd6037a
Clarified the difference tlog data vs timestamp data in the 'verifica…
kommendorkapten Oct 19, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
*.so
*.dylib

# Temporary files
*~

# Test binary, built with `go test -c`
*.test

Expand Down
9 changes: 9 additions & 0 deletions specs/dotsigstore_bundle/pb/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
all: protogen-go protogen-java

.PHONY: protogen-go
protogen-go:
docker run -v ${PWD}:/defs namely/protoc-all -d . -l go

.PHONY: protogen-java
protogen-java:
docker run -v ${PWD}:/defs namely/protoc-all -d . -l java
38 changes: 38 additions & 0 deletions specs/dotsigstore_bundle/pb/envelope.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// https://raw.githubusercontent.com/secure-systems-lab/dsse/9c813476bd36de70a5738c72e784f123ecea16af/envelope.proto
syntax = "proto3";

package io.intoto;

option go_package = "github.com/secure-systems-lab/dsse";

// An authenticated message of arbitrary type.
message Envelope {
// Message to be signed. (In JSON, this is encoded as base64.)
// REQUIRED.
bytes payload = 1;

// String unambiguously identifying how to interpret payload.
// REQUIRED.
string payloadType = 2;

// Signature over:
// PAE(type, body)
// Where PAE is defined as:
// PAE(type, body) = "DSSEv1" + SP + LEN(type) + SP + type + SP + LEN(body) + SP + body
// + = concatenation
// SP = ASCII space [0x20]
// "DSSEv1" = ASCII [0x44, 0x53, 0x53, 0x45, 0x76, 0x31]
// LEN(s) = ASCII decimal encoding of the byte length of s, with no leading zeros
// REQUIRED (length >= 1).
repeated Signature signatures = 3;
}

message Signature {
// Signature itself. (In JSON, this is encoded as base64.)
// REQUIRED.
bytes sig = 1;

// *Unauthenticated* hint identifying which public key was used.
// OPTIONAL.
string keyid = 2;
}
77 changes: 77 additions & 0 deletions specs/dotsigstore_bundle/pb/sigstore_bundle.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Copyright 2022 The Sigstore Authors.
//
// 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 dev.sigstore.bundle.v1;

// https://raw.githubusercontent.com/secure-systems-lab/dsse/9c813476bd36de70a5738c72e784f123ecea16af/envelope.proto
import "envelope.proto";
import "sigstore_common.proto";
import "sigstore_rekor.proto";

option go_package = "github.com/sigstore/proto/bundle/v1";
option java_package = "dev.sigstore.proto.bundle.v1";
option java_multiple_files = true;
option java_outer_classname = "BundleProto";

// Notes on versioning.
// The primary message ('Bundle') MUST be versioned, by populating the
// 'media_type' field. Semver-ish (only major/minor versions) scheme MUST
// be used. The current version as specified by this file is:
// application/vnd.dev.sigstore.bundle+json;version=0.1
// The semantic version is thus '0.1'.

// Various timestamped counter signatures over the artifacts signature.
// Currently only RFC3161 signatures are provided. More formats may be added
// in the future.
message TimestampVerificationData {
// A list of RFC3161 signed timestamps provided by the user.
// This can be used when the entry has not been stored on a
// transparency log, or in conjuction for a stronger trust model.
// Clients MUST verify the hashed message in the message imprint
// against the signature in the bundle.
repeated dev.sigstore.common.v1.RFC3161SignedTimestamp rfc3161_timestamps = 1;
}

// VerificationData contains extra data that can be used to verify things
// such as transparency and timestamp of the signature creation.
// As this message can be either empty (no timestamps), or a combination of
// an arbitrarily number of transparency log entries and signed timestamps,
// it is the client's responsibility to implement any required verification
// policies.
message VerificationData {
// This is the regular inclusion promise and proof, where
// the timestamp is coming from the transparency log.
repeated dev.sigstore.rekor.v1.TransparencyLogEntry tlog_entries = 1;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@haydentherapper should we consider making this a oneOf in case there is a new timestamp format we'd want to support in the future?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I had the same thought at one point, but I think the TimestampVerificationData is actually future proof here because it includes 0 or more tlog_entries. We could just add a new repeated dev.sigstore.rekor.v2.TransparencyLogEntry tlog_entries_v2 field.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When did we move tlog_entries under timestamp verification? Was this a new change?

It's not strictly timestamping. The integrated time from the bundle provides time, but the rest of the bundle is used to prove a signing occurred, regardless of time.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought we had something that allowed us to specify both timestamps and tlog entries? Is the expectation that both can be set there?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The proposal came 15th of Sept, and was committed ~25 days ago: #2204 (comment)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought we had something that allowed us to specify both timestamps and tlog entries? Is the expectation that both can be set there?

Yes, that is still the case. As both fields are repeated they can both be 0-n. The example verifier (which is now moved to another branch) verifies both if they are set. But as there are some different ideas on what the usage of TSA is, we can hold off on the verification flow. I'll open an issue on this topic once we have the new repo in place.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh ok, I think my issue is then just with naming - Instead of TimestampVerificationData, can we drop Timestamp?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copying in @znewman01 's comment from 15th Sept (the one I linked to) for more context.
The message was initially called VerificationData (as you are proposing).

To open the bikeshed back up: maybe SignatureTimeVerificationData? TimestampEvidence? But clarify that it has to do with time

Based on this comment I switched to TimestampVerificationData. I understand that it's not strictly timestamp, the tlog entry gives you more. But one important feature of the tlog entry is that it gives an external witness that the signature happened during the time the certificate was valid, and I think many clients will rely on this to accept the signature (beyond just verifying the signature was put on the public ledger).

I'm ok with VerificationData too (as I had that name first :) ).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since @znewman01 said he likes more nested messages, what about this structure?

message TimestampVerificationData {
  repeated TS3161 ts;
  // In the future
  // repeated Roughtime rtchain;
}

message VerificationData {
  repeated RekorBundle b;
  TimestampVerificationData tsv;
}

I'd worry that naming the message something with Timestamp downplays the primary purpose of Rekor, to provide transparency.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice @haydentherapper, I like that proposal!

// Timestamp verirication data, over the artifact's signature.
TimestampVerificationData timestamp_verification_data = 2;
}

message Bundle {
// MUST be application/vnd.dev.sigstore.bundle+json;version=0.1
// when encoded as JSON.
string media_type = 1;
VerificationData verification_data = 2;
dev.sigstore.common.v1.VerificationMaterial verification_material = 3;
oneof content {
dev.sigstore.common.v1.MessageSignature message_signature = 4;
// A DSSE envelope can contain arbitrary payloads.
// Verifiers must verify that the payload type is a
// supported and expected type. This is part of the DSSE
// protocol which is defined here https://github.com/secure-systems-lab/dsse/blob/master/protocol.md
io.intoto.Envelope dsse_envelope = 5;
}
// Reserved for future additions of artifact types.
reserved 6 to 50;
}
105 changes: 105 additions & 0 deletions specs/dotsigstore_bundle/pb/sigstore_common.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// Copyright 2022 The Sigstore Authors.
//
// 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 dev.sigstore.common.v1;

option go_package = "github.com/sigstore/proto/common/v1";
option java_package = "dev.sigstore.proto.common.v1";
option java_multiple_files = true;
option java_outer_classname = "CommonProto";

// This package defines commonly used message types within the Sigstore
// community.

// Only a subset of the secure hash standard algorithms are supported.
// See https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf for more
// details.
// UNSPECIFIED SHOULD not be used, primary reason for inclusion is to force
// any proto JSON serialization to emit the used hash algorithm, as default
// option is to *omit* the default value of an emum (which is the first
// value, represented by '0'.
enum HashAlgorithm {
UNSPECIFIED = 0;
SHA2_256 = 1;
SHA2_512 = 2;
}

// HashOutput captures a digest of a 'message' (generic octet sequence)
// and the corresponding hash algorithm used.
message HashOutput {
HashAlgorithm algorithm = 1;
// This is the raw octets of the message digest as computed by
// the hash algorithm.
bytes digest = 2;
}

// MessageSignature stores the computed signature over a message.
message MessageSignature {
// Message digest can be used to identify the artifact.
HashOutput message_digest = 1;
// The raw bytes as returned from the signature algorithm.
// The signature algorithm (and so the format of the signature bytes)
// are determined by the contents of the 'verification_material',
// either a key-pair or a certificate. If using a certificate, the
// certificate contains the required information on the signature
// algorithm.
// When using a key pair, the algorithm MUST be part of the public
// key, which MUST be communicated out-of-band.
bytes signature = 2;
}

// This message holds a RFC 3161 timestamp.
message RFC3161SignedTimestamp {
// Signed timestamp is the DER encoded TimeStampToken
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@znewman01 @haydentherapper FYI: I changed this to include the TimeStampToken instead of TSTInfo. After reading RFC3161 and RFC2630 more thoroughly I realized that TSTInfo does not capture the actual signature.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's actually TimeStampResp, not just the token

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea was that the Token is extracted from the TimeStampResp prior to be inserted here. Or do you see any real value of having the entire response? If we are extracting the token we will be missing the PKIStatusInfo. My idea was that the client would verify the status first, and only store the token in the bundle if the response was valid.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might be wrong cause I haven't looked into the clients much, but I think most (openssl allows either, but defaults to TimeStampResp) expect the TimeStampResp structure, even with PKIStatusInfo having little value.

I'd probably prefer that clients don't have to extract anything from this response either and can simply persist it.

Copy link
Member Author

@kommendorkapten kommendorkapten Oct 18, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As this is only a comment as of now (what the verifier should expect after decoding the bytes) we can be a bit flexible in the early stages. Also, I think that actually using this field is not something the early adopters will use, I would expect Rekor tlog entries for the near future. But regardless, getting the construct right early on is crucial.

What I could find in terms of libraries:

  • Go: Both response and token.
  • Java: Both response and token
  • Python: Seems to be centered around the time stamp token, but offers decode functions from DER to timestamp token.
  • JavaScript: Seems to offer both methods.
  • Rust: Seems to offer both methods

If we feel that that storing the entire TimeStampResp is more future proof, then we should change to that. I honestly have to little cross-language experience to give any advice.

edit: s/int/in/
edit2: added Rust info

// See https://www.rfc-editor.org/rfc/rfc3161.html#section-2.4.2
// For verification, the TimeStampToken MUST contain TSA's
// certificate chain.
bytes signed_timestamp = 1;
}


// PublicKeyIdentifier can be used to identify an (out of band) delivered
// key, to verify a signature.
message PublicKeyIdentifier {
// Optional unauthenticated hint on which key to use.
// The format of the hint must be agreed upon out of band by the
// signer and the verifiers, and so is not subject to this
// specification.
string hint = 1;
}

message X509Certificate {
// DER encoded X509 certificate.
bytes der_bytes = 1;
}

// A chain of X509 certificates.
message X509CertificateChain {
// The chain of certificates, with indices 0 to n.
// The first certificate in the array must be the leaf
// certificate used for signing. Any intermediate certificates
// must be stored as offset 1 to n-1, and the root certificate at
// position n.
repeated X509Certificate certificates = 1;
}

// VerificationMaterial captures details on the materials used to verify
// signatures.
message VerificationMaterial {
oneof content {
PublicKeyIdentifier public_key = 1;
X509CertificateChain x509_certificate_chain = 2;
}
}
108 changes: 108 additions & 0 deletions specs/dotsigstore_bundle/pb/sigstore_rekor.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
// Copyright 2022 The Sigstore Authors.
//
// 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 dev.sigstore.rekor.v1;

option go_package = "github.com/sigstore/proto/rekor/v1";
option java_package = "dev.sigstore.proto.rekor.v1";
option java_multiple_files = true;
option java_outer_classname = "RekorProto";

// KindVersion contains the entry's kind and api version.
message KindVersion {
// Kind is the type of entry being stored in the log.
// See here for a list: https://github.com/sigstore/rekor/tree/main/pkg/types
string kind = 1;
// The specific api version of the type.
string version = 2;
}

// The checkpoint contains a signature of the tree head (root hash),
// size of the tree, the transparency log's unique identifier (log ID),
// hostname and the current time.
// The result is a string, the format is described here
// https://github.com/transparency-dev/formats/blob/main/log/README.md
// The details are here https://github.com/sigstore/rekor/blob/main/pkg/util/signed_note.go#L114.
// The signature has the same format as
// TransparencyLogEntry.inclusion_proof. See below for more details.
message Checkpoint {
string envelope = 1;
}

// InclusionProof is the proof returned from the transparency log. Can
// be used for on line verification against the log.
message InclusionProof {
// The index of the entry in the log.
int64 log_index = 1;
// The hash digest stored at the root of the merkle tree at the time
// the proof was generated.
bytes root_hash = 2;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be a HashOutput?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably, right now trillian is SHA256 only but that may change in a PQ world.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm on the fence here. If there is a consensus on having this HashOutput I'm totally fine with that.
But, to be able to verify e.g the inclusion promise for an entry, some out-of-band data is already needed, like the public key (which may include parameters/what hash function to use). So there is already a need for certain knowledge of the transparency log, and also sharing what hash function is used for computing the Merkle tree is IMHO not a problem.
Having each entry in the hashes section having the hash algorithm specified will complicate the client code. For each hash output, a new instances of the hash function must be instantiated by the listed one ini the entry. What happens if the first hash is SHA256 and the second is SHA512. Should the client abort? If not, the client would still need to verify that all hashes are using the same algorithm.
I'm not sure the benefits outweighs the consequences here.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another note, the Checkpoint data also contains the root hash, base64 encoded, without a formal method of informing which hash function that was used.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personal bias here: I want as many types as possible always.

Specifically, every time I see a bytes I have to think "what format is that?" If I see HashOutput I think "that's the output of a hash algorithm, I don't care what format it is."

Agreed that it feels wonky to duplicate the algorithm. So maybe there's room for three (!!) types: HashOutput { bytes }, HashAlgorithm = enum and HashData = (HashOutput, HashAlgorithm). I understand if that seems like too much.

some out-of-band data is already needed, like the public key (which may include parameters/what hash function to use). So there is already a need for certain knowledge of the transparency log, and also sharing what hash function is used for computing the Merkle tree is IMHO not a problem.

I buy that. Should we try to enumerate all these parameters in a new type? That feels like a useful exercise. It would allow creating a cross-language test suite!

(Okay if that's a TODO and we don't do it in this PR)

// The size of the merkle tree at the time the proof was generated.
int64 tree_size = 3;
// A list of hashes required to compute the inclusion proof, sorted
// in order from leaf to root.
repeated bytes hashes = 4;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be repeated HashOutput?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think so, same reasoning as above

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See reply above.

// Signature of the current tree head. See above for more details.
Checkpoint checkpoint = 5;
}

// The inclusion promise is calculated by Rekor. It's calculated as a
// signature over a canonical JSON serialization of the persisted entry, the
// log ID, log index and the integration timestamp.
// See https://github.com/sigstore/rekor/blob/main/pkg/api/entries.go#L54
// The format of the signature depends on the transparency log's public key.
// If the signature algorithm requires a hash function and/or a signature
// scheme (e.g. RSA) those has to be retrieved out-of-band from the log's
// operators, together with the public key.
// This is primarily used to verify the integration timestamp's value.
message InclusionPromise {
bytes signed_entry_timestamp = 1;
}

// LogId captures the identity of a transparceny log.
message LogId {
// The unique id of the log, represented as the SHA-256 hash
// of the log's public key, computed over the DER encoding.
// This is similar to how it works for certificate transparency logs:
// https://www.rfc-editor.org/rfc/rfc6962#section-3.2
bytes key_id = 1;
}

// TransparencyLogEntry captures all the details required from Rekor to
// reconstruct an entry, given that the payload is provided via other means.
// This type can easily be created from the existing response from Rekor.
// Future iterations could rely on Rekor returning the minimal set of
// attributes (excluding the payload) that are required for verifying the
// inclusion promise. The inclusion promise (called SignedEntryTimestamp in
// the response from Rekor) is similar to a Signed Certificate Timestamp
// as described here https://www.rfc-editor.org/rfc/rfc9162#name-signed-certificate-timestam.
message TransparencyLogEntry {
// The index of the entry in the log.
int64 log_index = 1;
// The unique identifier of the log.
LogId log_id = 2;
// The kind (type) and version of the object associated with this
// entry. These values are required to construct the entry during
// verification.
KindVersion kind_version = 3;
// The UNIX timestamp from the log when the entry was persisted.
int64 integrated_time = 4;
// The inclusion promise/signed entry timestamp from the log.
InclusionPromise inclusion_promise = 5;
// The inclusion proof can be used for online verification that the
// entry was appended to the log, and that the log has not been
// altered.
optional InclusionProof inclusion_proof = 6;
}