From 66c7fbd1a7ec3bfb344fd88b7f29092201798313 Mon Sep 17 00:00:00 2001 From: Angelina Vu Date: Mon, 3 Aug 2026 18:11:56 +0000 Subject: [PATCH 1/5] Combine PRK and IDK_S vtlcalls. Signed-off-by: Angelina Vu --- litebox_common_lvbs/src/lib.rs | 12 +++++------ litebox_runner_lvbs/src/lib.rs | 29 +++++++++++++++++++------- litebox_shim_optee/src/idk.rs | 38 +++++++++++++++++++++++++--------- 3 files changed, 54 insertions(+), 25 deletions(-) diff --git a/litebox_common_lvbs/src/lib.rs b/litebox_common_lvbs/src/lib.rs index 916cd7f33..068dedc89 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_runner_lvbs/src/lib.rs b/litebox_runner_lvbs/src/lib.rs index 7a0635551..8616a80d5 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, @@ -261,10 +261,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..]), } @@ -315,9 +329,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_optee/src/idk.rs b/litebox_shim_optee/src/idk.rs index 282aea63b..aa1877180 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 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]; + 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,8 +128,9 @@ 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 { @@ -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(); From a0607ac9fb33764d2e08b0007a66d93dfd991e66 Mon Sep 17 00:00:00 2001 From: Angelina Vu Date: Wed, 5 Aug 2026 20:28:14 +0000 Subject: [PATCH 2/5] Use TPM random value passed from VTL0 to seed identity signing key generation. Signed-off-by: Angelina Vu --- litebox/src/fs/devices.rs | 2 +- litebox/src/platform/mock.rs | 2 +- litebox/src/platform/mod.rs | 2 +- .../src/host/snp/snp_impl.rs | 2 +- litebox_platform_linux_userland/src/lib.rs | 2 +- litebox_platform_lvbs/src/host/lvbs_impl.rs | 14 +++++++------- litebox_platform_windows_userland/src/lib.rs | 2 +- litebox_shim_linux/src/syscalls/misc.rs | 6 +++++- litebox_shim_optee/src/idk.rs | 7 ++++--- litebox_shim_optee/src/loader/ta_stack.rs | 2 +- litebox_shim_optee/src/syscalls/cryp.rs | 1 + 11 files changed, 24 insertions(+), 18 deletions(-) diff --git a/litebox/src/fs/devices.rs b/litebox/src/fs/devices.rs index df24df2da..ecd817a6e 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 5eed9f861..4e764814b 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 3b354a4db..be313cb34 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_platform_linux_kernel/src/host/snp/snp_impl.rs b/litebox_platform_linux_kernel/src/host/snp/snp_impl.rs index cc994a220..60ad240e5 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 7006a876d..859fe4f73 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 d77c792fd..f4eae7521 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 2cc274021..c488a75bb 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_shim_linux/src/syscalls/misc.rs b/litebox_shim_linux/src/syscalls/misc.rs index ee546e53e..b1c4a1328 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 aa1877180..53cb17c81 100644 --- a/litebox_shim_optee/src/idk.rs +++ b/litebox_shim_optee/src/idk.rs @@ -69,13 +69,13 @@ fn generate_identity_signing_key_inner( ) -> Result { validate_key_algorithm(key_alg)?; - let random_ptr = NormalWorldConstPtr::::with_contiguous_pages( + 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]; - random_ptr + tpm_random_ptr .read_slice_at_offset(0, &mut tpm_random) .map_err(|_| Errno::EFAULT)?; @@ -134,7 +134,8 @@ fn generate_identity_signing_private_key( 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); } diff --git a/litebox_shim_optee/src/loader/ta_stack.rs b/litebox_shim_optee/src/loader/ta_stack.rs index a0057a78b..5e8cb8c30 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 60394b0ea..c9f6c523c 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(()) From 1289e090e0489dbc57a5fe5baf44243ab948668e Mon Sep 17 00:00:00 2001 From: Angelina Vu Date: Mon, 24 Aug 2026 15:49:06 +0000 Subject: [PATCH 3/5] Function and variable renaming Undo changes to fill_bytes_crng interface Set trusted seed through Vtl1Gate to use in LVBS fill_bytes_crng implementation Signed-off-by: Angelina Vu --- litebox/src/fs/devices.rs | 2 +- litebox/src/platform/mock.rs | 2 +- litebox/src/platform/mod.rs | 2 +- litebox_common_lvbs/src/lib.rs | 14 ++++--- .../src/host/snp/snp_impl.rs | 2 +- litebox_platform_linux_userland/src/lib.rs | 2 +- litebox_platform_lvbs/src/host/lvbs_impl.rs | 19 +++++++-- litebox_platform_lvbs/src/host/mod.rs | 2 +- litebox_platform_lvbs/src/mshv/vsm.rs | 18 +++++++- litebox_platform_windows_userland/src/lib.rs | 2 +- litebox_runner_lvbs/src/lib.rs | 21 ++++------ litebox_shim_linux/src/syscalls/misc.rs | 6 +-- litebox_shim_optee/src/idk.rs | 41 +++++-------------- litebox_shim_optee/src/loader/ta_stack.rs | 2 +- litebox_shim_optee/src/syscalls/cryp.rs | 1 - 15 files changed, 68 insertions(+), 68 deletions(-) diff --git a/litebox/src/fs/devices.rs b/litebox/src/fs/devices.rs index ecd817a6e..df24df2da 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, None); + self.litebox.x.platform.fill_bytes_crng(buf); Ok(buf.len()) } } diff --git a/litebox/src/platform/mock.rs b/litebox/src/platform/mock.rs index 4e764814b..5eed9f861 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], _seed: Option<&[u8]>) { + fn fill_bytes_crng(&self, buf: &mut [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 be313cb34..3b354a4db 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], seed: Option<&[u8]>); + fn fill_bytes_crng(&self, buf: &mut [u8]); } /// Provider of derived device-specific keys. diff --git a/litebox_common_lvbs/src/lib.rs b/litebox_common_lvbs/src/lib.rs index 068dedc89..46f4ec4c1 100644 --- a/litebox_common_lvbs/src/lib.rs +++ b/litebox_common_lvbs/src/lib.rs @@ -27,6 +27,9 @@ pub const PAGE_SHIFT: usize = 12; /// Length of the Platform Root Key in bytes. pub const PRK_LEN: usize = 32; +/// Length of the CRNG seed. +pub const CRNG_SEED_LEN: usize = 32; + /// Maximum number of CPU cores addressable through the VTL0 `cpu_online_mask` /// ABI. Bounds how many bits of the mask VTL1 will honor when booting APs. pub const MAX_CORES: usize = 128; @@ -48,9 +51,8 @@ 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 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 exchanging secrets is subject to change +pub const VSM_VTL_CALL_FUNC_ID_EXCHANGE_SECRETS: 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; @@ -74,8 +76,7 @@ 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, - SetPlatformRootKeyAndGenerateIdentitySigningKey = - VSM_VTL_CALL_FUNC_ID_SET_PLATFORM_ROOT_KEY_AND_GENERATE_IDENTITY_SIGNING_KEY, + ExchangeSecrets = VSM_VTL_CALL_FUNC_ID_EXCHANGE_SECRETS, } // `HV_STATUS_*` constants used as discriminants for `HypervCallError`. @@ -968,6 +969,9 @@ pub trait Vtl1Gate { /// Read the platform root key from VTL0 `key_pa` and store it in VTL1 state. fn set_platform_root_key(&self, key_pa: u64) -> Result<(), VsmError>; + /// Read a CRNG seed from VTL0 `trusted_seed_pa` and store it in VTL1. + fn set_crng_seed(&self, trusted_seed_pa: u64) -> Result<(), VsmError>; + /// Close VTL1's window of trusting VTL0, making /// [`Vtl0Gate::end_of_boot_reached`] report `true` from here on. One-way: /// the window never reopens. 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 60ad240e5..cc994a220 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], _seed: Option<&[u8]>) { + fn fill_bytes_crng(&self, buf: &mut [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 859fe4f73..7006a876d 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], _seed: Option<&[u8]>) { + fn fill_bytes_crng(&self, buf: &mut [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 f4eae7521..f7f81999a 100644 --- a/litebox_platform_lvbs/src/host/lvbs_impl.rs +++ b/litebox_platform_lvbs/src/host/lvbs_impl.rs @@ -8,7 +8,7 @@ use crate::{ host::per_cpu_variables::with_per_cpu_variables, }; use digest::Digest; -use litebox_common_lvbs::PRK_LEN; +use litebox_common_lvbs::{CRNG_SEED_LEN, PRK_LEN}; use rand_core::{RngCore, SeedableRng}; use zeroize::Zeroizing; @@ -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], seed: Option<&[u8]>) { + fn fill_bytes_crng(&self, buf: &mut [u8]) { static RANDOM: spin::mutex::SpinMutex> = spin::mutex::SpinMutex::new(None); let mut random = RANDOM.lock(); random .get_or_insert_with(|| { LvbsCrng::new( - seed.expect("CRNG seed not provided"), + CRNG_SEED_ONCE.get().expect("CRNG seed not set"), rdrand_seed().expect("RDRAND unavailable during CRNG initialization"), ) }) @@ -176,6 +176,7 @@ impl LvbsCrng { } static PRK_ONCE: spin::Once<[u8; PRK_LEN]> = spin::Once::new(); +static CRNG_SEED_ONCE: spin::Once<[u8; CRNG_SEED_LEN]> = spin::Once::new(); // Do not expose a raw PRK getter (i.e., no `get_platform_root_key`). // Consumers should provide key derivation function and context @@ -193,6 +194,18 @@ pub(crate) fn set_platform_root_key(key: &[u8; PRK_LEN]) { }); } +/// Sets the trusted CRNG seed for this platform. +/// +/// This should be called once during platform initialization with a seed +/// derived from a hardware root of trust (e.g., a TPM). +pub(crate) fn set_crng_seed(seed: &[u8; CRNG_SEED_LEN]) { + CRNG_SEED_ONCE.call_once(|| { + let mut s = Zeroizing::new([0u8; CRNG_SEED_LEN]); + s.copy_from_slice(seed); + *s + }); +} + impl litebox::platform::DerivedKeyProvider for LvbsLinuxKernel { fn derive_key( &self, diff --git a/litebox_platform_lvbs/src/host/mod.rs b/litebox_platform_lvbs/src/host/mod.rs index 41466f7ff..2e1bdea5b 100644 --- a/litebox_platform_lvbs/src/host/mod.rs +++ b/litebox_platform_lvbs/src/host/mod.rs @@ -8,7 +8,7 @@ pub mod lvbs_impl; pub mod per_cpu_variables; pub use lvbs_impl::LvbsLinuxKernel; -pub(crate) use lvbs_impl::set_platform_root_key; +pub(crate) use lvbs_impl::{set_crng_seed, set_platform_root_key}; #[cfg(test)] pub mod mock; diff --git a/litebox_platform_lvbs/src/mshv/vsm.rs b/litebox_platform_lvbs/src/mshv/vsm.rs index 396413224..976f30da2 100644 --- a/litebox_platform_lvbs/src/mshv/vsm.rs +++ b/litebox_platform_lvbs/src/mshv/vsm.rs @@ -27,8 +27,8 @@ use core::ops::Range; use litebox::utils::TruncateExt; use litebox_common_linux::vmap::PhysPageAddr; use litebox_common_lvbs::{ - FrameTxn, HypervCallError, MemAttr, PAGE_SHIFT, PAGE_SIZE, PRK_LEN, ReservationStatus, - VsmError, Vtl0Gate, Vtl0PrivilegedWrite, Vtl1Gate, + CRNG_SEED_LEN, FrameTxn, HypervCallError, MemAttr, PAGE_SHIFT, PAGE_SIZE, PRK_LEN, + ReservationStatus, VsmError, Vtl0Gate, Vtl0PrivilegedWrite, Vtl1Gate, }; use rangemap::RangeSet; use spin::{Once, rwlock::RwLock as SpinRwLock}; @@ -790,4 +790,18 @@ impl Vtl1Gate for LvbsVtl1Gate { crate::host::set_platform_root_key(&keybuf); Ok(()) } + + fn set_crng_seed(&self, seed_pa: u64) -> Result<(), VsmError> { + if crate::platform_low().end_of_boot_reached() { + return Err(VsmError::OperationAfterEndOfBoot("set crng seed")); + } + + let seed_pa = PhysAddr::try_new(seed_pa).map_err(|_| VsmError::InvalidPhysicalAddress)?; + let mut seed = Zeroizing::new([0u8; CRNG_SEED_LEN]); + LvbsVtl0Gate::mint() + .read_vtl0_contiguous(seed_pa.as_u64(), &mut *seed) + .map_err(|_| VsmError::Vtl0CopyFailed)?; + crate::host::set_crng_seed(&seed); + Ok(()) + } } diff --git a/litebox_platform_windows_userland/src/lib.rs b/litebox_platform_windows_userland/src/lib.rs index c488a75bb..2cc274021 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], _seed: Option<&[u8]>) { + fn fill_bytes_crng(&self, buf: &mut [u8]) { getrandom::fill(buf).expect("getrandom failed"); } } diff --git a/litebox_runner_lvbs/src/lib.rs b/litebox_runner_lvbs/src/lib.rs index 8616a80d5..d338bce57 100644 --- a/litebox_runner_lvbs/src/lib.rs +++ b/litebox_runner_lvbs/src/lib.rs @@ -261,24 +261,16 @@ fn vtlcall_dispatch(params: &[u64; NUM_VTLCALL_PARAMS]) -> i64 { let smc_args_pfn = params[1]; optee_smc_handler_entry(smc_args_pfn) } - VsmFunction::SetPlatformRootKeyAndGenerateIdentitySigningKey => { - let tpm_random_pa = params[1]; + VsmFunction::ExchangeSecrets => { let public_key_pa = params[2]; let key_alg = params[3]; - let return_code = vsm_dispatch( - VsmFunction::SetPlatformRootKeyAndGenerateIdentitySigningKey, - ¶ms[1..2], - ); + let return_code = vsm_dispatch(VsmFunction::ExchangeSecrets, ¶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, - ) + litebox_shim_optee::idk::generate_identity_signing_key(public_key_pa, key_alg) } _ => vsm_dispatch(func_id, ¶ms[1..]), } @@ -329,9 +321,10 @@ fn vsm_dispatch(func_id: VsmFunction, params: &[u64]) -> i64 { VsmFunction::AllocateRingbufferMemory => { heki.allocate_ringbuffer_memory(params[0], params[1]) } - VsmFunction::SetPlatformRootKeyAndGenerateIdentitySigningKey => { - vtl1.set_platform_root_key(params[0]).map(|()| 0) - } + VsmFunction::ExchangeSecrets => vtl1 + .set_platform_root_key(params[0]) + .and_then(|()| vtl1.set_crng_seed(params[0] + PRK_LEN as u64)) + .map(|()| 0), VsmFunction::OpteeMessage => Err(VsmError::OperationNotSupported("OP-TEE communication")), }; match result { diff --git a/litebox_shim_linux/src/syscalls/misc.rs b/litebox_shim_linux/src/syscalls/misc.rs index b1c4a1328..ee546e53e 100644 --- a/litebox_shim_linux/src/syscalls/misc.rs +++ b/litebox_shim_linux/src/syscalls/misc.rs @@ -26,11 +26,7 @@ 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, - None, - ); + <_ as litebox::platform::CrngProvider>::fill_bytes_crng(self.global.platform, kbuf); 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 53cb17c81..282aea63b 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::{NormalWorldConstPtr, NormalWorldMutPtr}; +use crate::NormalWorldMutPtr; use litebox::{mm::linux::PAGE_SIZE, platform::CrngProvider, utils::TruncateExt}; use litebox_common_linux::errno::Errno; use num_enum::TryFromPrimitive; @@ -11,7 +11,6 @@ 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; @@ -41,8 +40,8 @@ enum EcdsaCurve { P521 = 0x03, } -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) { +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) { Ok(res) => res, Err(e) => e.as_neg().into(), } @@ -62,30 +61,16 @@ pub fn generate_identity_signing_key(tpm_random_pa: u64, public_key_pa: u64, key /// 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( - tpm_random_pa: u64, - public_key_pa: u64, - key_alg: u64, -) -> Result { +fn generate_identity_signing_key_inner(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(Some(&tpm_random))?; + let key_pair = get_identity_signing_key_pair()?; pubkey_ptr .write_at_offset(0, key_pair.public_key) .map_err(|_| Errno::EFAULT)?; @@ -115,11 +100,9 @@ fn validate_key_algorithm(key_alg: u64) -> Result<(), Errno> { } } -fn get_identity_signing_key_pair( - tpm_random: Option<&[u8; TPM_IDKS_RANDOM_LEN]>, -) -> Result<&'static IdentitySigningKeyPair, Errno> { +fn get_identity_signing_key_pair() -> Result<&'static IdentitySigningKeyPair, Errno> { IDENTITY_SIGNING_KEY_PAIR.try_call_once(|| { - let private_key = generate_identity_signing_private_key(tpm_random)?; + let private_key = generate_identity_signing_private_key()?; let public_key = identity_signing_public_key_from_private_key(&private_key)?; Ok(IdentitySigningKeyPair { private_key, @@ -128,14 +111,12 @@ fn get_identity_signing_key_pair( }) } -fn generate_identity_signing_private_key( - tpm_random: Option<&[u8; TPM_IDKS_RANDOM_LEN]>, -) -> Result, Errno> { +fn generate_identity_signing_private_key() +-> 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, tpm_random.map(|r| &r[..])); + litebox_platform_multiplex::platform().fill_bytes_crng(&mut *private_key_bytes); if is_valid_identity_signing_private_key(&private_key_bytes) { return Ok(private_key_bytes); } @@ -179,7 +160,7 @@ mod tests { let message = b"IDK_S signing test message"; let _task = init_platform(); - let private_key = generate_identity_signing_private_key(None).unwrap(); + let private_key = generate_identity_signing_private_key().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 5e8cb8c30..a0057a78b 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, None); + ::fill_bytes_crng(platform, &mut canary); 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 c9f6c523c..60394b0ea 100644 --- a/litebox_shim_optee/src/syscalls/cryp.rs +++ b/litebox_shim_optee/src/syscalls/cryp.rs @@ -310,7 +310,6 @@ impl Task { ::fill_bytes_crng( self.global.platform, buf, - None, ); } Ok(()) From 5e2ba4e95f9a980b54938571f0c35a0c4e10aecf Mon Sep 17 00:00:00 2001 From: Angelina Vu Date: Mon, 24 Aug 2026 16:58:35 +0000 Subject: [PATCH 4/5] ratchet Signed-off-by: Angelina Vu --- dev_tests/src/ratchet.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev_tests/src/ratchet.rs b/dev_tests/src/ratchet.rs index b1da9344e..550c88110 100644 --- a/dev_tests/src/ratchet.rs +++ b/dev_tests/src/ratchet.rs @@ -37,7 +37,7 @@ fn ratchet_globals() -> Result<()> { ("litebox/", 9), ("litebox_platform_linux_kernel/", 6), ("litebox_platform_linux_userland/", 5), - ("litebox_platform_lvbs/", 23), + ("litebox_platform_lvbs/", 24), ("litebox_platform_multiplex/", 1), ("litebox_platform_windows_userland/", 8), ("litebox_runner_lvbs/", 6), From 119f345debb5f7ee868d05dde65c2b150976c31e Mon Sep 17 00:00:00 2001 From: Angelina Vu Date: Fri, 28 Aug 2026 06:39:15 +0000 Subject: [PATCH 5/5] minor fixes --- litebox_platform_lvbs/src/host/lvbs_impl.rs | 6 +++--- litebox_runner_lvbs/src/lib.rs | 7 ++++++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/litebox_platform_lvbs/src/host/lvbs_impl.rs b/litebox_platform_lvbs/src/host/lvbs_impl.rs index f7f81999a..ef562f5ff 100644 --- a/litebox_platform_lvbs/src/host/lvbs_impl.rs +++ b/litebox_platform_lvbs/src/host/lvbs_impl.rs @@ -134,9 +134,9 @@ struct LvbsCrng { } impl LvbsCrng { - fn new(seed: &[u8], rdrand_seed: CrngSeed) -> Self { + fn new(seed: &[u8; CRNG_SEED_LEN], rdrand_seed: CrngSeed) -> Self { Self { - random: rand_chacha::ChaCha20Rng::from_seed(crng_seed_from_tpm_and_rdrand( + random: rand_chacha::ChaCha20Rng::from_seed(crng_seed_from_rot_and_rdrand( seed, rdrand_seed, )), @@ -244,7 +244,7 @@ fn rdrand_seed() -> Option { Some(seed) } -fn crng_seed_from_tpm_and_rdrand(seed: &[u8], rdrand_seed: CrngSeed) -> CrngSeed { +fn crng_seed_from_rot_and_rdrand(seed: &[u8; CRNG_SEED_LEN], rdrand_seed: CrngSeed) -> CrngSeed { sha2::Sha256::new() .chain_update(b"litebox-lvbs-crng-seed-v1") .chain_update(seed) diff --git a/litebox_runner_lvbs/src/lib.rs b/litebox_runner_lvbs/src/lib.rs index d338bce57..5d7bf8b76 100644 --- a/litebox_runner_lvbs/src/lib.rs +++ b/litebox_runner_lvbs/src/lib.rs @@ -323,7 +323,12 @@ fn vsm_dispatch(func_id: VsmFunction, params: &[u64]) -> i64 { } VsmFunction::ExchangeSecrets => vtl1 .set_platform_root_key(params[0]) - .and_then(|()| vtl1.set_crng_seed(params[0] + PRK_LEN as u64)) + .and_then(|()| { + params[0] + .checked_add(PRK_LEN as u64) + .ok_or(VsmError::IntegerOverflow) + }) + .and_then(|crng_seed_pa| vtl1.set_crng_seed(crng_seed_pa)) .map(|()| 0), VsmFunction::OpteeMessage => Err(VsmError::OperationNotSupported("OP-TEE communication")), };