ezk_sdp_types/attributes/
fingerprint.rs1use 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}