Skip to content

Commit

Permalink
Make Policy a generic trait
Browse files Browse the repository at this point in the history
Bug: 369821273
Change-Id: I05af93b0714823aa4e163d6a1d1e24dd7605f383
  • Loading branch information
ipetr0v committed Nov 14, 2024
1 parent 312ebb2 commit b7fcab9
Show file tree
Hide file tree
Showing 8 changed files with 91 additions and 111 deletions.
77 changes: 0 additions & 77 deletions oak_attestation_verification/src/policy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,84 +14,7 @@
// limitations under the License.
//

//! Contains code related to the policy that is combined from individual Event
//! policies and is used to verify the whole TEE software stack.

pub mod application;
pub mod binary;
pub mod kernel;
pub mod system;

use alloc::{boxed::Box, string::ToString, vec, vec::Vec};

use itertools::izip;
use oak_attestation_verification_types::policy::{EventPolicy, Policy};
use oak_proto_rust::oak::attestation::v1::{
attestation_results::Status, AttestationResults, EventAttestationResults, EventEndorsements,
EventLog,
};

/// Represents a combination of Event Policies.
///
/// They are represented as a list where each element corresponds to an `Event`
/// in the `EventLog` and `EventEndorsements` in the `EventEndorsementsLog` with
/// the same index. This means that mapping between Policies and Events is done
/// via ordering.
pub struct CombinedPolicy {
policies: Vec<Box<dyn EventPolicy>>,
}

impl CombinedPolicy {
pub fn new(policies: Vec<Box<dyn EventPolicy>>) -> Self {
CombinedPolicy { policies }
}
}

impl Policy for CombinedPolicy {
fn verify(
&self,
event_log: &EventLog,
event_endorsements: &EventEndorsements,
milliseconds_since_epoch: i64,
) -> anyhow::Result<AttestationResults> {
if event_log.encoded_events.len() != event_endorsements.encoded_event_endorsements.len() {
anyhow::bail!(
"eventLog length ({}) is not equal to the EventEndorsementsLog length ({})",
event_log.encoded_events.len(),
event_endorsements.encoded_event_endorsements.len()
);
}
if self.policies.len() != event_log.encoded_events.len() {
anyhow::bail!(
"number of Policies ({}) is not equal to the EventLog length ({})",
self.policies.len(),
event_log.encoded_events.len()
);
}

let verification_iterator = izip!(
self.policies.iter(),
event_log.encoded_events.iter(),
event_endorsements.encoded_event_endorsements.iter()
);
let event_attestation_results = verification_iterator
.map(|(event_policy, event, event_endorsements)| {
event_policy.verify(event, event_endorsements, milliseconds_since_epoch).unwrap_or(
// TODO: b/366186091 - Use Rust error types for failed attestation.
EventAttestationResults {},
)
})
.collect::<Vec<EventAttestationResults>>();

// TODO: b/366419879 - Combine per-event attestation results.
#[allow(deprecated)]
Ok(AttestationResults {
status: Status::Unspecified.into(),
reason: "".to_string(),
encryption_public_key: vec![],
signing_public_key: vec![],
extracted_evidence: None,
event_attestation_results,
})
}
}
7 changes: 5 additions & 2 deletions oak_attestation_verification/src/policy/application.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
//

use anyhow::Context;
use oak_attestation_verification_types::policy::EventPolicy;
use oak_attestation_verification_types::policy::Policy;
use oak_proto_rust::oak::attestation::v1::{
ApplicationLayerData, ApplicationLayerEndorsements, ApplicationLayerReferenceValues,
EventAttestationResults,
Expand All @@ -37,7 +37,10 @@ impl ApplicationPolicy {
}
}

