1use std::{fmt, sync::Arc};
4
5#[cfg(test)]
6use crate::xml::dom::Document;
7use base64::{Engine as _, engine::general_purpose::STANDARD};
8
9use crate::document::{DocumentParseSettings, XmlDocument, XmlParseWorkBudget};
10use rsa::RsaPrivateKey;
11
12use super::parse::{
13 parse_encrypted_data_node_with_policy_and_budget, validate_encrypted_data_metadata,
14};
15use super::types::{MAX_CIPHER_VALUE_BASE64_LEN, XMLENC_NS, validate_ciphertext_framing};
16use super::{
17 DataEncryptionAlgorithm, DecryptedContent, EncryptedData, EncryptedDataType, EncryptedKey,
18 KeyTransportAlgorithm, KeyWrapAlgorithm, OaepDigestAlgorithm, RsaOaepParameters, XmlEncError,
19 map_document_error,
20};
21
22#[cfg(test)]
23use super::parse_encrypted_data;
24
25#[derive(Debug)]
30pub struct KeyCandidateBudget {
31 maximum: usize,
32 remaining: usize,
33}
34
35impl KeyCandidateBudget {
36 pub fn for_operation() -> Self {
38 Self::with_limit(crate::hard_limits::KEY_CANDIDATE_CEILING)
39 }
40
41 pub fn with_limit(maximum: usize) -> Self {
43 Self {
44 maximum,
45 remaining: maximum,
46 }
47 }
48
49 pub const fn remaining(&self) -> usize {
51 self.remaining
52 }
53
54 pub fn consume(&mut self, count: usize) -> Result<(), XmlEncError> {
56 if count > self.remaining {
57 return Err(crate::policy::PolicyViolation::ResourceLimit {
58 resource: crate::policy::resource_name::KEY_CANDIDATES,
59 maximum: self.maximum,
60 actual: self
61 .maximum
62 .saturating_sub(self.remaining)
63 .saturating_add(count),
64 }
65 .into());
66 }
67 self.remaining -= count;
68 Ok(())
69 }
70
71 fn account_returned_candidates(
72 &mut self,
73 remaining_before: usize,
74 returned: usize,
75 ) -> Result<(), XmlEncError> {
76 let resolver_charged = remaining_before.saturating_sub(self.remaining);
77 self.consume(returned.saturating_sub(resolver_charged))
78 }
79}
80
81pub trait DecryptionKeyResolver {
83 fn resolve_key(
85 &self,
86 provider: &dyn crate::provider::CryptoProvider,
87 algorithm: DataEncryptionAlgorithm,
88 encrypted_key: Option<&EncryptedKey>,
89 ) -> Result<Vec<u8>, XmlEncError>;
90
91 fn resolve_key_candidates(
103 &self,
104 provider: &dyn crate::provider::CryptoProvider,
105 algorithm: DataEncryptionAlgorithm,
106 encrypted_key: Option<&EncryptedKey>,
107 budget: &mut KeyCandidateBudget,
108 ) -> Result<Vec<Vec<u8>>, XmlEncError> {
109 budget.consume(1)?;
110 self.resolve_key(provider, algorithm, encrypted_key)
111 .map(|key| vec![key])
112 }
113}
114
115#[derive(Debug, Clone, Copy, Default)]
117pub struct DocumentDecryptionOptions<'a> {
118 pub encrypted_data_id: Option<&'a str>,
120}
121
122pub struct DecryptContext<'a> {
124 resolver: &'a dyn DecryptionKeyResolver,
125 policy: crate::policy::DecryptionPolicy,
126 provider: &'a dyn crate::provider::CryptoProvider,
127 xml_backend: crate::XmlBackend,
128 id_attributes: &'a [crate::IdAttributeRegistration],
129}
130
131impl<'a> DecryptContext<'a> {
132 pub fn new(resolver: &'a dyn DecryptionKeyResolver) -> Self {
134 Self {
135 resolver,
136 policy: crate::policy::DecryptionPolicy::default(),
137 provider: crate::provider::default_provider(),
138 xml_backend: crate::XmlBackend::default(),
139 id_attributes: &[],
140 }
141 }
142
143 pub fn policy(mut self, policy: crate::policy::DecryptionPolicy) -> Self {
145 self.policy = policy;
146 self
147 }
148
149 pub fn provider(mut self, provider: &'a dyn crate::provider::CryptoProvider) -> Self {
151 self.provider = provider;
152 self
153 }
154
155 pub fn xml_backend(mut self, backend: crate::XmlBackend) -> Self {
157 self.xml_backend = backend;
158 self
159 }
160
161 fn document_parse_settings(&self) -> DocumentParseSettings {
162 DocumentParseSettings::from_policy(&self.policy.xml, &self.policy.resources)
163 .with_backend(self.xml_backend)
164 }
165
166 pub fn id_attributes(mut self, registrations: &'a [crate::IdAttributeRegistration]) -> Self {
168 self.id_attributes = registrations;
169 self
170 }
171
172 pub fn decrypt(&self, xml: &str) -> Result<DecryptedContent, XmlEncError> {
174 let encrypted = super::parse::parse_encrypted_data_with_policy_and_backend(
175 xml,
176 &self.policy,
177 self.xml_backend,
178 )?;
179 self.decrypt_data(&encrypted)
180 }
181
182 pub fn decrypt_data(&self, encrypted: &EncryptedData) -> Result<DecryptedContent, XmlEncError> {
184 self.process_decryption_candidates(encrypted, Ok)
185 }
186
187 fn process_decryption_candidates<T>(
188 &self,
189 encrypted: &EncryptedData,
190 mut accept: impl FnMut(DecryptedContent) -> Result<T, XmlEncError>,
191 ) -> Result<T, XmlEncError> {
192 self.policy.resources.validate()?;
193 validate_encrypted_data_metadata(encrypted, &self.policy)?;
194 encrypted.encryption_method.validate_structure()?;
195 validate_recipient_count(
196 encrypted.encrypted_keys.len(),
197 self.policy.resources.max_encryption_recipients,
198 )?;
199 let algorithm = DataEncryptionAlgorithm::from_uri(&encrypted.encryption_method.algorithm)?;
200 if self
201 .policy
202 .data_algorithms
203 .as_ref()
204 .is_some_and(|allowed| !allowed.contains(&algorithm))
205 {
206 return Err(crate::policy::PolicyViolation::Algorithm {
207 operation: "decryption",
208 algorithm: encrypted.encryption_method.algorithm.clone(),
209 }
210 .into());
211 }
212 self.provider
213 .require_capability(crate::provider::ProviderCapability::Decrypt(algorithm))?;
214 validate_typed_cipher_values(
215 encrypted,
216 algorithm,
217 self.policy.resources.max_encryption_plaintext_bytes,
218 self.policy.resources.max_xml_document_bytes,
219 )?;
220 let ciphertext = STANDARD
221 .decode(&encrypted.cipher_data.value)
222 .map_err(|error| XmlEncError::Base64(error.to_string()))?;
223 validate_content_framing_before_resolution(
224 algorithm,
225 ciphertext.len(),
226 &encrypted.encrypted_keys,
227 &self.policy,
228 )?;
229 validate_possible_plaintext_len(
230 algorithm,
231 ciphertext.len(),
232 self.policy.resources.max_encryption_plaintext_bytes,
233 )?;
234 let keys = resolve_content_key_candidates(
235 self.provider,
236 algorithm,
237 encrypted,
238 self.resolver,
239 &self.policy,
240 )?;
241 let keys = compatible_decryption_key_candidates(algorithm, keys)?;
242 validate_decryption_key_candidates(algorithm, keys.len())?;
243 let mut last_error = None;
244 for key in keys {
245 let attempt = (|| {
246 validate_key_len(algorithm, &key)?;
247 let plaintext = self
248 .provider
249 .decrypt_data(algorithm, &key, &ciphertext)
250 .map_err(|error| {
251 map_data_decryption_error(algorithm, ciphertext.len(), error)
252 })?;
253 validate_provider_plaintext_len(algorithm, ciphertext.len(), plaintext.len())?;
254 validate_plaintext_len(
255 plaintext.len(),
256 self.policy.resources.max_encryption_plaintext_bytes,
257 )?;
258 match encrypted.encrypted_type.as_ref() {
259 Some(EncryptedDataType::Element | EncryptedDataType::Content) => {
260 Ok(DecryptedContent::Xml(String::from_utf8(plaintext)?))
261 }
262 Some(EncryptedDataType::Other(_)) | None => {
263 Ok(DecryptedContent::Bytes(plaintext))
264 }
265 }
266 })();
267 match attempt {
268 Ok(content) => match accept(content) {
269 Ok(result) => return Ok(result),
270 Err(error) => last_error = Some(error),
271 },
272 Err(error) => last_error = Some(error),
273 }
274 }
275 Err(last_error.unwrap_or(XmlEncError::KeyNotFound))
276 }
277
278 pub fn decrypt_document(
280 &self,
281 xml: &str,
282 encrypted_data_id: Option<&str>,
283 ) -> Result<String, XmlEncError> {
284 decrypt_document_with_context(
285 xml,
286 DocumentEncryptedDataSelector::EncryptedDataId(encrypted_data_id),
287 self,
288 )
289 }
290
291 pub fn decrypt_owned_document(
293 &self,
294 document: &mut XmlDocument,
295 encrypted_data_id: Option<&str>,
296 ) -> Result<(), XmlEncError> {
297 let parse_budget = XmlParseWorkBudget::from_resources(&self.policy.resources);
298 decrypt_owned_document_with_context(
299 document,
300 DocumentEncryptedDataSelector::EncryptedDataId(encrypted_data_id),
301 self,
302 &parse_budget,
303 )
304 }
305
306 pub fn decrypt_document_from_start_node(
309 &self,
310 xml: &str,
311 start_node_id: Option<&str>,
312 ) -> Result<String, XmlEncError> {
313 decrypt_document_with_context(
314 xml,
315 DocumentEncryptedDataSelector::UniqueBelowStartNode(start_node_id),
316 self,
317 )
318 }
319
320 pub fn decrypt_first_document_from_start_node(
323 &self,
324 xml: &str,
325 start_node_id: Option<&str>,
326 ) -> Result<String, XmlEncError> {
327 decrypt_document_with_context(
328 xml,
329 DocumentEncryptedDataSelector::FirstBelowStartNode(start_node_id),
330 self,
331 )
332 }
333}
334
335#[derive(Clone)]
337pub struct SymmetricKeyDecryptor {
338 key: Vec<u8>,
339}
340
341impl fmt::Debug for SymmetricKeyDecryptor {
342 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
343 formatter
344 .debug_struct("SymmetricKeyDecryptor")
345 .field("key", &"[REDACTED]")
346 .finish()
347 }
348}
349
350impl SymmetricKeyDecryptor {
351 pub fn new(key: impl Into<Vec<u8>>) -> Self {
353 Self { key: key.into() }
354 }
355}
356
357impl DecryptionKeyResolver for SymmetricKeyDecryptor {
358 fn resolve_key(
359 &self,
360 _provider: &dyn crate::provider::CryptoProvider,
361 algorithm: DataEncryptionAlgorithm,
362 _encrypted_key: Option<&EncryptedKey>,
363 ) -> Result<Vec<u8>, XmlEncError> {
364 validate_key_len(algorithm, &self.key)?;
365 Ok(self.key.clone())
366 }
367}
368
369#[derive(Clone)]
371pub struct PrivateKeyDecryptor {
372 key: Arc<dyn crate::provider::KeyRecoveryKey>,
373}
374
375#[derive(Clone)]
377pub struct KekDecryptor {
378 kek: Vec<u8>,
379}
380
381impl fmt::Debug for KekDecryptor {
382 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
383 formatter
384 .debug_struct("KekDecryptor")
385 .field("kek", &"[REDACTED]")
386 .finish()
387 }
388}
389
390impl KekDecryptor {
391 pub fn new(kek: impl Into<Vec<u8>>) -> Self {
393 Self { kek: kek.into() }
394 }
395}
396
397impl DecryptionKeyResolver for KekDecryptor {
398 fn resolve_key(
399 &self,
400 provider: &dyn crate::provider::CryptoProvider,
401 algorithm: DataEncryptionAlgorithm,
402 encrypted_key: Option<&EncryptedKey>,
403 ) -> Result<Vec<u8>, XmlEncError> {
404 let encrypted_key = encrypted_key.ok_or(XmlEncError::KeyNotFound)?;
405 encrypted_key.encryption_method.validate_structure()?;
406 let wrapped = STANDARD
407 .decode(&encrypted_key.cipher_data.value)
408 .map_err(|error| XmlEncError::Base64(error.to_string()))?;
409 let wrap_algorithm =
410 KeyWrapAlgorithm::from_uri(&encrypted_key.encryption_method.algorithm)?;
411 let expected_kek_len = wrap_algorithm.key_len();
412 if self.kek.len() != expected_kek_len {
413 return Err(XmlEncError::InvalidKekSize {
414 algorithm: wrap_algorithm,
415 expected: expected_kek_len,
416 actual: self.kek.len(),
417 });
418 }
419 let expected_wrapped_len = algorithm.key_len() + 8;
420 if wrapped.len() != expected_wrapped_len {
421 return Err(XmlEncError::InvalidWrappedKeyLength {
422 expected: expected_wrapped_len,
423 actual: wrapped.len(),
424 });
425 }
426 provider.require_capability(crate::provider::ProviderCapability::KeyUnwrap(
427 wrap_algorithm,
428 ))?;
429 let key = provider
430 .unwrap_key(wrap_algorithm, &self.kek, &wrapped)
431 .map_err(|error| match error {
432 crate::provider::ProviderError::InvalidKeySize { expected, actual } => {
433 XmlEncError::InvalidKekSize {
434 algorithm: wrap_algorithm,
435 expected,
436 actual,
437 }
438 }
439 crate::provider::ProviderError::AuthenticationFailed
440 | crate::provider::ProviderError::InvalidInput(
441 crate::provider::ProviderInputError::AesKeyWrapFraming,
442 ) => XmlEncError::KeyWrapIntegrity,
443 error => XmlEncError::Provider(error),
444 })?;
445 validate_key_len(algorithm, &key)?;
446 Ok(key)
447 }
448}
449
450impl PrivateKeyDecryptor {
451 pub fn new(key: RsaPrivateKey) -> Self {
453 Self::provider_key(Arc::new(crate::provider::RustCryptoRsaPrivateKey::new(key)))
454 }
455
456 pub fn provider_key(key: Arc<dyn crate::provider::KeyRecoveryKey>) -> Self {
458 Self { key }
459 }
460}
461
462impl DecryptionKeyResolver for PrivateKeyDecryptor {
463 fn resolve_key(
464 &self,
465 provider: &dyn crate::provider::CryptoProvider,
466 algorithm: DataEncryptionAlgorithm,
467 encrypted_key: Option<&EncryptedKey>,
468 ) -> Result<Vec<u8>, XmlEncError> {
469 let encrypted_key = encrypted_key.ok_or(XmlEncError::KeyNotFound)?;
470 encrypted_key.encryption_method.validate_structure()?;
471 let wrapped = STANDARD
472 .decode(&encrypted_key.cipher_data.value)
473 .map_err(|error| XmlEncError::Base64(error.to_string()))?;
474 let label = encrypted_key
475 .encryption_method
476 .oaep_params
477 .clone()
478 .unwrap_or_default();
479 let transport =
480 KeyTransportAlgorithm::from_uri(&encrypted_key.encryption_method.algorithm)?;
481 let key = match transport {
482 KeyTransportAlgorithm::RsaOaepMgf1p => self.decrypt_oaep_mgf1p(
483 provider,
484 encrypted_key.encryption_method.oaep_digest.as_deref(),
485 label,
486 &wrapped,
487 ),
488 KeyTransportAlgorithm::RsaOaep11 => self.decrypt_oaep11(
489 provider,
490 encrypted_key.encryption_method.oaep_digest.as_deref(),
491 encrypted_key.encryption_method.mgf_algorithm.as_deref(),
492 label,
493 &wrapped,
494 ),
495 }?;
496 validate_key_len(algorithm, &key)?;
497 Ok(key)
498 }
499}
500
501impl PrivateKeyDecryptor {
502 fn decrypt_oaep_mgf1p(
503 &self,
504 provider: &dyn crate::provider::CryptoProvider,
505 digest: Option<&str>,
506 label: Vec<u8>,
507 wrapped: &[u8],
508 ) -> Result<Vec<u8>, XmlEncError> {
509 let parameters = RsaOaepParameters {
510 algorithm: KeyTransportAlgorithm::RsaOaepMgf1p,
511 digest: parse_oaep_digest(digest)?,
512 mgf_digest: OaepDigestAlgorithm::Sha1,
513 label,
514 };
515 recover_rsa_oaep(provider, self.key.as_ref(), ¶meters, wrapped)
516 }
517
518 fn decrypt_oaep11(
519 &self,
520 provider: &dyn crate::provider::CryptoProvider,
521 digest: Option<&str>,
522 mgf: Option<&str>,
523 label: Vec<u8>,
524 wrapped: &[u8],
525 ) -> Result<Vec<u8>, XmlEncError> {
526 let parameters = RsaOaepParameters {
527 algorithm: KeyTransportAlgorithm::RsaOaep11,
528 digest: parse_oaep_digest(digest)?,
529 mgf_digest: parse_oaep_mgf_digest(mgf)?,
530 label,
531 };
532 recover_rsa_oaep(provider, self.key.as_ref(), ¶meters, wrapped)
533 }
534}
535
536fn parse_oaep_digest(uri: Option<&str>) -> Result<OaepDigestAlgorithm, XmlEncError> {
537 let uri = uri.unwrap_or("http://www.w3.org/2000/09/xmldsig#sha1");
538 OaepDigestAlgorithm::from_uri(uri)
539 .ok_or_else(|| XmlEncError::UnsupportedAlgorithm(uri.to_owned()))
540}
541
542fn parse_oaep_mgf_digest(uri: Option<&str>) -> Result<OaepDigestAlgorithm, XmlEncError> {
543 let uri = uri.unwrap_or("http://www.w3.org/2009/xmlenc11#mgf1sha1");
544 OaepDigestAlgorithm::from_mgf_uri(uri)
545 .ok_or_else(|| XmlEncError::UnsupportedAlgorithm(uri.to_owned()))
546}
547
548fn recover_rsa_oaep(
549 provider: &dyn crate::provider::CryptoProvider,
550 key: &dyn crate::provider::KeyRecoveryKey,
551 parameters: &RsaOaepParameters,
552 wrapped: &[u8],
553) -> Result<Vec<u8>, XmlEncError> {
554 let expected = key.ciphertext_len();
555 if wrapped.len() != expected {
556 return Err(XmlEncError::InvalidWrappedKeyLength {
557 expected,
558 actual: wrapped.len(),
559 });
560 }
561 provider.require_capability(crate::provider::ProviderCapability::KeyRecovery(parameters))?;
562 provider
563 .recover_key(key, parameters, wrapped)
564 .map_err(|error| match error {
565 crate::provider::ProviderError::Random(message) => XmlEncError::Rng(message),
566 error @ (crate::provider::ProviderError::AuthenticationFailed
567 | crate::provider::ProviderError::InvalidInput(_)) => {
568 XmlEncError::Rsa(error.to_string())
569 }
570 error => XmlEncError::Provider(error),
571 })
572}
573
574pub fn decrypt(
576 xml: &str,
577 resolver: &dyn DecryptionKeyResolver,
578) -> Result<DecryptedContent, XmlEncError> {
579 DecryptContext::new(resolver).decrypt(xml)
580}
581
582pub fn decrypt_document(
589 xml: &str,
590 encrypted_data_id: Option<&str>,
591 resolver: &dyn DecryptionKeyResolver,
592) -> Result<String, XmlEncError> {
593 decrypt_document_with_options(
594 xml,
595 DocumentDecryptionOptions { encrypted_data_id },
596 resolver,
597 )
598}
599
600pub fn decrypt_document_with_options(
605 xml: &str,
606 options: DocumentDecryptionOptions<'_>,
607 resolver: &dyn DecryptionKeyResolver,
608) -> Result<String, XmlEncError> {
609 DecryptContext::new(resolver).decrypt_document(xml, options.encrypted_data_id)
610}
611
612#[derive(Clone, Copy)]
613enum DocumentEncryptedDataSelector<'a> {
614 EncryptedDataId(Option<&'a str>),
615 UniqueBelowStartNode(Option<&'a str>),
616 FirstBelowStartNode(Option<&'a str>),
617}
618
619fn decrypt_document_with_context(
620 xml: &str,
621 selector: DocumentEncryptedDataSelector<'_>,
622 context: &DecryptContext<'_>,
623) -> Result<String, XmlEncError> {
624 context.policy.resources.validate()?;
625 validate_encryption_document_len(xml.len(), &context.policy)?;
626 let parse_budget = XmlParseWorkBudget::from_resources(&context.policy.resources);
627 let settings = context.document_parse_settings();
628 let mut document =
629 XmlDocument::parse_with_settings_and_budget(xml.to_owned(), settings, &parse_budget)
630 .map_err(|error| map_document_error(error, settings))?;
631 decrypt_owned_document_with_context(&mut document, selector, context, &parse_budget)?;
632 Ok(document.into_xml())
633}
634
635fn decrypt_owned_document_with_context(
636 document: &mut XmlDocument,
637 selector: DocumentEncryptedDataSelector<'_>,
638 context: &DecryptContext<'_>,
639 parse_budget: &XmlParseWorkBudget,
640) -> Result<(), XmlEncError> {
641 context.policy.resources.validate()?;
642 document.validate_operation_policy(&context.policy.xml, &context.policy.resources)?;
643 let (target, target_len, encrypted) = document.with_view(|view| {
644 let start = match selector {
645 DocumentEncryptedDataSelector::UniqueBelowStartNode(Some(id))
646 | DocumentEncryptedDataSelector::FirstBelowStartNode(Some(id)) => view
647 .node_for_id(id, context.id_attributes)
648 .ok_or_else(|| XmlEncError::SelectedNodeUnavailable { id: id.to_owned() })
649 .and_then(|identity| view.resolve_node(identity).map_err(XmlEncError::from))?,
650 DocumentEncryptedDataSelector::UniqueBelowStartNode(None)
651 | DocumentEncryptedDataSelector::FirstBelowStartNode(None)
652 | DocumentEncryptedDataSelector::EncryptedDataId(_) => view.document().root(),
653 };
654 let encrypted_data_id = match selector {
655 DocumentEncryptedDataSelector::EncryptedDataId(id) => id,
656 DocumentEncryptedDataSelector::UniqueBelowStartNode(_)
657 | DocumentEncryptedDataSelector::FirstBelowStartNode(_) => None,
658 };
659 let mut matches = start.descendants().filter(|node| {
660 node.has_tag_name((XMLENC_NS, "EncryptedData"))
661 && encrypted_data_id.is_none_or(|id| node.attribute("Id") == Some(id))
662 });
663 let selected = matches.next().ok_or(XmlEncError::EncryptedDataNotFound)?;
664 if matches!(
665 selector,
666 DocumentEncryptedDataSelector::EncryptedDataId(_)
667 | DocumentEncryptedDataSelector::UniqueBelowStartNode(_)
668 ) && matches.next().is_some()
669 {
670 return Err(XmlEncError::AmbiguousEncryptedData);
671 }
672 Ok::<_, XmlEncError>((
673 view.node_identity(selected),
674 selected.range().len(),
675 parse_encrypted_data_node_with_policy_and_budget(
676 selected,
677 &context.policy,
678 parse_budget,
679 context.xml_backend,
680 )?,
681 ))
682 })?;
683 context.process_decryption_candidates(&encrypted, |candidate| {
684 let DecryptedContent::Xml(plaintext) = candidate else {
685 return Err(XmlEncError::ReplacementRequiresXml);
686 };
687 validate_encryption_document_len(
688 document
689 .as_xml()
690 .len()
691 .saturating_sub(target_len)
692 .saturating_add(plaintext.len()),
693 &context.policy,
694 )?;
695 let settings = context.document_parse_settings();
696 match encrypted.encrypted_type.as_ref() {
697 Some(EncryptedDataType::Element) => document
698 .replace_element_with_budget(target, &plaintext, settings, parse_budget)
699 .map_err(|error| map_document_error(error, settings))?,
700 Some(EncryptedDataType::Content) => document
701 .replace_node_with_fragment_with_budget(target, &plaintext, settings, parse_budget)
702 .map_err(|error| map_document_error(error, settings))?,
703 Some(EncryptedDataType::Other(_)) | None => {
704 return Err(XmlEncError::ReplacementRequiresXml);
705 }
706 }
707 Ok(())
708 })
709}
710
711fn validate_encryption_document_len(
712 actual: usize,
713 policy: &crate::policy::DecryptionPolicy,
714) -> Result<(), XmlEncError> {
715 policy.resources.validate_xml_document_len(actual)?;
716 Ok(())
717}
718
719fn validate_recipient_count(actual: usize, maximum: usize) -> Result<(), XmlEncError> {
720 if actual > maximum {
721 return Err(crate::policy::PolicyViolation::ResourceLimit {
722 resource: crate::policy::resource_name::ENCRYPTION_RECIPIENTS,
723 maximum,
724 actual,
725 }
726 .into());
727 }
728 Ok(())
729}
730
731pub fn decrypt_data(
733 encrypted: &EncryptedData,
734 resolver: &dyn DecryptionKeyResolver,
735) -> Result<DecryptedContent, XmlEncError> {
736 DecryptContext::new(resolver).decrypt_data(encrypted)
737}
738
739fn resolve_content_key_candidates(
740 provider: &dyn crate::provider::CryptoProvider,
741 algorithm: DataEncryptionAlgorithm,
742 encrypted: &EncryptedData,
743 resolver: &dyn DecryptionKeyResolver,
744 policy: &crate::policy::DecryptionPolicy,
745) -> Result<Vec<Vec<u8>>, XmlEncError> {
746 let mut budget = KeyCandidateBudget::with_limit(policy.resources.max_key_candidates);
747 let mut last_error = None;
748 let mut candidates =
749 match resolve_candidates_with_budget(resolver, provider, algorithm, None, &mut budget) {
750 Ok(keys) => keys,
751 Err(error) => {
752 record_candidate_source_error_or_fail_operation(error, &mut last_error)?;
753 Vec::new()
754 }
755 };
756 for encrypted_key in &encrypted.encrypted_keys {
757 if !encrypted_key_applies_to_data(encrypted_key, encrypted) {
758 continue;
759 }
760 if let Err(error) = validate_encrypted_key_policy(encrypted_key, policy) {
761 last_error = Some(error);
762 continue;
763 }
764 match resolve_candidates_with_budget(
765 resolver,
766 provider,
767 algorithm,
768 Some(encrypted_key),
769 &mut budget,
770 ) {
771 Ok(keys) => candidates.extend(keys),
772 Err(error) => record_candidate_source_error_or_fail_operation(error, &mut last_error)?,
773 }
774 }
775 if candidates.is_empty() {
776 Err(last_error.unwrap_or(XmlEncError::KeyNotFound))
777 } else {
778 Ok(candidates)
779 }
780}
781
782fn record_candidate_source_error_or_fail_operation(
783 error: XmlEncError,
784 last_error: &mut Option<XmlEncError>,
785) -> Result<(), XmlEncError> {
786 if matches!(&error, XmlEncError::Policy(_)) {
790 return Err(error);
791 }
792 *last_error = Some(error);
793 Ok(())
794}
795
796fn resolve_candidates_with_budget(
797 resolver: &dyn DecryptionKeyResolver,
798 provider: &dyn crate::provider::CryptoProvider,
799 algorithm: DataEncryptionAlgorithm,
800 encrypted_key: Option<&EncryptedKey>,
801 budget: &mut KeyCandidateBudget,
802) -> Result<Vec<Vec<u8>>, XmlEncError> {
803 let remaining_before = budget.remaining();
804 let keys = resolver.resolve_key_candidates(provider, algorithm, encrypted_key, budget)?;
805 budget.account_returned_candidates(remaining_before, keys.len())?;
806 Ok(keys)
807}
808
809fn encrypted_key_applies_to_data(
810 encrypted_key: &EncryptedKey,
811 encrypted_data: &EncryptedData,
812) -> bool {
813 if let Some(references) = encrypted_key.reference_list.as_ref()
817 && !references.data_references.is_empty()
818 {
819 let Some(id) = encrypted_data.id.as_deref() else {
820 return false;
821 };
822 let target = format!("#{id}");
823 if !references.data_references.iter().any(|uri| uri == &target) {
824 return false;
825 }
826 }
827 if let (Some(carried), Some(expected)) = (
828 encrypted_key.carried_key_name.as_deref(),
829 encrypted_data.key_name.as_deref(),
830 ) && carried != expected
831 {
832 return false;
833 }
834 true
835}
836
837fn compatible_decryption_key_candidates(
838 algorithm: DataEncryptionAlgorithm,
839 keys: Vec<Vec<u8>>,
840) -> Result<Vec<Vec<u8>>, XmlEncError> {
841 let mut compatible = Vec::with_capacity(keys.len());
842 let mut last_error = None;
843 for key in keys {
844 match validate_key_len(algorithm, &key) {
845 Ok(()) if !compatible.iter().any(|existing| existing == &key) => {
846 compatible.push(key);
847 }
848 Ok(()) => {}
849 Err(error) => last_error = Some(error),
850 }
851 }
852 if compatible.is_empty() {
853 return Err(last_error.unwrap_or(XmlEncError::KeyNotFound));
854 }
855 Ok(compatible)
856}
857
858fn validate_decryption_key_candidates(
859 algorithm: DataEncryptionAlgorithm,
860 actual: usize,
861) -> Result<(), XmlEncError> {
862 let maximum = crate::hard_limits::KEY_CANDIDATE_CEILING;
863 if actual > maximum {
864 return Err(crate::policy::PolicyViolation::ResourceLimit {
865 resource: crate::policy::resource_name::KEY_CANDIDATES,
866 maximum,
867 actual,
868 }
869 .into());
870 }
871 if actual > 1
872 && matches!(
873 algorithm,
874 DataEncryptionAlgorithm::Aes128Cbc | DataEncryptionAlgorithm::Aes256Cbc
875 )
876 {
877 return Err(XmlEncError::AmbiguousKeyCandidates { algorithm, actual });
878 }
879 Ok(())
880}
881
882fn validate_encrypted_key_policy(
883 encrypted_key: &EncryptedKey,
884 policy: &crate::policy::DecryptionPolicy,
885) -> Result<(), XmlEncError> {
886 encrypted_key.encryption_method.validate_structure()?;
887 let uri = &encrypted_key.encryption_method.algorithm;
888 if let Ok(transport) = KeyTransportAlgorithm::from_uri(uri) {
889 if policy
890 .key_transport_algorithms
891 .as_ref()
892 .is_some_and(|allowed| !allowed.contains(&transport))
893 {
894 return Err(crate::policy::PolicyViolation::Algorithm {
895 operation: "decryption",
896 algorithm: uri.clone(),
897 }
898 .into());
899 }
900 let digest = parse_oaep_digest(encrypted_key.encryption_method.oaep_digest.as_deref())?;
901 let mgf_digest = if transport == KeyTransportAlgorithm::RsaOaepMgf1p {
902 OaepDigestAlgorithm::Sha1
903 } else {
904 parse_oaep_mgf_digest(encrypted_key.encryption_method.mgf_algorithm.as_deref())?
905 };
906 for selected in [digest, mgf_digest] {
907 if policy
908 .oaep_digests
909 .as_ref()
910 .is_some_and(|allowed| !allowed.contains(&selected))
911 {
912 return Err(crate::policy::PolicyViolation::Algorithm {
913 operation: "decryption",
914 algorithm: selected.uri().to_owned(),
915 }
916 .into());
917 }
918 }
919 } else {
920 let wrap = KeyWrapAlgorithm::from_uri(uri)?;
921 if policy
922 .key_wrap_algorithms
923 .as_ref()
924 .is_some_and(|allowed| !allowed.contains(&wrap))
925 {
926 return Err(crate::policy::PolicyViolation::Algorithm {
927 operation: "decryption",
928 algorithm: uri.clone(),
929 }
930 .into());
931 }
932 }
933 Ok(())
934}
935
936fn validate_content_framing_before_resolution(
937 algorithm: DataEncryptionAlgorithm,
938 ciphertext_len: usize,
939 encrypted_keys: &[EncryptedKey],
940 policy: &crate::policy::DecryptionPolicy,
941) -> Result<(), XmlEncError> {
942 let Err(framing_error) = validate_ciphertext_framing(algorithm, ciphertext_len) else {
943 return Ok(());
944 };
945
946 if !encrypted_keys.is_empty() {
951 let mut last_key_error = None;
952 for encrypted_key in encrypted_keys {
953 match validate_encrypted_key_policy(encrypted_key, policy) {
954 Ok(()) => return Err(framing_error),
955 Err(error) => last_key_error = Some(error),
956 }
957 }
958 if let Some(error) = last_key_error {
959 return Err(error);
960 }
961 }
962 Err(framing_error)
963}
964
965fn validate_typed_cipher_values(
966 encrypted: &EncryptedData,
967 algorithm: DataEncryptionAlgorithm,
968 maximum_plaintext: usize,
969 maximum_cipher_values: usize,
970) -> Result<(), XmlEncError> {
971 let maximum_ciphertext = match algorithm {
972 DataEncryptionAlgorithm::Aes128Cbc | DataEncryptionAlgorithm::Aes256Cbc => {
973 (maximum_plaintext / 16)
974 .saturating_add(1)
975 .saturating_mul(16)
976 .saturating_add(16)
977 }
978 DataEncryptionAlgorithm::Aes128Gcm | DataEncryptionAlgorithm::Aes256Gcm => {
979 maximum_plaintext.saturating_add(28)
980 }
981 };
982 let projected = validate_cipher_value_len(&encrypted.cipher_data.value, maximum_ciphertext)?;
983 if projected > maximum_ciphertext {
984 return Err(crate::policy::PolicyViolation::ResourceLimit {
985 resource: crate::policy::resource_name::ENCRYPTION_PLAINTEXT_BYTES,
986 maximum: maximum_plaintext,
987 actual: projected.saturating_sub(algorithm.minimum_ciphertext_len()),
988 }
989 .into());
990 }
991
992 let mut aggregate_encoded = encrypted.cipher_data.value.len();
993 if aggregate_encoded > maximum_cipher_values {
994 return Err(crate::policy::PolicyViolation::ResourceLimit {
995 resource: crate::policy::resource_name::AGGREGATE_ENCRYPTION_CIPHER_VALUE_BYTES,
996 maximum: maximum_cipher_values,
997 actual: aggregate_encoded,
998 }
999 .into());
1000 }
1001
1002 let maximum_wrapped_key = projected_decoded_len_for_encoded_len(MAX_CIPHER_VALUE_BASE64_LEN);
1003 for encrypted_key in &encrypted.encrypted_keys {
1004 validate_cipher_value_len(&encrypted_key.cipher_data.value, maximum_wrapped_key)?;
1005 aggregate_encoded = aggregate_encoded.saturating_add(encrypted_key.cipher_data.value.len());
1006 if aggregate_encoded > maximum_cipher_values {
1007 return Err(crate::policy::PolicyViolation::ResourceLimit {
1008 resource: crate::policy::resource_name::AGGREGATE_ENCRYPTION_CIPHER_VALUE_BYTES,
1009 maximum: maximum_cipher_values,
1010 actual: aggregate_encoded,
1011 }
1012 .into());
1013 }
1014 }
1015 Ok(())
1016}
1017
1018fn validate_cipher_value_len(value: &str, maximum_decoded: usize) -> Result<usize, XmlEncError> {
1019 if value.len() > MAX_CIPHER_VALUE_BASE64_LEN {
1020 return Err(XmlEncError::InvalidStructure(format!(
1021 "CipherValue exceeds {MAX_CIPHER_VALUE_BASE64_LEN}-byte limit"
1022 )));
1023 }
1024 Ok(projected_decoded_len(value).min(maximum_decoded.saturating_add(1)))
1025}
1026
1027fn projected_decoded_len(value: &str) -> usize {
1028 let padding = value
1029 .as_bytes()
1030 .iter()
1031 .rev()
1032 .take(2)
1033 .take_while(|byte| **byte == b'=')
1034 .count();
1035 projected_decoded_len_for_encoded_len(value.len()).saturating_sub(padding)
1036}
1037
1038fn projected_decoded_len_for_encoded_len(encoded_len: usize) -> usize {
1039 encoded_len
1040 .checked_add(3)
1041 .map(|length| length / 4)
1042 .and_then(|quanta| quanta.checked_mul(3))
1043 .unwrap_or(usize::MAX)
1044}
1045
1046fn validate_key_len(algorithm: DataEncryptionAlgorithm, key: &[u8]) -> Result<(), XmlEncError> {
1047 if key.len() == algorithm.key_len() {
1048 Ok(())
1049 } else {
1050 Err(XmlEncError::InvalidKeySize {
1051 algorithm,
1052 expected: algorithm.key_len(),
1053 actual: key.len(),
1054 })
1055 }
1056}
1057
1058fn validate_possible_plaintext_len(
1059 algorithm: DataEncryptionAlgorithm,
1060 ciphertext_len: usize,
1061 maximum: usize,
1062) -> Result<(), XmlEncError> {
1063 let framing = algorithm.minimum_ciphertext_len();
1066 validate_plaintext_len(ciphertext_len.saturating_sub(framing), maximum)
1067}
1068
1069fn validate_provider_plaintext_len(
1070 algorithm: DataEncryptionAlgorithm,
1071 ciphertext_len: usize,
1072 plaintext_len: usize,
1073) -> Result<(), XmlEncError> {
1074 use crate::provider::{ProviderError, ProviderOperation};
1075
1076 match algorithm {
1077 DataEncryptionAlgorithm::Aes128Gcm | DataEncryptionAlgorithm::Aes256Gcm => {
1078 let expected = ciphertext_len - algorithm.minimum_ciphertext_len();
1079 if plaintext_len != expected {
1080 return Err(ProviderError::InvalidOutputSize {
1081 operation: ProviderOperation::Decrypt,
1082 expected,
1083 actual: plaintext_len,
1084 }
1085 .into());
1086 }
1087 }
1088 DataEncryptionAlgorithm::Aes128Cbc | DataEncryptionAlgorithm::Aes256Cbc => {
1089 let padded_len = ciphertext_len - 16;
1090 let minimum = padded_len - 16;
1091 let maximum = padded_len - 1;
1092 if !(minimum..=maximum).contains(&plaintext_len) {
1093 return Err(ProviderError::InvalidOutputSizeRange {
1094 operation: ProviderOperation::Decrypt,
1095 minimum,
1096 maximum,
1097 actual: plaintext_len,
1098 }
1099 .into());
1100 }
1101 }
1102 }
1103 Ok(())
1104}
1105
1106fn validate_plaintext_len(actual: usize, maximum: usize) -> Result<(), XmlEncError> {
1107 if actual <= maximum {
1108 Ok(())
1109 } else {
1110 Err(crate::policy::PolicyViolation::ResourceLimit {
1111 resource: crate::policy::resource_name::ENCRYPTION_PLAINTEXT_BYTES,
1112 maximum,
1113 actual,
1114 }
1115 .into())
1116 }
1117}
1118
1119fn map_data_decryption_error(
1120 algorithm: DataEncryptionAlgorithm,
1121 ciphertext_len: usize,
1122 error: crate::provider::ProviderError,
1123) -> XmlEncError {
1124 use crate::provider::ProviderError;
1125
1126 match (algorithm, error) {
1127 (
1128 DataEncryptionAlgorithm::Aes128Gcm | DataEncryptionAlgorithm::Aes256Gcm,
1129 ProviderError::AuthenticationFailed,
1130 ) => XmlEncError::AeadAuthenticationFailed,
1131 (
1132 DataEncryptionAlgorithm::Aes128Gcm | DataEncryptionAlgorithm::Aes256Gcm,
1133 ProviderError::InvalidInput(crate::provider::ProviderInputError::AesGcmFraming),
1134 ) => XmlEncError::DataTooShort {
1135 algorithm: "AES-GCM",
1136 minimum: 28,
1137 actual: ciphertext_len,
1138 },
1139 (
1140 DataEncryptionAlgorithm::Aes128Cbc | DataEncryptionAlgorithm::Aes256Cbc,
1141 ProviderError::InvalidInput(crate::provider::ProviderInputError::AesCbcFraming),
1142 ) if ciphertext_len < 32 => XmlEncError::DataTooShort {
1143 algorithm: "AES-CBC",
1144 minimum: 32,
1145 actual: ciphertext_len,
1146 },
1147 (
1148 DataEncryptionAlgorithm::Aes128Cbc | DataEncryptionAlgorithm::Aes256Cbc,
1149 ProviderError::InvalidInput(crate::provider::ProviderInputError::AesCbcFraming),
1150 ) => XmlEncError::InvalidCbcCiphertextLength(ciphertext_len.saturating_sub(16)),
1151 (
1152 DataEncryptionAlgorithm::Aes128Cbc | DataEncryptionAlgorithm::Aes256Cbc,
1153 ProviderError::InvalidInput(crate::provider::ProviderInputError::AesCbcCiphertext),
1154 ) => XmlEncError::InvalidPadding,
1155 (_, error) => XmlEncError::Provider(error),
1156 }
1157}
1158
1159#[cfg(test)]
1160mod tests {
1161 use std::cell::{Cell, RefCell};
1162 use std::sync::atomic::{AtomicUsize, Ordering};
1163
1164 use aes_gcm::{
1165 Aes128Gcm,
1166 aead::{AeadInOut, KeyInit},
1167 };
1168 use aes_kw::KwAes128;
1169 use base64::engine::general_purpose::STANDARD;
1170 use rand_chacha::{ChaCha20Rng, rand_core::SeedableRng};
1171 use rsa::{Oaep, RsaPublicKey, pkcs8::DecodePrivateKey};
1172 use sha1::Sha1;
1173 use sha2::{Sha256, Sha384};
1174
1175 use super::*;
1176 use crate::xmlenc::{CipherData, EncryptionMethod};
1177
1178 struct RecipientKeyResolver {
1179 recipient: &'static str,
1180 key: Vec<u8>,
1181 }
1182
1183 struct CountingResolver {
1184 candidate_calls: Cell<usize>,
1185 key: Vec<u8>,
1186 }
1187
1188 struct AllCallsResolver {
1189 calls: Cell<usize>,
1190 key: Vec<u8>,
1191 }
1192
1193 struct CandidateResolver {
1194 keys: Vec<Vec<u8>>,
1195 }
1196
1197 #[test]
1198 fn document_decryption_initial_parse_uses_the_policy_work_budget() {
1199 let xml = "<root/>";
1202 let policy = crate::policy::DecryptionPolicy {
1203 resources: crate::policy::ResourcePolicy {
1204 max_xml_parse_work_bytes: 0,
1205 ..crate::policy::ResourcePolicy::default()
1206 },
1207 ..crate::policy::DecryptionPolicy::default()
1208 };
1209 let resolver = SymmetricKeyDecryptor::new([0_u8; 16]);
1210
1211 let error = DecryptContext::new(&resolver)
1212 .policy(policy)
1213 .decrypt_document(xml, None)
1214 .expect_err("a zero parse-work budget must reject the input parse");
1215
1216 assert!(matches!(
1217 error,
1218 XmlEncError::Policy(crate::policy::PolicyViolation::ResourceLimit {
1219 resource: crate::policy::resource_name::XML_PARSE_WORK_BYTES,
1220 maximum: 0,
1221 actual,
1222 }) if actual == xml.len()
1223 ));
1224 }
1225
1226 struct AggregateRecipientResolver {
1227 attempts: Cell<usize>,
1228 key: Vec<u8>,
1229 }
1230
1231 struct AssociationRecordingResolver {
1232 visited: RefCell<Vec<String>>,
1233 key: Vec<u8>,
1234 }
1235
1236 struct OrderedRecipientResolver {
1237 wrong: Vec<u8>,
1238 correct: Vec<u8>,
1239 }
1240
1241 struct DirectAndRecipientResolver {
1242 direct: Vec<u8>,
1243 recipient: Vec<u8>,
1244 }
1245
1246 struct FailingDirectResolver {
1247 recipient: Vec<u8>,
1248 }
1249
1250 struct PolicyRejectingDirectResolver {
1251 recipient: Vec<u8>,
1252 }
1253
1254 struct MislabelledExhaustionResolver {
1255 direct: Vec<u8>,
1256 }
1257
1258 impl DecryptionKeyResolver for DirectAndRecipientResolver {
1259 fn resolve_key(
1260 &self,
1261 _provider: &dyn crate::provider::CryptoProvider,
1262 _algorithm: DataEncryptionAlgorithm,
1263 encrypted_key: Option<&EncryptedKey>,
1264 ) -> Result<Vec<u8>, XmlEncError> {
1265 Ok(if encrypted_key.is_some() {
1266 self.recipient.clone()
1267 } else {
1268 self.direct.clone()
1269 })
1270 }
1271 }
1272
1273 impl DecryptionKeyResolver for FailingDirectResolver {
1274 fn resolve_key(
1275 &self,
1276 _provider: &dyn crate::provider::CryptoProvider,
1277 algorithm: DataEncryptionAlgorithm,
1278 encrypted_key: Option<&EncryptedKey>,
1279 ) -> Result<Vec<u8>, XmlEncError> {
1280 if encrypted_key.is_some() {
1281 Ok(self.recipient.clone())
1282 } else {
1283 Err(XmlEncError::InvalidKeySize {
1284 algorithm,
1285 expected: 16,
1286 actual: 8,
1287 })
1288 }
1289 }
1290 }
1291
1292 impl DecryptionKeyResolver for PolicyRejectingDirectResolver {
1293 fn resolve_key(
1294 &self,
1295 _provider: &dyn crate::provider::CryptoProvider,
1296 _algorithm: DataEncryptionAlgorithm,
1297 encrypted_key: Option<&EncryptedKey>,
1298 ) -> Result<Vec<u8>, XmlEncError> {
1299 if encrypted_key.is_some() {
1300 Ok(self.recipient.clone())
1301 } else {
1302 Err(crate::policy::PolicyViolation::KeyTrust {
1303 reason: "test resolver rejected the operation",
1304 }
1305 .into())
1306 }
1307 }
1308 }
1309
1310 impl DecryptionKeyResolver for MislabelledExhaustionResolver {
1311 fn resolve_key(
1312 &self,
1313 _provider: &dyn crate::provider::CryptoProvider,
1314 _algorithm: DataEncryptionAlgorithm,
1315 _encrypted_key: Option<&EncryptedKey>,
1316 ) -> Result<Vec<u8>, XmlEncError> {
1317 Err(XmlEncError::KeyNotFound)
1318 }
1319
1320 fn resolve_key_candidates(
1321 &self,
1322 _provider: &dyn crate::provider::CryptoProvider,
1323 _algorithm: DataEncryptionAlgorithm,
1324 encrypted_key: Option<&EncryptedKey>,
1325 budget: &mut KeyCandidateBudget,
1326 ) -> Result<Vec<Vec<u8>>, XmlEncError> {
1327 if encrypted_key.is_none() {
1328 budget.consume(1)?;
1329 return Ok(vec![self.direct.clone()]);
1330 }
1331 budget.consume(budget.remaining().saturating_add(1))?;
1332 unreachable!("candidate budget exhaustion must return first")
1333 }
1334 }
1335
1336 impl DecryptionKeyResolver for OrderedRecipientResolver {
1337 fn resolve_key(
1338 &self,
1339 _provider: &dyn crate::provider::CryptoProvider,
1340 _algorithm: DataEncryptionAlgorithm,
1341 _encrypted_key: Option<&EncryptedKey>,
1342 ) -> Result<Vec<u8>, XmlEncError> {
1343 Err(XmlEncError::KeyNotFound)
1344 }
1345
1346 fn resolve_key_candidates(
1347 &self,
1348 _provider: &dyn crate::provider::CryptoProvider,
1349 _algorithm: DataEncryptionAlgorithm,
1350 encrypted_key: Option<&EncryptedKey>,
1351 budget: &mut KeyCandidateBudget,
1352 ) -> Result<Vec<Vec<u8>>, XmlEncError> {
1353 budget.consume(1)?;
1354 match encrypted_key.and_then(|key| key.id.as_deref()) {
1355 Some("first") => Ok(vec![self.wrong.clone()]),
1356 Some("second") => Ok(vec![self.correct.clone()]),
1357 _ => Err(XmlEncError::KeyNotFound),
1358 }
1359 }
1360 }
1361
1362 impl DecryptionKeyResolver for CandidateResolver {
1363 fn resolve_key(
1364 &self,
1365 _provider: &dyn crate::provider::CryptoProvider,
1366 _algorithm: DataEncryptionAlgorithm,
1367 _encrypted_key: Option<&EncryptedKey>,
1368 ) -> Result<Vec<u8>, XmlEncError> {
1369 Err(XmlEncError::KeyNotFound)
1370 }
1371
1372 fn resolve_key_candidates(
1373 &self,
1374 _provider: &dyn crate::provider::CryptoProvider,
1375 _algorithm: DataEncryptionAlgorithm,
1376 encrypted_key: Option<&EncryptedKey>,
1377 budget: &mut KeyCandidateBudget,
1378 ) -> Result<Vec<Vec<u8>>, XmlEncError> {
1379 if encrypted_key.is_none() {
1380 budget.consume(self.keys.len())?;
1381 Ok(self.keys.clone())
1382 } else {
1383 Err(XmlEncError::KeyNotFound)
1384 }
1385 }
1386 }
1387
1388 impl DecryptionKeyResolver for AggregateRecipientResolver {
1389 fn resolve_key(
1390 &self,
1391 _provider: &dyn crate::provider::CryptoProvider,
1392 _algorithm: DataEncryptionAlgorithm,
1393 _encrypted_key: Option<&EncryptedKey>,
1394 ) -> Result<Vec<u8>, XmlEncError> {
1395 Err(XmlEncError::KeyNotFound)
1396 }
1397
1398 fn resolve_key_candidates(
1399 &self,
1400 _provider: &dyn crate::provider::CryptoProvider,
1401 _algorithm: DataEncryptionAlgorithm,
1402 encrypted_key: Option<&EncryptedKey>,
1403 budget: &mut KeyCandidateBudget,
1404 ) -> Result<Vec<Vec<u8>>, XmlEncError> {
1405 let encrypted_key = encrypted_key.ok_or(XmlEncError::KeyNotFound)?;
1406 let attempts = budget.remaining();
1407 if attempts == 0 {
1408 budget.consume(1)?;
1409 }
1410 budget.consume(attempts)?;
1411 self.attempts.set(self.attempts.get() + attempts);
1412 if encrypted_key.id.as_deref() == Some("first") {
1413 Err(XmlEncError::KeyNotFound)
1414 } else {
1415 Ok(vec![self.key.clone()])
1416 }
1417 }
1418 }
1419
1420 impl DecryptionKeyResolver for AssociationRecordingResolver {
1421 fn resolve_key(
1422 &self,
1423 _provider: &dyn crate::provider::CryptoProvider,
1424 _algorithm: DataEncryptionAlgorithm,
1425 _encrypted_key: Option<&EncryptedKey>,
1426 ) -> Result<Vec<u8>, XmlEncError> {
1427 Err(XmlEncError::KeyNotFound)
1428 }
1429
1430 fn resolve_key_candidates(
1431 &self,
1432 _provider: &dyn crate::provider::CryptoProvider,
1433 _algorithm: DataEncryptionAlgorithm,
1434 encrypted_key: Option<&EncryptedKey>,
1435 budget: &mut KeyCandidateBudget,
1436 ) -> Result<Vec<Vec<u8>>, XmlEncError> {
1437 let encrypted_key = encrypted_key.ok_or(XmlEncError::KeyNotFound)?;
1438 budget.consume(1)?;
1439 self.visited
1440 .borrow_mut()
1441 .push(encrypted_key.id.clone().unwrap_or_default());
1442 Ok(vec![self.key.clone()])
1443 }
1444 }
1445
1446 fn associated_encrypted_key(
1447 id: &str,
1448 data_reference: Option<&str>,
1449 carried_key_name: Option<&str>,
1450 ) -> EncryptedKey {
1451 EncryptedKey {
1452 id: Some(id.into()),
1453 recipient: None,
1454 key_name: None,
1455 encryption_method: EncryptionMethod {
1456 algorithm: KeyTransportAlgorithm::RsaOaep11.uri().into(),
1457 key_size_bits: None,
1458 oaep_digest: None,
1459 mgf_algorithm: None,
1460 oaep_params: None,
1461 },
1462 cipher_data: CipherData {
1463 value: STANDARD.encode([0_u8; 256]),
1464 },
1465 reference_list: data_reference.map(|uri| crate::xmlenc::ReferenceList {
1466 data_references: vec![uri.into()],
1467 key_references: Vec::new(),
1468 }),
1469 carried_key_name: carried_key_name.map(str::to_owned),
1470 }
1471 }
1472
1473 fn encrypted_data_with_recipients(
1474 key: &[u8],
1475 encrypted_keys: Vec<EncryptedKey>,
1476 key_name: Option<&str>,
1477 ) -> EncryptedData {
1478 EncryptedData {
1479 id: Some("target".into()),
1480 encrypted_type: None,
1481 encryption_method: EncryptionMethod {
1482 algorithm: DataEncryptionAlgorithm::Aes128Gcm.uri().into(),
1483 key_size_bits: None,
1484 oaep_digest: None,
1485 mgf_algorithm: None,
1486 oaep_params: None,
1487 },
1488 key_name: key_name.map(str::to_owned),
1489 encrypted_keys,
1490 cipher_data: CipherData {
1491 value: STANDARD.encode(
1492 crate::provider::default_provider()
1493 .encrypt_data(DataEncryptionAlgorithm::Aes128Gcm, key, b"payload")
1494 .expect("test encryption must succeed"),
1495 ),
1496 },
1497 }
1498 }
1499
1500 #[derive(Debug, Default)]
1501 struct PermissiveUnwrapProvider {
1502 decrypt_calls: AtomicUsize,
1503 unwrap_calls: AtomicUsize,
1504 recover_calls: AtomicUsize,
1505 plaintext: Vec<u8>,
1506 candidate_plaintexts: Vec<Vec<u8>>,
1507 }
1508
1509 struct OpaqueRecoveryKey;
1510
1511 impl crate::provider::KeyRecoveryKey for OpaqueRecoveryKey {
1512 fn ciphertext_len(&self) -> usize {
1513 256
1514 }
1515
1516 fn recover_with_provider(
1517 &self,
1518 _provider: &dyn crate::provider::CryptoProvider,
1519 _parameters: &RsaOaepParameters,
1520 _ciphertext: &[u8],
1521 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
1522 panic!("custom provider must own recovery for its opaque key")
1523 }
1524 }
1525
1526 impl crate::provider::CryptoProvider for PermissiveUnwrapProvider {
1527 fn name(&self) -> &'static str {
1528 "permissive-unwrap-test"
1529 }
1530
1531 fn supports(&self, capability: crate::provider::ProviderCapability<'_>) -> bool {
1532 crate::provider::CryptoProvider::supports(
1533 &crate::provider::RustCryptoProvider,
1534 capability,
1535 )
1536 }
1537
1538 fn fill_random(&self, output: &mut [u8]) -> Result<(), crate::provider::ProviderError> {
1539 crate::provider::CryptoProvider::fill_random(
1540 &crate::provider::RustCryptoProvider,
1541 output,
1542 )
1543 }
1544
1545 fn derive_key(
1546 &self,
1547 parameters: &crate::provider::KdfParameters<'_>,
1548 secret: &[u8],
1549 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
1550 crate::provider::RustCryptoProvider.derive_key(parameters, secret)
1551 }
1552
1553 #[cfg(feature = "xmldsig")]
1554 fn digest(
1555 &self,
1556 algorithm: crate::xmldsig::DigestAlgorithm,
1557 data: &[u8],
1558 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
1559 crate::provider::CryptoProvider::digest(
1560 &crate::provider::RustCryptoProvider,
1561 algorithm,
1562 data,
1563 )
1564 }
1565
1566 #[cfg(feature = "xmldsig")]
1567 fn sign(
1568 &self,
1569 key: &dyn crate::xmldsig::SigningKey,
1570 algorithm: crate::xmldsig::SignatureAlgorithm,
1571 data: &[u8],
1572 ) -> Result<Vec<u8>, crate::xmldsig::SigningKeyError> {
1573 crate::provider::CryptoProvider::sign(
1574 &crate::provider::RustCryptoProvider,
1575 key,
1576 algorithm,
1577 data,
1578 )
1579 }
1580
1581 #[cfg(feature = "xmldsig")]
1582 fn verify(
1583 &self,
1584 key: &dyn crate::xmldsig::VerifyingKey,
1585 algorithm: crate::xmldsig::SignatureAlgorithm,
1586 data: &[u8],
1587 signature: &[u8],
1588 ) -> Result<bool, crate::xmldsig::DsigError> {
1589 crate::provider::CryptoProvider::verify(
1590 &crate::provider::RustCryptoProvider,
1591 key,
1592 algorithm,
1593 data,
1594 signature,
1595 )
1596 }
1597
1598 fn encrypt_data(
1599 &self,
1600 algorithm: DataEncryptionAlgorithm,
1601 key: &[u8],
1602 plaintext: &[u8],
1603 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
1604 crate::provider::CryptoProvider::encrypt_data(
1605 &crate::provider::RustCryptoProvider,
1606 algorithm,
1607 key,
1608 plaintext,
1609 )
1610 }
1611
1612 fn decrypt_data(
1613 &self,
1614 _algorithm: DataEncryptionAlgorithm,
1615 _key: &[u8],
1616 _ciphertext: &[u8],
1617 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
1618 let index = self.decrypt_calls.fetch_add(1, Ordering::Relaxed);
1619 Ok(self
1620 .candidate_plaintexts
1621 .get(index)
1622 .unwrap_or(&self.plaintext)
1623 .clone())
1624 }
1625
1626 fn wrap_key(
1627 &self,
1628 algorithm: KeyWrapAlgorithm,
1629 kek: &[u8],
1630 key: &[u8],
1631 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
1632 crate::provider::CryptoProvider::wrap_key(
1633 &crate::provider::RustCryptoProvider,
1634 algorithm,
1635 kek,
1636 key,
1637 )
1638 }
1639
1640 fn unwrap_key(
1641 &self,
1642 _algorithm: KeyWrapAlgorithm,
1643 _kek: &[u8],
1644 _wrapped: &[u8],
1645 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
1646 self.unwrap_calls.fetch_add(1, Ordering::Relaxed);
1647 Ok(vec![0_u8; 16])
1648 }
1649
1650 fn transport_key(
1651 &self,
1652 key: &dyn crate::provider::KeyTransportKey,
1653 parameters: &RsaOaepParameters,
1654 plaintext: &[u8],
1655 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
1656 crate::provider::CryptoProvider::transport_key(
1657 &crate::provider::RustCryptoProvider,
1658 key,
1659 parameters,
1660 plaintext,
1661 )
1662 }
1663
1664 fn recover_key(
1665 &self,
1666 _key: &dyn crate::provider::KeyRecoveryKey,
1667 _parameters: &RsaOaepParameters,
1668 _ciphertext: &[u8],
1669 ) -> Result<Vec<u8>, crate::provider::ProviderError> {
1670 self.recover_calls.fetch_add(1, Ordering::Relaxed);
1671 Ok(vec![0_u8; 16])
1672 }
1673 }
1674
1675 impl DecryptionKeyResolver for CountingResolver {
1676 fn resolve_key(
1677 &self,
1678 _provider: &dyn crate::provider::CryptoProvider,
1679 _algorithm: DataEncryptionAlgorithm,
1680 encrypted_key: Option<&EncryptedKey>,
1681 ) -> Result<Vec<u8>, XmlEncError> {
1682 if encrypted_key.is_some() {
1683 self.candidate_calls.set(self.candidate_calls.get() + 1);
1684 Ok(self.key.clone())
1685 } else {
1686 Err(XmlEncError::KeyNotFound)
1687 }
1688 }
1689 }
1690
1691 impl DecryptionKeyResolver for AllCallsResolver {
1692 fn resolve_key(
1693 &self,
1694 _provider: &dyn crate::provider::CryptoProvider,
1695 _algorithm: DataEncryptionAlgorithm,
1696 _encrypted_key: Option<&EncryptedKey>,
1697 ) -> Result<Vec<u8>, XmlEncError> {
1698 self.calls.set(self.calls.get() + 1);
1699 Ok(self.key.clone())
1700 }
1701 }
1702
1703 impl DecryptionKeyResolver for RecipientKeyResolver {
1704 fn resolve_key(
1705 &self,
1706 _provider: &dyn crate::provider::CryptoProvider,
1707 _algorithm: DataEncryptionAlgorithm,
1708 encrypted_key: Option<&EncryptedKey>,
1709 ) -> Result<Vec<u8>, XmlEncError> {
1710 if encrypted_key.and_then(|key| key.recipient.as_deref()) == Some(self.recipient) {
1711 Ok(self.key.clone())
1712 } else {
1713 Err(XmlEncError::KeyNotFound)
1714 }
1715 }
1716 }
1717
1718 #[test]
1719 fn decrypts_gcm_and_rejects_tampering() {
1720 let key = [7_u8; 16];
1722 let nonce = [9_u8; 12];
1723 let mut ciphertext = b"<Assertion>trusted</Assertion>".to_vec();
1724 Aes128Gcm::new_from_slice(&key)
1725 .expect("fixed key length")
1726 .encrypt_in_place(&nonce.into(), b"", &mut ciphertext)
1727 .expect("test encryption must succeed");
1728 let mut wire = nonce.to_vec();
1729 wire.extend_from_slice(&ciphertext);
1730 let xml = format!(
1731 "<xenc:EncryptedData xmlns:xenc=\"http://www.w3.org/2001/04/xmlenc#\" Type=\"http://www.w3.org/2001/04/xmlenc#Element\"><xenc:EncryptionMethod Algorithm=\"http://www.w3.org/2009/xmlenc11#aes128-gcm\"/><xenc:CipherData><xenc:CipherValue>{}</xenc:CipherValue></xenc:CipherData></xenc:EncryptedData>",
1732 STANDARD.encode(&wire)
1733 );
1734 let decrypted = decrypt(&xml, &SymmetricKeyDecryptor::new(key))
1735 .expect("valid AES-GCM XML must decrypt");
1736 assert_eq!(
1737 decrypted,
1738 DecryptedContent::Xml("<Assertion>trusted</Assertion>".into())
1739 );
1740 let last = wire.len() - 1;
1741 wire[last] ^= 1;
1742 let tampered = xml.replace(&STANDARD.encode(ciphertext), &STANDARD.encode(&wire[12..]));
1743 assert!(matches!(
1744 decrypt(&tampered, &SymmetricKeyDecryptor::new(key)),
1745 Err(XmlEncError::AeadAuthenticationFailed)
1746 ));
1747 }
1748
1749 #[test]
1750 fn candidate_keys_retry_only_authenticated_decryption() {
1751 let key = [7_u8; 16];
1754 let nonce = [9_u8; 12];
1755 let mut ciphertext = b"candidate plaintext".to_vec();
1756 Aes128Gcm::new_from_slice(&key)
1757 .expect("fixed key length")
1758 .encrypt_in_place(&nonce.into(), b"", &mut ciphertext)
1759 .expect("test encryption must succeed");
1760 let mut wire = nonce.to_vec();
1761 wire.extend_from_slice(&ciphertext);
1762 let encrypted = EncryptedData {
1763 id: None,
1764 encrypted_type: None,
1765 encryption_method: EncryptionMethod {
1766 algorithm: DataEncryptionAlgorithm::Aes128Gcm.uri().into(),
1767 key_size_bits: None,
1768 oaep_digest: None,
1769 mgf_algorithm: None,
1770 oaep_params: None,
1771 },
1772 key_name: None,
1773 encrypted_keys: Vec::new(),
1774 cipher_data: CipherData {
1775 value: STANDARD.encode(wire),
1776 },
1777 };
1778 let resolver = CandidateResolver {
1779 keys: vec![vec![1_u8; 16], key.to_vec()],
1780 };
1781
1782 let decrypted = DecryptContext::new(&resolver)
1783 .decrypt_data(&encrypted)
1784 .expect("a later authenticated candidate must decrypt");
1785
1786 assert_eq!(
1787 decrypted,
1788 DecryptedContent::Bytes(b"candidate plaintext".to_vec())
1789 );
1790 }
1791
1792 #[test]
1793 fn standalone_decryption_stops_after_first_successful_candidate() {
1794 let provider = PermissiveUnwrapProvider {
1797 plaintext: b"accepted".to_vec(),
1798 ..PermissiveUnwrapProvider::default()
1799 };
1800 let resolver = CandidateResolver {
1801 keys: vec![vec![1_u8; 16], vec![2_u8; 16], vec![3_u8; 16]],
1802 };
1803 let encrypted = EncryptedData {
1804 id: None,
1805 encrypted_type: None,
1806 encryption_method: EncryptionMethod {
1807 algorithm: DataEncryptionAlgorithm::Aes128Gcm.uri().into(),
1808 key_size_bits: None,
1809 oaep_digest: None,
1810 mgf_algorithm: None,
1811 oaep_params: None,
1812 },
1813 key_name: None,
1814 encrypted_keys: Vec::new(),
1815 cipher_data: CipherData {
1816 value: STANDARD.encode([0_u8; 36]),
1817 },
1818 };
1819
1820 let result = DecryptContext::new(&resolver)
1821 .provider(&provider)
1822 .decrypt_data(&encrypted)
1823 .expect("the first successful candidate must be returned");
1824
1825 assert_eq!(result, DecryptedContent::Bytes(b"accepted".to_vec()));
1826 assert_eq!(provider.decrypt_calls.load(Ordering::Relaxed), 1);
1827 }
1828
1829 #[test]
1830 fn document_decryption_discards_rejected_plaintext_before_next_candidate() {
1831 let provider = PermissiveUnwrapProvider {
1834 candidate_plaintexts: vec![b"<bad".to_vec(), b"<x/>".to_vec(), b"<u/>".to_vec()],
1835 ..PermissiveUnwrapProvider::default()
1836 };
1837 let resolver = CandidateResolver {
1838 keys: vec![vec![1_u8; 16], vec![2_u8; 16], vec![3_u8; 16]],
1839 };
1840 let encrypted = format!(
1841 "<xenc:EncryptedData xmlns:xenc=\"{XMLENC_NS}\" Type=\"{XMLENC_NS}Element\"><xenc:EncryptionMethod Algorithm=\"{}\"/><xenc:CipherData><xenc:CipherValue>{}</xenc:CipherValue></xenc:CipherData></xenc:EncryptedData>",
1842 DataEncryptionAlgorithm::Aes128Gcm.uri(),
1843 STANDARD.encode([0_u8; 32]),
1844 );
1845
1846 let result = DecryptContext::new(&resolver)
1847 .provider(&provider)
1848 .decrypt_document(&encrypted, None)
1849 .expect("a later candidate with valid replacement XML must succeed");
1850
1851 assert_eq!(result, "<x/>");
1852 assert_eq!(provider.decrypt_calls.load(Ordering::Relaxed), 2);
1853 }
1854
1855 #[test]
1856 fn cbc_rejects_multiple_unordered_key_candidates() {
1857 let encrypted = EncryptedData {
1860 id: None,
1861 encrypted_type: None,
1862 encryption_method: EncryptionMethod {
1863 algorithm: DataEncryptionAlgorithm::Aes128Cbc.uri().into(),
1864 key_size_bits: None,
1865 oaep_digest: None,
1866 mgf_algorithm: None,
1867 oaep_params: None,
1868 },
1869 key_name: None,
1870 encrypted_keys: Vec::new(),
1871 cipher_data: CipherData {
1872 value: STANDARD.encode(
1873 crate::provider::default_provider()
1874 .encrypt_data(
1875 DataEncryptionAlgorithm::Aes128Cbc,
1876 &[7_u8; 16],
1877 b"opaque plaintext",
1878 )
1879 .expect("test encryption must succeed"),
1880 ),
1881 },
1882 };
1883 let resolver = CandidateResolver {
1884 keys: vec![vec![1_u8; 16], vec![7_u8; 16]],
1885 };
1886
1887 let error = DecryptContext::new(&resolver)
1888 .decrypt_data(&encrypted)
1889 .expect_err("unauthenticated CBC must not guess among candidate keys");
1890
1891 assert!(matches!(
1892 error,
1893 XmlEncError::AmbiguousKeyCandidates {
1894 algorithm: DataEncryptionAlgorithm::Aes128Cbc,
1895 actual: 2,
1896 }
1897 ));
1898 }
1899
1900 #[test]
1901 fn cbc_accepts_duplicate_copies_of_one_key_identity() {
1902 let key = vec![0x27_u8; 16];
1905 let encrypted = EncryptedData {
1906 id: None,
1907 encrypted_type: None,
1908 encryption_method: EncryptionMethod {
1909 algorithm: DataEncryptionAlgorithm::Aes128Cbc.uri().into(),
1910 key_size_bits: None,
1911 oaep_digest: None,
1912 mgf_algorithm: None,
1913 oaep_params: None,
1914 },
1915 key_name: None,
1916 encrypted_keys: Vec::new(),
1917 cipher_data: CipherData {
1918 value: STANDARD.encode(
1919 crate::provider::default_provider()
1920 .encrypt_data(
1921 DataEncryptionAlgorithm::Aes128Cbc,
1922 &key,
1923 b"duplicate identity",
1924 )
1925 .expect("test encryption must succeed"),
1926 ),
1927 },
1928 };
1929 let resolver = CandidateResolver {
1930 keys: vec![key.clone(), key],
1931 };
1932
1933 assert_eq!(
1934 DecryptContext::new(&resolver)
1935 .decrypt_data(&encrypted)
1936 .expect("one distinct CBC key identity must decrypt"),
1937 DecryptedContent::Bytes(b"duplicate identity".to_vec())
1938 );
1939 }
1940
1941 #[test]
1942 fn candidate_keys_are_bounded_before_cryptographic_processing() {
1943 let encrypted = EncryptedData {
1946 id: None,
1947 encrypted_type: None,
1948 encryption_method: EncryptionMethod {
1949 algorithm: DataEncryptionAlgorithm::Aes128Gcm.uri().into(),
1950 key_size_bits: None,
1951 oaep_digest: None,
1952 mgf_algorithm: None,
1953 oaep_params: None,
1954 },
1955 key_name: None,
1956 encrypted_keys: Vec::new(),
1957 cipher_data: CipherData {
1958 value: STANDARD.encode(vec![0_u8; 28]),
1959 },
1960 };
1961 let actual = crate::hard_limits::KEY_CANDIDATE_CEILING + 1;
1962 let resolver = CandidateResolver {
1963 keys: vec![vec![0_u8; 16]; actual],
1964 };
1965
1966 let error = DecryptContext::new(&resolver)
1967 .decrypt_data(&encrypted)
1968 .expect_err("oversized candidate sets must fail before decryption");
1969
1970 assert!(matches!(
1971 error,
1972 XmlEncError::Policy(crate::policy::PolicyViolation::ResourceLimit {
1973 resource: crate::policy::resource_name::KEY_CANDIDATES,
1974 maximum: crate::hard_limits::KEY_CANDIDATE_CEILING,
1975 actual: observed,
1976 }) if observed == actual
1977 ));
1978 }
1979
1980 #[test]
1981 fn operation_policy_controls_candidate_budget() {
1982 let encrypted = EncryptedData {
1985 id: None,
1986 encrypted_type: None,
1987 encryption_method: EncryptionMethod {
1988 algorithm: DataEncryptionAlgorithm::Aes128Gcm.uri().into(),
1989 key_size_bits: None,
1990 oaep_digest: None,
1991 mgf_algorithm: None,
1992 oaep_params: None,
1993 },
1994 key_name: None,
1995 encrypted_keys: Vec::new(),
1996 cipher_data: CipherData {
1997 value: STANDARD.encode(vec![0_u8; 28]),
1998 },
1999 };
2000 let resolver = CandidateResolver {
2001 keys: vec![vec![0_u8; 16]; 3],
2002 };
2003 let mut policy = crate::policy::DecryptionPolicy::default();
2004 policy.resources.max_key_candidates = 2;
2005
2006 let error = DecryptContext::new(&resolver)
2007 .policy(policy)
2008 .decrypt_data(&encrypted)
2009 .expect_err("candidate accounting must use the operation policy ceiling");
2010
2011 assert!(matches!(
2012 error,
2013 XmlEncError::Policy(crate::policy::PolicyViolation::ResourceLimit {
2014 resource: crate::policy::resource_name::KEY_CANDIDATES,
2015 maximum: 2,
2016 actual: 3,
2017 })
2018 ));
2019 }
2020
2021 #[test]
2022 fn candidate_work_ceiling_is_shared_across_recipients() {
2023 let key = vec![0x39_u8; 16];
2026 let resolver = AggregateRecipientResolver {
2027 attempts: Cell::new(0),
2028 key: key.clone(),
2029 };
2030 let encrypted = encrypted_data_with_recipients(
2031 &key,
2032 vec![
2033 associated_encrypted_key("first", None, None),
2034 associated_encrypted_key("second", None, None),
2035 ],
2036 None,
2037 );
2038
2039 DecryptContext::new(&resolver)
2040 .decrypt_data(&encrypted)
2041 .expect_err("a second recipient must not receive a fresh candidate allowance");
2042 assert_eq!(
2043 resolver.attempts.get(),
2044 crate::hard_limits::KEY_CANDIDATE_CEILING
2045 );
2046 }
2047
2048 #[test]
2049 fn candidate_budget_exhaustion_is_fatal_after_a_key_was_found() {
2050 let key = vec![0x49_u8; 16];
2053 let resolver = MislabelledExhaustionResolver {
2054 direct: key.clone(),
2055 };
2056 let encrypted = encrypted_data_with_recipients(
2057 &key,
2058 vec![associated_encrypted_key("recipient", None, None)],
2059 None,
2060 );
2061
2062 let error = DecryptContext::new(&resolver)
2063 .decrypt_data(&encrypted)
2064 .expect_err("candidate exhaustion must override an earlier usable key");
2065
2066 assert!(matches!(
2067 error,
2068 XmlEncError::Policy(crate::policy::PolicyViolation::ResourceLimit {
2069 resource: "key candidates",
2070 maximum: crate::hard_limits::KEY_CANDIDATE_CEILING,
2071 actual,
2072 }) if actual == crate::hard_limits::KEY_CANDIDATE_CEILING + 1
2073 ));
2074 }
2075
2076 #[test]
2077 fn authenticated_decryption_continues_after_wrong_unwrapped_recipient_key() {
2078 let correct = vec![0x53_u8; 16];
2081 let encrypted = encrypted_data_with_recipients(
2082 &correct,
2083 vec![
2084 associated_encrypted_key("first", None, None),
2085 associated_encrypted_key("second", None, None),
2086 ],
2087 None,
2088 );
2089 let resolver = OrderedRecipientResolver {
2090 wrong: vec![0x11_u8; 16],
2091 correct,
2092 };
2093
2094 let plaintext = DecryptContext::new(&resolver)
2095 .decrypt_data(&encrypted)
2096 .expect("the second recipient key must authenticate");
2097 assert_eq!(plaintext, DecryptedContent::Bytes(b"payload".to_vec()));
2098 }
2099
2100 #[test]
2101 fn authenticated_decryption_continues_from_direct_key_to_recipient() {
2102 let correct = vec![0x63_u8; 16];
2105 let encrypted = encrypted_data_with_recipients(
2106 &correct,
2107 vec![associated_encrypted_key("recipient", None, None)],
2108 None,
2109 );
2110 let resolver = DirectAndRecipientResolver {
2111 direct: vec![0x19_u8; 16],
2112 recipient: correct,
2113 };
2114
2115 let plaintext = DecryptContext::new(&resolver)
2116 .decrypt_data(&encrypted)
2117 .expect("the embedded recipient must remain available after a direct candidate");
2118
2119 assert_eq!(plaintext, DecryptedContent::Bytes(b"payload".to_vec()));
2120 }
2121
2122 #[test]
2123 fn authenticated_decryption_continues_after_direct_lookup_error() {
2124 let correct = vec![0x64_u8; 16];
2127 let encrypted = encrypted_data_with_recipients(
2128 &correct,
2129 vec![associated_encrypted_key("recipient", None, None)],
2130 None,
2131 );
2132 let resolver = FailingDirectResolver { recipient: correct };
2133
2134 let plaintext = DecryptContext::new(&resolver)
2135 .decrypt_data(&encrypted)
2136 .expect("recipient lookup must follow a candidate-local direct error");
2137
2138 assert_eq!(plaintext, DecryptedContent::Bytes(b"payload".to_vec()));
2139 }
2140
2141 #[test]
2142 fn resolver_policy_rejection_stops_before_later_recipient() {
2143 let correct = vec![0x65_u8; 16];
2146 let encrypted = encrypted_data_with_recipients(
2147 &correct,
2148 vec![associated_encrypted_key("recipient", None, None)],
2149 None,
2150 );
2151 let resolver = PolicyRejectingDirectResolver { recipient: correct };
2152
2153 let error = DecryptContext::new(&resolver)
2154 .decrypt_data(&encrypted)
2155 .expect_err("operation policy rejection must be fatal");
2156
2157 assert!(matches!(
2158 error,
2159 XmlEncError::Policy(crate::policy::PolicyViolation::KeyTrust {
2160 reason: "test resolver rejected the operation",
2161 })
2162 ));
2163 }
2164
2165 #[test]
2166 fn cbc_rejects_distinct_direct_and_recipient_candidates() {
2167 let recipient = vec![0x73_u8; 16];
2170 let mut encrypted = encrypted_data_with_recipients(
2171 &recipient,
2172 vec![associated_encrypted_key("recipient", None, None)],
2173 None,
2174 );
2175 encrypted.encryption_method.algorithm = DataEncryptionAlgorithm::Aes128Cbc.uri().into();
2176 encrypted.cipher_data.value = STANDARD.encode(
2177 crate::provider::default_provider()
2178 .encrypt_data(DataEncryptionAlgorithm::Aes128Cbc, &recipient, b"payload")
2179 .expect("test encryption must succeed"),
2180 );
2181 let resolver = DirectAndRecipientResolver {
2182 direct: vec![0x29_u8; 16],
2183 recipient,
2184 };
2185
2186 let error = DecryptContext::new(&resolver)
2187 .decrypt_data(&encrypted)
2188 .expect_err("CBC must not guess between direct and recipient keys");
2189
2190 assert!(matches!(
2191 error,
2192 XmlEncError::AmbiguousKeyCandidates {
2193 algorithm: DataEncryptionAlgorithm::Aes128Cbc,
2194 actual: 2,
2195 }
2196 ));
2197 }
2198
2199 #[test]
2200 fn cbc_ambiguity_ignores_algorithm_incompatible_key_widths() {
2201 let key = vec![0x47_u8; 16];
2204 let ciphertext = crate::provider::default_provider()
2205 .encrypt_data(DataEncryptionAlgorithm::Aes128Cbc, &key, b"payload")
2206 .expect("test encryption must succeed");
2207 let encrypted = EncryptedData {
2208 id: None,
2209 encrypted_type: None,
2210 encryption_method: EncryptionMethod {
2211 algorithm: DataEncryptionAlgorithm::Aes128Cbc.uri().into(),
2212 key_size_bits: None,
2213 oaep_digest: None,
2214 mgf_algorithm: None,
2215 oaep_params: None,
2216 },
2217 key_name: None,
2218 encrypted_keys: Vec::new(),
2219 cipher_data: CipherData {
2220 value: STANDARD.encode(ciphertext),
2221 },
2222 };
2223 let resolver = CandidateResolver {
2224 keys: vec![vec![0_u8; 32], key],
2225 };
2226
2227 assert_eq!(
2228 DecryptContext::new(&resolver)
2229 .decrypt_data(&encrypted)
2230 .expect("the sole width-compatible CBC key must be selected"),
2231 DecryptedContent::Bytes(b"payload".to_vec())
2232 );
2233 }
2234
2235 #[test]
2236 fn data_reference_selects_the_associated_encrypted_key() {
2237 let key = vec![0x51_u8; 16];
2240 let resolver = AssociationRecordingResolver {
2241 visited: RefCell::new(Vec::new()),
2242 key: key.clone(),
2243 };
2244 let encrypted = encrypted_data_with_recipients(
2245 &key,
2246 vec![
2247 associated_encrypted_key("unrelated", Some("#other"), None),
2248 associated_encrypted_key("matching", Some("#target"), None),
2249 ],
2250 None,
2251 );
2252
2253 DecryptContext::new(&resolver)
2254 .decrypt_data(&encrypted)
2255 .expect("the associated recipient must decrypt");
2256 assert_eq!(resolver.visited.into_inner(), ["matching"]);
2257 }
2258
2259 #[test]
2260 fn carried_key_name_selects_the_named_content_key() {
2261 let key = vec![0x52_u8; 16];
2264 let resolver = AssociationRecordingResolver {
2265 visited: RefCell::new(Vec::new()),
2266 key: key.clone(),
2267 };
2268 let encrypted = encrypted_data_with_recipients(
2269 &key,
2270 vec![
2271 associated_encrypted_key("unrelated", None, Some("other")),
2272 associated_encrypted_key("matching", None, Some("wanted")),
2273 ],
2274 Some("wanted"),
2275 );
2276
2277 DecryptContext::new(&resolver)
2278 .decrypt_data(&encrypted)
2279 .expect("the matching carried key name must decrypt");
2280 assert_eq!(resolver.visited.into_inner(), ["matching"]);
2281 }
2282
2283 #[test]
2284 fn contradictory_encrypted_key_associations_fail_closed() {
2285 let key = vec![0x53_u8; 16];
2288 let resolver = AssociationRecordingResolver {
2289 visited: RefCell::new(Vec::new()),
2290 key: key.clone(),
2291 };
2292 let encrypted = encrypted_data_with_recipients(
2293 &key,
2294 vec![associated_encrypted_key("unrelated", Some("#other"), None)],
2295 None,
2296 );
2297
2298 assert!(matches!(
2299 DecryptContext::new(&resolver).decrypt_data(&encrypted),
2300 Err(XmlEncError::KeyNotFound)
2301 ));
2302 assert!(resolver.visited.into_inner().is_empty());
2303 }
2304
2305 #[test]
2306 fn direct_symmetric_key_ignores_embedded_key_hints() {
2307 let key = [0x28_u8; 16];
2310 let unrelated = EncryptedKey {
2311 id: None,
2312 recipient: Some("other-recipient".into()),
2313 key_name: None,
2314 encryption_method: super::super::EncryptionMethod {
2315 algorithm: "urn:unrelated:key-transport".into(),
2316 key_size_bits: None,
2317 oaep_digest: None,
2318 mgf_algorithm: None,
2319 oaep_params: None,
2320 },
2321 cipher_data: super::super::CipherData {
2322 value: STANDARD.encode([0_u8; 24]),
2323 },
2324 reference_list: None,
2325 carried_key_name: None,
2326 };
2327
2328 assert_eq!(
2329 SymmetricKeyDecryptor::new(key)
2330 .resolve_key(
2331 crate::provider::default_provider(),
2332 DataEncryptionAlgorithm::Aes128Gcm,
2333 Some(&unrelated)
2334 )
2335 .expect("direct key must ignore unrelated embedded hints"),
2336 key
2337 );
2338 }
2339
2340 #[test]
2341 fn decrypts_with_the_matching_recipient_key() {
2342 let key = [0x29_u8; 16];
2345 let plaintext = "recipient-specific plaintext";
2346 let encrypted = encrypted_gcm_element("", plaintext, None, true, &key);
2347 let recipient_key = |recipient: &str, method: &str| {
2348 format!(
2349 "<xenc:EncryptedKey Recipient=\"{recipient}\"><xenc:EncryptionMethod Algorithm=\"{method}\">{}</xenc:EncryptionMethod><xenc:CipherData><xenc:CipherValue>YQ==</xenc:CipherValue></xenc:CipherData></xenc:EncryptedKey>",
2350 if recipient == "alice" {
2351 "<ds:DigestMethod Algorithm=\"urn:unsupported:digest\"/>"
2352 } else {
2353 ""
2354 }
2355 )
2356 };
2357 let key_info = format!(
2358 "<ds:KeyInfo xmlns:ds=\"{}\">{}{}</ds:KeyInfo>",
2359 crate::xmlenc::types::XMLDSIG_NS,
2360 recipient_key("alice", KeyTransportAlgorithm::RsaOaep11.uri()),
2361 recipient_key("bob", KeyWrapAlgorithm::AesKw128.uri())
2362 );
2363 let xml = encrypted.replacen(
2364 "<xenc:CipherData>",
2365 &format!("{key_info}<xenc:CipherData>"),
2366 1,
2367 );
2368 let resolver = RecipientKeyResolver {
2369 recipient: "bob",
2370 key: key.to_vec(),
2371 };
2372
2373 assert_eq!(
2374 decrypt(&xml, &resolver).expect("second recipient key must be tried"),
2375 DecryptedContent::Bytes(plaintext.as_bytes().to_vec())
2376 );
2377 }
2378
2379 #[test]
2380 fn decryption_policy_bounds_recipients_before_key_resolution() {
2381 let key = [0x29_u8; 16];
2384 let encrypted = encrypted_gcm_element("", "bounded recipients", None, true, &key);
2385 let recipient_key = |recipient: &str| {
2386 format!(
2387 "<xenc:EncryptedKey Recipient=\"{recipient}\"><xenc:EncryptionMethod Algorithm=\"urn:test:key\"/><xenc:CipherData><xenc:CipherValue>YQ==</xenc:CipherValue></xenc:CipherData></xenc:EncryptedKey>"
2388 )
2389 };
2390 let key_info = format!(
2391 "<ds:KeyInfo xmlns:ds=\"{}\">{}{}</ds:KeyInfo>",
2392 crate::xmlenc::types::XMLDSIG_NS,
2393 recipient_key("alice"),
2394 recipient_key("bob")
2395 );
2396 let xml = encrypted.replacen(
2397 "<xenc:CipherData>",
2398 &format!("{key_info}<xenc:CipherData>"),
2399 1,
2400 );
2401 let parsed = parse_encrypted_data(&xml).expect("default parser accepts two recipients");
2402 let policy = crate::policy::DecryptionPolicy {
2403 resources: crate::policy::ResourcePolicy {
2404 max_encryption_recipients: 1,
2405 ..crate::policy::ResourcePolicy::default()
2406 },
2407 ..crate::policy::DecryptionPolicy::default()
2408 };
2409 let resolver = SymmetricKeyDecryptor::new(key);
2410 let context = DecryptContext::new(&resolver).policy(policy);
2411
2412 for error in [
2413 context
2414 .decrypt(&xml)
2415 .expect_err("XML recipient collection must be bounded"),
2416 context
2417 .decrypt_data(&parsed)
2418 .expect_err("typed recipient collection must be bounded"),
2419 ] {
2420 assert!(matches!(
2421 error,
2422 XmlEncError::Policy(crate::policy::PolicyViolation::ResourceLimit {
2423 resource: crate::policy::resource_name::ENCRYPTION_RECIPIENTS,
2424 maximum: 1,
2425 actual: 2,
2426 })
2427 ));
2428 }
2429 }
2430
2431 #[test]
2432 fn decrypts_session_key_wrapped_with_aes_kw() {
2433 let kek = [3_u8; 16];
2435 let session_key = [4_u8; 16];
2436 let mut wrapped = [0_u8; 24];
2437 KwAes128::new_from_slice(&kek)
2438 .expect("fixed KEK length")
2439 .wrap_key(&session_key, &mut wrapped)
2440 .expect("RFC 3394 test wrapping must succeed");
2441 let encrypted_key = EncryptedKey {
2442 id: None,
2443 recipient: None,
2444 key_name: None,
2445 encryption_method: super::super::EncryptionMethod {
2446 algorithm: "http://www.w3.org/2001/04/xmlenc#kw-aes128".into(),
2447 key_size_bits: None,
2448 oaep_digest: None,
2449 mgf_algorithm: None,
2450 oaep_params: None,
2451 },
2452 cipher_data: super::super::CipherData {
2453 value: STANDARD.encode(wrapped),
2454 },
2455 reference_list: None,
2456 carried_key_name: None,
2457 };
2458 let resolved = KekDecryptor::new(kek)
2459 .resolve_key(
2460 crate::provider::default_provider(),
2461 DataEncryptionAlgorithm::Aes128Gcm,
2462 Some(&encrypted_key),
2463 )
2464 .expect("wrapped session key must resolve");
2465 assert_eq!(resolved, session_key);
2466 }
2467
2468 #[test]
2469 fn rejects_invalid_kek_before_custom_provider_dispatch() {
2470 let encrypted_key = EncryptedKey {
2473 id: None,
2474 recipient: None,
2475 key_name: None,
2476 encryption_method: super::super::EncryptionMethod {
2477 algorithm: KeyWrapAlgorithm::AesKw128.uri().into(),
2478 key_size_bits: None,
2479 oaep_digest: None,
2480 mgf_algorithm: None,
2481 oaep_params: None,
2482 },
2483 cipher_data: super::super::CipherData {
2484 value: STANDARD.encode([0_u8; 24]),
2485 },
2486 reference_list: None,
2487 carried_key_name: None,
2488 };
2489 let provider = PermissiveUnwrapProvider::default();
2490
2491 assert!(matches!(
2492 KekDecryptor::new([0_u8; 32]).resolve_key(
2493 &provider,
2494 DataEncryptionAlgorithm::Aes128Gcm,
2495 Some(&encrypted_key),
2496 ),
2497 Err(XmlEncError::InvalidKekSize {
2498 algorithm: KeyWrapAlgorithm::AesKw128,
2499 expected: 16,
2500 actual: 32,
2501 })
2502 ));
2503 assert_eq!(provider.unwrap_calls.load(Ordering::Relaxed), 0);
2504 }
2505
2506 #[test]
2507 fn rejects_content_ciphertext_framing_before_resolution_or_provider_dispatch() {
2508 for (algorithm, ciphertext_len) in [
2511 (DataEncryptionAlgorithm::Aes128Gcm, 27),
2512 (DataEncryptionAlgorithm::Aes128Cbc, 33),
2513 ] {
2514 let resolver = AllCallsResolver {
2515 calls: Cell::new(0),
2516 key: vec![0_u8; algorithm.key_len()],
2517 };
2518 let provider = PermissiveUnwrapProvider::default();
2519 let encrypted = EncryptedData {
2520 id: None,
2521 encrypted_type: None,
2522 key_name: None,
2523 encryption_method: super::super::EncryptionMethod {
2524 algorithm: algorithm.uri().into(),
2525 key_size_bits: None,
2526 oaep_digest: None,
2527 mgf_algorithm: None,
2528 oaep_params: None,
2529 },
2530 encrypted_keys: Vec::new(),
2531 cipher_data: super::super::CipherData {
2532 value: STANDARD.encode(vec![0_u8; ciphertext_len]),
2533 },
2534 };
2535
2536 assert!(
2537 DecryptContext::new(&resolver)
2538 .provider(&provider)
2539 .decrypt_data(&encrypted)
2540 .is_err()
2541 );
2542 assert_eq!(resolver.calls.get(), 0);
2543 assert_eq!(provider.decrypt_calls.load(Ordering::Relaxed), 0);
2544 }
2545 }
2546
2547 #[test]
2548 fn rejects_custom_provider_plaintext_outside_algorithm_bounds() {
2549 for (algorithm, ciphertext_len, plaintext_len) in [
2552 (DataEncryptionAlgorithm::Aes128Gcm, 32, 5),
2553 (DataEncryptionAlgorithm::Aes128Cbc, 32, 16),
2554 ] {
2555 let resolver = AllCallsResolver {
2556 calls: Cell::new(0),
2557 key: vec![0_u8; algorithm.key_len()],
2558 };
2559 let provider = PermissiveUnwrapProvider {
2560 plaintext: vec![0_u8; plaintext_len],
2561 ..PermissiveUnwrapProvider::default()
2562 };
2563 let encrypted = EncryptedData {
2564 id: None,
2565 encrypted_type: None,
2566 key_name: None,
2567 encryption_method: super::super::EncryptionMethod {
2568 algorithm: algorithm.uri().into(),
2569 key_size_bits: None,
2570 oaep_digest: None,
2571 mgf_algorithm: None,
2572 oaep_params: None,
2573 },
2574 encrypted_keys: Vec::new(),
2575 cipher_data: super::super::CipherData {
2576 value: STANDARD.encode(vec![0_u8; ciphertext_len]),
2577 },
2578 };
2579
2580 let error = DecryptContext::new(&resolver)
2581 .provider(&provider)
2582 .decrypt_data(&encrypted)
2583 .expect_err("impossible provider output length must fail");
2584 match algorithm {
2585 DataEncryptionAlgorithm::Aes128Gcm => assert!(matches!(
2586 error,
2587 XmlEncError::Provider(crate::provider::ProviderError::InvalidOutputSize {
2588 operation: crate::provider::ProviderOperation::Decrypt,
2589 expected: 4,
2590 actual: 5,
2591 })
2592 )),
2593 DataEncryptionAlgorithm::Aes128Cbc => assert!(matches!(
2594 error,
2595 XmlEncError::Provider(crate::provider::ProviderError::InvalidOutputSizeRange {
2596 operation: crate::provider::ProviderOperation::Decrypt,
2597 minimum: 0,
2598 maximum: 15,
2599 actual: 16,
2600 })
2601 )),
2602 _ => unreachable!("the regression table covers one GCM and one CBC algorithm"),
2603 }
2604 assert_eq!(provider.decrypt_calls.load(Ordering::Relaxed), 1);
2605 }
2606 }
2607
2608 #[test]
2609 fn rejects_malformed_aes_kw_before_custom_provider_dispatch() {
2610 let provider = PermissiveUnwrapProvider::default();
2613 for actual in [0, 23, 25] {
2614 let encrypted_key = EncryptedKey {
2615 id: None,
2616 recipient: None,
2617 key_name: None,
2618 encryption_method: super::super::EncryptionMethod {
2619 algorithm: KeyWrapAlgorithm::AesKw128.uri().into(),
2620 key_size_bits: None,
2621 oaep_digest: None,
2622 mgf_algorithm: None,
2623 oaep_params: None,
2624 },
2625 cipher_data: super::super::CipherData {
2626 value: STANDARD.encode(vec![0_u8; actual]),
2627 },
2628 reference_list: None,
2629 carried_key_name: None,
2630 };
2631 assert!(matches!(
2632 KekDecryptor::new([0_u8; 16]).resolve_key(
2633 &provider,
2634 DataEncryptionAlgorithm::Aes128Gcm,
2635 Some(&encrypted_key),
2636 ),
2637 Err(XmlEncError::InvalidWrappedKeyLength {
2638 expected: 24,
2639 actual: output_len,
2640 }) if output_len == actual
2641 ));
2642 }
2643 assert_eq!(provider.unwrap_calls.load(Ordering::Relaxed), 0);
2644 }
2645
2646 #[test]
2647 fn rejects_malformed_rsa_oaep_before_custom_provider_dispatch() {
2648 let private_key = RsaPrivateKey::from_pkcs8_pem(include_str!(
2651 "../../tests/fixtures/keys/rsa/rsa-2048-key.pem"
2652 ))
2653 .expect("RSA donor private key must parse");
2654 let provider = PermissiveUnwrapProvider::default();
2655 for actual in [0, 255, 257] {
2656 assert!(matches!(
2657 recover_rsa_oaep(
2658 &provider,
2659 &private_key,
2660 &RsaOaepParameters::default(),
2661 &vec![0_u8; actual],
2662 ),
2663 Err(XmlEncError::InvalidWrappedKeyLength {
2664 expected: 256,
2665 actual: output_len,
2666 }) if output_len == actual
2667 ));
2668 }
2669 assert_eq!(provider.recover_calls.load(Ordering::Relaxed), 0);
2670 }
2671
2672 #[test]
2673 fn custom_provider_recovers_with_an_opaque_private_key() {
2674 let encrypted_key = EncryptedKey {
2677 id: None,
2678 recipient: None,
2679 key_name: None,
2680 encryption_method: super::super::EncryptionMethod {
2681 algorithm: KeyTransportAlgorithm::RsaOaep11.uri().into(),
2682 key_size_bits: None,
2683 oaep_digest: Some(OaepDigestAlgorithm::Sha256.uri().into()),
2684 mgf_algorithm: Some(OaepDigestAlgorithm::Sha256.mgf_uri().into()),
2685 oaep_params: None,
2686 },
2687 cipher_data: super::super::CipherData {
2688 value: STANDARD.encode(vec![0x5a; 256]),
2689 },
2690 reference_list: None,
2691 carried_key_name: None,
2692 };
2693 let provider = PermissiveUnwrapProvider::default();
2694 let decryptor = PrivateKeyDecryptor::provider_key(Arc::new(OpaqueRecoveryKey));
2695
2696 let key = decryptor
2697 .resolve_key(
2698 &provider,
2699 DataEncryptionAlgorithm::Aes128Gcm,
2700 Some(&encrypted_key),
2701 )
2702 .expect("custom provider must recover through its opaque private key");
2703
2704 assert_eq!(key, vec![0_u8; 16]);
2705 assert_eq!(provider.recover_calls.load(Ordering::Relaxed), 1);
2706 }
2707
2708 #[test]
2709 fn rejects_truncated_gcm_and_invalid_wrapped_key() {
2710 assert!(matches!(
2712 crate::provider::default_provider().decrypt_data(
2713 DataEncryptionAlgorithm::Aes128Gcm,
2714 &[0_u8; 16],
2715 &[0_u8; 27],
2716 ),
2717 Err(crate::provider::ProviderError::InvalidInput(
2718 crate::provider::ProviderInputError::AesGcmFraming
2719 ))
2720 ));
2721 let truncated = EncryptedData {
2722 id: None,
2723 encrypted_type: None,
2724 key_name: None,
2725 encryption_method: super::super::EncryptionMethod {
2726 algorithm: DataEncryptionAlgorithm::Aes128Gcm.uri().into(),
2727 key_size_bits: None,
2728 oaep_digest: None,
2729 mgf_algorithm: None,
2730 oaep_params: None,
2731 },
2732 encrypted_keys: Vec::new(),
2733 cipher_data: super::super::CipherData {
2734 value: STANDARD.encode([0_u8; 27]),
2735 },
2736 };
2737 assert!(matches!(
2738 DecryptContext::new(&SymmetricKeyDecryptor::new([0_u8; 16])).decrypt_data(&truncated),
2739 Err(XmlEncError::DataTooShort {
2740 algorithm: "AES-GCM",
2741 actual: 27,
2742 ..
2743 })
2744 ));
2745 let encrypted_key = EncryptedKey {
2746 id: None,
2747 recipient: None,
2748 key_name: None,
2749 encryption_method: super::super::EncryptionMethod {
2750 algorithm: "http://www.w3.org/2001/04/xmlenc#kw-aes128".into(),
2751 key_size_bits: None,
2752 oaep_digest: None,
2753 mgf_algorithm: None,
2754 oaep_params: None,
2755 },
2756 cipher_data: super::super::CipherData {
2757 value: STANDARD.encode([0_u8; 24]),
2758 },
2759 reference_list: None,
2760 carried_key_name: None,
2761 };
2762 assert!(matches!(
2763 KekDecryptor::new([0_u8; 16]).resolve_key(
2764 crate::provider::default_provider(),
2765 DataEncryptionAlgorithm::Aes128Gcm,
2766 Some(&encrypted_key)
2767 ),
2768 Err(XmlEncError::KeyWrapIntegrity)
2769 ));
2770 assert!(matches!(
2771 KekDecryptor::new([0_u8; 32]).resolve_key(
2772 crate::provider::default_provider(),
2773 DataEncryptionAlgorithm::Aes128Gcm,
2774 Some(&encrypted_key)
2775 ),
2776 Err(XmlEncError::InvalidKekSize {
2777 algorithm: KeyWrapAlgorithm::AesKw128,
2778 expected: 16,
2779 actual: 32
2780 })
2781 ));
2782 }
2783
2784 #[test]
2785 fn decrypts_oaep11_with_independent_digest_and_mgf() {
2786 let private_key = RsaPrivateKey::from_pkcs8_pem(include_str!(
2788 "../../tests/fixtures/keys/rsa/rsa-2048-key.pem"
2789 ))
2790 .expect("RSA donor private key must parse");
2791 let public_key = RsaPublicKey::from(&private_key);
2792 let session_key = [6_u8; 16];
2793 let label = b"xmlenc-label".to_vec();
2794 let wrapped = public_key
2795 .encrypt(
2796 &mut ChaCha20Rng::from_seed([17_u8; 32]),
2797 Oaep::<Sha256, Sha384>::new_with_mgf_hash_and_label(label.clone()),
2798 &session_key,
2799 )
2800 .expect("OAEP test wrapping must succeed");
2801 let encrypted_key = EncryptedKey {
2802 id: Some("wrapped-key".into()),
2803 recipient: Some("recipient-a".into()),
2804 key_name: None,
2805 encryption_method: super::super::EncryptionMethod {
2806 algorithm: "http://www.w3.org/2009/xmlenc11#rsa-oaep".into(),
2807 key_size_bits: None,
2808 oaep_digest: Some("http://www.w3.org/2001/04/xmlenc#sha256".into()),
2809 mgf_algorithm: Some("http://www.w3.org/2009/xmlenc11#mgf1sha384".into()),
2810 oaep_params: Some(label),
2811 },
2812 cipher_data: super::super::CipherData {
2813 value: STANDARD.encode(wrapped),
2814 },
2815 reference_list: None,
2816 carried_key_name: None,
2817 };
2818 let resolved = PrivateKeyDecryptor::new(private_key)
2819 .resolve_key(
2820 crate::provider::default_provider(),
2821 DataEncryptionAlgorithm::Aes128Gcm,
2822 Some(&encrypted_key),
2823 )
2824 .expect("OAEP 1.1 wrapped key must resolve");
2825 assert_eq!(resolved, session_key);
2826 }
2827
2828 #[test]
2829 fn decrypts_legacy_oaep_uri_with_sha256_digest() {
2830 let private_key = RsaPrivateKey::from_pkcs8_pem(include_str!(
2832 "../../tests/fixtures/keys/rsa/rsa-2048-key.pem"
2833 ))
2834 .expect("RSA donor private key must parse");
2835 let public_key = RsaPublicKey::from(&private_key);
2836 let session_key = [8_u8; 16];
2837 let wrapped = public_key
2838 .encrypt(
2839 &mut ChaCha20Rng::from_seed([19_u8; 32]),
2840 Oaep::<Sha256, Sha1>::new_with_mgf_hash(),
2841 &session_key,
2842 )
2843 .expect("legacy OAEP URI test wrapping must succeed");
2844 let encrypted_key = EncryptedKey {
2845 id: None,
2846 recipient: None,
2847 key_name: None,
2848 encryption_method: super::super::EncryptionMethod {
2849 algorithm: "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p".into(),
2850 key_size_bits: None,
2851 oaep_digest: Some("http://www.w3.org/2001/04/xmlenc#sha256".into()),
2852 mgf_algorithm: None,
2853 oaep_params: None,
2854 },
2855 cipher_data: super::super::CipherData {
2856 value: STANDARD.encode(wrapped),
2857 },
2858 reference_list: None,
2859 carried_key_name: None,
2860 };
2861 let resolved = PrivateKeyDecryptor::new(private_key)
2862 .resolve_key(
2863 crate::provider::default_provider(),
2864 DataEncryptionAlgorithm::Aes128Gcm,
2865 Some(&encrypted_key),
2866 )
2867 .expect("legacy OAEP URI with SHA-256 must resolve");
2868 assert_eq!(resolved, session_key);
2869 }
2870
2871 #[test]
2872 fn decrypts_sha384_oaep_with_the_xmlenc_digest_uri() {
2873 let private_key = RsaPrivateKey::from_pkcs8_pem(include_str!(
2876 "../../tests/fixtures/keys/rsa/rsa-2048-key.pem"
2877 ))
2878 .expect("RSA donor private key must parse");
2879 let public_key = RsaPublicKey::from(&private_key);
2880 let session_key = [9_u8; 16];
2881 let digest = "http://www.w3.org/2001/04/xmlenc#sha384";
2882
2883 for (algorithm, mgf_algorithm) in [
2884 ("http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p", None),
2885 (
2886 "http://www.w3.org/2009/xmlenc11#rsa-oaep",
2887 Some("http://www.w3.org/2009/xmlenc11#mgf1sha1"),
2888 ),
2889 ] {
2890 let wrapped = public_key
2891 .encrypt(
2892 &mut ChaCha20Rng::from_seed([23_u8; 32]),
2893 Oaep::<Sha384, Sha1>::new_with_mgf_hash(),
2894 &session_key,
2895 )
2896 .expect("SHA-384 OAEP test wrapping must succeed");
2897 let encrypted_key = EncryptedKey {
2898 id: None,
2899 recipient: None,
2900 key_name: None,
2901 encryption_method: super::super::EncryptionMethod {
2902 algorithm: algorithm.into(),
2903 key_size_bits: None,
2904 oaep_digest: Some(digest.into()),
2905 mgf_algorithm: mgf_algorithm.map(str::to_owned),
2906 oaep_params: None,
2907 },
2908 cipher_data: super::super::CipherData {
2909 value: STANDARD.encode(wrapped),
2910 },
2911 reference_list: None,
2912 carried_key_name: None,
2913 };
2914 let resolved = PrivateKeyDecryptor::new(private_key.clone())
2915 .resolve_key(
2916 crate::provider::default_provider(),
2917 DataEncryptionAlgorithm::Aes128Gcm,
2918 Some(&encrypted_key),
2919 )
2920 .expect("official XMLENC SHA-384 URI must resolve");
2921 assert_eq!(resolved, session_key);
2922 }
2923 }
2924
2925 #[test]
2926 fn rejects_unknown_oaep_digest_and_mgf_as_unsupported() {
2927 let private_key = RsaPrivateKey::from_pkcs8_pem(include_str!(
2929 "../../tests/fixtures/keys/rsa/rsa-2048-key.pem"
2930 ))
2931 .expect("RSA donor private key must parse");
2932 let decryptor = PrivateKeyDecryptor::new(private_key);
2933 let mut encrypted_key = EncryptedKey {
2934 id: None,
2935 recipient: None,
2936 key_name: None,
2937 encryption_method: super::super::EncryptionMethod {
2938 algorithm: "http://www.w3.org/2009/xmlenc11#rsa-oaep".into(),
2939 key_size_bits: None,
2940 oaep_digest: Some("urn:unsupported:digest".into()),
2941 mgf_algorithm: Some("http://www.w3.org/2009/xmlenc11#mgf1sha1".into()),
2942 oaep_params: None,
2943 },
2944 cipher_data: super::super::CipherData {
2945 value: STANDARD.encode([0_u8; 256]),
2946 },
2947 reference_list: None,
2948 carried_key_name: None,
2949 };
2950 assert!(matches!(
2951 decryptor.resolve_key(crate::provider::default_provider(), DataEncryptionAlgorithm::Aes128Gcm, Some(&encrypted_key)),
2952 Err(XmlEncError::UnsupportedAlgorithm(uri)) if uri == "urn:unsupported:digest"
2953 ));
2954
2955 encrypted_key.encryption_method.oaep_digest = None;
2956 encrypted_key.encryption_method.mgf_algorithm = Some("urn:unsupported:mgf".into());
2957 assert!(matches!(
2958 decryptor.resolve_key(crate::provider::default_provider(), DataEncryptionAlgorithm::Aes128Gcm, Some(&encrypted_key)),
2959 Err(XmlEncError::UnsupportedAlgorithm(uri)) if uri == "urn:unsupported:mgf"
2960 ));
2961 }
2962
2963 #[test]
2964 fn decryption_policy_enforces_oaep_digest_and_plaintext_limits() {
2965 let encrypted_key = EncryptedKey {
2968 id: None,
2969 recipient: Some("selected".into()),
2970 key_name: None,
2971 encryption_method: super::super::EncryptionMethod {
2972 algorithm: KeyTransportAlgorithm::RsaOaep11.uri().into(),
2973 key_size_bits: None,
2974 oaep_digest: Some(OaepDigestAlgorithm::Sha256.uri().into()),
2975 mgf_algorithm: Some("http://www.w3.org/2009/xmlenc11#mgf1sha1".into()),
2976 oaep_params: None,
2977 },
2978 cipher_data: super::super::CipherData {
2979 value: STANDARD.encode([0_u8; 256]),
2980 },
2981 reference_list: None,
2982 carried_key_name: None,
2983 };
2984 let encrypted = EncryptedData {
2985 id: None,
2986 encrypted_type: None,
2987 key_name: None,
2988 encryption_method: super::super::EncryptionMethod {
2989 algorithm: DataEncryptionAlgorithm::Aes128Gcm.uri().into(),
2990 key_size_bits: None,
2991 oaep_digest: None,
2992 mgf_algorithm: None,
2993 oaep_params: None,
2994 },
2995 encrypted_keys: vec![encrypted_key],
2996 cipher_data: super::super::CipherData {
2997 value: STANDARD.encode([0_u8; 28]),
2998 },
2999 };
3000 let policy = crate::policy::DecryptionPolicy {
3001 oaep_digests: Some(std::collections::HashSet::from([
3002 OaepDigestAlgorithm::Sha256,
3003 ])),
3004 ..crate::policy::DecryptionPolicy::default()
3005 };
3006 assert!(matches!(
3007 DecryptContext::new(&RecipientKeyResolver {
3008 recipient: "selected",
3009 key: vec![0_u8; 16],
3010 })
3011 .policy(policy)
3012 .decrypt_data(&encrypted),
3013 Err(XmlEncError::Policy(
3014 crate::policy::PolicyViolation::Algorithm { .. }
3015 ))
3016 ));
3017
3018 let ciphertext = crate::provider::default_provider()
3019 .encrypt_data(DataEncryptionAlgorithm::Aes128Gcm, &[0_u8; 16], b"four")
3020 .expect("test encryption must succeed");
3021 let bounded = EncryptedData {
3022 encrypted_keys: Vec::new(),
3023 cipher_data: super::super::CipherData {
3024 value: STANDARD.encode(ciphertext),
3025 },
3026 ..encrypted
3027 };
3028 let policy = crate::policy::DecryptionPolicy {
3029 resources: crate::policy::ResourcePolicy {
3030 max_encryption_plaintext_bytes: 3,
3031 ..crate::policy::ResourcePolicy::default()
3032 },
3033 ..crate::policy::DecryptionPolicy::default()
3034 };
3035 assert!(matches!(
3036 DecryptContext::new(&SymmetricKeyDecryptor::new([0_u8; 16]))
3037 .policy(policy)
3038 .decrypt_data(&bounded),
3039 Err(XmlEncError::Policy(
3040 crate::policy::PolicyViolation::ResourceLimit {
3041 resource: crate::policy::resource_name::ENCRYPTION_PLAINTEXT_BYTES,
3042 maximum: 3,
3043 actual: 4
3044 }
3045 ))
3046 ));
3047
3048 let cbc_ciphertext = crate::provider::default_provider()
3049 .encrypt_data(DataEncryptionAlgorithm::Aes128Cbc, &[0_u8; 16], b"four")
3050 .expect("test CBC encryption must succeed");
3051 let bounded_cbc = EncryptedData {
3052 encryption_method: super::super::EncryptionMethod {
3053 algorithm: DataEncryptionAlgorithm::Aes128Cbc.uri().into(),
3054 key_size_bits: None,
3055 oaep_digest: None,
3056 mgf_algorithm: None,
3057 oaep_params: None,
3058 },
3059 encrypted_keys: Vec::new(),
3060 cipher_data: super::super::CipherData {
3061 value: STANDARD.encode(cbc_ciphertext),
3062 },
3063 ..bounded
3064 };
3065 let policy = crate::policy::DecryptionPolicy {
3066 resources: crate::policy::ResourcePolicy {
3067 max_encryption_plaintext_bytes: 4,
3068 ..crate::policy::ResourcePolicy::default()
3069 },
3070 ..crate::policy::DecryptionPolicy::default()
3071 };
3072 assert_eq!(
3073 DecryptContext::new(&SymmetricKeyDecryptor::new([0_u8; 16]))
3074 .policy(policy)
3075 .decrypt_data(&bounded_cbc)
3076 .expect("CBC plaintext at the configured limit must decrypt"),
3077 DecryptedContent::Bytes(b"four".to_vec())
3078 );
3079 }
3080
3081 #[test]
3082 fn typed_decryption_input_cannot_bypass_metadata_policy() {
3083 let ciphertext = crate::provider::default_provider()
3086 .encrypt_data(DataEncryptionAlgorithm::Aes128Gcm, &[0_u8; 16], b"data")
3087 .expect("test encryption must succeed");
3088 let encrypted = EncryptedData {
3089 id: Some("oversized".into()),
3090 encrypted_type: None,
3091 key_name: None,
3092 encryption_method: super::super::EncryptionMethod {
3093 algorithm: DataEncryptionAlgorithm::Aes128Gcm.uri().into(),
3094 key_size_bits: None,
3095 oaep_digest: None,
3096 mgf_algorithm: None,
3097 oaep_params: None,
3098 },
3099 encrypted_keys: Vec::new(),
3100 cipher_data: super::super::CipherData {
3101 value: STANDARD.encode(ciphertext),
3102 },
3103 };
3104 let policy = crate::policy::DecryptionPolicy {
3105 resources: crate::policy::ResourcePolicy {
3106 max_encryption_metadata_bytes: 8,
3107 ..crate::policy::ResourcePolicy::default()
3108 },
3109 ..crate::policy::DecryptionPolicy::default()
3110 };
3111
3112 assert!(matches!(
3113 DecryptContext::new(&SymmetricKeyDecryptor::new([0_u8; 16]))
3114 .policy(policy)
3115 .decrypt_data(&encrypted),
3116 Err(XmlEncError::Policy(
3117 crate::policy::PolicyViolation::ResourceLimit {
3118 resource: crate::policy::resource_name::ENCRYPTION_METADATA_BYTES,
3119 maximum: 8,
3120 actual: 9,
3121 }
3122 ))
3123 ));
3124 }
3125
3126 #[test]
3127 fn typed_cipher_values_are_bounded_before_decode_or_resolution() {
3128 let key = [0x41_u8; 16];
3131 let ciphertext = crate::provider::default_provider()
3132 .encrypt_data(DataEncryptionAlgorithm::Aes128Gcm, &key, b"data")
3133 .expect("test encryption must succeed");
3134 let mut encrypted = EncryptedData {
3135 id: None,
3136 encrypted_type: None,
3137 key_name: None,
3138 encryption_method: super::super::EncryptionMethod {
3139 algorithm: DataEncryptionAlgorithm::Aes128Gcm.uri().into(),
3140 key_size_bits: None,
3141 oaep_digest: None,
3142 mgf_algorithm: None,
3143 oaep_params: None,
3144 },
3145 encrypted_keys: Vec::new(),
3146 cipher_data: super::super::CipherData {
3147 value: STANDARD.encode(ciphertext),
3148 },
3149 };
3150 let policy = crate::policy::DecryptionPolicy {
3151 resources: crate::policy::ResourcePolicy {
3152 max_encryption_plaintext_bytes: 4,
3153 ..crate::policy::ResourcePolicy::default()
3154 },
3155 ..crate::policy::DecryptionPolicy::default()
3156 };
3157 encrypted.cipher_data.value = "A".repeat(48);
3158 assert!(matches!(
3159 DecryptContext::new(&SymmetricKeyDecryptor::new(key))
3160 .policy(policy)
3161 .decrypt_data(&encrypted),
3162 Err(XmlEncError::Policy(
3163 crate::policy::PolicyViolation::ResourceLimit {
3164 resource: crate::policy::resource_name::ENCRYPTION_PLAINTEXT_BYTES,
3165 ..
3166 }
3167 ))
3168 ));
3169
3170 encrypted.cipher_data.value = STANDARD.encode([0_u8; 28]);
3171 encrypted.encrypted_keys.push(EncryptedKey {
3172 id: None,
3173 recipient: None,
3174 key_name: None,
3175 encryption_method: super::super::EncryptionMethod {
3176 algorithm: KeyWrapAlgorithm::AesKw128.uri().into(),
3177 key_size_bits: None,
3178 oaep_digest: None,
3179 mgf_algorithm: None,
3180 oaep_params: None,
3181 },
3182 cipher_data: super::super::CipherData {
3183 value: "A".repeat(MAX_CIPHER_VALUE_BASE64_LEN + 4),
3184 },
3185 reference_list: None,
3186 carried_key_name: None,
3187 });
3188 let resolver = CountingResolver {
3189 candidate_calls: Cell::new(0),
3190 key: key.to_vec(),
3191 };
3192 assert!(matches!(
3193 DecryptContext::new(&resolver).decrypt_data(&encrypted),
3194 Err(XmlEncError::InvalidStructure(_))
3195 ));
3196 assert_eq!(resolver.candidate_calls.get(), 0);
3197
3198 encrypted.encrypted_keys[0].cipher_data.value = "AAAA".into();
3199 let aggregate_encoded_len =
3200 encrypted.cipher_data.value.len() + encrypted.encrypted_keys[0].cipher_data.value.len();
3201 let policy = crate::policy::DecryptionPolicy {
3202 resources: crate::policy::ResourcePolicy {
3203 max_encryption_plaintext_bytes: 4,
3204 max_xml_document_bytes: aggregate_encoded_len - 1,
3205 ..crate::policy::ResourcePolicy::default()
3206 },
3207 ..crate::policy::DecryptionPolicy::default()
3208 };
3209 let resolver = CountingResolver {
3210 candidate_calls: Cell::new(0),
3211 key: key.to_vec(),
3212 };
3213 assert!(matches!(
3214 DecryptContext::new(&resolver)
3215 .policy(policy)
3216 .decrypt_data(&encrypted),
3217 Err(XmlEncError::Policy(
3218 crate::policy::PolicyViolation::ResourceLimit {
3219 resource:
3220 crate::policy::resource_name::AGGREGATE_ENCRYPTION_CIPHER_VALUE_BYTES,
3221 maximum,
3222 actual,
3223 }
3224 )) if maximum == aggregate_encoded_len - 1 && actual == aggregate_encoded_len
3225 ));
3226 assert_eq!(resolver.candidate_calls.get(), 0);
3227 }
3228
3229 #[test]
3230 fn typed_legacy_oaep_mgf_is_rejected_before_key_resolution() {
3231 let key = [0x43_u8; 16];
3234 let ciphertext = crate::provider::default_provider()
3235 .encrypt_data(DataEncryptionAlgorithm::Aes128Gcm, &key, b"data")
3236 .expect("test encryption must succeed");
3237 let encrypted = EncryptedData {
3238 id: None,
3239 encrypted_type: None,
3240 key_name: None,
3241 encryption_method: super::super::EncryptionMethod {
3242 algorithm: DataEncryptionAlgorithm::Aes128Gcm.uri().into(),
3243 key_size_bits: None,
3244 oaep_digest: None,
3245 mgf_algorithm: None,
3246 oaep_params: None,
3247 },
3248 encrypted_keys: vec![EncryptedKey {
3249 id: None,
3250 recipient: None,
3251 key_name: None,
3252 encryption_method: super::super::EncryptionMethod {
3253 algorithm: KeyTransportAlgorithm::RsaOaepMgf1p.uri().into(),
3254 key_size_bits: None,
3255 oaep_digest: Some(OaepDigestAlgorithm::Sha256.uri().into()),
3256 mgf_algorithm: Some(OaepDigestAlgorithm::Sha384.mgf_uri().into()),
3257 oaep_params: None,
3258 },
3259 cipher_data: super::super::CipherData {
3260 value: STANDARD.encode([0_u8; 256]),
3261 },
3262 reference_list: None,
3263 carried_key_name: None,
3264 }],
3265 cipher_data: super::super::CipherData {
3266 value: STANDARD.encode(ciphertext),
3267 },
3268 };
3269 let resolver = CountingResolver {
3270 candidate_calls: Cell::new(0),
3271 key: key.to_vec(),
3272 };
3273
3274 assert!(matches!(
3275 DecryptContext::new(&resolver).decrypt_data(&encrypted),
3276 Err(XmlEncError::InvalidStructure(message))
3277 if message == "MGF is only valid for XML Encryption 1.1 RSA-OAEP"
3278 ));
3279 assert_eq!(resolver.candidate_calls.get(), 0);
3280
3281 let private_key = RsaPrivateKey::from_pkcs8_pem(include_str!(
3282 "../../tests/fixtures/keys/rsa/rsa-2048-key.pem"
3283 ))
3284 .expect("tracked RSA private key must parse");
3285 assert!(matches!(
3286 PrivateKeyDecryptor::new(private_key).resolve_key(
3287 crate::provider::default_provider(),
3288 DataEncryptionAlgorithm::Aes128Gcm,
3289 encrypted.encrypted_keys.first(),
3290 ),
3291 Err(XmlEncError::InvalidStructure(message))
3292 if message == "MGF is only valid for XML Encryption 1.1 RSA-OAEP"
3293 ));
3294 }
3295
3296 #[test]
3297 fn typed_zero_key_size_is_rejected_before_key_resolution() {
3298 let key = [0x45_u8; 16];
3301 let ciphertext = crate::provider::default_provider()
3302 .encrypt_data(DataEncryptionAlgorithm::Aes128Gcm, &key, b"data")
3303 .expect("test encryption must succeed");
3304 let encrypted = EncryptedData {
3305 id: None,
3306 encrypted_type: None,
3307 key_name: None,
3308 encryption_method: super::super::EncryptionMethod {
3309 algorithm: DataEncryptionAlgorithm::Aes128Gcm.uri().into(),
3310 key_size_bits: None,
3311 oaep_digest: None,
3312 mgf_algorithm: None,
3313 oaep_params: None,
3314 },
3315 encrypted_keys: vec![EncryptedKey {
3316 id: None,
3317 recipient: None,
3318 key_name: None,
3319 encryption_method: super::super::EncryptionMethod {
3320 algorithm: KeyTransportAlgorithm::RsaOaep11.uri().into(),
3321 key_size_bits: Some(0),
3322 oaep_digest: Some(OaepDigestAlgorithm::Sha256.uri().into()),
3323 mgf_algorithm: Some(OaepDigestAlgorithm::Sha256.mgf_uri().into()),
3324 oaep_params: None,
3325 },
3326 cipher_data: super::super::CipherData {
3327 value: STANDARD.encode([0_u8; 256]),
3328 },
3329 reference_list: None,
3330 carried_key_name: None,
3331 }],
3332 cipher_data: super::super::CipherData {
3333 value: STANDARD.encode(ciphertext),
3334 },
3335 };
3336 let resolver = CountingResolver {
3337 candidate_calls: Cell::new(0),
3338 key: key.to_vec(),
3339 };
3340
3341 assert!(matches!(
3342 DecryptContext::new(&resolver).decrypt_data(&encrypted),
3343 Err(XmlEncError::InvalidStructure(message))
3344 if message == "KeySize must be a positive integer"
3345 ));
3346 assert_eq!(resolver.candidate_calls.get(), 0);
3347 }
3348
3349 #[test]
3350 fn typed_content_method_is_validated_before_key_resolution() {
3351 let key = [0x44_u8; 16];
3354 let ciphertext = crate::provider::default_provider()
3355 .encrypt_data(DataEncryptionAlgorithm::Aes128Gcm, &key, b"data")
3356 .expect("test encryption must succeed");
3357 let encrypted = EncryptedData {
3358 id: None,
3359 encrypted_type: None,
3360 key_name: None,
3361 encryption_method: super::super::EncryptionMethod {
3362 algorithm: DataEncryptionAlgorithm::Aes128Gcm.uri().into(),
3363 key_size_bits: Some(256),
3364 oaep_digest: None,
3365 mgf_algorithm: None,
3366 oaep_params: None,
3367 },
3368 encrypted_keys: Vec::new(),
3369 cipher_data: super::super::CipherData {
3370 value: STANDARD.encode(ciphertext),
3371 },
3372 };
3373 let resolver = AllCallsResolver {
3374 calls: Cell::new(0),
3375 key: key.to_vec(),
3376 };
3377
3378 assert!(matches!(
3379 DecryptContext::new(&resolver).decrypt_data(&encrypted),
3380 Err(XmlEncError::InvalidStructure(message))
3381 if message.contains("requires KeySize 128, got 256")
3382 ));
3383 assert_eq!(resolver.calls.get(), 0);
3384 }
3385
3386 #[test]
3387 fn unknown_encrypted_key_algorithm_never_reaches_resolver() {
3388 let key = [0x42_u8; 16];
3391 let ciphertext = crate::provider::default_provider()
3392 .encrypt_data(DataEncryptionAlgorithm::Aes128Gcm, &key, b"data")
3393 .expect("test encryption must succeed");
3394 let encrypted = EncryptedData {
3395 id: None,
3396 encrypted_type: None,
3397 key_name: None,
3398 encryption_method: super::super::EncryptionMethod {
3399 algorithm: DataEncryptionAlgorithm::Aes128Gcm.uri().into(),
3400 key_size_bits: None,
3401 oaep_digest: None,
3402 mgf_algorithm: None,
3403 oaep_params: None,
3404 },
3405 encrypted_keys: vec![EncryptedKey {
3406 id: None,
3407 recipient: None,
3408 key_name: None,
3409 encryption_method: super::super::EncryptionMethod {
3410 algorithm: "urn:example:unknown-key-algorithm".into(),
3411 key_size_bits: None,
3412 oaep_digest: None,
3413 mgf_algorithm: None,
3414 oaep_params: None,
3415 },
3416 cipher_data: super::super::CipherData {
3417 value: STANDARD.encode([0_u8; 24]),
3418 },
3419 reference_list: None,
3420 carried_key_name: None,
3421 }],
3422 cipher_data: super::super::CipherData {
3423 value: STANDARD.encode(ciphertext),
3424 },
3425 };
3426 let resolver = CountingResolver {
3427 candidate_calls: Cell::new(0),
3428 key: key.to_vec(),
3429 };
3430
3431 assert!(matches!(
3432 DecryptContext::new(&resolver).decrypt_data(&encrypted),
3433 Err(XmlEncError::UnsupportedAlgorithm(_))
3434 ));
3435 assert_eq!(resolver.candidate_calls.get(), 0);
3436 }
3437
3438 #[test]
3439 fn cbc_padding_errors_do_not_expose_decrypted_octets() {
3440 let error = map_data_decryption_error(
3443 DataEncryptionAlgorithm::Aes128Cbc,
3444 32,
3445 crate::provider::ProviderError::InvalidInput(
3446 crate::provider::ProviderInputError::AesCbcCiphertext,
3447 ),
3448 );
3449
3450 assert_eq!(error.to_string(), "invalid XMLEnc padding");
3451 }
3452
3453 #[test]
3454 fn replaces_element_and_content_in_caller_owned_documents() {
3455 let key = [0x31_u8; 16];
3458 let element = encrypted_gcm_element(
3459 "http://www.w3.org/2001/04/xmlenc#Element",
3460 "<secret id=\"visible\">value</secret>",
3461 None,
3462 true,
3463 &key,
3464 );
3465 assert_eq!(
3466 decrypt_document(&element, None, &SymmetricKeyDecryptor::new(key))
3467 .expect("root Element replacement must succeed"),
3468 "<secret id=\"visible\">value</secret>"
3469 );
3470
3471 let content = encrypted_gcm_element(
3472 "http://www.w3.org/2001/04/xmlenc#Content",
3473 "before<child/>after",
3474 None,
3475 false,
3476 &key,
3477 );
3478 let document =
3479 format!("<root xmlns:xenc=\"{XMLENC_NS}\"><prefix/>{content}<suffix/></root>");
3480 let replaced = decrypt_document(&document, None, &SymmetricKeyDecryptor::new(key))
3481 .expect("nested Content replacement must succeed");
3482 assert_eq!(
3483 replaced,
3484 format!(
3485 "<root xmlns:xenc=\"{XMLENC_NS}\"><prefix/>before<child/>after<suffix/></root>"
3486 )
3487 );
3488 }
3489
3490 #[test]
3491 fn accepts_whitespace_and_comments_around_element_plaintext() {
3492 let key = [0x34_u8; 16];
3495 let plaintext = "\n<!--before--><secret/><!--after-->\n";
3496 let encrypted = encrypted_gcm_element(
3497 "http://www.w3.org/2001/04/xmlenc#Element",
3498 plaintext,
3499 None,
3500 true,
3501 &key,
3502 );
3503
3504 assert_eq!(
3505 decrypt_document(&encrypted, None, &SymmetricKeyDecryptor::new(key))
3506 .expect("one element with boundary trivia must be accepted"),
3507 plaintext
3508 );
3509 }
3510
3511 #[test]
3512 fn decrypts_unknown_and_empty_type_hints_as_opaque_bytes() {
3513 let key = [0x35_u8; 16];
3516 let plaintext = "\0opaque\u{ff}bytes";
3517 let unknown = encrypted_gcm_element("urn:example:binary", plaintext, None, true, &key);
3518 let empty = encrypted_gcm_element("", plaintext, None, true, &key).replacen(
3519 "<xenc:EncryptedData",
3520 "<xenc:EncryptedData Type=\"\"",
3521 1,
3522 );
3523
3524 let parsed = parse_encrypted_data(&unknown).expect("unknown Type must remain parseable");
3525 assert_eq!(
3526 parsed.encrypted_type,
3527 Some(EncryptedDataType::Other("urn:example:binary".into()))
3528 );
3529 assert!(matches!(
3530 decrypt_document(&unknown, None, &SymmetricKeyDecryptor::new(key)),
3531 Err(XmlEncError::ReplacementRequiresXml)
3532 ));
3533
3534 for encrypted in [unknown, empty] {
3535 assert_eq!(
3536 decrypt(&encrypted, &SymmetricKeyDecryptor::new(key))
3537 .expect("opaque Type hints must not block decryption"),
3538 DecryptedContent::Bytes(plaintext.as_bytes().to_vec())
3539 );
3540 }
3541 }
3542
3543 #[test]
3544 fn selects_document_encrypted_data_by_id_and_rejects_ambiguity() {
3545 let key = [0x32_u8; 16];
3548 let first = encrypted_gcm_element(
3549 "http://www.w3.org/2001/04/xmlenc#Content",
3550 "first",
3551 Some("first"),
3552 false,
3553 &key,
3554 );
3555 let second = encrypted_gcm_element(
3556 "http://www.w3.org/2001/04/xmlenc#Content",
3557 "second",
3558 Some("second"),
3559 false,
3560 &key,
3561 );
3562 let document = format!("<root xmlns:xenc=\"{XMLENC_NS}\">{first}{second}</root>");
3563 let resolver = SymmetricKeyDecryptor::new(key);
3564 assert!(matches!(
3565 decrypt_document(&document, None, &resolver),
3566 Err(XmlEncError::AmbiguousEncryptedData)
3567 ));
3568 let replaced = decrypt_document(&document, Some("second"), &resolver)
3569 .expect("Id selection must choose exactly one encrypted region");
3570 assert!(replaced.contains("second"));
3571 assert!(replaced.contains("Id=\"first\""));
3572 assert!(matches!(
3573 decrypt_document(&document, Some("missing"), &resolver),
3574 Err(XmlEncError::EncryptedDataNotFound)
3575 ));
3576 }
3577
3578 #[test]
3579 fn selects_encrypted_data_below_a_unique_operation_start_node() {
3580 let key = [0x42_u8; 16];
3583 let first = encrypted_gcm_element(
3584 "http://www.w3.org/2001/04/xmlenc#Content",
3585 "first",
3586 None,
3587 false,
3588 &key,
3589 );
3590 let second = encrypted_gcm_element(
3591 "http://www.w3.org/2001/04/xmlenc#Content",
3592 "second",
3593 None,
3594 false,
3595 &key,
3596 );
3597 let document = format!(
3598 "<root xmlns:xenc=\"{XMLENC_NS}\"><scope Id=\"first\">{first}</scope><scope Id=\"second\">{second}</scope></root>"
3599 );
3600 let resolver = SymmetricKeyDecryptor::new(key);
3601 let context = DecryptContext::new(&resolver);
3602 let replaced = context
3603 .decrypt_document_from_start_node(&document, Some("second"))
3604 .expect("ancestor ID must select its encrypted descendant");
3605 assert!(replaced.contains("<scope Id=\"second\">second</scope>"));
3606 assert!(replaced.contains("<scope Id=\"first\"><xenc:EncryptedData"));
3607
3608 assert!(matches!(
3609 context.decrypt_document_from_start_node(&document, Some("missing")),
3610 Err(XmlEncError::SelectedNodeUnavailable { id }) if id == "missing"
3611 ));
3612 let duplicate = document.replace("Id=\"second\"", "Id=\"first\"");
3613 assert!(matches!(
3614 context.decrypt_document_from_start_node(&duplicate, Some("first")),
3615 Err(XmlEncError::SelectedNodeUnavailable { id }) if id == "first"
3616 ));
3617 let ambiguous = format!(
3618 "<root xmlns:xenc=\"{XMLENC_NS}\"><scope Id=\"selected\">{first}{second}</scope></root>"
3619 );
3620 assert!(matches!(
3621 context.decrypt_document_from_start_node(&ambiguous, Some("selected")),
3622 Err(XmlEncError::AmbiguousEncryptedData)
3623 ));
3624
3625 let first_replaced = context
3626 .decrypt_first_document_from_start_node(&ambiguous, Some("selected"))
3627 .expect("first-match selection must leave later encrypted descendants untouched");
3628 assert!(first_replaced.contains("<scope Id=\"selected\">first<xenc:EncryptedData"));
3629 let replaced_document =
3630 Document::parse(&first_replaced).expect("first-match output must remain valid XML");
3631 assert_eq!(
3632 replaced_document
3633 .descendants()
3634 .filter(|node| node.has_tag_name((XMLENC_NS, "EncryptedData")))
3635 .count(),
3636 1
3637 );
3638 }
3639
3640 #[test]
3641 fn rejects_non_xml_or_malformed_document_replacement_plaintext() {
3642 let key = [0x33_u8; 16];
3645 let binary = encrypted_gcm_element("", "binary", None, true, &key);
3646 assert!(matches!(
3647 decrypt_document(&binary, None, &SymmetricKeyDecryptor::new(key)),
3648 Err(XmlEncError::ReplacementRequiresXml)
3649 ));
3650
3651 let malformed = encrypted_gcm_element(
3652 "http://www.w3.org/2001/04/xmlenc#Element",
3653 "<unclosed>",
3654 None,
3655 true,
3656 &key,
3657 );
3658 assert!(matches!(
3659 decrypt_document(&malformed, None, &SymmetricKeyDecryptor::new(key)),
3660 Err(XmlEncError::XmlParse(_))
3661 ));
3662
3663 for invalid_element in ["text-only", "<first/><second/>"] {
3664 let encrypted = encrypted_gcm_element(
3665 "http://www.w3.org/2001/04/xmlenc#Element",
3666 invalid_element,
3667 None,
3668 false,
3669 &key,
3670 );
3671 let document = format!("<root xmlns:xenc=\"{XMLENC_NS}\">{encrypted}</root>");
3672 assert!(
3673 decrypt_document(&document, None, &SymmetricKeyDecryptor::new(key)).is_err(),
3674 "Element plaintext must contain exactly one element: {invalid_element}"
3675 );
3676 }
3677
3678 let content = encrypted_gcm_element(
3679 "http://www.w3.org/2001/04/xmlenc#Content",
3680 "plaintext",
3681 None,
3682 false,
3683 &key,
3684 );
3685 let with_dtd = format!(
3686 "<!DOCTYPE root [<!ATTLIST root Id ID #IMPLIED>]><root xmlns:xenc=\"{XMLENC_NS}\">{content}</root>"
3687 );
3688 assert!(matches!(
3689 decrypt_document(&with_dtd, None, &SymmetricKeyDecryptor::new(key)),
3690 Err(XmlEncError::XmlParse(
3691 crate::xml::dom::ParseError::DtdDetected
3692 ))
3693 ));
3694 let mut policy = crate::policy::DecryptionPolicy::default();
3695 policy.xml.allow_internal_dtd = true;
3696 assert!(
3697 DecryptContext::new(&SymmetricKeyDecryptor::new(key))
3698 .policy(policy)
3699 .decrypt_document(&with_dtd, None)
3700 .expect("explicit internal-DTD opt-in must decrypt")
3701 .contains("plaintext")
3702 );
3703 }
3704
3705 #[test]
3706 fn rejects_plaintext_markup_that_crosses_the_encrypted_region() {
3707 let key = [0x36_u8; 16];
3711 let crossing_markup = "</parent><attacker/><parent>";
3712 for type_uri in [
3713 "http://www.w3.org/2001/04/xmlenc#Content",
3714 "http://www.w3.org/2001/04/xmlenc#Element",
3715 ] {
3716 let encrypted = encrypted_gcm_element(type_uri, crossing_markup, None, false, &key);
3717 let document =
3718 format!("<outer xmlns:xenc=\"{XMLENC_NS}\"><parent>{encrypted}</parent></outer>");
3719 assert!(
3720 decrypt_document(&document, None, &SymmetricKeyDecryptor::new(key)).is_err(),
3721 "{type_uri} plaintext must not escape its replacement boundary"
3722 );
3723 }
3724 }
3725
3726 #[test]
3727 fn document_decryption_applies_byte_and_node_policy_before_parsing() {
3728 let key = [0x38_u8; 16];
3731 let encrypted = encrypted_gcm_element(
3732 "http://www.w3.org/2001/04/xmlenc#Content",
3733 "plaintext",
3734 None,
3735 false,
3736 &key,
3737 );
3738 let document = format!("<root xmlns:xenc=\"{XMLENC_NS}\"><a/>{encrypted}</root>");
3739 let byte_policy = crate::policy::DecryptionPolicy {
3740 resources: crate::policy::ResourcePolicy {
3741 max_xml_document_bytes: document.len() - 1,
3742 ..crate::policy::ResourcePolicy::default()
3743 },
3744 ..crate::policy::DecryptionPolicy::default()
3745 };
3746 assert!(matches!(
3747 DecryptContext::new(&SymmetricKeyDecryptor::new(key))
3748 .policy(byte_policy)
3749 .decrypt_document(&document, None),
3750 Err(XmlEncError::Policy(crate::policy::PolicyViolation::ResourceLimit {
3751 resource: crate::policy::resource_name::XML_DOCUMENT,
3752 maximum,
3753 actual,
3754 })) if maximum == document.len() - 1 && actual == document.len()
3755 ));
3756
3757 let node_policy = crate::policy::DecryptionPolicy {
3758 resources: crate::policy::ResourcePolicy {
3759 max_xml_nodes: 3,
3760 ..crate::policy::ResourcePolicy::default()
3761 },
3762 ..crate::policy::DecryptionPolicy::default()
3763 };
3764 assert!(matches!(
3765 DecryptContext::new(&SymmetricKeyDecryptor::new(key))
3766 .policy(node_policy)
3767 .decrypt_document(&document, None),
3768 Err(XmlEncError::Policy(
3769 crate::policy::PolicyViolation::ResourceLimit {
3770 resource: crate::policy::resource_name::XML_NODES,
3771 maximum: 3,
3772 actual: 4,
3773 }
3774 ))
3775 ));
3776 }
3777
3778 #[test]
3779 fn decryption_entry_points_enforce_policy_depth() {
3780 let xml = "<root><child><leaf/></child></root>";
3783 let policy = crate::policy::DecryptionPolicy {
3784 resources: crate::policy::ResourcePolicy {
3785 max_xml_depth: 2,
3786 ..crate::policy::ResourcePolicy::default()
3787 },
3788 ..crate::policy::DecryptionPolicy::default()
3789 };
3790 let resolver = SymmetricKeyDecryptor::new([0_u8; 16]);
3791 let mut document = XmlDocument::parse(xml).expect("wide retained fixture must parse");
3792
3793 assert!(matches!(
3794 DecryptContext::new(&resolver)
3795 .policy(policy.clone())
3796 .decrypt_document(xml, None),
3797 Err(XmlEncError::Policy(
3798 crate::policy::PolicyViolation::ResourceLimit {
3799 resource: crate::policy::resource_name::XML_DEPTH,
3800 maximum: 2,
3801 actual: 3,
3802 }
3803 ))
3804 ));
3805 assert!(matches!(
3806 DecryptContext::new(&resolver)
3807 .policy(policy)
3808 .decrypt_owned_document(&mut document, None),
3809 Err(XmlEncError::Policy(
3810 crate::policy::PolicyViolation::ResourceLimit {
3811 resource: crate::policy::resource_name::XML_DEPTH,
3812 maximum: 2,
3813 actual: 3,
3814 }
3815 ))
3816 ));
3817 }
3818
3819 #[test]
3820 fn fragment_validation_does_not_charge_its_internal_wrapper_node() {
3821 let key = [0x39_u8; 16];
3824 let plaintext = "<item/>".repeat(20);
3825 let encrypted = encrypted_gcm_element(
3826 "http://www.w3.org/2001/04/xmlenc#Content",
3827 &plaintext,
3828 None,
3829 false,
3830 &key,
3831 );
3832 let document = format!("<root xmlns:xenc=\"{XMLENC_NS}\">{encrypted}</root>");
3833 let resolver = SymmetricKeyDecryptor::new(key);
3834 let expected = decrypt_document(&document, None, &resolver)
3835 .expect("unbounded setup decryption must succeed");
3836 let exact_output_nodes = Document::parse(&expected)
3837 .expect("decrypted output must parse")
3838 .descendants()
3839 .count();
3840 let policy = crate::policy::DecryptionPolicy {
3841 resources: crate::policy::ResourcePolicy {
3842 max_xml_nodes: exact_output_nodes,
3843 ..crate::policy::ResourcePolicy::default()
3844 },
3845 ..crate::policy::DecryptionPolicy::default()
3846 };
3847
3848 assert_eq!(
3849 DecryptContext::new(&resolver)
3850 .policy(policy)
3851 .decrypt_document(&document, None)
3852 .expect("temporary wrapper must not consume caller node budget"),
3853 expected
3854 );
3855 }
3856
3857 #[test]
3858 fn owned_decryption_rejects_projected_node_limit_atomically() {
3859 let key = [0x3a_u8; 16];
3862 let plaintext = "<item/>".repeat(64);
3863 let encrypted = encrypted_gcm_element(
3864 "http://www.w3.org/2001/04/xmlenc#Content",
3865 &plaintext,
3866 None,
3867 false,
3868 &key,
3869 );
3870 let mut document = XmlDocument::parse(format!(
3871 "<root xmlns:xenc=\"{XMLENC_NS}\">{encrypted}</root>"
3872 ))
3873 .expect("owned encrypted fixture must parse");
3874 let input_nodes = document.with_view(|view| view.node_count());
3875 let before = document.as_xml().to_owned();
3876 let policy = crate::policy::DecryptionPolicy {
3877 resources: crate::policy::ResourcePolicy {
3878 max_xml_nodes: input_nodes,
3879 ..crate::policy::ResourcePolicy::default()
3880 },
3881 ..crate::policy::DecryptionPolicy::default()
3882 };
3883
3884 let error = DecryptContext::new(&SymmetricKeyDecryptor::new(key))
3885 .policy(policy)
3886 .decrypt_owned_document(&mut document, None)
3887 .expect_err("expanded plaintext must exceed the operation node ceiling");
3888
3889 assert!(matches!(
3890 error,
3891 XmlEncError::Policy(crate::policy::PolicyViolation::ResourceLimit {
3892 resource: crate::policy::resource_name::XML_NODES,
3893 maximum,
3894 ..
3895 }) if maximum == input_nodes
3896 ));
3897 assert_eq!(document.as_xml(), before);
3898 assert_eq!(document.generation(), 0);
3899 }
3900
3901 #[test]
3902 fn owned_decryption_reports_decrypted_depth_as_policy() {
3903 let key = [0x3b_u8; 16];
3907 let plaintext = format!("{}value{}", "<nested>".repeat(32), "</nested>".repeat(32));
3908 let encrypted = encrypted_gcm_element(
3909 "http://www.w3.org/2001/04/xmlenc#Element",
3910 &plaintext,
3911 None,
3912 false,
3913 &key,
3914 );
3915 let mut document = XmlDocument::parse(format!(
3916 "<root xmlns:xenc=\"{XMLENC_NS}\">{encrypted}</root>"
3917 ))
3918 .expect("encrypted fixture must parse");
3919 let input_depth = document.with_view(|view| view.max_depth());
3920 let before = document.as_xml().to_owned();
3921 let policy = crate::policy::DecryptionPolicy {
3922 resources: crate::policy::ResourcePolicy {
3923 max_xml_depth: input_depth,
3924 ..crate::policy::ResourcePolicy::default()
3925 },
3926 ..crate::policy::DecryptionPolicy::default()
3927 };
3928
3929 let error = DecryptContext::new(&SymmetricKeyDecryptor::new(key))
3930 .policy(policy)
3931 .decrypt_owned_document(&mut document, None)
3932 .expect_err("deep plaintext must exceed the active depth policy");
3933
3934 assert!(matches!(
3935 error,
3936 XmlEncError::Policy(crate::policy::PolicyViolation::ResourceLimit {
3937 resource: crate::policy::resource_name::XML_DEPTH,
3938 maximum,
3939 actual,
3940 }) if maximum == input_depth && actual > maximum
3941 ));
3942 assert_eq!(document.as_xml(), before);
3943 assert_eq!(document.generation(), 0);
3944 }
3945
3946 #[test]
3947 fn validates_replacement_plaintext_in_its_namespace_context() {
3948 let key = [0x37_u8; 16];
3951 let encrypted = encrypted_gcm_element(
3952 "http://www.w3.org/2001/04/xmlenc#Content",
3953 "<shared:child/>",
3954 None,
3955 false,
3956 &key,
3957 );
3958 let document = format!(
3959 "<root xmlns:xenc=\"{XMLENC_NS}\" xmlns:shared=\"urn:shared\">{encrypted}</root>"
3960 );
3961 let decrypted = decrypt_document(&document, None, &SymmetricKeyDecryptor::new(key))
3962 .expect("inherited namespace prefixes must remain valid");
3963 assert_eq!(
3964 decrypted,
3965 format!(
3966 "<root xmlns:xenc=\"{XMLENC_NS}\" xmlns:shared=\"urn:shared\"><shared:child/></root>"
3967 )
3968 );
3969 }
3970
3971 fn encrypted_gcm_element(
3972 type_uri: &str,
3973 plaintext: &str,
3974 id: Option<&str>,
3975 declare_namespace: bool,
3976 key: &[u8; 16],
3977 ) -> String {
3978 let nonce = [0x44_u8; 12];
3979 let mut ciphertext = plaintext.as_bytes().to_vec();
3980 Aes128Gcm::new_from_slice(key)
3981 .expect("fixed content key length")
3982 .encrypt_in_place(&nonce.into(), b"", &mut ciphertext)
3983 .expect("test encryption must succeed");
3984 let mut wire = nonce.to_vec();
3985 wire.extend_from_slice(&ciphertext);
3986 let namespace = declare_namespace
3987 .then_some(format!(" xmlns:xenc=\"{XMLENC_NS}\""))
3988 .unwrap_or_default();
3989 let data_type = (!type_uri.is_empty())
3990 .then_some(format!(" Type=\"{type_uri}\""))
3991 .unwrap_or_default();
3992 let id = id
3993 .map(|value| format!(" Id=\"{value}\""))
3994 .unwrap_or_default();
3995 format!(
3996 "<xenc:EncryptedData{namespace}{data_type}{id}><xenc:EncryptionMethod Algorithm=\"http://www.w3.org/2009/xmlenc11#aes128-gcm\"/><xenc:CipherData><xenc:CipherValue>{}</xenc:CipherValue></xenc:CipherData></xenc:EncryptedData>",
3997 STANDARD.encode(wire)
3998 )
3999 }
4000}