//
// Copyright 2023 The Project Oak 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 oak.attestation.v1;

import "google/protobuf/timestamp.proto";
import "proto/digest.proto";
import "proto/validity.proto";
import "proto/attestation/tcb_version.proto";
import "proto/session/messages.proto";
import "proto/session/session.proto";

option go_package = "proto/oak/attestation/v1";
option java_multiple_files = true;
option java_package = "com.google.oak.attestation.v1";

// Represents a verification result along with certain measurements and other
// detail to the client for further processing. Nomenclature follows RFC 9334.
message AttestationResults {
  enum Status {
    STATUS_UNSPECIFIED = 0;
    STATUS_SUCCESS = 1;
    STATUS_GENERIC_FAILURE = 2;
  }

  // Indicates whether the verification passed. Used only in conjunction
  // with legacy attestation verification; for policy-based verification
  // this must be STATUS_SUCCESS (note that this is not the default).
  Status status = 1;

  // Provides the reason why verification did not pass, on non-success status.
  // Used only in conjunction with legacy attestation verification; for
  // policy-based verification this field must not be used.
  string reason = 2;

  // Contains the verified public key for encryption whenever the status
  // indicates success. The key is serialized as an X25519 octet string.
  //
  // Deprecated: Use `extracted_evidence.encryption_public_key` instead.
  bytes encryption_public_key = 3 [deprecated = true];

  // Contains the verified public key for signing whenever the status
  // indicates success. The key is serialized using the SEC 1
  // Elliptic-Curve-Point-to-Octet-String conversion.
  //
  // Deprecated: Use `extracted_evidence.signing_public_key` instead.
  bytes signing_public_key = 4 [deprecated = true];

  // Contains the evidence values whenever the status indicates success.
  ExtractedEvidence extracted_evidence = 5;

  // Detailed attestation verification results for each event. The length and
  // order coincides with the number and order of policies in the verifier.
  // Field will not be populated with legacy attestation verification.
  repeated EventAttestationResults event_attestation_results = 6;
}

// Attestation verification results for an individual event.
message EventAttestationResults {
  // Map of artifacts extracted from current event.
  // An example of an artifact could be a encryption public key recorded in the
  // event and signed by the evidence.
  map<string, bytes> artifacts = 1;
}

// Details about the endorsement statement which can be passed across FFI
// boundaries.
message EndorsementDetails {
  reserved 2;

  // Digest of the first subject in the endorsement.
  RawDigest subject_digest = 1;

  // Validity of the verified endorsement.
  oak.Validity valid = 4;

  // All claims contained in the verified endorsement.
  repeated string claim_types = 3;
}

// Evidence values extracted from attestation evidence during verification.
message ExtractedEvidence {
  oneof evidence_values {
    OakRestrictedKernelData oak_restricted_kernel = 1;
    OakContainersData oak_containers = 2;
    // TODO: b/437347371 - move this field out of the Oak codebase.
    CbData cb = 3 [deprecated = true];
    OakStandaloneData standalone = 7625;
  }

  // Contains the public key for encryption. The key is serialized as an X25519
  // octet string.
  bytes encryption_public_key = 4;

  // Contains the public key for signing. The key is serialized using the SEC 1
  // Elliptic-Curve-Point-to-Octet-String conversion.
  bytes signing_public_key = 5;
}

// Values extracted from the root layer evidence.
message RootLayerData {
  oneof report {
    // Values extracted from an AMD SEV-SNP attestation report.
    AmdAttestationReport sev_snp = 1;
    // Values extracted from an Intel TDX attestation report.
    IntelTdxAttestationReport tdx = 2;
    // Values extracted from a fake report when not running in a TEE.
    FakeAttestationReport fake = 3;
  }
}

/// The AMD EPYC CPU model.
enum AmdProduct {
  AMD_PRODUCT_UNSUPPORTED = 0;
  AMD_PRODUCT_MILAN = 1;
  AMD_PRODUCT_GENOA = 2;
  AMD_PRODUCT_TURIN = 3;
}

// Values extracted from an AMD SEV-SNP attestation report.
// NEXT_ID: 9
message AmdAttestationReport {
  // The custom bytes that were passed to the report when it was requested.
  bytes report_data = 1;

  // This represents the actual, up-to-date TCB version of the currently running
  // SEV-SNP firmware. It reflects the latest security patches and updates
  // applied to the firmware.
  TcbVersion current_tcb = 2;

  // This is the TCB version reported in attestation reports. It can be set
  // independently from the current_tcb by the hypervisor. This allows for a
  // smoother transition when updating firmware, giving guest owners time to
  // retrieve new VCEK certificates before switching to a new VCEK derived from
  // the updated TCB.
  // See Section 3.4 of the AMD SEV-SNP specification:
  // https://www.amd.com/content/dam/amd/en/documents/epyc-technical-docs/specifications/56860.pdf
  TcbVersion reported_tcb = 7;

  // Whether the VM was booted in debug mode.
  bool debug = 3;

  // The measurement of the initial memory and CPU state of the VM before
  // startup. This implicitly includes the measurement of the Stage 0 firmware
  // binary.
  bytes initial_measurement = 4;

  // Model of the underlying AMD CPU.
  AmdProduct product = 8;

  // The hardware ID of the AMD SEV-SNP platform that generated the attestation
  // report.
  bytes hardware_id = 5;

  // The VM Protection Leve (VMPL) that was active when the attestation report
  // was generated.
  uint32 vmpl = 6;
}

