Skip to content

Commit

Permalink
emu: Hide hmac output from cpu with input from key-vault.
Browse files Browse the repository at this point in the history
This was changed in the RTL in
chipsalliance/caliptra-rtl@6563a0a,
which broke several driver tests when running under verilator.

This commit changes the emulator and the driver tests to match the new
RTL behavior, and the tests now pass on both the emulated and verilated
models.
  • Loading branch information
korran committed Sep 7, 2023
1 parent f14b7a0 commit 8d25ef3
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 42 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 4 additions & 12 deletions drivers/test-fw/src/bin/hmac384_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,12 +292,9 @@ fn test_hmac5() {
0x20, 0x66, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x3f,
];

let result: [u8; 48] = [
0x7e, 0x97, 0xa1, 0xb8, 0x23, 0x87, 0x43, 0x50, 0x9d, 0x5, 0xb9, 0x38, 0x91, 0x27, 0xc3,
0x8d, 0x57, 0xf2, 0xf2, 0x18, 0x48, 0x35, 0x16, 0x49, 0xf5, 0xbe, 0xbc, 0x7e, 0x3c, 0x59,
0x13, 0xaa, 0xdf, 0x5, 0xce, 0x52, 0x7b, 0x89, 0xb7, 0xd6, 0xb, 0xcf, 0x8a, 0x14, 0xe4,
0xbc, 0x31, 0x23,
];
// The hardware no longer reveals HMAC results to the CPU that use data from
// the key-vault, returning all zeroes instead
let result = [0u8; 48];

