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), diff --git a/litebox_common_lvbs/src/lib.rs b/litebox_common_lvbs/src/lib.rs index 916cd7f33..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,11 +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 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 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; @@ -76,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, - SetPlatformRootKey = VSM_VTL_CALL_FUNC_ID_SET_PLATFORM_ROOT_KEY, - GenerateIdentitySigningKey = VSM_VTL_CALL_FUNC_ID_GENERATE_IDENTITY_SIGNING_KEY, + ExchangeSecrets = VSM_VTL_CALL_FUNC_ID_EXCHANGE_SECRETS, } // `HV_STATUS_*` constants used as discriminants for `HypervCallError`. @@ -970,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_lvbs/src/host/lvbs_impl.rs b/litebox_platform_lvbs/src/host/lvbs_impl.rs index d77c792fd..ef562f5ff 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; @@ -112,7 +112,7 @@ impl litebox::platform::CrngProvider for LvbsLinuxKernel { random .get_or_insert_with(|| { LvbsCrng::new( - PRK_ONCE.get().expect("Platform root key not initialized"), + CRNG_SEED_ONCE.get().expect("CRNG seed not set"), 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; CRNG_SEED_LEN], 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_rot_and_rdrand( + seed, rdrand_seed, )), bytes_until_reseed: CRNG_RESEED_INTERVAL_BYTES, @@ -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, @@ -231,10 +244,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_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(prk) + .chain_update(seed) .chain_update(rdrand_seed) .finalize() .into() 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_runner_lvbs/src/lib.rs b/litebox_runner_lvbs/src/lib.rs index 7a0635551..5d7bf8b76 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,9 +261,15 @@ 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]; + VsmFunction::ExchangeSecrets => { + let public_key_pa = params[2]; + let key_alg = params[3]; + + 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(public_key_pa, key_alg) } _ => vsm_dispatch(func_id, ¶ms[1..]), @@ -315,10 +321,15 @@ 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::ExchangeSecrets => vtl1 + .set_platform_root_key(params[0]) + .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")), }; match result {