diff --git a/litebox/src/fs/devices.rs b/litebox/src/fs/devices.rs index df24df2da7..ecd817a6ee 100644 --- a/litebox/src/fs/devices.rs +++ b/litebox/src/fs/devices.rs @@ -293,7 +293,7 @@ where Ok(0) } Device::URandom => { - self.litebox.x.platform.fill_bytes_crng(buf); + self.litebox.x.platform.fill_bytes_crng(buf, None); Ok(buf.len()) } } diff --git a/litebox/src/platform/mock.rs b/litebox/src/platform/mock.rs index 5eed9f861e..4e764814b4 100644 --- a/litebox/src/platform/mock.rs +++ b/litebox/src/platform/mock.rs @@ -321,7 +321,7 @@ impl StdioProvider for MockPlatform { } impl CrngProvider for MockPlatform { - fn fill_bytes_crng(&self, buf: &mut [u8]) { + fn fill_bytes_crng(&self, buf: &mut [u8], _seed: Option<&[u8]>) { let mut random = self.random.lock().unwrap(); let mut off = 0; while off < buf.len() { diff --git a/litebox/src/platform/mod.rs b/litebox/src/platform/mod.rs index 3b354a4dbd..be313cb342 100644 --- a/litebox/src/platform/mod.rs +++ b/litebox/src/platform/mod.rs @@ -599,7 +599,7 @@ pub trait CrngProvider { /// Panics if unable to fill the buffer with random bytes. This is /// considered a fatal error--LiteBox code is not expected to handle such /// failures. - fn fill_bytes_crng(&self, buf: &mut [u8]); + fn fill_bytes_crng(&self, buf: &mut [u8], seed: Option<&[u8]>); } /// Provider of derived device-specific keys. diff --git a/litebox_common_lvbs/src/lib.rs b/litebox_common_lvbs/src/lib.rs index 916cd7f33d..068dedc899 100644 --- a/litebox_common_lvbs/src/lib.rs +++ b/litebox_common_lvbs/src/lib.rs @@ -48,11 +48,9 @@ pub const VSM_VTL_CALL_FUNC_ID_KEXEC_VALIDATE: u32 = 0x1_ffea; pub const VSM_VTL_CALL_FUNC_ID_PATCH_TEXT: u32 = 0x1_ffeb; pub const VSM_VTL_CALL_FUNC_ID_ALLOCATE_RINGBUFFER_MEMORY: u32 = 0x1_ffec; -// This VSM function ID for setting the platform root key is subject to change -pub const VSM_VTL_CALL_FUNC_ID_SET_PLATFORM_ROOT_KEY: u32 = 0x1_ffed; - -// This VSM function ID for generating the identity signing key is subject to change -pub const VSM_VTL_CALL_FUNC_ID_GENERATE_IDENTITY_SIGNING_KEY: u32 = 0x1_ffee; +// This VSM function ID for setting the platform root key and generating the identity signing key is subject to change +pub const VSM_VTL_CALL_FUNC_ID_SET_PLATFORM_ROOT_KEY_AND_GENERATE_IDENTITY_SIGNING_KEY: u32 = + 0x1_ffed; // This VSM function ID for OP-TEE messages is subject to change pub const VSM_VTL_CALL_FUNC_ID_OPTEE_MESSAGE: u32 = 0x1_fff0; @@ -76,8 +74,8 @@ pub enum VsmFunction { PatchText = VSM_VTL_CALL_FUNC_ID_PATCH_TEXT, OpteeMessage = VSM_VTL_CALL_FUNC_ID_OPTEE_MESSAGE, AllocateRingbufferMemory = VSM_VTL_CALL_FUNC_ID_ALLOCATE_RINGBUFFER_MEMORY, - SetPlatformRootKey = VSM_VTL_CALL_FUNC_ID_SET_PLATFORM_ROOT_KEY, - GenerateIdentitySigningKey = VSM_VTL_CALL_FUNC_ID_GENERATE_IDENTITY_SIGNING_KEY, + SetPlatformRootKeyAndGenerateIdentitySigningKey = + VSM_VTL_CALL_FUNC_ID_SET_PLATFORM_ROOT_KEY_AND_GENERATE_IDENTITY_SIGNING_KEY, } // `HV_STATUS_*` constants used as discriminants for `HypervCallError`. diff --git a/litebox_platform_linux_kernel/src/host/snp/snp_impl.rs b/litebox_platform_linux_kernel/src/host/snp/snp_impl.rs index cc994a2202..60ad240e55 100644 --- a/litebox_platform_linux_kernel/src/host/snp/snp_impl.rs +++ b/litebox_platform_linux_kernel/src/host/snp/snp_impl.rs @@ -589,7 +589,7 @@ impl HostInterface for HostSnpInterface { } impl litebox::platform::CrngProvider for SnpLinuxKernel { - fn fill_bytes_crng(&self, buf: &mut [u8]) { + fn fill_bytes_crng(&self, buf: &mut [u8], _seed: Option<&[u8]>) { // FIXME: call into the trusted host to get random bytes. static RANDOM: spin::mutex::SpinMutex = spin::mutex::SpinMutex::new(litebox::utils::rng::FastRng::new_from_seed( diff --git a/litebox_platform_linux_userland/src/lib.rs b/litebox_platform_linux_userland/src/lib.rs index 7006a876d0..859fe4f735 100644 --- a/litebox_platform_linux_userland/src/lib.rs +++ b/litebox_platform_linux_userland/src/lib.rs @@ -2341,7 +2341,7 @@ unsafe fn interrupt_signal_handler( } impl litebox::platform::CrngProvider for LinuxUserland { - fn fill_bytes_crng(&self, buf: &mut [u8]) { + fn fill_bytes_crng(&self, buf: &mut [u8], _seed: Option<&[u8]>) { getrandom::fill(buf).expect("getrandom failed"); } } diff --git a/litebox_platform_lvbs/src/host/lvbs_impl.rs b/litebox_platform_lvbs/src/host/lvbs_impl.rs index d77c792fde..f4eae7521a 100644 --- a/litebox_platform_lvbs/src/host/lvbs_impl.rs +++ b/litebox_platform_lvbs/src/host/lvbs_impl.rs @@ -105,14 +105,14 @@ unsafe impl litebox::platform::ThreadLocalStorageProvider for LvbsLinuxKernel { } impl litebox::platform::CrngProvider for LvbsLinuxKernel { - fn fill_bytes_crng(&self, buf: &mut [u8]) { + fn fill_bytes_crng(&self, buf: &mut [u8], seed: Option<&[u8]>) { static RANDOM: spin::mutex::SpinMutex> = spin::mutex::SpinMutex::new(None); let mut random = RANDOM.lock(); random .get_or_insert_with(|| { LvbsCrng::new( - PRK_ONCE.get().expect("Platform root key not initialized"), + seed.expect("CRNG seed not provided"), rdrand_seed().expect("RDRAND unavailable during CRNG initialization"), ) }) @@ -134,10 +134,10 @@ struct LvbsCrng { } impl LvbsCrng { - fn new(prk: &[u8; PRK_LEN], rdrand_seed: CrngSeed) -> Self { + fn new(seed: &[u8], rdrand_seed: CrngSeed) -> Self { Self { - random: rand_chacha::ChaCha20Rng::from_seed(crng_seed_from_prk_and_rdrand( - prk, + random: rand_chacha::ChaCha20Rng::from_seed(crng_seed_from_tpm_and_rdrand( + seed, rdrand_seed, )), bytes_until_reseed: CRNG_RESEED_INTERVAL_BYTES, @@ -231,10 +231,10 @@ fn rdrand_seed() -> Option { Some(seed) } -fn crng_seed_from_prk_and_rdrand(prk: &[u8; PRK_LEN], rdrand_seed: CrngSeed) -> CrngSeed { +fn crng_seed_from_tpm_and_rdrand(seed: &[u8], rdrand_seed: CrngSeed) -> CrngSeed { sha2::Sha256::new() .chain_update(b"litebox-lvbs-crng-seed-v1") - .chain_update(prk) + .chain_update(seed) .chain_update(rdrand_seed) .finalize() .into() diff --git a/litebox_platform_windows_userland/src/lib.rs b/litebox_platform_windows_userland/src/lib.rs index 2cc2740210..c488a75bb6 100644 --- a/litebox_platform_windows_userland/src/lib.rs +++ b/litebox_platform_windows_userland/src/lib.rs @@ -2057,7 +2057,7 @@ unsafe impl litebox::platform::ThreadLocalStorageProvider for WindowsUserland { } impl litebox::platform::CrngProvider for WindowsUserland { - fn fill_bytes_crng(&self, buf: &mut [u8]) { + fn fill_bytes_crng(&self, buf: &mut [u8], _seed: Option<&[u8]>) { getrandom::fill(buf).expect("getrandom failed"); } } diff --git a/litebox_runner_lvbs/src/lib.rs b/litebox_runner_lvbs/src/lib.rs index 8e5350bdc5..d178aeb423 100644 --- a/litebox_runner_lvbs/src/lib.rs +++ b/litebox_runner_lvbs/src/lib.rs @@ -13,7 +13,7 @@ use litebox::{ utils::{ReinterpretSignedExt, TruncateExt}, }; use litebox_common_linux::errno::Errno; -use litebox_common_lvbs::{NUM_VTLCALL_PARAMS, VsmError, VsmFunction}; +use litebox_common_lvbs::{NUM_VTLCALL_PARAMS, PRK_LEN, VsmError, VsmFunction}; use litebox_common_optee::{ OpteeMessageCommand, OpteeMsgArgs, OpteeRpcArgs, OpteeSmcArgs, OpteeSmcResult, OpteeSmcReturnCode, TeeOrigin, TeeResult, UteeEntryFunc, UteeParams, optee_msg_args_total_size, @@ -256,10 +256,24 @@ fn vtlcall_dispatch(params: &[u64; NUM_VTLCALL_PARAMS]) -> i64 { let smc_args_pfn = params[1]; optee_smc_handler_entry(smc_args_pfn) } - VsmFunction::GenerateIdentitySigningKey => { - let public_key_pa = params[1]; - let key_alg = params[2]; - litebox_shim_optee::idk::generate_identity_signing_key(public_key_pa, key_alg) + VsmFunction::SetPlatformRootKeyAndGenerateIdentitySigningKey => { + let tpm_random_pa = params[1]; + let public_key_pa = params[2]; + let key_alg = params[3]; + + let return_code = vsm_dispatch( + VsmFunction::SetPlatformRootKeyAndGenerateIdentitySigningKey, + ¶ms[1..2], + ); + if return_code < 0 { + return return_code; + } + + litebox_shim_optee::idk::generate_identity_signing_key( + tpm_random_pa + PRK_LEN as u64, + public_key_pa, + key_alg, + ) } _ => vsm_dispatch(func_id, ¶ms[1..]), } @@ -310,9 +324,8 @@ fn vsm_dispatch(func_id: VsmFunction, params: &[u64]) -> i64 { VsmFunction::AllocateRingbufferMemory => { heki.allocate_ringbuffer_memory(params[0], params[1]) } - VsmFunction::SetPlatformRootKey => vtl1.set_platform_root_key(params[0]).map(|()| 0), - VsmFunction::GenerateIdentitySigningKey => { - Err(VsmError::OperationNotSupported("Identity key generation")) + VsmFunction::SetPlatformRootKeyAndGenerateIdentitySigningKey => { + vtl1.set_platform_root_key(params[0]).map(|()| 0) } VsmFunction::OpteeMessage => Err(VsmError::OperationNotSupported("OP-TEE communication")), }; diff --git a/litebox_shim_linux/src/syscalls/misc.rs b/litebox_shim_linux/src/syscalls/misc.rs index ee546e53eb..b1c4a13280 100644 --- a/litebox_shim_linux/src/syscalls/misc.rs +++ b/litebox_shim_linux/src/syscalls/misc.rs @@ -26,7 +26,11 @@ impl Task { while offset < count { let len = (count - offset).min(kbuf.len()); let kbuf = &mut kbuf[..len]; - <_ as litebox::platform::CrngProvider>::fill_bytes_crng(self.global.platform, kbuf); + <_ as litebox::platform::CrngProvider>::fill_bytes_crng( + self.global.platform, + kbuf, + None, + ); buf.copy_from_slice::(offset, kbuf) .ok_or(Errno::EFAULT)?; offset += len; diff --git a/litebox_shim_optee/src/idk.rs b/litebox_shim_optee/src/idk.rs index 282aea63b1..558187cbe2 100644 --- a/litebox_shim_optee/src/idk.rs +++ b/litebox_shim_optee/src/idk.rs @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -use crate::NormalWorldMutPtr; +use crate::{NormalWorldConstPtr, NormalWorldMutPtr}; use litebox::{mm::linux::PAGE_SIZE, platform::CrngProvider, utils::TruncateExt}; use litebox_common_linux::errno::Errno; use num_enum::TryFromPrimitive; @@ -11,6 +11,7 @@ use zeroize::Zeroizing; const IDENTITY_SIGNING_PRIVATE_KEY_LEN: usize = 48; const IDENTITY_SIGNING_PUBLIC_KEY_LEN: usize = 97; +const TPM_IDKS_RANDOM_LEN: usize = 32; const KEY_ALGORITHM_MASK: u64 = 0xff00; const KEY_VARIANT_MASK: u64 = 0xff; const KEY_ALGORITHM_VALUE_MASK: u64 = KEY_ALGORITHM_MASK | KEY_VARIANT_MASK; @@ -40,8 +41,8 @@ enum EcdsaCurve { P521 = 0x03, } -pub fn generate_identity_signing_key(public_key_pa: u64, key_alg: u64) -> i64 { - match generate_identity_signing_key_inner(public_key_pa, key_alg) { +pub fn generate_identity_signing_key(tpm_random_pa: u64, public_key_pa: u64, key_alg: u64) -> i64 { + match generate_identity_signing_key_inner(tpm_random_pa, public_key_pa, key_alg) { Ok(res) => res, Err(e) => e.as_neg().into(), } @@ -61,16 +62,30 @@ pub fn generate_identity_signing_key(public_key_pa: u64, key_alg: u64) -> i64 { /// This function assumes that the caller prepares a buffer at the given physical /// address (in a single or contiguous physical memory page(s)) whose length is equal to /// or greater than `IDENTITY_SIGNING_PUBLIC_KEY_LEN`. -fn generate_identity_signing_key_inner(public_key_pa: u64, key_alg: u64) -> Result { +fn generate_identity_signing_key_inner( + tpm_random_pa: u64, + public_key_pa: u64, + key_alg: u64, +) -> Result { validate_key_algorithm(key_alg)?; + let tpm_random_ptr = NormalWorldConstPtr::::with_contiguous_pages( + tpm_random_pa.trunc(), + TPM_IDKS_RANDOM_LEN, + ) + .map_err(|_| Errno::EINVAL)?; + let mut tpm_random = [0u8; TPM_IDKS_RANDOM_LEN]; + tpm_random_ptr + .read_slice_at_offset(0, &mut tpm_random) + .map_err(|_| Errno::EFAULT)?; + let pubkey_ptr = NormalWorldMutPtr::<[u8; IDENTITY_SIGNING_PUBLIC_KEY_LEN], PAGE_SIZE>::with_usize( public_key_pa.trunc(), ) .map_err(|_| Errno::EINVAL)?; - let key_pair = get_identity_signing_key_pair()?; + let key_pair = get_identity_signing_key_pair(Some(&tpm_random))?; pubkey_ptr .write_at_offset(0, key_pair.public_key) .map_err(|_| Errno::EFAULT)?; @@ -100,9 +115,11 @@ fn validate_key_algorithm(key_alg: u64) -> Result<(), Errno> { } } -fn get_identity_signing_key_pair() -> Result<&'static IdentitySigningKeyPair, Errno> { +fn get_identity_signing_key_pair( + tpm_random: Option<&[u8; TPM_IDKS_RANDOM_LEN]>, +) -> Result<&'static IdentitySigningKeyPair, Errno> { IDENTITY_SIGNING_KEY_PAIR.try_call_once(|| { - let private_key = generate_identity_signing_private_key()?; + let private_key = generate_identity_signing_private_key(tpm_random)?; let public_key = identity_signing_public_key_from_private_key(&private_key)?; Ok(IdentitySigningKeyPair { private_key, @@ -111,12 +128,13 @@ fn get_identity_signing_key_pair() -> Result<&'static IdentitySigningKeyPair, Er }) } -fn generate_identity_signing_private_key() --> Result, Errno> { +fn generate_identity_signing_private_key( + tpm_random: Option<&[u8; TPM_IDKS_RANDOM_LEN]>, +) -> Result, Errno> { let mut private_key_bytes = Zeroizing::new([0u8; IDENTITY_SIGNING_PRIVATE_KEY_LEN]); for _ in 0..MAX_KEYGEN_ATTEMPT { - litebox_platform_multiplex::platform().fill_bytes_crng(&mut *private_key_bytes); + litebox_platform_multiplex::platform().fill_bytes_crng(&mut *private_key_bytes, tpm_random.map(|r| &r[..])); if is_valid_identity_signing_private_key(&private_key_bytes) { return Ok(private_key_bytes); } @@ -160,7 +178,7 @@ mod tests { let message = b"IDK_S signing test message"; let _task = init_platform(); - let private_key = generate_identity_signing_private_key().unwrap(); + let private_key = generate_identity_signing_private_key(None).unwrap(); assert!(is_valid_identity_signing_private_key(&private_key)); let signing_key = SigningKey::from_slice(&private_key[..]).unwrap(); let public_key = identity_signing_public_key_from_private_key(&private_key).unwrap(); diff --git a/litebox_shim_optee/src/loader/ta_stack.rs b/litebox_shim_optee/src/loader/ta_stack.rs index a0057a78b7..5e8cb8c30c 100644 --- a/litebox_shim_optee/src/loader/ta_stack.rs +++ b/litebox_shim_optee/src/loader/ta_stack.rs @@ -258,7 +258,7 @@ impl TaStack { // Random 16-byte stack canary let mut canary = [0u8; 16]; - ::fill_bytes_crng(platform, &mut canary); + ::fill_bytes_crng(platform, &mut canary, None); self.push_bytes(&canary)?; // `reenter_thread` *jumps* into the TA entry point (which is a function) rather than diff --git a/litebox_shim_optee/src/syscalls/cryp.rs b/litebox_shim_optee/src/syscalls/cryp.rs index 60394b0eae..c9f6c523c8 100644 --- a/litebox_shim_optee/src/syscalls/cryp.rs +++ b/litebox_shim_optee/src/syscalls/cryp.rs @@ -310,6 +310,7 @@ impl Task { ::fill_bytes_crng( self.global.platform, buf, + None, ); } Ok(())