Skip to main content

xml_sec/xmlenc/
derived_key.rs

1//! Source-aware DerivedKey processing without implicit master-key discovery.
2
3use crate::xml::dom::Node;
4
5use super::parse::{bounded_simple_text_with_limit, validate_metadata_len};
6use super::{
7    KeyDerivationMethod, XmlEncError,
8    types::{XMLENC_NS, XMLENC11_NS},
9};
10
11/// Public descriptor transported by XML Encryption 1.1 DerivedKey.
12/// It contains no private material and never selects a permissive policy.
13#[derive(Debug, Clone, PartialEq, Eq)]
14pub struct DerivedKey {
15    /// Optional method; omission requires an explicit method in request context.
16    pub method: Option<KeyDerivationMethod>,
17    /// Optional name of the derived key, distinct from the master key name.
18    pub derived_key_name: Option<String>,
19    /// Optional master-key association. Names are whitespace significant.
20    pub master_key_name: Option<String>,
21    /// Optional recipient association, supplied to the application resolver.
22    pub recipient: Option<String>,
23    /// Optional identifier of this descriptor in its source document.
24    pub id: Option<String>,
25    /// Optional type hint; it never overrides the consuming algorithm's width.
26    pub key_type: Option<String>,
27    /// Optional association with consuming encrypted objects.
28    pub reference_list: Option<super::ReferenceList>,
29}
30
31pub(super) fn parse(
32    node: Node<'_, '_>,
33    resources: &crate::policy::ResourcePolicy,
34) -> Result<DerivedKey, XmlEncError> {
35    let maximum = resources.max_encryption_metadata_bytes;
36    super::parse::require_element(node, XMLENC11_NS, "DerivedKey")?;
37    let attribute = |name| -> Result<_, XmlEncError> {
38        let value = node.attribute(name);
39        if let Some(value) = value {
40            validate_metadata_len(value.len(), maximum)?;
41        }
42        Ok(value.map(str::to_owned))
43    };
44    for child in node.children() {
45        if child.is_text()
46            && child.text().is_some_and(|text| {
47                !text
48                    .bytes()
49                    .all(|b| matches!(b, b' ' | b'\t' | b'\r' | b'\n'))
50            })
51        {
52            return Err(XmlEncError::InvalidStructure(
53                "DerivedKey contains character data".into(),
54            ));
55        }
56    }
57    let mut children = node.children().filter(Node::is_element).peekable();
58    let method = if children
59        .peek()
60        .is_some_and(|child| child.has_tag_name((XMLENC11_NS, "KeyDerivationMethod")))
61    {
62        Some(super::key_derivation::parse_node(
63            children.next().expect("peeked child"),
64            maximum,
65        )?)
66    } else {
67        None
68    };
69    let reference_list = if children
70        .peek()
71        .is_some_and(|child| child.has_tag_name((XMLENC_NS, "ReferenceList")))
72    {
73        Some(super::parse::parse_reference_list_with_resources(
74            children.next().expect("peeked child"),
75            resources,
76        )?)
77    } else {
78        None
79    };
80    let mut name = |tag| -> Result<_, XmlEncError> {
81        if children
82            .peek()
83            .is_some_and(|child| child.has_tag_name((XMLENC11_NS, tag)))
84        {
85            Ok(Some(bounded_simple_text_with_limit(
86                children.next().expect("peeked child"),
87                tag,
88                maximum,
89            )?))
90        } else {
91            Ok(None)
92        }
93    };
94    // XMLEnc 1.1 ยง3.5.2: optional fields have this sequence, and missing
95    // method/master information must be known by the recipient, not invented.
96    // https://www.w3.org/TR/2013/REC-xmlenc-core1-20130411/#sec-DerivedKey
97    let derived_key_name = name("DerivedKeyName")?;
98    let master_key_name = name("MasterKeyName")?;
99    if children.next().is_some() {
100        return Err(XmlEncError::InvalidStructure(
101            "unexpected or unordered DerivedKey child".into(),
102        ));
103    }
104    Ok(DerivedKey {
105        method,
106        derived_key_name,
107        master_key_name,
108        reference_list,
109        recipient: attribute("Recipient")?,
110        id: attribute("Id")?,
111        key_type: attribute("Type")?,
112    })
113}