Skip to content

[PM-5693] KeyStore implementation #7

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weโ€™ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 79 commits into from
Feb 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
79 commits
Select commit Hold shift + click to select a range
d7c7c3e
Initial CryptoService impl
dani-garcia Jul 26, 2024
6068e84
More work
dani-garcia Aug 23, 2024
50dc1b4
Refactor keystore to also handle resizes
dani-garcia Aug 23, 2024
216eb25
Merge branch 'main' into ps/secure-crypto-service
dani-garcia Aug 23, 2024
4b846ed
Fix
dani-garcia Aug 23, 2024
7a01168
Paralelization plus alternative to locatekey
dani-garcia Aug 23, 2024
c649bf0
WASM support
dani-garcia Aug 23, 2024
b901ef7
Merge branch 'main' into ps/secure-crypto-service
dani-garcia Sep 20, 2024
e2129ad
Remove unnecessary trait
dani-garcia Sep 23, 2024
f708fcc
Inline cryptoengine
dani-garcia Sep 23, 2024
30854f7
Impl KeyStore in Slice struct directly
dani-garcia Sep 23, 2024
bed894a
Reset the values to None after munlock has zeroized them
dani-garcia Sep 23, 2024
709dfce
Merge branch 'main' into ps/secure-crypto-service
dani-garcia Sep 23, 2024
f7eda88
Fmt
dani-garcia Sep 23, 2024
ce2343e
Add benchmark
dani-garcia Sep 24, 2024
bcd712f
Respect no-memory-hardening flag
dani-garcia Sep 24, 2024
38343d2
Fix cfg flags, silence warnings
dani-garcia Sep 24, 2024
f34ce02
Export memfd correctly
dani-garcia Sep 24, 2024
cc27320
Fix memtest
dani-garcia Sep 24, 2024
281619d
Merge branch 'main' into ps/secure-crypto-service
dani-garcia Sep 24, 2024
32d298f
Try fat LTO to fix windows
dani-garcia Sep 24, 2024
c43aa08
Disable memsec on windows to fix it
dani-garcia Sep 24, 2024
dd37d1d
Incorrect optional dep
dani-garcia Sep 24, 2024
45f3d32
Try updating windows in memsec
dani-garcia Sep 24, 2024
1f70169
Remove unnecessary bound
dani-garcia Sep 25, 2024
22a8b17
Move store impl around a bit
dani-garcia Sep 25, 2024
c63f656
Make KeyStore pub
dani-garcia Sep 25, 2024
db3f8d4
Merge branch 'main' into ps/secure-crypto-service-impl
dani-garcia Oct 2, 2024
eb81684
Some renames/simplifications
dani-garcia Oct 2, 2024
d279626
Add some missing implementations
dani-garcia Oct 2, 2024
d5f1ede
Rename
dani-garcia Oct 3, 2024
8652d79
Introduce mutable context
dani-garcia Oct 3, 2024
fdb0263
Refactor keyref/encryptable locations
dani-garcia Oct 4, 2024
6ea6267
Some additions needed to migrate the code
dani-garcia Oct 7, 2024
32088c7
Merge branch 'main' into ps/secure-crypto-service
dani-garcia Oct 7, 2024
f882fb2
Remove bench
dani-garcia Oct 7, 2024
bec4786
Remove using
dani-garcia Oct 7, 2024
c2ffea6
Fix TODO
dani-garcia Oct 8, 2024
c0d2b63
Comment
dani-garcia Oct 8, 2024
cacf4db
Merge branch 'main' into ps/secure-crypto-service
dani-garcia Oct 8, 2024
f4ca816
Fmt
dani-garcia Oct 8, 2024
748ba75
Merge branch 'main' into ps/secure-crypto-service
dani-garcia Oct 22, 2024
713ec80
Merge branch 'main' into ps/secure-crypto-service
dani-garcia Nov 4, 2024
8f8e378
Merge branch 'main' into ps/secure-crypto-service
dani-garcia Dec 11, 2024
14485e8
Documentation improvements, renames and refactors
dani-garcia Dec 12, 2024
84c0aca
Fmt
dani-garcia Dec 12, 2024
f38398e
Fix lints and tests
dani-garcia Dec 12, 2024
fada9c1
Search/replace was a bit too powerful hah
dani-garcia Dec 12, 2024
f9ed542
Fix doclink
dani-garcia Dec 12, 2024
e7bfdc3
Add some more comments about why we're doing the custom slice
dani-garcia Dec 12, 2024
34b256e
Add context doc
dani-garcia Dec 12, 2024
fe6b28f
Add more tests
dani-garcia Dec 14, 2024
45c9ee2
Add more docs
dani-garcia Dec 16, 2024
ad8ed59
Merge branch 'main' into ps/secure-crypto-service
dani-garcia Dec 16, 2024
75b97fa
Fix wrong test
dani-garcia Dec 16, 2024
33ec078
Merge branch 'main' into ps/secure-crypto-service
dani-garcia Dec 16, 2024
275574f
Add ignore dep
dani-garcia Dec 16, 2024
1d8911a
Merge branch 'main' into ps/secure-crypto-service
dani-garcia Jan 20, 2025
b969352
Split backend implementations to a separate PR
dani-garcia Jan 20, 2025
8fddf86
MissingKey2 -> MissingKeyRef
dani-garcia Jan 20, 2025
f03ba9e
Change visibilities
dani-garcia Jan 20, 2025
f8c8427
Upsert + docs
dani-garcia Jan 20, 2025
fb34e6c
Fmt
dani-garcia Jan 20, 2025
7a1dc2d
KeyRef->KeyId
dani-garcia Jan 21, 2025
67c32fa
Reorganize traits and split encryptable
dani-garcia Jan 21, 2025
2360396
UsesKey -> IdentifyKey
dani-garcia Jan 21, 2025
4e690e6
Merge branch 'main' into ps/secure-crypto-service
dani-garcia Jan 21, 2025
4e6b707
Add default impl for KeyStore
dani-garcia Jan 21, 2025
cc1c27e
Add decryptable/encryptable tests
dani-garcia Jan 21, 2025
a2afdf3
Fmt
dani-garcia Jan 21, 2025
5fa459d
Fix test and add docs
dani-garcia Jan 21, 2025
628e81b
Add context usage docs
dani-garcia Jan 22, 2025
548ccc4
Merge branch 'main' into ps/secure-crypto-service
dani-garcia Jan 28, 2025
9bd664b
Doc updates
dani-garcia Jan 28, 2025
8a37052
Merge branch 'main' into ps/secure-crypto-service
dani-garcia Feb 3, 2025
379c581
Mod docs
dani-garcia Feb 3, 2025
24b5ed7
Make context clear local only
dani-garcia Feb 3, 2025
7e6f7a2
clear -> clear_local
dani-garcia Feb 3, 2025
65b7d4f
Merge branch 'main' into ps/secure-crypto-service
dani-garcia Feb 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions crates/bitwarden-crypto/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ pub enum CryptoError {
MissingKey(Uuid),
#[error("The item was missing a required field: {0}")]
MissingField(&'static str),
#[error("Missing Key for Id: {0}")]
MissingKeyId(String),
#[error("Crypto store is read-only")]
ReadOnlyKeyStore,

#[error("Insufficient KDF parameters")]
InsufficientKdfParameters,
Expand Down
4 changes: 4 additions & 0 deletions crates/bitwarden-crypto/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,10 @@ mod util;
pub use util::{generate_random_alphanumeric, generate_random_bytes, pbkdf2};
mod wordlist;
pub use wordlist::EFF_LONG_WORD_LIST;
mod store;
pub use store::{KeyStore, KeyStoreContext};
mod traits;
pub use traits::{Decryptable, Encryptable, IdentifyKey, KeyId, KeyIds};
pub use zeroizing_alloc::ZeroAlloc as ZeroizingAllocator;

#[cfg(feature = "uniffi")]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
use zeroize::ZeroizeOnDrop;

use crate::{store::backend::StoreBackend, KeyId};

/// This is a basic key store backend that stores keys in a HashMap memory.
/// No protections are provided for the keys stored in this backend, beyond enforcing
/// zeroization on drop.
pub(crate) struct BasicBackend<Key: KeyId> {
keys: std::collections::HashMap<Key, Key::KeyValue>,
}

impl<Key: KeyId> BasicBackend<Key> {
pub fn new() -> Self {
Self {
keys: std::collections::HashMap::new(),
}
}
}

impl<Key: KeyId> StoreBackend<Key> for BasicBackend<Key> {
fn upsert(&mut self, key_id: Key, key: <Key as KeyId>::KeyValue) {
self.keys.insert(key_id, key);
}

fn get(&self, key_id: Key) -> Option<&<Key as KeyId>::KeyValue> {
self.keys.get(&key_id)
}

fn remove(&mut self, key_id: Key) {
self.keys.remove(&key_id);
}

Check warning on line 31 in crates/bitwarden-crypto/src/store/backend/implementation/basic.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-crypto/src/store/backend/implementation/basic.rs#L29-L31

Added lines #L29 - L31 were not covered by tests

fn clear(&mut self) {
self.keys.clear();
}

fn retain(&mut self, f: fn(Key) -> bool) {
self.keys.retain(|k, _| f(*k));
}

Check warning on line 39 in crates/bitwarden-crypto/src/store/backend/implementation/basic.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-crypto/src/store/backend/implementation/basic.rs#L37-L39

Added lines #L37 - L39 were not covered by tests
}

/// [KeyId::KeyValue] already implements [ZeroizeOnDrop],
/// so we only need to ensure the map is cleared on drop.
impl<Key: KeyId> ZeroizeOnDrop for BasicBackend<Key> {}
impl<Key: KeyId> Drop for BasicBackend<Key> {
fn drop(&mut self) {
self.clear();
}
}
28 changes: 28 additions & 0 deletions crates/bitwarden-crypto/src/store/backend/implementation/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use super::StoreBackend;
use crate::store::KeyId;

mod basic;

/// Initializes a key store backend with the best available implementation for the current platform
pub fn create_store<Key: KeyId>() -> Box<dyn StoreBackend<Key>> {
Box::new(basic::BasicBackend::<Key>::new())
}

#[cfg(test)]
mod tests {
use super::*;
use crate::{traits::tests::TestSymmKey, SymmetricCryptoKey};

#[test]
fn test_creates_a_valid_store() {
let mut store = create_store::<TestSymmKey>();

let key = SymmetricCryptoKey::generate(rand::thread_rng());
store.upsert(TestSymmKey::A(0), key.clone());

assert_eq!(
store.get(TestSymmKey::A(0)).unwrap().to_base64(),
key.to_base64()
);
}
}
38 changes: 38 additions & 0 deletions crates/bitwarden-crypto/src/store/backend/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
use zeroize::ZeroizeOnDrop;

use crate::store::KeyId;

mod implementation;

pub use implementation::create_store;

/// This trait represents a platform that can store and return keys. If possible,
/// it will try to enable as many security protections on the keys as it can.
/// The keys themselves implement [ZeroizeOnDrop], so the store will only need to make sure
/// that the keys are dropped when they are no longer needed.
///
/// The default implementation is a basic in-memory store that does not provide any security
/// guarantees.
///
/// We have other implementations in testing using `mlock` and `memfd_secret` for protecting keys in
/// memory.
///
/// Other implementations could use secure enclaves, HSMs or OS provided keychains.
pub trait StoreBackend<Key: KeyId>: ZeroizeOnDrop + Send + Sync {
/// Inserts a key into the store. If the key already exists, it will be replaced.
fn upsert(&mut self, key_id: Key, key: Key::KeyValue);

/// Retrieves a key from the store.
fn get(&self, key_id: Key) -> Option<&Key::KeyValue>;

#[allow(unused)]
/// Removes a key from the store.
fn remove(&mut self, key_id: Key);

/// Removes all keys from the store.
fn clear(&mut self);

/// Retains only the elements specified by the predicate.
/// In other words, remove all keys for which `f` returns false.
fn retain(&mut self, f: fn(Key) -> bool);
}
Loading