add retry flow to restore; fix salt bug

salt was reading from the wrong location on a device that
previously was initialized but doing a restore to.
This commit is contained in:
bunnie 2022-07-19 05:07:22 +08:00
parent 7b3c928429
commit 4ead1010cd
3 changed files with 61 additions and 6 deletions

View file

@ -29,6 +29,12 @@
"zh": "中止恢复!",
"en-tts": "Aborting restore!"
},
"rootkeys.try_again": {
"en": "Try again?",
"ja": "再試行?",
"zh": "再试一次?",
"en-tts": "Try again?"
},
"rootkeys.restore_zero_key": {
"en": "Note: your backup was encrypted with the '0' key. Skipping password entry.\nThis is normal for developers.\n\nUsers should burn BBRAM or eFuse key for secure backups!",
"ja": "注:バックアップは「0」キーで暗号化されています。 パスワード入力をスキップします。\n\n安全なバックアップのためにBBRAMまたはeFuseキーを焼きます!",

View file

@ -173,6 +173,7 @@ pub(crate) struct RootKeys {
xns: xous_names::XousNames,
jtag: jtag::Jtag,
fake_key: [u8; 32], // a base set of random numbers used to respond to invalid keyloc requests in AES operations
restore_running: bool,
}
impl<'a> RootKeys {
@ -267,6 +268,7 @@ impl<'a> RootKeys {
xns,
jtag,
fake_key,
restore_running: false,
};
/*
// dumps the key enclave -- in a format for Renode integration. Or if you just wanted to steal all the keys.
@ -757,7 +759,7 @@ impl<'a> RootKeys {
/// salt from a staging area, and not our KEYROM. However, `setup_key_init` must be called
/// first to ensure that the staging area has a valid salt.
fn get_salt(&mut self) -> [u8; 16] {
if !self.is_initialized() {
if !self.is_initialized() || self.restore_running {
// we're not initialized, use the salt that should already be in the staging area
let mut key: [u8; 16] = [0; 16];
for (word, &keyword) in key.chunks_mut(4).into_iter()
@ -844,6 +846,8 @@ impl<'a> RootKeys {
// stage the plaintext FPGA key into the keyrom area for encryption by the key_init routine.
self.sensitive_data.borrow_mut().as_slice_mut::<u8>()[KeyRomLocs::FPGA_KEY as usize..KeyRomLocs::FPGA_KEY as usize + 32]
.copy_from_slice(&key.0);
self.restore_running = true;
}
/// used to recycle a PDDB after a key init event
@ -2437,6 +2441,8 @@ impl<'a> RootKeys {
// now purge the keyrom copy and other temporaries
self.purge_sensitive_data();
// reset this flag to false in case this was called at the end of a restore op; harmless if it's already false.
self.restore_running = false;
// re-allow suspend/resume ops
self.susres.set_suspendable(true).expect("couldn't re-allow suspend/resume");

View file

@ -1533,11 +1533,11 @@ fn main() -> ! {
rootkeys_modal.key_event(['🛑', '\u{0000}', '\u{0000}', '\u{0000}']);
log::info!("set_ux_password result: {:?}", result);
// clear all the state, re-enable suspend/resume
keys.finish_key_init();
match result {
Ok(_) => {
// clear all the state, re-enable suspend/resume
keys.finish_key_init();
let (mut header, ct) = keys.read_backup()
.expect("Internal error: we're doing a backup, but somehow the backup record has disappeared on us!");
if u64::from_le_bytes(header.dna) == llio.soc_dna().unwrap() {
@ -1557,6 +1557,9 @@ fn main() -> ! {
// don't unblock the caller if we go to the reboot arc
}
Err(RootkeyResult::AlignmentError) => {
// clear all the state, re-enable suspend/resume
keys.finish_key_init();
modals.show_notification(t!("rootkeys.init.fail_alignment", xous::LANG), None).expect("modals error");
if let Some(sender) = deferred_response {
xous::return_scalar(sender, 1).ok();
@ -1564,23 +1567,63 @@ fn main() -> ! {
}
Err(RootkeyResult::KeyError) => {
modals.show_notification(t!("rootkeys.init.fail_key", xous::LANG), None).expect("modals error");
if let Some(sender) = deferred_response {
xous::return_scalar(sender, 1).ok();
modals.add_list_item(t!("rootkeys.gwup.yes", xous::LANG)).expect("modals error");
modals.add_list_item(t!("rootkeys.gwup.no", xous::LANG)).expect("modals error");
match modals.get_radiobutton(t!("rootkeys.try_again", xous::LANG)) {
Ok(response) => {
if response == t!("rootkeys.gwup.no", xous::LANG) {
// clear all the state, re-enable suspend/resume
keys.finish_key_init();
if let Some(dr) = deferred_response.take() {
xous::return_scalar(dr, 1).unwrap();
}
continue;
} else if response == t!("rootkeys.gwup.yes", xous::LANG) {
// get the update password, so we can encrypt the FPGA key to it.
keys.set_ux_password_type(Some(PasswordType::Update));
password_action.set_action_opcode(Opcode::UxDoRestorePwReturn.to_u32().unwrap());
rootkeys_modal.modify(
Some(ActionType::TextEntry(password_action.clone())),
Some(t!("rootkeys.get_update_password_restore", xous::LANG)), false,
None, true, None
);
#[cfg(feature="tts")]
tts.tts_blocking(t!("rootkeys.get_update_password_restore", xous::LANG)).unwrap();
log::info!("{}ROOTKEY.UPDPW,{}", xous::BOOKEND_START, xous::BOOKEND_END);
rootkeys_modal.activate();
} else {
// clear all the state, re-enable suspend/resume
keys.finish_key_init();
log::error!("get_radiobutton had an unexpected response: {:?}", response);
}
}
_ => log::error!("get_radiobutton failed"),
}
}
Err(RootkeyResult::IntegrityError) => {
// clear all the state, re-enable suspend/resume
keys.finish_key_init();
modals.show_notification(t!("rootkeys.init.fail_verify", xous::LANG), None).expect("modals error");
if let Some(sender) = deferred_response {
xous::return_scalar(sender, 1).ok();
}
}
Err(RootkeyResult::FlashError) => {
// clear all the state, re-enable suspend/resume
keys.finish_key_init();
modals.show_notification(t!("rootkeys.init.fail_burn", xous::LANG), None).expect("modals error");
if let Some(sender) = deferred_response {
xous::return_scalar(sender, 1).ok();
}
}
Err(RootkeyResult::StateError) => {
// clear all the state, re-enable suspend/resume
keys.finish_key_init();
modals.show_notification(t!("rootkeys.wrong_state", xous::LANG), None).expect("modals error");
if let Some(sender) = deferred_response {
xous::return_scalar(sender, 1).ok();