diff --git a/apps/desktop/desktop_native/Cargo.lock b/apps/desktop/desktop_native/Cargo.lock index c225dc49f73..d40c519ec1d 100644 --- a/apps/desktop/desktop_native/Cargo.lock +++ b/apps/desktop/desktop_native/Cargo.lock @@ -62,6 +62,12 @@ dependencies = [ "memchr", ] +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + [[package]] name = "anstream" version = "0.6.18" @@ -369,6 +375,12 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + [[package]] name = "base64" version = "0.22.1" @@ -419,11 +431,16 @@ checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" [[package]] name = "bitwarden-russh" version = "0.1.0" -source = "git+https://github.com/bitwarden/bitwarden-russh.git?rev=3d48f140fd506412d186203238993163a8c4e536#3d48f140fd506412d186203238993163a8c4e536" dependencies = [ "anyhow", "byteorder", + "ecdsa", + "ed25519-dalek", "futures", + "p256", + "p384", + "p521", + "rsa", "russh-cryptovec", "ssh-encoding", "ssh-key", @@ -732,6 +749,18 @@ version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -775,6 +804,7 @@ dependencies = [ "fiat-crypto", "rustc_version", "subtle", + "zeroize", ] [[package]] @@ -896,6 +926,7 @@ name = "desktop_core" version = "0.0.0" dependencies = [ "aes", + "allocator-api2", "anyhow", "arboard", "argon2", @@ -909,11 +940,13 @@ dependencies = [ "dirs", "ed25519", "futures", + "hashbrown 0.15.3", "homedir", "interprocess", "keytar", "libc", "log", + "memsec", "oo7", "pin-project", "pkcs8", @@ -937,6 +970,8 @@ dependencies = [ "windows-future", "zbus", "zbus_polkit", + "zeroize", + "zeroizing-alloc", ] [[package]] @@ -1031,6 +1066,20 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + [[package]] name = "ed25519" version = "2.2.3" @@ -1049,8 +1098,11 @@ checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" dependencies = [ "curve25519-dalek", "ed25519", + "serde", "sha2", + "signature", "subtle", + "zeroize", ] [[package]] @@ -1059,6 +1111,27 @@ version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7914353092ddf589ad78f25c5c1c21b7f80b0ff8621e7c814c3485b5306da9d" +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array", + "group", + "hkdf", + "pem-rfc7468", + "pkcs8", + "rand_core", + "sec1", + "subtle", + "zeroize", +] + [[package]] name = "embed_plist" version = "1.2.2" @@ -1141,6 +1214,16 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" +[[package]] +name = "ff" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" +dependencies = [ + "rand_core", + "subtle", +] + [[package]] name = "fiat-crypto" version = "0.2.9" @@ -1284,6 +1367,7 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", + "zeroize", ] [[package]] @@ -1352,6 +1436,17 @@ dependencies = [ "scroll", ] +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + [[package]] name = "hashbrown" version = "0.14.5" @@ -1360,9 +1455,14 @@ checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.15.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] [[package]] name = "heck" @@ -1419,7 +1519,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" dependencies = [ "equivalent", - "hashbrown 0.15.2", + "hashbrown 0.15.3", ] [[package]] @@ -1592,6 +1692,17 @@ dependencies = [ "autocfg", ] +[[package]] +name = "memsec" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c797b9d6bb23aab2fc369c65f871be49214f5c759af65bde26ffaaa2b646b492" +dependencies = [ + "getrandom 0.2.15", + "libc", + "windows-sys 0.45.0", +] + [[package]] name = "mime" version = "0.3.17" @@ -2033,6 +2144,44 @@ dependencies = [ "log", ] +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "p384" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe42f1670a52a47d448f14b6a5c61dd78fce51856e68edaa38f7ae3a46b8d6b6" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "p521" +version = "0.13.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc9e2161f1f215afdfce23677034ae137bbd45016a880c2eb3ba8eb95f085b2" +dependencies = [ + "base16ct", + "ecdsa", + "elliptic-curve", + "primeorder", + "rand_core", + "sha2", +] + [[package]] name = "parking" version = "2.2.1" @@ -2254,6 +2403,15 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + [[package]] name = "proc-macro-crate" version = "3.2.0" @@ -2395,6 +2553,16 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + [[package]] name = "rsa" version = "0.9.8" @@ -2518,6 +2686,20 @@ dependencies = [ "sha2", ] +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + [[package]] name = "security-framework" version = "3.1.0" @@ -2743,6 +2925,7 @@ dependencies = [ "num-bigint-dig", "rand_core", "rsa", + "sec1", "sha2", "signature", "ssh-cipher", @@ -3518,6 +3701,15 @@ dependencies = [ "windows-link", ] +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + [[package]] name = "windows-sys" version = "0.52.0" @@ -3536,6 +3728,21 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + [[package]] name = "windows-targets" version = "0.48.5" @@ -3583,6 +3790,12 @@ dependencies = [ "windows_x86_64_msvc 0.53.0", ] +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -3601,6 +3814,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" @@ -3619,6 +3838,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + [[package]] name = "windows_i686_gnu" version = "0.48.5" @@ -3649,6 +3874,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + [[package]] name = "windows_i686_msvc" version = "0.48.5" @@ -3676,6 +3907,12 @@ dependencies = [ "windows-core 0.61.0", ] +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" @@ -3694,6 +3931,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" @@ -3712,6 +3955,12 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" @@ -3911,6 +4160,12 @@ dependencies = [ "syn", ] +[[package]] +name = "zeroizing-alloc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebff5e6b81c1c7dca2d0bd333b2006da48cb37dbcae5a8da888f31fcb3c19934" + [[package]] name = "zvariant" version = "4.2.0" diff --git a/apps/desktop/desktop_native/Cargo.toml b/apps/desktop/desktop_native/Cargo.toml index d9e61124864..fffbb504dd5 100644 --- a/apps/desktop/desktop_native/Cargo.toml +++ b/apps/desktop/desktop_native/Cargo.toml @@ -15,7 +15,7 @@ arboard = { version = "=3.4.1", default-features = false } argon2 = "=0.5.3" base64 = "=0.22.1" bindgen = "0.71.1" -bitwarden-russh = { git = "https://github.com/bitwarden/bitwarden-russh.git", rev = "3d48f140fd506412d186203238993163a8c4e536" } +bitwarden-russh = { path = "/home/quexten/projects/bitwarden-russh" } byteorder = "=1.5.0" bytes = "1.9.0" cbc = "=0.1.2" diff --git a/apps/desktop/desktop_native/core/Cargo.toml b/apps/desktop/desktop_native/core/Cargo.toml index a8a8e0a2a44..c4556179f02 100644 --- a/apps/desktop/desktop_native/core/Cargo.toml +++ b/apps/desktop/desktop_native/core/Cargo.toml @@ -55,6 +55,11 @@ rsa = { workspace = true } ed25519 = { workspace = true, features = ["pkcs8"] } bytes = { workspace = true } sysinfo = { workspace = true, features = ["windows"] } +memsec = { version = "0.7.0", features = ["alloc_ext"] } +allocator-api2 = "0.2.21" +zeroizing-alloc = "0.1.0" +hashbrown = "0.15.3" +zeroize = "1.8.1" [target.'cfg(windows)'.dependencies] widestring = { workspace = true, optional = true } diff --git a/apps/desktop/desktop_native/core/src/alloc/linux_memfd_secret.rs b/apps/desktop/desktop_native/core/src/alloc/linux_memfd_secret.rs new file mode 100644 index 00000000000..0e35b9fd34a --- /dev/null +++ b/apps/desktop/desktop_native/core/src/alloc/linux_memfd_secret.rs @@ -0,0 +1,57 @@ +use std::{alloc::Layout, ptr::NonNull, sync::OnceLock}; + +use allocator_api2::alloc::{AllocError, Allocator}; + +pub(crate) struct LinuxMemfdSecretAlloc; + +impl LinuxMemfdSecretAlloc { + pub fn new() -> Option { + fn is_available() -> bool { + static IS_SUPPORTED: OnceLock = OnceLock::new(); + + *IS_SUPPORTED.get_or_init(|| unsafe { + let Some(ptr) = (unsafe { memsec::memfd_secret_sized(1) }) else { + return false; + }; + memsec::free_memfd_secret(ptr); + true + }) + } + + if !is_available() { + return None; + } + + Some(Self) + } +} + +unsafe impl Allocator for LinuxMemfdSecretAlloc { + fn allocate(&self, layout: Layout) -> Result, AllocError> { + // Note: The allocator_api2 Allocator traits requires us to handle zero-sized allocations. + // We return an invalid pointer as you cannot allocate a zero-sized slice in most + // allocators. This is what allocator_api2::Global does as well: + // https://github.com/zakarumych/allocator-api2/blob/2dde97af85f3559619689cef152e90e6d8a0cee3/src/alloc/global.rs#L24-L29 + if layout.size() == 0 { + return Ok(unsafe { + NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut( + layout.align() as *mut u8, + 0, + )) + }); + } + + let ptr: NonNull<[u8]> = unsafe { memsec::memfd_secret_sized(layout.size()) } + .expect("memfd_secret_sized failed"); + + Ok(ptr) + } + + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + if layout.size() == 0 { + return; + } + + memsec::free_memfd_secret(ptr); + } +} \ No newline at end of file diff --git a/apps/desktop/desktop_native/core/src/alloc/malloc.rs b/apps/desktop/desktop_native/core/src/alloc/malloc.rs new file mode 100644 index 00000000000..be9ee163932 --- /dev/null +++ b/apps/desktop/desktop_native/core/src/alloc/malloc.rs @@ -0,0 +1,75 @@ +use std::{ + alloc::{GlobalAlloc, Layout}, + ptr::NonNull, +}; + +use allocator_api2::alloc::{AllocError, Allocator}; + +pub(crate) struct MlockAlloc(zeroizing_alloc::ZeroAlloc); + +impl MlockAlloc { + pub fn new() -> Self { + Self(zeroizing_alloc::ZeroAlloc(std::alloc::System)) + } +} + +unsafe fn ptr_to_nonnull_slice(ptr: *mut u8, len: usize) -> Result, AllocError> { + if ptr.is_null() { + return Err(AllocError); + } + + // SAFETY: The caller must ensure that `ptr` is valid for `len` elements. + Ok(unsafe { + let slice = std::slice::from_raw_parts_mut(ptr, len); + NonNull::new(slice).expect("slice is never null") + }) +} + +unsafe impl Allocator for MlockAlloc { + fn allocate(&self, layout: Layout) -> Result, AllocError> { + // Note: The allocator_api2 Allocator traits requires us to handle zero-sized allocations. + // We return an invalid pointer as you cannot allocate a zero-sized slice in most + // allocators. This is what allocator_api2::Global does as well: + // https://github.com/zakarumych/allocator-api2/blob/2dde97af85f3559619689cef152e90e6d8a0cee3/src/alloc/global.rs#L24-L29 + if layout.size() == 0 { + return Ok(unsafe { + NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut( + layout.align() as *mut u8, + 0, + )) + }); + } + + let ptr = unsafe { self.0.alloc(layout) }; + + if ptr.is_null() { + return Err(AllocError); + } + + #[cfg(all( + not(target_arch = "wasm32"), + not(windows), + not(feature = "no-memory-hardening") + ))] + unsafe { + memsec::mlock(ptr, layout.size()) + }; + + unsafe { ptr_to_nonnull_slice(ptr, layout.size()) } + } + + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + if layout.size() == 0 { + return; + } + + #[cfg(all( + not(target_arch = "wasm32"), + not(windows), + not(feature = "no-memory-hardening") + ))] + memsec::munlock(ptr.as_ptr(), layout.size()); + + self.0.dealloc(ptr.as_ptr(), layout); + } +} \ No newline at end of file diff --git a/apps/desktop/desktop_native/core/src/alloc/mod.rs b/apps/desktop/desktop_native/core/src/alloc/mod.rs new file mode 100644 index 00000000000..141e5249905 --- /dev/null +++ b/apps/desktop/desktop_native/core/src/alloc/mod.rs @@ -0,0 +1,39 @@ +use allocator_api2::alloc::Allocator; +use std::hash::Hash; + +mod malloc; + +pub(super) type MlockBackend = CustomAllocBackend; +pub(super) use malloc::MlockAlloc; + +mod linux_memfd_secret; +pub type LinuxMemfdSecretBackend = + CustomAllocBackend; +pub(crate) use linux_memfd_secret::LinuxMemfdSecretAlloc; + +pub struct CustomAllocBackend { + map: hashbrown::HashMap, +} + +impl CustomAllocBackend { + pub(super) fn new(alloc: Alloc) -> Self { + Self { + map: hashbrown::HashMap::new_in(alloc), + } + } +} + + +impl CustomAllocBackend { + pub fn insert(&mut self, key: Key, value: Value) { + self.map.insert(key, value); + } + + pub fn get(&self, key: &Key) -> Option<&Value> { + self.map.get(key) + } + + pub fn remove(&mut self, key: &Key) -> Option { + self.map.remove(key) + } +} \ No newline at end of file diff --git a/apps/desktop/desktop_native/core/src/lib.rs b/apps/desktop/desktop_native/core/src/lib.rs index aeb8a5b8929..80e9ade25b0 100644 --- a/apps/desktop/desktop_native/core/src/lib.rs +++ b/apps/desktop/desktop_native/core/src/lib.rs @@ -7,4 +7,5 @@ pub mod ipc; pub mod password; pub mod powermonitor; pub mod process_isolation; -pub mod ssh_agent; \ No newline at end of file +pub mod ssh_agent; +pub mod alloc; \ No newline at end of file diff --git a/apps/desktop/desktop_native/core/src/ssh_agent/mod.rs b/apps/desktop/desktop_native/core/src/ssh_agent/mod.rs index 3db7eb808b4..4fc66c497ae 100644 --- a/apps/desktop/desktop_native/core/src/ssh_agent/mod.rs +++ b/apps/desktop/desktop_native/core/src/ssh_agent/mod.rs @@ -9,6 +9,7 @@ use tokio_util::sync::CancellationToken; use bitwarden_russh::{session_bind::SessionBindResult, ssh_agent::{self, SshKey}}; + #[cfg_attr(target_os = "windows", path = "windows.rs")] #[cfg_attr(target_os = "macos", path = "unix.rs")] #[cfg_attr(target_os = "linux", path = "unix.rs")] @@ -22,6 +23,7 @@ mod request_parser; #[derive(Clone)] pub struct BitwardenDesktopAgent { + key_backend: Arc>>, keystore: ssh_agent::KeyStore, cancellation_token: CancellationToken, show_ui_request_tx: tokio::sync::mpsc::Sender, @@ -43,7 +45,7 @@ pub struct SshAgentUIRequest { #[derive(Clone)] pub struct BitwardenSshKey { - pub private_key: Option, + pub key_backend: Arc>>, pub name: String, pub cipher_uuid: String, } @@ -54,19 +56,21 @@ impl SshKey for BitwardenSshKey { } fn public_key_bytes(&self) -> Vec { - if let Some(ref private_key) = self.private_key { - private_key.public_key().to_bytes().unwrap_or_default() - } else { - Vec::new() - } + let a = self.key_backend.blocking_lock(); + a.get(&self.cipher_uuid) + .expect("Key should be present in the keystore") + .public_key() + .to_bytes() + .expect("Cipher private key is always correctly parsed") } - fn private_key(&self) -> Option> { - if let Some(ref private_key) = self.private_key { - Some(Box::new(private_key.clone())) - } else { - None - } + async fn private_key(&self) -> Option> { + let a = self.key_backend.lock().await; + let p = a.get(&self.cipher_uuid) + .expect("Key should be present in the keystore") + .clone(); + drop(a); + Some(Box::new(p)) } } @@ -204,10 +208,13 @@ impl BitwardenDesktopAgent { .public_key() .to_bytes() .expect("Cipher private key is always correctly parsed"); + println!("setting key: {}", cipher_id); + self.key_backend.blocking_lock().insert(cipher_id.clone(), private_key.clone()); + println!("key backend set key"); keystore.0.write().expect("RwLock is not poisoned").insert( public_key_bytes, BitwardenSshKey { - private_key: Some(private_key), + key_backend: self.key_backend.clone(), name: name.clone(), cipher_uuid: cipher_id.clone(), }, @@ -236,7 +243,6 @@ impl BitwardenDesktopAgent { .expect("RwLock is not poisoned") .iter_mut() .for_each(|(_public_key, key)| { - key.private_key = None; }); Ok(()) } diff --git a/apps/desktop/desktop_native/core/src/ssh_agent/unix.rs b/apps/desktop/desktop_native/core/src/ssh_agent/unix.rs index f2a06fd9512..a04605ffb67 100644 --- a/apps/desktop/desktop_native/core/src/ssh_agent/unix.rs +++ b/apps/desktop/desktop_native/core/src/ssh_agent/unix.rs @@ -23,6 +23,7 @@ impl BitwardenDesktopAgent { auth_response_rx: Arc>>, ) -> Result { let agent = BitwardenDesktopAgent { + key_backend: Arc::new(Mutex::new(crate::alloc::LinuxMemfdSecretBackend::new(crate::alloc::LinuxMemfdSecretAlloc::new().unwrap()))), keystore: ssh_agent::KeyStore(Arc::new(RwLock::new(HashMap::new()))), cancellation_token: CancellationToken::new(), show_ui_request_tx: auth_request_tx,