impl EventPolicy for ApplicationPolicy {
// We have to use [`Policy<[u8], [u8]>`] instead of [`EventPolicy`], because
// Rust doesn't yet support implementing trait aliases.
// <https://github.com/rust-lang/rfcs/blob/master/text/1733-trait-alias.md>
impl Policy<[u8], [u8]> for ApplicationPolicy {
fn verify(
&self,
encoded_event: &[u8],
Expand Down
4 changes: 2 additions & 2 deletions oak_attestation_verification/src/policy/binary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
//

use anyhow::Context;
use oak_attestation_verification_types::policy::EventPolicy;
use oak_attestation_verification_types::policy::Policy;
use oak_proto_rust::oak::attestation::v1::{
EventAttestationResults, EventData, EventReferenceValues,
};
Expand All @@ -35,7 +35,7 @@ impl BinaryPolicy {
}
}

impl EventPolicy for BinaryPolicy {
impl Policy<[u8], [u8]> for BinaryPolicy {
fn verify(
&self,
encoded_event: &[u8],
Expand Down
4 changes: 2 additions & 2 deletions oak_attestation_verification/src/policy/kernel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
//

use anyhow::Context;
use oak_attestation_verification_types::policy::EventPolicy;
use oak_attestation_verification_types::policy::Policy;
use oak_proto_rust::oak::attestation::v1::{
EventAttestationResults, KernelLayerData, KernelLayerEndorsements, KernelLayerReferenceValues,
};
Expand All @@ -36,7 +36,7 @@ impl KernelPolicy {
}
}

impl EventPolicy for KernelPolicy {
impl Policy<[u8], [u8]> for KernelPolicy {
fn verify(
&self,
encoded_event: &[u8],
Expand Down
4 changes: 2 additions & 2 deletions oak_attestation_verification/src/policy/system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
//

use anyhow::Context;
use oak_attestation_verification_types::policy::EventPolicy;
use oak_attestation_verification_types::policy::Policy;
use oak_proto_rust::oak::attestation::v1::{
EventAttestationResults, SystemLayerData, SystemLayerEndorsements, SystemLayerReferenceValues,
};
Expand All @@ -36,7 +36,7 @@ impl SystemPolicy {
}
}

impl EventPolicy for SystemPolicy {
impl Policy<[u8], [u8]> for SystemPolicy {
fn verify(
&self,
encoded_event: &[u8],
Expand Down
80 changes: 71 additions & 9 deletions oak_attestation_verification/src/verifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,20 @@

//! Provides verification based on evidence, endorsements and reference values.

use alloc::{boxed::Box, format};
use alloc::{boxed::Box, format, string::ToString, vec, vec::Vec};

use anyhow::Context;
use coset::{cwt::ClaimsSet, CborSerializable, CoseKey};
use ecdsa::{signature::Verifier, Signature};
use itertools::izip;
use oak_attestation_verification_types::{
policy::Policy, util::Clock, verifier::AttestationVerifier,
policy::EventPolicy, util::Clock, verifier::AttestationVerifier,
};
use oak_dice::cert::{cose_key_to_verifying_key, get_public_key_from_claims_set};
use oak_proto_rust::oak::attestation::v1::{
attestation_results::Status, endorsements, AttestationResults, Endorsements, EventLog,
Evidence, ExpectedValues, ExtractedEvidence, LayerEvidence, ReferenceValues,
attestation_results::Status, endorsements, AttestationResults, Endorsements,
EventAttestationResults, EventEndorsements, EventLog, Evidence, ExpectedValues,
ExtractedEvidence, LayerEvidence, ReferenceValues,
};
use p256::ecdsa::VerifyingKey;

Expand Down Expand Up @@ -62,13 +64,13 @@ pub fn to_attestation_results(
}

pub struct AmdSevSnpDiceAttestationVerifier {
policy: Box<dyn Policy>,
policies: Vec<Box<dyn EventPolicy>>,
clock: Box<dyn Clock>,
}

impl AmdSevSnpDiceAttestationVerifier {
pub fn new(policy: Box<dyn Policy>, clock: Box<dyn Clock>) -> Self {
Self { policy, clock }
pub fn new(policies: Vec<Box<dyn EventPolicy>>, clock: Box<dyn Clock>) -> Self {
Self { policies, clock }
}
}

Expand All @@ -81,7 +83,7 @@ impl AttestationVerifier for AmdSevSnpDiceAttestationVerifier {
// Last layer's certificate authority key is not used to sign anything.
let _ = verify_dice_chain(evidence).context("couldn't verify DICE chain")?;

// Verify event log and event endorsements with corresponding policy.
// Verify event log and event endorsements with corresponding policies.
let event_log = &evidence
.event_log
.as_ref()
Expand All @@ -90,7 +92,24 @@ impl AttestationVerifier for AmdSevSnpDiceAttestationVerifier {
.event_endorsements
.as_ref()
.ok_or_else(|| anyhow::anyhow!("event endorsements were not provided"))?;
self.policy.verify(event_log, event_endorsements, self.clock.get_milliseconds_since_epoch())
let event_attestation_results = verify_event_log(
event_log,
event_endorsements,
self.policies.as_slice(),
self.clock.get_milliseconds_since_epoch(),
)
.context("couldn't verify event log")?;

// TODO: b/366419879 - Combine per-event attestation results.
#[allow(deprecated)]
Ok(AttestationResults {
status: Status::Unspecified.into(),
reason: "".to_string(),
encryption_public_key: vec![],
signing_public_key: vec![],
extracted_evidence: None,
event_attestation_results,
})
}
}

Expand Down Expand Up @@ -322,3 +341,46 @@ fn validate_that_event_log_is_captured_in_dice_layers(
},
)
}

/// Verifies an Event Log using a combination of Event Policies.
///
/// Event Policies are provided as a list where each element corresponds to an
/// [`Event`] in the [`EventLog`] and [`EventEndorsement`] in the
/// [`EventEndorsements`] with the same index. This means that mapping between
/// Policies and Events is done via ordering.
fn verify_event_log(
event_log: &EventLog,
event_endorsements: &EventEndorsements,
policies: &[Box<dyn EventPolicy>],
milliseconds_since_epoch: i64,
) -> anyhow::Result<Vec<EventAttestationResults>> {
if event_log.encoded_events.len() != event_endorsements.encoded_event_endorsements.len() {
anyhow::bail!(
"event log length ({}) is not equal to the number of endorsements ({})",
event_log.encoded_events.len(),
event_endorsements.encoded_event_endorsements.len()
);
}
if policies.len() != event_log.encoded_events.len() {
anyhow::bail!(
"number of policies ({}) is not equal to the event log length ({})",
policies.len(),
event_log.encoded_events.len()
);
}

let verification_iterator = izip!(
policies.iter(),
event_log.encoded_events.iter(),
event_endorsements.encoded_event_endorsements.iter()
);
let event_attestation_results = verification_iterator
.map(|(event_policy, event, event_endorsements)| {
event_policy.verify(event, event_endorsements, milliseconds_since_epoch).unwrap_or(
// TODO: b/366186091 - Use Rust error types for failed attestation.
EventAttestationResults {},
)
})
.collect::<Vec<EventAttestationResults>>();
Ok(event_attestation_results)
}
1 change: 1 addition & 0 deletions oak_attestation_verification_types/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
//

#![no_std]
#![feature(trait_alias)]

extern crate alloc;

Expand Down
25 changes: 8 additions & 17 deletions oak_attestation_verification_types/src/policy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,32 +14,23 @@
// limitations under the License.
//

use oak_proto_rust::oak::attestation::v1::{
AttestationResults, EventAttestationResults, EventEndorsements, EventLog,
};
use oak_proto_rust::oak::attestation::v1::EventAttestationResults;

/// Verification Policy that takes an EventLog and corresponding Event
/// Endorsements and performs attestation verification.
/// Verification Policy that takes a generic evidence and endorsement and
/// performs attestation verification.
///
/// Verification Policy correspond to the "Appraisal Policy for Evidence"
/// provided by the RATS standard.
/// <https://datatracker.ietf.org/doc/html/rfc9334#section-8.5>
pub trait Policy: Send + Sync {
pub trait Policy<V: ?Sized, N: ?Sized>: Send + Sync {
fn verify(
&self,
event_log: &EventLog,
event_endorsements: &EventEndorsements,
evidence: &V,
endorsement: &N,
milliseconds_since_epoch: i64,
) -> anyhow::Result<AttestationResults>;
) -> anyhow::Result<EventAttestationResults>;
}

/// Verification Policy that takes an encoded Event and an encoded Event
/// Endorsement and performs attestation verification for this specific Event.
pub trait EventPolicy: Send + Sync {
fn verify(
&self,
encoded_event: &[u8],
encoded_event_endorsement: &[u8],
milliseconds_since_epoch: i64,
) -> anyhow::Result<EventAttestationResults>;
}
pub trait EventPolicy = Policy<[u8], [u8]>;

0 comments on commit b7fcab9

Please sign in to comment.