1use crate::attributes::integrity_attr::message_integrity_attribute;
2use crate::attributes::integrity_attr::HmacSha;
3use crate::Decode;
4use hmac_sha1::hmac_sha1;
5use std::convert::TryInto;
6
7const MESSAGE_INTEGRITY: u16 = 0x0008;
8const MESSAGE_INTEGRITY_SIZE: usize = 20;
9
10impl HmacSha for MessageIntegrity {
11 fn hmac_sha(key: &[u8], message: &[u8]) -> Vec<u8> {
12 hmac_sha1(key, message).to_vec()
13 }
14}
15
16message_integrity_attribute!(
17 MessageIntegrity,
39 MESSAGE_INTEGRITY,
40 MESSAGE_INTEGRITY_SIZE
41);
42
43#[cfg(test)]
44mod tests {
45 use super::*;
46 use crate::attributes::{EncodeAttributeValue, Verifiable};
47 use crate::context::AttributeEncoderContext;
48 use crate::{Algorithm, AlgorithmId, DecoderContextBuilder, HMACKey};
49 use crate::{StunAttribute, StunErrorType};
50
51 #[test]
52 fn encode_message_integrity_with_short_term() {
53 let mut input: [u8; 48] = [0xff; 48];
54 input.copy_from_slice(&stun_vectors::SAMPLE_IPV4_RESPONSE[..48]);
55 input[3] = 0x1c;
57
58 let mut output: [u8; MESSAGE_INTEGRITY_SIZE] = [0xff; MESSAGE_INTEGRITY_SIZE];
59 let hmac_hash = [
60 0x2b, 0x91, 0xf5, 0x99, 0xfd, 0x9e, 0x90, 0xc3, 0x8c, 0x74, 0x89, 0xf9, 0x2a, 0xf9,
61 0xba, 0x53, 0xf0, 0x6b, 0xe7, 0xd7,
62 ];
63
64 let password = "VOkJxbRl1RmTxUk/WvJxBt";
65 let key = HMACKey::new_short_term(password).expect("Could not create HMACKey");
66 let attr = MessageIntegrity::new(key);
67 let ctx = AttributeEncoderContext::new(None, &input, &mut output);
68
69 let size = attr.encode(ctx).expect("Could not encode MessageIntegrty");
70 assert_eq!(size, MESSAGE_INTEGRITY_SIZE);
71 output.iter().for_each(|x| assert_eq!(*x, 0x00));
73
74 input[3] = 0x34;
76 let ctx = AttributeEncoderContext::new(None, &input, &mut output[..size]);
77
78 attr.post_encode(ctx)
80 .expect("Could not encode MessageIntegrty");
81
82 assert_eq!(output, hmac_hash);
83
84 let ctx = AttributeEncoderContext::new(None, &input, &mut output);
86 let attr = MessageIntegrity::from(&hmac_hash);
87 let error = attr
88 .encode(ctx)
89 .expect_err("Could not encode Decodable attribute");
90 assert_eq!(error, StunErrorType::InvalidParam);
91
92 let ctx = AttributeEncoderContext::new(None, &input, &mut output);
93 let error = attr
94 .post_encode(ctx)
95 .expect_err("Could not encode Decodable attribute");
96 assert_eq!(error, StunErrorType::InvalidParam);
97 }
98
99 #[test]
100 fn encode_message_integrity_with_long_term() {
101 let mut input: [u8; 92] = [0xff; 92];
102 input.copy_from_slice(&stun_vectors::SAMPLE_REQUEST_LONG_TERM_AUTH[..92]);
103 input[3] = 0x48;
105
106 let mut output: [u8; MESSAGE_INTEGRITY_SIZE] = [0xff; MESSAGE_INTEGRITY_SIZE];
107 let hmac_hash = [
108 0xF6, 0x70, 0x24, 0x65, 0x6D, 0xD6, 0x4A, 0x3E, 0x02, 0xB8, 0xE0, 0x71, 0x2E, 0x85,
109 0xC9, 0xA2, 0x8C, 0xA8, 0x96, 0x66,
110 ];
111
112 let username = "\u{30DE}\u{30C8}\u{30EA}\u{30C3}\u{30AF}\u{30B9}";
113 let password = "TheMatrIX";
117 let realm = "example.org";
118
119 let algorithm = Algorithm::from(AlgorithmId::MD5);
120 let key = HMACKey::new_long_term(username, realm, password, algorithm)
121 .expect("Could not create HMACKey");
122 let attr = MessageIntegrity::new(key);
123 let ctx = AttributeEncoderContext::new(None, &input, &mut output);
124
125 let size = attr.encode(ctx).expect("Could not encode MessageIntegrty");
126 assert_eq!(size, MESSAGE_INTEGRITY_SIZE);
127 output.iter().for_each(|x| assert_eq!(*x, 0x00));
129
130 input[3] = 0x60;
132 let ctx = AttributeEncoderContext::new(None, &input, &mut output[..size]);
133
134 attr.post_encode(ctx)
136 .expect("Could not encode MessageIntegrty");
137
138 assert_eq!(output, hmac_hash);
139 }
140
141 #[test]
142 fn validate_message_integrity_with_short_term() {
143 let input = crate::get_input_text::<MessageIntegrity>(&stun_vectors::SAMPLE_IPV4_RESPONSE)
144 .expect("Can not get input buffer");
145 let hmac_hash = [
146 0x2b, 0x91, 0xf5, 0x99, 0xfd, 0x9e, 0x90, 0xc3, 0x8c, 0x74, 0x89, 0xf9, 0x2a, 0xf9,
147 0xba, 0x53, 0xf0, 0x6b, 0xe7, 0xd7,
148 ];
149
150 let attr = MessageIntegrity::from(&hmac_hash);
151 let _val = format!("{:?}", attr);
152
153 let password = "VOkJxbRl1RmTxUk/WvJxBt";
154 let key = HMACKey::new_short_term(password).expect("Could not create HMACKey");
155
156 assert!(attr.validate(&input, &key));
157 }
158
159 #[test]
160 fn validation_error() {
161 let input = crate::get_input_text::<MessageIntegrity>(&stun_vectors::SAMPLE_IPV4_RESPONSE)
162 .expect("Can not get input buffer");
163 let hmac_hash = [
164 0x2b, 0x91, 0xf5, 0x99, 0xfd, 0x9e, 0x90, 0xc3, 0x8c, 0x74, 0x89, 0xf9, 0x2a, 0xf9,
165 0xba, 0x53, 0xf0, 0x6b, 0xe7, 0xd7,
166 ];
167
168 let attr = MessageIntegrity::from(&hmac_hash);
169 let _val = format!("{:?}", attr);
170
171 let ctx = DecoderContextBuilder::default().build();
173 assert!(!attr.verify(&input, &ctx));
174
175 let input: [u8; 48] = [0xff; 48];
176 let password = "VOkJxbRl1RmTxUk/WvJxBt";
177 let key = HMACKey::new_short_term(password).expect("Could not create HMACKey");
178 let attr = MessageIntegrity::new(key.clone());
179 assert!(!attr.validate(&input, &key));
180 }
181
182 #[test]
183 fn validate_message_integrity_with_long_term() {
184 let input =
185 crate::get_input_text::<MessageIntegrity>(&stun_vectors::SAMPLE_REQUEST_LONG_TERM_AUTH)
186 .expect("Can not get input buffer");
187 let hmac_hash = [
188 0xF6, 0x70, 0x24, 0x65, 0x6D, 0xD6, 0x4A, 0x3E, 0x02, 0xB8, 0xE0, 0x71, 0x2E, 0x85,
189 0xC9, 0xA2, 0x8C, 0xA8, 0x96, 0x66,
190 ];
191
192 let attr = MessageIntegrity::from(hmac_hash);
193
194 let username = "\u{30DE}\u{30C8}\u{30EA}\u{30C3}\u{30AF}\u{30B9}";
195 let password = "TheMatrIX";
199 let realm = "example.org";
200 let algorithm = Algorithm::from(AlgorithmId::MD5);
201 let key = HMACKey::new_long_term(username, realm, password, algorithm)
202 .expect("Could not create HMACKey");
203
204 assert!(attr.validate(&input, &key));
205 }
206
207 #[test]
208 fn message_integrity_stunt_attribute() {
209 let key = HMACKey::new_short_term("test").expect("Can not create short term credential");
210 let attr = StunAttribute::MessageIntegrity(MessageIntegrity::new(key));
211 assert!(attr.is_message_integrity());
212 assert!(attr.as_message_integrity().is_ok());
213 assert!(attr.as_error_code().is_err());
214
215 assert!(attr.attribute_type().is_comprehension_required());
216 assert!(!attr.attribute_type().is_comprehension_optional());
217
218 let dbg_fmt = format!("{:?}", attr);
219 assert_eq!("MessageIntegrity(Encodable(EncodableMessageIntegrity(HMACKey(HMACKeyPriv { mechanism: ShortTerm, key: [116, 101, 115, 116] }))))", dbg_fmt);
220 }
221}