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::{
31 EncryptKey,
32 PrefixOptions,
33 RangeOptions,
34 StringOptions,
35 SubstringOptions,
36 SuffixOptions,
37};
38
39pub struct ClientEncryption {
42 crypt: Crypt,
43 exec: CryptExecutor,
44 key_vault: Collection<RawDocumentBuf>,
45}
46
47impl ClientEncryption {
48 pub fn new(
69 key_vault_client: Client,
70 key_vault_namespace: Namespace,
71 kms_providers: impl IntoIterator<
72 Item = (KmsProvider, crate::bson::Document, Option<TlsOptions>),
73 >,
74 ) -> Result<Self> {
75 Self::builder(key_vault_client, key_vault_namespace, kms_providers).build()
76 }
77
78 pub fn builder(
101 key_vault_client: Client,
102 key_vault_namespace: Namespace,
103 kms_providers: impl IntoIterator<
104 Item = (KmsProvider, crate::bson::Document, Option<TlsOptions>),
105 >,
106 ) -> ClientEncryptionBuilder {
107 ClientEncryptionBuilder {
108 key_vault_client,
109 key_vault_namespace,
110 kms_providers: kms_providers.into_iter().collect(),
111 key_cache_expiration: None,
112 }
113 }
114
115 pub async fn delete_key(&self, id: &Binary) -> Result<DeleteResult> {
123 self.key_vault.delete_one(doc! { "_id": id }).await
124 }
125
126 pub async fn get_key(&self, id: &Binary) -> Result<Option<RawDocumentBuf>> {
129 self.key_vault.find_one(doc! { "_id": id }).await
130 }
131
132 pub async fn get_keys(&self) -> Result<Cursor<RawDocumentBuf>> {
135 self.key_vault.find(doc! {}).await
136 }
137
138 pub async fn add_key_alt_name(
142 &self,
143 id: &Binary,
144 key_alt_name: &str,
145 ) -> Result<Option<RawDocumentBuf>> {
146 self.key_vault
147 .find_one_and_update(
148 doc! { "_id": id },
149 doc! { "$addToSet": { "keyAltNames": key_alt_name } },
150 )
151 .await
152 }
153
154 pub async fn remove_key_alt_name(
158 &self,
159 id: &Binary,
160 key_alt_name: &str,
161 ) -> Result<Option<RawDocumentBuf>> {
162 let update = doc! {
163 "$set": {
164 "keyAltNames": {
165 "$cond": [
166 { "$eq": ["$keyAltNames", [key_alt_name]] },
167 "$$REMOVE",
168 {
169 "$filter": {
170 "input": "$keyAltNames",
171 "cond": { "$ne": ["$$this", key_alt_name] },
172 }
173 }
174 ]
175 }
176 }
177 };
178 self.key_vault
179 .find_one_and_update(doc! { "_id": id }, vec![update])
180 .await
181 }
182
183 pub async fn get_key_by_alt_name(
185 &self,
186 key_alt_name: impl AsRef<str>,
187 ) -> Result<Option<RawDocumentBuf>> {
188 self.key_vault
189 .find_one(doc! { "keyAltNames": key_alt_name.as_ref() })
190 .await
191 }
192
193 pub async fn decrypt(&self, value: RawBinaryRef<'_>) -> Result<crate::bson::RawBson> {
196 if value.subtype != BinarySubtype::Encrypted {
197 return Err(Error::invalid_argument(format!(
198 "Invalid binary subtype for decrypt: expected {:?}, got {:?}",
199 BinarySubtype::Encrypted,
200 value.subtype
201 )));
202 }
203 let ctx = self
204 .crypt
205 .ctx_builder()
206 .build_explicit_decrypt(value.bytes)?;
207 let result = self.exec.run_ctx(ctx, None).await?;
208 Ok(result
209 .get("v")?
210 .ok_or_else(|| Error::internal("invalid decryption result"))?
211 .to_raw_bson())
212 }
213}
214
215pub struct ClientEncryptionBuilder {
218 key_vault_client: Client,
219 key_vault_namespace: Namespace,
220 kms_providers: Vec<(KmsProvider, crate::bson::Document, Option<TlsOptions>)>,
221 key_cache_expiration: Option<Duration>,
222}
223
224impl ClientEncryptionBuilder {
225 pub fn key_cache_expiration(mut self, expiration: impl Into<Option<Duration>>) -> Self {
228 self.key_cache_expiration = expiration.into();
229 self
230 }
231
232 pub fn build(self) -> Result<ClientEncryption> {
234 let kms_providers = KmsProviders::new(self.kms_providers)?;
235
236 let mut crypt_builder = Crypt::builder()
237 .kms_providers(&kms_providers.credentials_doc()?)?
238 .use_need_kms_credentials_state()
239 .use_range_v2()?
240 .retry_kms(true)?;
241 if let Some(key_cache_expiration) = self.key_cache_expiration {
242 let expiration_ms: u64 = key_cache_expiration.as_millis().try_into().map_err(|_| {
243 Error::invalid_argument(format!(
244 "key_cache_expiration must not exceed {} milliseconds, got {:?}",
245 u64::MAX,
246 key_cache_expiration
247 ))
248 })?;
249 crypt_builder = crypt_builder.key_cache_expiration(expiration_ms)?;
250 }
251 let crypt = crypt_builder.build()?;
252
253 let exec = CryptExecutor::new_explicit(
254 self.key_vault_client.weak(),
255 self.key_vault_namespace.clone(),
256 kms_providers,
257 )?;
258 let key_vault = self
259 .key_vault_client
260 .database(&self.key_vault_namespace.db)
261 .collection_with_options(
262 &self.key_vault_namespace.coll,
263 CollectionOptions::builder()
264 .write_concern(WriteConcern::majority())
265 .read_concern(ReadConcern::majority())
266 .build(),
267 );
268
269 Ok(ClientEncryption {
270 crypt,
271 exec,
272 key_vault,
273 })
274 }
275}
276
277#[derive(Debug, Clone, Serialize, Deserialize)]
279#[serde(untagged)]
280#[non_exhaustive]
281#[allow(missing_docs)]
282pub enum MasterKey {
283 Aws(AwsMasterKey),
284 Azure(AzureMasterKey),
285 Gcp(GcpMasterKey),
286 Kmip(KmipMasterKey),
287 Local(LocalMasterKey),
288}
289
290#[serde_with::skip_serializing_none]
292#[derive(Debug, Clone, Serialize, Deserialize, TypedBuilder)]
293#[builder(field_defaults(default, setter(into)))]
294#[serde(rename_all = "camelCase")]
295#[non_exhaustive]
296pub struct AwsMasterKey {
297 #[serde(skip)]
300 pub name: Option<String>,
301
302 pub region: String,
304
305 pub key: String,
307
308 pub endpoint: Option<String>,
311}
312
313impl From<AwsMasterKey> for MasterKey {
314 fn from(aws_master_key: AwsMasterKey) -> Self {
315 Self::Aws(aws_master_key)
316 }
317}
318
319#[serde_with::skip_serializing_none]
321#[derive(Debug, Clone, Serialize, Deserialize, TypedBuilder)]
322#[builder(field_defaults(default, setter(into)))]
323#[serde(rename_all = "camelCase")]
324#[non_exhaustive]
325pub struct AzureMasterKey {
326 #[serde(skip)]
329 pub name: Option<String>,
330
331 pub key_vault_endpoint: String,
333
334 pub key_name: String,
336
337 pub key_version: Option<String>,
339}
340
341impl From<AzureMasterKey> for MasterKey {
342 fn from(azure_master_key: AzureMasterKey) -> Self {
343 Self::Azure(azure_master_key)
344 }
345}
346
347#[serde_with::skip_serializing_none]
349#[derive(Debug, Clone, Serialize, Deserialize, TypedBuilder)]
350#[builder(field_defaults(default, setter(into)))]
351#[serde(rename_all = "camelCase")]
352#[non_exhaustive]
353pub struct GcpMasterKey {
354 #[serde(skip)]
357 pub name: Option<String>,
358
359 pub project_id: String,
361
362 pub location: String,
364
365 pub key_ring: String,
367
368 pub key_name: String,
370
371 pub key_version: Option<String>,
373
374 pub endpoint: Option<String>,
376}
377
378impl From<GcpMasterKey> for MasterKey {
379 fn from(gcp_master_key: GcpMasterKey) -> Self {
380 Self::Gcp(gcp_master_key)
381 }
382}
383
384#[serde_with::skip_serializing_none]
386#[derive(Debug, Clone, Serialize, Deserialize, TypedBuilder)]
387#[builder(field_defaults(default, setter(into)))]
388#[serde(rename_all = "camelCase")]
389#[non_exhaustive]
390pub struct LocalMasterKey {
391 #[serde(skip)]
394 pub name: Option<String>,
395}
396
397impl From<LocalMasterKey> for MasterKey {
398 fn from(local_master_key: LocalMasterKey) -> Self {
399 Self::Local(local_master_key)
400 }
401}
402
403#[serde_with::skip_serializing_none]
405#[derive(Debug, Clone, Serialize, Deserialize, TypedBuilder)]
406#[builder(field_defaults(default, setter(into)))]
407#[serde(rename_all = "camelCase")]
408#[non_exhaustive]
409pub struct KmipMasterKey {
410 #[serde(skip)]
413 pub name: Option<String>,
414
415 pub key_id: Option<String>,
418
419 pub delegated: Option<bool>,
421
422 pub endpoint: Option<String>,
424}
425
426impl From<KmipMasterKey> for MasterKey {
427 fn from(kmip_master_key: KmipMasterKey) -> Self {
428 Self::Kmip(kmip_master_key)
429 }
430}
431
432impl MasterKey {
433 pub fn provider(&self) -> KmsProvider {
435 let (provider, name) = match self {
436 MasterKey::Aws(AwsMasterKey { name, .. }) => (KmsProvider::aws(), name.clone()),
437 MasterKey::Azure(AzureMasterKey { name, .. }) => (KmsProvider::azure(), name.clone()),
438 MasterKey::Gcp(GcpMasterKey { name, .. }) => (KmsProvider::gcp(), name.clone()),
439 MasterKey::Kmip(KmipMasterKey { name, .. }) => (KmsProvider::kmip(), name.clone()),
440 MasterKey::Local(LocalMasterKey { name, .. }) => (KmsProvider::local(), name.clone()),
441 };
442 if let Some(name) = name {
443 provider.with_name(name)
444 } else {
445 provider
446 }
447 }
448}
449
450