Skip to content
File

Blob: firmware/vendor/str0m/src/crypto/finger.rs

rust90 lines
1use core::fmt;
2 
3use subtle::ConstantTimeEq;
4 
5/// Certificate fingerprint.
6///
7/// DTLS uses self signed certificates, and the fingerprint is communicated via
8/// SDP to let the remote peer verify who is connecting.
9#[derive(Debug, Clone)]
10pub struct Fingerprint {
11 /// Hash function used to produce the `bytes`.
12 ///
13 /// This is normally `sha-256`.
14 pub hash_func: String,
15 
16 /// Digest of the certificate by the algorithm in `hash_func`.
17 pub bytes: Vec<u8>,
18}
19 
20impl PartialEq for Fingerprint {
21 fn eq(&self, other: &Self) -> bool {
22 // Use constant-time comparison for the bytes to prevent timing attacks
23 self.hash_func == other.hash_func && self.bytes[..].ct_eq(&other.bytes[..]).into()
24 }
25}
26 
27impl Eq for Fingerprint {}
28 
29impl std::hash::Hash for Fingerprint {
30 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
31 self.hash_func.hash(state);
32 self.bytes.hash(state);
33 }
34}
35 
36// DO NOT CHANGE!
37// This format is exactly what's needed in n SDP.
38impl fmt::Display for Fingerprint {
39 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40 write!(f, "{} ", self.hash_func)?;
41 for (i, b) in self.bytes.iter().enumerate() {
42 if i > 0 {
43 write!(f, ":")?;
44 }
45 write!(f, "{:02X}", b)?;
46 }
47 Ok(())
48 }
49}
50 
51impl std::str::FromStr for Fingerprint {
52 type Err = String;
53 
54 fn from_str(hex_string: &str) -> Result<Self, Self::Err> {
55 let (hash_func, hex_with_colons) = hex_string
56 .split_once(' ')
57 .ok_or_else(|| "Failed to split once".to_owned())?;
58 
59 let mut bytes = Vec::new();
60 for hex in hex_with_colons.split(':') {
61 let byte = u8::from_str_radix(hex, 16)
62 .map_err(|e| format!("Failed to parse fingerprint: {}", e))?;
63 bytes.push(byte);
64 }
65 
66 Ok(Self {
67 hash_func: hash_func.to_owned(),
68 bytes,
69 })
70 }
71}
72 
73#[cfg(test)]
74mod test {
75 use super::*;
76 
77 #[test]
78 fn fingerprint_format() {
79 let f = Fingerprint {
80 hash_func: "foo".to_string(),
81 bytes: vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17],
82 };
83 
84 assert_eq!(
85 f.to_string(),
86 "foo 00:01:02:03:04:05:06:07:08:09:0A:0B:0C:0D:0E:0F:10:11"
87 );
88 }
89}