diff --git a/services/pddb/Cargo.toml b/services/pddb/Cargo.toml index 34ad0fab9..3767a60f9 100644 --- a/services/pddb/Cargo.toml +++ b/services/pddb/Cargo.toml @@ -13,7 +13,7 @@ xous-ipc = "0.10.4" log-server = { package = "xous-api-log", version = "0.1.63" } ticktimer-server = { package = "xous-api-ticktimer", version = "0.9.63" } xous-names = { package = "xous-api-names", version = "0.9.65" } -susres = { package = "xous-api-susres", version = "0.9.63", optional = true } +susres = { package = "xous-api-susres", version = "0.9.63" } log = "0.4.14" num-derive = { version = "0.4.2", default-features = false } num-traits = { version = "0.2.14", default-features = false } @@ -21,10 +21,10 @@ rkyv = { version = "0.8.8", default-features = false, features = [ "std", "alloc", ] } -trng = { path = "../trng", optional = true } -spinor = { path = "../spinor", optional = true } +trng = { path = "../trng" } +spinor = { path = "../spinor" } aes = { path = "../aes" } -root-keys = { path = "../root-keys", optional = true } +root-keys = { path = "../root-keys" } cipher = "0.4.2" bitfield = "0.13.2" aes-gcm-siv = { version = "0.11.1", default-features = false, features = [ @@ -32,13 +32,10 @@ aes-gcm-siv = { version = "0.11.1", default-features = false, features = [ "aes", ] } # aes-gcm-siv = {git="https://github.com/RustCrypto/AEADs.git", branch="master"} -llio = { path = "../llio", optional = true } +llio = { path = "../llio" } subtle = { version = "2.4.1", default-features = false } -tts-frontend = { path = "../tts", optional = true } +tts-frontend = { path = "../tts" } rand_core = "0.6.4" -cram-hal-service = { path = "../cram-hal-service", optional = true } -cramium-emu = { path = "../cramium-emu", optional = true } -cramium-api = { path = "../../libs/cramium-api", optional = true } # passwords sha2 = { version = "0.10.8" } @@ -51,10 +48,9 @@ zeroize_derive = "1.4.2" blowfish = { version = "0.9.1", features = ["bcrypt"] } # UX (for password entry and notifications) -gam = { path = "../gam", optional = true } -locales = { path = "../../locales", optional = true } -modals = { path = "../modals", optional = true } -ux-api = { path = "../../libs/ux-api", optional = true, features = ["std"] } +gam = { path = "../gam" } +locales = { path = "../../locales" } +modals = { path = "../modals" } utralib = { version = "0.1.25", optional = true, default-features = false } @@ -69,46 +65,10 @@ hex = { version = "0.4.3", default-features = false, features = [ "alloc", ], optional = true } -# gen 2 dependencies -keystore = { path = "../keystore", optional = true } -xous-swapper = { path = "../xous-swapper", features = [ - "spinor", -], optional = true } - [features] -precursor = ["utralib/precursor", "sha2/precursor", "gen1"] -hosted = ["utralib/hosted", "sha2/hosted", "gen1"] -renode = ["utralib/renode", "sha2/renode", "gen1"] -cramium-soc = ["utralib/cramium-soc", "gen2", "cram-hal-service"] -hosted-baosec = ["gen2", "cramium-emu", "cramium-api"] - -# gen1 PDDB pulls in the graphical libraries for direct capture of passwords -# from users. This gives maximum control over the flow of sensitive password data, -# but also complicates the code base and dependencies, making it less portable. - -# gen2 PDDB focuses on cross-platform portability, keeping the PDDB dependencies tightly -# focused on just doing what the PDDB needs to do from a filesystem perspective. This -# means that the PDDB must inevitably rely upon some less well specified mechanism for -# gathering password materials from the user. - -# gen-1 implementation feature set -gen1 = [ - "susres", - "trng", - "spinor", - "root-keys", - "llio", - "tts-frontend", - "gam", - "locales", - "modals", -] - -# gen-2 features -gen2 = ["keystore"] -# gen-2 boards -board-baosec = ["ux-api/board-baosec", "cramium-api", "gen2", "xous-swapper"] - +precursor = ["utralib/precursor", "sha2/precursor"] +hosted = ["utralib/hosted", "sha2/hosted"] +renode = ["utralib/renode", "sha2/renode"] # when selected, physical disk addresses are set to 64 bits, otherwise, they are 32 bits. # 32 bit addressing is recommended for Precursor, as its disk is only 128MiB and it has limited RAM for bookkeeping. u64_pa = [] diff --git a/services/pddb/src/api.rs b/services/pddb/src/api.rs index 8417e4070..c5169d217 100644 --- a/services/pddb/src/api.rs +++ b/services/pddb/src/api.rs @@ -148,14 +148,12 @@ pub(crate) enum Opcode { KeyDrop = 20, /// Menu opcodes - #[cfg(feature = "gen1")] MenuListBasis = 21, /// Security state checks IsEfuseSecured = 22, /// Suspend/resume callback - #[cfg(feature = "gen1")] SuspendResume = 23, /// quit the server Quit = 24, @@ -217,14 +215,12 @@ pub(crate) enum Opcode { ListKeyV2 = 45, /// change unlock PIN - #[cfg(feature = "gen1")] MenuChangePin = 46, /// run a test or diagnostic command (depends on the build) InternalTest = 47, /// Clear password cache and ask for it again - #[cfg(feature = "gen1")] UncacheAndAskPassword = 48, /// Unmount the PDDB. diff --git a/services/pddb/src/backend/hw.rs b/services/pddb/src/backend/hw.rs index b7953f612..1df677489 100644 --- a/services/pddb/src/backend/hw.rs +++ b/services/pddb/src/backend/hw.rs @@ -15,88 +15,15 @@ use aes::{Aes256, BLOCK_SIZE, Block}; use aes_gcm_siv::aead::{Aead, Payload}; use aes_gcm_siv::{Aes256GcmSiv, Nonce, Tag}; use backend::bcrypt::*; -#[cfg(not(any(feature = "hosted-baosec", feature = "board-baosec")))] -use gam::modal::*; use modals::Modals; -#[cfg(feature = "gen1")] use root_keys::api::AesRootkeyType; -#[cfg(feature = "gen1")] use root_keys::api::KeywrapError; use sha2::{Digest, Sha512_256Hw, Sha512_256Sw}; use spinor::SPINOR_BULK_ERASE_SIZE; use subtle::ConstantTimeEq; -#[cfg(any(feature = "hosted-baosec", feature = "board-baosec"))] -use ux_api::widgets::*; use crate::*; -/* - Refactor notes -- - - What to do about rootkeys? The features used by this crate are: - - selection of an AES key at an index - - password entry to unlock key at index (this is handled inside rootkeys) - - key wrapping using the indexed key - - block decrypt/encrypt with the indexed key - - also queries are made with regards to the key box health and initialization status - - What to do about modals? - - The work flow for many of the crates assumes we can have a blocking user I/O - via the modals crate - - I think that the modals crate should probably be the "right" layer for things - to talk to the UI. - Question: - - Can we adapt modals to a small (128x128) pixel display? - - Can we adapt modals to a console-like text interface? - - Suggestion: - - Stop the refactor on PDDB at this moment and dig into modals/rootkeys - - Rootkeys can place the keys in RRAM at the "final" location according to ACRAM lock abilities - even if the lifecycle stuff is broken, the ability to read/write those keys are configured - "out of band" - - Modals should include an implementation directly inside the modals crate that pulls in - the mini-gfx library, so that there are no other dependencies to get user I/O going. - - Observation: I could check in this partial, broken code right now into a branch, and come back - to it later. As long as I don't select the PDDB crate as a cramium target, it doesn't break - anything else in the code base? - - Probably better just to branch this for now - let's make a branch, stick it in xous-core, - and put some notes around it in a WIP pull request. In fact let's put all this data in that - PR so we have some publicly trackable information about how this is progressing. - - Xous-swapper refactor notes: - - SPINOR shares the same interface as the swap SRAM, and therefore, the Spinor interface - has to live inside xous-swapper. - - Xous also needs to be extended to implement Virtual Addresses that are not backed by - physical addresses, but are on-demand allocated by copying SPINOR contents into pages that - are allocated in SRAM. The general idea is something like this: - - A new flag is added that can be passed to xous::MapMemory(). This flag is the `Swapped` flag, - and it indicates to the kernel that the physical address should be `null` and marked as `swapped` - for the mapping in its initial page table map in the given process. - - A "special" range of virtual addresses needs to be carved out which is where the memory-mapped - FLASH memory would go to. Thus, a process would gain access to FLASH by simply calling MapMemory - with the FLASH memory VA range as the virtual address, `None` as the PA, and the Swapped flag - as one of the args in Memory Arguments - - When the virtual address is referenced, it will page fault; the page fault handler will pass - this to Xous-Swapper in the userspace, which will then add a check for the virtual address. - If the virtual address is in the magic range for SPINOR, the contents are fetched using the - SPINOR interface based on the linear mapping of the lower bits of the address onto the SPINOR - memory space. - - WHnever a write happens inside Xous-Swapper to a location in FLASH, the page table entry for - the mapped FLASH location needs to be marked as invalid and returned to the free pool. This - uses the swap system to keep the read-view of FLASH in sync with hte write-view. This also - means that Xous-Swapper's SPINOR map has to keep a scoreboard of what pages are mapped to - what processes, so that we can search for the mapping and clear it whenever a write comes in. - - Development of this can probably happen separately from the emu-layer version. The basic thing - would be to drill down into the kernel with the kernel and a simple test server that just - tries to map the SPINOR and read some contents out, and perhaps update a sector. This will - exercise the path in isolation and allow us to test this routine as a separate primitive - from the PDDB. -*/ - #[cfg(not(feature = "deterministic"))] type FspaceSet = HashSet; #[cfg(feature = "deterministic")] @@ -210,14 +137,8 @@ type EmuMemoryRange = xous::MemoryRange; #[cfg(any(feature = "precursor", feature = "renode"))] type EmuSpinor = spinor::Spinor; -#[cfg(all(feature = "board-baosec", feature = "gen2"))] -type EmuMemoryRange = xous::MemoryRange; -#[cfg(all(feature = "board-baosec", feature = "gen2"))] -type EmuSpinor = xous_swapper::Spinor; - pub(crate) struct PddbOs { spinor: EmuSpinor, - #[cfg(feature = "gen1")] rootkeys: root_keys::RootKeys, tt: ticktimer_server::Ticktimer, pddb_mr: EmuMemoryRange, @@ -354,40 +275,6 @@ impl PddbOs { #[cfg(feature = "perfcounter")] use_perf: true, }; - #[cfg(any(feature = "cramium-soc"))] - let ret = PddbOs { - spinor: crate::hw::Spinor::new(&xns).unwrap(), - tt: ticktimer_server::Ticktimer::new().unwrap(), - pddb_mr: pddb, - pt_phys_base: PageAlignedPa::from(0 as u32), - key_phys_base, - mbbb_phys_base, - fscb_phys_base, - data_phys_base: PageAlignedPa::from( - fscb_phys_base.as_u32() + FSCB_PAGES as u32 * PAGE_SIZE as u32, - ), - system_basis_key: None, - cipher_ecb: None, - fspace_cache: FspaceSet::new(), - fspace_log_addrs: Vec::::new(), - fspace_log_next_addr: None, - fspace_log_len: 0, - dna, - // default to our own DNA in this case - migration_dna: dna, - dna_mode: DnaMode::Normal, - entropy: trngpool, - pw_cid, - failed_logins: 0, - #[cfg(all(feature = "pddbtest", feature = "autobasis"))] - testnames: HashSet::new(), - #[cfg(feature = "perfcounter")] - perfclient, - #[cfg(feature = "perfcounter")] - pc_id, - #[cfg(feature = "perfcounter")] - use_perf: true, - }; // emulated #[cfg(not(target_os = "xous"))] let ret = { @@ -475,14 +362,10 @@ impl PddbOs { self.pddb_mr.reset(); } - #[cfg(feature = "gen1")] pub(crate) fn is_efuse_secured(&self) -> bool { self.rootkeys.is_efuse_secured().expect("couldn't query efuse security state") == Some(true) } - #[cfg(feature = "gen2")] - pub(crate) fn is_efuse_secured(&self) -> bool { unimplemented!() } - pub(crate) fn nonce_gen(&self) -> Nonce { let nonce_array = self.entropy.borrow_mut().get_nonce(); *Nonce::from_slice(&nonce_array) @@ -500,16 +383,10 @@ impl PddbOs { pub(crate) fn timestamp_now(&self) -> u64 { self.tt.elapsed_ms() } /// checks if the root keys are initialized, which is a prerequisite to formatting and mounting - #[cfg(feature = "gen1")] pub(crate) fn rootkeys_initialized(&self) -> bool { self.rootkeys.is_initialized().expect("couldn't query initialization state of the rootkeys server") } - #[cfg(feature = "gen2")] - pub(crate) fn rootkeys_initialized(&self) -> bool { - unimplemented!(); - } - /// patches data at an offset starting from the data physical base address, which corresponds /// exactly to the first entry in the page table pub(crate) fn patch_data(&self, data: &[u8], offset: u32) { @@ -894,12 +771,8 @@ impl PddbOs { self.cipher_ecb = None; } - #[cfg(feature = "gen1")] pub(crate) fn clear_password(&self) { self.rootkeys.clear_password(AesRootkeyType::User0); } - #[cfg(feature = "gen2")] - pub(crate) fn clear_password(&self) { todo!("implement password clearing") } - pub(crate) fn try_login(&mut self) -> PasswordState { use aes::cipher::KeyInit; if self.system_basis_key.is_none() || self.cipher_ecb.is_none() { @@ -938,49 +811,42 @@ impl PddbOs { // now try to populate our keys, and prep a migration if necessary let mut syskey_pt = [0u8; 32]; let mut syskey = [0u8; 32]; - #[cfg(feature = "gen1")] - { - let mut keys_updated = false; - match self.rootkeys.unwrap_key(&scd.system_key_pt, AES_KEYSIZE) { - Ok(skpt) => syskey_pt.copy_from_slice(&skpt), - Err(e) => match e { - KeywrapError::UpgradeToNew((key, upgrade)) => { - log::warn!("pt key migration required"); - syskey_pt.copy_from_slice(&key); - new_crypto_keys.system_key_pt.copy_from_slice(&upgrade); - keys_updated = true; - } - _ => { - log::error!("Couldn't unwrap our system key: {:?}", e); - self.failed_logins = self.failed_logins.saturating_add(1); - return PasswordState::Incorrect(self.failed_logins); - } - }, - } - match self.rootkeys.unwrap_key(&scd.system_key, AES_KEYSIZE) { - Ok(sk) => syskey.copy_from_slice(&sk), - Err(e) => match e { - KeywrapError::UpgradeToNew((key, upgrade)) => { - log::warn!("data key migration required"); - syskey.copy_from_slice(&key); - new_crypto_keys.system_key.copy_from_slice(&upgrade); - keys_updated = true; - } - _ => { - log::error!("Couldn't unwrap our system key: {:?}", e); - self.failed_logins = self.failed_logins.saturating_add(1); - return PasswordState::Incorrect(self.failed_logins); - } - }, - } - if keys_updated { - log::warn!("Migration event from incorrectly wrapped key"); - self.patch_keys(new_crypto_keys.deref(), 0); - } + let mut keys_updated = false; + match self.rootkeys.unwrap_key(&scd.system_key_pt, AES_KEYSIZE) { + Ok(skpt) => syskey_pt.copy_from_slice(&skpt), + Err(e) => match e { + KeywrapError::UpgradeToNew((key, upgrade)) => { + log::warn!("pt key migration required"); + syskey_pt.copy_from_slice(&key); + new_crypto_keys.system_key_pt.copy_from_slice(&upgrade); + keys_updated = true; + } + _ => { + log::error!("Couldn't unwrap our system key: {:?}", e); + self.failed_logins = self.failed_logins.saturating_add(1); + return PasswordState::Incorrect(self.failed_logins); + } + }, } - #[cfg(feature = "gen2")] - { - todo!("implement password entry") + match self.rootkeys.unwrap_key(&scd.system_key, AES_KEYSIZE) { + Ok(sk) => syskey.copy_from_slice(&sk), + Err(e) => match e { + KeywrapError::UpgradeToNew((key, upgrade)) => { + log::warn!("data key migration required"); + syskey.copy_from_slice(&key); + new_crypto_keys.system_key.copy_from_slice(&upgrade); + keys_updated = true; + } + _ => { + log::error!("Couldn't unwrap our system key: {:?}", e); + self.failed_logins = self.failed_logins.saturating_add(1); + return PasswordState::Incorrect(self.failed_logins); + } + }, + } + if keys_updated { + log::warn!("Migration event from incorrectly wrapped key"); + self.patch_keys(new_crypto_keys.deref(), 0); } let cipher = Aes256::new(GenericArray::from_slice(&syskey_pt)); @@ -1013,18 +879,11 @@ impl PddbOs { fn syskey_ensure(&mut self) { while self.try_login() != PasswordState::Correct { self.clear_password(); // clear the bad password entry - #[cfg(feature = "gen1")] - { - let xns = xous_names::XousNames::new().unwrap(); - let modals = modals::Modals::new(&xns).expect("can't connect to Modals server"); - modals - .show_notification(t!("pddb.badpass_infallible", locales::LANG), None) - .expect("notification failed"); - } - #[cfg(feature = "gen2")] - { - todo!("implement feedback that syskey is not available"); - } + let xns = xous_names::XousNames::new().unwrap(); + let modals = modals::Modals::new(&xns).expect("can't connect to Modals server"); + modals + .show_notification(t!("pddb.badpass_infallible", locales::LANG), None) + .expect("notification failed"); } } @@ -2117,7 +1976,6 @@ impl PddbOs { } } - #[cfg(feature = "gen1")] fn pw_check(&self, modals: &modals::Modals) -> Result<()> { let mut success = false; while !success { @@ -2150,7 +2008,6 @@ impl PddbOs { } /// this function attempts to change the PIN. returns Ok() if changed, error if not. - #[cfg(feature = "gen1")] pub(crate) fn pddb_change_pin(&mut self, modals: &modals::Modals) -> Result<()> { if let Some(system_keys) = &self.system_basis_key { // get the new password diff --git a/services/pddb/src/lib.rs b/services/pddb/src/lib.rs index ab662824d..3af3e7af1 100644 --- a/services/pddb/src/lib.rs +++ b/services/pddb/src/lib.rs @@ -21,11 +21,6 @@ use core::ops::DerefMut; use std::cell::RefCell; use std::convert::TryInto; -#[cfg(all(feature = "gen2", feature = "cramium-soc"))] -use cram_hal_service::trng; -#[cfg(all(feature = "gen2", feature = "hosted-baosec"))] -use cramium_emu::trng; - #[derive(num_derive::FromPrimitive, num_derive::ToPrimitive, Debug)] pub enum CbOp { Change, @@ -268,7 +263,6 @@ impl Pddb { /// Computes checksums on the entire PDDB database. This operation can take some time and causes a /// progress bar to pop up. This should be called only after the PDDB has been unmounted, to ensure /// that the disk contents do not change after the checksums have been computed. - #[cfg(feature = "gen1")] pub fn compute_checksums(&self) -> root_keys::api::Checksums { let alloc = root_keys::api::Checksums::default(); let mut buf = Buffer::into_buf(alloc).expect("Couldn't convert memory structure"); diff --git a/services/pddb/src/main.rs b/services/pddb/src/main.rs index adbf643db..bfbdf8101 100644 --- a/services/pddb/src/main.rs +++ b/services/pddb/src/main.rs @@ -1,3 +1,6 @@ +#![cfg_attr(target_os = "none", no_std)] +#![cfg_attr(target_os = "none", no_main)] + extern crate bitfield; /// # PDDB - Plausibly Deniable DataBase /// @@ -369,9 +372,7 @@ use backend::*; mod ux; use rkyv::with::Identity; use ux::*; -#[cfg(feature = "gen1")] mod menu; -#[cfg(feature = "gen1")] use menu::*; mod libstd; @@ -398,10 +399,7 @@ use std::sync::Arc; use std::sync::atomic::{AtomicBool, Ordering}; use std::thread; -#[cfg(not(any(feature = "hosted-baosec", feature = "cramium-soc")))] -use gam::*; use locales::t; -use modals::Modals; use num_traits::*; use rkyv::{ Archive, Place, Serialize, @@ -410,8 +408,6 @@ use rkyv::{ ser::{Positional, allocator::SubAllocator, writer::Buffer as RkyvBuffer}, with::{ArchiveWith, SerializeWith}, }; -#[cfg(any(feature = "hosted-baosec", feature = "cramium-soc"))] -use ux_api::widgets::*; use xous::{Message, msg_blocking_scalar_unpack, send_message}; use xous_ipc::Buffer; @@ -508,7 +504,7 @@ fn wrapped_main() -> ! { let entropy = Rc::new(RefCell::new(TrngPool::new())); // for less-secured user prompts (everything but password entry) - let modals = Modals::new(&xns).expect("can't connect to Modals server"); + let modals = modals::Modals::new(&xns).expect("can't connect to Modals server"); // our very own password modal. Password modals are precious and privately owned, to avoid // other processes from crafting them. @@ -559,9 +555,8 @@ fn wrapped_main() -> ! { } }); - let my_cid = xous::connect(pddb_sid).unwrap(); // our menu handler - #[cfg(feature = "gen1")] + let my_cid = xous::connect(pddb_sid).unwrap(); let _ = thread::spawn({ let my_cid = my_cid.clone(); move || { @@ -669,7 +664,6 @@ fn wrapped_main() -> ! { let mut scratch = [MaybeUninit::::uninit(); 256]; // register a suspend/resume listener - #[cfg(feature = "gen1")] let mut susres = susres::Susres::new(Some(susres::SuspendOrder::Early), &xns, Opcode::SuspendResume as u32, my_cid) .expect("couldn't create suspend/resume object"); @@ -678,7 +672,6 @@ fn wrapped_main() -> ! { let op: Opcode = FromPrimitive::from_usize(msg.body.id() & 0xffff).unwrap_or(Opcode::InvalidOpcode); log::debug!("{:x?}", op); match op { - #[cfg(feature = "gen1")] Opcode::SuspendResume => xous::msg_scalar_unpack!(msg, token, _, _, _, { basis_cache.suspend(&mut pddb_os); susres.suspend_until_resume(token).expect("couldn't execute suspend/resume"); @@ -722,9 +715,7 @@ fn wrapped_main() -> ! { // If we need more nuance out of this routine, consider creating a custom public enum type to help // marshall this. Opcode::TryMount => xous::msg_blocking_scalar_unpack!(msg, _, _, _, _, { - #[cfg(feature = "gen1")] let llio = llio::Llio::new(&xns); - #[cfg(feature = "gen1")] while !llio.is_ec_ready() { // spin-wait while the EC is not ready -- so that a PDDB mount does not interfere with // on-going EC updates. Also causes the mount dialog to delay until the EC status has been @@ -738,9 +729,7 @@ fn wrapped_main() -> ! { // can't mount if we have no root keys log::info!("{}PDDB.SKIPMOUNT,{}", xous::BOOKEND_START, xous::BOOKEND_END); // allow the main menu to be used in this case - #[cfg(feature = "gen1")] let gam = gam::Gam::new(&xns).unwrap(); - #[cfg(feature = "gen1")] gam.allow_mainmenu().expect("couldn't allow main menu activation"); xous::return_scalar2(msg.sender, 1, 0).expect("could't return scalar"); } else { @@ -810,9 +799,7 @@ fn wrapped_main() -> ! { } // get a handle to the GAM and inform it that main menu should be allowed. The handle // is dropped when this routine finishes. - #[cfg(feature = "gen1")] let gam = gam::Gam::new(&xns).unwrap(); - #[cfg(feature = "gen1")] gam.allow_mainmenu().expect("couldn't allow main menu activation"); // setup the heap initial_heap = heap_usage(); @@ -2401,7 +2388,6 @@ fn ensure_password(modals: &modals::Modals, pddb_os: &mut PddbOs, _pw_cid: xous: } } } - fn try_mount_or_format( modals: &modals::Modals, pddb_os: &mut PddbOs, diff --git a/services/pddb/src/ux.rs b/services/pddb/src/ux.rs index 0765cd892..dbcfe92ad 100644 --- a/services/pddb/src/ux.rs +++ b/services/pddb/src/ux.rs @@ -1,9 +1,6 @@ -#[cfg(not(any(feature = "hosted-baosec", feature = "cramium-soc")))] use gam::modal::*; use locales::t; use num_traits::*; -#[cfg(any(feature = "hosted-baosec", feature = "cramium-soc"))] -use ux_api::widgets::*; use xous::msg_scalar_unpack; use xous::{CID, SID}; use xous_ipc::Buffer; @@ -119,7 +116,7 @@ pub(crate) fn password_ux_manager( } Some(PwManagerOpcode::PwReturn) => { let mut buf = unsafe { Buffer::from_memory_message(msg.body.memory_message().unwrap()) }; - let pw = buf.to_original::().unwrap(); + let pw = buf.to_original::().unwrap(); if let Some(mut response) = dr.take() { let mut buffer = unsafe {