diff --git a/dpe/Cargo.toml b/dpe/Cargo.toml index 57f287f5..560cb307 100644 --- a/dpe/Cargo.toml +++ b/dpe/Cargo.toml @@ -20,6 +20,7 @@ disable_csr = [] disable_internal_info = [] disable_internal_dice = [] disable_retain_parent_context = [] +disable_export_cdi = [] no-cfi = ["crypto/no-cfi"] [dependencies] diff --git a/dpe/src/commands/derive_context.rs b/dpe/src/commands/derive_context.rs index 39acc8d6..f087c45e 100644 --- a/dpe/src/commands/derive_context.rs +++ b/dpe/src/commands/derive_context.rs @@ -1,7 +1,7 @@ // Licensed under the Apache-2.0 license. use super::CommandExecution; use crate::{ - context::{ActiveContextArgs, Context, ContextHandle, ContextState}, + context::{ActiveContextArgs, Context, ContextHandle, ContextState, ContextType}, dpe_instance::{DpeEnv, DpeInstance, DpeTypes}, response::{DeriveContextResp, DpeErrorCode, Response, ResponseHdr}, tci::TciMeasurement, @@ -36,6 +36,8 @@ bitflags! { const INPUT_ALLOW_CA = 1u32 << 26; const INPUT_ALLOW_X509 = 1u32 << 25; const RECURSIVE = 1u32 << 24; + const EXPORT_CDI = 1u32 << 23; + const CREATE_CERTIFICATE = 1u32 << 22; } } @@ -91,6 +93,14 @@ impl DeriveContextCmd { self.flags.contains(DeriveContextFlags::RECURSIVE) } + pub const fn allows_exports_cdi(&self) -> bool { + self.flags.contains(DeriveContextFlags::EXPORT_CDI) + } + + pub const fn allows_create_certificate(&self) -> bool { + self.flags.contains(DeriveContextFlags::CREATE_CERTIFICATE) + } + /// Whether it is okay to make a default context. /// /// When a default context is in a locality, it MUST be the only context in the locality. This @@ -196,6 +206,8 @@ impl CommandExecution for DeriveContextCmd { || (!dpe.support.internal_dice() && self.uses_internal_dice_input()) || (!dpe.support.retain_parent_context() && self.retains_parent()) || (!dpe.support.x509() && self.allows_x509()) + || (!dpe.support.cdi_export() + && (self.allows_create_certificate() && self.allows_exports_cdi())) || (!dpe.support.recursive() && self.is_recursive()) { return Err(DpeErrorCode::ArgumentNotSupported); @@ -204,6 +216,11 @@ impl CommandExecution for DeriveContextCmd { let parent_idx = dpe.get_active_context_pos(&self.handle, locality)?; if (!dpe.contexts[parent_idx].allow_ca() && self.allows_ca()) || (!dpe.contexts[parent_idx].allow_x509() && self.allows_x509()) + || (self.allows_exports_cdi() && !self.allows_create_certificate()) + || (self.allows_exports_cdi() && self.is_recursive()) + || (self.allows_exports_cdi() && self.changes_locality()) + || (self.allows_exports_cdi() + && dpe.contexts[parent_idx].context_type == ContextType::Simulation) || (self.is_recursive() && self.retains_parent()) { return Err(DpeErrorCode::InvalidArgument); @@ -267,6 +284,8 @@ impl CommandExecution for DeriveContextCmd { Err(DpeErrorCode::ArgumentNotSupported)? } } + } else if self.allows_create_certificate() && self.allows_exports_cdi() { + todo!("(clundin): Generate ECA certificiate / export random CDI") } else { let child_idx = dpe .get_next_inactive_context_pos() @@ -784,6 +803,7 @@ mod tests { handle, parent_handle, resp_hdr, + .. }) = DeriveContextCmd { handle: dpe.contexts[old_default_idx].handle, data: [0; DPE_PROFILE.get_tci_size()], @@ -996,4 +1016,118 @@ mod tests { let digest = hasher_2.finish().unwrap(); assert_eq!(digest.bytes(), dpe.contexts[child_idx].tci.tci_cumulative.0); } + + #[test] + fn test_cdi_export_flags() { + CfiCounter::reset_for_test(); + let mut env = DpeEnv:: { + crypto: OpensslCrypto::new(), + platform: DefaultPlatform, + }; + let mut dpe = DpeInstance::new( + &mut env, + Support::AUTO_INIT + | Support::CDI_EXPORT + | Support::X509 + | Support::RECURSIVE + | Support::SIMULATION, + ) + .unwrap(); + + // When `DeriveContextFlags::EXPORT_CDI` is set, `DeriveContextFlags::CREATE_CERTIFICATE` MUST + // also be set, or `DpeErrorCode::InvalidArgument` is raised. + assert_eq!( + Err(DpeErrorCode::InvalidArgument), + DeriveContextCmd { + handle: ContextHandle::default(), + data: [0; DPE_PROFILE.get_tci_size()], + flags: DeriveContextFlags::EXPORT_CDI | DeriveContextFlags::CHANGE_LOCALITY, + tci_type: 0, + target_locality: TEST_LOCALITIES[1] + } + .execute(&mut dpe, &mut env, TEST_LOCALITIES[0]) + ); + assert_eq!( + Err(DpeErrorCode::InvalidArgument), + DeriveContextCmd { + handle: ContextHandle::default(), + data: [0; DPE_PROFILE.get_tci_size()], + flags: DeriveContextFlags::EXPORT_CDI | DeriveContextFlags::RECURSIVE, + tci_type: 0, + target_locality: TEST_LOCALITIES[0] + } + .execute(&mut dpe, &mut env, TEST_LOCALITIES[0]) + ); + + let simulation_handle = match InitCtxCmd::new_simulation() + .execute(&mut dpe, &mut env, TEST_LOCALITIES[0]) + .unwrap() + { + Response::InitCtx(resp) => resp.handle, + _ => panic!("Wrong response type."), + }; + // DPE must return an `DpeErrorCode::InvalidArgument` error if the context-handle refers to a simulation context. + assert_eq!( + Err(DpeErrorCode::InvalidArgument), + DeriveContextCmd { + handle: simulation_handle, + data: [0; DPE_PROFILE.get_tci_size()], + flags: DeriveContextFlags::CREATE_CERTIFICATE | DeriveContextFlags::EXPORT_CDI, + tci_type: 0, + target_locality: TEST_LOCALITIES[0] + } + .execute(&mut dpe, &mut env, TEST_LOCALITIES[0]) + ); + + // DPE must return an `DpeErrorCode::InvalidArgument` if `DeriveContextFlags::EXPORT_CDI` and `DeriveContextFlags::RECURSIVE` are set. + assert_eq!( + Err(DpeErrorCode::InvalidArgument), + DeriveContextCmd { + handle: ContextHandle::default(), + data: [0; DPE_PROFILE.get_tci_size()], + flags: DeriveContextFlags::CREATE_CERTIFICATE + | DeriveContextFlags::EXPORT_CDI + | DeriveContextFlags::RECURSIVE, + tci_type: 0, + target_locality: TEST_LOCALITIES[0] + } + .execute(&mut dpe, &mut env, TEST_LOCALITIES[0]) + ); + + dpe = DpeInstance::new( + &mut env, + Support::AUTO_INIT | Support::CDI_EXPORT | Support::X509, + ) + .unwrap(); + + // Happy case! + assert!(DeriveContextCmd { + handle: ContextHandle::default(), + data: [0; DPE_PROFILE.get_tci_size()], + flags: DeriveContextFlags::EXPORT_CDI | DeriveContextFlags::CREATE_CERTIFICATE, + tci_type: 0, + target_locality: TEST_LOCALITIES[0] + } + .execute(&mut dpe, &mut env, TEST_LOCALITIES[0]) + .is_ok()); + + let mut dpe = DpeInstance::new( + &mut env, + Support::AUTO_INIT | Support::INTERNAL_INFO | Support::INTERNAL_DICE | Support::X509, + ) + .unwrap(); + + // `DpeInstance` needs `Support::EXPORT_CDI` to use `DeriveContextFlags::EXPORT_CDI`. + assert_eq!( + Err(DpeErrorCode::ArgumentNotSupported), + DeriveContextCmd { + handle: ContextHandle::default(), + data: [0; DPE_PROFILE.get_tci_size()], + flags: DeriveContextFlags::CREATE_CERTIFICATE | DeriveContextFlags::EXPORT_CDI, + tci_type: 0, + target_locality: TEST_LOCALITIES[0] + } + .execute(&mut dpe, &mut env, TEST_LOCALITIES[0]) + ); + } } diff --git a/dpe/src/lib.rs b/dpe/src/lib.rs index 9f56ea04..b4da833c 100644 --- a/dpe/src/lib.rs +++ b/dpe/src/lib.rs @@ -25,6 +25,8 @@ pub mod x509; use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout}; +const MAX_EXPORTED_CDI_SIZE: usize = 256; + // Max cert size returned by CertifyKey const MAX_CERT_SIZE: usize = 6144; #[cfg(not(feature = "arbitrary_max_handles"))] diff --git a/dpe/src/response.rs b/dpe/src/response.rs index 18c1f533..d4bb0fef 100644 --- a/dpe/src/response.rs +++ b/dpe/src/response.rs @@ -6,7 +6,7 @@ Abstract: --*/ use crate::{ context::ContextHandle, validation::ValidationError, CURRENT_PROFILE_MAJOR_VERSION, - CURRENT_PROFILE_MINOR_VERSION, DPE_PROFILE, MAX_CERT_SIZE, MAX_HANDLES, + CURRENT_PROFILE_MINOR_VERSION, DPE_PROFILE, MAX_CERT_SIZE, MAX_EXPORTED_CDI_SIZE, MAX_HANDLES, }; use crypto::CryptoError; use platform::{PlatformError, MAX_CHUNK_SIZE}; @@ -18,6 +18,7 @@ pub enum Response { GetProfile(GetProfileResp), InitCtx(NewHandleResp), DeriveContext(DeriveContextResp), + DeriveContextExportedCdi(DeriveContextExportedCdiResp), RotateCtx(NewHandleResp), CertifyKey(CertifyKeyResp), Sign(SignResp), @@ -32,6 +33,7 @@ impl Response { Response::GetProfile(res) => res.as_bytes(), Response::InitCtx(res) => res.as_bytes(), Response::DeriveContext(res) => res.as_bytes(), + Response::DeriveContextExportedCdi(res) => res.as_bytes(), Response::RotateCtx(res) => res.as_bytes(), Response::CertifyKey(res) => res.as_bytes(), Response::Sign(res) => res.as_bytes(), @@ -141,6 +143,25 @@ pub struct DeriveContextResp { pub parent_handle: ContextHandle, } +#[repr(C)] +#[derive( + Debug, + PartialEq, + Eq, + zerocopy::IntoBytes, + zerocopy::FromBytes, + zerocopy::Immutable, + zerocopy::KnownLayout, +)] +pub struct DeriveContextExportedCdiResp { + pub resp_hdr: ResponseHdr, + pub handle: ContextHandle, + pub parent_handle: ContextHandle, + pub exported_cdi: [u8; MAX_EXPORTED_CDI_SIZE], + pub certificate_size: u32, + pub new_certificate: [u8; MAX_CERT_SIZE], +} + #[repr(C)] #[derive( Debug, diff --git a/dpe/src/support.rs b/dpe/src/support.rs index d5f75220..5a31d31f 100644 --- a/dpe/src/support.rs +++ b/dpe/src/support.rs @@ -18,6 +18,7 @@ bitflags! { const INTERNAL_INFO = 1u32 << 22; const INTERNAL_DICE = 1u32 << 21; const RETAIN_PARENT_CONTEXT = 1u32 << 19; + const CDI_EXPORT = 1u32 << 18; } } @@ -49,6 +50,9 @@ impl Support { pub fn retain_parent_context(&self) -> bool { self.contains(Support::RETAIN_PARENT_CONTEXT) } + pub fn cdi_export(&self) -> bool { + self.contains(Support::CDI_EXPORT) + } /// Disables supported features based on compilation features pub fn preprocess_support(&self) -> Support { @@ -90,6 +94,10 @@ impl Support { { support.insert(Support::RETAIN_PARENT_CONTEXT); } + #[cfg(feature = "disable_export_cdi")] + { + support.insert(Support::CDI_EXPORT); + } self.difference(support) } } @@ -135,6 +143,8 @@ pub mod test { assert_eq!(flags, 1 << 21); let flags = Support::RETAIN_PARENT_CONTEXT.bits(); assert_eq!(flags, 1 << 19); + let flags = Support::CDI_EXPORT.bits(); + assert_eq!(flags, 1 << 18); // Supports a couple combos. let flags = (Support::SIMULATION | Support::AUTO_INIT @@ -161,6 +171,7 @@ pub mod test { | (1 << 22) | (1 << 21) | (1 << 19) + | (1 << 18) ); } } diff --git a/simulator/src/main.rs b/simulator/src/main.rs index 36120dc0..d12ae05c 100644 --- a/simulator/src/main.rs +++ b/simulator/src/main.rs @@ -52,6 +52,7 @@ fn handle_request(dpe: &mut DpeInstance, env: &mut DpeEnv, stream Response::GetProfile(ref res) => res.resp_hdr.status, Response::InitCtx(ref res) => res.resp_hdr.status, Response::DeriveContext(ref res) => res.resp_hdr.status, + Response::DeriveContextExportedCdi(ref res) => res.resp_hdr.status, Response::RotateCtx(ref res) => res.resp_hdr.status, Response::CertifyKey(ref res) => res.resp_hdr.status, Response::Sign(ref res) => res.resp_hdr.status,