1#![doc = include_str!("../../docs/xmlenc.md")]
14
15use crate::xml::dom::Node;
16
17mod decrypt;
18mod encrypt;
19mod parse;
20mod types;
21
22pub use decrypt::{
23 DecryptContext, DecryptionKeyResolver, DocumentDecryptionOptions, KekDecryptor,
24 KeyCandidateBudget, PrivateKeyDecryptor, SymmetricKeyDecryptor, decrypt, decrypt_data,
25 decrypt_document, decrypt_document_with_options,
26};
27pub use encrypt::{
28 EncryptedDataBuilder, validate_key_transport_recipient, validate_rsa_recipient_key,
29};
30pub use parse::{
31 parse_encrypted_data, parse_encrypted_data_node_with_policy,
32 parse_encrypted_data_node_with_policy_and_backend,
33 parse_encrypted_data_template_node_with_policy,
34 parse_encrypted_data_template_node_with_policy_and_backend,
35};
36pub use types::{
37 CipherData, DataEncryptionAlgorithm, DecryptedContent, DocumentEncryptionOptions,
38 EncryptedData, EncryptedDataType, EncryptedKey, EncryptionMethod, EncryptionRecipient,
39 EncryptionResult, KeyTransportAlgorithm, KeyWrapAlgorithm, OaepDigestAlgorithm, ReferenceList,
40 ReplacementMode, RsaOaepParameters, XmlEncError,
41};
42
43fn map_document_error(
44 error: crate::document::XmlDocumentError,
45 settings: crate::document::DocumentParseSettings,
46) -> XmlEncError {
47 match error.into_policy_violation(settings) {
48 Ok(error) => XmlEncError::Policy(error),
49 Err(crate::document::XmlDocumentError::Parse(error)) => XmlEncError::XmlParse(error),
50 Err(crate::document::XmlDocumentError::ProjectedNodeLimit { maximum }) => {
51 crate::policy::PolicyViolation::ResourceLimit {
52 resource: crate::policy::resource_name::XML_NODES,
53 maximum,
54 actual: maximum.saturating_add(1),
55 }
56 .into()
57 }
58 Err(error) => XmlEncError::Document(error),
59 }
60}
61
62fn has_single_element_with_boundary_trivia(parent: Node<'_, '_>) -> bool {
63 let mut element_count = 0;
64 for node in parent.children() {
65 if node.is_element() {
66 element_count += 1;
67 if element_count > 1 {
68 return false;
69 }
70 } else if node.is_comment() {
71 continue;
72 } else if node.is_text() {
73 if !node.text().is_some_and(|text| {
76 text.chars()
77 .all(|character| matches!(character, ' ' | '\t' | '\n' | '\r'))
78 }) {
79 return false;
80 }
81 } else {
82 return false;
83 }
84 }
85 element_count == 1
86}
87
88#[cfg(test)]
89mod tests {
90 use super::*;
91 use crate::document::{DocumentParseSettings, XmlDocumentError};
92
93 #[test]
94 fn document_errors_have_one_xmlenc_policy_mapping() {
95 let settings = DocumentParseSettings::new_with_depth(false, 8, 3, 128);
98 assert!(matches!(
99 map_document_error(
100 XmlDocumentError::DocumentTooDeep {
101 maximum: 3,
102 actual: 4,
103 },
104 settings,
105 ),
106 XmlEncError::Policy(crate::policy::PolicyViolation::ResourceLimit {
107 resource: crate::policy::resource_name::XML_DEPTH,
108 maximum: 3,
109 actual: 4,
110 })
111 ));
112 assert!(matches!(
113 map_document_error(
114 XmlDocumentError::ProjectedNodeLimit { maximum: 8 },
115 settings,
116 ),
117 XmlEncError::Policy(crate::policy::PolicyViolation::ResourceLimit {
118 resource: crate::policy::resource_name::XML_NODES,
119 maximum: 8,
120 actual: 9,
121 })
122 ));
123 }
124}