1#[cfg(feature = "std")]
88use alloc::collections::BTreeMap;
89use alloc::string::String;
90use alloc::sync::Arc;
91use alloc::vec;
92use alloc::vec::Vec;
93use core::convert::TryFrom;
94#[cfg(feature = "std")]
95use std::sync::{Mutex, OnceLock};
96
97use byteorder::{BigEndian, ByteOrder};
98
99use crate::attribute::*;
100
101use tracing::{error, trace, warn};
102
103use hmac::digest::core_api::CoreWrapper;
104use hmac::digest::CtOutput;
105use hmac::HmacCore;
106
107pub const MAGIC_COOKIE: u32 = 0x2112A442;
109
110#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
112pub struct Method(u16);
113
114impl core::fmt::Display for Method {
115 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
116 write!(f, "{}({:#x}: {})", self.0, self.0, self.name())
117 }
118}
119
120#[cfg(feature = "std")]
121static METHOD_NAME_MAP: OnceLock<Mutex<BTreeMap<Method, &'static str>>> = OnceLock::new();
122
123impl Method {
124 #[cfg(feature = "std")]
126 pub fn add_name(self, name: &'static str) {
127 let mut mnames = METHOD_NAME_MAP
128 .get_or_init(Default::default)
129 .lock()
130 .unwrap();
131 mnames.insert(self, name);
132 }
133
134 pub const fn new(val: u16) -> Self {
146 if val >= 0xf000 {
147 panic!("Method value is out of range!");
148 }
149 Self(val)
150 }
151
152 pub fn value(&self) -> u16 {
162 self.0
163 }
164
165 pub fn name(self) -> &'static str {
173 match self {
174 BINDING => "BINDING",
175 _ => {
176 #[cfg(feature = "std")]
177 {
178 let mnames = METHOD_NAME_MAP
179 .get_or_init(Default::default)
180 .lock()
181 .unwrap();
182 if let Some(name) = mnames.get(&self) {
183 return name;
184 }
185 }
186 "unknown"
187 }
188 }
189 }
190}
191
192pub const BINDING: Method = Method::new(0x0001);
195
196#[derive(Debug, thiserror::Error)]
198#[non_exhaustive]
199pub enum StunParseError {
200 #[error("The provided data is not a STUN message")]
202 NotStun,
203 #[error("Not enough data available to parse the packet, expected {}, actual {}", .expected, .actual)]
205 Truncated {
206 expected: usize,
208 actual: usize,
210 },
211 #[error("Too many bytes for this data, expected {}, actual {}", .expected, .actual)]
213 TooLarge {
214 expected: usize,
216 actual: usize,
218 },
219 #[error("Integrity value does not match")]
221 IntegrityCheckFailed,
222 #[error("Missing attribute {}", .0)]
224 MissingAttribute(AttributeType),
225 #[error("An attribute {} was encountered after a message integrity attribute", .0)]
227 AttributeAfterIntegrity(AttributeType),
228 #[error("An attribute {} was encountered after a fingerprint attribute", .0)]
230 AttributeAfterFingerprint(AttributeType),
231 #[error("Fingerprint does not match")]
233 FingerprintMismatch,
234 #[error("The provided data does not match the message")]
236 DataMismatch,
237 #[error("The attribute contains invalid data")]
239 InvalidAttributeData,
240 #[error("Cannot parse with this attribute")]
242 WrongAttributeImplementation,
243}
244
245#[derive(Debug, thiserror::Error)]
247#[non_exhaustive]
248pub enum StunWriteError {
249 #[error("The attribute already exists in the message")]
251 AttributeExists(AttributeType),
252 #[error("The message already contains a fingerprint attribute")]
254 FingerprintExists,
255 #[error("The message already contains a message intregrity attribute")]
257 MessageIntegrityExists,
258 #[error("Too many bytes for this data, expected {}, actual {}", .expected, .actual)]
260 TooLarge {
261 expected: usize,
263 actual: usize,
265 },
266 #[error("Not enough data available to parse the packet, expected {}, actual {}", .expected, .actual)]
268 TooSmall {
269 expected: usize,
271 actual: usize,
273 },
274 #[error("Failed to compute integrity")]
276 IntegrityFailed,
277 #[error("Out of range input provided")]
279 OutOfRange {
280 value: usize,
282 min: usize,
284 max: usize,
286 },
287}
288
289#[derive(Debug, Clone, PartialEq, Eq)]
291#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
292pub struct LongTermCredentials {
293 username: String,
294 password: String,
295 realm: String,
296}
297
298impl LongTermCredentials {
299 pub fn new(username: String, password: String, realm: String) -> Self {
315 Self {
316 username,
317 password,
318 realm,
319 }
320 }
321
322 pub fn username(&self) -> &str {
324 &self.username
325 }
326
327 pub fn password(&self) -> &str {
329 &self.password
330 }
331
332 pub fn realm(&self) -> &str {
334 &self.realm
335 }
336}
337
338#[derive(Debug, Clone, PartialEq, Eq)]
340#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
341pub struct ShortTermCredentials {
342 password: String,
343}
344
345impl ShortTermCredentials {
346 pub fn new(password: String) -> Self {
356 Self { password }
357 }
358
359 pub fn password(&self) -> &str {
361 &self.password
362 }
363}
364
365#[derive(Debug, Clone, PartialEq, Eq)]
369#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
370pub enum MessageIntegrityCredentials {
371 ShortTerm(ShortTermCredentials),
373 LongTerm(LongTermCredentials),
375}
376
377impl From<LongTermCredentials> for MessageIntegrityCredentials {
378 fn from(value: LongTermCredentials) -> Self {
379 MessageIntegrityCredentials::LongTerm(value)
380 }
381}
382
383impl From<ShortTermCredentials> for MessageIntegrityCredentials {
384 fn from(value: ShortTermCredentials) -> Self {
385 MessageIntegrityCredentials::ShortTerm(value)
386 }
387}
388
389impl MessageIntegrityCredentials {
390 pub fn make_key(&self) -> IntegrityKey {
392 match self {
393 MessageIntegrityCredentials::ShortTerm(short) => {
394 IntegrityKey::new(short.password.as_bytes().to_vec())
395 }
396 MessageIntegrityCredentials::LongTerm(long) => {
397 use md5::{Digest, Md5};
398 let mut digest = Md5::new();
399 digest.update(long.username.as_bytes());
400 digest.update(":".as_bytes());
401 digest.update(long.realm.as_bytes());
402 digest.update(":".as_bytes());
403 digest.update(long.password.as_bytes());
404 IntegrityKey::new(digest.finalize().to_vec())
405 }
406 }
407 }
408}
409
410type HmacSha1 = hmac::Hmac<sha1::Sha1>;
411type HmacSha256 = hmac::Hmac<sha2::Sha256>;
412
413#[derive(Debug, Clone)]
415pub struct IntegrityKey {
416 bytes: Vec<u8>,
417 #[cfg(feature = "std")]
418 sha1: Arc<Mutex<Option<HmacSha1>>>,
419 #[cfg(feature = "std")]
420 sha256: Arc<Mutex<Option<HmacSha256>>>,
421}
422
423impl PartialEq<IntegrityKey> for IntegrityKey {
424 fn eq(&self, other: &Self) -> bool {
425 self.bytes == other.bytes
426 }
427}
428
429impl Eq for IntegrityKey {}
430
431impl IntegrityKey {
432 fn new(bytes: Vec<u8>) -> Self {
433 Self {
434 bytes,
435 #[cfg(feature = "std")]
436 sha1: Default::default(),
437 #[cfg(feature = "std")]
438 sha256: Default::default(),
439 }
440 }
441 pub(crate) fn as_bytes(&self) -> &[u8] {
442 &self.bytes
443 }
444
445 pub(crate) fn verify_sha1(&self, data: &[&[u8]], expected: &[u8]) -> bool {
446 use hmac::digest::Output;
447 let computed = self.compute_sha1(data);
448 computed == Output::<sha1::Sha1Core>::from_slice(expected).into()
449 }
450
451 pub(crate) fn compute_sha1(
452 &self,
453 data: &[&[u8]],
454 ) -> CtOutput<CoreWrapper<HmacCore<CoreWrapper<sha1::Sha1Core>>>> {
455 use hmac::Mac;
456 #[cfg(feature = "std")]
457 let mut sha1 = self.sha1.lock().unwrap();
458 #[cfg(feature = "std")]
459 let hmac = sha1.get_or_insert_with(|| HmacSha1::new_from_slice(self.as_bytes()).unwrap());
460 #[cfg(not(feature = "std"))]
461 let mut hmac = HmacSha1::new_from_slice(self.as_bytes()).unwrap();
462
463 for data in data {
464 hmac.update(data);
465 }
466 #[cfg(feature = "std")]
467 let ret = hmac.finalize_reset();
468 #[cfg(not(feature = "std"))]
469 let ret = hmac.finalize();
470 ret
471 }
472
473 pub(crate) fn verify_sha256(&self, data: &[&[u8]], expected: &[u8]) -> bool {
474 if expected.is_empty() {
475 return false;
476 }
477 let computed = self.compute_sha256(data);
478 if computed.len() < expected.len() {
479 return false;
480 }
481 &computed[..expected.len()] == expected
483 }
484
485 pub(crate) fn compute_sha256(&self, data: &[&[u8]]) -> [u8; 32] {
486 use hmac::Mac;
487 #[cfg(feature = "std")]
488 let mut sha256 = self.sha256.lock().unwrap();
489 #[cfg(feature = "std")]
490 let hmac =
491 sha256.get_or_insert_with(|| HmacSha256::new_from_slice(self.as_bytes()).unwrap());
492 #[cfg(not(feature = "std"))]
493 let mut hmac = HmacSha256::new_from_slice(self.as_bytes()).unwrap();
494
495 for data in data {
496 hmac.update(data);
497 }
498 #[cfg(feature = "std")]
499 let ret = hmac.finalize_reset();
500 #[cfg(not(feature = "std"))]
501 let ret = hmac.finalize();
502 ret.into_bytes().into()
503 }
504}
505
506#[derive(Copy, Clone, Debug, PartialEq, Eq)]
518pub enum MessageClass {
519 Request,
521 Indication,
523 Success,
525 Error,
527}
528
529impl MessageClass {
530 pub fn is_response(self) -> bool {
533 matches!(self, MessageClass::Success | MessageClass::Error)
534 }
535
536 fn to_bits(self) -> u16 {
537 match self {
538 MessageClass::Request => 0x000,
539 MessageClass::Indication => 0x010,
540 MessageClass::Success => 0x100,
541 MessageClass::Error => 0x110,
542 }
543 }
544}
545
546#[derive(Copy, Clone, Debug, PartialEq, Eq)]
548pub struct MessageType(u16);
549
550impl core::fmt::Display for MessageType {
551 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
552 write!(
553 f,
554 "MessageType(class: {:?}, method: {}",
555 self.class(),
556 self.method(),
557 )
558 }
559}
560
561impl MessageType {
562 pub fn from_class_method(class: MessageClass, method: Method) -> Self {
573 let class_bits = MessageClass::to_bits(class);
574 let method = method.value();
575 let method_bits = method & 0xf | (method & 0x70) << 1 | (method & 0xf80) << 2;
576 Self(class_bits | method_bits)
579 }
580
581 pub fn class(self) -> MessageClass {
591 let class = (self.0 & 0x10) >> 4 | (self.0 & 0x100) >> 7;
592 match class {
593 0x0 => MessageClass::Request,
594 0x1 => MessageClass::Indication,
595 0x2 => MessageClass::Success,
596 0x3 => MessageClass::Error,
597 _ => unreachable!(),
598 }
599 }
600
601 pub fn has_class(self, cls: MessageClass) -> bool {
611 self.class() == cls
612 }
613
614 pub fn is_response(self) -> bool {
630 self.class().is_response()
631 }
632
633 pub fn method(self) -> Method {
643 Method::new(self.0 & 0xf | (self.0 & 0xe0) >> 1 | (self.0 & 0x3e00) >> 2)
644 }
645
646 pub fn has_method(self, method: Method) -> bool {
656 self.method() == method
657 }
658
659 pub fn write_into(&self, dest: &mut [u8]) {
661 BigEndian::write_u16(dest, self.0);
662 }
663
664 pub fn to_bytes(self) -> Vec<u8> {
666 let mut ret = vec![0; 2];
667 BigEndian::write_u16(&mut ret[0..2], self.0);
668 ret
669 }
670
671 pub fn from_bytes(data: &[u8]) -> Result<Self, StunParseError> {
673 let data = BigEndian::read_u16(data);
674 if data & 0xc000 != 0x0 {
675 return Err(StunParseError::NotStun);
677 }
678 Ok(Self(data))
679 }
680}
681impl TryFrom<&[u8]> for MessageType {
682 type Error = StunParseError;
683
684 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
685 MessageType::from_bytes(value)
686 }
687}
688
689#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
691pub struct TransactionId {
692 id: u128,
693}
694
695impl TransactionId {
696 pub fn generate() -> TransactionId {
698 #[cfg(not(feature = "std"))]
699 {
700 use rand::TryRngCore;
701 let mut dest = [0; 16];
702 rand::rngs::OsRng
703 .try_fill_bytes(&mut dest)
704 .expect("Cannot generate random data");
705 u128::from_be_bytes(dest).into()
706 }
707 #[cfg(feature = "std")]
708 {
709 use rand::Rng;
710 let mut rng = rand::rng();
711 rng.random::<u128>().into()
712 }
713 }
714}
715
716impl From<u128> for TransactionId {
717 fn from(id: u128) -> Self {
718 Self {
719 id: id & 0xffff_ffff_ffff_ffff_ffff_ffff,
720 }
721 }
722}
723impl From<TransactionId> for u128 {
724 fn from(id: TransactionId) -> Self {
725 id.id
726 }
727}
728impl core::fmt::Display for TransactionId {
729 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
730 write!(f, "{:#x}", self.id)
731 }
732}
733
734#[derive(Debug)]
738pub struct MessageHeader {
739 mtype: MessageType,
740 transaction_id: TransactionId,
741 length: u16,
742}
743
744impl MessageHeader {
745 pub const LENGTH: usize = 20;
747
748 pub fn from_bytes(data: &[u8]) -> Result<Self, StunParseError> {
761 if data.len() < 20 {
762 return Err(StunParseError::Truncated {
763 expected: 20,
764 actual: data.len(),
765 });
766 }
767 let mtype = MessageType::from_bytes(data)?;
768 let mlength = BigEndian::read_u16(&data[2..]);
769 let tid = BigEndian::read_u128(&data[4..]);
770 let cookie = (tid >> 96) as u32;
771 if cookie != MAGIC_COOKIE {
772 warn!(
773 "malformed cookie constant {:?} != stored data {:?}",
774 MAGIC_COOKIE, cookie
775 );
776 return Err(StunParseError::NotStun);
777 }
778
779 Ok(Self {
780 mtype,
781 transaction_id: tid.into(),
782 length: mlength,
783 })
784 }
785
786 pub fn data_length(&self) -> u16 {
789 self.length
790 }
791
792 pub fn transaction_id(&self) -> TransactionId {
794 self.transaction_id
795 }
796
797 pub fn get_type(&self) -> MessageType {
799 self.mtype
800 }
801
802 fn new(mtype: MessageType, transaction_id: TransactionId, length: u16) -> Self {
803 Self {
804 mtype,
805 transaction_id,
806 length,
807 }
808 }
809
810 fn write_into(&self, dest: &mut [u8]) {
811 self.mtype.write_into(&mut dest[..2]);
812 let transaction: u128 = self.transaction_id.into();
813 let tid = (MAGIC_COOKIE as u128) << 96 | transaction & 0xffff_ffff_ffff_ffff_ffff_ffff;
814 BigEndian::write_u128(&mut dest[4..20], tid);
815 BigEndian::write_u16(&mut dest[2..4], self.length);
816 }
817}
818
819#[derive(Debug, Clone, Copy)]
824pub struct Message<'a> {
825 data: &'a [u8],
826}
827
828impl core::fmt::Display for Message<'_> {
829 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
830 write!(
831 f,
832 "Message(class: {:?}, method: {}, transaction: {}, attributes: ",
833 self.get_type().class(),
834 self.get_type().method(),
835 self.transaction_id()
836 )?;
837 let iter = self.iter_attributes();
838 write!(f, "[")?;
839 for (i, (_offset, a)) in iter.enumerate() {
840 if i > 0 {
841 write!(f, ", ")?;
842 }
843 write!(f, "{a}")?;
844 }
845 write!(f, "]")?;
846 write!(f, ")")
847 }
848}
849
850#[derive(Clone, Copy, Debug, PartialEq, Eq)]
852pub enum IntegrityAlgorithm {
853 Sha1,
855 Sha256,
857}
858
859impl<'a> Message<'a> {
860 pub fn builder<B: MessageWrite>(
876 mtype: MessageType,
877 transaction_id: TransactionId,
878 mut write: B,
879 ) -> B {
880 let mut data = [0; 20];
881 MessageHeader::new(mtype, transaction_id, 0).write_into(&mut data);
882 write.push_data(&data);
883 write
884 }
885
886 pub fn builder_request<B: MessageWrite>(method: Method, write: B) -> B {
900 Message::builder(
901 MessageType::from_class_method(MessageClass::Request, method),
902 TransactionId::generate(),
903 write,
904 )
905 }
906
907 pub fn builder_success<B: MessageWrite>(orig: &Message, write: B) -> B {
927 if !orig.has_class(MessageClass::Request) {
928 panic!(
929 "A success response message was attempted to be created from a non-request message"
930 );
931 }
932 Message::builder(
933 MessageType::from_class_method(MessageClass::Success, orig.method()),
934 orig.transaction_id(),
935 write,
936 )
937 }
938
939 pub fn builder_error<B: MessageWrite>(orig: &Message, write: B) -> B {
959 if !orig.has_class(MessageClass::Request) {
960 panic!(
961 "An error response message was attempted to be created from a non-request message"
962 );
963 }
964 Message::builder(
965 MessageType::from_class_method(MessageClass::Error, orig.method()),
966 orig.transaction_id(),
967 write,
968 )
969 }
970
971 pub fn builder_indication<B: MessageWrite>(method: Method, write: B) -> B {
985 Message::builder(
986 MessageType::from_class_method(MessageClass::Indication, method),
987 TransactionId::generate(),
988 write,
989 )
990 }
991
992 pub fn get_type(&self) -> MessageType {
1006 MessageType::try_from(&self.data[..2]).unwrap()
1007 }
1008
1009 pub fn class(&self) -> MessageClass {
1021 self.get_type().class()
1022 }
1023
1024 pub fn has_class(&self, cls: MessageClass) -> bool {
1036 self.class() == cls
1037 }
1038
1039 pub fn is_response(&self) -> bool {
1061 self.class().is_response()
1062 }
1063
1064 pub fn method(&self) -> Method {
1076 self.get_type().method()
1077 }
1078
1079 pub fn has_method(&self, method: Method) -> bool {
1092 self.method() == method
1093 }
1094
1095 pub fn transaction_id(&self) -> TransactionId {
1109 BigEndian::read_u128(&self.data[4..]).into()
1110 }
1111
1112 #[tracing::instrument(
1128 name = "message_from_bytes",
1129 level = "trace",
1130 skip(data),
1131 fields(
1132 data.len = data.len()
1133 )
1134 )]
1135 pub fn from_bytes(data: &'a [u8]) -> Result<Self, StunParseError> {
1136 let orig_data = data;
1137
1138 let header = MessageHeader::from_bytes(data)?;
1139 let mlength = header.data_length() as usize;
1140 if mlength + MessageHeader::LENGTH > data.len() {
1141 warn!(
1143 "malformed advertised size {} and data size {} don't match",
1144 mlength + 20,
1145 data.len()
1146 );
1147 return Err(StunParseError::Truncated {
1148 expected: mlength + MessageHeader::LENGTH,
1149 actual: data.len(),
1150 });
1151 }
1152
1153 let ending_attributes = [
1154 MessageIntegrity::TYPE,
1155 MessageIntegritySha256::TYPE,
1156 Fingerprint::TYPE,
1157 ];
1158 let mut seen_ending_attributes = [AttributeType::new(0); 3];
1160 let mut seen_ending_len = 0;
1161 let mut data_offset = MessageHeader::LENGTH;
1162 for attr in MessageRawAttributesIter::new(data) {
1163 let (_offset, attr) = attr.map_err(|e| {
1164 warn!("failed to parse message attribute at offset {data_offset}: {e}",);
1165 e
1166 })?;
1167
1168 if seen_ending_len > 0 && !ending_attributes.contains(&attr.get_type()) {
1171 if seen_ending_attributes.contains(&Fingerprint::TYPE) {
1172 warn!("unexpected attribute {} after FINGERPRINT", attr.get_type());
1173 return Ok(Message { data: orig_data });
1174 } else {
1175 warn!(
1177 "unexpected attribute {} after MESSAGE_INTEGRITY",
1178 attr.get_type()
1179 );
1180 return Ok(Message { data: orig_data });
1181 }
1182 }
1183
1184 if ending_attributes.contains(&attr.get_type()) {
1185 if seen_ending_attributes.contains(&attr.get_type()) {
1186 if seen_ending_attributes.contains(&Fingerprint::TYPE) {
1187 warn!("unexpected attribute {} after FINGERPRINT", attr.get_type());
1188 return Ok(Message { data: orig_data });
1189 } else {
1190 warn!(
1192 "unexpected attribute {} after MESSAGE_INTEGRITY",
1193 attr.get_type()
1194 );
1195 return Ok(Message { data: orig_data });
1196 }
1197 } else {
1198 seen_ending_attributes[seen_ending_len] = attr.get_type();
1199 seen_ending_len += 1;
1200 }
1202 }
1203 let padded_len = attr.padded_len();
1204 if attr.get_type() == Fingerprint::TYPE {
1205 let f = Fingerprint::from_raw_ref(&attr)?;
1206 let msg_fingerprint = f.fingerprint();
1207 let mut header = [0; 4];
1208 header[0] = orig_data[0];
1209 header[1] = orig_data[1];
1210 BigEndian::write_u16(
1211 &mut header[2..4],
1212 (data_offset + padded_len - MessageHeader::LENGTH) as u16,
1213 );
1214 let fingerprint_data = &orig_data[4..data_offset];
1215 let calculated_fingerprint = Fingerprint::compute(&[&header, fingerprint_data]);
1216 if &calculated_fingerprint != msg_fingerprint {
1217 warn!(
1218 "fingerprint mismatch {:?} != {:?}",
1219 calculated_fingerprint, msg_fingerprint
1220 );
1221 return Err(StunParseError::FingerprintMismatch);
1222 }
1223 }
1224 data_offset += padded_len;
1225 }
1226 Ok(Message { data: orig_data })
1227 }
1228
1229 pub fn validate_integrity(
1252 &self,
1253 credentials: &MessageIntegrityCredentials,
1254 ) -> Result<IntegrityAlgorithm, StunParseError> {
1255 let key = credentials.make_key();
1256 self.validate_integrity_with_key(&key)
1257 }
1258
1259 #[tracing::instrument(
1261 name = "message_validate_integrity_with_key",
1262 level = "trace",
1263 skip(self, key),
1264 fields(
1265 msg.transaction = %self.transaction_id(),
1266 )
1267 )]
1268 pub fn validate_integrity_with_key(
1269 &self,
1270 key: &IntegrityKey,
1271 ) -> Result<IntegrityAlgorithm, StunParseError> {
1272 let raw_sha1 = self.raw_attribute(MessageIntegrity::TYPE);
1273 let raw_sha256 = self.raw_attribute(MessageIntegritySha256::TYPE);
1274 let (algo, msg_hmac) = match (raw_sha1, raw_sha256) {
1275 (_, Some(sha256)) => {
1276 let integrity = MessageIntegritySha256::try_from(&sha256)?;
1277 (IntegrityAlgorithm::Sha256, integrity.hmac().to_vec())
1278 }
1279 (Some(sha1), None) => {
1280 let integrity = MessageIntegrity::try_from(&sha1)?;
1281 (IntegrityAlgorithm::Sha1, integrity.hmac().to_vec())
1282 }
1283 (None, None) => return Err(StunParseError::MissingAttribute(MessageIntegrity::TYPE)),
1284 };
1285
1286 let data = self.data;
1289 debug_assert!(data.len() >= MessageHeader::LENGTH);
1290 let mut data = &data[MessageHeader::LENGTH..];
1291 let mut data_offset = MessageHeader::LENGTH;
1292 while !data.is_empty() {
1293 let attr = RawAttribute::from_bytes(data)?;
1294 if algo == IntegrityAlgorithm::Sha1 && attr.get_type() == MessageIntegrity::TYPE {
1295 let msg = MessageIntegrity::try_from(&attr)?;
1296 debug_assert!(msg.hmac().as_slice() == msg_hmac);
1297
1298 let mut header = [0; 4];
1301 header[0] = self.data[0];
1302 header[1] = self.data[1];
1303 let hmac_data = &self.data[4..data_offset];
1304 BigEndian::write_u16(
1305 &mut header[2..4],
1306 data_offset as u16 + 24 - MessageHeader::LENGTH as u16,
1307 );
1308 MessageIntegrity::verify(
1309 &[header.as_slice(), hmac_data],
1310 key,
1311 msg_hmac.as_slice().try_into().unwrap(),
1312 )?;
1313 return Ok(algo);
1314 } else if algo == IntegrityAlgorithm::Sha256
1315 && attr.get_type() == MessageIntegritySha256::TYPE
1316 {
1317 let msg = MessageIntegritySha256::try_from(&attr)?;
1318 debug_assert!(msg.hmac() == msg_hmac);
1319
1320 let mut header = [0; 4];
1323 header[0] = self.data[0];
1324 header[1] = self.data[1];
1325 let hmac_data = &self.data[4..data_offset];
1326 BigEndian::write_u16(
1327 &mut header[2..4],
1328 data_offset as u16 + attr.padded_len() as u16 - MessageHeader::LENGTH as u16,
1329 );
1330 MessageIntegritySha256::verify(&[&header, hmac_data], key, &msg_hmac)?;
1331 return Ok(algo);
1332 }
1333 let padded_len = attr.padded_len();
1334 debug_assert!(padded_len <= data.len());
1336 data = &data[padded_len..];
1337 data_offset += padded_len;
1338 }
1339
1340 unreachable!();
1343 }
1344
1345 pub fn nth_raw_attribute(&self, atype: AttributeType, n: usize) -> Option<RawAttribute<'_>> {
1364 self.nth_raw_attribute_and_offset(atype, n)
1365 .map(|(_offset, attr)| attr)
1366 }
1367
1368 pub fn raw_attribute(&self, atype: AttributeType) -> Option<RawAttribute<'_>> {
1372 self.nth_raw_attribute(atype, 0)
1373 }
1374
1375 #[tracing::instrument(
1397 name = "message_nth_raw_attribute_and_offset",
1398 level = "trace",
1399 skip(self, atype),
1400 fields(
1401 msg.transaction = %self.transaction_id(),
1402 attribute_type = %atype,
1403 )
1404 )]
1405 pub fn nth_raw_attribute_and_offset(
1406 &self,
1407 atype: AttributeType,
1408 n: usize,
1409 ) -> Option<(usize, RawAttribute<'_>)> {
1410 if let Some((offset, attr)) = self
1411 .iter_attributes()
1412 .filter(|(_offset, attr)| attr.get_type() == atype)
1413 .nth(n)
1414 {
1415 trace!("found attribute at offset: {offset}");
1416 Some((offset, attr))
1417 } else {
1418 trace!("could not find attribute");
1419 None
1420 }
1421 }
1422
1423 pub fn raw_attribute_and_offset(
1428 &self,
1429 atype: AttributeType,
1430 ) -> Option<(usize, RawAttribute<'_>)> {
1431 self.nth_raw_attribute_and_offset(atype, 0)
1432 }
1433
1434 pub fn nth_attribute<A: AttributeFromRaw<'a> + AttributeStaticType>(
1456 &'a self,
1457 n: usize,
1458 ) -> Result<A, StunParseError> {
1459 self.nth_attribute_and_offset(n).map(|(_offset, attr)| attr)
1460 }
1461
1462 pub fn attribute<A: AttributeFromRaw<'a> + AttributeStaticType>(
1466 &'a self,
1467 ) -> Result<A, StunParseError> {
1468 self.nth_attribute(0)
1469 }
1470
1471 pub fn nth_attribute_and_offset<A: AttributeFromRaw<'a> + AttributeStaticType>(
1497 &'a self,
1498 n: usize,
1499 ) -> Result<(usize, A), StunParseError> {
1500 self.nth_raw_attribute_and_offset(A::TYPE, n)
1501 .ok_or(StunParseError::MissingAttribute(A::TYPE))
1502 .and_then(|(offset, raw)| A::from_raw(raw).map(|attr| (offset, attr)))
1503 }
1504
1505 pub fn attribute_and_offset<A: AttributeFromRaw<'a> + AttributeStaticType>(
1510 &'a self,
1511 ) -> Result<(usize, A), StunParseError> {
1512 self.nth_attribute_and_offset(0)
1513 }
1514
1515 pub fn iter_attributes(&self) -> impl Iterator<Item = (usize, RawAttribute<'_>)> {
1517 MessageAttributesIter::new(self.data)
1518 }
1519
1520 #[tracing::instrument(
1568 level = "trace",
1569 skip(msg, write),
1570 fields(
1571 msg.transaction = %msg.transaction_id(),
1572 )
1573 )]
1574 pub fn check_attribute_types<B: MessageWrite>(
1575 msg: &Message,
1576 supported: &[AttributeType],
1577 required_in_msg: &[AttributeType],
1578 write: B,
1579 ) -> Option<B> {
1580 let unsupported: Vec<AttributeType> = msg
1582 .iter_attributes()
1583 .map(|(_offset, a)| a.get_type())
1584 .filter(|at| at.comprehension_required() && !supported.contains(at))
1586 .collect();
1587 if !unsupported.is_empty() {
1588 warn!(
1589 "Message contains unknown comprehension required attributes {:?}, returning unknown attributes",
1590 unsupported
1591 );
1592 return Some(Message::unknown_attributes(msg, &unsupported, write));
1593 }
1594 let has_required_attribute_missing = required_in_msg
1595 .iter()
1596 .any(|&at| {
1598 !msg.iter_attributes()
1599 .map(|(_offset, a)| a.get_type())
1600 .any(|a| a == at)
1601 });
1602 if has_required_attribute_missing {
1603 warn!("Message is missing required attributes, returning bad request");
1604 return Some(Message::bad_request(msg, write));
1605 }
1606 None
1607 }
1608
1609 pub fn unknown_attributes<B: MessageWrite>(
1630 src: &Message,
1631 attributes: &[AttributeType],
1632 write: B,
1633 ) -> B {
1634 let mut out = Message::builder_error(src, write);
1635 let software = Software::new("stun-types").unwrap();
1636 out.add_attribute(&software).unwrap();
1637 let error = ErrorCode::new(420, "Unknown Attributes").unwrap();
1638 out.add_attribute(&error).unwrap();
1639 let unknown = UnknownAttributes::new(attributes);
1640 if !attributes.is_empty() {
1641 out.add_attribute(&unknown).unwrap();
1642 }
1643 out
1644 }
1645
1646 pub fn bad_request<B: MessageWrite>(src: &Message, write: B) -> B {
1664 let mut out = Message::builder_error(src, write);
1665 let software = Software::new("stun-types").unwrap();
1666 out.add_attribute(&software).unwrap();
1667 let error = ErrorCode::new(400, "Bad Request").unwrap();
1668 out.add_attribute(&error).unwrap();
1669 out
1670 }
1671
1672 pub fn has_attribute(&self, atype: AttributeType) -> bool {
1688 self.iter_attributes()
1689 .any(|(_offset, attr)| attr.get_type() == atype)
1690 }
1691
1692 pub fn as_bytes(&self) -> &[u8] {
1694 self.data
1695 }
1696}
1697impl<'a> TryFrom<&'a [u8]> for Message<'a> {
1698 type Error = StunParseError;
1699
1700 fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {
1701 Message::from_bytes(value)
1702 }
1703}
1704
1705#[derive(Debug)]
1706struct MessageRawAttributesIter<'a> {
1707 data: &'a [u8],
1708 data_i: usize,
1709}
1710
1711impl<'a> MessageRawAttributesIter<'a> {
1712 fn new(data: &'a [u8]) -> Self {
1713 Self {
1714 data,
1715 data_i: MessageHeader::LENGTH,
1716 }
1717 }
1718}
1719
1720impl<'a> Iterator for MessageRawAttributesIter<'a> {
1721 type Item = Result<(usize, RawAttribute<'a>), StunParseError>;
1722
1723 fn next(&mut self) -> Option<Self::Item> {
1724 if self.data_i >= self.data.len() {
1725 return None;
1726 }
1727
1728 match RawAttribute::from_bytes(&self.data[self.data_i..]) {
1729 Ok(attr) => {
1730 let padded_len = attr.padded_len();
1731 self.data_i += padded_len;
1732 if self.data_i > self.data.len() {
1733 warn!(
1734 "attribute {} extends past the end of the data",
1735 attr.get_type()
1736 );
1737 return Some(Err(StunParseError::Truncated {
1738 expected: self.data_i,
1739 actual: self.data.len(),
1740 }));
1741 }
1742 Some(Ok((self.data_i - padded_len, attr)))
1743 }
1744 Err(e) => {
1745 let offset = self.data_i;
1746 self.data_i = self.data.len();
1747 let e = match e {
1748 StunParseError::Truncated { expected, actual } => StunParseError::Truncated {
1749 expected: expected + 4 + offset,
1750 actual: actual + 4 + offset,
1751 },
1752 StunParseError::TooLarge { expected, actual } => StunParseError::TooLarge {
1753 expected: expected + 4 + offset,
1754 actual: actual + 4 + offset,
1755 },
1756 e => e,
1757 };
1758 Some(Err(e))
1759 }
1760 }
1761 }
1762}
1763
1764#[doc(hidden)]
1765#[derive(Debug)]
1766pub struct MessageAttributesIter<'a> {
1767 header_parsed: bool,
1768 inner: MessageRawAttributesIter<'a>,
1769 last_attr_type: AttributeType,
1770 seen_message_integrity: bool,
1771}
1772
1773impl<'a> MessageAttributesIter<'a> {
1774 pub fn new(data: &'a [u8]) -> Self {
1778 Self {
1779 header_parsed: false,
1780 inner: MessageRawAttributesIter::new(data),
1781 seen_message_integrity: false,
1782 last_attr_type: AttributeType::new(0),
1783 }
1784 }
1785}
1786
1787impl<'a> Iterator for MessageAttributesIter<'a> {
1788 type Item = (usize, RawAttribute<'a>);
1789
1790 fn next(&mut self) -> Option<Self::Item> {
1791 if self.last_attr_type == Fingerprint::TYPE {
1793 return None;
1794 }
1795
1796 if !self.header_parsed {
1797 let Ok(hdr) = MessageHeader::from_bytes(self.inner.data) else {
1798 self.last_attr_type = Fingerprint::TYPE;
1799 return None;
1800 };
1801 if hdr.data_length() as usize + MessageHeader::LENGTH > self.inner.data.len() {
1802 self.last_attr_type = Fingerprint::TYPE;
1803 return None;
1804 }
1805 self.header_parsed = true;
1806 }
1807
1808 let (offset, attr) = self.inner.next()?.ok()?;
1809 let attr_type = attr.get_type();
1810 if self.seen_message_integrity {
1811 if self.last_attr_type != Fingerprint::TYPE && attr_type == Fingerprint::TYPE {
1812 self.last_attr_type = attr_type;
1813 return Some((offset, attr));
1814 }
1815 if self.last_attr_type == MessageIntegrity::TYPE
1816 && attr_type == MessageIntegritySha256::TYPE
1817 {
1818 self.last_attr_type = attr_type;
1819 return Some((offset, attr));
1820 }
1821 self.last_attr_type = Fingerprint::TYPE;
1822 return None;
1823 }
1824 if attr.get_type() == MessageIntegrity::TYPE
1825 || attr.get_type() == MessageIntegritySha256::TYPE
1826 || attr.get_type() == Fingerprint::TYPE
1827 {
1828 self.seen_message_integrity = true;
1829 }
1830 self.last_attr_type = attr.get_type();
1831
1832 Some((offset, attr))
1833 }
1834}
1835
1836#[allow(clippy::len_without_is_empty)]
1837pub trait MessageWrite {
1839 type Output;
1841 fn max_size(&self) -> Option<usize> {
1844 None
1845 }
1846
1847 fn mut_data(&mut self) -> &mut [u8];
1849 fn data(&self) -> &[u8];
1851 fn len(&self) -> usize;
1853 fn push_data(&mut self, data: &[u8]);
1855 fn push_attribute_unchecked(&mut self, attr: &dyn AttributeWrite);
1857
1858 fn has_attribute(&self, atype: AttributeType) -> bool;
1860
1861 fn has_any_attribute(&self, atypes: &[AttributeType]) -> Option<AttributeType>;
1864
1865 fn finish(self) -> Self::Output;
1867}
1868
1869pub trait MessageWriteExt: MessageWrite {
1871 fn get_type(&self) -> MessageType {
1883 MessageType::from_bytes(self.data()).unwrap()
1884 }
1885
1886 fn class(&self) -> MessageClass {
1898 self.get_type().class()
1899 }
1900
1901 fn has_class(&self, cls: MessageClass) -> bool {
1913 self.class() == cls
1914 }
1915
1916 fn is_response(&self) -> bool {
1938 self.class().is_response()
1939 }
1940
1941 fn method(&self) -> Method {
1953 self.get_type().method()
1954 }
1955
1956 fn has_method(&self, method: Method) -> bool {
1969 self.method() == method
1970 }
1971
1972 fn transaction_id(&self) -> TransactionId {
1986 BigEndian::read_u128(&self.data()[4..]).into()
1987 }
1988
1989 fn add_message_integrity(
2024 &mut self,
2025 credentials: &MessageIntegrityCredentials,
2026 algorithm: IntegrityAlgorithm,
2027 ) -> Result<(), StunWriteError> {
2028 let key = credentials.make_key();
2029 self.add_message_integrity_with_key(&key, algorithm)
2030 }
2031
2032 #[tracing::instrument(
2034 name = "message_add_integrity_with_key",
2035 level = "trace",
2036 err,
2037 skip(self),
2038 fields(
2039 msg.transaction = %self.transaction_id(),
2040 )
2041 )]
2042 fn add_message_integrity_with_key(
2043 &mut self,
2044 key: &IntegrityKey,
2045 algorithm: IntegrityAlgorithm,
2046 ) -> Result<(), StunWriteError> {
2047 let mut atypes = [AttributeType::new(0); 3];
2048 let mut i = 0;
2049 atypes[i] = match algorithm {
2050 IntegrityAlgorithm::Sha1 => MessageIntegrity::TYPE,
2051 IntegrityAlgorithm::Sha256 => MessageIntegritySha256::TYPE,
2052 };
2053 i += 1;
2054 if algorithm == IntegrityAlgorithm::Sha1 {
2055 atypes[i] = MessageIntegritySha256::TYPE;
2056 i += 1;
2057 }
2058 atypes[i] = Fingerprint::TYPE;
2059 i += 1;
2060
2061 match self.has_any_attribute(&atypes[..i]) {
2062 Some(MessageIntegrity::TYPE) => {
2064 return Err(StunWriteError::AttributeExists(MessageIntegrity::TYPE))
2065 }
2066 Some(MessageIntegritySha256::TYPE) => {
2067 return Err(StunWriteError::AttributeExists(
2068 MessageIntegritySha256::TYPE,
2069 ));
2070 }
2071 Some(Fingerprint::TYPE) => return Err(StunWriteError::FingerprintExists),
2072 _ => (),
2073 }
2074 match algorithm {
2075 IntegrityAlgorithm::Sha1 => {
2076 check_attribute_can_fit(self, &MessageIntegrity::new([0; 20]))?
2077 }
2078 IntegrityAlgorithm::Sha256 => {
2079 check_attribute_can_fit(self, &MessageIntegritySha256::new(&[0; 32]).unwrap())?
2080 }
2081 };
2082
2083 add_message_integrity_unchecked(self, key, algorithm);
2084
2085 Ok(())
2086 }
2087
2088 #[tracing::instrument(
2106 name = "message_add_fingerprint",
2107 level = "trace",
2108 skip(self),
2109 fields(
2110 msg.transaction = %self.transaction_id(),
2111 )
2112 )]
2113 fn add_fingerprint(&mut self) -> Result<(), StunWriteError> {
2114 if self.has_attribute(Fingerprint::TYPE) {
2115 return Err(StunWriteError::AttributeExists(Fingerprint::TYPE));
2116 }
2117
2118 check_attribute_can_fit(self, &Fingerprint::new([0; 4]))?;
2119 add_fingerprint_unchecked(self);
2120
2121 Ok(())
2122 }
2123
2124 #[tracing::instrument(
2155 name = "message_add_attribute",
2156 level = "trace",
2157 err,
2158 skip(self, attr),
2159 fields(
2160 msg.transaction = %self.transaction_id(),
2161 )
2162 )]
2163 fn add_attribute(&mut self, attr: &dyn AttributeWrite) -> Result<(), StunWriteError> {
2164 let ty = attr.get_type();
2165 match ty {
2166 MessageIntegrity::TYPE => {
2167 panic!("Cannot write MessageIntegrity with `add_attribute`. Use add_message_integrity() instead");
2168 }
2169 MessageIntegritySha256::TYPE => {
2170 panic!("Cannot write MessageIntegritySha256 with `add_attribute`. Use add_message_integrity() instead");
2171 }
2172 Fingerprint::TYPE => {
2173 panic!(
2174 "Cannot write Fingerprint with `add_attribute`. Use add_fingerprint() instead"
2175 );
2176 }
2177 _ => (),
2178 }
2179 match self.has_any_attribute(&[
2180 MessageIntegrity::TYPE,
2181 MessageIntegritySha256::TYPE,
2182 Fingerprint::TYPE,
2183 ]) {
2184 Some(MessageIntegrity::TYPE) => return Err(StunWriteError::MessageIntegrityExists),
2186 Some(MessageIntegritySha256::TYPE) => {
2187 return Err(StunWriteError::MessageIntegrityExists)
2188 }
2189 Some(Fingerprint::TYPE) => return Err(StunWriteError::FingerprintExists),
2190 _ => (),
2191 }
2192 check_attribute_can_fit(self, attr)?;
2193 self.push_attribute_unchecked(attr);
2194 Ok(())
2195 }
2196}
2197
2198impl<T: MessageWrite> MessageWriteExt for T {}
2199
2200#[derive(Debug, Default)]
2202pub struct MessageWriteVec {
2203 output: Vec<u8>,
2204 attributes: smallvec::SmallVec<[AttributeType; 16]>,
2205}
2206
2207impl MessageWriteVec {
2208 pub fn new() -> Self {
2210 Self::default()
2211 }
2212
2213 pub fn with_capacity(capacity: usize) -> Self {
2215 Self {
2216 output: Vec::with_capacity(capacity),
2217 attributes: Default::default(),
2218 }
2219 }
2220}
2221
2222impl core::ops::Deref for MessageWriteVec {
2223 type Target = Vec<u8>;
2224 fn deref(&self) -> &Self::Target {
2225 &self.output
2226 }
2227}
2228
2229impl core::ops::DerefMut for MessageWriteVec {
2230 fn deref_mut(&mut self) -> &mut Self::Target {
2231 &mut self.output
2232 }
2233}
2234
2235impl MessageWrite for MessageWriteVec {
2236 type Output = Vec<u8>;
2237
2238 fn mut_data(&mut self) -> &mut [u8] {
2239 &mut self.output
2240 }
2241
2242 fn data(&self) -> &[u8] {
2243 &self.output
2244 }
2245
2246 fn len(&self) -> usize {
2247 self.output.len()
2248 }
2249
2250 fn push_data(&mut self, data: &[u8]) {
2251 self.output.extend(data)
2252 }
2253
2254 fn finish(self) -> Self::Output {
2255 self.output
2256 }
2257
2258 fn push_attribute_unchecked(&mut self, attr: &dyn AttributeWrite) {
2259 let offset = self.output.len();
2260 let padded_len = attr.padded_len();
2261 let expected = offset + padded_len;
2262 BigEndian::write_u16(
2263 &mut self.output[2..4],
2264 (expected - MessageHeader::LENGTH) as u16,
2265 );
2266 self.output.resize(expected, 0);
2267 attr.write_into_unchecked(&mut self.output[offset..]);
2268 self.attributes.push(attr.get_type());
2269 }
2270
2271 fn has_attribute(&self, atype: AttributeType) -> bool {
2272 self.attributes.contains(&atype)
2273 }
2274
2275 fn has_any_attribute(&self, atypes: &[AttributeType]) -> Option<AttributeType> {
2276 self.attributes
2277 .iter()
2278 .find(|&typ| atypes.contains(typ))
2279 .cloned()
2280 }
2281}
2282
2283#[derive(Debug, Default)]
2285pub struct MessageWriteMutSlice<'a> {
2286 output: &'a mut [u8],
2287 offset: usize,
2288 attributes: smallvec::SmallVec<[AttributeType; 16]>,
2289}
2290
2291impl<'a> MessageWriteMutSlice<'a> {
2292 pub fn new(data: &'a mut [u8]) -> Self {
2294 Self {
2295 output: data,
2296 offset: 0,
2297 attributes: Default::default(),
2298 }
2299 }
2300}
2301
2302impl core::ops::Deref for MessageWriteMutSlice<'_> {
2303 type Target = [u8];
2304 fn deref(&self) -> &Self::Target {
2305 self.output
2306 }
2307}
2308
2309impl core::ops::DerefMut for MessageWriteMutSlice<'_> {
2310 fn deref_mut(&mut self) -> &mut Self::Target {
2311 self.output
2312 }
2313}
2314
2315impl<'a> MessageWrite for MessageWriteMutSlice<'a> {
2316 type Output = usize;
2317
2318 fn max_size(&self) -> Option<usize> {
2319 Some(self.output.len())
2320 }
2321
2322 fn mut_data(&mut self) -> &mut [u8] {
2323 &mut self.output[..self.offset]
2324 }
2325
2326 fn data(&self) -> &[u8] {
2327 &self.output[..self.offset]
2328 }
2329
2330 fn len(&self) -> usize {
2331 self.offset
2332 }
2333
2334 fn push_data(&mut self, data: &[u8]) {
2335 let len = data.len();
2336 self.output[self.offset..self.offset + len].copy_from_slice(data);
2337 self.offset += len;
2338 }
2339
2340 fn push_attribute_unchecked(&mut self, attr: &dyn AttributeWrite) {
2341 let padded_len = attr.padded_len();
2342 let expected = self.offset + padded_len;
2343 BigEndian::write_u16(
2344 &mut self.output[2..4],
2345 (expected - MessageHeader::LENGTH) as u16,
2346 );
2347 self.attributes.push(attr.get_type());
2348 attr.write_into(&mut self.output[self.offset..self.offset + padded_len])
2349 .unwrap();
2350 self.offset += padded_len;
2351 }
2352
2353 fn finish(self) -> Self::Output {
2354 self.offset
2355 }
2356
2357 fn has_attribute(&self, atype: AttributeType) -> bool {
2358 self.attributes.contains(&atype)
2359 }
2360
2361 fn has_any_attribute(&self, atypes: &[AttributeType]) -> Option<AttributeType> {
2362 self.attributes
2363 .iter()
2364 .find(|&typ| atypes.contains(typ))
2365 .cloned()
2366 }
2367}
2368
2369fn check_attribute_can_fit<O, T: MessageWrite<Output = O> + ?Sized>(
2370 this: &mut T,
2371 attr: &dyn AttributeWrite,
2372) -> Result<usize, StunWriteError> {
2373 let len = attr.padded_len();
2374 let out_data = this.data();
2375 if out_data.len() < MessageHeader::LENGTH {
2376 return Err(StunWriteError::TooSmall {
2377 expected: 20,
2378 actual: out_data.len(),
2379 });
2380 }
2381 let expected = BigEndian::read_u16(&out_data[2..4]) as usize + MessageHeader::LENGTH + len;
2382 if let Some(max) = this.max_size() {
2383 if max < expected {
2384 return Err(StunWriteError::TooSmall {
2385 expected,
2386 actual: max,
2387 });
2388 }
2389 }
2390 Ok(expected)
2391}
2392
2393fn add_message_integrity_unchecked<O, T: MessageWrite<Output = O> + ?Sized>(
2394 this: &mut T,
2395 key: &IntegrityKey,
2396 algorithm: IntegrityAlgorithm,
2397) {
2398 match algorithm {
2401 IntegrityAlgorithm::Sha1 => {
2402 this.push_attribute_unchecked(&MessageIntegrity::new([0; 20]));
2403 let len = this.len();
2404 let data = this.mut_data();
2405 let integrity = MessageIntegrity::compute(&[&data[..len - 24]], key).unwrap();
2406 data[len - 20..].copy_from_slice(&integrity);
2407 }
2408 IntegrityAlgorithm::Sha256 => {
2409 this.push_attribute_unchecked(&MessageIntegritySha256::new(&[0; 32]).unwrap());
2410 let len = this.len();
2411 let data = this.mut_data();
2412 let integrity = MessageIntegritySha256::compute(&[&data[..len - 36]], key).unwrap();
2413 data[len - 32..].copy_from_slice(&integrity);
2414 }
2415 }
2416}
2417
2418fn add_fingerprint_unchecked<O, T: MessageWrite<Output = O> + ?Sized>(this: &mut T) {
2419 this.push_attribute_unchecked(&Fingerprint::new([0; 4]));
2422 let len = this.len();
2423 let data = this.mut_data();
2424 let fingerprint = Fingerprint::compute(&[&data[..len - 8]]);
2425 let fingerprint = Fingerprint::new(fingerprint);
2426 fingerprint.write_into(&mut data[len - 8..]).unwrap();
2427}
2428
2429#[cfg(test)]
2430mod tests {
2431 use alloc::borrow::ToOwned;
2432 use tracing::error;
2433
2434 use super::*;
2435
2436 #[test]
2437 #[should_panic(expected = "Method value is out of range")]
2438 fn method_value_out_of_range() {
2439 let _log = crate::tests::test_init_log();
2440 Method::new(0xf000);
2441 }
2442
2443 #[test]
2444 #[cfg(feature = "std")]
2445 fn method_name() {
2446 let _log = crate::tests::test_init_log();
2447 assert_eq!(BINDING.name(), "BINDING");
2448 let method = Method::new(0x111);
2449 method.add_name("SOME-NAME");
2450 assert_eq!(method.name(), "SOME-NAME");
2451 assert_eq!(Method::new(0x112).name(), "unknown");
2452 }
2453
2454 #[test]
2455 fn msg_type_roundtrip() {
2456 let _log = crate::tests::test_init_log();
2457 for m in 0..0xfff {
2459 let m = Method::new(m);
2460 let classes = vec![
2461 MessageClass::Request,
2462 MessageClass::Indication,
2463 MessageClass::Success,
2464 MessageClass::Error,
2465 ];
2466 for c in classes {
2467 let mtype = MessageType::from_class_method(c, m);
2468 trace!("{mtype}");
2469 assert_eq!(mtype.class(), c);
2470 assert_eq!(mtype.method(), m);
2471 let bytes = mtype.to_bytes();
2472 let ptype = MessageType::from_bytes(&bytes).unwrap();
2473 assert_eq!(mtype, ptype);
2474 }
2475 }
2476 }
2477
2478 #[test]
2479 fn msg_type_not_stun() {
2480 assert!(matches!(
2481 MessageType::from_bytes(&[0xc0, 0x00]),
2482 Err(StunParseError::NotStun)
2483 ));
2484 }
2485
2486 #[test]
2487 fn msg_roundtrip() {
2488 let _log = crate::tests::test_init_log();
2489 for m in (0x009..0x4ff).step_by(0x123) {
2491 let m = Method::new(m);
2492 let classes = vec![
2493 MessageClass::Request,
2494 MessageClass::Indication,
2495 MessageClass::Success,
2496 MessageClass::Error,
2497 ];
2498 for c in classes {
2499 let mtype = MessageType::from_class_method(c, m);
2500 for tid in (0x18..0xff_ffff_ffff_ffff_ffff).step_by(0xfedc_ba98_7654_3210) {
2501 let mut msg = Message::builder(mtype, tid.into(), MessageWriteVec::default());
2502 let attr = RawAttribute::new(1.into(), &[3]);
2503 assert!(msg.add_attribute(&attr).is_ok());
2504 let data = msg.finish();
2505
2506 let msg = Message::from_bytes(&data).unwrap();
2507 let msg_attr = msg.raw_attribute(1.into()).unwrap();
2508 assert_eq!(msg_attr, attr);
2509 assert_eq!(msg.get_type(), mtype);
2510 assert_eq!(msg.transaction_id(), tid.into());
2511 }
2512 }
2513 }
2514 }
2515
2516 #[test]
2517 fn unknown_attributes() {
2518 let _log = crate::tests::test_init_log();
2519 let src = Message::builder_request(BINDING, MessageWriteVec::default()).finish();
2520 let src = Message::from_bytes(&src).unwrap();
2521 let msg =
2522 Message::unknown_attributes(&src, &[Software::TYPE], MessageWriteVec::new()).finish();
2523 let msg = Message::from_bytes(&msg).unwrap();
2524 assert_eq!(msg.transaction_id(), src.transaction_id());
2525 assert_eq!(msg.class(), MessageClass::Error);
2526 assert_eq!(msg.method(), src.method());
2527 let err = msg.attribute::<ErrorCode>().unwrap();
2528 assert_eq!(err.code(), 420);
2529 let unknown_attrs = msg.attribute::<UnknownAttributes>().unwrap();
2530 assert!(unknown_attrs.has_attribute(Software::TYPE));
2531 }
2532
2533 #[test]
2534 fn bad_request() {
2535 let _log = crate::tests::test_init_log();
2536 let src = Message::builder_request(BINDING, MessageWriteVec::new()).finish();
2537 let src = Message::from_bytes(&src).unwrap();
2538 let msg = Message::bad_request(&src, MessageWriteVec::new()).finish();
2539 let msg = Message::from_bytes(&msg).unwrap();
2540 assert_eq!(msg.transaction_id(), src.transaction_id());
2541 assert_eq!(msg.class(), MessageClass::Error);
2542 assert_eq!(msg.method(), src.method());
2543 let err = msg.attribute::<ErrorCode>().unwrap();
2544 assert_eq!(err.code(), 400);
2545 }
2546
2547 #[test]
2548 fn fingerprint() {
2549 let _log = crate::tests::test_init_log();
2550 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2551 let software = Software::new("s").unwrap();
2552 msg.add_attribute(&software).unwrap();
2553 msg.add_fingerprint().unwrap();
2554 let bytes = msg.finish();
2555 let new_msg = Message::from_bytes(&bytes).unwrap();
2557 let (offset, software) = new_msg.attribute_and_offset::<Software>().unwrap();
2558 assert_eq!(software.software(), "s");
2559 assert_eq!(offset, 20);
2560 let (offset, _new_fingerprint) = new_msg.attribute_and_offset::<Fingerprint>().unwrap();
2561 assert_eq!(offset, 28);
2562 }
2563
2564 #[test]
2565 fn integrity() {
2566 let _log = crate::tests::test_init_log();
2567 for algorithm in [IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256] {
2568 let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2569 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2570 let software = Software::new("s").unwrap();
2571 msg.add_attribute(&software).unwrap();
2572 msg.add_message_integrity(&credentials, algorithm).unwrap();
2573 let bytes = msg.finish();
2574 let new_msg = Message::from_bytes(&bytes).unwrap();
2576 new_msg.validate_integrity(&credentials).unwrap();
2577 let (offset, software) = new_msg.attribute_and_offset::<Software>().unwrap();
2578 assert_eq!(software.software(), "s");
2579 assert_eq!(offset, 20);
2580 }
2581 }
2582
2583 #[test]
2584 fn write_into_short_destination() {
2585 let _log = crate::tests::test_init_log();
2586 const LEN: usize = MessageHeader::LENGTH + 8;
2587 let mut data = [0; LEN - 1];
2588 let mut msg = Message::builder_request(BINDING, MessageWriteMutSlice::new(&mut data));
2589 let software = Software::new("s").unwrap();
2590 assert!(
2591 matches!(msg.add_attribute(&software), Err(StunWriteError::TooSmall { expected, actual }) if expected == LEN && actual == LEN - 1)
2592 );
2593 }
2594
2595 #[test]
2596 fn add_duplicate_integrity() {
2597 let _log = crate::tests::test_init_log();
2598 let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2599 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2600 msg.add_message_integrity(&credentials, IntegrityAlgorithm::Sha1)
2601 .unwrap();
2602 assert!(matches!(
2603 msg.add_message_integrity(&credentials, IntegrityAlgorithm::Sha1),
2604 Err(StunWriteError::AttributeExists(MessageIntegrity::TYPE))
2605 ));
2606 msg.add_message_integrity(&credentials, IntegrityAlgorithm::Sha256)
2607 .unwrap();
2608 assert!(matches!(
2609 msg.add_message_integrity(&credentials, IntegrityAlgorithm::Sha256),
2610 Err(StunWriteError::AttributeExists(
2611 MessageIntegritySha256::TYPE
2612 ))
2613 ));
2614 let software = Software::new("s").unwrap();
2615 assert!(matches!(
2616 msg.add_attribute(&software),
2617 Err(StunWriteError::MessageIntegrityExists)
2618 ));
2619 }
2620
2621 #[test]
2622 fn add_sha1_integrity_after_sha256() {
2623 let _log = crate::tests::test_init_log();
2624 let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2625 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2626 msg.add_message_integrity(&credentials, IntegrityAlgorithm::Sha256)
2627 .unwrap();
2628 assert!(matches!(
2629 msg.add_message_integrity(&credentials, IntegrityAlgorithm::Sha1),
2630 Err(StunWriteError::AttributeExists(
2631 MessageIntegritySha256::TYPE
2632 ))
2633 ));
2634 }
2635
2636 #[test]
2637 fn add_attribute_after_integrity() {
2638 let _log = crate::tests::test_init_log();
2639 for algorithm in [IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256] {
2640 let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2641 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2642 msg.add_message_integrity(&credentials, algorithm).unwrap();
2643 let software = Software::new("s").unwrap();
2644 assert!(matches!(
2645 msg.add_attribute(&software),
2646 Err(StunWriteError::MessageIntegrityExists)
2647 ));
2648 }
2649 }
2650
2651 #[test]
2652 fn add_raw_attribute_after_integrity() {
2653 let _log = crate::tests::test_init_log();
2654 for algorithm in [IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256] {
2655 let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2656 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2657 msg.add_message_integrity(&credentials, algorithm).unwrap();
2658 let software = Software::new("s").unwrap();
2659 let raw = software.to_raw();
2660 assert!(matches!(
2661 msg.add_attribute(&raw),
2662 Err(StunWriteError::MessageIntegrityExists)
2663 ));
2664 }
2665 }
2666
2667 #[test]
2668 fn add_integrity_after_fingerprint() {
2669 let _log = crate::tests::test_init_log();
2670 for algorithm in [IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256] {
2671 let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2672 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2673 msg.add_fingerprint().unwrap();
2674 assert!(matches!(
2675 msg.add_message_integrity(&credentials, algorithm),
2676 Err(StunWriteError::FingerprintExists)
2677 ));
2678 }
2679 }
2680
2681 #[test]
2682 fn duplicate_fingerprint() {
2683 let _log = crate::tests::test_init_log();
2684 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2685 msg.add_fingerprint().unwrap();
2686 assert!(matches!(
2687 msg.add_fingerprint(),
2688 Err(StunWriteError::AttributeExists(Fingerprint::TYPE))
2689 ));
2690 }
2691
2692 #[test]
2693 fn parse_invalid_fingerprint() {
2694 let _log = crate::tests::test_init_log();
2695 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2696 msg.add_fingerprint().unwrap();
2697 let mut bytes = msg.finish();
2698 bytes[24] = 0x80;
2699 bytes[25] = 0x80;
2700 bytes[26] = 0x80;
2701 bytes[27] = 0x80;
2702 assert!(matches!(
2703 Message::from_bytes(&bytes),
2704 Err(StunParseError::FingerprintMismatch)
2705 ));
2706 }
2707
2708 #[test]
2709 fn parse_wrong_magic() {
2710 let _log = crate::tests::test_init_log();
2711 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2712 msg.add_fingerprint().unwrap();
2713 let mut bytes = msg.finish();
2714 bytes[4] = 0x80;
2715 assert!(matches!(
2716 Message::from_bytes(&bytes),
2717 Err(StunParseError::NotStun)
2718 ));
2719 }
2720
2721 #[test]
2722 fn parse_attribute_after_integrity() {
2723 let _log = crate::tests::test_init_log();
2724 for algorithm in [IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256] {
2725 let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2726 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2727 msg.add_message_integrity(&credentials, algorithm).unwrap();
2728 let mut bytes = msg.finish();
2729 let software = Software::new("s").unwrap();
2730 let software_bytes = RawAttribute::from(&software).to_bytes();
2731 let software_len = software_bytes.len();
2732 bytes.extend(software_bytes);
2733 bytes[3] += software_len as u8;
2734 let msg = Message::from_bytes(&bytes).unwrap();
2735 assert!(msg.raw_attribute(Software::TYPE).is_none());
2736 }
2737 }
2738
2739 #[test]
2740 fn parse_duplicate_integrity_after_integrity() {
2741 let _log = crate::tests::test_init_log();
2742 for algorithm in [IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256] {
2743 let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2744 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2745 msg.add_message_integrity(&credentials, algorithm).unwrap();
2746 add_message_integrity_unchecked(&mut msg, &credentials.make_key(), algorithm);
2748 let bytes = msg.finish();
2749 let integrity_type = match algorithm {
2750 IntegrityAlgorithm::Sha1 => MessageIntegrity::TYPE,
2751 IntegrityAlgorithm::Sha256 => MessageIntegritySha256::TYPE,
2752 };
2753 let msg = Message::from_bytes(&bytes).unwrap();
2754 msg.nth_raw_attribute(integrity_type, 0).unwrap();
2755 assert!(msg.nth_raw_attribute(integrity_type, 1).is_none());
2756 }
2757 }
2758
2759 #[test]
2760 fn parse_attribute_after_fingerprint() {
2761 let _log = crate::tests::test_init_log();
2762 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2763 msg.add_fingerprint().unwrap();
2764 let mut bytes = msg.finish();
2765 let software = Software::new("s").unwrap();
2766 let software_bytes = RawAttribute::from(&software).to_bytes();
2767 let software_len = software_bytes.len();
2768 bytes.extend(software_bytes);
2769 bytes[3] += software_len as u8;
2770 let msg = Message::from_bytes(&bytes).unwrap();
2771 assert!(msg.raw_attribute(Fingerprint::TYPE).is_some());
2772 assert!(msg.raw_attribute(Software::TYPE).is_none());
2773 }
2774
2775 #[test]
2776 fn parse_duplicate_fingerprint_after_fingerprint() {
2777 let _log = crate::tests::test_init_log();
2778 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2779 msg.add_fingerprint().unwrap();
2780 add_fingerprint_unchecked(&mut msg);
2781 let bytes = msg.finish();
2782 let msg = Message::from_bytes(&bytes).unwrap();
2783 assert!(msg.nth_raw_attribute(Fingerprint::TYPE, 0).is_some());
2784 assert!(msg.nth_raw_attribute(Fingerprint::TYPE, 1).is_none());
2785 }
2786
2787 #[test]
2788 fn add_attribute_after_fingerprint() {
2789 let _log = crate::tests::test_init_log();
2790 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2791 msg.add_fingerprint().unwrap();
2792 let software = Software::new("s").unwrap();
2793 assert!(matches!(
2794 msg.add_attribute(&software),
2795 Err(StunWriteError::FingerprintExists)
2796 ));
2797 }
2798
2799 #[test]
2800 fn add_raw_attribute_after_fingerprint() {
2801 let _log = crate::tests::test_init_log();
2802 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2803 msg.add_fingerprint().unwrap();
2804 let software = Software::new("s").unwrap();
2805 let raw = software.to_raw();
2806 assert!(matches!(
2807 msg.add_attribute(&raw),
2808 Err(StunWriteError::FingerprintExists)
2809 ));
2810 }
2811
2812 #[test]
2813 fn parse_truncated_message_header() {
2814 let _log = crate::tests::test_init_log();
2815 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2816 msg.add_fingerprint().unwrap();
2817 let bytes = msg.finish();
2818 assert!(matches!(
2819 Message::from_bytes(&bytes[..8]),
2820 Err(StunParseError::Truncated {
2821 expected: 20,
2822 actual: 8
2823 })
2824 ));
2825 }
2826
2827 #[test]
2828 fn parse_truncated_message() {
2829 let _log = crate::tests::test_init_log();
2830 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2831 msg.add_fingerprint().unwrap();
2832 let bytes = msg.finish();
2833 assert!(matches!(
2834 Message::from_bytes(&bytes[..24]),
2835 Err(StunParseError::Truncated {
2836 expected: 28,
2837 actual: 24
2838 })
2839 ));
2840 }
2841
2842 #[test]
2843 fn parse_truncated_message_attribute() {
2844 let _log = crate::tests::test_init_log();
2845 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2846 msg.add_fingerprint().unwrap();
2847 let mut bytes = msg.finish();
2848 bytes[3] = 4;
2850 assert!(matches!(
2851 Message::from_bytes(&bytes[..24]),
2852 Err(StunParseError::Truncated {
2853 expected: 28,
2854 actual: 24
2855 })
2856 ));
2857 }
2858
2859 #[test]
2860 fn parse_attribute_extends_past_message_end() {
2861 let _log = crate::tests::test_init_log();
2862 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2863 msg.add_attribute(&Software::new("a").unwrap()).unwrap();
2864 msg[23] += 1;
2865 let mut bytes = msg.finish();
2866 bytes[3] -= 1;
2867 error!("{bytes:x?}");
2868 error!("{:?}", Message::from_bytes(&bytes[..27]));
2869 assert!(matches!(
2870 Message::from_bytes(&bytes[..27]),
2871 Err(StunParseError::Truncated {
2872 expected: 28,
2873 actual: 27
2874 })
2875 ));
2876 }
2877
2878 #[test]
2879 fn valid_attributes() {
2880 let _log = crate::tests::test_init_log();
2881 let mut src = Message::builder_request(BINDING, MessageWriteVec::new());
2882 let username = Username::new("123").unwrap();
2883 src.add_attribute(&username).unwrap();
2884 let nonce = Nonce::new("nonce").unwrap();
2885 src.add_attribute(&nonce).unwrap();
2886 let src = src.finish();
2887 let src = Message::from_bytes(&src).unwrap();
2888
2889 let res = Message::check_attribute_types(
2891 &src,
2892 &[Username::TYPE, Nonce::TYPE],
2893 &[Username::TYPE],
2894 MessageWriteVec::new(),
2895 );
2896 assert!(res.is_none());
2897
2898 let res = Message::check_attribute_types(
2900 &src,
2901 &[Username::TYPE, Nonce::TYPE],
2902 &[Fingerprint::TYPE],
2903 MessageWriteVec::new(),
2904 );
2905 assert!(res.is_some());
2906 let res = res.unwrap();
2907 let res = res.finish();
2908 let res = Message::from_bytes(&res).unwrap();
2909 assert!(res.has_class(MessageClass::Error));
2910 assert!(res.has_method(src.method()));
2911 let err = res.attribute::<ErrorCode>().unwrap();
2912 assert_eq!(err.code(), 400);
2913
2914 let res =
2916 Message::check_attribute_types(&src, &[Username::TYPE], &[], MessageWriteVec::new());
2917 assert!(res.is_some());
2918 let res = res.unwrap();
2919 let data = res.finish();
2920 let res = Message::from_bytes(&data).unwrap();
2921 assert!(res.has_class(MessageClass::Error));
2922 assert!(res.has_method(src.method()));
2923 let err = res.attribute::<ErrorCode>().unwrap();
2924 assert_eq!(err.code(), 420);
2925 let unknown = res.attribute::<UnknownAttributes>().unwrap();
2926 assert!(unknown.has_attribute(Nonce::TYPE));
2927 }
2928
2929 #[test]
2930 fn attributes_iter_with_short_data() {
2931 let _log = crate::tests::test_init_log();
2932 assert_eq!(
2933 MessageAttributesIter::new(&[0x0, 0x1, 0x2, 0x3, 0x4]).next(),
2934 None
2935 );
2936 assert_eq!(
2937 MessageAttributesIter::new(&[
2938 0x0, 0x1, 0x2, 0x3, 0x21, 0x12, 0xa4, 0x42, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf,
2939 0x10, 0x11, 0x12, 0x13, 0x14,
2940 ])
2941 .next(),
2942 None
2943 );
2944 }
2945
2946 #[test]
2947 fn attributes_iter_software_after_fingerprint_ignored() {
2948 let _log = crate::tests::test_init_log();
2949 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2950 msg.add_fingerprint().unwrap();
2951 let mut bytes = msg.finish();
2952 let software = Software::new("s").unwrap();
2953 let software_bytes = RawAttribute::from(&software).to_bytes();
2954 let software_len = software_bytes.len();
2955 bytes.extend(software_bytes);
2956 bytes[3] += software_len as u8;
2957 let mut it = MessageAttributesIter::new(&bytes);
2958 let (_offset, fingerprint) = it.next().unwrap();
2959 assert_eq!(fingerprint.get_type(), Fingerprint::TYPE);
2960 assert_eq!(it.next(), None);
2961 }
2962
2963 #[test]
2964 fn attributes_iter_message_integrities_fingerprint() {
2965 let _log = crate::tests::test_init_log();
2966 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2967 let credentials = ShortTermCredentials::new("pass".to_owned());
2968 msg.add_message_integrity(&credentials.clone().into(), IntegrityAlgorithm::Sha1)
2969 .unwrap();
2970 msg.add_message_integrity(&credentials.clone().into(), IntegrityAlgorithm::Sha256)
2971 .unwrap();
2972 msg.add_fingerprint().unwrap();
2973 let mut bytes = msg.finish();
2974 let software = Software::new("s").unwrap();
2975 let software_bytes = RawAttribute::from(&software).to_bytes();
2976 let software_len = software_bytes.len();
2977 bytes.extend(software_bytes);
2978 bytes[3] += software_len as u8;
2979 let mut it = MessageAttributesIter::new(&bytes);
2980 assert_eq!(it.next().unwrap().1.get_type(), MessageIntegrity::TYPE);
2981 assert_eq!(
2982 it.next().unwrap().1.get_type(),
2983 MessageIntegritySha256::TYPE
2984 );
2985 assert_eq!(it.next().unwrap().1.get_type(), Fingerprint::TYPE);
2986 assert_eq!(it.next(), None);
2987 }
2988
2989 #[test]
2990 fn attributes_iter_fingerprint_after_fingerprint_ignored() {
2991 let _log = crate::tests::test_init_log();
2992 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2993 msg.add_fingerprint().unwrap();
2994 let mut bytes = msg.finish();
2995 let fingerprint = Fingerprint::new([bytes[bytes.len() - 1].wrapping_sub(1); 4]);
2996 let fingerprint_bytes = RawAttribute::from(&fingerprint).to_bytes();
2997 let fingerprint_len = fingerprint_bytes.len();
2998 bytes.extend(fingerprint_bytes);
2999 bytes[3] += fingerprint_len as u8;
3000 let mut it = MessageAttributesIter::new(&bytes);
3001 let (_offset, fingerprint) = it.next().unwrap();
3002 assert_eq!(fingerprint.get_type(), Fingerprint::TYPE);
3003 assert_eq!(it.next(), None);
3004 }
3005
3006 #[test]
3007 fn write_vec_state() {
3008 let _log = crate::tests::test_init_log();
3009 let mut src = Message::builder_request(BINDING, MessageWriteVec::with_capacity(0x10));
3010 assert_eq!(src.len(), 20);
3011 assert_eq!(src[4], 0x21);
3012 let username = Username::new("123").unwrap();
3013 src.add_attribute(&username).unwrap();
3014 let nonce = Nonce::new("nonce").unwrap();
3015 src.add_attribute(&nonce).unwrap();
3016
3017 assert!(src.has_attribute(Username::TYPE));
3018 assert!(src.has_attribute(Nonce::TYPE));
3019 assert_eq!(
3020 src.has_any_attribute(&[Username::TYPE, Nonce::TYPE]),
3021 Some(Username::TYPE)
3022 );
3023 assert_eq!(
3024 src.has_any_attribute(&[Nonce::TYPE, Username::TYPE]),
3025 Some(Username::TYPE)
3026 );
3027 assert!(src.has_class(MessageClass::Request));
3028 assert!(!src.is_response());
3029 assert!(src.has_method(BINDING));
3030 assert!(!src.has_method(Method::new(0x111)));
3031 }
3032
3033 #[test]
3034 fn write_mut_slice_success() {
3035 let _log = crate::tests::test_init_log();
3036 let mut data = [0; 64];
3037 let mut src = Message::builder_request(BINDING, MessageWriteMutSlice::new(&mut data));
3038 assert_eq!(src.len(), 20);
3039 assert_eq!(src[4], 0x21);
3040 let username = Username::new("123").unwrap();
3041 src.add_attribute(&username).unwrap();
3042 let nonce = Nonce::new("nonce").unwrap();
3043 src.add_attribute(&nonce).unwrap();
3044 assert!(src.has_attribute(Username::TYPE));
3045 assert!(!src.has_attribute(Software::TYPE));
3046 assert_eq!(src.finish(), 40);
3047 let msg = Message::from_bytes(&data[..40]).unwrap();
3048 let u2 = msg.attribute::<Username>().unwrap();
3049 assert_eq!(u2.username(), "123");
3050 let n2 = msg.attribute::<Nonce>().unwrap();
3051 assert_eq!(n2.nonce(), "nonce");
3052 }
3053
3054 #[test]
3055 fn write_mut_slice_too_short() {
3056 let _log = crate::tests::test_init_log();
3057 let mut data = [0; 20];
3058 let mut src = Message::builder_request(BINDING, MessageWriteMutSlice::new(&mut data));
3059 assert!(matches!(
3060 src.add_attribute(&Username::new("123").unwrap()),
3061 Err(StunWriteError::TooSmall {
3062 expected: 28,
3063 actual: 20
3064 })
3065 ));
3066 }
3067
3068 #[test]
3069 #[should_panic(expected = "created from a non-request message")]
3070 fn builder_success_panic() {
3071 let _log = crate::tests::test_init_log();
3072 let msg = Message::builder(
3073 MessageType::from_class_method(MessageClass::Indication, BINDING),
3074 TransactionId::generate(),
3075 MessageWriteVec::new(),
3076 )
3077 .finish();
3078 let msg = Message::from_bytes(&msg).unwrap();
3079 let _builder = Message::builder_success(&msg, MessageWriteVec::new());
3080 }
3081
3082 #[test]
3083 #[should_panic(expected = "created from a non-request message")]
3084 fn builder_error_panic() {
3085 let _log = crate::tests::test_init_log();
3086 let msg = Message::builder(
3087 MessageType::from_class_method(MessageClass::Indication, BINDING),
3088 TransactionId::generate(),
3089 MessageWriteVec::new(),
3090 )
3091 .finish();
3092 let msg = Message::from_bytes(&msg).unwrap();
3093 let _builder = Message::builder_error(&msg, MessageWriteVec::new());
3094 }
3095
3096 #[test]
3097 #[should_panic(expected = "Use add_message_integrity() instead")]
3098 fn builder_add_attribute_integrity_panic() {
3099 let _log = crate::tests::test_init_log();
3100 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3101 let hmac = [2; 20];
3102 let integrity = MessageIntegrity::new(hmac);
3103 msg.add_attribute(&integrity).unwrap();
3104 }
3105
3106 #[test]
3107 #[should_panic(expected = "Use add_message_integrity() instead")]
3108 fn builder_add_raw_attribute_integrity_panic() {
3109 let _log = crate::tests::test_init_log();
3110 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3111 let hmac = [2; 20];
3112 let integrity = MessageIntegrity::new(hmac);
3113 let raw = integrity.to_raw();
3114 msg.add_attribute(&raw).unwrap();
3115 }
3116
3117 #[test]
3118 #[should_panic(expected = "Use add_message_integrity() instead")]
3119 fn builder_add_attribute_integrity_sha256_panic() {
3120 let _log = crate::tests::test_init_log();
3121 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3122 let hmac = [2; 16];
3123 let integrity = MessageIntegritySha256::new(&hmac).unwrap();
3124 msg.add_attribute(&integrity).unwrap();
3125 }
3126
3127 #[test]
3128 #[should_panic(expected = "Use add_message_integrity() instead")]
3129 fn builder_add_raw_attribute_integrity_sha256_panic() {
3130 let _log = crate::tests::test_init_log();
3131 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3132 let hmac = [2; 16];
3133 let integrity = MessageIntegritySha256::new(&hmac).unwrap();
3134 let raw = integrity.to_raw();
3135 msg.add_attribute(&raw).unwrap();
3136 }
3137
3138 #[test]
3139 #[should_panic(expected = "Use add_fingerprint() instead")]
3140 fn builder_add_attribute_fingerprint_panic() {
3141 let _log = crate::tests::test_init_log();
3142 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3143 let fingerprint = [2; 4];
3144 let fingerprint = Fingerprint::new(fingerprint);
3145 msg.add_attribute(&fingerprint).unwrap();
3146 }
3147
3148 #[test]
3149 #[should_panic(expected = "Use add_fingerprint() instead")]
3150 fn builder_add_raw_attribute_fingerprint_panic() {
3151 let _log = crate::tests::test_init_log();
3152 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3153 let fingerprint = [2; 4];
3154 let fingerprint = Fingerprint::new(fingerprint);
3155 let raw = fingerprint.to_raw();
3156 msg.add_attribute(&raw).unwrap();
3157 }
3158
3159 #[test]
3160 fn rfc5769_vector1() {
3161 let _log = crate::tests::test_init_log();
3162 let data = vec![
3164 0x00, 0x01, 0x00, 0x58, 0x21, 0x12, 0xa4, 0x42, 0xb7, 0xe7, 0xa7, 0x01, 0xbc, 0x34, 0xd6, 0x86, 0xfa, 0x87, 0xdf, 0xae, 0x80, 0x22, 0x00, 0x10, 0x53, 0x54, 0x55, 0x4e, 0x20, 0x74, 0x65, 0x73, 0x74, 0x20, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x00, 0x24, 0x00, 0x04, 0x6e, 0x00, 0x01, 0xff, 0x80, 0x29, 0x00, 0x08, 0x93, 0x2f, 0xf9, 0xb1, 0x51, 0x26, 0x3b, 0x36, 0x00, 0x06, 0x00, 0x09, 0x65, 0x76, 0x74, 0x6a, 0x3a, 0x68, 0x36, 0x76, 0x59, 0x20, 0x20, 0x20, 0x00, 0x08, 0x00, 0x14, 0x9a, 0xea, 0xa7, 0x0c, 0xbf, 0xd8, 0xcb, 0x56, 0x78, 0x1e, 0xf2, 0xb5, 0xb2, 0xd3, 0xf2, 0x49, 0xc1, 0xb5, 0x71, 0xa2, 0x80, 0x28, 0x00, 0x04, 0xe5, 0x7a, 0x3b, 0xcf, ];
3192 let msg = Message::from_bytes(&data).unwrap();
3193 assert!(msg.has_class(MessageClass::Request));
3194 assert!(msg.has_method(BINDING));
3195 assert_eq!(msg.transaction_id(), 0xb7e7_a701_bc34_d686_fa87_dfae.into());
3196
3197 let mut builder = Message::builder(
3198 MessageType::from_class_method(MessageClass::Request, BINDING),
3199 msg.transaction_id(),
3200 MessageWriteVec::new(),
3201 );
3202
3203 assert!(msg.has_attribute(Software::TYPE));
3205 let raw = msg.raw_attribute(Software::TYPE).unwrap();
3206 assert!(Software::try_from(&raw).is_ok());
3207 let software = Software::try_from(&raw).unwrap();
3208 assert_eq!(software.software(), "STUN test client");
3209 builder.add_attribute(&software).unwrap();
3210
3211 builder
3213 .add_attribute(&RawAttribute::new(0x24.into(), &[0x6e, 0x00, 0x01, 0xff]))
3214 .unwrap();
3215
3216 builder
3218 .add_attribute(&RawAttribute::new(
3219 0x8029.into(),
3220 &[0x93, 0x2f, 0xf9, 0xb1, 0x51, 0x26, 0x3b, 0x36],
3221 ))
3222 .unwrap();
3223
3224 assert!(msg.has_attribute(Username::TYPE));
3226 let raw = msg.raw_attribute(Username::TYPE).unwrap();
3227 assert!(Username::try_from(&raw).is_ok());
3228 let username = Username::try_from(&raw).unwrap();
3229 assert_eq!(username.username(), "evtj:h6vY");
3230 builder.add_attribute(&username).unwrap();
3231
3232 let credentials = MessageIntegrityCredentials::ShortTerm(ShortTermCredentials {
3234 password: "VOkJxbRl1RmTxUk/WvJxBt".to_owned(),
3235 });
3236 assert!(matches!(
3237 msg.validate_integrity(&credentials),
3238 Ok(IntegrityAlgorithm::Sha1)
3239 ));
3240 builder
3241 .add_message_integrity(&credentials, IntegrityAlgorithm::Sha1)
3242 .unwrap();
3243
3244 assert!(msg.has_attribute(Fingerprint::TYPE));
3246 builder.add_fingerprint().unwrap();
3247
3248 let mut msg_data = builder.finish();
3250 msg_data[73] = 0x20;
3252 msg_data[74] = 0x20;
3253 msg_data[75] = 0x20;
3254 assert_eq!(msg_data[..80], data[..80]);
3257 }
3258
3259 #[test]
3260 fn rfc5769_vector2() {
3261 let _log = crate::tests::test_init_log();
3262 let data = vec![
3264 0x01, 0x01, 0x00, 0x3c, 0x21, 0x12, 0xa4, 0x42, 0xb7, 0xe7, 0xa7, 0x01, 0xbc, 0x34, 0xd6, 0x86, 0xfa, 0x87, 0xdf, 0xae, 0x80, 0x22, 0x00, 0x0b, 0x74, 0x65, 0x73, 0x74, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x20, 0x00, 0x20, 0x00, 0x08, 0x00, 0x01, 0xa1, 0x47, 0xe1, 0x12, 0xa6, 0x43, 0x00, 0x08, 0x00, 0x14, 0x2b, 0x91, 0xf5, 0x99, 0xfd, 0x9e, 0x90, 0xc3, 0x8c, 0x74, 0x89, 0xf9, 0x2a, 0xf9, 0xba, 0x53, 0xf0, 0x6b, 0xe7, 0xd7, 0x80, 0x28, 0x00, 0x04, 0xc0, 0x7d, 0x4c, 0x96, ];
3285
3286 let msg = Message::from_bytes(&data).unwrap();
3287 assert!(msg.has_class(MessageClass::Success));
3288 assert!(msg.has_method(BINDING));
3289 assert_eq!(msg.transaction_id(), 0xb7e7_a701_bc34_d686_fa87_dfae.into());
3290 let mut builder = Message::builder(
3291 MessageType::from_class_method(MessageClass::Success, BINDING),
3292 msg.transaction_id(),
3293 MessageWriteVec::new(),
3294 );
3295
3296 assert!(msg.has_attribute(Software::TYPE));
3298 let raw = msg.raw_attribute(Software::TYPE).unwrap();
3299 assert!(Software::try_from(&raw).is_ok());
3300 let software = Software::try_from(&raw).unwrap();
3301 assert_eq!(software.software(), "test vector");
3302 builder.add_attribute(&software).unwrap();
3303
3304 assert!(msg.has_attribute(XorMappedAddress::TYPE));
3306 let raw = msg.raw_attribute(XorMappedAddress::TYPE).unwrap();
3307 assert!(XorMappedAddress::try_from(&raw).is_ok());
3308 let xor_mapped_addres = XorMappedAddress::try_from(&raw).unwrap();
3309 assert_eq!(
3310 xor_mapped_addres.addr(msg.transaction_id()),
3311 "192.0.2.1:32853".parse().unwrap()
3312 );
3313 builder.add_attribute(&xor_mapped_addres).unwrap();
3314
3315 let credentials = MessageIntegrityCredentials::ShortTerm(ShortTermCredentials {
3317 password: "VOkJxbRl1RmTxUk/WvJxBt".to_owned(),
3318 });
3319 let ret = msg.validate_integrity(&credentials);
3320 warn!("{:?}", ret);
3321 assert!(matches!(ret, Ok(IntegrityAlgorithm::Sha1)));
3322 builder
3323 .add_message_integrity(&credentials, IntegrityAlgorithm::Sha1)
3324 .unwrap();
3325
3326 assert!(msg.has_attribute(Fingerprint::TYPE));
3328 builder.add_fingerprint().unwrap();
3329
3330 let mut msg_data = builder.finish();
3332 msg_data[35] = 0x20;
3334 assert_eq!(msg_data[..52], data[..52]);
3335 }
3336
3337 #[test]
3338 fn rfc5769_vector3() {
3339 let _log = crate::tests::test_init_log();
3340 let data = vec![
3342 0x01, 0x01, 0x00, 0x48, 0x21, 0x12, 0xa4, 0x42, 0xb7, 0xe7, 0xa7, 0x01, 0xbc, 0x34, 0xd6, 0x86, 0xfa, 0x87, 0xdf, 0xae, 0x80, 0x22, 0x00, 0x0b, 0x74, 0x65, 0x73, 0x74, 0x20, 0x76, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x20, 0x00, 0x20, 0x00, 0x14, 0x00, 0x02, 0xa1, 0x47, 0x01, 0x13, 0xa9, 0xfa, 0xa5, 0xd3, 0xf1, 0x79, 0xbc, 0x25, 0xf4, 0xb5, 0xbe, 0xd2, 0xb9, 0xd9, 0x00, 0x08, 0x00, 0x14, 0xa3, 0x82, 0x95, 0x4e, 0x4b, 0xe6, 0x7b, 0xf1, 0x17, 0x84, 0xc9, 0x7c, 0x82, 0x92, 0xc2, 0x75, 0xbf, 0xe3, 0xed, 0x41, 0x80, 0x28, 0x00, 0x04, 0xc8, 0xfb, 0x0b, 0x4c, ];
3366
3367 let msg = Message::from_bytes(&data).unwrap();
3368 assert!(msg.has_class(MessageClass::Success));
3369 assert!(msg.has_method(BINDING));
3370 assert_eq!(msg.transaction_id(), 0xb7e7_a701_bc34_d686_fa87_dfae.into());
3371 let mut builder = Message::builder(
3372 MessageType::from_class_method(MessageClass::Success, BINDING),
3373 msg.transaction_id(),
3374 MessageWriteVec::new(),
3375 );
3376
3377 assert!(msg.has_attribute(Software::TYPE));
3379 let raw = msg.raw_attribute(Software::TYPE).unwrap();
3380 assert!(Software::try_from(&raw).is_ok());
3381 let software = Software::try_from(&raw).unwrap();
3382 assert_eq!(software.software(), "test vector");
3383 builder.add_attribute(&software).unwrap();
3384
3385 assert!(msg.has_attribute(XorMappedAddress::TYPE));
3387 let raw = msg.raw_attribute(XorMappedAddress::TYPE).unwrap();
3388 assert!(XorMappedAddress::try_from(&raw).is_ok());
3389 let xor_mapped_addres = XorMappedAddress::try_from(&raw).unwrap();
3390 assert_eq!(
3391 xor_mapped_addres.addr(msg.transaction_id()),
3392 "[2001:db8:1234:5678:11:2233:4455:6677]:32853"
3393 .parse()
3394 .unwrap()
3395 );
3396 builder.add_attribute(&xor_mapped_addres).unwrap();
3397
3398 let credentials = MessageIntegrityCredentials::ShortTerm(ShortTermCredentials {
3400 password: "VOkJxbRl1RmTxUk/WvJxBt".to_owned(),
3401 });
3402 assert!(matches!(
3403 msg.validate_integrity(&credentials),
3404 Ok(IntegrityAlgorithm::Sha1)
3405 ));
3406 builder
3407 .add_message_integrity(&credentials, IntegrityAlgorithm::Sha1)
3408 .unwrap();
3409
3410 assert!(msg.has_attribute(Fingerprint::TYPE));
3412 builder.add_fingerprint().unwrap();
3413
3414 let mut msg_data = builder.finish();
3416 msg_data[35] = 0x20;
3418 assert_eq!(msg_data[..64], data[..64]);
3419 }
3420
3421 #[test]
3422 fn rfc5769_vector4() {
3423 let _log = crate::tests::test_init_log();
3424 let data = vec![
3426 0x00, 0x01, 0x00, 0x60, 0x21, 0x12, 0xa4, 0x42, 0x78, 0xad, 0x34, 0x33, 0xc6, 0xad, 0x72, 0xc0, 0x29, 0xda, 0x41, 0x2e, 0x00, 0x06, 0x00, 0x12, 0xe3, 0x83, 0x9e, 0xe3, 0x83, 0x88, 0xe3, 0x83, 0xaa, 0xe3, 0x83, 0x83, 0xe3, 0x82, 0xaf, 0xe3, 0x82, 0xb9, 0x00, 0x00, 0x00, 0x15, 0x00, 0x1c, 0x66, 0x2f, 0x2f, 0x34, 0x39, 0x39, 0x6b, 0x39, 0x35, 0x34, 0x64, 0x36, 0x4f, 0x4c, 0x33, 0x34, 0x6f, 0x4c, 0x39, 0x46, 0x53, 0x54, 0x76, 0x79, 0x36, 0x34, 0x73, 0x41, 0x00, 0x14, 0x00, 0x0b, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x00, 0x00, 0x08, 0x00, 0x14, 0xf6, 0x70, 0x24, 0x65, 0x6d, 0xd6, 0x4a, 0x3e, 0x02, 0xb8, 0xe0, 0x71, 0x2e, 0x85, 0xc9, 0xa2, 0x8c, 0xa8, 0x96, 0x66, ];
3456
3457 let msg = Message::from_bytes(&data).unwrap();
3458 assert!(msg.has_class(MessageClass::Request));
3459 assert!(msg.has_method(BINDING));
3460 assert_eq!(msg.transaction_id(), 0x78ad_3433_c6ad_72c0_29da_412e.into());
3461 let mut builder = Message::builder(
3462 MessageType::from_class_method(MessageClass::Request, BINDING),
3463 msg.transaction_id(),
3464 MessageWriteVec::new(),
3465 );
3466
3467 let long_term = LongTermCredentials {
3468 username: "\u{30DE}\u{30C8}\u{30EA}\u{30C3}\u{30AF}\u{30B9}".to_owned(),
3469 password: "The\u{00AD}M\u{00AA}tr\u{2168}".to_owned(),
3470 realm: "example.org".to_owned(),
3471 };
3472 assert!(msg.has_attribute(Username::TYPE));
3474 let raw = msg.raw_attribute(Username::TYPE).unwrap();
3475 assert!(Username::try_from(&raw).is_ok());
3476 let username = Username::try_from(&raw).unwrap();
3477 assert_eq!(username.username(), &long_term.username);
3478 builder.add_attribute(&username).unwrap();
3479
3480 let expected_nonce = "f//499k954d6OL34oL9FSTvy64sA";
3482 assert!(msg.has_attribute(Nonce::TYPE));
3483 let raw = msg.raw_attribute(Nonce::TYPE).unwrap();
3484 assert!(Nonce::try_from(&raw).is_ok());
3485 let nonce = Nonce::try_from(&raw).unwrap();
3486 assert_eq!(nonce.nonce(), expected_nonce);
3487 builder.add_attribute(&nonce).unwrap();
3488
3489 assert!(msg.has_attribute(Realm::TYPE));
3491 let raw = msg.raw_attribute(Realm::TYPE).unwrap();
3492 assert!(Realm::try_from(&raw).is_ok());
3493 let realm = Realm::try_from(&raw).unwrap();
3494 assert_eq!(realm.realm(), long_term.realm());
3495 builder.add_attribute(&realm).unwrap();
3496
3497 assert_eq!(builder.finish()[4..], data[4..92]);
3505 }
3506
3507 #[test]
3508 fn rfc8489_vector1() {
3509 let _log = crate::tests::test_init_log();
3510 let data = vec![
3513 0x00, 0x01, 0x00, 0x90, 0x21, 0x12, 0xa4, 0x42, 0x78, 0xad, 0x34, 0x33, 0xc6, 0xad, 0x72, 0xc0, 0x29, 0xda, 0x41, 0x2e, 0x00, 0x1e, 0x00, 0x20, 0x4a, 0x3c, 0xf3, 0x8f, 0xef, 0x69, 0x92, 0xbd, 0xa9, 0x52, 0xc6, 0x78, 0x04, 0x17, 0xda, 0x0f, 0x24, 0x81, 0x94, 0x15, 0x56, 0x9e, 0x60, 0xb2, 0x05, 0xc4, 0x6e, 0x41, 0x40, 0x7f, 0x17, 0x04, 0x00, 0x15, 0x00, 0x29, 0x6f, 0x62, 0x4d, 0x61, 0x74, 0x4a, 0x6f, 0x73, 0x32, 0x41, 0x41, 0x41, 0x43, 0x66, 0x2f, 0x2f, 0x34, 0x39, 0x39, 0x6b, 0x39, 0x35, 0x34, 0x64, 0x36, 0x4f, 0x4c, 0x33, 0x34, 0x6f, 0x4c, 0x39, 0x46, 0x53, 0x54, 0x76, 0x79, 0x36, 0x34, 0x73, 0x41, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x0b, 0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x6f, 0x72, 0x67, 0x00, 0x00, 0x1d, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x20, 0xb5, 0xc7, 0xbf, 0x00, 0x5b, 0x6c, 0x52, 0xa2, 0x1c, 0x51, 0xc5, 0xe8, 0x92, 0xf8, 0x19, 0x24, 0x13, 0x62, 0x96, 0xcb, 0x92, 0x7c, 0x43, 0x14, 0x93, 0x09, 0x27, 0x8c, 0xc6, 0x51, 0x8e, 0x65, ];
3555
3556 let msg = Message::from_bytes(&data).unwrap();
3557 assert!(msg.has_class(MessageClass::Request));
3558 assert!(msg.has_method(BINDING));
3559 assert_eq!(msg.transaction_id(), 0x78ad_3433_c6ad_72c0_29da_412e.into());
3560 let mut builder = Message::builder(
3561 MessageType::from_class_method(MessageClass::Success, BINDING),
3562 msg.transaction_id(),
3563 MessageWriteVec::new(),
3564 );
3565
3566 let long_term = LongTermCredentials {
3567 username: "\u{30DE}\u{30C8}\u{30EA}\u{30C3}\u{30AF}\u{30B9}".to_owned(),
3568 password: "The\u{00AD}M\u{00AA}tr\u{2168}".to_owned(),
3569 realm: "example.org".to_owned(),
3570 };
3571 assert!(msg.has_attribute(Userhash::TYPE));
3573 let raw = msg.raw_attribute(Userhash::TYPE).unwrap();
3574 assert!(Userhash::try_from(&raw).is_ok());
3575 let userhash = Userhash::try_from(&raw).unwrap();
3576 builder.add_attribute(&userhash).unwrap();
3577
3578 let expected_nonce = "obMatJos2AAACf//499k954d6OL34oL9FSTvy64sA";
3580 assert!(msg.has_attribute(Nonce::TYPE));
3581 let raw = msg.raw_attribute(Nonce::TYPE).unwrap();
3582 assert!(Nonce::try_from(&raw).is_ok());
3583 let nonce = Nonce::try_from(&raw).unwrap();
3584 assert_eq!(nonce.nonce(), expected_nonce);
3585 builder.add_attribute(&nonce).unwrap();
3586
3587 assert!(msg.has_attribute(Realm::TYPE));
3589 let raw = msg.raw_attribute(Realm::TYPE).unwrap();
3590 assert!(Realm::try_from(&raw).is_ok());
3591 let realm = Realm::try_from(&raw).unwrap();
3592 assert_eq!(realm.realm(), long_term.realm);
3593 builder.add_attribute(&realm).unwrap();
3594
3595 assert!(msg.has_attribute(PasswordAlgorithm::TYPE));
3597 let raw = msg.raw_attribute(PasswordAlgorithm::TYPE).unwrap();
3598 assert!(PasswordAlgorithm::try_from(&raw).is_ok());
3599 let algo = PasswordAlgorithm::try_from(&raw).unwrap();
3600 assert_eq!(algo.algorithm(), PasswordAlgorithmValue::SHA256);
3601 builder.add_attribute(&algo).unwrap();
3602
3603 assert_eq!(builder.finish()[4..], data[4..128]);
3611 }
3612}