1mod create_data_key;
4mod encrypt;
5
6use std::time::Duration;
7
8use mongocrypt::{ctx::KmsProvider, Crypt};
9use serde::{Deserialize, Serialize};
10use typed_builder::TypedBuilder;
11
12#[cfg(feature = "bson-3")]
13use crate::bson_compat::RawBsonRefExt as _;
14use crate::{
15 bson::{doc, spec::BinarySubtype, Binary, RawBinaryRef, RawDocumentBuf},
16 client::options::TlsOptions,
17 coll::options::CollectionOptions,
18 error::{Error, Result},
19 options::{ReadConcern, WriteConcern},
20 results::DeleteResult,
21 Client,
22 Collection,
23 Cursor,
24 Namespace,
25};
26
27use super::{options::KmsProviders, state_machine::CryptExecutor};
28
29pub use super::client_builder::EncryptedClientBuilder;
30pub use crate::action::csfle::encrypt::{EncryptKey, RangeOptions};
31
32pub struct ClientEncryption {
35 crypt: Crypt,
36 exec: CryptExecutor,
37 key_vault: Collection<RawDocumentBuf>,
38}
39
40impl ClientEncryption {
41 pub fn new(
62 key_vault_client: Client,
63 key_vault_namespace: Namespace,
64 kms_providers: impl IntoIterator<
65 Item = (KmsProvider, crate::bson::Document, Option<TlsOptions>),
66 >,
67 ) -> Result<Self> {
68 Self::builder(key_vault_client, key_vault_namespace, kms_providers).build()
69 }
70
71 pub fn builder(
94 key_vault_client: Client,
95 key_vault_namespace: Namespace,
96 kms_providers: impl IntoIterator<
97 Item = (KmsProvider, crate::bson::Document, Option<TlsOptions>),
98 >,
99 ) -> ClientEncryptionBuilder {
100 ClientEncryptionBuilder {
101 key_vault_client,
102 key_vault_namespace,
103 kms_providers: kms_providers.into_iter().collect(),
104 key_cache_expiration: None,
105 }
106 }
107
108 pub async fn delete_key(&self, id: &Binary) -> Result<DeleteResult> {
116 self.key_vault.delete_one(doc! { "_id": id }).await
117 }
118
119 pub async fn get_key(&self, id: &Binary) -> Result<Option<RawDocumentBuf>> {
122 self.key_vault.find_one(doc! { "_id": id }).await
123 }
124
125 pub async fn get_keys(&self) -> Result<Cursor<RawDocumentBuf>> {
128 self.key_vault.find(doc! {}).await
129 }
130
131 pub async fn add_key_alt_name(
135 &self,
136 id: &Binary,
137 key_alt_name: &str,
138 ) -> Result<Option<RawDocumentBuf>> {
139 self.key_vault
140 .find_one_and_update(
141 doc! { "_id": id },
142 doc! { "$addToSet": { "keyAltNames": key_alt_name } },
143 )
144 .await
145 }
146
147 pub async fn remove_key_alt_name(
151 &self,
152 id: &Binary,
153 key_alt_name: &str,
154 ) -> Result<Option<RawDocumentBuf>> {
155 let update = doc! {
156 "$set": {
157 "keyAltNames": {
158 "$cond": [
159 { "$eq": ["$keyAltNames", [key_alt_name]] },
160 "$$REMOVE",
161 {
162 "$filter": {
163 "input": "$keyAltNames",
164 "cond": { "$ne": ["$$this", key_alt_name] },
165 }
166 }
167 ]
168 }
169 }
170 };
171 self.key_vault
172 .find_one_and_update(doc! { "_id": id }, vec![update])
173 .await
174 }
175
176 pub async fn get_key_by_alt_name(
178 &self,
179 key_alt_name: impl AsRef<str>,
180 ) -> Result<Option<RawDocumentBuf>> {
181 self.key_vault
182 .find_one(doc! { "keyAltNames": key_alt_name.as_ref() })
183 .await
184 }
185
186 pub async fn decrypt(&self, value: RawBinaryRef<'_>) -> Result<crate::bson::RawBson> {
189 if value.subtype != BinarySubtype::Encrypted {
190 return Err(Error::invalid_argument(format!(
191 "Invalid binary subtype for decrypt: expected {:?}, got {:?}",
192 BinarySubtype::Encrypted,
193 value.subtype
194 )));
195 }
196 let ctx = self
197 .crypt
198 .ctx_builder()
199 .build_explicit_decrypt(value.bytes)?;
200 let result = self.exec.run_ctx(ctx, None).await?;
201 Ok(result
202 .get("v")?
203 .ok_or_else(|| Error::internal("invalid decryption result"))?
204 .to_raw_bson())
205 }
206}
207
208pub struct ClientEncryptionBuilder {
211 key_vault_client: Client,
212 key_vault_namespace: Namespace,
213 kms_providers: Vec<(KmsProvider, crate::bson::Document, Option<TlsOptions>)>,
214 key_cache_expiration: Option<Duration>,
215}
216
217impl ClientEncryptionBuilder {
218 pub fn key_cache_expiration(mut self, expiration: impl Into<Option<Duration>>) -> Self {
221 self.key_cache_expiration = expiration.into();
222 self
223 }
224
225 pub fn build(self) -> Result<ClientEncryption> {
227 let kms_providers = KmsProviders::new(self.kms_providers)?;
228
229 let mut crypt_builder = Crypt::builder()
230 .kms_providers(&kms_providers.credentials_doc()?)?
231 .use_need_kms_credentials_state()
232 .use_range_v2()?
233 .retry_kms(true)?;
234 if let Some(key_cache_expiration) = self.key_cache_expiration {
235 let expiration_ms: u64 = key_cache_expiration.as_millis().try_into().map_err(|_| {
236 Error::invalid_argument(format!(
237 "key_cache_expiration must not exceed {} milliseconds, got {:?}",
238 u64::MAX,
239 key_cache_expiration
240 ))
241 })?;
242 crypt_builder = crypt_builder.key_cache_expiration(expiration_ms)?;
243 }
244 let crypt = crypt_builder.build()?;
245
246 let exec = CryptExecutor::new_explicit(
247 self.key_vault_client.weak(),
248 self.key_vault_namespace.clone(),
249 kms_providers,
250 )?;
251 let key_vault = self
252 .key_vault_client
253 .database(&self.key_vault_namespace.db)
254 .collection_with_options(
255 &self.key_vault_namespace.coll,
256 CollectionOptions::builder()
257 .write_concern(WriteConcern::majority())
258 .read_concern(ReadConcern::majority())
259 .build(),
260 );
261
262 Ok(ClientEncryption {
263 crypt,
264 exec,
265 key_vault,
266 })
267 }
268}
269
270#[derive(Debug, Clone, Serialize, Deserialize)]
272#[serde(untagged)]
273#[non_exhaustive]
274#[allow(missing_docs)]
275pub enum MasterKey {
276 Aws(AwsMasterKey),
277 Azure(AzureMasterKey),
278 Gcp(GcpMasterKey),
279 Kmip(KmipMasterKey),
280 Local(LocalMasterKey),
281}
282
283#[serde_with::skip_serializing_none]
285#[derive(Debug, Clone, Serialize, Deserialize, TypedBuilder)]
286#[builder(field_defaults(default, setter(into)))]
287#[serde(rename_all = "camelCase")]
288#[non_exhaustive]
289pub struct AwsMasterKey {
290 #[serde(skip)]
293 pub name: Option<String>,
294
295 pub region: String,
297
298 pub key: String,
300
301 pub endpoint: Option<String>,
304}
305
306impl From<AwsMasterKey> for MasterKey {
307 fn from(aws_master_key: AwsMasterKey) -> Self {
308 Self::Aws(aws_master_key)
309 }
310}
311
312#[serde_with::skip_serializing_none]
314#[derive(Debug, Clone, Serialize, Deserialize, TypedBuilder)]
315#[builder(field_defaults(default, setter(into)))]
316#[serde(rename_all = "camelCase")]
317#[non_exhaustive]
318pub struct AzureMasterKey {
319 #[serde(skip)]
322 pub name: Option<String>,
323
324 pub key_vault_endpoint: String,
326
327 pub key_name: String,
329
330 pub key_version: Option<String>,
332}
333
334impl From<AzureMasterKey> for MasterKey {
335 fn from(azure_master_key: AzureMasterKey) -> Self {
336 Self::Azure(azure_master_key)
337 }
338}
339
340#[serde_with::skip_serializing_none]
342#[derive(Debug, Clone, Serialize, Deserialize, TypedBuilder)]
343#[builder(field_defaults(default, setter(into)))]
344#[serde(rename_all = "camelCase")]
345#[non_exhaustive]
346pub struct GcpMasterKey {
347 #[serde(skip)]
350 pub name: Option<String>,
351
352 pub project_id: String,
354
355 pub location: String,
357
358 pub key_ring: String,
360
361 pub key_name: String,
363
364 pub key_version: Option<String>,
366
367 pub endpoint: Option<String>,
369}
370
371impl From<GcpMasterKey> for MasterKey {
372 fn from(gcp_master_key: GcpMasterKey) -> Self {
373 Self::Gcp(gcp_master_key)
374 }
375}
376
377#[serde_with::skip_serializing_none]
379#[derive(Debug, Clone, Serialize, Deserialize, TypedBuilder)]
380#[builder(field_defaults(default, setter(into)))]
381#[serde(rename_all = "camelCase")]
382#[non_exhaustive]
383pub struct LocalMasterKey {
384 #[serde(skip)]
387 pub name: Option<String>,
388}
389
390impl From<LocalMasterKey> for MasterKey {
391 fn from(local_master_key: LocalMasterKey) -> Self {
392 Self::Local(local_master_key)
393 }
394}
395
396#[serde_with::skip_serializing_none]
398#[derive(Debug, Clone, Serialize, Deserialize, TypedBuilder)]
399#[builder(field_defaults(default, setter(into)))]
400#[serde(rename_all = "camelCase")]
401#[non_exhaustive]
402pub struct KmipMasterKey {
403 #[serde(skip)]
406 pub name: Option<String>,
407
408 pub key_id: Option<String>,
411
412 pub delegated: Option<bool>,
414
415 pub endpoint: Option<String>,
417}
418
419impl From<KmipMasterKey> for MasterKey {
420 fn from(kmip_master_key: KmipMasterKey) -> Self {
421 Self::Kmip(kmip_master_key)
422 }
423}
424
425impl MasterKey {
426 pub fn provider(&self) -> KmsProvider {
428 let (provider, name) = match self {
429 MasterKey::Aws(AwsMasterKey { name, .. }) => (KmsProvider::aws(), name.clone()),
430 MasterKey::Azure(AzureMasterKey { name, .. }) => (KmsProvider::azure(), name.clone()),
431 MasterKey::Gcp(GcpMasterKey { name, .. }) => (KmsProvider::gcp(), name.clone()),
432 MasterKey::Kmip(KmipMasterKey { name, .. }) => (KmsProvider::kmip(), name.clone()),
433 MasterKey::Local(LocalMasterKey { name, .. }) => (KmsProvider::local(), name.clone()),
434 };
435 if let Some(name) = name {
436 provider.with_name(name)
437 } else {
438 provider
439 }
440 }
441}
442
443