mirror of
https://github.com/saymrwulf/xous-core.git
synced 2026-11-08 04:56:43 +00:00
add collateral erasure and checking of IFR copy of pubkeys
The IFR copy of pubkeys is truly actually indelible because of the no-exceptions write inhibit byte. Add code to check against that copy. Note that the IFR region's downside is the presence of the write-inhibit byte means the check is complicated as the full key is striped across two locations, but this code handles that.
This commit is contained in:
parent
24c76b077e
commit
6b7ff11b4e
2 changed files with 53 additions and 2 deletions
|
|
@ -458,7 +458,7 @@ pub fn compare_refkeys(
|
|||
csprng: &mut Csprng,
|
||||
pubkey_ptr: *const bao1x_api::signatures::SignatureInFlash,
|
||||
fail_counter: usize,
|
||||
) {
|
||||
) -> HardenedBool {
|
||||
let reference_keys =
|
||||
[bao1x_api::BAO1_PUBKEY, bao1x_api::BAO2_PUBKEY, bao1x_api::BETA_PUBKEY, bao1x_api::DEV_PUBKEY];
|
||||
// check that the pub keys match those burned into the indelible key area
|
||||
|
|
@ -472,7 +472,22 @@ pub fn compare_refkeys(
|
|||
good_compare = HardenedBool::FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
csprng.random_delay();
|
||||
// The IFR (indelible) copy is weird, because the highest byte doesn't match (it's actually a flag that
|
||||
// indicates the region has to be write protected). Thus, the IFR keys are a set of four, disjointed
|
||||
// 31-byte memory areas, plus a collection of 4 bytes that correspond to the missing MSB.
|
||||
let ifr_keys = [
|
||||
unsafe { core::slice::from_raw_parts(0x6040_01A0 as *const u8, 31) },
|
||||
unsafe { core::slice::from_raw_parts(0x6040_01C0 as *const u8, 31) },
|
||||
unsafe { core::slice::from_raw_parts(0x6040_01E0 as *const u8, 31) },
|
||||
unsafe { core::slice::from_raw_parts(0x6040_0200 as *const u8, 31) },
|
||||
];
|
||||
let ifr_msb = unsafe { core::slice::from_raw_parts(0x6040_0240 as *const u8, 4) };
|
||||
for (i, (boot0_key, ref_key)) in pk_src.sealed_data.pubkeys.iter().zip(ifr_keys).enumerate() {
|
||||
if ref_key != &boot0_key.pk[..31] || ifr_msb[i] != boot0_key.pk[31] {
|
||||
good_compare = HardenedBool::FALSE;
|
||||
}
|
||||
}
|
||||
csprng.random_delay();
|
||||
match good_compare.is_true() {
|
||||
Some(false) => {
|
||||
|
|
@ -493,4 +508,5 @@ pub fn compare_refkeys(
|
|||
None => die(),
|
||||
}
|
||||
bollard!(die, 4);
|
||||
good_compare
|
||||
}
|
||||
|
|
|
|||
|
|
@ -276,6 +276,41 @@ pub fn erase_secrets(_csprng: &mut Option<&mut Csprng>) -> Result<(), String> {
|
|||
);
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
pub fn erase_collateral(csprng: &mut Option<&mut Csprng>) -> Result<(), String> {
|
||||
let slot_mgr = SlotManager::new();
|
||||
let mut rram = crate::rram::Reram::new();
|
||||
|
||||
let slot = &bao1x_api::offsets::COLLATERAL;
|
||||
for data_index in slot.try_into_data_iter().unwrap() {
|
||||
bollard!(die_no_std, 4);
|
||||
csprng.as_deref_mut().map(|rng| rng.random_delay());
|
||||
// only clear ACL if it isn't already cleared
|
||||
if slot_mgr.get_acl(slot).unwrap().raw_u32() != 0 {
|
||||
// clear the ACL so we can operate on the data
|
||||
slot_mgr
|
||||
.set_acl(&mut rram, slot, &AccessSettings::Data(DataSlotAccess::new_with_raw_value(0)))
|
||||
.expect("couldn't reset ACL");
|
||||
}
|
||||
let bytes = unsafe { slot_mgr.read_data_slot(data_index) };
|
||||
// only erase if the key hasn't already been erased, to avoid stressing the RRAM array
|
||||
// erase_secrets() may be called on every boot in some modes.
|
||||
bollard!(die_no_std, 4);
|
||||
if !bytes.iter().all(|&b| b == ERASE_VALUE) {
|
||||
let mut eraser = alloc::vec::Vec::with_capacity(slot.len() * SLOT_ELEMENT_LEN_BYTES);
|
||||
eraser.resize(slot.len() * SLOT_ELEMENT_LEN_BYTES, ERASE_VALUE);
|
||||
|
||||
slot_mgr.write(&mut rram, slot, &eraser).ok();
|
||||
}
|
||||
let check = unsafe { slot_mgr.read_data_slot(data_index) };
|
||||
if !check.iter().all(|&b| b == ERASE_VALUE) {
|
||||
crate::println!("Failed to erase key at {}: {:x?}", data_index, check);
|
||||
}
|
||||
bollard!(die_no_std, 4);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
pub fn erase_secrets(csprng: &mut Option<&mut Csprng>) -> Result<(), String> {
|
||||
// ensure coreuser settings, as we could enter from a variety of loader stages
|
||||
|
|
|
|||
Loading…
Reference in a new issue