// 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.trustroot.v1;

import "google/api/field_behavior.proto";
import "sigstore_common.proto";

option go_package = "github.com/sigstore/protobuf-specs/gen/pb-go/trustroot/v1";
option java_package = "dev.sigstore.proto.trustroot.v1";
option java_multiple_files = true;
option java_outer_classname = "TrustRootProto";
option ruby_package = "Sigstore::TrustRoot::V1";

// TransparencyLogInstance describes the immutable parameters from a
// transparency log.
// See https://www.rfc-editor.org/rfc/rfc9162.html#name-log-parameters
// for more details.
// The included parameters are the minimal set required to identify a log,
// and verify an inclusion proof/promise.
message TransparencyLogInstance {
        // The base URL at which can be used to URLs for the client.
        string base_url = 1;
        // The hash algorithm used for the Merkle Tree.
        dev.sigstore.common.v1.HashAlgorithm hash_algorithm = 2;
        // The public key used to verify signatures generated by the log.
        // This attribute contains the signature algorithm used by the log.
        dev.sigstore.common.v1.PublicKey public_key = 3;
        // The unique identifier for this transparency log.
        // Represented as the SHA-256 hash of the log's public key,
        // calculated over the DER encoding of the key represented as
        // SubjectPublicKeyInfo.
        // See https://www.rfc-editor.org/rfc/rfc6962#section-3.2
        dev.sigstore.common.v1.LogId log_id = 4;
        // The checkpoint key identifier for the log used in a checkpoint.
        // Optional, not provided for logs that do not generate checkpoints.
        // For logs that do generate checkpoints, if not set, assume
        // log_id equals checkpoint_key_id.
        // Follows the specification described here
        // for ECDSA and Ed25519 signatures:
        // https://github.com/C2SP/C2SP/blob/main/signed-note.md#signatures
        // For RSA signatures, the key ID will match the ECDSA format, the
        // hashed DER-encoded SPKI public key. Publicly witnessed logs MUST NOT
        // use RSA-signed checkpoints, since witnesses do not support
        // RSA signatures.
        // This is provided for convenience. Clients can also calculate the
        // checkpoint key ID given the log's public key.
        // SHOULD be set for logs generating Ed25519 signatures.
        // SHOULD be 4 bytes long, as a truncated hash.
        dev.sigstore.common.v1.LogId checkpoint_key_id = 5;
}

// CertificateAuthority enlists the information required to identify which
// CA to use and perform signature verification.
message CertificateAuthority {
        // The root certificate MUST be self-signed, and so the subject and
        // issuer are the same.
        dev.sigstore.common.v1.DistinguishedName subject = 1;
        // The URI identifies the certificate authority.
        //
        // It is RECOMMENDED that the URI is the base URL for the certificate
        // authority, that can be provided to any SDK/client provided
        // by the certificate authority to interact with the certificate
        // authority.
        string uri = 2;
        // The certificate chain for this CA. The last certificate in the chain
        // MUST be the trust anchor. The trust anchor MAY be a self-signed root
        // CA certificate or MAY be an intermediate CA certificate.
        dev.sigstore.common.v1.X509CertificateChain cert_chain = 3;
        // The time the *entire* chain was valid. This is at max the
        // longest interval when *all* certificates in the chain were valid,
        // but it MAY be shorter. Clients MUST check timestamps against *both*
        // the `valid_for` time range *and* the entire certificate chain.
        //
        // The TimeRange should be considered valid *inclusive* of the
        // endpoints.
        dev.sigstore.common.v1.TimeRange valid_for = 4;
}

