diff --git a/oak_attestation_verification/src/policy/application.rs b/oak_attestation_verification/src/policy/application.rs index 7fa1d49290..77be726b65 100644 --- a/oak_attestation_verification/src/policy/application.rs +++ b/oak_attestation_verification/src/policy/application.rs @@ -15,7 +15,7 @@ // use anyhow::Context; -use oak_attestation_verification_types::{policy::Policy, APPLICATION_ENDORSEMENT_ID}; +use oak_attestation_verification_types::policy::Policy; use oak_proto_rust::oak::{ attestation::v1::{ ApplicationEndorsement, ApplicationLayerData, ApplicationLayerReferenceValues, @@ -26,8 +26,7 @@ use oak_proto_rust::oak::{ use crate::{ compare::compare_application_layer_measurement_digests, - expect::acquire_application_event_expected_values, - util::{decode_endorsement_proto, decode_event_proto}, + expect::acquire_application_event_expected_values, util::decode_event_proto, }; pub struct ApplicationPolicy { @@ -47,17 +46,15 @@ impl Policy<[u8], Variant> for ApplicationPolicy { fn verify( &self, encoded_event: &[u8], - encoded_event_endorsement: &Variant, + encoded_endorsement: &Variant, milliseconds_since_epoch: i64, ) -> anyhow::Result { let event = decode_event_proto::( "type.googleapis.com/oak.attestation.v1.ApplicationLayerData", encoded_event, )?; - let endorsement = decode_endorsement_proto::( - &APPLICATION_ENDORSEMENT_ID, - encoded_event_endorsement, - )?; + let endorsement: ApplicationEndorsement = + encoded_endorsement.try_into().map_err(anyhow::Error::msg)?; let expected_values = acquire_application_event_expected_values( milliseconds_since_epoch, diff --git a/oak_attestation_verification/src/policy/binary.rs b/oak_attestation_verification/src/policy/binary.rs index 49309a2acc..3164f549b1 100644 --- a/oak_attestation_verification/src/policy/binary.rs +++ b/oak_attestation_verification/src/policy/binary.rs @@ -40,7 +40,7 @@ impl Policy<[u8], Variant> for BinaryPolicy { fn verify( &self, encoded_event: &[u8], - _encoded_event_endorsement: &Variant, + _encoded_endorsement: &Variant, milliseconds_since_epoch: i64, ) -> anyhow::Result { let event = decode_event_proto::( diff --git a/oak_attestation_verification/src/policy/container.rs b/oak_attestation_verification/src/policy/container.rs index 97279e1d32..bc7335c06f 100644 --- a/oak_attestation_verification/src/policy/container.rs +++ b/oak_attestation_verification/src/policy/container.rs @@ -15,7 +15,7 @@ // use anyhow::Context; -use oak_attestation_verification_types::{policy::Policy, CONTAINER_ENDORSEMENT_ID}; +use oak_attestation_verification_types::policy::Policy; use oak_proto_rust::oak::{ attestation::v1::{ ContainerEndorsement, ContainerLayerData, ContainerLayerReferenceValues, @@ -26,8 +26,7 @@ use oak_proto_rust::oak::{ use crate::{ compare::compare_container_layer_measurement_digests, - expect::acquire_container_event_expected_values, - util::{decode_endorsement_proto, decode_event_proto}, + expect::acquire_container_event_expected_values, util::decode_event_proto, }; pub struct ContainerPolicy { @@ -47,17 +46,15 @@ impl Policy<[u8], Variant> for ContainerPolicy { fn verify( &self, encoded_event: &[u8], - encoded_event_endorsement: &Variant, + encoded_endorsement: &Variant, milliseconds_since_epoch: i64, ) -> anyhow::Result { let event = decode_event_proto::( "type.googleapis.com/oak.attestation.v1.ContainerLayerData", encoded_event, )?; - let endorsement = decode_endorsement_proto::( - &CONTAINER_ENDORSEMENT_ID, - encoded_event_endorsement, - )?; + let endorsement: ContainerEndorsement = + encoded_endorsement.try_into().map_err(anyhow::Error::msg)?; let expected_values = acquire_container_event_expected_values( milliseconds_since_epoch, diff --git a/oak_attestation_verification/src/policy/firmware.rs b/oak_attestation_verification/src/policy/firmware.rs index 3daa9b0d1f..99e64027fd 100644 --- a/oak_attestation_verification/src/policy/firmware.rs +++ b/oak_attestation_verification/src/policy/firmware.rs @@ -15,7 +15,7 @@ // use anyhow::Context; -use oak_attestation_verification_types::{policy::Policy, FIRMWARE_ENDORSEMENT_ID}; +use oak_attestation_verification_types::policy::Policy; use oak_proto_rust::oak::{ attestation::v1::{BinaryReferenceValue, EventAttestationResults, FirmwareEndorsement}, Variant, @@ -23,7 +23,7 @@ use oak_proto_rust::oak::{ use crate::{ compare::compare_measurement_digest, expect::acquire_stage0_expected_values, - platform::convert_amd_sev_snp_initial_measurement, util::decode_endorsement_proto, + platform::convert_amd_sev_snp_initial_measurement, }; pub struct FirmwarePolicy { @@ -40,14 +40,12 @@ impl Policy<[u8], Variant> for FirmwarePolicy { fn verify( &self, firmware_measurement: &[u8], - encoded_firmware_endorsement: &Variant, + encoded_endorsement: &Variant, milliseconds_since_epoch: i64, ) -> anyhow::Result { let initial_measurement = convert_amd_sev_snp_initial_measurement(firmware_measurement); - let endorsement = decode_endorsement_proto::( - &FIRMWARE_ENDORSEMENT_ID, - encoded_firmware_endorsement, - )?; + let endorsement: FirmwareEndorsement = + encoded_endorsement.try_into().map_err(anyhow::Error::msg)?; let expected_values = acquire_stage0_expected_values( milliseconds_since_epoch, diff --git a/oak_attestation_verification/src/policy/kernel.rs b/oak_attestation_verification/src/policy/kernel.rs index 64e8e04a46..c59702b47e 100644 --- a/oak_attestation_verification/src/policy/kernel.rs +++ b/oak_attestation_verification/src/policy/kernel.rs @@ -15,7 +15,7 @@ // use anyhow::Context; -use oak_attestation_verification_types::{policy::Policy, KERNEL_ENDORSEMENT_ID}; +use oak_attestation_verification_types::policy::Policy; use oak_proto_rust::oak::{ attestation::v1::{ EventAttestationResults, KernelEndorsement, KernelLayerReferenceValues, Stage0Measurements, @@ -26,8 +26,7 @@ use oak_proto_rust::oak::{ use crate::{ compare::compare_kernel_layer_measurement_digests, expect::acquire_kernel_event_expected_values, - extract::stage0_measurements_to_kernel_layer_data, - util::{decode_endorsement_proto, decode_event_proto}, + extract::stage0_measurements_to_kernel_layer_data, util::decode_event_proto, }; pub struct KernelPolicy { @@ -44,7 +43,7 @@ impl Policy<[u8], Variant> for KernelPolicy { fn verify( &self, encoded_event: &[u8], - encoded_event_endorsement: &Variant, + encoded_endorsement: &Variant, milliseconds_since_epoch: i64, ) -> anyhow::Result { let event = @@ -52,10 +51,8 @@ impl Policy<[u8], Variant> for KernelPolicy { "type.googleapis.com/oak.attestation.v1.Stage0Measurements", encoded_event, )?); - let endorsement = decode_endorsement_proto::( - &KERNEL_ENDORSEMENT_ID, - encoded_event_endorsement, - )?; + let endorsement: KernelEndorsement = + encoded_endorsement.try_into().map_err(anyhow::Error::msg)?; let expected_values = acquire_kernel_event_expected_values( milliseconds_since_epoch, @@ -63,6 +60,7 @@ impl Policy<[u8], Variant> for KernelPolicy { &self.reference_values, ) .context("couldn't verify kernel endorsements")?; + compare_kernel_layer_measurement_digests(&event, &expected_values) .context("couldn't verify kernel event")?; diff --git a/oak_attestation_verification/src/policy/platform.rs b/oak_attestation_verification/src/policy/platform.rs index 90784bd2ae..3028f58347 100644 --- a/oak_attestation_verification/src/policy/platform.rs +++ b/oak_attestation_verification/src/policy/platform.rs @@ -15,7 +15,7 @@ // use anyhow::Context; -use oak_attestation_verification_types::{policy::Policy, AMD_SEV_SNP_PLATFORM_ENDORSEMENT_ID}; +use oak_attestation_verification_types::policy::Policy; use oak_proto_rust::oak::{ attestation::v1::{AmdSevReferenceValues, AmdSevSnpEndorsement, EventAttestationResults}, Variant, @@ -28,7 +28,6 @@ use crate::{ convert_amd_sev_snp_attestation_report, verify_amd_sev_attestation_report_values, verify_amd_sev_snp_attestation_report_validity, }, - util::decode_endorsement_proto, }; pub struct AmdSevSnpPolicy { @@ -45,19 +44,17 @@ impl Policy for AmdSevSnpPolicy { fn verify( &self, attestation_report: &AttestationReport, - encoded_platform_endorsement: &Variant, + encoded_endorsement: &Variant, milliseconds_since_epoch: i64, ) -> anyhow::Result { - let platform_endorsement = decode_endorsement_proto::( - &AMD_SEV_SNP_PLATFORM_ENDORSEMENT_ID, - encoded_platform_endorsement, - )?; + let endorsement: AmdSevSnpEndorsement = + encoded_endorsement.try_into().map_err(anyhow::Error::msg)?; // Ensure the Attestation report is properly signed by the platform and the // corresponding certificate is signed by AMD. verify_amd_sev_snp_attestation_report_validity( attestation_report, - &platform_endorsement.tee_certificate, + &endorsement.tee_certificate, milliseconds_since_epoch, ) .context("couldn't verify AMD SEV-SNP attestation validity")?; diff --git a/oak_attestation_verification/src/policy/system.rs b/oak_attestation_verification/src/policy/system.rs index 4fd6a02c5f..1cb77d5ea0 100644 --- a/oak_attestation_verification/src/policy/system.rs +++ b/oak_attestation_verification/src/policy/system.rs @@ -15,7 +15,7 @@ // use anyhow::Context; -use oak_attestation_verification_types::{policy::Policy, SYSTEM_ENDORSEMENT_ID}; +use oak_attestation_verification_types::policy::Policy; use oak_proto_rust::oak::{ attestation::v1::{ EventAttestationResults, SystemEndorsement, SystemLayerData, SystemLayerReferenceValues, @@ -25,8 +25,7 @@ use oak_proto_rust::oak::{ use crate::{ compare::compare_system_layer_measurement_digests, - expect::acquire_system_event_expected_values, - util::{decode_endorsement_proto, decode_event_proto}, + expect::acquire_system_event_expected_values, util::decode_event_proto, }; pub struct SystemPolicy { @@ -43,17 +42,15 @@ impl Policy<[u8], Variant> for SystemPolicy { fn verify( &self, encoded_event: &[u8], - encoded_event_endorsement: &Variant, + encoded_endorsement: &Variant, milliseconds_since_epoch: i64, ) -> anyhow::Result { let event = decode_event_proto::( "type.googleapis.com/oak.attestation.v1.SystemLayerData", encoded_event, )?; - let endorsement = decode_endorsement_proto::( - &SYSTEM_ENDORSEMENT_ID, - encoded_event_endorsement, - )?; + let endorsement: SystemEndorsement = + encoded_endorsement.try_into().map_err(anyhow::Error::msg)?; let expected_values = acquire_system_event_expected_values( milliseconds_since_epoch, diff --git a/oak_attestation_verification/src/util.rs b/oak_attestation_verification/src/util.rs index 9e05013c00..747cc80965 100644 --- a/oak_attestation_verification/src/util.rs +++ b/oak_attestation_verification/src/util.rs @@ -30,7 +30,7 @@ use oak_proto_rust::oak::{ RootLayerData, RootLayerReferenceValues, Signature, SkipVerification, StringLiterals, SystemLayerReferenceValues, TextReferenceValue, Validity, VerifyingKeySet, }, - HexDigest, RawDigest, Variant, + HexDigest, RawDigest, }; use p256::pkcs8::{der::Decode, DecodePublicKey}; use prost::Message; @@ -426,20 +426,6 @@ pub fn decode_event_proto( ) } -/// Decodes serialized endorsement into a specified [`Message`]. -pub fn decode_endorsement_proto( - id: &[u8], - message: &Variant, -) -> anyhow::Result { - if message.id == id { - let decoded_message = M::decode(message.value.as_ref()) - .map_err(|error| anyhow::anyhow!("couldn't decode endorsement: {:?}", error))?; - Ok(decoded_message) - } else { - anyhow::bail!("unexpected endorsement ID, expected {:?}, found {:?}", id, message.id); - } -} - /// Decodes [`Any`] message into a specified [`Message`]. pub fn decode_protobuf_any( expected_type_url: &str, diff --git a/oak_attestation_verification/tests/policy_tests.rs b/oak_attestation_verification/tests/policy_tests.rs index 809441f32a..04e13feafb 100644 --- a/oak_attestation_verification/tests/policy_tests.rs +++ b/oak_attestation_verification/tests/policy_tests.rs @@ -21,17 +21,12 @@ use oak_attestation_verification::policy::{ application::ApplicationPolicy, container::ContainerPolicy, firmware::FirmwarePolicy, kernel::KernelPolicy, platform::AmdSevSnpPolicy, system::SystemPolicy, }; -use oak_attestation_verification_types::{ - policy::Policy, AMD_SEV_SNP_PLATFORM_ENDORSEMENT_ID, FIRMWARE_ENDORSEMENT_ID, -}; +use oak_attestation_verification_types::policy::Policy; use oak_file_utils::data_path; -use oak_proto_rust::oak::{ - attestation::v1::{ - binary_reference_value, endorsements, reference_values, AmdSevSnpEndorsement, Endorsements, - Evidence, FirmwareEndorsement, OakContainersReferenceValues, - OakRestrictedKernelReferenceValues, ReferenceValues, SkipVerification, - }, - Variant, +use oak_proto_rust::oak::attestation::v1::{ + binary_reference_value, endorsements, reference_values, AmdSevSnpEndorsement, Endorsements, + Evidence, FirmwareEndorsement, OakContainersReferenceValues, + OakRestrictedKernelReferenceValues, ReferenceValues, SkipVerification, }; use oak_sev_snp_attestation_report::AttestationReport; use prost::Message; @@ -146,7 +141,7 @@ fn amd_sev_snp_platform_policy_verify_succeeds() { OC_REFERENCE_VALUES.root_layer.as_ref().unwrap().amd_sev.as_ref().unwrap(); let policy = AmdSevSnpPolicy::new(platform_reference_values); let attestation_report = extract_attestation_report(&OC_EVIDENCE).unwrap(); - let platform_endorsement = AmdSevSnpEndorsement { + let endorsement = AmdSevSnpEndorsement { tee_certificate: match OC_ENDORSEMENTS.r#type.as_ref() { Some(endorsements::Type::OakContainers(e)) => { e.root_layer.as_ref().unwrap().tee_certificate.to_vec() @@ -154,12 +149,8 @@ fn amd_sev_snp_platform_policy_verify_succeeds() { _ => vec![], }, }; - let encoded_endorsement = Variant { - id: AMD_SEV_SNP_PLATFORM_ENDORSEMENT_ID.to_vec(), - value: platform_endorsement.encode_to_vec(), - }; - let result = policy.verify(attestation_report, &encoded_endorsement, MILLISECONDS_SINCE_EPOCH); + let result = policy.verify(attestation_report, &endorsement.into(), MILLISECONDS_SINCE_EPOCH); // TODO: b/356631062 - Verify detailed attestation results. assert!(result.is_ok(), "Failed: {:?}", result.err().unwrap()); @@ -186,13 +177,10 @@ fn amd_sev_snp_firmware_policy_verify_succeeds() { let firmware_measurement = &extract_attestation_report(&OC_EVIDENCE).unwrap().data.measurement; // TODO: b/375137648 - Use new endorsements directly once available. let firmware_endorsement = FirmwareEndorsement { firmware: None }; - let encoded_endorsement = Variant { - id: FIRMWARE_ENDORSEMENT_ID.to_vec(), - value: firmware_endorsement.encode_to_vec(), - }; let result = - policy.verify(firmware_measurement, &encoded_endorsement, MILLISECONDS_SINCE_EPOCH); + policy.verify(firmware_measurement, &firmware_endorsement.into(), MILLISECONDS_SINCE_EPOCH); + // TODO: b/356631062 - Verify detailed attestation results. assert!(result.is_ok(), "Failed: {:?}", result.err().unwrap()); } diff --git a/oak_attestation_verification_types/src/lib.rs b/oak_attestation_verification_types/src/lib.rs index d507387e3a..46cde0edb6 100644 --- a/oak_attestation_verification_types/src/lib.rs +++ b/oak_attestation_verification_types/src/lib.rs @@ -22,16 +22,3 @@ extern crate alloc; pub mod policy; pub mod util; pub mod verifier; - -pub static AMD_SEV_SNP_PLATFORM_ENDORSEMENT_ID: [u8; 16] = - [90, 18, 208, 15, 72, 160, 66, 36, 191, 244, 151, 92, 118, 87, 67, 143]; -pub static FIRMWARE_ENDORSEMENT_ID: [u8; 16] = - [222, 74, 13, 85, 96, 234, 77, 198, 171, 209, 9, 237, 116, 79, 128, 234]; -pub static KERNEL_ENDORSEMENT_ID: [u8; 16] = - [137, 81, 29, 101, 93, 53, 70, 1, 144, 11, 30, 109, 186, 248, 66, 182]; -pub static SYSTEM_ENDORSEMENT_ID: [u8; 16] = - [71, 34, 101, 93, 150, 61, 79, 201, 132, 67, 241, 69, 113, 221, 50, 162]; -pub static APPLICATION_ENDORSEMENT_ID: [u8; 16] = - [232, 78, 215, 20, 102, 157, 67, 10, 166, 15, 138, 101, 30, 90, 85, 3]; -pub static CONTAINER_ENDORSEMENT_ID: [u8; 16] = - [114, 151, 165, 31, 160, 93, 73, 161, 175, 219, 100, 205, 238, 7, 134, 45]; diff --git a/oak_proto_rust/src/lib.rs b/oak_proto_rust/src/lib.rs index db84aeb76f..ff54daf862 100644 --- a/oak_proto_rust/src/lib.rs +++ b/oak_proto_rust/src/lib.rs @@ -37,8 +37,9 @@ pub mod perftools { } } -pub mod oak { +pub mod variant; +pub mod oak { // Do not lint generated code. #![allow(clippy::all, clippy::pedantic, clippy::nursery)] diff --git a/oak_proto_rust/src/variant.rs b/oak_proto_rust/src/variant.rs new file mode 100644 index 0000000000..dce7365a46 --- /dev/null +++ b/oak_proto_rust/src/variant.rs @@ -0,0 +1,125 @@ +// +// Copyright 2025 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. + +use prost::Message; + +use crate::oak::{ + attestation::v1::{ + AmdSevSnpEndorsement, ApplicationEndorsement, ContainerEndorsement, FirmwareEndorsement, + KernelEndorsement, SystemEndorsement, + }, + Variant, +}; + +/// A random ID for each endorsement protocol buffer type that appears as ID +/// in the oak::Variant encoding. +const AMD_SEV_SNP_PLATFORM_ENDORSEMENT_ID: [u8; 16] = + [90, 18, 208, 15, 72, 160, 66, 36, 191, 244, 151, 92, 118, 87, 67, 143]; +const FIRMWARE_ENDORSEMENT_ID: [u8; 16] = + [222, 74, 13, 85, 96, 234, 77, 198, 171, 209, 9, 237, 116, 79, 128, 234]; +const KERNEL_ENDORSEMENT_ID: [u8; 16] = + [137, 81, 29, 101, 93, 53, 70, 1, 144, 11, 30, 109, 186, 248, 66, 182]; +const SYSTEM_ENDORSEMENT_ID: [u8; 16] = + [71, 34, 101, 93, 150, 61, 79, 201, 132, 67, 241, 69, 113, 221, 50, 162]; +const APPLICATION_ENDORSEMENT_ID: [u8; 16] = + [232, 78, 215, 20, 102, 157, 67, 10, 166, 15, 138, 101, 30, 90, 85, 3]; +const CONTAINER_ENDORSEMENT_ID: [u8; 16] = + [114, 151, 165, 31, 160, 93, 73, 161, 175, 219, 100, 205, 238, 7, 134, 45]; + +fn try_into_message(id: &[u8], variant: &Variant) -> Result { + if variant.id != id { + return Err("unexpected variant ID"); + } + + M::decode(variant.value.as_ref()).map_err(|_| "couldn't decode variant") +} + +impl TryFrom<&Variant> for AmdSevSnpEndorsement { + type Error = &'static str; + fn try_from(value: &Variant) -> Result { + try_into_message(&AMD_SEV_SNP_PLATFORM_ENDORSEMENT_ID, value) + } +} + +impl TryFrom<&Variant> for FirmwareEndorsement { + type Error = &'static str; + fn try_from(value: &Variant) -> Result { + try_into_message(&FIRMWARE_ENDORSEMENT_ID, value) + } +} + +impl TryFrom<&Variant> for KernelEndorsement { + type Error = &'static str; + fn try_from(value: &Variant) -> Result { + try_into_message(&KERNEL_ENDORSEMENT_ID, value) + } +} + +impl TryFrom<&Variant> for SystemEndorsement { + type Error = &'static str; + fn try_from(value: &Variant) -> Result { + try_into_message(&SYSTEM_ENDORSEMENT_ID, value) + } +} + +impl TryFrom<&Variant> for ContainerEndorsement { + type Error = &'static str; + fn try_from(value: &Variant) -> Result { + try_into_message(&CONTAINER_ENDORSEMENT_ID, value) + } +} + +impl TryFrom<&Variant> for ApplicationEndorsement { + type Error = &'static str; + fn try_from(value: &Variant) -> Result { + try_into_message(&APPLICATION_ENDORSEMENT_ID, value) + } +} + +impl From for Variant { + fn from(value: AmdSevSnpEndorsement) -> Self { + Variant { id: AMD_SEV_SNP_PLATFORM_ENDORSEMENT_ID.to_vec(), value: value.encode_to_vec() } + } +} + +impl From for Variant { + fn from(value: FirmwareEndorsement) -> Self { + Variant { id: FIRMWARE_ENDORSEMENT_ID.to_vec(), value: value.encode_to_vec() } + } +} + +impl From for Variant { + fn from(value: KernelEndorsement) -> Self { + Variant { id: KERNEL_ENDORSEMENT_ID.to_vec(), value: value.encode_to_vec() } + } +} + +impl From for Variant { + fn from(value: SystemEndorsement) -> Self { + Variant { id: SYSTEM_ENDORSEMENT_ID.to_vec(), value: value.encode_to_vec() } + } +} + +impl From for Variant { + fn from(value: ContainerEndorsement) -> Self { + Variant { id: CONTAINER_ENDORSEMENT_ID.to_vec(), value: value.encode_to_vec() } + } +} + +impl From for Variant { + fn from(value: ApplicationEndorsement) -> Self { + Variant { id: APPLICATION_ENDORSEMENT_ID.to_vec(), value: value.encode_to_vec() } + } +}