bitwarden_core/client/
encryption_settings.rs

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