Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion dev_tests/src/ratchet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
16 changes: 9 additions & 7 deletions litebox_common_lvbs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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`.
Expand Down Expand Up @@ -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.
Expand Down
27 changes: 20 additions & 7 deletions litebox_platform_lvbs/src/host/lvbs_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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"),
)
})
Expand All @@ -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,
Expand Down Expand Up @@ -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
Expand All @@ -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<E>(
&self,
Expand Down Expand Up @@ -231,10 +244,10 @@ fn rdrand_seed() -> Option<CrngSeed> {
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()
Expand Down
2 changes: 1 addition & 1 deletion litebox_platform_lvbs/src/host/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
18 changes: 16 additions & 2 deletions litebox_platform_lvbs/src/mshv/vsm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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(())
}
}
27 changes: 19 additions & 8 deletions litebox_runner_lvbs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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, &params[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, &params[1..]),
Expand Down Expand Up @@ -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 {
Expand Down