Skip to content
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

[PM-5693] CryptoService using memfd_secret on Linux #7

Open
wants to merge 42 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 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
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
11 changes: 11 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions crates/bitwarden-crypto/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ uuid = { workspace = true }
wasm-bindgen = { workspace = true, optional = true }
zeroize = { version = ">=1.7.0, <2.0", features = ["derive", "aarch64"] }

[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
memsec = { version = "0.7.0", features = [
"alloc_ext",
], git = "https://github.com/dani-garcia/memsec", rev = "3d2e272d284442637bac0a7d94f76883960db7e2" }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should try and get this merged upstream.


[dev-dependencies]
criterion = "0.5.1"
rand_chacha = "0.3.1"
Expand Down
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 Ref. {0}")]
MissingKey2(String),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MissingKey2 ๐Ÿ˜ญ Will this be removed once we remove all usages of the old interfaces?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, that's removed in the other PR that starts using this code in the rest of the SDK:
https://github.com/bitwarden/sdk-internal/pull/8/files#diff-3a39fb8ed55a85cd232b4ac7681c85bb81462727f6d311b1a4c33be7c5b7f4ed

I didn't want to update it here to avoid needing to touch up code which was going to need to be updated in the other PR anyway

#[error("Crypto store is read-only")]
ReadOnlyCryptoStore,

#[error("Insufficient KDF parameters")]
InsufficientKdfParameters,
Expand Down
238 changes: 238 additions & 0 deletions crates/bitwarden-crypto/src/keys/encryptable.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
use super::key_ref::{AsymmetricKeyRef, KeyRef, SymmetricKeyRef};
use crate::{service::CryptoServiceContext, AsymmetricEncString, CryptoError, EncString};

/// This trait should be implemented by any struct capable of knowing which key it needs
/// to encrypt or decrypt itself.
pub trait UsesKey<Key: KeyRef> {
fn uses_key(&self) -> Key;
}

pub trait Encryptable<
SymmKeyRef: SymmetricKeyRef,
AsymmKeyRef: AsymmetricKeyRef,
Key: KeyRef,
Output,
>
{
fn encrypt(
&self,
ctx: &mut CryptoServiceContext<SymmKeyRef, AsymmKeyRef>,
key: Key,
) -> Result<Output, crate::CryptoError>;
}

pub trait Decryptable<
SymmKeyRef: SymmetricKeyRef,
AsymmKeyRef: AsymmetricKeyRef,
Key: KeyRef,
Output,
>
{
fn decrypt(
&self,
ctx: &mut CryptoServiceContext<SymmKeyRef, AsymmKeyRef>,
key: Key,
) -> Result<Output, crate::CryptoError>;
}

// Basic Encryptable/Decryptable implementations to and from bytes
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should these be doc comments?


impl<SymmKeyRef: SymmetricKeyRef, AsymmKeyRef: AsymmetricKeyRef>
Decryptable<SymmKeyRef, AsymmKeyRef, SymmKeyRef, Vec<u8>> for EncString
{
fn decrypt(
&self,
ctx: &mut CryptoServiceContext<SymmKeyRef, AsymmKeyRef>,
key: SymmKeyRef,
) -> Result<Vec<u8>, crate::CryptoError> {
ctx.decrypt_data_with_symmetric_key(key, self)
}

Check warning on line 49 in crates/bitwarden-crypto/src/keys/encryptable.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-crypto/src/keys/encryptable.rs#L43-L49

Added lines #L43 - L49 were not covered by tests
}

impl<SymmKeyRef: SymmetricKeyRef, AsymmKeyRef: AsymmetricKeyRef>
Decryptable<SymmKeyRef, AsymmKeyRef, AsymmKeyRef, Vec<u8>> for AsymmetricEncString
{
fn decrypt(
&self,
ctx: &mut CryptoServiceContext<SymmKeyRef, AsymmKeyRef>,
key: AsymmKeyRef,
) -> Result<Vec<u8>, crate::CryptoError> {
ctx.decrypt_data_with_asymmetric_key(key, self)
}

Check warning on line 61 in crates/bitwarden-crypto/src/keys/encryptable.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-crypto/src/keys/encryptable.rs#L55-L61

Added lines #L55 - L61 were not covered by tests
}

impl<SymmKeyRef: SymmetricKeyRef, AsymmKeyRef: AsymmetricKeyRef>
Encryptable<SymmKeyRef, AsymmKeyRef, SymmKeyRef, EncString> for &[u8]
{
fn encrypt(
&self,
ctx: &mut CryptoServiceContext<SymmKeyRef, AsymmKeyRef>,
key: SymmKeyRef,
) -> Result<EncString, crate::CryptoError> {
ctx.encrypt_data_with_symmetric_key(key, self)
}

Check warning on line 73 in crates/bitwarden-crypto/src/keys/encryptable.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-crypto/src/keys/encryptable.rs#L67-L73

Added lines #L67 - L73 were not covered by tests
}

impl<SymmKeyRef: SymmetricKeyRef, AsymmKeyRef: AsymmetricKeyRef>
Encryptable<SymmKeyRef, AsymmKeyRef, AsymmKeyRef, AsymmetricEncString> for &[u8]
{
fn encrypt(
&self,
ctx: &mut CryptoServiceContext<SymmKeyRef, AsymmKeyRef>,
key: AsymmKeyRef,
) -> Result<AsymmetricEncString, crate::CryptoError> {
ctx.encrypt_data_with_asymmetric_key(key, self)
}

Check warning on line 85 in crates/bitwarden-crypto/src/keys/encryptable.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-crypto/src/keys/encryptable.rs#L79-L85

Added lines #L79 - L85 were not covered by tests
}

// Encryptable/Decryptable implementations to and from strings

impl<SymmKeyRef: SymmetricKeyRef, AsymmKeyRef: AsymmetricKeyRef>
Decryptable<SymmKeyRef, AsymmKeyRef, SymmKeyRef, String> for EncString
{
fn decrypt(
&self,
ctx: &mut CryptoServiceContext<SymmKeyRef, AsymmKeyRef>,
key: SymmKeyRef,
) -> Result<String, crate::CryptoError> {
let bytes: Vec<u8> = self.decrypt(ctx, key)?;
String::from_utf8(bytes).map_err(|_| CryptoError::InvalidUtf8String)
}

Check warning on line 100 in crates/bitwarden-crypto/src/keys/encryptable.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-crypto/src/keys/encryptable.rs#L93-L100

Added lines #L93 - L100 were not covered by tests
}

impl<SymmKeyRef: SymmetricKeyRef, AsymmKeyRef: AsymmetricKeyRef>
Decryptable<SymmKeyRef, AsymmKeyRef, AsymmKeyRef, String> for AsymmetricEncString
{
fn decrypt(
&self,
ctx: &mut CryptoServiceContext<SymmKeyRef, AsymmKeyRef>,
key: AsymmKeyRef,
) -> Result<String, crate::CryptoError> {
let bytes: Vec<u8> = self.decrypt(ctx, key)?;
String::from_utf8(bytes).map_err(|_| CryptoError::InvalidUtf8String)
}

Check warning on line 113 in crates/bitwarden-crypto/src/keys/encryptable.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-crypto/src/keys/encryptable.rs#L106-L113

Added lines #L106 - L113 were not covered by tests
}

impl<SymmKeyRef: SymmetricKeyRef, AsymmKeyRef: AsymmetricKeyRef>
Encryptable<SymmKeyRef, AsymmKeyRef, SymmKeyRef, EncString> for &str
{
fn encrypt(
&self,
ctx: &mut CryptoServiceContext<SymmKeyRef, AsymmKeyRef>,
key: SymmKeyRef,
) -> Result<EncString, crate::CryptoError> {
self.as_bytes().encrypt(ctx, key)
}

Check warning on line 125 in crates/bitwarden-crypto/src/keys/encryptable.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-crypto/src/keys/encryptable.rs#L119-L125

Added lines #L119 - L125 were not covered by tests
}

impl<SymmKeyRef: SymmetricKeyRef, AsymmKeyRef: AsymmetricKeyRef>
Encryptable<SymmKeyRef, AsymmKeyRef, AsymmKeyRef, AsymmetricEncString> for &str
{
fn encrypt(
&self,
ctx: &mut CryptoServiceContext<SymmKeyRef, AsymmKeyRef>,
key: AsymmKeyRef,
) -> Result<AsymmetricEncString, crate::CryptoError> {
self.as_bytes().encrypt(ctx, key)
}

Check warning on line 137 in crates/bitwarden-crypto/src/keys/encryptable.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-crypto/src/keys/encryptable.rs#L131-L137

Added lines #L131 - L137 were not covered by tests
}

impl<SymmKeyRef: SymmetricKeyRef, AsymmKeyRef: AsymmetricKeyRef>
Encryptable<SymmKeyRef, AsymmKeyRef, SymmKeyRef, EncString> for String
{
fn encrypt(
&self,
ctx: &mut CryptoServiceContext<SymmKeyRef, AsymmKeyRef>,
key: SymmKeyRef,
) -> Result<EncString, crate::CryptoError> {
self.as_bytes().encrypt(ctx, key)
}

Check warning on line 149 in crates/bitwarden-crypto/src/keys/encryptable.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-crypto/src/keys/encryptable.rs#L143-L149

Added lines #L143 - L149 were not covered by tests
}

impl<SymmKeyRef: SymmetricKeyRef, AsymmKeyRef: AsymmetricKeyRef>
Encryptable<SymmKeyRef, AsymmKeyRef, AsymmKeyRef, AsymmetricEncString> for String
{
fn encrypt(
&self,
ctx: &mut CryptoServiceContext<SymmKeyRef, AsymmKeyRef>,
key: AsymmKeyRef,
) -> Result<AsymmetricEncString, crate::CryptoError> {
self.as_bytes().encrypt(ctx, key)
}

Check warning on line 161 in crates/bitwarden-crypto/src/keys/encryptable.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-crypto/src/keys/encryptable.rs#L155-L161

Added lines #L155 - L161 were not covered by tests
}

// Generic implementations for Optional values

impl<
SymmKeyRef: SymmetricKeyRef,
AsymmKeyRef: AsymmetricKeyRef,
Key: KeyRef,
T: Encryptable<SymmKeyRef, AsymmKeyRef, Key, Output>,
Output,
> Encryptable<SymmKeyRef, AsymmKeyRef, Key, Option<Output>> for Option<T>
{
fn encrypt(
&self,
ctx: &mut CryptoServiceContext<SymmKeyRef, AsymmKeyRef>,
key: Key,
) -> Result<Option<Output>, crate::CryptoError> {
self.as_ref()
.map(|value| value.encrypt(ctx, key))
.transpose()
}

Check warning on line 182 in crates/bitwarden-crypto/src/keys/encryptable.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-crypto/src/keys/encryptable.rs#L174-L182

Added lines #L174 - L182 were not covered by tests
}

impl<
SymmKeyRef: SymmetricKeyRef,
AsymmKeyRef: AsymmetricKeyRef,
Key: KeyRef,
T: Decryptable<SymmKeyRef, AsymmKeyRef, Key, Output>,
Output,
> Decryptable<SymmKeyRef, AsymmKeyRef, Key, Option<Output>> for Option<T>
{
fn decrypt(
&self,
ctx: &mut CryptoServiceContext<SymmKeyRef, AsymmKeyRef>,
key: Key,
) -> Result<Option<Output>, crate::CryptoError> {
self.as_ref()
.map(|value| value.decrypt(ctx, key))
.transpose()
}

Check warning on line 201 in crates/bitwarden-crypto/src/keys/encryptable.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-crypto/src/keys/encryptable.rs#L193-L201

Added lines #L193 - L201 were not covered by tests
}

// Generic implementations for Vec values

impl<
SymmKeyRef: SymmetricKeyRef,
AsymmKeyRef: AsymmetricKeyRef,
Key: KeyRef,
T: Encryptable<SymmKeyRef, AsymmKeyRef, Key, Output>,
Output,
> Encryptable<SymmKeyRef, AsymmKeyRef, Key, Vec<Output>> for Vec<T>
{
fn encrypt(
&self,
ctx: &mut CryptoServiceContext<SymmKeyRef, AsymmKeyRef>,
key: Key,
) -> Result<Vec<Output>, crate::CryptoError> {
self.iter().map(|value| value.encrypt(ctx, key)).collect()
}

Check warning on line 220 in crates/bitwarden-crypto/src/keys/encryptable.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-crypto/src/keys/encryptable.rs#L214-L220

Added lines #L214 - L220 were not covered by tests
}

impl<
SymmKeyRef: SymmetricKeyRef,
AsymmKeyRef: AsymmetricKeyRef,
Key: KeyRef,
T: Decryptable<SymmKeyRef, AsymmKeyRef, Key, Output>,
Output,
> Decryptable<SymmKeyRef, AsymmKeyRef, Key, Vec<Output>> for Vec<T>
{
fn decrypt(
&self,
ctx: &mut CryptoServiceContext<SymmKeyRef, AsymmKeyRef>,
key: Key,
) -> Result<Vec<Output>, crate::CryptoError> {
self.iter().map(|value| value.decrypt(ctx, key)).collect()
}

Check warning on line 237 in crates/bitwarden-crypto/src/keys/encryptable.rs

View check run for this annotation

Codecov / codecov/patch

crates/bitwarden-crypto/src/keys/encryptable.rs#L231-L237

Added lines #L231 - L237 were not covered by tests
}
89 changes: 89 additions & 0 deletions crates/bitwarden-crypto/src/keys/key_ref.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
use crate::{AsymmetricCryptoKey, SymmetricCryptoKey};

// Hide the `KeyRef` trait from the public API, to avoid confusion
// the trait itself needs to be public to reference it in the macro, so wrap it in a hidden module
#[doc(hidden)]
pub mod __internal {
use std::{fmt::Debug, hash::Hash};

use zeroize::ZeroizeOnDrop;

use crate::CryptoKey;

/// This trait represents a key reference that can be used to identify cryptographic keys in the
/// key store. It is used to abstract over the different types of keys that can be used in
/// the system, an end user would not implement this trait directly, and would instead use
/// the `SymmetricKeyRef` and `AsymmetricKeyRef` traits.
pub trait KeyRef:
Debug + Clone + Copy + Hash + Eq + PartialEq + Ord + PartialOrd + Send + Sync + 'static
{
type KeyValue: CryptoKey + Send + Sync + ZeroizeOnDrop;

/// Returns whether the key is local to the current context or shared globally by the
/// service.
fn is_local(&self) -> bool;
}
}
pub(crate) use __internal::KeyRef;

// These traits below are just basic aliases of the `KeyRef` trait, but they allow us to have two
// separate trait bounds

pub trait SymmetricKeyRef: KeyRef<KeyValue = SymmetricCryptoKey> {}
pub trait AsymmetricKeyRef: KeyRef<KeyValue = AsymmetricCryptoKey> {}

// Just a small derive_like macro that can be used to generate the key reference enums.
// Example usage:
// ```rust
// key_refs! {
// #[symmetric]
// pub enum KeyRef {
// User,
// Org(Uuid),
// #[local]
// Local(String),
// }
// }
#[macro_export]
macro_rules! key_refs {
( $(
#[$meta_type:tt]
$(pub)? enum $name:ident {
$(
$( #[$variant_tag:tt] )?
$variant:ident $( ( $inner:ty ) )?
,)+
}
)+ ) => { $(
#[derive(std::fmt::Debug, Clone, Copy, std::hash::Hash, Eq, PartialEq, Ord, PartialOrd)]
pub enum $name { $(
$variant $( ($inner) )?
,)+ }

impl $crate::key_ref::__internal::KeyRef for $name {
type KeyValue = key_refs!(@key_type $meta_type);

fn is_local(&self) -> bool {
use $name::*;
match self { $(
key_refs!(@variant_match $variant $( ( $inner ) )?) =>
key_refs!(@variant_tag $( $variant_tag )? ),
)+ }
}
}

key_refs!(@key_trait $meta_type $name);
)+ };

( @key_type symmetric ) => { $crate::SymmetricCryptoKey };
( @key_type asymmetric ) => { $crate::AsymmetricCryptoKey };

( @key_trait symmetric $name:ident ) => { impl $crate::key_ref::SymmetricKeyRef for $name {} };
( @key_trait asymmetric $name:ident ) => { impl $crate::key_ref::AsymmetricKeyRef for $name {} };

( @variant_match $variant:ident ( $inner:ty ) ) => { $variant (_) };
( @variant_match $variant:ident ) => { $variant };

( @variant_tag local ) => { true };
( @variant_tag ) => { false };
}
5 changes: 5 additions & 0 deletions crates/bitwarden-crypto/src/keys/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
mod key_encryptable;
pub use key_encryptable::{CryptoKey, KeyContainer, KeyDecryptable, KeyEncryptable, LocateKey};
mod encryptable;
pub use encryptable::{Decryptable, Encryptable, UsesKey};
pub mod key_ref;
pub(crate) use key_ref::KeyRef;
pub use key_ref::{AsymmetricKeyRef, SymmetricKeyRef};
mod master_key;
pub use master_key::{
default_argon2_iterations, default_argon2_memory, default_argon2_parallelism,
Expand Down
1 change: 1 addition & 0 deletions crates/bitwarden-crypto/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ mod wordlist;
pub use wordlist::EFF_LONG_WORD_LIST;
mod allocator;
pub use allocator::ZeroizingAllocator;
pub mod service;

#[cfg(feature = "uniffi")]
uniffi::setup_scaffolding!();
Expand Down
Loading
Loading