// Values extracted from an Intel TDX attestation report.
message IntelTdxAttestationReport {
  // The custom bytes that were passed to the report when it was requested.
  bytes report_data = 1;
}

// Values extracted from a fake attestation report when not running in a TEE.
message FakeAttestationReport {
  // The custom bytes that were passed to the report when it was requested.
  bytes report_data = 1;
}

// Values extracted from the the kernel layer evidence, as measured by stage0.
message KernelLayerData {
  // Measured digests of the image part of the kernel.
  RawDigest kernel_image = 1;

  reserved 2;

  // Measured digests of the setup data part of the kernel.
  RawDigest kernel_setup_data = 3;

  // Command-line that was passed to the kernel during startup. If absent,
  // verification will only succeed with the corresponding reference value set
  // to skip (for compatibility with the legacy version of the evidence
  // producing code). Empty value corresponds to the kernel being run with an
  // empty command line.
  optional string kernel_raw_cmd_line = 7;

  // Measured digests of the initial RAM disk.
  RawDigest init_ram_fs = 4;

  // Measured digests of the physical memory map.
  RawDigest memory_map = 5;

  // Measured digests of the commands for building the ACPI tables.
  RawDigest acpi = 6;
}

// Values extracted from the evidence that represents an application running
// under the Oak Restricted Kernel.
message ApplicationLayerData {
  // Measurement RawDigest of the application binary.
  RawDigest binary = 1;

  // Measurement RawDigest of the application configuration.
  RawDigest config = 2;
}

// Values extracted from the evidence that represents the Oak Containers system
// image.
message SystemLayerData {
  // Measurement RawDigest of the system image.
  RawDigest system_image = 1;
}

// Values extracted from the evidence that represents the Container Runtime
// Bundle used in Oak Containers.
message ContainerLayerData {
  // Measurement RawDigest of the container bundle.
  RawDigest bundle = 1;

  // Measurement RawDigest of the configuration used by the container.
  RawDigest config = 2;

  // Key used to encrypt a single message with hybrid encryption before sending
  // it to the enclave. This key must not be used to establish streaming
  // sessions, and each new message must use a random nonce.
  bytes hybrid_encryption_public_key = 3;

  // Key used to verify artifacts signed by the TEE.
  bytes signing_public_key = 4;

  // Key used to verify that Noise session is bound to the evidence.
  bytes session_binding_public_key = 5;
}

// Event that contains public keys corresponding to key pairs generated at the
// application layer.
message ApplicationKeysData {
  // Key used to verify that an encrypted session is bound to the enclave's
  // evidence.
  bytes session_binding_public_key = 1;

  // Key used to encrypt a single message with hybrid encryption before sending
  // it to the enclave. This key must not be used to establish streaming
  // sessions, and each new message must use a random nonce.
  bytes hybrid_encryption_public_key = 2;

  // Key used to verify artifacts generated and signed by the enclave.
  bytes signing_public_key = 3;
}

// Event containing a public key used to verify that an encrypted session is
// bound to the enclave's evidence.
message SessionBindingPublicKeyData {
  // An ECDSA-P256 public key represented as a SEC1 encoded point:
  // <https://www.secg.org/sec1-v2.pdf#page=16>
  bytes session_binding_public_key = 1;
}

// Values extracted from the evidence that represents an event.
message EventData {
  // Measurement RawDigest of an event.
  RawDigest event = 1;
}

// Values extracted from the evidence for a restricted kernel application.
message OakRestrictedKernelData {
  RootLayerData root_layer = 1;
  KernelLayerData kernel_layer = 2;
  ApplicationLayerData application_layer = 3;
}

// Values extracted from the evidence for an Oak Containers instance.
message OakContainersData {
  RootLayerData root_layer = 1;
  KernelLayerData kernel_layer = 2;
  SystemLayerData system_layer = 3;
  ContainerLayerData container_layer = 4;
}

// Values extracted from the evidence for a CB instance.
message CbData {
  RootLayerData root_layer = 1;
  reserved 2, 3, 4;
  repeated EventData layers = 5;
}

// Oak Standalone currently skips all attestation
message OakStandaloneData {}

message CollectedAttestation {
  message RequestMetadata {
    // URI from which the attestation was obtained.
    string uri = 1;
    google.protobuf.Timestamp request_time = 2;
  }
  RequestMetadata request_metadata = 1;

  // Maps unique IDs of attestation providers to the corresponding evidence.
  // This matches the corresponding map in Oak Session.
  map<string, oak.session.v1.EndorsedEvidence> endorsed_evidence = 2;

  // Maps unique IDs of attestation providers to the corresponding session
  // bindings.
  map<string, oak.session.v1.SessionBinding> session_bindings = 3;

  // The hash of the completed Noise handshake transcript.
  bytes handshake_hash = 4;
}
