Skip to main content

bitwarden_core/client/
encryption_settings.rs

1#[cfg(any(feature = "internal", feature = "secrets"))]
2use bitwarden_crypto::KeyStore;
3#[cfg(feature = "secrets")]
4use bitwarden_crypto::SymmetricCryptoKey;
5#[cfg(feature = "internal")]
6use bitwarden_crypto::UnsignedSharedKey;
7use bitwarden_error::bitwarden_error;
8use thiserror::Error;
9#[cfg(feature = "internal")]
10use tracing::{info, instrument};
11
12#[cfg(any(feature = "secrets", feature = "internal"))]
13use crate::OrganizationId;
14#[cfg(any(feature = "internal", feature = "secrets"))]
15use crate::key_management::{KeyIds, SymmetricKeyId};
16use crate::{MissingPrivateKeyError, error::UserIdAlreadySetError};
17
18#[allow(missing_docs)]
19#[bitwarden_error(flat)]
20#[derive(Debug, Error)]
21pub enum EncryptionSettingsError {
22    #[error("Cryptography error, {0}")]
23    Crypto(#[from] bitwarden_crypto::CryptoError),
24
25    #[error("Cryptography Initialization error")]
26    CryptoInitialization,
27
28    #[error(transparent)]
29    MissingPrivateKey(#[from] MissingPrivateKeyError),
30
31    #[error(transparent)]
32    UserIdAlreadySet(#[from] UserIdAlreadySetError),
33
34    #[error("Wrong Pin")]
35    WrongPin,
36
37    /// The user-key could not be set to the state, and the sdk will remain locked
38    #[error("Unable to set user-key to state")]
39    UserKeyStateUpdateFailed,
40
41    #[error("Unable to retrieve user-key from state")]
42    UserKeyStateRetrievalFailed,
43
44    #[error("Invalid upgrade token")]
45    InvalidUpgradeToken,
46}
47
48#[allow(missing_docs)]
49pub struct EncryptionSettings {}
50
51impl EncryptionSettings {
52    /// Initialize the encryption settings with only a single decrypted organization key.
53    /// This is used only for logging in Secrets Manager with an access token
54    #[cfg(feature = "secrets")]
55    pub(crate) fn new_single_org_key(
56        organization_id: OrganizationId,
57        key: SymmetricCryptoKey,
58        store: &KeyStore<KeyIds>,
59    ) {
60        // FIXME: [PM-18098] When this is part of crypto we won't need to use deprecated methods
61        #[allow(deprecated)]
62        store
63            .context_mut()
64            .set_symmetric_key(SymmetricKeyId::Organization(organization_id), key)
65            .expect("Mutable context");
66    }
67
68    #[cfg(feature = "internal")]
69    #[instrument(err, skip_all)]
70    pub(crate) fn set_org_keys(
71        org_enc_keys: Vec<(OrganizationId, UnsignedSharedKey)>,
72        store: &KeyStore<KeyIds>,
73    ) -> Result<(), EncryptionSettingsError> {
74        use crate::key_management::PrivateKeyId;
75
76        let mut ctx = store.context_mut();
77
78        // FIXME: [PM-11690] - Early abort to handle private key being corrupt
79        if org_enc_keys.is_empty() {
80            info!("No organization keys to set");
81            return Ok(());
82        }
83
84        if !ctx.has_private_key(PrivateKeyId::UserPrivateKey) {
85            info!("User private key is missing, cannot set organization keys");
86            return Err(MissingPrivateKeyError.into());
87        }
88
89        // Make sure we only keep the keys given in the arguments and not any of the previous
90        // ones, which might be from organizations that the user is no longer a part of anymore
91        ctx.retain_symmetric_keys(|key_ref| !matches!(key_ref, SymmetricKeyId::Organization(_)));
92
93        info!("Decrypting organization keys");
94        // Decrypt the org keys with the private key
95        for (org_id, org_enc_key) in org_enc_keys {
96            let _span =
97                tracing::span!(tracing::Level::INFO, "decapsulate_org_key", org_id = %org_id)
98                    .entered();
99            match org_enc_key.decapsulate(PrivateKeyId::UserPrivateKey, &mut ctx) {
100                Err(e) => {
101                    tracing::error!("Failed to decapsulate organization key: {}", e);
102                    return Err(e.into());
103                }
104                Ok(org_symmetric_key) => {
105                    tracing::info!(
106                        org_id = %org_id,
107                        "Successfully decapsulated organization key for org",
108                    );
109                    ctx.persist_symmetric_key(
110                        org_symmetric_key,
111                        SymmetricKeyId::Organization(org_id),
112                    )?;
113                }
114            }
115        }
116
117        Ok(())
118    }
119}