From ead5bd7dac688c84fdfdf91bf85ce7f3dc5cccd4 Mon Sep 17 00:00:00 2001 From: bunnie Date: Thu, 30 Jun 2022 22:58:54 +0800 Subject: [PATCH] enable gateware updates when no root keys are present --- services/root-keys/locales/i18n.json | 12 +++++ services/root-keys/src/api.rs | 6 +++ services/root-keys/src/implementation.rs | 26 +++++++++++ services/root-keys/src/lib.rs | 3 ++ services/root-keys/src/main.rs | 59 ++++++++++++++++++++++++ services/status/src/mainmenu.rs | 9 ++++ 6 files changed, 115 insertions(+) diff --git a/services/root-keys/locales/i18n.json b/services/root-keys/locales/i18n.json index e778effa6..afbc63f24 100644 --- a/services/root-keys/locales/i18n.json +++ b/services/root-keys/locales/i18n.json @@ -11,6 +11,18 @@ "zh": "输入密码 软件更新 安全含义:至关重要 ", "en-tts": "Enter update password. This password is critically important." }, + "rootkeys.blind_update": { + "en": "No root keys detected. Shall we copy the staged gateware anyways, overwriting the current image?", + "ja": "ルートキーが検出されませんでした。 とにかくステージングされたゲートウェアをコピーして、現在のイメージを上書きしませんか?", + "zh": "未检测到根密钥。 我们是否要复制暂存的网关软件,覆盖当前映像?", + "en-tts": "No root keys detected. Shall we copy the staged gateware anyways, overwriting the current image?" + }, + "rootkeys.wrong_state": { + "en": "System in an unexpected state. Aborting.", + "ja": "予期しない状態のシステム。 中止します。", + "zh": "系统处于意外状态。 中止。", + "en-tts": "System in an unexpected state. Aborting." + }, "rootkeys.already_init": { "en": "Root keys already initialized.", "ja": "ルートキーはすでに初期化されています。", diff --git a/services/root-keys/src/api.rs b/services/root-keys/src/api.rs index 1fa7b96a8..81099b5f8 100644 --- a/services/root-keys/src/api.rs +++ b/services/root-keys/src/api.rs @@ -67,6 +67,10 @@ pub(crate) enum Opcode { SuspendResume = 32, Quit = 33, + + /// makes a "blind copy" of the staged gateware. This will destroy root keys, + /// but the call will not succeed if the image was provisioned. + UxBlindCopy = 34, } #[derive(Debug, num_derive::FromPrimitive, num_derive::ToPrimitive, PartialEq, Eq)] @@ -93,6 +97,8 @@ pub enum RootkeyResult { KeyError = 1, IntegrityError = 2, FlashError = 3, + /// enclave is in the wrong state to do the requested operation + StateError = 4, } /// AES operation definitions diff --git a/services/root-keys/src/implementation.rs b/services/root-keys/src/implementation.rs index 0dbf6c781..960f5a16f 100644 --- a/services/root-keys/src/implementation.rs +++ b/services/root-keys/src/implementation.rs @@ -1527,6 +1527,32 @@ impl<'a> RootKeys { Ok(()) } + /// blind-copy a staged gateware to the boot location. This can only be done if not root keys + /// have been initialized. This routine exists just to make the UX flow consistent between + /// unprovisioned and provisioned devices. + pub(crate) fn do_gateware_provision_uninitialized(&mut self, rootkeys_modal: &mut Modal, main_cid: xous::CID) -> Result<(), RootkeyResult> { + if self.is_initialized() { + return Err(RootkeyResult::StateError); + } + let mut progress_action = Slider::new(main_cid, Opcode::UxGutter.to_u32().unwrap(), + 0, 100, 10, Some("%"), 0, true, true + ); + progress_action.set_is_password(true); + rootkeys_modal.modify( + Some(ActionType::Slider(progress_action)), + Some(t!("rootkeys.gwup_starting", xous::LANG)), false, + None, true, None); + rootkeys_modal.activate(); + xous::yield_slice(); // give some time to the GAM to render + let mut pb = ProgressBar::new(rootkeys_modal, &mut progress_action); + pb.set_percentage(1); + self.ticktimer.sleep_ms(250).expect("couldn't show final message"); + self.make_gateware_backup(Some(&mut pb), true)?; + pb.set_percentage(100); + self.ticktimer.sleep_ms(250).expect("couldn't show final message"); + Ok(()) + } + /// copy data from a source region to a destination region, re-encrypting and patching as we go along. /// the region/region_base should be specified for the destination oracle /// diff --git a/services/root-keys/src/lib.rs b/services/root-keys/src/lib.rs index d5348e47d..54f847ddd 100644 --- a/services/root-keys/src/lib.rs +++ b/services/root-keys/src/lib.rs @@ -51,6 +51,9 @@ impl RootKeys { pub fn get_update_gateware_op(&self) -> u32 { Opcode::UxUpdateGateware.to_u32().unwrap() } + pub fn get_blind_copy_gateware_op(&self) -> u32 { + Opcode::UxBlindCopy.to_u32().unwrap() + } pub fn get_try_selfsign_op(&self) -> u32 { Opcode::UxSelfSignXous.to_u32().unwrap() } diff --git a/services/root-keys/src/main.rs b/services/root-keys/src/main.rs index f1b8c6410..d340c8648 100644 --- a/services/root-keys/src/main.rs +++ b/services/root-keys/src/main.rs @@ -591,6 +591,9 @@ fn main() -> ! { Err(RootkeyResult::FlashError) => { modals.show_notification(t!("rootkeys.init.fail_burn", xous::LANG), None).expect("modals error"); } + Err(RootkeyResult::StateError) => { + modals.show_notification(t!("rootkeys.wrong_state", xous::LANG), None).expect("modals error"); + } } }, Some(Opcode::UxTryReboot) => { @@ -643,6 +646,53 @@ fn main() -> ! { xous::Message::new_scalar(Opcode::UxTryReboot.to_usize().unwrap(), 0, 0, 0, 0) ).expect("couldn't initiate dialog box"); } + Some(Opcode::UxBlindCopy) => { + 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.blind_update", xous::LANG)) { + Ok(response) => { + if response == t!("rootkeys.gwup.no", xous::LANG) { + continue; + } if response != t!("rootkeys.gwup.yes", xous::LANG) { + log::error!("got unexpected response from radio box: {:?}", response); + continue; + } else { + // just proceed forward! + } + } + _ => { + log::error!("modals error, aborting"); + continue; + } + } + + let result = keys.do_gateware_provision_uninitialized(&mut rootkeys_modal, main_cid); + // the stop emoji, when sent to the slider action bar in progress mode, will cause it to close and relinquish focus + rootkeys_modal.key_event(['🛑', '\u{0000}', '\u{0000}', '\u{0000}']); + + match result { + Ok(_) => { + modals.show_notification(t!("rootkeys.gwup.finished", xous::LANG), None).expect("modals error"); + } + Err(RootkeyResult::AlignmentError) => { + modals.show_notification(t!("rootkeys.init.fail_alignment", xous::LANG), None).expect("modals error"); + } + Err(RootkeyResult::KeyError) => { + // probably a bad password, purge it, so the user can try again + keys.purge_password(PasswordType::Update); + modals.show_notification(t!("rootkeys.init.fail_key", xous::LANG), None).expect("modals error"); + } + Err(RootkeyResult::IntegrityError) => { + modals.show_notification(t!("rootkeys.init.fail_verify", xous::LANG), None).expect("modals error"); + } + Err(RootkeyResult::FlashError) => { + modals.show_notification(t!("rootkeys.init.fail_burn", xous::LANG), None).expect("modals error"); + } + Err(RootkeyResult::StateError) => { + modals.show_notification(t!("rootkeys.wrong_state", xous::LANG), None).expect("modals error"); + } + } + } Some(Opcode::UxUpdateGateware) => { // steps: // - check update signature "Inspecting gateware update, this will take a moment..." @@ -808,6 +858,9 @@ fn main() -> ! { Err(RootkeyResult::FlashError) => { modals.show_notification(t!("rootkeys.init.fail_burn", xous::LANG), None).expect("modals error"); } + Err(RootkeyResult::StateError) => { + modals.show_notification(t!("rootkeys.wrong_state", xous::LANG), None).expect("modals error"); + } } } Some(Opcode::UxSelfSignXous) => { @@ -883,6 +936,9 @@ fn main() -> ! { Err(RootkeyResult::FlashError) => { modals.show_notification(t!("rootkeys.init.fail_burn", xous::LANG), None).expect("modals error"); } + Err(RootkeyResult::StateError) => { + modals.show_notification(t!("rootkeys.wrong_state", xous::LANG), None).expect("modals error"); + } } } Some(Opcode::UxAesEnsurePassword) => msg_blocking_scalar_unpack!(msg, key_index, _, _, _, { @@ -1088,6 +1144,9 @@ fn main() -> ! { Err(RootkeyResult::FlashError) => { modals.show_notification(t!("rootkeys.init.fail_burn", xous::LANG), None).expect("modals error"); } + Err(RootkeyResult::StateError) => { + modals.show_notification(t!("rootkeys.wrong_state", xous::LANG), None).expect("modals error"); + } } } diff --git a/services/status/src/mainmenu.rs b/services/status/src/mainmenu.rs index c18b1a39a..274c06ed2 100644 --- a/services/status/src/mainmenu.rs +++ b/services/status/src/mainmenu.rs @@ -75,10 +75,19 @@ pub fn create_main_menu(keys: Arc>, menu_management_sid: xous::S action_payload: MenuPayload::Scalar([0, 0, 0, 0]), close_on_select: true, }); + menuitems.push(MenuItem { + name: String::from_str(t!("mainmenu.provision_gateware", xous::LANG)), + action_conn: Some(key_conn), + // note this is using the blind copy opcode -- makes a copy without installing keys + action_opcode: keys.lock().unwrap().get_blind_copy_gateware_op(), + action_payload: MenuPayload::Scalar([0, 0, 0, 0]), + close_on_select: true, + }); } else { menuitems.push(MenuItem { name: String::from_str(t!("mainmenu.provision_gateware", xous::LANG)), action_conn: Some(key_conn), + // note this is using the update opcode -- makes a copy while installing keys action_opcode: keys.lock().unwrap().get_update_gateware_op(), action_payload: MenuPayload::Scalar([0, 0, 0, 0]), close_on_select: true,