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("Invalid signing key")]
31    InvalidSigningKey,
32
33    #[error(transparent)]
34    MissingPrivateKey(#[from] MissingPrivateKeyError),
35
36    #[error(transparent)]
37    UserIdAlreadySetError(#[from] UserIdAlreadySetError),
38}
39
40#[allow(missing_docs)]
41pub struct EncryptionSettings {}
42
43impl EncryptionSettings {
44    /// Initialize the encryption settings with the decrypted user key and the encrypted user
45    /// private key This should only be used when unlocking the vault via biometrics or when the
46    /// vault is set to lock: "never" Otherwise handling the decrypted user key is dangerous and
47    /// discouraged
48    #[cfg(feature = "internal")]
49    pub(crate) fn new_decrypted_key(
50        user_key: SymmetricCryptoKey,
51        private_key: EncString,
52        signing_key: Option<EncString>,
53        store: &KeyStore<KeyIds>,
54    ) -> Result<(), EncryptionSettingsError> {
55        use bitwarden_crypto::{AsymmetricCryptoKey, CoseSerializable, KeyDecryptable, SigningKey};
56        use log::warn;
57
58        use crate::key_management::{AsymmetricKeyId, SigningKeyId, SymmetricKeyId};
59
60        let private_key = {
61            let dec: Vec<u8> = private_key.decrypt_with_key(&user_key)?;
62            // FIXME: [PM-11690] - Temporarily ignore invalid private keys until we have a recovery
63            // process in place.
64            AsymmetricCryptoKey::from_der(&dec.into())
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                use bitwarden_crypto::CryptoError;
78
79                let dec: Vec<u8> = key.decrypt_with_key(&user_key)?;
80                SigningKey::from_cose(&dec.into()).map_err(Into::<CryptoError>::into)
81            })
82            .transpose()?;
83
84        // FIXME: [PM-18098] When this is part of crypto we won't need to use deprecated methods
85        #[allow(deprecated)]
86        {
87            let mut ctx = store.context_mut();
88            ctx.set_symmetric_key(SymmetricKeyId::User, user_key)?;
89            if let Some(private_key) = private_key {
90                ctx.set_asymmetric_key(AsymmetricKeyId::UserPrivateKey, private_key)?;
91            }
92
93            if let Some(signing_key) = signing_key {
94                ctx.set_signing_key(SigningKeyId::UserSigningKey, signing_key)?;
95            }
96        }
97
98        Ok(())
99    }
100
101    /// Initialize the encryption settings with only a single decrypted organization key.
102    /// This is used only for logging in Secrets Manager with an access token
103    #[cfg(feature = "secrets")]
104    pub(crate) fn new_single_org_key(
105        organization_id: Uuid,
106        key: SymmetricCryptoKey,
107        store: &KeyStore<KeyIds>,
108    ) {
109        // FIXME: [PM-18098] When this is part of crypto we won't need to use deprecated methods
110        #[allow(deprecated)]
111        store
112            .context_mut()
113            .set_symmetric_key(SymmetricKeyId::Organization(organization_id), key)
114            .expect("Mutable context");
115    }
116
117    #[cfg(feature = "internal")]
118    pub(crate) fn set_org_keys(
119        org_enc_keys: Vec<(Uuid, UnsignedSharedKey)>,
120        store: &KeyStore<KeyIds>,
121    ) -> Result<(), EncryptionSettingsError> {
122        use crate::key_management::AsymmetricKeyId;
123
124        let mut ctx = store.context_mut();
125
126        // FIXME: [PM-11690] - Early abort to handle private key being corrupt
127        if org_enc_keys.is_empty() {
128            return Ok(());
129        }
130
131        if !ctx.has_asymmetric_key(AsymmetricKeyId::UserPrivateKey) {
132            return Err(MissingPrivateKeyError.into());
133        }
134
135        // Make sure we only keep the keys given in the arguments and not any of the previous
136        // ones, which might be from organizations that the user is no longer a part of anymore
137        ctx.retain_symmetric_keys(|key_ref| !matches!(key_ref, SymmetricKeyId::Organization(_)));
138
139        // Decrypt the org keys with the private key
140        for (org_id, org_enc_key) in org_enc_keys {
141            ctx.decapsulate_key_unsigned(
142                AsymmetricKeyId::UserPrivateKey,
143                SymmetricKeyId::Organization(org_id),
144                &org_enc_key,
145            )?;
146        }
147
148        Ok(())
149    }
150}