// TrustedRoot describes the client's complete set of trusted entities.
// How the TrustedRoot is populated is not specified, but can be a
// combination of many sources such as TUF repositories, files on disk etc.
//
// The TrustedRoot is not meant to be used for any artifact verification, only
// to capture the complete/global set of trusted verification materials.
// When verifying an artifact, based on the artifact and policies, a selection
// of keys/authorities are expected to be extracted and provided to the
// verification function. This way the set of keys/authorities can be kept to
// a minimal set by the policy to gain better control over what signatures
// that are allowed.
//
// The embedded transparency logs, CT logs, CAs and TSAs MUST include any
// previously used instance -- otherwise signatures made in the past cannot
// be verified.
//
// All the listed instances SHOULD be sorted by the 'valid_for' in ascending
// order, that is, the oldest instance first. Only the last instance is
// allowed to have their 'end' timestamp unset. All previous instances MUST
// have a closed interval of validity. The last instance MAY have a closed
// interval. Clients MUST accept instances that overlaps in time, if not
// clients may experience problems during rotations of verification
// materials.
//
// To be able to manage planned rotations of either transparency logs or
// certificate authorities, clienst MUST accept lists of instances where
// the last instance have a 'valid_for' that belongs to the future.
// This should not be a problem as clients SHOULD first seek the trust root
// for a suitable instance before creating a per artifact trust root (that
// is, a sub-set of the complete trust root) that is used for verification.
message TrustedRoot {
        // MUST be application/vnd.dev.sigstore.trustedroot.v0.1+json
        // when encoded as JSON.
        // Clients MUST be able to process and parse content with the media
        // type defined in the old format:
        // application/vnd.dev.sigstore.trustedroot+json;version=0.1
        string media_type = 1;
        // A set of trusted Rekor servers.
        repeated TransparencyLogInstance tlogs = 2;
        // A set of trusted certificate authorities (e.g Fulcio), and any
        // intermediate certificates they provide.
        // If a CA is issuing multiple intermediate certificate, each
        // combination shall be represented as separate chain. I.e, a single
        // root cert may appear in multiple chains but with different
        // intermediate and/or leaf certificates.
        // The certificates are intended to be used for verifying artifact
        // signatures.
        repeated CertificateAuthority certificate_authorities = 3;
        // A set of trusted certificate transparency logs.
        repeated TransparencyLogInstance ctlogs = 4;
        // A set of trusted timestamping authorities.
        repeated CertificateAuthority timestamp_authorities = 5;
}


// SigningConfig represents the trusted entities/state needed by Sigstore
// signing. In particular, it primarily contains service URLs that a Sigstore
// signer may need to connect to for the online aspects of signing.
message SigningConfig {
        // MUST be application/vnd.dev.sigstore.signingconfig.v0.2+json
        // Clients MAY choose to also support
        // application/vnd.dev.sigstore.signingconfig.v0.1+json
        string media_type = 5;

        // URLs to Fulcio-compatible CAs, capable of receiving
        // Certificate Signing Requests (CSRs) and responding with
        // issued certificates.
        //
        // These URLs MUST be the "base" URL for the CAs, which clients
        // should construct an appropriate CSR endpoint on top of.
        // For example, if a CA URL is `https://example.com/ca`, then
        // the client MAY construct the CSR endpoint as
        // `https://example.com/ca/api/v2/signingCert`.
        //
        // Clients MUST select only one Service with the highest API version
        // that the client is compatible with, that is within its
        // validity period, and has the newest validity start date.
        // Client SHOULD select the first Service that meets this requirement.
        // All listed Services SHOULD be sorted by the `valid_for` window in
        // descending order, with the newest instance first.
        repeated Service ca_urls = 6;

        // URLs to OpenID Connect identity providers.
        //
        // These URLs MUST be the "base" URLs for the OIDC IdPs, which clients
        // should perform well-known OpenID Connect discovery against.
        //
        // Clients MUST select only one Service with the highest API version
        // that the client is compatible with, that is within its
        // validity period, and has the newest validity start date.
        // Client SHOULD select the first Service that meets this requirement.
        // All listed Services SHOULD be sorted by the `valid_for` window in
        // descending order, with the newest instance first.
        repeated Service oidc_urls = 7;

        // URLs to Rekor transparency logs.
        //
        // These URL MUST be the "base" URLs for the transparency logs,
        // which clients should construct appropriate API endpoints on top of.
        //
        // Clients MUST select Services with the highest API version
        // that the client is compatible with, that are within its
        // validity period, and have the newest validity start dates.
        // All listed Services SHOULD be sorted by the `valid_for` window in
        // descending order, with the newest instance first.
        //
        // Clients MUST select Services based on the selector value of
        // `rekor_tlog_config`.
        repeated Service rekor_tlog_urls = 8;

        // Specifies how a client should select the set of Rekor transparency
        // logs to write to.
        ServiceConfiguration rekor_tlog_config = 9;

        // URLs to RFC 3161 Time Stamping Authorities (TSA).
        //
        // These URLs MUST be the *full* URL for the TSA, meaning that it
        // should be suitable for submitting Time Stamp Requests (TSRs) to
        // via HTTP, per RFC 3161.
        //
        // Clients MUST select Services with the highest API version
        // that the client is compatible with, that are within its
        // validity period, and have the newest validity start dates.
        // All listed Services SHOULD be sorted by the `valid_for` window in
        // descending order, with the newest instance first.
        //
        // Clients MUST select Services based on the selector value of
        // `tsa_config`.
        repeated Service tsa_urls = 10;

        // Specifies how a client should select the set of TSAs to request
        // signed timestamps from.
        ServiceConfiguration tsa_config = 11;

        // Reserved tags for previously defined service URL fields
        reserved 1 to 4;
}

