ezk_sdp_types/attributes/
fingerprint.rs

1use bytes::Bytes;
2use bytesstr::BytesStr;
3use internal::IResult;
4use nom::{
5    branch::alt,
6    bytes::complete::{tag_no_case, take, take_while1},
7    character::complete::char,
8    combinator::{map, map_res},
9    error::context,
10    multi::separated_list1,
11    sequence::separated_pair,
12};
13use std::fmt;
14
15use crate::not_whitespace;
16
17#[derive(Debug, Clone)]
18pub struct Fingerprint {
19    pub algorithm: FingerprintAlgorithm,
20    pub fingerprint: Vec<u8>,
21}
22
23#[derive(Debug, Clone, PartialEq, Eq)]
24pub enum FingerprintAlgorithm {
25    SHA1,
26    SHA224,
27    SHA256,
28    SHA384,
29    SHA512,
30    MD5,
31    MD2,
32    Other(BytesStr),
33}
34
35impl Fingerprint {
36    pub fn parse<'i>(src: &Bytes, i: &'i str) -> IResult<&'i str, Self> {
37        context(
38            "parsing fingerprint-attribute",
39            map(
40                separated_pair(
41                    alt((
42                        map(tag_no_case("SHA-1"), |_| FingerprintAlgorithm::SHA1),
43                        map(tag_no_case("SHA-224"), |_| FingerprintAlgorithm::SHA224),
44                        map(tag_no_case("SHA-256"), |_| FingerprintAlgorithm::SHA256),
45                        map(tag_no_case("SHA-384"), |_| FingerprintAlgorithm::SHA384),
46                        map(tag_no_case("SHA-512"), |_| FingerprintAlgorithm::SHA512),
47                        map(tag_no_case("MD5"), |_| FingerprintAlgorithm::MD5),
48                        map(tag_no_case("MD2"), |_| FingerprintAlgorithm::MD2),
49                        map(take_while1(not_whitespace), |other| {
50                            FingerprintAlgorithm::Other(BytesStr::from_parse(src, other))
51                        }),
52                    )),
53                    take_while1(char::is_whitespace),
54                    separated_list1(
55                        char(':'),
56                        map_res(take(2usize), |hex: &str| u8::from_str_radix(hex, 16)),
57                    ),
58                ),
59                |(algorithm, fingerprint)| Self {
60                    algorithm,
61                    fingerprint,
62                },
63            ),
64        )(i)
65    }
66}
67
68impl fmt::Display for FingerprintAlgorithm {
69    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70        f.write_str(match self {
71            FingerprintAlgorithm::SHA1 => "SHA-1",
72            FingerprintAlgorithm::SHA224 => "SHA-224",
73            FingerprintAlgorithm::SHA256 => "SHA-256",
74            FingerprintAlgorithm::SHA384 => "SHA-384",
75            FingerprintAlgorithm::SHA512 => "SHA-512",
76            FingerprintAlgorithm::MD5 => "MD5",
77            FingerprintAlgorithm::MD2 => "MD2",
78            FingerprintAlgorithm::Other(bytes_str) => bytes_str.as_str(),
79        })
80    }
81}
82
83impl fmt::Display for Fingerprint {
84    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85        write!(f, "{} ", self.algorithm)?;
86
87        let mut iter = self.fingerprint.iter();
88
89        if let Some(b) = iter.next() {
90            write!(f, "{b:2X}")?;
91
92            for b in iter {
93                write!(f, ":{b:02X}")?;
94            }
95        }
96
97        Ok(())
98    }
99}
100
101#[cfg(test)]
102mod test {
103    use super::*;
104
105    #[test]
106    fn fingerprint() {
107        let input = BytesStr::from_static("SHA-256 D7:87:8B:B1:29:F2:19:E4:D3:06:C9:66:32:58:2C:65:4E:3E:81:3B:EC:CE:26:8C:4D:71:8A:B5:49:E0:8E:94");
108
109        let (rem, fingerprint) = Fingerprint::parse(input.as_ref(), &input).unwrap();
110
111        assert!(rem.is_empty());
112
113        assert_eq!(fingerprint.algorithm, FingerprintAlgorithm::SHA256);
114
115        assert_eq!(
116            fingerprint.fingerprint,
117            [
118                0xD7, 0x87, 0x8B, 0xB1, 0x29, 0xF2, 0x19, 0xE4, 0xD3, 0x06, 0xC9, 0x66, 0x32, 0x58,
119                0x2C, 0x65, 0x4E, 0x3E, 0x81, 0x3B, 0xEC, 0xCE, 0x26, 0x8C, 0x4D, 0x71, 0x8A, 0xB5,
120                0x49, 0xE0, 0x8E, 0x94
121            ]
122        );
123
124        assert_eq!(fingerprint.to_string(), input.as_str());
125    }
126}