Skip to content
Draft
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 litebox/src/fs/devices.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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())
}
}
Expand Down
2 changes: 1 addition & 1 deletion litebox/src/platform/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
2 changes: 1 addition & 1 deletion litebox/src/platform/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
12 changes: 5 additions & 7 deletions litebox_common_lvbs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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`.
Expand Down
2 changes: 1 addition & 1 deletion litebox_platform_linux_kernel/src/host/snp/snp_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<litebox::utils::rng::FastRng> =
spin::mutex::SpinMutex::new(litebox::utils::rng::FastRng::new_from_seed(
Expand Down
2 changes: 1 addition & 1 deletion litebox_platform_linux_userland/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}
}
Expand Down
14 changes: 7 additions & 7 deletions litebox_platform_lvbs/src/host/lvbs_impl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Option<LvbsCrng>> = 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"),
)
})
Expand All @@ -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,
Expand Down Expand Up @@ -231,10 +231,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_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()
Expand Down
2 changes: 1 addition & 1 deletion litebox_platform_windows_userland/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}
}
Expand Down
29 changes: 21 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 @@ -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,
&params[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, &params[1..]),
}
Expand Down Expand Up @@ -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")),
};
Expand Down
6 changes: 5 additions & 1 deletion litebox_shim_linux/src/syscalls/misc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,11 @@ impl<Platform: ShimPlatform, FS: ShimFS> Task<Platform, FS> {
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::<Platform>(offset, kbuf)
.ok_or(Errno::EFAULT)?;
offset += len;
Expand Down
40 changes: 29 additions & 11 deletions litebox_shim_optee/src/idk.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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(),
}
Expand All @@ -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<i64, Errno> {
fn generate_identity_signing_key_inner(
tpm_random_pa: u64,
public_key_pa: u64,
key_alg: u64,
) -> Result<i64, Errno> {
validate_key_algorithm(key_alg)?;

let tpm_random_ptr = NormalWorldConstPtr::<u8, PAGE_SIZE>::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)?;
Expand Down Expand Up @@ -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,
Expand All @@ -111,12 +128,13 @@ fn get_identity_signing_key_pair() -> Result<&'static IdentitySigningKeyPair, Er
})
}

fn generate_identity_signing_private_key()
-> Result<Zeroizing<[u8; IDENTITY_SIGNING_PRIVATE_KEY_LEN]>, Errno> {
fn generate_identity_signing_private_key(
tpm_random: Option<&[u8; TPM_IDKS_RANDOM_LEN]>,
) -> Result<Zeroizing<[u8; IDENTITY_SIGNING_PRIVATE_KEY_LEN]>, 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);
}
Expand Down Expand Up @@ -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();
Expand Down
2 changes: 1 addition & 1 deletion litebox_shim_optee/src/loader/ta_stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -258,7 +258,7 @@ impl TaStack {

// Random 16-byte stack canary
let mut canary = [0u8; 16];
<Platform as litebox::platform::CrngProvider>::fill_bytes_crng(platform, &mut canary);
<Platform as litebox::platform::CrngProvider>::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
Expand Down
1 change: 1 addition & 0 deletions litebox_shim_optee/src/syscalls/cryp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,7 @@ impl Task {
<crate::Platform as litebox::platform::CrngProvider>::fill_bytes_crng(
self.global.platform,
buf,
None,
);
}
Ok(())
Expand Down