// Take the Data Generate the Tag in buffer
let mut out_tag = Array4x12::default();
Expand All @@ -310,12 +307,7 @@ fn test_hmac5() {
assert!(actual.is_ok());
assert_eq!(out_tag, Array4x12::from(result));

let step_1_result_expected: [u8; 48] = [
0x88, 0xe8, 0x47, 0xe, 0x8, 0x10, 0xc2, 0xf6, 0x7d, 0x56, 0x66, 0x37, 0x43, 0x14, 0x9c,
0x65, 0xe, 0x4c, 0x0, 0x3e, 0xd9, 0x97, 0x98, 0x49, 0xbb, 0x53, 0x2, 0xd7, 0xce, 0x5e,
0xf3, 0x62, 0xc2, 0xa3, 0xb8, 0x26, 0xcb, 0xee, 0xbf, 0x97, 0x32, 0xca, 0x62, 0xa, 0x9d,
0xe4, 0x6b, 0xe3,
];
let step_1_result_expected: [u8; 48] = [0u8; 48];

// Generate the HMAC of the Tag in to a hmac_step_1
let mut hmac_step_1 = Array4x12::default();
Expand Down
32 changes: 27 additions & 5 deletions drivers/tests/integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,11 +188,21 @@ fn test_doe_when_debug_not_locked() {
.unwrap();

let txn = model.wait_for_mailbox_receive().unwrap();

// The hardware no longer reveals HMAC results to the CPU that use data from
// the key-vault, replacing them with zeroes. Used to be
// DOE_TEST_VECTORS_DEBUG_MODE.expected_test_results
// TODO: Do an ECDSA keygen operation instead to ensure the key-vault
// contents are as expected
let expected_test_results = DoeTestResults {
hmac_uds_as_key: [0u32; 12],
hmac_uds_as_data: [0u32; 12],
hmac_field_entropy_as_key: [0u32; 12],
hmac_field_entropy_as_data: [0u32; 12],
};

let test_results = DoeTestResults::read_from(txn.req.data.as_slice()).unwrap();
assert_eq!(
test_results,
DOE_TEST_VECTORS_DEBUG_MODE.expected_test_results
)
assert_eq!(test_results, expected_test_results)
}

const DOE_TEST_VECTORS: DoeTestVectors = DoeTestVectors {
Expand Down Expand Up @@ -260,7 +270,19 @@ fn test_doe_when_debug_locked() {

let txn = model.wait_for_mailbox_receive().unwrap();
let test_results = DoeTestResults::read_from(txn.req.data.as_slice()).unwrap();
assert_eq!(test_results, DOE_TEST_VECTORS.expected_test_results)

// The hardware no longer reveals HMAC results that use data from the
// key-vault, replacing them with zeroes. Used to be DOE_TEST_VECTORS.expected_test_results
// TODO: Do an ECDSA keygen operation instead to ensure the key-vault
// contents are as expected
let expected_test_results = DoeTestResults {
hmac_uds_as_key: [0u32; 12],
hmac_uds_as_data: [0u32; 12],
hmac_field_entropy_as_key: [0u32; 12],
hmac_field_entropy_as_data: [0u32; 12],
};

assert_eq!(test_results, expected_test_results);
}

#[test]
Expand Down
1 change: 1 addition & 0 deletions sw-emulator/lib/periph/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ lazy_static.workspace = true
sha3.workspace = true
smlang.workspace = true
tock-registers.workspace = true
zerocopy.workspace = true
1 change: 1 addition & 0 deletions sw-emulator/lib/periph/src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ u32_array_impl!(13);
u32_array_impl!(14);
u32_array_impl!(15);
u32_array_impl!(16);
u32_array_impl!(32);

pub fn words_from_bytes_le<A: U32ArrayBytes>(arr: &A) -> A::WordArray {
let mut result = A::WordArray::default();
Expand Down
112 changes: 87 additions & 25 deletions sw-emulator/lib/periph/src/hmac_sha384.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,17 @@ Abstract:
--*/

use crate::helpers::bytes_from_words_le;
use crate::{KeyUsage, KeyVault};
use caliptra_emu_bus::{
ActionHandle, BusError, Clock, ReadOnlyMemory, ReadOnlyRegister, ReadWriteMemory,
ReadWriteRegister, Timer, WriteOnlyMemory,
};
use caliptra_emu_bus::{ActionHandle, BusError, Clock, ReadOnlyRegister, ReadWriteRegister, Timer};
use caliptra_emu_crypto::EndianessTransform;
use caliptra_emu_crypto::{Hmac512, Hmac512Mode};
use caliptra_emu_derive::Bus;
use caliptra_emu_types::{RvData, RvSize};
use tock_registers::interfaces::{ReadWriteable, Readable, Writeable};
use tock_registers::register_bitfields;
use tock_registers::registers::InMemoryRegister;
use zerocopy::AsBytes;

register_bitfields! [
u32,
Expand Down Expand Up @@ -137,16 +136,16 @@ pub struct HmacSha384 {
status: ReadOnlyRegister<u32, Status::Register>,

/// HMAC Key Register
#[peripheral(offset = 0x0000_0040, mask = 0x0000_003f)]
key: WriteOnlyMemory<HMAC_KEY_SIZE>,
#[register_array(offset = 0x0000_0040, item_size = 4, len = 12, read_fn = read_access_fault, write_fn = on_write_key)]
key: [u32; HMAC_KEY_SIZE / 4],

/// HMAC Block Register
#[peripheral(offset = 0x0000_0080, mask = 0x0000_007f)]
block: ReadWriteMemory<HMAC_BLOCK_SIZE>,
#[register_array(offset = 0x0000_0080, item_size = 4, len = 32, read_fn = read_access_fault, write_fn = on_write_block)]
block: [u32; HMAC_BLOCK_SIZE / 4],

/// HMAC Tag Register
#[peripheral(offset = 0x0000_0100, mask = 0x0000_00ff)]
tag: ReadOnlyMemory<HMAC_TAG_SIZE>,
#[register_array(offset = 0x0000_0100, item_size = 4, len = 12, read_fn = on_read_tag, write_fn = write_access_fault)]
tag: [u32; HMAC_TAG_SIZE / 4],

/// LSFR Seed Register
#[register_array(offset = 0x0000_0130)]
Expand Down Expand Up @@ -176,6 +175,15 @@ pub struct HmacSha384 {
#[register(offset = 0x0000_0614)]
tag_write_status: ReadOnlyRegister<u32, TagWriteStatus::Register>,

// True if the current key was read from the key-vault
key_from_kv: bool,

// True if the current block was read from the key-vault
block_from_kv: bool,

// True if the tag should be hidden from the CPU
hide_tag_from_cpu: bool,

/// HMAC engine
hmac: Hmac512<HMAC_KEY_SIZE>,

Expand Down Expand Up @@ -230,9 +238,9 @@ impl HmacSha384 {
version1: ReadOnlyRegister::new(Self::VERSION1_VAL),
control: ReadWriteRegister::new(0),
status: ReadOnlyRegister::new(Status::READY::SET.value),
key: WriteOnlyMemory::new(),
block: ReadWriteMemory::new(),
tag: ReadOnlyMemory::new(),
key: Default::default(),
block: Default::default(),
tag: Default::default(),
lfsr_seed: Default::default(),
key_read_ctrl: ReadWriteRegister::new(0),
key_read_status: ReadOnlyRegister::new(KeyReadStatus::READY::SET.value),
Expand All @@ -242,13 +250,54 @@ impl HmacSha384 {
tag_write_status: ReadOnlyRegister::new(TagWriteStatus::READY::SET.value),
key_vault,
timer: Timer::new(clock),
key_from_kv: false,
block_from_kv: false,
hide_tag_from_cpu: false,
op_complete_action: None,
op_key_read_complete_action: None,
op_block_read_complete_action: None,
op_tag_write_complete_action: None,
}
}

fn read_access_fault(&mut self, _size: RvSize, _index: usize) -> Result<u32, BusError> {
Err(BusError::LoadAccessFault)
}

fn write_access_fault(
&mut self,
_size: RvSize,
_index: usize,
_val: RvData,
) -> Result<(), BusError> {
Err(BusError::StoreAccessFault)
}

fn on_write_key(&mut self, _size: RvSize, index: usize, val: RvData) -> Result<(), BusError> {
if self.key_from_kv {
self.key_from_kv = false;
self.key.fill(0);
}
self.key[index] = val;
Ok(())
}

fn on_write_block(&mut self, _size: RvSize, index: usize, val: RvData) -> Result<(), BusError> {
if self.block_from_kv {
self.block_from_kv = false;
self.block.fill(0);
}
self.block[index] = val;
Ok(())
}

fn on_read_tag(&mut self, _size: RvSize, index: usize) -> Result<RvData, BusError> {
if self.hide_tag_from_cpu {
return Ok(0);
}
Ok(self.tag[index])
}

/// On Write callback for `control` register
///
/// # Arguments
Expand Down Expand Up @@ -276,13 +325,16 @@ impl HmacSha384 {

if self.control.reg.is_set(Control::INIT) {
// Initialize the HMAC engine with key and initial data block
self.hmac.init(self.key.data(), self.block.data());
self.hmac.init(
&bytes_from_words_le(&self.key),
&bytes_from_words_le(&self.block),
);

// Schedule a future call to poll() complete the operation.
self.op_complete_action = Some(self.timer.schedule_poll_in(INIT_TICKS));
} else if self.control.reg.is_set(Control::NEXT) {
// Update a HMAC engine with a new block
self.hmac.update(self.block.data());
self.hmac.update(&bytes_from_words_le(&self.block));

// Schedule a future call to poll() complete the operation.
self.op_complete_action = Some(self.timer.schedule_poll_in(UPDATE_TICKS));
Expand Down Expand Up @@ -432,7 +484,10 @@ impl HmacSha384 {

fn op_complete(&mut self) {
// Retrieve the tag
self.hmac.tag(self.tag.data_mut());
self.hmac.tag(self.tag.as_bytes_mut());
// Don't reveal the tag to the CPU if the inputs came from the
// key-vault.
self.hide_tag_from_cpu = self.block_from_kv || self.key_from_kv;

// Check if tag control is enabled.
if self
Expand Down Expand Up @@ -476,7 +531,10 @@ impl HmacSha384 {
};

if let Some(key) = &key {
self.key.data_mut().copy_from_slice(&key[..HMAC_KEY_SIZE]);
self.key_from_kv = true;
self.key
.as_bytes_mut()
.copy_from_slice(&key[..HMAC_KEY_SIZE]);
}

self.key_read_status.reg.modify(
Expand All @@ -490,7 +548,7 @@ impl HmacSha384 {
let key_id = self.block_read_ctrl.reg.read(KeyReadControl::KEY_ID);

// Clear the block
self.block.data_mut().fill(0);
self.block.fill(0);

let mut key_usage = KeyUsage::default();
key_usage.set_hmac_data(true);
Expand All @@ -504,6 +562,7 @@ impl HmacSha384 {
}
Ok(data) => {
self.format_block(&data);
self.block_from_kv = true;
KeyReadStatus::ERROR::KV_SUCCESS.value
}
};
Expand Down Expand Up @@ -539,7 +598,7 @@ impl HmacSha384 {
block_arr[HMAC_BLOCK_SIZE - 16..].copy_from_slice(&len.to_be_bytes());

block_arr.to_big_endian();
self.block.data_mut().copy_from_slice(&block_arr);
self.block.as_bytes_mut().copy_from_slice(&block_arr);
}

fn tag_write_complete(&mut self) {
Expand All @@ -551,7 +610,7 @@ impl HmacSha384 {
.key_vault
.write_key(
key_id,
self.tag.data(),
self.tag.as_bytes(),
self.tag_write_ctrl.reg.read(TagWriteControl::USAGE),
)
.err()
Expand All @@ -573,9 +632,9 @@ impl HmacSha384 {
}

fn zeroize(&mut self) {
self.key.data_mut().fill(0);
self.block.data_mut().fill(0);
self.tag.data_mut().fill(0);
self.key.fill(0);
self.block.fill(0);
self.tag.fill(0);
}
}

Expand Down Expand Up @@ -660,7 +719,10 @@ mod tests {
let mut hmac = HmacSha384::new(&Clock::new(), KeyVault::new());
for addr in (OFFSET_BLOCK..(OFFSET_BLOCK + HMAC_BLOCK_SIZE as u32)).step_by(4) {
assert_eq!(hmac.write(RvSize::Word, addr, u32::MAX).ok(), Some(()));
assert_eq!(hmac.read(RvSize::Word, addr).ok(), Some(u32::MAX));
assert_eq!(
hmac.read(RvSize::Word, addr),
Err(BusError::LoadAccessFault)
);
}
}

Expand Down Expand Up @@ -1020,7 +1082,7 @@ mod tests {
&hmac.key_vault.read_key(tag_id, key_usage).unwrap()[..HMAC_TAG_SIZE],
);
} else {
tag_le.clone_from_slice(hmac.tag.data());
tag_le.clone_from_slice(hmac.tag.as_bytes());
}

tag_le.to_little_endian();
Expand Down

0 comments on commit 8d25ef3

Please sign in to comment.