bitwarden_core/client/
encryption_settings.rs

1#[cfg(feature = "internal")]
2use bitwarden_crypto::{AsymmetricCryptoKey, EncString, UnsignedSharedKey};
3#[cfg(any(feature = "internal", feature = "secrets"))]
4use bitwarden_crypto::{KeyStore, SymmetricCryptoKey};
5use bitwarden_error::bitwarden_error;
6use thiserror::Error;
7#[cfg(any(feature = "internal", feature = "secrets"))]
8use uuid::Uuid;
9
10#[cfg(feature = "internal")]
11use crate::key_management::AsymmetricKeyId;
12#[cfg(any(feature = "internal", feature = "secrets"))]
13use crate::key_management::{KeyIds, SymmetricKeyId};
14use crate::{error::UserIdAlreadySetError, MissingPrivateKeyError, VaultLockedError};
15
16#[bitwarden_error(flat)]
17#[derive(Debug, Error)]
18pub enum EncryptionSettingsError {
19    #[error("Cryptography error, {0}")]
20    Crypto(#[from] bitwarden_crypto::CryptoError),
21
22    #[error(transparent)]
23    InvalidBase64(#[from] base64::DecodeError),
24
25    #[error(transparent)]
26    VaultLocked(#[from] VaultLockedError),
27
28    #[error("Invalid private key")]
29    InvalidPrivateKey,
30
31    #[error(transparent)]
32    MissingPrivateKey(#[from] MissingPrivateKeyError),
33
34    #[error(transparent)]
35    UserIdAlreadySetError(#[from] UserIdAlreadySetError),
36}
37
38pub struct EncryptionSettings {}
39
40impl EncryptionSettings {
41    /// Initialize the encryption settings with the decrypted user key and the encrypted user
42    /// private key This should only be used when unlocking the vault via biometrics or when the
43    /// vault is set to lock: "never" Otherwise handling the decrypted user key is dangerous and
44    /// discouraged
45    #[cfg(feature = "internal")]
46    pub(crate) fn new_decrypted_key(
47        user_key: SymmetricCryptoKey,
48        private_key: EncString,
49        store: &KeyStore<KeyIds>,
50    ) -> Result<(), EncryptionSettingsError> {
51        use bitwarden_crypto::KeyDecryptable;
52        use log::warn;
53
54        use crate::key_management::{AsymmetricKeyId, SymmetricKeyId};
55
56        let private_key = {
57            let dec: Vec<u8> = private_key.decrypt_with_key(&user_key)?;
58
59            // FIXME: [PM-11690] - Temporarily ignore invalid private keys until we have a recovery
60            // process in place.
61            AsymmetricCryptoKey::from_der(&dec)
62                .map_err(|_| {
63                    warn!("Invalid private key");
64                })
65                .ok()
66
67            // Some(
68            //     AsymmetricCryptoKey::from_der(&dec)
69            //         .map_err(|_| EncryptionSettingsError::InvalidPrivateKey)?,
70            // )
71        };
72
73        // FIXME: [PM-18098] When this is part of crypto we won't need to use deprecated methods
74        #[allow(deprecated)]
75        {
76            let mut ctx = store.context_mut();
77            ctx.set_symmetric_key(SymmetricKeyId::User, user_key)?;
78            if let Some(private_key) = private_key {
79                ctx.set_asymmetric_key(AsymmetricKeyId::UserPrivateKey, private_key)?;
80            }
81        }
82
83        Ok(())
84    }
85
86    /// Initialize the encryption settings with only a single decrypted organization key.
87    /// This is used only for logging in Secrets Manager with an access token
88    #[cfg(feature = "secrets")]
89    pub(crate) fn new_single_org_key(
90        organization_id: Uuid,
91        key: SymmetricCryptoKey,
92        store: &KeyStore<KeyIds>,
93    ) {
94        // FIXME: [PM-18098] When this is part of crypto we won't need to use deprecated methods
95        #[allow(deprecated)]
96        store
97            .context_mut()
98            .set_symmetric_key(SymmetricKeyId::Organization(organization_id), key)
99            .expect("Mutable context");
100    }
101
102    #[cfg(feature = "internal")]
103    pub(crate) fn set_org_keys(
104        org_enc_keys: Vec<(Uuid, UnsignedSharedKey)>,
105        store: &KeyStore<KeyIds>,
106    ) -> Result<(), EncryptionSettingsError> {
107        let mut ctx = store.context_mut();
108
109        // FIXME: [PM-11690] - Early abort to handle private key being corrupt
110        if org_enc_keys.is_empty() {
111            return Ok(());
112        }
113
114        if !ctx.has_asymmetric_key(AsymmetricKeyId::UserPrivateKey) {
115            return Err(MissingPrivateKeyError.into());
116        }
117
118        // Make sure we only keep the keys given in the arguments and not any of the previous
119        // ones, which might be from organizations that the user is no longer a part of anymore
120        ctx.retain_symmetric_keys(|key_ref| !matches!(key_ref, SymmetricKeyId::Organization(_)));
121
122        // Decrypt the org keys with the private key
123        for (org_id, org_enc_key) in org_enc_keys {
124            ctx.decapsulate_key_unsigned(
125                AsymmetricKeyId::UserPrivateKey,
126                SymmetricKeyId::Organization(org_id),
127                &org_enc_key,
128            )?;
129        }
130
131        Ok(())
132    }
133}