Skip to content

Commit

Permalink
improved glitch resistance for starting post boot
Browse files Browse the repository at this point in the history
  • Loading branch information
Athryx committed Mar 6, 2024
1 parent 5d27e54 commit ebd0682
Show file tree
Hide file tree
Showing 4 changed files with 130 additions and 91 deletions.
120 changes: 47 additions & 73 deletions application_processor/src/boot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ use crate::ectf_params::{
COMPONENT_KEYS
};
use crate::ap_driver::ApDriver;
use crate::post_boot;

const COMPONENT_COUNT: usize = 2;

Expand All @@ -45,37 +46,13 @@ impl ComponentBootState {
}
}

#[inline(always)]
fn boot_send_m1(driver: &mut ApDriver, state: &mut [ComponentBootState; COMPONENT_COUNT]) -> Result<(), ApError> {
for component in state {
// send enc(m1 || cid || ra)
let ap_nonce = driver.gen_nonce();
let message = BootMessageStart {
m: MessageStage::M1,
component_id: component.component_id,
nonce: ap_nonce,
};

let req = StartProtocolMessage::Boot(
EncryptedMessage::new_encrypted(message, &BOOT_CR_KEY, driver.gen_bytes())?,
);

driver.send_struct(component.i2c_addr(), req)?;

// TODO: determine when this should be true, this might not be true if component answers with error
component.protocol_in_progress = true;

component.expected_reply_nonce = ap_nonce + 1;
}

Ok(())
}

