diff --git a/Cargo.lock b/Cargo.lock index 895980c07..5de9f7f42 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -382,6 +382,7 @@ dependencies = [ "uniffi", "uuid", "wasm-bindgen", + "wasm-bindgen-futures", "zeroize", "zxcvbn", ] diff --git a/crates/bitwarden-core/Cargo.toml b/crates/bitwarden-core/Cargo.toml index a846f6edd..db4f16e4b 100644 --- a/crates/bitwarden-core/Cargo.toml +++ b/crates/bitwarden-core/Cargo.toml @@ -24,6 +24,7 @@ uniffi = ["bitwarden-crypto/uniffi", "dep:uniffi"] # Uniffi bindings wasm = [ "bitwarden-error/wasm", "dep:wasm-bindgen", + "dep:wasm-bindgen-futures", "dep:tsify-next" ] # WASM support @@ -50,6 +51,7 @@ tsify-next = { workspace = true, optional = true } uniffi = { workspace = true, optional = true, features = ["tokio"] } uuid = { workspace = true } wasm-bindgen = { workspace = true, optional = true } +wasm-bindgen-futures = { workspace = true, optional = true } zeroize = { version = ">=1.7.0, <2.0", features = ["derive", "aarch64"] } zxcvbn = { version = ">=3.0.1, <4.0", optional = true } diff --git a/crates/bitwarden-core/src/auth/auth_request.rs b/crates/bitwarden-core/src/auth/auth_request.rs index 3a514fbf5..306f2696d 100644 --- a/crates/bitwarden-core/src/auth/auth_request.rs +++ b/crates/bitwarden-core/src/auth/auth_request.rs @@ -140,9 +140,9 @@ mod tests { use bitwarden_crypto::{Kdf, MasterKey}; use super::*; - use crate::{ - key_management::SymmetricKeyId, - mobile::crypto::{AuthRequestMethod, InitUserCryptoMethod, InitUserCryptoRequest}, + use crate::key_management::{ + crypto::{AuthRequestMethod, InitUserCryptoMethod, InitUserCryptoRequest}, + SymmetricKeyId, }; #[test] diff --git a/crates/bitwarden-core/src/auth/login/auth_request.rs b/crates/bitwarden-core/src/auth/login/auth_request.rs index 59b3215c0..d3f8ef4bf 100644 --- a/crates/bitwarden-core/src/auth/login/auth_request.rs +++ b/crates/bitwarden-core/src/auth/login/auth_request.rs @@ -12,7 +12,7 @@ use crate::{ auth_request::new_auth_request, }, client::{LoginMethod, UserLoginMethod}, - mobile::crypto::{AuthRequestMethod, InitUserCryptoMethod, InitUserCryptoRequest}, + key_management::crypto::{AuthRequestMethod, InitUserCryptoMethod, InitUserCryptoRequest}, require, ApiError, Client, }; diff --git a/crates/bitwarden-core/src/client/test_accounts.rs b/crates/bitwarden-core/src/client/test_accounts.rs index 06d4773e0..8555d1989 100644 --- a/crates/bitwarden-core/src/client/test_accounts.rs +++ b/crates/bitwarden-core/src/client/test_accounts.rs @@ -4,10 +4,7 @@ use std::collections::HashMap; use bitwarden_crypto::{EncString, Kdf}; use crate::{ - mobile::crypto::{ - initialize_org_crypto, initialize_user_crypto, InitOrgCryptoRequest, InitUserCryptoMethod, - InitUserCryptoRequest, - }, + key_management::crypto::{InitOrgCryptoRequest, InitUserCryptoMethod, InitUserCryptoRequest}, Client, }; @@ -20,10 +17,14 @@ impl Client { true, )])); - initialize_user_crypto(&client, account.user).await.unwrap(); + client + .crypto() + .initialize_user_crypto(account.user) + .await + .unwrap(); if let Some(org) = account.org { - initialize_org_crypto(&client, org).await.unwrap(); + client.crypto().initialize_org_crypto(org).await.unwrap(); } client diff --git a/crates/bitwarden-core/src/mobile/crypto.rs b/crates/bitwarden-core/src/key_management/crypto.rs similarity index 97% rename from crates/bitwarden-core/src/mobile/crypto.rs rename to crates/bitwarden-core/src/key_management/crypto.rs index d816c7bf4..c5cdba909 100644 --- a/crates/bitwarden-core/src/mobile/crypto.rs +++ b/crates/bitwarden-core/src/key_management/crypto.rs @@ -11,6 +11,8 @@ use bitwarden_crypto::{ AsymmetricCryptoKey, CryptoError, EncString, Kdf, KeyDecryptable, KeyEncryptable, MasterKey, SymmetricCryptoKey, UnsignedSharedKey, UserKey, }; +use bitwarden_error::bitwarden_error; +use schemars::JsonSchema; use serde::{Deserialize, Serialize}; #[cfg(feature = "wasm")] use {tsify_next::Tsify, wasm_bindgen::prelude::*}; @@ -23,8 +25,9 @@ use crate::{ /// Catch all error for mobile crypto operations. #[allow(missing_docs)] +#[bitwarden_error(flat)] #[derive(Debug, thiserror::Error)] -pub enum MobileCryptoError { +pub enum CryptoClientError { #[error(transparent)] NotAuthenticated(#[from] NotAuthenticatedError), #[error(transparent)] @@ -123,7 +126,7 @@ pub enum AuthRequestMethod { } /// Initialize the user's cryptographic state. -pub async fn initialize_user_crypto( +pub(super) async fn initialize_user_crypto( client: &Client, req: InitUserCryptoRequest, ) -> Result<(), EncryptionSettingsError> { @@ -236,7 +239,7 @@ pub struct InitOrgCryptoRequest { } /// Initialize the user's organizational cryptographic state. -pub(crate) async fn initialize_org_crypto( +pub(super) async fn initialize_org_crypto( client: &Client, req: InitOrgCryptoRequest, ) -> Result<(), EncryptionSettingsError> { @@ -245,7 +248,7 @@ pub(crate) async fn initialize_org_crypto( Ok(()) } -pub(super) async fn get_user_encryption_key(client: &Client) -> Result { +pub(super) async fn get_user_encryption_key(client: &Client) -> Result { let key_store = client.internal.get_key_store(); let ctx = key_store.context(); // This is needed because the mobile clients need access to the user encryption key @@ -259,6 +262,7 @@ pub(super) async fn get_user_encryption_key(client: &Client) -> Result Result { +) -> Result { let key_store = client.internal.get_key_store(); let ctx = key_store.context(); // FIXME: [PM-18099] Once MasterKey deals with KeyIds, this should be updated @@ -308,6 +312,7 @@ pub(super) fn update_password( #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase", deny_unknown_fields)] #[cfg_attr(feature = "uniffi", derive(uniffi::Record))] +#[cfg_attr(feature = "wasm", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))] pub struct DerivePinKeyResponse { /// [UserKey] protected by PIN pin_protected_user_key: EncString, @@ -318,7 +323,7 @@ pub struct DerivePinKeyResponse { pub(super) fn derive_pin_key( client: &Client, pin: String, -) -> Result { +) -> Result { let key_store = client.internal.get_key_store(); let ctx = key_store.context(); // FIXME: [PM-18099] Once PinKey deals with KeyIds, this should be updated @@ -341,7 +346,7 @@ pub(super) fn derive_pin_key( pub(super) fn derive_pin_user_key( client: &Client, encrypted_pin: EncString, -) -> Result { +) -> Result { let key_store = client.internal.get_key_store(); let ctx = key_store.context(); // FIXME: [PM-18099] Once PinKey deals with KeyIds, this should be updated @@ -361,7 +366,7 @@ fn derive_pin_protected_user_key( pin: &str, login_method: &LoginMethod, user_key: &SymmetricCryptoKey, -) -> Result { +) -> Result { use bitwarden_crypto::PinKey; let derived_key = match login_method { @@ -377,6 +382,7 @@ fn derive_pin_protected_user_key( } #[allow(missing_docs)] +#[bitwarden_error(flat)] #[derive(Debug, thiserror::Error)] pub enum EnrollAdminPasswordResetError { #[error(transparent)] @@ -408,7 +414,10 @@ pub(super) fn enroll_admin_password_reset( } /// Request for migrating an account from password to key connector. +#[derive(Serialize, Deserialize, Debug, JsonSchema)] +#[serde(rename_all = "camelCase", deny_unknown_fields)] #[cfg_attr(feature = "uniffi", derive(uniffi::Record))] +#[cfg_attr(feature = "wasm", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))] pub struct DeriveKeyConnectorRequest { /// Encrypted user key, used to validate the master key pub user_key_encrypted: EncString, @@ -421,6 +430,7 @@ pub struct DeriveKeyConnectorRequest { } #[allow(missing_docs)] +#[bitwarden_error(flat)] #[derive(Debug, thiserror::Error)] pub enum DeriveKeyConnectorError { #[error(transparent)] diff --git a/crates/bitwarden-core/src/mobile/crypto_client.rs b/crates/bitwarden-core/src/key_management/crypto_client.rs similarity index 87% rename from crates/bitwarden-core/src/mobile/crypto_client.rs rename to crates/bitwarden-core/src/key_management/crypto_client.rs index 42634ce32..9c5bdd440 100644 --- a/crates/bitwarden-core/src/mobile/crypto_client.rs +++ b/crates/bitwarden-core/src/key_management/crypto_client.rs @@ -1,14 +1,16 @@ use bitwarden_crypto::CryptoError; #[cfg(feature = "internal")] use bitwarden_crypto::{EncString, UnsignedSharedKey}; +#[cfg(feature = "wasm")] +use wasm_bindgen::prelude::*; use super::crypto::{ - derive_key_connector, make_key_pair, verify_asymmetric_keys, DeriveKeyConnectorError, - DeriveKeyConnectorRequest, EnrollAdminPasswordResetError, MakeKeyPairResponse, - MobileCryptoError, VerifyAsymmetricKeysRequest, VerifyAsymmetricKeysResponse, + derive_key_connector, make_key_pair, verify_asymmetric_keys, CryptoClientError, + DeriveKeyConnectorError, DeriveKeyConnectorRequest, EnrollAdminPasswordResetError, + MakeKeyPairResponse, VerifyAsymmetricKeysRequest, VerifyAsymmetricKeysResponse, }; #[cfg(feature = "internal")] -use crate::mobile::crypto::{ +use crate::key_management::crypto::{ derive_pin_key, derive_pin_user_key, enroll_admin_password_reset, get_user_encryption_key, initialize_org_crypto, initialize_user_crypto, update_password, DerivePinKeyResponse, InitOrgCryptoRequest, InitUserCryptoRequest, UpdatePasswordResponse, @@ -16,10 +18,12 @@ use crate::mobile::crypto::{ use crate::{client::encryption_settings::EncryptionSettingsError, Client}; /// A client for the crypto operations. +#[cfg_attr(feature = "wasm", wasm_bindgen)] pub struct CryptoClient { pub(crate) client: crate::Client, } +#[cfg_attr(feature = "wasm", wasm_bindgen)] impl CryptoClient { /// Initialization method for the user crypto. Needs to be called before any other crypto /// operations. @@ -39,9 +43,27 @@ impl CryptoClient { initialize_org_crypto(&self.client, req).await } + /// Generates a new key pair and encrypts the private key with the provided user key. + /// Crypto initialization not required. + pub fn make_key_pair(&self, user_key: String) -> Result { + make_key_pair(user_key) + } + + /// Verifies a user's asymmetric keys by decrypting the private key with the provided user + /// key. Returns if the private key is decryptable and if it is a valid matching key. + /// Crypto initialization not required. + pub fn verify_asymmetric_keys( + &self, + request: VerifyAsymmetricKeysRequest, + ) -> Result { + verify_asymmetric_keys(request) + } +} + +impl CryptoClient { /// Get the uses's decrypted encryption key. Note: It's very important /// to keep this key safe, as it can be used to decrypt all of the user's data - pub async fn get_user_encryption_key(&self) -> Result { + pub async fn get_user_encryption_key(&self) -> Result { get_user_encryption_key(&self.client).await } @@ -50,14 +72,14 @@ impl CryptoClient { pub fn update_password( &self, new_password: String, - ) -> Result { + ) -> Result { update_password(&self.client, new_password) } /// Generates a PIN protected user key from the provided PIN. The result can be stored and later /// used to initialize another client instance by using the PIN and the PIN key with /// `initialize_user_crypto`. - pub fn derive_pin_key(&self, pin: String) -> Result { + pub fn derive_pin_key(&self, pin: String) -> Result { derive_pin_key(&self.client, pin) } @@ -66,7 +88,7 @@ impl CryptoClient { pub fn derive_pin_user_key( &self, encrypted_pin: EncString, - ) -> Result { + ) -> Result { derive_pin_user_key(&self.client, encrypted_pin) } @@ -86,21 +108,6 @@ impl CryptoClient { ) -> Result { derive_key_connector(request) } - - /// Generates a new key pair and encrypts the private key with the provided user key. - pub fn make_key_pair(&self, user_key: String) -> Result { - make_key_pair(user_key) - } - - /// Verifies a user's asymmetric keys by decrypting the private key with the provided user - /// key. Returns if the private key is decryptable and if it is a valid matching key. - /// Crypto initialization not required. - pub fn verify_asymmetric_keys( - &self, - request: VerifyAsymmetricKeysRequest, - ) -> Result { - verify_asymmetric_keys(request) - } } impl Client { diff --git a/crates/bitwarden-core/src/key_management/mod.rs b/crates/bitwarden-core/src/key_management/mod.rs index dd13ab21c..394ae5db9 100644 --- a/crates/bitwarden-core/src/key_management/mod.rs +++ b/crates/bitwarden-core/src/key_management/mod.rs @@ -9,6 +9,11 @@ //! [Encryptable](bitwarden_crypto::Encryptable) and [Decryptable](bitwarden_crypto::Encryptable). use bitwarden_crypto::{key_ids, KeyStore, SymmetricCryptoKey}; +pub mod crypto; +mod crypto_client; + +pub use crypto_client::CryptoClient; + key_ids! { #[symmetric] pub enum SymmetricKeyId { diff --git a/crates/bitwarden-core/src/mobile/mod.rs b/crates/bitwarden-core/src/mobile/mod.rs index bdf7e7163..aa6e90a80 100644 --- a/crates/bitwarden-core/src/mobile/mod.rs +++ b/crates/bitwarden-core/src/mobile/mod.rs @@ -3,11 +3,8 @@ //! This module consists of stop-gap functionality for the mobile clients until the SDK owns it's //! own state. -pub mod crypto; mod kdf; mod client_kdf; -mod crypto_client; pub use client_kdf::KdfClient; -pub use crypto_client::CryptoClient; diff --git a/crates/bitwarden-core/tests/register.rs b/crates/bitwarden-core/tests/register.rs index dbca3dd0d..0a275ad17 100644 --- a/crates/bitwarden-core/tests/register.rs +++ b/crates/bitwarden-core/tests/register.rs @@ -7,7 +7,7 @@ async fn test_register_initialize_crypto() { use std::num::NonZeroU32; use bitwarden_core::{ - mobile::crypto::{InitUserCryptoMethod, InitUserCryptoRequest}, + key_management::crypto::{InitUserCryptoMethod, InitUserCryptoRequest}, Client, }; use bitwarden_crypto::Kdf; diff --git a/crates/bitwarden-uniffi/src/crypto.rs b/crates/bitwarden-uniffi/src/crypto.rs index 003cb42c7..56ddb7a73 100644 --- a/crates/bitwarden-uniffi/src/crypto.rs +++ b/crates/bitwarden-uniffi/src/crypto.rs @@ -1,4 +1,4 @@ -use bitwarden_core::mobile::crypto::{ +use bitwarden_core::key_management::crypto::{ DeriveKeyConnectorRequest, DerivePinKeyResponse, InitOrgCryptoRequest, InitUserCryptoRequest, UpdatePasswordResponse, }; @@ -8,7 +8,7 @@ use crate::error::{Error, Result}; #[allow(missing_docs)] #[derive(uniffi::Object)] -pub struct CryptoClient(pub(crate) bitwarden_core::mobile::CryptoClient); +pub struct CryptoClient(pub(crate) bitwarden_core::key_management::CryptoClient); #[uniffi::export(async_runtime = "tokio")] impl CryptoClient { diff --git a/crates/bitwarden-uniffi/src/error.rs b/crates/bitwarden-uniffi/src/error.rs index 9ca9a97b7..3e0ca8db3 100644 --- a/crates/bitwarden-uniffi/src/error.rs +++ b/crates/bitwarden-uniffi/src/error.rs @@ -40,15 +40,17 @@ pub enum Error { #[error(transparent)] Api(#[from] bitwarden_core::ApiError), #[error(transparent)] - DeriveKeyConnector(#[from] bitwarden_core::mobile::crypto::DeriveKeyConnectorError), + DeriveKeyConnector(#[from] bitwarden_core::key_management::crypto::DeriveKeyConnectorError), #[error(transparent)] EncryptionSettings( #[from] bitwarden_core::client::encryption_settings::EncryptionSettingsError, ), #[error(transparent)] - EnrollAdminPasswordReset(#[from] bitwarden_core::mobile::crypto::EnrollAdminPasswordResetError), + EnrollAdminPasswordReset( + #[from] bitwarden_core::key_management::crypto::EnrollAdminPasswordResetError, + ), #[error(transparent)] - MobileCrypto(#[from] bitwarden_core::mobile::crypto::MobileCryptoError), + MobileCrypto(#[from] bitwarden_core::key_management::crypto::CryptoClientError), #[error(transparent)] AuthValidate(#[from] bitwarden_core::auth::AuthValidateError), #[error(transparent)] diff --git a/crates/bitwarden-wasm-internal/src/client.rs b/crates/bitwarden-wasm-internal/src/client.rs index 18adfacb0..d30262be2 100644 --- a/crates/bitwarden-wasm-internal/src/client.rs +++ b/crates/bitwarden-wasm-internal/src/client.rs @@ -1,15 +1,13 @@ extern crate console_error_panic_hook; use std::fmt::Display; -use bitwarden_core::{Client, ClientSettings}; +use bitwarden_core::{key_management::CryptoClient, Client, ClientSettings}; use bitwarden_error::bitwarden_error; use bitwarden_exporters::ExporterClientExt; use bitwarden_generators::GeneratorClientsExt; use bitwarden_vault::{VaultClient, VaultClientExt}; use wasm_bindgen::prelude::*; -use crate::CryptoClient; - #[allow(missing_docs)] #[wasm_bindgen] pub struct BitwardenClient(pub(crate) Client); @@ -47,7 +45,7 @@ impl BitwardenClient { #[allow(missing_docs)] pub fn crypto(&self) -> CryptoClient { - CryptoClient::new(self.0.crypto()) + self.0.crypto() } #[allow(missing_docs)] diff --git a/crates/bitwarden-wasm-internal/src/crypto.rs b/crates/bitwarden-wasm-internal/src/crypto.rs deleted file mode 100644 index 5adb8f5a1..000000000 --- a/crates/bitwarden-wasm-internal/src/crypto.rs +++ /dev/null @@ -1,57 +0,0 @@ -use bitwarden_core::{ - client::encryption_settings::EncryptionSettingsError, - mobile::crypto::{ - InitOrgCryptoRequest, InitUserCryptoRequest, MakeKeyPairResponse, - VerifyAsymmetricKeysRequest, VerifyAsymmetricKeysResponse, - }, -}; -use bitwarden_crypto::CryptoError; -use wasm_bindgen::prelude::*; - -#[allow(missing_docs)] -#[wasm_bindgen] -pub struct CryptoClient(bitwarden_core::mobile::CryptoClient); - -impl CryptoClient { - #[allow(missing_docs)] - pub fn new(client: bitwarden_core::mobile::CryptoClient) -> Self { - Self(client) - } -} - -#[wasm_bindgen] -impl CryptoClient { - /// Initialization method for the user crypto. Needs to be called before any other crypto - /// operations. - pub async fn initialize_user_crypto( - &self, - req: InitUserCryptoRequest, - ) -> Result<(), EncryptionSettingsError> { - self.0.initialize_user_crypto(req).await - } - - /// Initialization method for the organization crypto. Needs to be called after - /// `initialize_user_crypto` but before any other crypto operations. - pub async fn initialize_org_crypto( - &self, - req: InitOrgCryptoRequest, - ) -> Result<(), EncryptionSettingsError> { - self.0.initialize_org_crypto(req).await - } - - /// Generates a new key pair and encrypts the private key with the provided user key. - /// Crypto initialization not required. - pub fn make_key_pair(&self, user_key: String) -> Result { - self.0.make_key_pair(user_key) - } - - /// Verifies a user's asymmetric keys by decrypting the private key with the provided user - /// key. Returns if the private key is decryptable and if it is a valid matching key. - /// Crypto initialization not required. - pub fn verify_asymmetric_keys( - &self, - request: VerifyAsymmetricKeysRequest, - ) -> Result { - self.0.verify_asymmetric_keys(request) - } -} diff --git a/crates/bitwarden-wasm-internal/src/lib.rs b/crates/bitwarden-wasm-internal/src/lib.rs index 81ff14cdd..ac84eeabf 100644 --- a/crates/bitwarden-wasm-internal/src/lib.rs +++ b/crates/bitwarden-wasm-internal/src/lib.rs @@ -1,7 +1,6 @@ #![doc = include_str!("../README.md")] mod client; -mod crypto; mod custom_types; mod init; mod pure_crypto; @@ -9,5 +8,4 @@ mod ssh; pub use bitwarden_ipc::wasm::*; pub use client::BitwardenClient; -pub use crypto::CryptoClient; pub use init::init_sdk;