diff --git a/bao1x-boot/boot1/src/secboot.rs b/bao1x-boot/boot1/src/secboot.rs index da2e16c65..e8764c741 100644 --- a/bao1x-boot/boot1/src/secboot.rs +++ b/bao1x-boot/boot1/src/secboot.rs @@ -1,14 +1,6 @@ -use bao1x_api::{bollard, signatures::FunctionCode}; +use bao1x_api::{PARANOID_MODE, PARANOID_MODE_DUPE, bollard, pubkeys::BOOT1_TO_LOADER_OR_BAREMETAL}; use bao1x_hal::hardening::Csprng; -pub const ALLOWED_FUNCTIONS: [u32; 5] = [ - FunctionCode::Baremetal as u32, - FunctionCode::UpdatedBaremetal as u32, - FunctionCode::Loader as u32, - FunctionCode::UpdatedLoader as u32, - FunctionCode::Developer as u32, -]; - #[inline(always)] fn seal_boot1_keys() { // This is a security-critical initialization. Failure to do this correctly totally breaks @@ -25,25 +17,26 @@ fn seal_boot1_keys() { } pub fn try_boot(or_die: bool, csprng: &mut Csprng) { + let one_way = bao1x_hal::acram::OneWayCounter::new(); + bollard!(bao1x_hal::sigcheck::die_no_std, 4); + csprng.random_delay(); + let (paranoid1, paranoid2) = one_way.hardened_get2(PARANOID_MODE, PARANOID_MODE_DUPE).unwrap(); + csprng.random_delay(); + // loader is at the same offset as baremetal. Accept either as valid boot. // This diverges if the signature check is successful - match bao1x_hal::sigcheck::validate_image( - bao1x_api::LOADER_START as *const u32, - bao1x_api::BOOT1_START as *const u32, - bao1x_api::BOOT1_REVOCATION_OFFSET, - &ALLOWED_FUNCTIONS, - false, - None, - Some(csprng), - ) { - Ok((k, k2, tag)) => { - crate::println!( - "Booting with key {}/{}({})", - k, - k2, - core::str::from_utf8(&tag).unwrap_or("invalid tag") - ); - if k != k2 { + match bao1x_hal::sigcheck::validate_image(BOOT1_TO_LOADER_OR_BAREMETAL, None, Some(csprng)) { + Ok((key, key_inv, tag, target)) => { + if paranoid1 == 0 && paranoid2 == 0 { + // only emit prints if not in paranoid mode + crate::println!( + "Booting with key {}/{}({})", + key, + !key_inv, + core::str::from_utf8(&tag).unwrap_or("invalid tag") + ); + } + if key != !key_inv { bao1x_hal::sigcheck::die_no_std(); } @@ -53,20 +46,35 @@ pub fn try_boot(or_die: bool, csprng: &mut Csprng) { // the tag is from signed, trusted data // k is just a nominal slot number. If either match, assume we are dealing with a // developer image. + bao1x_hal::sigcheck::hardened_erase_policy(paranoid1, paranoid2, key, key_inv, tag, csprng) + .inspect_err(|e| crate::println!("{}", e)) + .ok(); // "ok" because the expected error is a check on logic/configuration bugs, not attacks + + // this print message is not hardened, and it's actually retrospective of the policy + // implementation if tag == *bao1x_api::pubkeys::KEYSLOT_INITIAL_TAGS[bao1x_api::pubkeys::DEVELOPER_KEY_SLOT] - || k == bao1x_api::pubkeys::DEVELOPER_KEY_SLOT + || key == bao1x_api::pubkeys::DEVELOPER_KEY_SLOT + || !key_inv == bao1x_api::pubkeys::DEVELOPER_KEY_SLOT { crate::println!("Developer key detected, ensuring secrets are erased"); - bao1x_hal::sigcheck::erase_secrets(&mut Some(csprng)); } + + // double up the security check if in paranoid mode + csprng.random_delay(); + if paranoid1 != 0 || paranoid2 != 0 { + bollard!(bao1x_hal::sigcheck::die_no_std, 4); + bao1x_hal::sigcheck::validate_image(BOOT1_TO_LOADER_OR_BAREMETAL, None, Some(csprng)) + .unwrap_or_else(|_| bao1x_hal::hardening::die()); + } + + csprng.random_delay(); + bollard!(bao1x_hal::sigcheck::die_no_std, 4); // this has to be called *after* erase_secrets, because we can't erase the secrets // once the mappings have been sealed off. This is why we can't use the auto-jump method // like we do in boot0. - csprng.random_delay(); - bollard!(bao1x_hal::sigcheck::die_no_std, 4); seal_boot1_keys(); bollard!(bao1x_hal::sigcheck::die_no_std, 4); - bao1x_hal::sigcheck::jump_to(bao1x_api::LOADER_START); + bao1x_hal::sigcheck::jump_to((target ^ u32::from_le_bytes(tag)) as usize); } Err(e) => crate::println!("Image did not validate: {:?}", e), }