// sends final message telling components to boot
fn boot_send_m3(
driver: &mut ApDriver,
fn send_m3_and_boot(
driver_option: &mut Option<ApDriver>,
state: &mut [ComponentBootState; COMPONENT_COUNT],
) -> Result<(), ApError> {
let driver = driver_option.as_mut().unwrap();

for component in state {
// send enc(m3 || cid || rb + 1 || signature)
let message = BootMessageFinalize {
Expand All @@ -87,31 +64,53 @@ fn boot_send_m3(
let signed_message = SignedMessage::new_signed(message, &AP_PRIVKEY)?;
let enc_message = EncryptedMessage::new_encrypted(signed_message, &BOOT_CR_KEY, driver.gen_bytes())?;

driver.send_struct(component.i2c_addr(), enc_message)?;
let mut encrypted_boot_message: EncryptedData<MAX_I2C_MESSAGE_LEN> = driver.send_and_receive_struct(component.i2c_addr(), enc_message)?;
// recieved encrypted boot message
component.protocol_in_progress = false;

let boot_message = decrypt(&mut encrypted_boot_message, &BOOT_DATA_ENC_KEY)?;
let boot_message = str::from_utf8(boot_message.as_slice())?;

// Print boot message from component
// TODO: maybe only print these messages after both components have sent them back
uprintln_info!("0x{:x}>{}", component.component_id, boot_message);
}

Ok(())
uprintln_info!("AP>{}", AP_BOOT_MSG);

post_boot::boot(driver_option.take().unwrap());
}

#[inline(always)]
fn boot_recv_m2_send_m3(
driver: &mut ApDriver,
state: &mut [ComponentBootState; COMPONENT_COUNT]
) -> Result<(), ApError> {
fn boot_components(driver_option: &mut Option<ApDriver>, state: &mut [ComponentBootState; COMPONENT_COUNT]) -> Result<(), ApError> {
let driver = driver_option.as_mut().unwrap();

// verify components by sending m1 and verifiying their m2 response
for component in state.iter_mut() {
let mut enc_response: EncryptedMessage<SignedMessage<BootMessageComponentReply>> = driver.receive_struct(component.i2c_addr())?;
// send enc(m1 || cid || ra)
let ap_nonce = driver.gen_nonce();
let message = BootMessageStart {
m: MessageStage::M1,
component_id: component.component_id,
nonce: ap_nonce,
};

let req = StartProtocolMessage::Boot(
EncryptedMessage::new_encrypted(message, &BOOT_CR_KEY, driver.gen_bytes())?,
);

let mut enc_response: EncryptedMessage<SignedMessage<BootMessageComponentReply>> =
driver.send_and_receive_struct(component.i2c_addr(), req)?;
component.protocol_in_progress = true;

// received enc(m2 || cid || bid || ra + 1 || rb || signature)
let signed_response = enc_response.get_decrypted_data(&BOOT_CR_KEY)?;

let response: BootMessageComponentReply = postcard::from_bytes(&signed_response.message_data)?;

// glitch protect these checks
multi_if!(
response.m == MessageStage::M2
&& response.component_id == component.component_id
&& response.start_nonce_plus_one == component.expected_reply_nonce,
&& response.start_nonce_plus_one == ap_nonce + 1,
(),
{ return Err(ApError::SuspiciousActivity) },
driver.get_chacha(),
Expand All @@ -130,47 +129,21 @@ fn boot_recv_m2_send_m3(
component.expected_reply_nonce = response.reply_nonce + 1;
}

// verify components are using different build ids
// verify components are using different build ids then tell components to boot and boot
check_or_error_jump_table!(
state[0].key_index != state[1].key_index,
fn(&mut ApDriver, &mut [ComponentBootState; COMPONENT_COUNT]) -> Result<(), ApError>,
boot_send_m3,
(driver, state),
fn(&mut Option<ApDriver>, &mut [ComponentBootState; COMPONENT_COUNT]) -> Result<(), ApError>,
send_m3_and_boot,
(driver_option, state),
Err(ApError::SuspiciousActivity),
driver.get_chacha(),
)
}

#[inline(always)]
fn boot_recv_messages(driver: &mut ApDriver, state: &mut [ComponentBootState; COMPONENT_COUNT]) -> Result<(), ApError> {
for component in state {
let mut encrypted_boot_message: EncryptedData<MAX_I2C_MESSAGE_LEN> = driver.receive_struct(component.i2c_addr())?;

let boot_message = decrypt(&mut encrypted_boot_message, &BOOT_DATA_ENC_KEY)?;
let boot_message = str::from_utf8(boot_message.as_slice())?;

// Print boot message from component
// TODO: maybe only print these messages after both components have sent them back
uprintln_info!("0x{:x}>{}", component.component_id, boot_message);
}

Ok(())
}

fn boot_components(driver: &mut ApDriver, state: &mut [ComponentBootState; COMPONENT_COUNT]) -> Result<(), ApError> {
boot_send_m1(driver, state)?;
boot_recv_m2_send_m3(driver, state)?;
boot_recv_messages(driver, state)?;

// Print boot message
// This always needs to be printed when booting
uprintln_info!("AP>{}", AP_BOOT_MSG);

Ok(())
}

// Boot the components and board if the components validate
pub fn attempt_boot(driver: &mut ApDriver) -> Result<(), ApError> {
pub fn attempt_boot(driver_option: &mut Option<ApDriver>) -> Result<(), ApError> {
let driver = driver_option.as_mut().unwrap();

let mut flash_data = driver.get_flash_data();
if flash_data.components_len != COMPONENT_COUNT {
// not enough components to boot
Expand All @@ -185,13 +158,14 @@ pub fn attempt_boot(driver: &mut ApDriver) -> Result<(), ApError> {
// make sure we are booting with distinct component ids (with glitch hardened check)
let result = check_or_error_jump_table!(
boot_state[0].component_id != boot_state[1].component_id,
fn(&mut ApDriver, &mut [ComponentBootState; COMPONENT_COUNT]) -> Result<(), ApError>,
fn(&mut Option<ApDriver>, &mut [ComponentBootState; COMPONENT_COUNT]) -> Result<(), ApError>,
boot_components,
(driver, &mut boot_state),
(driver_option, &mut boot_state),
Err(ApError::SuspiciousActivity),
driver.get_chacha(),
);

let driver = driver_option.as_mut().unwrap();
if let Err(err) = result {
// send error message to components which were still expecting a message
for component in boot_state {
Expand Down
13 changes: 5 additions & 8 deletions application_processor/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ fn main() -> ! {
}

let mut driver = ApDriver::new();

driver.sleep(Duration::from_secs(1));
let mut driver = Some(driver);

uprintln_info!("Application Processor Started");

Expand All @@ -84,13 +84,10 @@ fn main() -> ! {
uprintln_debug!("running command: {command}");

let result = match command {
"list" => list::scan_components(&mut driver),
"attest" => attest::attest(&mut driver),
"replace" => replace::replace(&mut driver),
"boot" => match boot::attempt_boot(&mut driver) {
Ok(()) => post_boot::boot(driver),
Err(err) => Err(err),
},
"list" => list::scan_components(driver.as_mut().unwrap()),
"attest" => attest::attest(driver.as_mut().unwrap()),
"replace" => replace::replace(driver.as_mut().unwrap()),
"boot" => boot::attempt_boot(&mut driver),
&_ => Err(ApError::InvalidCommand),
};

Expand Down
21 changes: 11 additions & 10 deletions component/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,29 +60,28 @@ fn main() -> ! {
}

let mut driver = ComponentDriver::new();

driver.sleep(Duration::from_secs(1));
let mut driver = Some(driver);

uprint_info!("Component Started");

led_on(Led::Green);

loop {
let Ok(command) = driver.recv_struct() else {
let Ok(command) = driver.as_mut().unwrap().recv_struct() else {
uprintln_error!("invalid command received");
continue;
};

let result = match command {
StartProtocolMessage::ScanId => process_scan(&mut driver),
StartProtocolMessage::Attest => process_attest(&mut driver),
StartProtocolMessage::Boot(mut boot_data) => match process_boot(&mut driver, &mut boot_data) {
Ok(()) => post_boot::boot(driver),
Err(err) => Err(err),
},
StartProtocolMessage::ScanId => process_scan(driver.as_mut().unwrap()),
StartProtocolMessage::Attest => process_attest(driver.as_mut().unwrap()),
StartProtocolMessage::Boot(mut boot_data) => process_boot(&mut driver, &mut boot_data),
};

if let Err(error) = result {
let driver = driver.as_mut().unwrap();

// FIXME: figure out how to handle this error
// i2c state will be all messed up if this fails
// FIXME: not all errors require sending component an error
Expand Down Expand Up @@ -142,9 +141,11 @@ fn process_attest(driver: &mut ComponentDriver) -> Result<(), ComponentError> {
}

fn process_boot(
driver: &mut ComponentDriver,
driver_option: &mut Option<ComponentDriver>,
encrypted_message: &mut EncryptedMessage<BootMessageStart>
) -> Result<(), ComponentError> {
let driver = driver_option.as_mut().unwrap();

// received enc(m1 || cid || ra)
let message = encrypted_message.get_decrypted_data(&BOOT_CR_KEY)?;

Expand Down Expand Up @@ -186,5 +187,5 @@ fn process_boot(
// reply with encrypted boot message
driver.send_struct(encrypted_boot_message())?;

Ok(())
post_boot::boot(driver_option.take().unwrap());
}
67 changes: 67 additions & 0 deletions design_macros/Cargo.lock

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

0 comments on commit ebd0682

Please sign in to comment.