bitwarden_core/client/
encryption_settings.rs1#[cfg(feature = "internal")]
2use std::sync::RwLock;
3
4#[cfg(feature = "internal")]
5use bitwarden_crypto::{
6 Aes256CbcHmacKey, AsymmetricCryptoKey, CoseKeyBytes, CoseSerializable, EncString,
7 KeyDecryptable, Pkcs8PrivateKeyBytes, SigningKey, UnsignedSharedKey, XChaCha20Poly1305Key,
8};
9#[cfg(any(feature = "internal", feature = "secrets"))]
10use bitwarden_crypto::{KeyStore, SymmetricCryptoKey};
11use bitwarden_error::bitwarden_error;
12#[cfg(feature = "internal")]
13use log::warn;
14use thiserror::Error;
15#[cfg(any(feature = "internal", feature = "secrets"))]
16use uuid::Uuid;
17
18#[cfg(feature = "internal")]
19use crate::key_management::{AsymmetricKeyId, SecurityState, SignedSecurityState, SigningKeyId};
20#[cfg(any(feature = "internal", feature = "secrets"))]
21use crate::key_management::{KeyIds, SymmetricKeyId};
22use crate::{error::UserIdAlreadySetError, MissingPrivateKeyError, VaultLockedError};
23
24#[allow(missing_docs)]
25#[bitwarden_error(flat)]
26#[derive(Debug, Error)]
27pub enum EncryptionSettingsError {
28 #[error("Cryptography error, {0}")]
29 Crypto(#[from] bitwarden_crypto::CryptoError),
30
31 #[error(transparent)]
32 InvalidBase64(#[from] base64::DecodeError),
33
34 #[error(transparent)]
35 VaultLocked(#[from] VaultLockedError),
36
37 #[error("Invalid private key")]
38 InvalidPrivateKey,
39
40 #[error("Invalid signing key")]
41 InvalidSigningKey,
42
43 #[error("Invalid security state")]
44 InvalidSecurityState,
45
46 #[error(transparent)]
47 MissingPrivateKey(#[from] MissingPrivateKeyError),
48
49 #[error(transparent)]
50 UserIdAlreadySetError(#[from] UserIdAlreadySetError),
51}
52
53#[allow(clippy::large_enum_variant)]
54#[cfg(feature = "internal")]
55pub(crate) enum AccountEncryptionKeys {
56 V1 {
57 user_key: Aes256CbcHmacKey,
58 private_key: EncString,
59 },
60 V2 {
61 user_key: XChaCha20Poly1305Key,
62 private_key: EncString,
63 signing_key: EncString,
64 security_state: SignedSecurityState,
65 },
66}
67
68#[allow(missing_docs)]
69pub struct EncryptionSettings {}
70
71impl EncryptionSettings {
72 #[cfg(feature = "internal")]
77 pub(crate) fn new_decrypted_key(
78 encryption_keys: AccountEncryptionKeys,
79 store: &KeyStore<KeyIds>,
80 security_state_rwlock: &RwLock<Option<SecurityState>>,
81 ) -> Result<(), EncryptionSettingsError> {
82 match encryption_keys {
87 AccountEncryptionKeys::V1 {
88 user_key,
89 private_key,
90 } => {
91 Self::init_v1(user_key, private_key, store)?;
92 }
93 AccountEncryptionKeys::V2 {
94 user_key,
95 private_key,
96 signing_key,
97 security_state,
98 } => {
99 Self::init_v2(
100 user_key,
101 private_key,
102 signing_key,
103 security_state,
104 store,
105 security_state_rwlock,
106 )?;
107 }
108 }
109
110 Ok(())
111 }
112
113 #[cfg(feature = "internal")]
114 fn init_v1(
115 user_key: Aes256CbcHmacKey,
116 private_key: EncString,
117 store: &KeyStore<KeyIds>,
118 ) -> Result<(), EncryptionSettingsError> {
119 let user_key = SymmetricCryptoKey::Aes256CbcHmacKey(user_key);
120
121 let private_key = {
122 let dec: Vec<u8> = private_key.decrypt_with_key(&user_key)?;
123
124 AsymmetricCryptoKey::from_der(&Pkcs8PrivateKeyBytes::from(dec))
127 .map_err(|_| {
128 warn!("Invalid private key");
129 })
130 .ok()
131
132 };
137
138 #[allow(deprecated)]
140 {
141 let mut ctx = store.context_mut();
142 ctx.set_symmetric_key(SymmetricKeyId::User, user_key)?;
143 if let Some(private_key) = private_key {
144 ctx.set_asymmetric_key(AsymmetricKeyId::UserPrivateKey, private_key)?;
145 }
146 }
147
148 Ok(())
149 }
150
151 #[cfg(feature = "internal")]
152 fn init_v2(
153 user_key: XChaCha20Poly1305Key,
154 private_key: EncString,
155 signing_key: EncString,
156 security_state: SignedSecurityState,
157 store: &KeyStore<KeyIds>,
158 sdk_security_state: &RwLock<Option<SecurityState>>,
159 ) -> Result<(), EncryptionSettingsError> {
160 use crate::key_management::SecurityState;
161
162 let user_key = SymmetricCryptoKey::XChaCha20Poly1305Key(user_key);
163
164 let signing_key: Vec<u8> = signing_key.decrypt_with_key(&user_key)?;
167 let signing_key = SigningKey::from_cose(&CoseKeyBytes::from(signing_key))
168 .map_err(|_| EncryptionSettingsError::InvalidSigningKey)?;
169 let private_key: Vec<u8> = private_key.decrypt_with_key(&user_key)?;
170 let private_key = AsymmetricCryptoKey::from_der(&Pkcs8PrivateKeyBytes::from(private_key))
171 .map_err(|_| EncryptionSettingsError::InvalidPrivateKey)?;
172
173 let security_state: SecurityState = security_state
174 .verify_and_unwrap(&signing_key.to_verifying_key())
175 .map_err(|_| EncryptionSettingsError::InvalidSecurityState)?;
176 *sdk_security_state.write().expect("RwLock not poisoned") = Some(security_state);
177
178 #[allow(deprecated)]
179 {
180 let mut ctx = store.context_mut();
181 ctx.set_symmetric_key(SymmetricKeyId::User, user_key)?;
182 ctx.set_asymmetric_key(AsymmetricKeyId::UserPrivateKey, private_key)?;
183 ctx.set_signing_key(SigningKeyId::UserSigningKey, signing_key)?;
184 }
185
186 Ok(())
187 }
188
189 #[cfg(feature = "secrets")]
192 pub(crate) fn new_single_org_key(
193 organization_id: Uuid,
194 key: SymmetricCryptoKey,
195 store: &KeyStore<KeyIds>,
196 ) {
197 #[allow(deprecated)]
199 store
200 .context_mut()
201 .set_symmetric_key(SymmetricKeyId::Organization(organization_id), key)
202 .expect("Mutable context");
203 }
204
205 #[cfg(feature = "internal")]
206 pub(crate) fn set_org_keys(
207 org_enc_keys: Vec<(Uuid, UnsignedSharedKey)>,
208 store: &KeyStore<KeyIds>,
209 ) -> Result<(), EncryptionSettingsError> {
210 use crate::key_management::AsymmetricKeyId;
211
212 let mut ctx = store.context_mut();
213
214 if org_enc_keys.is_empty() {
216 return Ok(());
217 }
218
219 if !ctx.has_asymmetric_key(AsymmetricKeyId::UserPrivateKey) {
220 return Err(MissingPrivateKeyError.into());
221 }
222
223 ctx.retain_symmetric_keys(|key_ref| !matches!(key_ref, SymmetricKeyId::Organization(_)));
226
227 for (org_id, org_enc_key) in org_enc_keys {
229 ctx.decapsulate_key_unsigned(
230 AsymmetricKeyId::UserPrivateKey,
231 SymmetricKeyId::Organization(org_id),
232 &org_enc_key,
233 )?;
234 }
235
236 Ok(())
237 }
238}