diff --git a/litebox_runner_lvbs/src/lib.rs b/litebox_runner_lvbs/src/lib.rs index 442eba6eb..80bdb7513 100644 --- a/litebox_runner_lvbs/src/lib.rs +++ b/litebox_runner_lvbs/src/lib.rs @@ -241,7 +241,9 @@ pub fn init(is_bsp: bool) -> &'static Platform { .get() .expect("init must publish the platform before any core uses it"); if is_bsp { - let shim = litebox_shim_optee::OpteeShimBuilder::new(platform, session_manager()).build(); + let shim = litebox_shim_optee::OpteeShimBuilder::new(platform, session_manager()) + .with_ta_signing_cert(TA_SIGNING_CERT_DER) + .build(); register_embedded_tas(&shim); } platform @@ -823,7 +825,9 @@ fn open_session_new_instance( client_identity: Option, ta_req_info: &litebox_shim_optee::msg_handler::TaRequestInfo, ) -> Result<(), OpteeSmcReturnCode> { - let shim = litebox_shim_optee::OpteeShimBuilder::new(platform, session_manager()).build(); + let shim = litebox_shim_optee::OpteeShimBuilder::new(platform, session_manager()) + .with_ta_signing_cert(TA_SIGNING_CERT_DER) + .build(); if shim.get_ta_bin(&ta_uuid).is_none() { msg_args.session = 0; msg_args.ret = TeeResult::ItemNotFound; @@ -1413,6 +1417,7 @@ fn write_rpc_args_to_normal_world( const LDELF_BINARY: &[u8] = &[0u8; 0]; const TA_BINARY: &[u8] = &[0u8; 0]; const TA_BINARIES: &[&[u8]] = &[TA_BINARY]; +const TA_SIGNING_CERT_DER: &[u8] = &[0u8; 0]; /// Register a TA binary embedded in the runner image. fn register_embedded_ta( diff --git a/litebox_shim_optee/Cargo.toml b/litebox_shim_optee/Cargo.toml index 75a74e903..2704876b9 100644 --- a/litebox_shim_optee/Cargo.toml +++ b/litebox_shim_optee/Cargo.toml @@ -23,6 +23,9 @@ zerocopy = { version = "0.8", default-features = false, features = ["derive"] } zeroize = { version = "1.8", default-features = false, features = ["alloc"] } p384 = { version = "0.13.1", default-features = false, features = ["arithmetic", "ecdsa"] } +[features] +idks-production = [] + [lints] workspace = true diff --git a/litebox_shim_optee/src/idk.rs b/litebox_shim_optee/src/idk.rs index 745b1e51f..9530f040a 100644 --- a/litebox_shim_optee/src/idk.rs +++ b/litebox_shim_optee/src/idk.rs @@ -1,11 +1,24 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -use crate::NormalWorldMutPtr; -use litebox::{mm::linux::PAGE_SIZE, utils::TruncateExt}; +use crate::syscalls::pta::PTA_DEFAULT_FLAGS; +use crate::{ + NormalWorldMutPtr, TA_DIGEST_LEN, TaDigest, Task, UserConstPtr, UserMutPtr, syscalls::Cleanup, +}; +use alloc::vec::Vec; +use litebox::{ + mm::linux::PAGE_SIZE, + platform::{RawConstPointer as _, RawMutPointer as _}, + utils::TruncateExt, +}; use litebox_common_linux::errno::Errno; +use litebox_common_optee::{TaFlags, TeeParamType, TeeResult, TeeUuid, UteeParams}; use num_enum::TryFromPrimitive; -use p384::{NonZeroScalar, elliptic_curve::sec1::ToEncodedPoint}; +use p384::{ + NonZeroScalar, + ecdsa::{Signature, SigningKey, signature::Signer}, + elliptic_curve::sec1::ToEncodedPoint, +}; use spin::Once; use zeroize::Zeroizing; @@ -15,11 +28,196 @@ const KEY_ALGORITHM_MASK: u64 = 0xff00; const KEY_VARIANT_MASK: u64 = 0xff; const KEY_ALGORITHM_VALUE_MASK: u64 = KEY_ALGORITHM_MASK | KEY_VARIANT_MASK; const MAX_KEYGEN_ATTEMPT: usize = 256; +const IDKS_ENDORSEMENT_DATA_MAX_SIZE: usize = 8 * 1024 * 1024; +const IDKS_ENDORSEMENT_MAGIC: &[u8; 4] = b"IDKS"; +const IDKS_ENDORSEMENT_VERSION: u32 = 1; +#[cfg(not(feature = "idks-production"))] +const IDKS_DEBUG_FLAG: u8 = 1; +#[cfg(feature = "idks-production")] +const IDKS_DEBUG_FLAG: u8 = 0; +const ISOLATION_SOLUTION: &[u8] = b"LVBS"; +pub(crate) const IDKS_ENDORSEMENT_SIGNATURE_LEN: usize = 96; +const IDKS_ENDORSEMENT_METADATA_LEN: usize = IDKS_ENDORSEMENT_MAGIC.len() + + size_of::() // version + + size_of::() // TA data length + + size_of::() + + size_of::() + + TA_DIGEST_LEN + + size_of::() // TA dynamic flag + + size_of::() + + ISOLATION_SOLUTION.len() + + size_of::(); // certificate length +pub(crate) struct IdksPta; + +#[derive(Clone, Copy, TryFromPrimitive)] +#[repr(u32)] +pub(crate) enum IdksCommandId { + EndorseData = 0, +} + +impl IdksPta { + pub(crate) const FLAGS: TaFlags = PTA_DEFAULT_FLAGS.union(TaFlags::CONCURRENT); + pub(crate) const UUID: TeeUuid = TeeUuid { + time_low: 0xfd79_8211, + time_mid: 0x38a3, + time_hi_and_version: 0x474a, + clock_seq_and_node: [0xab, 0x6c, 0x75, 0x61, 0x0d, 0x45, 0x35, 0x93], + }; + + pub(crate) fn open_session(params: &UteeParams) -> Result { + crate::syscalls::pta::open_default_pta_session(params) + } + + pub(crate) fn close_session( + _task: &Task, + _session_id: u32, + ) { + } + + pub(crate) fn invoke_command( + task: &Task, + cmd_id: u32, + params: &mut UteeParams, + ) -> Result { + match IdksCommandId::try_from(cmd_id).map_err(|_| TeeResult::BadParameters)? { + IdksCommandId::EndorseData => Self::endorse_data(task, params).map(|()| Cleanup::None), + } + } + + fn endorse_data( + task: &Task, + params: &mut UteeParams, + ) -> Result<(), TeeResult> { + use TeeParamType::{MemrefInput, MemrefOutput, None}; + // [in] params[0].memref.buffer Opaque TA data + // [in] params[0].memref.size TA data size + // [out] params[1].memref.buffer Output buffer for signed endorsement + // [out] params[1].memref.size Buffer size + if !params.has_types([MemrefInput, MemrefOutput, None, None]) { + return Err(TeeResult::BadParameters); + } + + let (ta_data_addr, ta_data_size) = params + .get_values(0) + .map_err(|_| TeeResult::BadParameters)? + .ok_or(TeeResult::BadParameters)?; + let ta_data_size = usize::try_from(ta_data_size).map_err(|_| TeeResult::BadParameters)?; + if ta_data_size > IDKS_ENDORSEMENT_DATA_MAX_SIZE { + return Err(TeeResult::BadParameters); + } + if ta_data_size > 0 && ta_data_addr == 0 { + return Err(TeeResult::BadParameters); + } + + let (endorsement_addr, endorsement_size) = params + .get_values(1) + .map_err(|_| TeeResult::BadParameters)? + .ok_or(TeeResult::BadParameters)?; + let ta_signing_cert = task.global.ta_signing_cert; + let required_endorsement_size = endorsement_data_len(ta_data_size, ta_signing_cert.len()) + .and_then(|size| size.checked_add(IDKS_ENDORSEMENT_SIGNATURE_LEN)) + .ok_or(TeeResult::BadParameters)?; + let required_endorsement_size_u64 = + u64::try_from(required_endorsement_size).map_err(|_| TeeResult::BadParameters)?; + if endorsement_size < required_endorsement_size_u64 { + params + .set_values(1, endorsement_addr, required_endorsement_size_u64) + .map_err(|_| TeeResult::BadParameters)?; + return Err(TeeResult::ShortBuffer); + } + if endorsement_addr == 0 { + return Err(TeeResult::BadParameters); + } + + let ta_data = if ta_data_size == 0 { + Vec::new().into_boxed_slice() + } else { + UserConstPtr::::from_usize( + usize::try_from(ta_data_addr).map_err(|_| TeeResult::BadParameters)?, + ) + .to_owned_slice(ta_data_size) + .ok_or(TeeResult::BadParameters)? + }; + let mut endorsement = build_endorsement_data( + &ta_data, + &task.ta_app_id, + task.ta_svn, + &task.ta_digest, + task.ta_dynamic, + ta_signing_cert, + ) + .ok_or(TeeResult::BadParameters)?; + let key_pair = get_identity_signing_key_pair(task.global.platform) + .map_err(|_| TeeResult::GenericError)?; + let signature = endorse_data_with(&endorsement, &key_pair.private_key) + .map_err(|_| TeeResult::GenericError)?; + endorsement.extend_from_slice(&signature); + UserMutPtr::::from_usize( + usize::try_from(endorsement_addr).map_err(|_| TeeResult::BadParameters)?, + ) + .copy_from_slice(0, &endorsement) + .ok_or(TeeResult::AccessDenied)?; + params + .set_values(1, endorsement_addr, required_endorsement_size_u64) + .map_err(|_| TeeResult::BadParameters) + } +} + +fn endorsement_data_len(ta_data_len: usize, ta_signing_cert_len: usize) -> Option { + u32::try_from(ta_data_len).ok()?; + u32::try_from(ta_signing_cert_len).ok()?; + ta_data_len + .checked_add(IDKS_ENDORSEMENT_METADATA_LEN)? + .checked_add(ta_signing_cert_len) +} + +/// IDK_S-signed wire format: +/// MAGIC || VERSION || TA_DATA_LEN || TA_DATA || TA_UUID || TA_SVN || TA_DIGEST || +/// TA_DYNAMIC || DEBUG || ISOLATION_SOLUTION || TA_SIGNING_CERT_LEN || TA_SIGNING_CERT_DER. +/// +/// Integers and UUID are little endian; both lengths are u32 byte counts. +/// A zero certificate length means absent. +fn build_endorsement_data( + ta_data: &[u8], + ta_uuid: &TeeUuid, + ta_svn: u32, + ta_digest: &TaDigest, + ta_dynamic: bool, + ta_signing_cert: &[u8], +) -> Option> { + let capacity = endorsement_data_len(ta_data.len(), ta_signing_cert.len())?; + let ta_data_len = u32::try_from(ta_data.len()).ok()?; + let cert_len = u32::try_from(ta_signing_cert.len()).ok()?; + let mut endorsement = Vec::with_capacity(capacity); + endorsement.extend_from_slice(IDKS_ENDORSEMENT_MAGIC); + endorsement.extend_from_slice(&IDKS_ENDORSEMENT_VERSION.to_le_bytes()); + endorsement.extend_from_slice(&ta_data_len.to_le_bytes()); + endorsement.extend_from_slice(ta_data); + endorsement.extend_from_slice(&ta_uuid.to_le_bytes()); + endorsement.extend_from_slice(&ta_svn.to_le_bytes()); + endorsement.extend_from_slice(ta_digest); + endorsement.push(u8::from(ta_dynamic)); + endorsement.push(IDKS_DEBUG_FLAG); + endorsement.extend_from_slice(ISOLATION_SOLUTION); + endorsement.extend_from_slice(&cert_len.to_le_bytes()); + endorsement.extend_from_slice(ta_signing_cert); + Some(endorsement) +} + +fn endorse_data_with( + endorsement_data: &[u8], + private_key: &[u8; IDENTITY_SIGNING_PRIVATE_KEY_LEN], +) -> Result<[u8; IDKS_ENDORSEMENT_SIGNATURE_LEN], Errno> { + let signing_key = SigningKey::from_slice(private_key).map_err(|_| Errno::EINVAL)?; + let signature: Signature = signing_key.sign(endorsement_data); + let mut signature_bytes = [0u8; IDKS_ENDORSEMENT_SIGNATURE_LEN]; + signature_bytes.copy_from_slice(&signature.to_bytes()); + Ok(signature_bytes) +} static IDENTITY_SIGNING_KEY_PAIR: Once = Once::new(); struct IdentitySigningKeyPair { - #[allow(dead_code, reason = "retained for future IDK_S signing operations")] private_key: Zeroizing<[u8; IDENTITY_SIGNING_PRIVATE_KEY_LEN]>, public_key: [u8; IDENTITY_SIGNING_PUBLIC_KEY_LEN], } @@ -161,26 +359,216 @@ fn identity_signing_public_key_from_private_key( mod tests { use super::*; + // Opaque fixture; certificate validation is the verifier's responsibility. + const TEST_CERT: &[u8] = &[0x30, 0x03, 0x02, 0x01, 0x01]; + #[test] - fn identity_signing_private_key_signs_and_verifies_message() { - use crate::syscalls::tests::init_platform; - use p384::ecdsa::{ - Signature, SigningKey, VerifyingKey, - signature::{Signer, Verifier}, + fn endorsement_has_expected_flat_layout() { + let uuid = TeeUuid { + time_low: 0x1122_3344, + time_mid: 0x5566, + time_hi_and_version: 0x7788, + clock_seq_and_node: [0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00], }; + let digest = [0xa5; TA_DIGEST_LEN]; + let long_data = [0x5a; 256]; + for (cert, ta_dynamic) in [ + (TEST_CERT, false), + (TEST_CERT, true), + (&[][..], false), + (&[][..], true), + ] { + for data in [b"TA data".as_slice(), &[], &long_data] { + let endorsement = + build_endorsement_data(data, &uuid, 7, &digest, ta_dynamic, cert).unwrap(); + let mut expected = Vec::from(b"IDKS\x01\x00\x00\x00".as_slice()); + expected.extend_from_slice(&u32::try_from(data.len()).unwrap().to_le_bytes()); + expected.extend_from_slice(data); + expected.extend_from_slice(&[ + 0x44, 0x33, 0x22, 0x11, 0x66, 0x55, 0x88, 0x77, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, + 0xee, 0xff, 0x00, + ]); + expected.extend_from_slice(&[7, 0, 0, 0]); + expected.extend_from_slice(&digest); + expected.push(u8::from(ta_dynamic)); + expected.push(IDKS_DEBUG_FLAG); + expected.extend_from_slice(b"LVBS"); + expected.extend_from_slice(&u32::try_from(cert.len()).unwrap().to_le_bytes()); + expected.extend_from_slice(cert); + assert_eq!(endorsement, expected); + assert_eq!( + endorsement.len(), + endorsement_data_len(data.len(), cert.len()).unwrap() + ); + + // Parsing must not require caller-supplied lengths. + let data_len = u32::from_le_bytes(endorsement[8..12].try_into().unwrap()) as usize; + let (parsed_data, metadata) = endorsement[12..].split_at(data_len); + assert_eq!(parsed_data, data); + assert_eq!(&metadata[..16], uuid.to_le_bytes()); + assert_eq!(metadata[16 + 4 + TA_DIGEST_LEN], u8::from(ta_dynamic)); + let cert_len_offset = 16 + 4 + TA_DIGEST_LEN + 1 + 1 + 4; + let cert_len = u32::from_le_bytes( + metadata[cert_len_offset..cert_len_offset + 4] + .try_into() + .unwrap(), + ) as usize; + let (parsed_cert, remaining) = metadata[cert_len_offset + 4..].split_at(cert_len); + assert_eq!(parsed_cert, cert); + assert!(remaining.is_empty()); + } + } + } + + #[test] + fn pta_endorsement_uses_global_certificate_and_reports_output_size() { + use p384::ecdsa::{Signature, VerifyingKey, signature::Verifier}; + + for (cert, ta_dynamic) in [ + (TEST_CERT, false), + (TEST_CERT, true), + (&[][..], false), + (&[][..], true), + ] { + let shim = crate::syscalls::tests::shim_builder() + .with_ta_signing_cert(cert) + .build(); + let mut task = shim.0.new_test_task(); + task.ta_dynamic = ta_dynamic; + assert!(core::ptr::eq(task.global.ta_signing_cert, cert)); + + for data in [b"TA data".as_slice(), &[]] { + let mut params = UteeParams::new(); + params.set_type(0, TeeParamType::MemrefInput).unwrap(); + params.set_type(1, TeeParamType::MemrefOutput).unwrap(); + let data_addr = if data.is_empty() { + 0 + } else { + data.as_ptr() as u64 + }; + params.set_values(0, data_addr, data.len() as u64).unwrap(); + let expected = build_endorsement_data( + data, + &task.ta_app_id, + task.ta_svn, + &task.ta_digest, + task.ta_dynamic, + cert, + ) + .unwrap(); + let required_size = expected.len() + IDKS_ENDORSEMENT_SIGNATURE_LEN; + + assert_eq!( + IdksPta::endorse_data(&task, &mut params), + Err(TeeResult::ShortBuffer) + ); + assert_eq!( + params.get_values(1).unwrap(), + Some((0, required_size as u64)) + ); + + let mut output = alloc::vec![0xcc; required_size + 1]; + let output_addr = output.as_mut_ptr() as u64; + params + .set_values(1, output_addr, (required_size - 1) as u64) + .unwrap(); + assert_eq!( + IdksPta::endorse_data(&task, &mut params), + Err(TeeResult::ShortBuffer) + ); + assert!(output.iter().all(|byte| *byte == 0xcc)); + assert_eq!( + params.get_values(1).unwrap(), + Some((output_addr, required_size as u64)) + ); - let message = b"IDK_S signing test message"; + IdksPta::endorse_data(&task, &mut params).unwrap(); + assert_eq!(&output[..expected.len()], expected); + assert_eq!(output[required_size], 0xcc); + let key_pair = get_identity_signing_key_pair(task.global.platform).unwrap(); + let verifying_key = VerifyingKey::from_sec1_bytes(&key_pair.public_key).unwrap(); + let signature = + Signature::from_slice(&output[expected.len()..required_size]).unwrap(); + verifying_key.verify(&expected, &signature).unwrap(); + } + } + } + + #[test] + fn pta_rejects_invalid_parameter_types_and_buffers() { + let task = crate::syscalls::tests::init_platform(); + let mut params = UteeParams::new(); + params.set_type(0, TeeParamType::MemrefInput).unwrap(); + params.set_type(1, TeeParamType::MemrefInput).unwrap(); + params.set_type(2, TeeParamType::MemrefOutput).unwrap(); + assert_eq!( + IdksPta::endorse_data(&task, &mut params), + Err(TeeResult::BadParameters) + ); + + params.set_type(1, TeeParamType::MemrefOutput).unwrap(); + params.set_type(2, TeeParamType::None).unwrap(); + params.set_values(0, 0, 1).unwrap(); + assert_eq!( + IdksPta::endorse_data(&task, &mut params), + Err(TeeResult::BadParameters) + ); + params + .set_values(0, 1, (IDKS_ENDORSEMENT_DATA_MAX_SIZE + 1) as u64) + .unwrap(); + assert_eq!( + IdksPta::endorse_data(&task, &mut params), + Err(TeeResult::BadParameters) + ); + params.set_values(0, 0, 0).unwrap(); + params.set_values(1, 0, u64::MAX).unwrap(); + assert_eq!( + IdksPta::endorse_data(&task, &mut params), + Err(TeeResult::BadParameters) + ); + } + + #[test] + fn endorsement_length_rejects_overflow() { + assert!(endorsement_data_len(usize::MAX, 0).is_none()); + assert!(endorsement_data_len(0, usize::MAX).is_none()); + assert!(endorsement_data_len(0, u32::MAX as usize + 1).is_none()); + assert!(endorsement_data_len(u32::MAX as usize + 1, 0).is_none()); + } + + #[test] + fn endorsement_signature_covers_plaintext_and_certificate() { + use p384::ecdsa::{Signature, VerifyingKey, signature::Verifier}; - let _task = init_platform(); - let shim = crate::syscalls::tests::shim_builder().build(); - let private_key = generate_identity_signing_private_key(shim.platform()).unwrap(); - assert!(is_valid_identity_signing_private_key(&private_key)); - let signing_key = SigningKey::from_slice(&private_key[..]).unwrap(); + let mut private_key = [0u8; IDENTITY_SIGNING_PRIVATE_KEY_LEN]; + private_key[IDENTITY_SIGNING_PRIVATE_KEY_LEN - 1] = 1; + let mut endorsement = build_endorsement_data( + b"TA data", + &TeeUuid::NIL, + 7, + &[0xa5; TA_DIGEST_LEN], + false, + TEST_CERT, + ) + .unwrap(); + let signature = endorse_data_with(&endorsement, &private_key).unwrap(); let public_key = identity_signing_public_key_from_private_key(&private_key).unwrap(); let verifying_key = VerifyingKey::from_sec1_bytes(&public_key).unwrap(); + let signature = Signature::from_slice(&signature).unwrap(); + verifying_key.verify(&endorsement, &signature).unwrap(); - let signature: Signature = signing_key.sign(message); - - verifying_key.verify(message, &signature).unwrap(); + let cert_start = endorsement.len() - TEST_CERT.len(); + for offset in [ + 8, + 12, + 12 + b"TA data".len() + 16 + 4, + 12 + b"TA data".len() + 16 + 4 + TA_DIGEST_LEN, + cert_start - 4, + cert_start, + ] { + endorsement[offset] ^= 1; + assert!(verifying_key.verify(&endorsement, &signature).is_err()); + endorsement[offset] ^= 1; + } } } diff --git a/litebox_shim_optee/src/lib.rs b/litebox_shim_optee/src/lib.rs index 4d96ccd24..f39614f46 100644 --- a/litebox_shim_optee/src/lib.rs +++ b/litebox_shim_optee/src/lib.rs @@ -28,6 +28,7 @@ use litebox_common_optee::{ TeeAttributeType, TeeCrypStateHandle, TeeHandleFlag, TeeIdentity, TeeLogin, TeeObjHandle, TeeObjectInfo, TeeObjectType, TeeOperationMode, TeeResult, TeeUuid, UteeAttribute, }; +use sha2::{Digest, Sha256}; pub mod loader; pub mod session; @@ -41,6 +42,8 @@ pub mod idk; pub use session::{OpenSessionTarget, SessionManager, SessionToken, TaInstance}; const MAX_KERNEL_BUF_SIZE: usize = 0x80_000; +pub(crate) const TA_DIGEST_LEN: usize = 32; +pub(crate) type TaDigest = [u8; TA_DIGEST_LEN]; /// Platform capabilities required by the OP-TEE shim. pub trait OpteeShimPlatform: @@ -152,6 +155,7 @@ pub struct OpteeShimBuilder { platform: &'static Platform, session_manager: &'static session::SessionManager, litebox: LiteBox, + ta_signing_cert: &'static [u8], } impl OpteeShimBuilder { @@ -166,9 +170,17 @@ impl OpteeShimBuilder { platform, session_manager, litebox: LiteBox::new(platform), + ta_signing_cert: &[], } } + /// A certificate for TA signature verification. Defaults to empty (no certificate). + #[must_use] + pub fn with_ta_signing_cert(mut self, ta_signing_cert: &'static [u8]) -> Self { + self.ta_signing_cert = ta_signing_cert; + self + } + /// Returns the litebox object for the shim. pub fn litebox(&self) -> &LiteBox { &self.litebox @@ -183,6 +195,7 @@ impl OpteeShimBuilder { pm: PageManager::new(&self.litebox), _litebox: self.litebox, ta_uuid_map: ta_uuid_map(), + ta_signing_cert: self.ta_signing_cert, pta_busy: spin::mutex::SpinMutex::new(HashSet::new()), }); OpteeShim(global) @@ -205,6 +218,7 @@ struct GlobalState { _litebox: litebox::LiteBox, /// The TA UUID to binary map for TA loading. ta_uuid_map: &'static TaUuidMap, + ta_signing_cert: &'static [u8], /// Tracks which non-concurrent PTAs (i.e., PTAs w/o `TaFlags::CONCURRENT`) /// are currently busy. A busy PTA is *rejected* with `TeeResult::Busy` /// rather than queued. @@ -237,11 +251,6 @@ impl GlobalState { } } - /// Get the TA flags associated with the given TA UUID. - pub(crate) fn get_ta_flags(&self, ta_uuid: &TeeUuid) -> TaFlags { - self.ta_uuid_map.get_flags(ta_uuid).unwrap_or_default() - } - /// Monotonic time elapsed since this instance was created, used as GP /// "system time" (`TEE_GetSystemTime`). /// @@ -286,7 +295,7 @@ impl Clone for OpteeShim { impl OpteeShim { /// Load the given `ldelf` binary into memory while making it ready to load the TA binary specified - /// by `ta_uuid` (and optionally `ta_bin`). + /// by `ta_uuid`. /// /// The loaded program is an *instance*: a single instance can serve many /// sessions. The active session id is supplied per entry via @@ -298,12 +307,23 @@ impl OpteeShim { ldelf_bin: &[u8], ta_uuid: TeeUuid, ) -> Result, loader::elf::ElfLoaderError> { + let (ta_binary, ta_flags) = self + .0 + .ta_uuid_map + .get_with_flags(&ta_uuid) + .ok_or(loader::elf::ElfLoaderError::OpenError(Errno::ENOENT))?; + let ta_digest = Sha256::digest(&ta_binary).into(); let entrypoints = crate::OpteeShimEntrypoints { _not_send: core::marker::PhantomData, task: Task { global: self.0.clone(), thread: ThreadState::new(), ta_app_id: ta_uuid, + // TODO: Populate this from trusted TA version metadata when available. + ta_svn: 0, + ta_digest, + // TODO: Set from the TA source when dynamic loading is supported. + ta_dynamic: false, tee_cryp_state_map: TeeCrypStateMap::new(), tee_obj_map: TeeObjMap::new(), ta_handle_map: TaHandleMap::new(), @@ -330,8 +350,6 @@ impl OpteeShim { } else { None }; - // Get TA flags from the stored binary - let ta_flags = entrypoints.task.global.get_ta_flags(&ta_uuid); Ok(LoadedProgram { entrypoints: Some(entrypoints), params_address, @@ -1446,9 +1464,11 @@ impl TaUuidMap { self.inner.read().get(uuid).map(|info| info.binary.clone()) } - /// Get the TA flags for a given UUID. - pub(crate) fn get_flags(&self, uuid: &TeeUuid) -> Option { - self.inner.read().get(uuid).map(|info| info.flags) + fn get_with_flags(&self, uuid: &TeeUuid) -> Option<(Arc<[u8]>, TaFlags)> { + self.inner + .read() + .get(uuid) + .map(|info| (info.binary.clone(), info.flags)) } // Lazy removal of TA binaries when they are no longer needed. @@ -1471,6 +1491,11 @@ struct Task { thread: ThreadState, /// TA UUID ta_app_id: TeeUuid, + /// TA security version number + ta_svn: u32, + /// SHA-256 digest of the raw TA binary. + ta_digest: TaDigest, + ta_dynamic: bool, /// TEE cryptography state map tee_cryp_state_map: TeeCrypStateMap, /// TEE object map @@ -1638,6 +1663,9 @@ mod test_utils { global: self.clone(), thread: ThreadState::new(), ta_app_id: TeeUuid::default(), + ta_svn: 0, + ta_digest: [0; TA_DIGEST_LEN], + ta_dynamic: false, tee_cryp_state_map: TeeCrypStateMap::new(), tee_obj_map: TeeObjMap::new(), ta_handle_map: TaHandleMap::new(), diff --git a/litebox_shim_optee/src/syscalls/pta.rs b/litebox_shim_optee/src/syscalls/pta.rs index a92bda6a2..ae959ed6f 100644 --- a/litebox_shim_optee/src/syscalls/pta.rs +++ b/litebox_shim_optee/src/syscalls/pta.rs @@ -4,8 +4,7 @@ //! Implementation of pseudo TAs (PTAs) which export system services as //! the functions of built-in TAs. -use crate::syscalls::Cleanup; -use crate::{Task, UserConstPtr, UserMutPtr}; +use crate::{Task, UserConstPtr, UserMutPtr, idk::IdksPta, syscalls::Cleanup}; use alloc::vec; use alloc::vec::Vec; use hmac::{Hmac, Mac}; @@ -28,12 +27,14 @@ struct SystemPta; #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] pub(crate) enum PseudoTa { System, + Idks, } impl PseudoTa { pub(crate) fn from_uuid(uuid: &TeeUuid) -> Option { match *uuid { SystemPta::UUID => Some(Self::System), + IdksPta::UUID => Some(Self::Idks), _ => None, } } @@ -42,6 +43,7 @@ impl PseudoTa { fn open_session(self, params: &UteeParams) -> Result { match self { Self::System => SystemPta::open_session(params), + Self::Idks => IdksPta::open_session(params), } } @@ -54,6 +56,7 @@ impl PseudoTa { let _busy = task.try_set_busy(self)?; match self { Self::System => SystemPta::invoke_command(task, cmd_id, params), + Self::Idks => IdksPta::invoke_command(task, cmd_id, params), } } @@ -64,22 +67,37 @@ impl PseudoTa { ) { match self { Self::System => SystemPta::close_session(task, session_id), + Self::Idks => IdksPta::close_session(task, session_id), } } fn flags(self) -> TaFlags { match self { Self::System => SystemPta::FLAGS, + Self::Idks => IdksPta::FLAGS, } } } -const PTA_DEFAULT_FLAGS: TaFlags = TaFlags::SINGLE_INSTANCE +pub(crate) const PTA_DEFAULT_FLAGS: TaFlags = TaFlags::SINGLE_INSTANCE .union(TaFlags::MULTI_SESSION) .union(TaFlags::INSTANCE_KEEP_ALIVE); const MAX_PTA_SESSIONS_PER_TASK: usize = 100; +pub(crate) fn open_default_pta_session(params: &UteeParams) -> Result { + if !params.has_types([ + TeeParamType::None, + TeeParamType::None, + TeeParamType::None, + TeeParamType::None, + ]) { + return Err(TeeResult::BadParameters); + } + + crate::SessionIdPool::allocate().ok_or(TeeResult::Busy) +} + struct PtaBusyGuard<'a, Platform: crate::OpteeShimPlatform> { task: &'a Task, pta: PseudoTa, @@ -223,16 +241,7 @@ impl SystemPta { }; fn open_session(params: &UteeParams) -> Result { - if !params.has_types([ - TeeParamType::None, - TeeParamType::None, - TeeParamType::None, - TeeParamType::None, - ]) { - return Err(TeeResult::BadParameters); - } - - crate::SessionIdPool::allocate().ok_or(TeeResult::Busy) + open_default_pta_session(params) } fn close_session(_task: &Task, _session_id: u32) {