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
12use crate::{
13 bson::{doc, spec::BinarySubtype, Binary, RawBinaryRef, RawDocumentBuf},
14 client::options::TlsOptions,
15 coll::options::CollectionOptions,
16 error::{Error, Result},
17 options::{ReadConcern, WriteConcern},
18 results::DeleteResult,
19 Client,
20 Collection,
21 Cursor,
22 Namespace,
23};
24
25use super::{options::KmsProviders, state_machine::CryptExecutor};
26
27pub use super::client_builder::EncryptedClientBuilder;
28pub use crate::action::csfle::encrypt::{EncryptKey, RangeOptions};
29
30pub struct ClientEncryption {
33 crypt: Crypt,
34 exec: CryptExecutor,
35 key_vault: Collection<RawDocumentBuf>,
36}
37
38impl ClientEncryption {
39 pub fn new(
62 key_vault_client: Client,
63 key_vault_namespace: Namespace,
64 kms_providers: impl IntoIterator<Item = (KmsProvider, bson::Document, Option<TlsOptions>)>,
65 ) -> Result<Self> {
66 Self::builder(key_vault_client, key_vault_namespace, kms_providers).build()
67 }
68
69 pub fn builder(
94 key_vault_client: Client,
95 key_vault_namespace: Namespace,
96 kms_providers: impl IntoIterator<Item = (KmsProvider, bson::Document, Option<TlsOptions>)>,
97 ) -> ClientEncryptionBuilder {
98 ClientEncryptionBuilder {
99 key_vault_client,
100 key_vault_namespace,
101 kms_providers: kms_providers.into_iter().collect(),
102 key_cache_expiration: None,
103 }
104 }
105
106 pub async fn delete_key(&self, id: &Binary) -> Result<DeleteResult> {
114 self.key_vault.delete_one(doc! { "_id": id }).await
115 }
116
117 pub async fn get_key(&self, id: &Binary) -> Result<Option<RawDocumentBuf>> {
120 self.key_vault.find_one(doc! { "_id": id }).await
121 }
122
123 pub async fn get_keys(&self) -> Result<Cursor<RawDocumentBuf>> {
126 self.key_vault.find(doc! {}).await
127 }
128
129 pub async fn add_key_alt_name(
133 &self,
134 id: &Binary,
135 key_alt_name: &str,
136 ) -> Result<Option<RawDocumentBuf>> {
137 self.key_vault
138 .find_one_and_update(
139 doc! { "_id": id },
140 doc! { "$addToSet": { "keyAltNames": key_alt_name } },
141 )
142 .await
143 }
144
145 pub async fn remove_key_alt_name(
149 &self,
150 id: &Binary,
151 key_alt_name: &str,
152 ) -> Result<Option<RawDocumentBuf>> {
153 let update = doc! {
154 "$set": {
155 "keyAltNames": {
156 "$cond": [
157 { "$eq": ["$keyAltNames", [key_alt_name]] },
158 "$$REMOVE",
159 {
160 "$filter": {
161 "input": "$keyAltNames",
162 "cond": { "$ne": ["$$this", key_alt_name] },
163 }
164 }
165 ]
166 }
167 }
168 };
169 self.key_vault
170 .find_one_and_update(doc! { "_id": id }, vec![update])
171 .await
172 }
173
174 pub async fn get_key_by_alt_name(
176 &self,
177 key_alt_name: impl AsRef<str>,
178 ) -> Result<Option<RawDocumentBuf>> {
179 self.key_vault
180 .find_one(doc! { "keyAltNames": key_alt_name.as_ref() })
181 .await
182 }
183
184 pub async fn decrypt(&self, value: RawBinaryRef<'_>) -> Result<bson::RawBson> {
187 if value.subtype != BinarySubtype::Encrypted {
188 return Err(Error::invalid_argument(format!(
189 "Invalid binary subtype for decrypt: expected {:?}, got {:?}",
190 BinarySubtype::Encrypted,
191 value.subtype
192 )));
193 }
194 let ctx = self
195 .crypt
196 .ctx_builder()
197 .build_explicit_decrypt(value.bytes)?;
198 let result = self.exec.run_ctx(ctx, None).await?;
199 Ok(result
200 .get("v")?
201 .ok_or_else(|| Error::internal("invalid decryption result"))?
202 .to_raw_bson())
203 }
204}
205
206pub struct ClientEncryptionBuilder {
209 key_vault_client: Client,
210 key_vault_namespace: Namespace,
211 kms_providers: Vec<(KmsProvider, bson::Document, Option<TlsOptions>)>,
212 key_cache_expiration: Option<Duration>,
213}
214
215impl ClientEncryptionBuilder {
216 pub fn key_cache_expiration(mut self, expiration: impl Into<Option<Duration>>) -> Self {
219 self.key_cache_expiration = expiration.into();
220 self
221 }
222
223 pub fn build(self) -> Result<ClientEncryption> {
225 let kms_providers = KmsProviders::new(self.kms_providers)?;
226
227 let mut crypt_builder = Crypt::builder()
228 .kms_providers(&kms_providers.credentials_doc()?)?
229 .use_need_kms_credentials_state()
230 .use_range_v2()?
231 .retry_kms(true)?;
232 if let Some(key_cache_expiration) = self.key_cache_expiration {
233 let expiration_ms: u64 = key_cache_expiration.as_millis().try_into().map_err(|_| {
234 Error::invalid_argument(format!(
235 "key_cache_expiration must not exceed {} milliseconds, got {:?}",
236 u64::MAX,
237 key_cache_expiration
238 ))
239 })?;
240 crypt_builder = crypt_builder.key_cache_expiration(expiration_ms)?;
241 }
242 let crypt = crypt_builder.build()?;
243
244 let exec = CryptExecutor::new_explicit(
245 self.key_vault_client.weak(),
246 self.key_vault_namespace.clone(),
247 kms_providers,
248 )?;
249 let key_vault = self
250 .key_vault_client
251 .database(&self.key_vault_namespace.db)
252 .collection_with_options(
253 &self.key_vault_namespace.coll,
254 CollectionOptions::builder()
255 .write_concern(WriteConcern::majority())
256 .read_concern(ReadConcern::majority())
257 .build(),
258 );
259
260 Ok(ClientEncryption {
261 crypt,
262 exec,
263 key_vault,
264 })
265 }
266}
267
268#[derive(Debug, Clone, Serialize, Deserialize)]
270#[serde(untagged)]
271#[non_exhaustive]
272#[allow(missing_docs)]
273pub enum MasterKey {
274 Aws(AwsMasterKey),
275 Azure(AzureMasterKey),
276 Gcp(GcpMasterKey),
277 Kmip(KmipMasterKey),
278 Local(LocalMasterKey),
279}
280
281#[serde_with::skip_serializing_none]
283#[derive(Debug, Clone, Serialize, Deserialize, TypedBuilder)]
284#[builder(field_defaults(default, setter(into)))]
285#[serde(rename_all = "camelCase")]
286#[non_exhaustive]
287pub struct AwsMasterKey {
288 #[serde(skip)]
291 pub name: Option<String>,
292
293 pub region: String,
295
296 pub key: String,
298
299 pub endpoint: Option<String>,
302}
303
304impl From<AwsMasterKey> for MasterKey {
305 fn from(aws_master_key: AwsMasterKey) -> Self {
306 Self::Aws(aws_master_key)
307 }
308}
309
310#[serde_with::skip_serializing_none]
312#[derive(Debug, Clone, Serialize, Deserialize, TypedBuilder)]
313#[builder(field_defaults(default, setter(into)))]
314#[serde(rename_all = "camelCase")]
315#[non_exhaustive]
316pub struct AzureMasterKey {
317 #[serde(skip)]
320 pub name: Option<String>,
321
322 pub key_vault_endpoint: String,
324
325 pub key_name: String,
327
328 pub key_version: Option<String>,
330}
331
332impl From<AzureMasterKey> for MasterKey {
333 fn from(azure_master_key: AzureMasterKey) -> Self {
334 Self::Azure(azure_master_key)
335 }
336}
337
338#[serde_with::skip_serializing_none]
340#[derive(Debug, Clone, Serialize, Deserialize, TypedBuilder)]
341#[builder(field_defaults(default, setter(into)))]
342#[serde(rename_all = "camelCase")]
343#[non_exhaustive]
344pub struct GcpMasterKey {
345 #[serde(skip)]
348 pub name: Option<String>,
349
350 pub project_id: String,
352
353 pub location: String,
355
356 pub key_ring: String,
358
359 pub key_name: String,
361
362 pub key_version: Option<String>,
364
365 pub endpoint: Option<String>,
367}
368
369impl From<GcpMasterKey> for MasterKey {
370 fn from(gcp_master_key: GcpMasterKey) -> Self {
371 Self::Gcp(gcp_master_key)
372 }
373}
374
375#[serde_with::skip_serializing_none]
377#[derive(Debug, Clone, Serialize, Deserialize, TypedBuilder)]
378#[builder(field_defaults(default, setter(into)))]
379#[serde(rename_all = "camelCase")]
380#[non_exhaustive]
381pub struct LocalMasterKey {
382 #[serde(skip)]
385 pub name: Option<String>,
386}
387
388impl From<LocalMasterKey> for MasterKey {
389 fn from(local_master_key: LocalMasterKey) -> Self {
390 Self::Local(local_master_key)
391 }
392}
393
394#[serde_with::skip_serializing_none]
396#[derive(Debug, Clone, Serialize, Deserialize, TypedBuilder)]
397#[builder(field_defaults(default, setter(into)))]
398#[serde(rename_all = "camelCase")]
399#[non_exhaustive]
400pub struct KmipMasterKey {
401 #[serde(skip)]
404 pub name: Option<String>,
405
406 pub key_id: Option<String>,
409
410 pub delegated: Option<bool>,
412
413 pub endpoint: Option<String>,
415}
416
417impl From<KmipMasterKey> for MasterKey {
418 fn from(kmip_master_key: KmipMasterKey) -> Self {
419 Self::Kmip(kmip_master_key)
420 }
421}
422
423impl MasterKey {
424 pub fn provider(&self) -> KmsProvider {
426 let (provider, name) = match self {
427 MasterKey::Aws(AwsMasterKey { name, .. }) => (KmsProvider::aws(), name.clone()),
428 MasterKey::Azure(AzureMasterKey { name, .. }) => (KmsProvider::azure(), name.clone()),
429 MasterKey::Gcp(GcpMasterKey { name, .. }) => (KmsProvider::gcp(), name.clone()),
430 MasterKey::Kmip(KmipMasterKey { name, .. }) => (KmsProvider::kmip(), name.clone()),
431 MasterKey::Local(LocalMasterKey { name, .. }) => (KmsProvider::local(), name.clone()),
432 };
433 if let Some(name) = name {
434 provider.with_name(name)
435 } else {
436 provider
437 }
438 }
439}
440
441