bitwarden_core/client/
encryption_settings.rs

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