Skip to main content

bitwarden_user_crypto_management/key_rotation/
mod.rs

1//! Client to manage the cryptographic machinery of a user account, including key-rotation
2mod crypto;
3mod data;
4mod partial_rotateable_keyset;
5mod password_change_and_rotate_user_keys;
6mod rotate_user_keys;
7mod rotation_context;
8mod sync;
9mod unlock;
10mod unlock_method;
11
12use bitwarden_error::bitwarden_error;
13use serde::{Deserialize, Serialize};
14use thiserror::Error;
15#[cfg(feature = "wasm")]
16use tsify::Tsify;
17#[cfg(feature = "wasm")]
18use wasm_bindgen::prelude::*;
19
20use crate::{
21    UserCryptoManagementClient,
22    key_rotation::{
23        rotate_user_keys::UpgradeTokenAction,
24        rotation_context::organization_memberships_needing_trust,
25        unlock::{V1EmergencyAccessMembership, V1OrganizationMembership},
26    },
27};
28
29/// Response model for untrusted memberships, containing both organization and emergency access
30/// memberships.
31#[derive(Serialize, Deserialize)]
32#[cfg_attr(feature = "wasm", derive(Tsify), tsify(into_wasm_abi, from_wasm_abi))]
33pub struct UntrustedMembershipsResponse {
34    emergency_access_memberships: Vec<V1EmergencyAccessMembership>,
35    organization_memberships: Vec<V1OrganizationMembership>,
36}
37
38#[cfg_attr(feature = "wasm", wasm_bindgen)]
39impl UserCryptoManagementClient {
40    /// The organization public keys the user has to confirm as trusted before a key rotation.
41    ///
42    /// When the rotation creates a V2 upgrade token, the list is empty. Organization admins update
43    /// account recovery from that token, so the user confirms nothing. Every other rotation returns
44    /// one entry per organization the user is enrolled in for account recovery.
45    pub async fn get_untrusted_organization_public_keys(
46        &self,
47        upgrade_token_action: UpgradeTokenAction,
48    ) -> Result<Vec<V1OrganizationMembership>, RotateUserKeysError> {
49        let api_client = &self.client.internal.get_api_configurations().api_client;
50        let key_rotation_data = sync::get_key_rotation_data(api_client)
51            .await
52            .map_err(|_| RotateUserKeysError::Api)?;
53        Ok(organization_memberships_needing_trust(
54            key_rotation_data.organization_memberships,
55            upgrade_token_action,
56            self.client.internal.get_key_store(),
57        ))
58    }
59
60    /// Fetches the emergency access public keys for V1 emergency access memberships for the user.
61    /// These have to be trusted manually be the user before rotating.
62    pub async fn get_untrusted_emergency_access_public_keys(
63        &self,
64    ) -> Result<Vec<V1EmergencyAccessMembership>, RotateUserKeysError> {
65        let api_client = &self.client.internal.get_api_configurations().api_client;
66        let key_rotation_data = sync::get_key_rotation_data(api_client)
67            .await
68            .map_err(|_| RotateUserKeysError::Api)?;
69        Ok(key_rotation_data.emergency_access_memberships)
70    }
71
72    /// The organization and emergency access public keys the user has to confirm as trusted before
73    /// a key rotation.
74    ///
75    /// When the rotation creates a V2 upgrade token, the organization list is empty. Organization
76    /// admins update account recovery from that token, so the user confirms nothing. Every other
77    /// rotation returns one entry per organization the user is enrolled in for account recovery.
78    ///
79    /// Emergency access grantees always need a confirmation, because every rotation shares the new
80    /// user key with each of them.
81    pub async fn get_untrusted_memberships(
82        &self,
83        upgrade_token_action: UpgradeTokenAction,
84    ) -> Result<UntrustedMembershipsResponse, RotateUserKeysError> {
85        let api_client = &self.client.internal.get_api_configurations().api_client;
86        let key_rotation_data = sync::get_key_rotation_data(api_client)
87            .await
88            .map_err(|_| RotateUserKeysError::Api)?;
89        Ok(UntrustedMembershipsResponse {
90            emergency_access_memberships: key_rotation_data.emergency_access_memberships,
91            organization_memberships: organization_memberships_needing_trust(
92                key_rotation_data.organization_memberships,
93                upgrade_token_action,
94                self.client.internal.get_key_store(),
95            ),
96        })
97    }
98}
99
100/// Errors that can occur while converting key rotation data response models into their domain
101/// representations.
102#[allow(missing_docs)]
103#[derive(Debug, Error)]
104pub enum KeyRotationDataParseError {
105    #[error(transparent)]
106    MissingField(#[from] bitwarden_core::MissingFieldError),
107    #[error(transparent)]
108    Crypto(#[from] bitwarden_crypto::CryptoError),
109    #[error(transparent)]
110    B64(#[from] bitwarden_encoding::NotB64EncodedError),
111}
112
113#[derive(Debug, Error)]
114#[bitwarden_error(flat)]
115pub enum RotateUserKeysError {
116    #[error("API error during key rotation")]
117    Api,
118    #[error("Cryptographic error during key rotation")]
119    Crypto,
120    #[error("Invalid public key provided during key rotation")]
121    InvalidPublicKey,
122    #[error("Key Connector API error during key rotation")]
123    KeyConnectorApi,
124    #[error("Untrusted key encountered during key rotation")]
125    UntrustedKey,
126    #[error("Vault contains old attachments that must be re-uploaded before key rotation")]
127    OldAttachments,
128}