1#[cfg(test)]
2mod integrity_test;
3
4use crate::attributes::*;
5use crate::checks::*;
6use crate::message::*;
7use md5::{Digest, Md5};
8use shared::error::*;
9
10use ring::hmac;
11use std::fmt;
12
13pub(crate) const CREDENTIALS_SEP: &str = ":";
15
16#[derive(Default, Clone)]
23pub struct MessageIntegrity(pub Vec<u8>);
27
28fn new_hmac(key: &[u8], message: &[u8]) -> Vec<u8> {
29 let mac = hmac::Key::new(hmac::HMAC_SHA1_FOR_LEGACY_USE_ONLY, key);
30 hmac::sign(&mac, message).as_ref().to_vec()
31}
32
33impl fmt::Display for MessageIntegrity {
34 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
35 write!(f, "KEY: 0x{:x?}", self.0)
36 }
37}
38
39impl Setter for MessageIntegrity {
40 fn add_to(&self, m: &mut Message) -> Result<()> {
44 for a in &m.attributes.0 {
45 if a.typ == ATTR_FINGERPRINT {
48 return Err(Error::ErrFingerprintBeforeIntegrity);
49 }
50 }
51 let length = m.length;
55 m.length += (MESSAGE_INTEGRITY_SIZE + ATTRIBUTE_HEADER_SIZE) as u32;
57 m.write_length(); let v = new_hmac(&self.0, &m.raw); m.length = length; m.add(ATTR_MESSAGE_INTEGRITY, &v);
62
63 Ok(())
64 }
65}
66
67pub(crate) const MESSAGE_INTEGRITY_SIZE: usize = 20;
68
69impl MessageIntegrity {
70 pub fn new_long_term_integrity(username: String, realm: String, password: String) -> Self {
73 let s = [username, realm, password].join(CREDENTIALS_SEP);
74
75 let mut h = Md5::new();
76 h.update(s.as_bytes());
77
78 MessageIntegrity(h.finalize().as_slice().to_vec())
79 }
80
81 pub fn new_short_term_integrity(password: String) -> Self {
84 MessageIntegrity(password.as_bytes().to_vec())
85 }
86
87 pub fn check(&self, m: &mut Message) -> Result<()> {
91 let v = m.get(ATTR_MESSAGE_INTEGRITY)?;
92
93 let length = m.length as usize;
97 let mut after_integrity = false;
98 let mut size_reduced = 0;
99
100 for a in &m.attributes.0 {
101 if after_integrity {
102 size_reduced += nearest_padded_value_length(a.length as usize);
103 size_reduced += ATTRIBUTE_HEADER_SIZE;
104 }
105 if a.typ == ATTR_MESSAGE_INTEGRITY {
106 after_integrity = true;
107 }
108 }
109 m.length -= size_reduced as u32;
110 m.write_length();
111 let start_of_hmac = MESSAGE_HEADER_SIZE + m.length as usize
113 - (ATTRIBUTE_HEADER_SIZE + MESSAGE_INTEGRITY_SIZE);
114 let b = &m.raw[..start_of_hmac]; let expected = new_hmac(&self.0, b);
116 m.length = length as u32;
117 m.write_length(); check_hmac(&v, &expected)
119 }
120}