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