diff --git a/services/root-keys/locales/i18n.json b/services/root-keys/locales/i18n.json index f265ceeec..8bdd630c9 100644 --- a/services/root-keys/locales/i18n.json +++ b/services/root-keys/locales/i18n.json @@ -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キーを焼きます!", diff --git a/services/root-keys/src/implementation.rs b/services/root-keys/src/implementation.rs index b35ea2116..25b1b1136 100644 --- a/services/root-keys/src/implementation.rs +++ b/services/root-keys/src/implementation.rs @@ -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::()[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"); diff --git a/services/root-keys/src/main.rs b/services/root-keys/src/main.rs index 9be0340f2..631462d9a 100644 --- a/services/root-keys/src/main.rs +++ b/services/root-keys/src/main.rs @@ -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();