Skip to main content

lib3mf_core/parser/
crypto_parser.rs

1use crate::error::{Lib3mfError, Result};
2use crate::model::crypto::*;
3use crate::parser::xml_parser::{XmlParser, get_attribute};
4use quick_xml::events::Event;
5use std::io::BufRead;
6
7/// Parses an XML-DSIG `<Signature>` element into a `Signature` structure.
8pub fn parse_signature<R: BufRead>(parser: &mut XmlParser<R>) -> Result<Signature> {
9    let mut signature = Signature::default();
10
11    loop {
12        // Read event separately to limit scope of borrow
13        let evt_info = match parser.read_next_event()? {
14            Event::Start(e) => Some((e.local_name().as_ref().to_vec(), e.name().as_ref().to_vec())),
15            Event::End(e) if e.local_name().as_ref() == b"Signature" => return Ok(signature),
16            Event::Eof => {
17                return Err(Lib3mfError::Validation(
18                    "Unexpected EOF in Signature".to_string(),
19                ));
20            }
21            _ => None,
22        };
23
24        if let Some((local_name, raw_name)) = evt_info {
25            match local_name.as_slice() {
26                b"SignedInfo" => {
27                    signature.signed_info = parse_signed_info(parser)?;
28                }
29                b"SignatureValue" => {
30                    let val = parser.read_text_content()?;
31                    signature.signature_value = SignatureValue { value: val };
32                }
33                b"KeyInfo" => {
34                    signature.key_info = Some(parse_key_info(parser)?);
35                }
36                _ => {
37                    parser.read_to_end(&raw_name)?;
38                }
39            }
40        }
41    }
42}
43
44fn parse_signed_info<R: BufRead>(parser: &mut XmlParser<R>) -> Result<SignedInfo> {
45    let mut info = SignedInfo::default();
46
47    loop {
48        let evt_info = match parser.read_next_event()? {
49            Event::Start(e) => {
50                let alg = get_attribute(&e, b"Algorithm").map(|s| s.into_owned());
51                let uri = get_attribute(&e, b"URI").map(|s| s.into_owned());
52                Some((
53                    e.local_name().as_ref().to_vec(),
54                    e.name().as_ref().to_vec(),
55                    alg,
56                    uri,
57                    false,
58                ))
59            }
60            Event::Empty(e) => {
61                let alg = get_attribute(&e, b"Algorithm").map(|s| s.into_owned());
62                let uri = get_attribute(&e, b"URI").map(|s| s.into_owned());
63                Some((
64                    e.local_name().as_ref().to_vec(),
65                    e.name().as_ref().to_vec(),
66                    alg,
67                    uri,
68                    true,
69                ))
70            }
71            Event::End(e) if e.local_name().as_ref() == b"SignedInfo" => return Ok(info),
72            Event::Eof => {
73                return Err(Lib3mfError::Validation(
74                    "Unexpected EOF in SignedInfo".to_string(),
75                ));
76            }
77            _ => None,
78        };
79
80        if let Some((local_name, raw_name, alg, uri, is_empty)) = evt_info {
81            match local_name.as_slice() {
82                b"CanonicalizationMethod" => {
83                    info.canonicalization_method = CanonicalizationMethod {
84                        algorithm: alg.unwrap_or_default(),
85                    };
86                    if !is_empty {
87                        parser.read_to_end(&raw_name)?;
88                    }
89                }
90                b"SignatureMethod" => {
91                    info.signature_method = SignatureMethod {
92                        algorithm: alg.unwrap_or_default(),
93                    };
94                    if !is_empty {
95                        parser.read_to_end(&raw_name)?;
96                    }
97                }
98                b"Reference" => {
99                    // Logic for Reference: if empty, it's invalid usually, but we handle it.
100                    // If Start, we need to recurse.
101                    if !is_empty {
102                        // We need to pass the URI we extracted.
103                        // parse_reference logic assumes it gets parser.
104                        // But parse_reference usually expects to handle Start event attributes...
105                        // Since we consumed the Start event, we must handle attributes here or pass them.
106                        // I will modify parse_reference to take URI and assume start event consumed.
107                        let r = parse_reference_content(parser, uri.unwrap_or_default())?;
108                        info.references.push(r);
109                    } else {
110                        // Empty Reference? Not really valid but...
111                        let r = Reference {
112                            uri: uri.unwrap_or_default(),
113                            ..Default::default()
114                        };
115                        info.references.push(r);
116                    }
117                }
118                _ => {
119                    if !is_empty {
120                        parser.read_to_end(&raw_name)?;
121                    }
122                }
123            }
124        }
125    }
126}
127
128// Renamed from parse_reference to parse_reference_content as it assumes Start event consumed
129fn parse_reference_content<R: BufRead>(
130    parser: &mut XmlParser<R>,
131    uri: String,
132) -> Result<Reference> {
133    let mut r = Reference {
134        uri,
135        ..Default::default()
136    };
137
138    loop {
139        let evt_info = match parser.read_next_event()? {
140            Event::Start(e) => {
141                let alg = get_attribute(&e, b"Algorithm").map(|s| s.into_owned());
142                Some((
143                    e.local_name().as_ref().to_vec(),
144                    e.name().as_ref().to_vec(),
145                    alg,
146                    false,
147                ))
148            }
149            Event::Empty(e) => {
150                let alg = get_attribute(&e, b"Algorithm").map(|s| s.into_owned());
151                Some((
152                    e.local_name().as_ref().to_vec(),
153                    e.name().as_ref().to_vec(),
154                    alg,
155                    true,
156                ))
157            }
158            Event::End(e) if e.local_name().as_ref() == b"Reference" => return Ok(r),
159            Event::Eof => {
160                return Err(Lib3mfError::Validation(
161                    "Unexpected EOF in Reference".to_string(),
162                ));
163            }
164            _ => None,
165        };
166
167        if let Some((local_name, raw_name, alg, is_empty)) = evt_info {
168            match local_name.as_slice() {
169                b"DigestMethod" => {
170                    r.digest_method = DigestMethod {
171                        algorithm: alg.unwrap_or_default(),
172                    };
173                    if !is_empty {
174                        parser.read_to_end(&raw_name)?;
175                    }
176                }
177                b"DigestValue" => {
178                    // Start element, read text content
179                    if !is_empty {
180                        let val = parser.read_text_content()?;
181                        r.digest_value = DigestValue { value: val };
182                    }
183                }
184                b"Transforms" => {
185                    if !is_empty {
186                        let transforms = parse_transforms_content(parser)?;
187                        r.transforms = Some(transforms);
188                    }
189                }
190                _ => {
191                    if !is_empty {
192                        parser.read_to_end(&raw_name)?;
193                    }
194                }
195            }
196        }
197    }
198}
199
200fn parse_transforms_content<R: BufRead>(parser: &mut XmlParser<R>) -> Result<Vec<Transform>> {
201    let mut transforms = Vec::new();
202    loop {
203        let evt_info = match parser.read_next_event()? {
204            Event::Start(e) => {
205                let alg = get_attribute(&e, b"Algorithm").map(|s| s.into_owned());
206                Some((
207                    e.local_name().as_ref().to_vec(),
208                    e.name().as_ref().to_vec(),
209                    alg,
210                    false,
211                ))
212            }
213            Event::Empty(e) => {
214                let alg = get_attribute(&e, b"Algorithm").map(|s| s.into_owned());
215                Some((
216                    e.local_name().as_ref().to_vec(),
217                    e.name().as_ref().to_vec(),
218                    alg,
219                    true,
220                ))
221            }
222            Event::End(e) if e.local_name().as_ref() == b"Transforms" => return Ok(transforms),
223            Event::Eof => {
224                return Err(Lib3mfError::Validation(
225                    "Unexpected EOF in Transforms".to_string(),
226                ));
227            }
228            _ => None,
229        };
230
231        if let Some((local_name, raw_name, alg, is_empty)) = evt_info {
232            match local_name.as_slice() {
233                b"Transform" => {
234                    transforms.push(Transform {
235                        algorithm: alg.unwrap_or_default(),
236                    });
237                    if !is_empty {
238                        parser.read_to_end(&raw_name)?;
239                    }
240                }
241                _ => {
242                    if !is_empty {
243                        parser.read_to_end(&raw_name)?;
244                    }
245                }
246            }
247        }
248    }
249}
250
251fn parse_key_info<R: BufRead>(parser: &mut XmlParser<R>) -> Result<KeyInfo> {
252    let mut info = KeyInfo::default();
253
254    loop {
255        let evt_info = match parser.read_next_event()? {
256            Event::Start(e) => Some((e.local_name().as_ref().to_vec(), e.name().as_ref().to_vec())),
257            Event::End(e) if e.local_name().as_ref() == b"KeyInfo" => return Ok(info),
258            Event::Eof => {
259                return Err(Lib3mfError::Validation(
260                    "Unexpected EOF in KeyInfo".to_string(),
261                ));
262            }
263            _ => None,
264        };
265
266        if let Some((local_name, raw_name)) = evt_info {
267            match local_name.as_slice() {
268                b"KeyName" => {
269                    let val = parser.read_text_content()?;
270                    info.key_name = Some(val);
271                }
272                b"KeyValue" => {
273                    info.key_value = Some(parse_key_value(parser)?);
274                }
275                b"X509Data" => {
276                    info.x509_data = Some(parse_x509_data(parser)?);
277                }
278                _ => {
279                    parser.read_to_end(&raw_name)?;
280                }
281            }
282        }
283    }
284}
285
286fn parse_x509_data<R: BufRead>(parser: &mut XmlParser<R>) -> Result<X509Data> {
287    let mut data = X509Data::default();
288    loop {
289        let evt_info = match parser.read_next_event()? {
290            Event::Start(e) => Some((e.local_name().as_ref().to_vec(), e.name().as_ref().to_vec())),
291            Event::End(e) if e.local_name().as_ref() == b"X509Data" => return Ok(data),
292            Event::Eof => {
293                return Err(Lib3mfError::Validation(
294                    "Unexpected EOF in X509Data".to_string(),
295                ));
296            }
297            _ => None,
298        };
299
300        if let Some((local_name, raw_name)) = evt_info {
301            match local_name.as_slice() {
302                b"X509Certificate" => {
303                    // X509Certificate is a text string (Base64)
304                    let val = parser.read_text_content()?;
305                    // Clean up whitespace?
306                    let cleaned = val.chars().filter(|c| !c.is_whitespace()).collect();
307                    data.certificate = Some(cleaned);
308                }
309                _ => {
310                    parser.read_to_end(&raw_name)?;
311                }
312            }
313        }
314    }
315}
316
317fn parse_key_value<R: BufRead>(parser: &mut XmlParser<R>) -> Result<KeyValue> {
318    let mut val = KeyValue::default();
319    loop {
320        let evt_info = match parser.read_next_event()? {
321            Event::Start(e) => Some((e.local_name().as_ref().to_vec(), e.name().as_ref().to_vec())),
322            Event::End(e) if e.local_name().as_ref() == b"KeyValue" => return Ok(val),
323            Event::Eof => {
324                return Err(Lib3mfError::Validation(
325                    "Unexpected EOF in KeyValue".to_string(),
326                ));
327            }
328            _ => None,
329        };
330
331        if let Some((local_name, raw_name)) = evt_info {
332            match local_name.as_slice() {
333                b"RSAKeyValue" => {
334                    val.rsa_key_value = Some(parse_rsa_key_value(parser)?);
335                }
336                _ => {
337                    parser.read_to_end(&raw_name)?;
338                }
339            }
340        }
341    }
342}
343
344fn parse_rsa_key_value<R: BufRead>(parser: &mut XmlParser<R>) -> Result<RSAKeyValue> {
345    let mut modulus = String::new();
346    let mut exponent = String::new();
347
348    loop {
349        let evt_info = match parser.read_next_event()? {
350            Event::Start(e) => Some((e.local_name().as_ref().to_vec(), e.name().as_ref().to_vec())),
351            Event::End(e) if e.local_name().as_ref() == b"RSAKeyValue" => {
352                return Ok(RSAKeyValue { modulus, exponent });
353            }
354            Event::Eof => {
355                return Err(Lib3mfError::Validation(
356                    "Unexpected EOF in RSAKeyValue".to_string(),
357                ));
358            }
359            _ => None,
360        };
361
362        if let Some((local_name, raw_name)) = evt_info {
363            match local_name.as_slice() {
364                b"Modulus" => modulus = parser.read_text_content()?,
365                b"Exponent" => exponent = parser.read_text_content()?,
366                _ => {
367                    parser.read_to_end(&raw_name)?;
368                }
369            }
370        }
371    }
372}