// Service represents an instance of a service that is a part of Sigstore infrastructure.
// Clients MUST use the API version hint to determine the service with the
// highest API version that the client is compatible with. Clients MUST also
// only connect to services within the specified validity period and that has the
// newest validity start date.
message Service {
        // URL of the service. MUST include scheme and authority. MAY include path.
        string url = 1;

        // Specifies the major API version. A value of 0 represents a service that
        // has not yet been released.
        uint32 major_api_version = 2;

        // Validity period of a service. A service that has only a start date
        // SHOULD be considered the most recent instance of that service, but
        // the client MUST NOT assume there is only one valid instance.
        // The TimeRange MUST be considered valid *inclusive* of the
        // endpoints.
        dev.sigstore.common.v1.TimeRange valid_for = 3;
}

// ServiceSelector specifies how a client SHOULD select a set of
// Services to connect to. A client SHOULD throw an error if
// the value is SERVICE_SELECTOR_UNDEFINED.
enum ServiceSelector {
        SERVICE_SELECTOR_UNDEFINED = 0;
        // Clients SHOULD select all Services based on supported API version
        // and validity window.
        ALL = 1;
        // Clients SHOULD select one Service based on supported API version
        // and validity window. It is up to the client implementation to
        // decide how to select the Service, e.g. random or round-robin. 
        ANY = 2;
        // Clients SHOULD select a specific number of Services based on
        // supported API version and validity window, using the provided
        // `count`. It is up to the client implementation to decide how to
        // select the Service, e.g. random or round-robin. 
        EXACT = 3;
}

// ServiceConfiguration specifies how a client should select a set of
// Services to connect to, along with a count when a specific number
// of Services is requested.
message ServiceConfiguration {
        // How a client should select a set of Services to connect to.
        ServiceSelector selector = 1;

        // count specifies the number of Services the client should use.
        // Only used when selector is set to EXACT, and count MUST be greater
        // than 0. count MUST be less than or equal to the number of Services.
        uint32 count = 2;
}

// ClientTrustConfig describes the complete state needed by a client
// to perform both signing and verification operations against a particular
// instance of Sigstore.
message ClientTrustConfig {
        // MUST be application/vnd.dev.sigstore.clienttrustconfig.v0.1+json
        string media_type = 1;

        // The root of trust, which MUST be present.
        TrustedRoot trusted_root = 2 [(google.api.field_behavior) = REQUIRED];

        // Configuration for signing clients, which MUST be present.
        SigningConfig signing_config = 3 [(google.api.field_behavior) = REQUIRED];
}
