1#[cfg(feature = "std")]
90use alloc::collections::BTreeMap;
91use alloc::string::String;
92use alloc::sync::Arc;
93use alloc::vec;
94use alloc::vec::Vec;
95use core::convert::TryFrom;
96#[cfg(feature = "std")]
97use std::sync::{Mutex, OnceLock};
98
99use byteorder::{BigEndian, ByteOrder};
100
101use crate::attribute::*;
102
103use tracing::{debug, trace, warn};
104
105use hmac::digest::core_api::CoreWrapper;
106use hmac::digest::CtOutput;
107use hmac::HmacCore;
108
109pub const MAGIC_COOKIE: u32 = 0x2112A442;
111
112#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
114pub struct Method(u16);
115
116impl core::fmt::Display for Method {
117 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
118 write!(f, "{}({:#x}: {})", self.0, self.0, self.name())
119 }
120}
121
122#[cfg(feature = "std")]
123static METHOD_NAME_MAP: OnceLock<Mutex<BTreeMap<Method, &'static str>>> = OnceLock::new();
124
125impl Method {
126 #[cfg(feature = "std")]
128 pub fn add_name(self, name: &'static str) {
129 let mut mnames = METHOD_NAME_MAP
130 .get_or_init(Default::default)
131 .lock()
132 .unwrap();
133 mnames.insert(self, name);
134 }
135
136 pub const fn new(val: u16) -> Self {
148 if val >= 0xf000 {
149 panic!("Method value is out of range!");
150 }
151 Self(val)
152 }
153
154 pub fn value(&self) -> u16 {
164 self.0
165 }
166
167 pub fn name(self) -> &'static str {
175 match self {
176 BINDING => "BINDING",
177 _ => {
178 #[cfg(feature = "std")]
179 {
180 let mnames = METHOD_NAME_MAP
181 .get_or_init(Default::default)
182 .lock()
183 .unwrap();
184 if let Some(name) = mnames.get(&self) {
185 return name;
186 }
187 }
188 "unknown"
189 }
190 }
191 }
192}
193
194pub const BINDING: Method = Method::new(0x0001);
197
198#[derive(Debug, thiserror::Error, Clone, Copy, PartialEq, Eq)]
200#[non_exhaustive]
201pub enum StunParseError {
202 #[error("The provided data is not a STUN message")]
204 NotStun,
205 #[error("Not enough data available to parse the packet, expected {}, actual {}", .expected, .actual)]
207 Truncated {
208 expected: usize,
210 actual: usize,
212 },
213 #[error("Too many bytes for this data, expected {}, actual {}", .expected, .actual)]
215 TooLarge {
216 expected: usize,
218 actual: usize,
220 },
221 #[error("Missing attribute {}", .0)]
223 MissingAttribute(AttributeType),
224 #[error("An attribute {} was encountered after a message integrity attribute", .0)]
226 AttributeAfterIntegrity(AttributeType),
227 #[error("An attribute {} was encountered after a fingerprint attribute", .0)]
229 AttributeAfterFingerprint(AttributeType),
230 #[error("Fingerprint does not match")]
232 FingerprintMismatch,
233 #[error("The provided data does not match the message")]
235 DataMismatch,
236 #[error("The attribute contains invalid data")]
238 InvalidAttributeData,
239 #[error("Cannot parse with this attribute")]
241 WrongAttributeImplementation,
242}
243
244#[derive(Debug, thiserror::Error)]
246#[non_exhaustive]
247pub enum StunWriteError {
248 #[error("The attribute already exists in the message")]
250 AttributeExists(AttributeType),
251 #[error("The message already contains a fingerprint attribute")]
253 FingerprintExists,
254 #[error("The message already contains a message intregrity attribute")]
256 MessageIntegrityExists,
257 #[error("Too many bytes for this data, expected {}, actual {}", .expected, .actual)]
259 TooLarge {
260 expected: usize,
262 actual: usize,
264 },
265 #[error("Not enough data available to parse the packet, expected {}, actual {}", .expected, .actual)]
267 TooSmall {
268 expected: usize,
270 actual: usize,
272 },
273 #[error("Failed to compute integrity")]
275 IntegrityFailed,
276 #[error("Out of range input provided")]
278 OutOfRange {
279 value: usize,
281 min: usize,
283 max: usize,
285 },
286}
287
288#[derive(Debug, thiserror::Error, Copy, Clone)]
290pub enum ValidateError {
291 #[error("The message failed to parse the relevant integrity attributes")]
293 Parse(StunParseError),
294 #[error("The message failed integrity checks")]
296 IntegrityFailed,
297}
298
299impl From<StunParseError> for ValidateError {
300 fn from(value: StunParseError) -> Self {
301 Self::Parse(value)
302 }
303}
304
305#[derive(Debug, Clone, PartialEq, Eq)]
307#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
308pub struct LongTermCredentials {
309 username: String,
310 password: String,
311}
312
313impl LongTermCredentials {
314 pub fn new(username: String, password: String) -> Self {
328 Self { username, password }
329 }
330
331 pub fn username(&self) -> &str {
333 &self.username
334 }
335
336 pub fn password(&self) -> &str {
338 &self.password
339 }
340
341 pub fn to_key(&self, realm: String) -> LongTermKeyCredentials {
343 LongTermKeyCredentials {
344 username: self.username.clone(),
345 password: self.password.clone(),
346 realm,
347 }
348 }
349}
350
351#[derive(Debug, Clone, PartialEq, Eq)]
353#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
354pub struct LongTermKeyCredentials {
355 username: String,
356 password: String,
357 realm: String,
358}
359
360impl LongTermKeyCredentials {
361 pub fn new(username: String, password: String, realm: String) -> Self {
377 Self {
378 username,
379 password,
380 realm,
381 }
382 }
383
384 pub fn username(&self) -> &str {
386 &self.username
387 }
388
389 pub fn password(&self) -> &str {
391 &self.password
392 }
393
394 pub fn realm(&self) -> &str {
396 &self.realm
397 }
398
399 pub fn make_key(&self, algorithm: IntegrityAlgorithm) -> IntegrityKey {
401 match algorithm {
402 IntegrityAlgorithm::Sha1 => {
403 use md5::{Digest, Md5};
404 let mut digest = Md5::new();
405 digest.update(self.username.as_bytes());
406 digest.update(":".as_bytes());
407 digest.update(self.realm.as_bytes());
408 digest.update(":".as_bytes());
409 digest.update(self.password.as_bytes());
410 IntegrityKey::new_with_algo(IntegrityAlgorithm::Sha1, digest.finalize().to_vec())
411 }
412 IntegrityAlgorithm::Sha256 => {
413 use sha2::{Digest, Sha256};
414 let mut digest = Sha256::new();
415 digest.update(self.username.as_bytes());
416 digest.update(":".as_bytes());
417 digest.update(self.realm.as_bytes());
418 digest.update(":".as_bytes());
419 digest.update(self.password.as_bytes());
420 IntegrityKey::new_with_algo(IntegrityAlgorithm::Sha256, digest.finalize().to_vec())
421 }
422 }
423 }
424}
425
426#[derive(Debug, Clone, PartialEq, Eq)]
428#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
429pub struct ShortTermCredentials {
430 password: String,
431}
432
433impl ShortTermCredentials {
434 pub fn new(password: String) -> Self {
444 Self { password }
445 }
446
447 pub fn password(&self) -> &str {
449 &self.password
450 }
451
452 pub fn make_key(&self) -> IntegrityKey {
454 IntegrityKey::new(self.password.as_bytes().to_vec())
455 }
456}
457
458#[derive(Debug, Clone, PartialEq, Eq)]
462#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
463pub enum MessageIntegrityCredentials {
464 ShortTerm(ShortTermCredentials),
466 LongTerm(LongTermKeyCredentials),
468}
469
470impl From<LongTermKeyCredentials> for MessageIntegrityCredentials {
471 fn from(value: LongTermKeyCredentials) -> Self {
472 MessageIntegrityCredentials::LongTerm(value)
473 }
474}
475
476impl From<ShortTermCredentials> for MessageIntegrityCredentials {
477 fn from(value: ShortTermCredentials) -> Self {
478 MessageIntegrityCredentials::ShortTerm(value)
479 }
480}
481
482impl MessageIntegrityCredentials {
483 pub fn make_key(&self, algorithm: IntegrityAlgorithm) -> IntegrityKey {
485 match self {
486 MessageIntegrityCredentials::ShortTerm(short) => short.make_key(),
487 MessageIntegrityCredentials::LongTerm(long) => long.make_key(algorithm),
488 }
489 }
490}
491
492type HmacSha1 = hmac::Hmac<sha1::Sha1>;
493type HmacSha256 = hmac::Hmac<sha2::Sha256>;
494
495#[derive(Debug, Clone)]
497pub struct IntegrityKey {
498 key_algorithm: Option<IntegrityAlgorithm>,
499 bytes: Vec<u8>,
500 #[cfg(feature = "std")]
501 sha1: Arc<Mutex<Option<HmacSha1>>>,
502 #[cfg(feature = "std")]
503 sha256: Arc<Mutex<Option<HmacSha256>>>,
504}
505
506impl PartialEq<IntegrityKey> for IntegrityKey {
507 fn eq(&self, other: &Self) -> bool {
508 self.bytes == other.bytes
509 }
510}
511
512impl Eq for IntegrityKey {}
513
514impl IntegrityKey {
515 fn new(bytes: Vec<u8>) -> Self {
516 Self {
517 key_algorithm: None,
518 bytes,
519 #[cfg(feature = "std")]
520 sha1: Default::default(),
521 #[cfg(feature = "std")]
522 sha256: Default::default(),
523 }
524 }
525 fn new_with_algo(key_algorithm: IntegrityAlgorithm, bytes: Vec<u8>) -> Self {
526 let mut ret = Self::new(bytes);
527 ret.key_algorithm = Some(key_algorithm);
528 ret
529 }
530 pub(crate) fn as_bytes(&self) -> &[u8] {
531 &self.bytes
532 }
533
534 pub(crate) fn verify_sha1(&self, data: &[&[u8]], expected: &[u8]) -> bool {
535 if self
536 .key_algorithm
537 .is_some_and(|algo| algo != IntegrityAlgorithm::Sha1)
538 {
539 return false;
540 }
541 use hmac::digest::Output;
542 let computed = self.compute_sha1(data);
543 #[allow(deprecated)]
545 {
546 computed == Output::<sha1::Sha1Core>::from_slice(expected).into()
547 }
548 }
549
550 pub(crate) fn compute_sha1(
551 &self,
552 data: &[&[u8]],
553 ) -> CtOutput<CoreWrapper<HmacCore<CoreWrapper<sha1::Sha1Core>>>> {
554 use hmac::Mac;
555 #[cfg(feature = "std")]
556 let mut sha1 = self.sha1.lock().unwrap();
557 #[cfg(feature = "std")]
558 let hmac = sha1.get_or_insert_with(|| HmacSha1::new_from_slice(self.as_bytes()).unwrap());
559 #[cfg(not(feature = "std"))]
560 let mut hmac = HmacSha1::new_from_slice(self.as_bytes()).unwrap();
561
562 for data in data {
563 hmac.update(data);
564 }
565 #[cfg(feature = "std")]
566 let ret = hmac.finalize_reset();
567 #[cfg(not(feature = "std"))]
568 let ret = hmac.finalize();
569 ret
570 }
571
572 pub(crate) fn verify_sha256(&self, data: &[&[u8]], expected: &[u8]) -> bool {
573 use subtle::ConstantTimeEq;
574 if self
575 .key_algorithm
576 .is_some_and(|algo| algo != IntegrityAlgorithm::Sha256)
577 {
578 return false;
579 }
580 if expected.is_empty() {
581 return false;
582 }
583 let computed = self.compute_sha256(data);
584 if computed.len() < expected.len() {
585 return false;
586 }
587 computed[..expected.len()].ct_eq(expected).into()
588 }
589
590 pub(crate) fn compute_sha256(&self, data: &[&[u8]]) -> [u8; 32] {
591 trace!("computing sha256 using {data:?}");
592 use hmac::Mac;
593 #[cfg(feature = "std")]
594 let mut sha256 = self.sha256.lock().unwrap();
595 #[cfg(feature = "std")]
596 let hmac =
597 sha256.get_or_insert_with(|| HmacSha256::new_from_slice(self.as_bytes()).unwrap());
598 #[cfg(not(feature = "std"))]
599 let mut hmac = HmacSha256::new_from_slice(self.as_bytes()).unwrap();
600
601 for data in data {
602 hmac.update(data);
603 }
604 #[cfg(feature = "std")]
605 let ret = hmac.finalize_reset();
606 #[cfg(not(feature = "std"))]
607 let ret = hmac.finalize();
608 ret.into_bytes().into()
609 }
610}
611
612#[derive(Copy, Clone, Debug, PartialEq, Eq)]
624pub enum MessageClass {
625 Request,
627 Indication,
629 Success,
631 Error,
633}
634
635impl MessageClass {
636 pub fn is_response(self) -> bool {
639 matches!(self, MessageClass::Success | MessageClass::Error)
640 }
641
642 fn to_bits(self) -> u16 {
643 match self {
644 MessageClass::Request => 0x000,
645 MessageClass::Indication => 0x010,
646 MessageClass::Success => 0x100,
647 MessageClass::Error => 0x110,
648 }
649 }
650}
651
652#[derive(Copy, Clone, Debug, PartialEq, Eq)]
654pub struct MessageType(u16);
655
656impl core::fmt::Display for MessageType {
657 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
658 write!(
659 f,
660 "MessageType(class: {:?}, method: {}",
661 self.class(),
662 self.method(),
663 )
664 }
665}
666
667impl MessageType {
668 pub fn from_class_method(class: MessageClass, method: Method) -> Self {
679 let class_bits = MessageClass::to_bits(class);
680 let method = method.value();
681 let method_bits = method & 0xf | (method & 0x70) << 1 | (method & 0xf80) << 2;
682 Self(class_bits | method_bits)
685 }
686
687 pub fn class(self) -> MessageClass {
697 let class = (self.0 & 0x10) >> 4 | (self.0 & 0x100) >> 7;
698 match class {
699 0x0 => MessageClass::Request,
700 0x1 => MessageClass::Indication,
701 0x2 => MessageClass::Success,
702 0x3 => MessageClass::Error,
703 _ => unreachable!(),
704 }
705 }
706
707 pub fn has_class(self, cls: MessageClass) -> bool {
717 self.class() == cls
718 }
719
720 pub fn is_response(self) -> bool {
736 self.class().is_response()
737 }
738
739 pub fn method(self) -> Method {
749 Method::new(self.0 & 0xf | (self.0 & 0xe0) >> 1 | (self.0 & 0x3e00) >> 2)
750 }
751
752 pub fn has_method(self, method: Method) -> bool {
762 self.method() == method
763 }
764
765 pub fn write_into(&self, dest: &mut [u8]) {
767 BigEndian::write_u16(dest, self.0);
768 }
769
770 pub fn to_bytes(self) -> Vec<u8> {
772 let mut ret = vec![0; 2];
773 BigEndian::write_u16(&mut ret[0..2], self.0);
774 ret
775 }
776
777 pub fn from_bytes(data: &[u8]) -> Result<Self, StunParseError> {
779 let data = BigEndian::read_u16(data);
780 if data & 0xc000 != 0x0 {
781 return Err(StunParseError::NotStun);
783 }
784 Ok(Self(data))
785 }
786}
787impl TryFrom<&[u8]> for MessageType {
788 type Error = StunParseError;
789
790 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
791 MessageType::from_bytes(value)
792 }
793}
794
795#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
797pub struct TransactionId {
798 id: u128,
799}
800
801impl TransactionId {
802 pub fn generate() -> TransactionId {
804 #[cfg(not(feature = "std"))]
805 {
806 use rand::TryRngCore;
807 let mut dest = [0; 16];
808 rand::rngs::OsRng
809 .try_fill_bytes(&mut dest)
810 .expect("Cannot generate random data");
811 u128::from_be_bytes(dest).into()
812 }
813 #[cfg(feature = "std")]
814 {
815 use rand::Rng;
816 let mut rng = rand::rng();
817 rng.random::<u128>().into()
818 }
819 }
820}
821
822impl From<u128> for TransactionId {
823 fn from(id: u128) -> Self {
824 Self {
825 id: id & 0xffff_ffff_ffff_ffff_ffff_ffff,
826 }
827 }
828}
829impl From<TransactionId> for u128 {
830 fn from(id: TransactionId) -> Self {
831 id.id
832 }
833}
834impl core::fmt::Display for TransactionId {
835 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
836 write!(f, "{:#x}", self.id)
837 }
838}
839
840#[derive(Debug)]
844pub struct MessageHeader {
845 mtype: MessageType,
846 transaction_id: TransactionId,
847 length: u16,
848}
849
850impl MessageHeader {
851 pub const LENGTH: usize = 20;
853
854 pub fn from_bytes(data: &[u8]) -> Result<Self, StunParseError> {
867 if data.len() < 20 {
868 return Err(StunParseError::Truncated {
869 expected: 20,
870 actual: data.len(),
871 });
872 }
873 let mtype = MessageType::from_bytes(data)?;
874 let mlength = BigEndian::read_u16(&data[2..]);
875 let tid = BigEndian::read_u128(&data[4..]);
876 let cookie = (tid >> 96) as u32;
877 if cookie != MAGIC_COOKIE {
878 warn!(
879 "malformed cookie constant {:?} != stored data {:?}",
880 MAGIC_COOKIE, cookie
881 );
882 return Err(StunParseError::NotStun);
883 }
884
885 Ok(Self {
886 mtype,
887 transaction_id: tid.into(),
888 length: mlength,
889 })
890 }
891
892 pub fn data_length(&self) -> u16 {
895 self.length
896 }
897
898 pub fn transaction_id(&self) -> TransactionId {
900 self.transaction_id
901 }
902
903 pub fn get_type(&self) -> MessageType {
905 self.mtype
906 }
907
908 fn new(mtype: MessageType, transaction_id: TransactionId, length: u16) -> Self {
909 Self {
910 mtype,
911 transaction_id,
912 length,
913 }
914 }
915
916 fn write_into(&self, dest: &mut [u8]) {
917 self.mtype.write_into(&mut dest[..2]);
918 let transaction: u128 = self.transaction_id.into();
919 let tid = (MAGIC_COOKIE as u128) << 96 | transaction & 0xffff_ffff_ffff_ffff_ffff_ffff;
920 BigEndian::write_u128(&mut dest[4..20], tid);
921 BigEndian::write_u16(&mut dest[2..4], self.length);
922 }
923}
924
925#[derive(Debug, Clone, Copy)]
930pub struct Message<'a> {
931 data: &'a [u8],
932}
933
934impl core::fmt::Display for Message<'_> {
935 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
936 write!(
937 f,
938 "Message(class: {:?}, method: {}, transaction: {}, attributes: ",
939 self.get_type().class(),
940 self.get_type().method(),
941 self.transaction_id()
942 )?;
943 let iter = self.iter_attributes();
944 write!(f, "[")?;
945 for (i, (_offset, a)) in iter.enumerate() {
946 if i > 0 {
947 write!(f, ", ")?;
948 }
949 write!(f, "{a}")?;
950 }
951 write!(f, "]")?;
952 write!(f, ")")
953 }
954}
955
956#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
958pub enum IntegrityAlgorithm {
959 Sha1,
961 Sha256,
963}
964
965impl<'a> Message<'a> {
966 pub fn builder<B: MessageWrite>(
982 mtype: MessageType,
983 transaction_id: TransactionId,
984 mut write: B,
985 ) -> B {
986 let mut data = [0; 20];
987 MessageHeader::new(mtype, transaction_id, 0).write_into(&mut data);
988 write.push_data(&data);
989 write
990 }
991
992 pub fn builder_request<B: MessageWrite>(method: Method, write: B) -> B {
1006 Message::builder(
1007 MessageType::from_class_method(MessageClass::Request, method),
1008 TransactionId::generate(),
1009 write,
1010 )
1011 }
1012
1013 pub fn builder_success<B: MessageWrite>(orig: &Message, write: B) -> B {
1033 if !orig.has_class(MessageClass::Request) {
1034 panic!(
1035 "A success response message was attempted to be created from a non-request message"
1036 );
1037 }
1038 Message::builder(
1039 MessageType::from_class_method(MessageClass::Success, orig.method()),
1040 orig.transaction_id(),
1041 write,
1042 )
1043 }
1044
1045 pub fn builder_error<B: MessageWrite>(orig: &Message, write: B) -> B {
1065 if !orig.has_class(MessageClass::Request) {
1066 panic!(
1067 "An error response message was attempted to be created from a non-request message"
1068 );
1069 }
1070 Message::builder(
1071 MessageType::from_class_method(MessageClass::Error, orig.method()),
1072 orig.transaction_id(),
1073 write,
1074 )
1075 }
1076
1077 pub fn builder_indication<B: MessageWrite>(method: Method, write: B) -> B {
1091 Message::builder(
1092 MessageType::from_class_method(MessageClass::Indication, method),
1093 TransactionId::generate(),
1094 write,
1095 )
1096 }
1097
1098 pub fn get_type(&self) -> MessageType {
1112 MessageType::try_from(&self.data[..2]).unwrap()
1113 }
1114
1115 pub fn class(&self) -> MessageClass {
1127 self.get_type().class()
1128 }
1129
1130 pub fn has_class(&self, cls: MessageClass) -> bool {
1142 self.class() == cls
1143 }
1144
1145 pub fn is_response(&self) -> bool {
1167 self.class().is_response()
1168 }
1169
1170 pub fn method(&self) -> Method {
1182 self.get_type().method()
1183 }
1184
1185 pub fn has_method(&self, method: Method) -> bool {
1198 self.method() == method
1199 }
1200
1201 pub fn transaction_id(&self) -> TransactionId {
1215 BigEndian::read_u128(&self.data[4..]).into()
1216 }
1217
1218 #[tracing::instrument(
1240 name = "message_from_bytes",
1241 level = "trace",
1242 skip(data),
1243 fields(
1244 data.len = data.len()
1245 )
1246 )]
1247 pub fn from_bytes(data: &'a [u8]) -> Result<Self, StunParseError> {
1248 let orig_data = data;
1249
1250 let header = MessageHeader::from_bytes(data)?;
1251 let mlength = header.data_length() as usize;
1252 if mlength + MessageHeader::LENGTH > data.len() {
1253 warn!(
1255 "malformed advertised size {} and data size {} don't match",
1256 mlength + 20,
1257 data.len()
1258 );
1259 return Err(StunParseError::Truncated {
1260 expected: mlength + MessageHeader::LENGTH,
1261 actual: data.len(),
1262 });
1263 }
1264
1265 let ending_attributes = [
1266 MessageIntegrity::TYPE,
1267 MessageIntegritySha256::TYPE,
1268 Fingerprint::TYPE,
1269 ];
1270 let mut seen_ending_attributes = [AttributeType::new(0); 3];
1272 let mut seen_ending_len = 0;
1273 let mut data_offset = MessageHeader::LENGTH;
1274 for attr in MessageRawAttributesIter::new(data) {
1275 let (_offset, attr) = attr.inspect_err(|e| {
1276 warn!("failed to parse message attribute at offset {data_offset}: {e}",);
1277 })?;
1278
1279 if seen_ending_len > 0 && !ending_attributes.contains(&attr.get_type()) {
1282 if seen_ending_attributes.contains(&Fingerprint::TYPE) {
1283 warn!("unexpected attribute {} after FINGERPRINT", attr.get_type());
1284 return Ok(Message { data: orig_data });
1285 } else {
1286 warn!(
1288 "unexpected attribute {} after MESSAGE_INTEGRITY",
1289 attr.get_type()
1290 );
1291 return Ok(Message { data: orig_data });
1292 }
1293 }
1294
1295 if ending_attributes.contains(&attr.get_type()) {
1296 if seen_ending_attributes.contains(&attr.get_type()) {
1297 if seen_ending_attributes.contains(&Fingerprint::TYPE) {
1298 warn!("unexpected attribute {} after FINGERPRINT", attr.get_type());
1299 return Ok(Message { data: orig_data });
1300 } else {
1301 warn!(
1303 "unexpected attribute {} after MESSAGE_INTEGRITY",
1304 attr.get_type()
1305 );
1306 return Ok(Message { data: orig_data });
1307 }
1308 } else {
1309 seen_ending_attributes[seen_ending_len] = attr.get_type();
1310 seen_ending_len += 1;
1311 }
1313 }
1314 let padded_len = attr.padded_len();
1315 if attr.get_type() == Fingerprint::TYPE {
1316 let f = Fingerprint::from_raw_ref(&attr)?;
1317 let msg_fingerprint = f.fingerprint();
1318 let mut header = [0; 4];
1319 header[0] = orig_data[0];
1320 header[1] = orig_data[1];
1321 BigEndian::write_u16(
1322 &mut header[2..4],
1323 (data_offset + padded_len - MessageHeader::LENGTH) as u16,
1324 );
1325 let fingerprint_data = &orig_data[4..data_offset];
1326 let calculated_fingerprint = Fingerprint::compute(&[&header, fingerprint_data]);
1327 if &calculated_fingerprint != msg_fingerprint {
1328 warn!(
1329 "fingerprint mismatch {:?} != {:?}",
1330 calculated_fingerprint, msg_fingerprint
1331 );
1332 return Err(StunParseError::FingerprintMismatch);
1333 }
1334 }
1335 data_offset += padded_len;
1336 }
1337 Ok(Message { data: orig_data })
1338 }
1339
1340 pub fn validate_integrity(
1363 &self,
1364 credentials: &MessageIntegrityCredentials,
1365 ) -> Result<IntegrityAlgorithm, ValidateError> {
1366 let raw_sha1 = self.raw_attribute(MessageIntegrity::TYPE);
1367 let raw_sha256 = self.raw_attribute(MessageIntegritySha256::TYPE);
1368 let (algo, msg_hmac) = match (raw_sha1, raw_sha256) {
1369 (_, Some(sha256)) => {
1370 let integrity = MessageIntegritySha256::try_from(&sha256)?;
1371 (IntegrityAlgorithm::Sha256, integrity.hmac().to_vec())
1372 }
1373 (Some(sha1), None) => {
1374 let integrity = MessageIntegrity::try_from(&sha1)?;
1375 (IntegrityAlgorithm::Sha1, integrity.hmac().to_vec())
1376 }
1377 (None, None) => {
1378 return Err(StunParseError::MissingAttribute(MessageIntegrity::TYPE).into())
1379 }
1380 };
1381 let key = credentials.make_key(algo);
1382 self.validate_integrity_with_hmac(algo, &msg_hmac, &key)
1383 }
1384
1385 pub fn validate_integrity_with_key(
1387 &self,
1388 key: &IntegrityKey,
1389 ) -> Result<IntegrityAlgorithm, ValidateError> {
1390 let raw_sha1 = self.raw_attribute(MessageIntegrity::TYPE);
1391 let raw_sha256 = self.raw_attribute(MessageIntegritySha256::TYPE);
1392 let (algo, msg_hmac) = if let Some(algo) = key.key_algorithm {
1393 match (algo, raw_sha1, raw_sha256) {
1394 (IntegrityAlgorithm::Sha256, _, Some(sha256)) => {
1395 let integrity = MessageIntegritySha256::try_from(&sha256)?;
1396 (algo, integrity.hmac().to_vec())
1397 }
1398 (IntegrityAlgorithm::Sha1, Some(sha1), _) => {
1399 let integrity = MessageIntegrity::try_from(&sha1)?;
1400 (algo, integrity.hmac().to_vec())
1401 }
1402 _ => return Err(StunParseError::MissingAttribute(MessageIntegrity::TYPE).into()),
1403 }
1404 } else {
1405 match (raw_sha1, raw_sha256) {
1406 (_, Some(sha256)) => {
1407 let integrity = MessageIntegritySha256::try_from(&sha256)?;
1408 (IntegrityAlgorithm::Sha256, integrity.hmac().to_vec())
1409 }
1410 (Some(sha1), None) => {
1411 let integrity = MessageIntegrity::try_from(&sha1)?;
1412 (IntegrityAlgorithm::Sha1, integrity.hmac().to_vec())
1413 }
1414 (None, None) => {
1415 return Err(StunParseError::MissingAttribute(MessageIntegrity::TYPE).into())
1416 }
1417 }
1418 };
1419 self.validate_integrity_with_hmac(algo, &msg_hmac, key)
1420 }
1421
1422 #[tracing::instrument(
1423 name = "message_validate_integrity_with_hmac",
1424 level = "trace",
1425 skip(self, key, msg_hmac),
1426 fields(
1427 msg.transaction = %self.transaction_id(),
1428 )
1429 )]
1430 fn validate_integrity_with_hmac(
1431 &self,
1432 algo: IntegrityAlgorithm,
1433 msg_hmac: &[u8],
1434 key: &IntegrityKey,
1435 ) -> Result<IntegrityAlgorithm, ValidateError> {
1436 if key.key_algorithm.is_some_and(|key_algo| key_algo != algo) {
1437 debug!(
1438 "Key algorithm ({:?}) does not match algo ({algo:?})",
1439 key.key_algorithm
1440 );
1441 return Err(StunParseError::DataMismatch.into());
1442 }
1443 let data = self.data;
1446 debug_assert!(data.len() >= MessageHeader::LENGTH);
1447 let mut data = &data[MessageHeader::LENGTH..];
1448 let mut data_offset = MessageHeader::LENGTH;
1449 while !data.is_empty() {
1450 let attr = RawAttribute::from_bytes(data)?;
1451 if algo == IntegrityAlgorithm::Sha1 && attr.get_type() == MessageIntegrity::TYPE {
1452 let msg = MessageIntegrity::try_from(&attr)?;
1453 debug_assert!(msg.hmac().as_slice() == msg_hmac);
1454
1455 let mut header = [0; 4];
1458 header[0] = self.data[0];
1459 header[1] = self.data[1];
1460 let hmac_data = &self.data[4..data_offset];
1461 BigEndian::write_u16(
1462 &mut header[2..4],
1463 data_offset as u16 + 24 - MessageHeader::LENGTH as u16,
1464 );
1465 if MessageIntegrity::verify(
1466 &[header.as_slice(), hmac_data],
1467 key,
1468 msg_hmac.try_into().unwrap(),
1469 ) {
1470 return Ok(algo);
1471 } else {
1472 return Err(ValidateError::IntegrityFailed);
1473 }
1474 } else if algo == IntegrityAlgorithm::Sha256
1475 && attr.get_type() == MessageIntegritySha256::TYPE
1476 {
1477 let msg = MessageIntegritySha256::try_from(&attr)?;
1478 debug_assert!(msg.hmac() == msg_hmac);
1479
1480 let mut header = [0; 4];
1483 header[0] = self.data[0];
1484 header[1] = self.data[1];
1485 let hmac_data = &self.data[4..data_offset];
1486 BigEndian::write_u16(
1487 &mut header[2..4],
1488 data_offset as u16 + attr.padded_len() as u16 - MessageHeader::LENGTH as u16,
1489 );
1490 if MessageIntegritySha256::verify(&[&header, hmac_data], key, msg_hmac) {
1491 return Ok(algo);
1492 } else {
1493 return Err(ValidateError::IntegrityFailed);
1494 }
1495 }
1496 let padded_len = attr.padded_len();
1497 debug_assert!(padded_len <= data.len());
1499 data = &data[padded_len..];
1500 data_offset += padded_len;
1501 }
1502
1503 unreachable!();
1506 }
1507
1508 pub fn nth_raw_attribute(&self, atype: AttributeType, n: usize) -> Option<RawAttribute<'_>> {
1527 self.nth_raw_attribute_and_offset(atype, n)
1528 .map(|(_offset, attr)| attr)
1529 }
1530
1531 pub fn raw_attribute(&self, atype: AttributeType) -> Option<RawAttribute<'_>> {
1535 self.nth_raw_attribute(atype, 0)
1536 }
1537
1538 #[tracing::instrument(
1560 name = "message_nth_raw_attribute_and_offset",
1561 level = "trace",
1562 skip(self, atype),
1563 fields(
1564 msg.transaction = %self.transaction_id(),
1565 attribute_type = %atype,
1566 )
1567 )]
1568 pub fn nth_raw_attribute_and_offset(
1569 &self,
1570 atype: AttributeType,
1571 n: usize,
1572 ) -> Option<(usize, RawAttribute<'_>)> {
1573 if let Some((offset, attr)) = self
1574 .iter_attributes()
1575 .filter(|(_offset, attr)| attr.get_type() == atype)
1576 .nth(n)
1577 {
1578 trace!("found attribute at offset: {offset}");
1579 Some((offset, attr))
1580 } else {
1581 trace!("could not find attribute");
1582 None
1583 }
1584 }
1585
1586 pub fn raw_attribute_and_offset(
1591 &self,
1592 atype: AttributeType,
1593 ) -> Option<(usize, RawAttribute<'_>)> {
1594 self.nth_raw_attribute_and_offset(atype, 0)
1595 }
1596
1597 pub fn nth_attribute<A: AttributeFromRaw<'a> + AttributeStaticType>(
1619 &'a self,
1620 n: usize,
1621 ) -> Result<A, StunParseError> {
1622 self.nth_attribute_and_offset(n).map(|(_offset, attr)| attr)
1623 }
1624
1625 pub fn attribute<A: AttributeFromRaw<'a> + AttributeStaticType>(
1629 &'a self,
1630 ) -> Result<A, StunParseError> {
1631 self.nth_attribute(0)
1632 }
1633
1634 pub fn nth_attribute_and_offset<A: AttributeFromRaw<'a> + AttributeStaticType>(
1660 &'a self,
1661 n: usize,
1662 ) -> Result<(usize, A), StunParseError> {
1663 self.nth_raw_attribute_and_offset(A::TYPE, n)
1664 .ok_or(StunParseError::MissingAttribute(A::TYPE))
1665 .and_then(|(offset, raw)| A::from_raw(raw).map(|attr| (offset, attr)))
1666 }
1667
1668 pub fn attribute_and_offset<A: AttributeFromRaw<'a> + AttributeStaticType>(
1673 &'a self,
1674 ) -> Result<(usize, A), StunParseError> {
1675 self.nth_attribute_and_offset(0)
1676 }
1677
1678 pub fn iter_attributes(&self) -> impl Iterator<Item = (usize, RawAttribute<'_>)> {
1680 MessageAttributesIter::new(self.data)
1681 }
1682
1683 #[tracing::instrument(
1731 level = "trace",
1732 skip(msg, write),
1733 fields(
1734 msg.transaction = %msg.transaction_id(),
1735 )
1736 )]
1737 pub fn check_attribute_types<B: MessageWrite>(
1738 msg: &Message,
1739 supported: &[AttributeType],
1740 required_in_msg: &[AttributeType],
1741 write: B,
1742 ) -> Option<B> {
1743 let unsupported: Vec<AttributeType> = msg
1745 .iter_attributes()
1746 .map(|(_offset, a)| a.get_type())
1747 .filter(|at| at.comprehension_required() && !supported.contains(at))
1749 .collect();
1750 if !unsupported.is_empty() {
1751 warn!(
1752 "Message contains unknown comprehension required attributes {:?}, returning unknown attributes",
1753 unsupported
1754 );
1755 return Some(Message::unknown_attributes(msg, &unsupported, write));
1756 }
1757 let has_required_attribute_missing = required_in_msg
1758 .iter()
1759 .any(|&at| {
1761 !msg.iter_attributes()
1762 .map(|(_offset, a)| a.get_type())
1763 .any(|a| a == at)
1764 });
1765 if has_required_attribute_missing {
1766 warn!("Message is missing required attributes, returning bad request");
1767 return Some(Message::bad_request(msg, write));
1768 }
1769 None
1770 }
1771
1772 pub fn unknown_attributes<B: MessageWrite>(
1793 src: &Message,
1794 attributes: &[AttributeType],
1795 write: B,
1796 ) -> B {
1797 let mut out = Message::builder_error(src, write);
1798 let software = Software::new("stun-types").unwrap();
1799 out.add_attribute(&software).unwrap();
1800 let error = ErrorCode::new(420, "Unknown Attributes").unwrap();
1801 out.add_attribute(&error).unwrap();
1802 let unknown = UnknownAttributes::new(attributes);
1803 if !attributes.is_empty() {
1804 out.add_attribute(&unknown).unwrap();
1805 }
1806 out
1807 }
1808
1809 pub fn bad_request<B: MessageWrite>(src: &Message, write: B) -> B {
1827 let mut out = Message::builder_error(src, write);
1828 let software = Software::new("stun-types").unwrap();
1829 out.add_attribute(&software).unwrap();
1830 let error = ErrorCode::new(400, "Bad Request").unwrap();
1831 out.add_attribute(&error).unwrap();
1832 out
1833 }
1834
1835 pub fn has_attribute(&self, atype: AttributeType) -> bool {
1851 self.iter_attributes()
1852 .any(|(_offset, attr)| attr.get_type() == atype)
1853 }
1854
1855 pub fn as_bytes(&self) -> &[u8] {
1857 self.data
1858 }
1859}
1860impl<'a> TryFrom<&'a [u8]> for Message<'a> {
1861 type Error = StunParseError;
1862
1863 fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {
1864 Message::from_bytes(value)
1865 }
1866}
1867
1868impl AsRef<[u8]> for Message<'_> {
1869 fn as_ref(&self) -> &[u8] {
1870 self.data
1871 }
1872}
1873
1874#[derive(Debug)]
1875struct MessageRawAttributesIter<'a> {
1876 data: &'a [u8],
1877 data_i: usize,
1878}
1879
1880impl<'a> MessageRawAttributesIter<'a> {
1881 fn new(data: &'a [u8]) -> Self {
1882 Self {
1883 data,
1884 data_i: MessageHeader::LENGTH,
1885 }
1886 }
1887}
1888
1889impl<'a> Iterator for MessageRawAttributesIter<'a> {
1890 type Item = Result<(usize, RawAttribute<'a>), StunParseError>;
1891
1892 fn next(&mut self) -> Option<Self::Item> {
1893 if self.data_i >= self.data.len() {
1894 return None;
1895 }
1896
1897 match RawAttribute::from_bytes(&self.data[self.data_i..]) {
1898 Ok(attr) => {
1899 let padded_len = attr.padded_len();
1900 self.data_i += padded_len;
1901 if self.data_i > self.data.len() {
1902 warn!(
1903 "attribute {} extends past the end of the data",
1904 attr.get_type()
1905 );
1906 return Some(Err(StunParseError::Truncated {
1907 expected: self.data_i,
1908 actual: self.data.len(),
1909 }));
1910 }
1911 Some(Ok((self.data_i - padded_len, attr)))
1912 }
1913 Err(e) => {
1914 let offset = self.data_i;
1915 self.data_i = self.data.len();
1916 let e = match e {
1917 StunParseError::Truncated { expected, actual } => StunParseError::Truncated {
1918 expected: expected + 4 + offset,
1919 actual: actual + 4 + offset,
1920 },
1921 StunParseError::TooLarge { expected, actual } => StunParseError::TooLarge {
1922 expected: expected + 4 + offset,
1923 actual: actual + 4 + offset,
1924 },
1925 e => e,
1926 };
1927 Some(Err(e))
1928 }
1929 }
1930 }
1931}
1932
1933#[doc(hidden)]
1934#[derive(Debug)]
1935pub struct MessageAttributesIter<'a> {
1936 header_parsed: bool,
1937 inner: MessageRawAttributesIter<'a>,
1938 last_attr_type: AttributeType,
1939 seen_message_integrity: bool,
1940}
1941
1942impl<'a> MessageAttributesIter<'a> {
1943 pub fn new(data: &'a [u8]) -> Self {
1952 Self {
1953 header_parsed: false,
1954 inner: MessageRawAttributesIter::new(data),
1955 seen_message_integrity: false,
1956 last_attr_type: AttributeType::new(0),
1957 }
1958 }
1959}
1960
1961impl<'a> Iterator for MessageAttributesIter<'a> {
1962 type Item = (usize, RawAttribute<'a>);
1963
1964 fn next(&mut self) -> Option<Self::Item> {
1965 if self.last_attr_type == Fingerprint::TYPE {
1967 return None;
1968 }
1969
1970 if !self.header_parsed {
1971 let Ok(hdr) = MessageHeader::from_bytes(self.inner.data) else {
1972 self.last_attr_type = Fingerprint::TYPE;
1973 return None;
1974 };
1975 if hdr.data_length() as usize + MessageHeader::LENGTH > self.inner.data.len() {
1976 self.last_attr_type = Fingerprint::TYPE;
1977 return None;
1978 }
1979 self.header_parsed = true;
1980 }
1981
1982 let (offset, attr) = self.inner.next()?.ok()?;
1983 let attr_type = attr.get_type();
1984 if self.seen_message_integrity {
1985 if self.last_attr_type != Fingerprint::TYPE && attr_type == Fingerprint::TYPE {
1986 self.last_attr_type = attr_type;
1987 return Some((offset, attr));
1988 }
1989 if self.last_attr_type == MessageIntegrity::TYPE
1990 && attr_type == MessageIntegritySha256::TYPE
1991 {
1992 self.last_attr_type = attr_type;
1993 return Some((offset, attr));
1994 }
1995 self.last_attr_type = Fingerprint::TYPE;
1996 return None;
1997 }
1998 if attr.get_type() == MessageIntegrity::TYPE
1999 || attr.get_type() == MessageIntegritySha256::TYPE
2000 || attr.get_type() == Fingerprint::TYPE
2001 {
2002 self.seen_message_integrity = true;
2003 }
2004 self.last_attr_type = attr.get_type();
2005
2006 Some((offset, attr))
2007 }
2008}
2009
2010#[allow(clippy::len_without_is_empty)]
2011pub trait MessageWrite {
2013 type Output;
2015 fn max_size(&self) -> Option<usize> {
2018 None
2019 }
2020
2021 fn mut_data(&mut self) -> &mut [u8];
2023 fn data(&self) -> &[u8];
2025 fn len(&self) -> usize;
2027 fn push_data(&mut self, data: &[u8]);
2029 fn push_attribute_unchecked(&mut self, attr: &dyn AttributeWrite);
2031
2032 fn has_attribute(&self, atype: AttributeType) -> bool;
2034
2035 fn has_any_attribute(&self, atypes: &[AttributeType]) -> Option<AttributeType>;
2038
2039 fn finish(self) -> Self::Output;
2041}
2042
2043pub trait MessageWriteExt: MessageWrite {
2045 fn get_type(&self) -> MessageType {
2057 MessageType::from_bytes(self.data()).unwrap()
2058 }
2059
2060 fn class(&self) -> MessageClass {
2072 self.get_type().class()
2073 }
2074
2075 fn has_class(&self, cls: MessageClass) -> bool {
2087 self.class() == cls
2088 }
2089
2090 fn is_response(&self) -> bool {
2112 self.class().is_response()
2113 }
2114
2115 fn method(&self) -> Method {
2127 self.get_type().method()
2128 }
2129
2130 fn has_method(&self, method: Method) -> bool {
2143 self.method() == method
2144 }
2145
2146 fn transaction_id(&self) -> TransactionId {
2160 BigEndian::read_u128(&self.data()[4..]).into()
2161 }
2162
2163 fn add_message_integrity(
2198 &mut self,
2199 credentials: &MessageIntegrityCredentials,
2200 algorithm: IntegrityAlgorithm,
2201 ) -> Result<(), StunWriteError> {
2202 let key = credentials.make_key(algorithm);
2203 self.add_message_integrity_with_key(&key, algorithm)
2204 }
2205
2206 #[tracing::instrument(
2208 name = "message_add_integrity_with_key",
2209 level = "trace",
2210 err,
2211 skip(self),
2212 fields(
2213 msg.transaction = %self.transaction_id(),
2214 )
2215 )]
2216 fn add_message_integrity_with_key(
2217 &mut self,
2218 key: &IntegrityKey,
2219 algorithm: IntegrityAlgorithm,
2220 ) -> Result<(), StunWriteError> {
2221 let mut atypes = [AttributeType::new(0); 3];
2222 let mut i = 0;
2223 atypes[i] = match algorithm {
2224 IntegrityAlgorithm::Sha1 => MessageIntegrity::TYPE,
2225 IntegrityAlgorithm::Sha256 => MessageIntegritySha256::TYPE,
2226 };
2227 i += 1;
2228 if algorithm == IntegrityAlgorithm::Sha1 {
2229 atypes[i] = MessageIntegritySha256::TYPE;
2230 i += 1;
2231 }
2232 atypes[i] = Fingerprint::TYPE;
2233 i += 1;
2234
2235 match self.has_any_attribute(&atypes[..i]) {
2236 Some(MessageIntegrity::TYPE) => {
2238 return Err(StunWriteError::AttributeExists(MessageIntegrity::TYPE))
2239 }
2240 Some(MessageIntegritySha256::TYPE) => {
2241 return Err(StunWriteError::AttributeExists(
2242 MessageIntegritySha256::TYPE,
2243 ));
2244 }
2245 Some(Fingerprint::TYPE) => return Err(StunWriteError::FingerprintExists),
2246 _ => (),
2247 }
2248 match algorithm {
2249 IntegrityAlgorithm::Sha1 => {
2250 check_attribute_can_fit(self, &MessageIntegrity::new([0; 20]))?
2251 }
2252 IntegrityAlgorithm::Sha256 => {
2253 check_attribute_can_fit(self, &MessageIntegritySha256::new(&[0; 32]).unwrap())?
2254 }
2255 };
2256
2257 add_message_integrity_unchecked(self, key, algorithm);
2258
2259 Ok(())
2260 }
2261
2262 #[tracing::instrument(
2280 name = "message_add_fingerprint",
2281 level = "trace",
2282 skip(self),
2283 fields(
2284 msg.transaction = %self.transaction_id(),
2285 )
2286 )]
2287 fn add_fingerprint(&mut self) -> Result<(), StunWriteError> {
2288 if self.has_attribute(Fingerprint::TYPE) {
2289 return Err(StunWriteError::AttributeExists(Fingerprint::TYPE));
2290 }
2291
2292 check_attribute_can_fit(self, &Fingerprint::new([0; 4]))?;
2293 add_fingerprint_unchecked(self);
2294
2295 Ok(())
2296 }
2297
2298 #[tracing::instrument(
2329 name = "message_add_attribute",
2330 level = "trace",
2331 err,
2332 skip(self, attr),
2333 fields(
2334 msg.transaction = %self.transaction_id(),
2335 )
2336 )]
2337 fn add_attribute(&mut self, attr: &dyn AttributeWrite) -> Result<(), StunWriteError> {
2338 let ty = attr.get_type();
2339 match ty {
2340 MessageIntegrity::TYPE => {
2341 panic!("Cannot write MessageIntegrity with `add_attribute`. Use add_message_integrity() instead");
2342 }
2343 MessageIntegritySha256::TYPE => {
2344 panic!("Cannot write MessageIntegritySha256 with `add_attribute`. Use add_message_integrity() instead");
2345 }
2346 Fingerprint::TYPE => {
2347 panic!(
2348 "Cannot write Fingerprint with `add_attribute`. Use add_fingerprint() instead"
2349 );
2350 }
2351 _ => (),
2352 }
2353 match self.has_any_attribute(&[
2354 MessageIntegrity::TYPE,
2355 MessageIntegritySha256::TYPE,
2356 Fingerprint::TYPE,
2357 ]) {
2358 Some(MessageIntegrity::TYPE) => return Err(StunWriteError::MessageIntegrityExists),
2360 Some(MessageIntegritySha256::TYPE) => {
2361 return Err(StunWriteError::MessageIntegrityExists)
2362 }
2363 Some(Fingerprint::TYPE) => return Err(StunWriteError::FingerprintExists),
2364 _ => (),
2365 }
2366 check_attribute_can_fit(self, attr)?;
2367 self.push_attribute_unchecked(attr);
2368 Ok(())
2369 }
2370}
2371
2372impl<T: MessageWrite> MessageWriteExt for T {}
2373
2374#[derive(Debug, Default)]
2376pub struct MessageWriteVec {
2377 output: Vec<u8>,
2378 attributes: smallvec::SmallVec<[AttributeType; 16]>,
2379}
2380
2381impl MessageWriteVec {
2382 pub fn new() -> Self {
2384 Self::default()
2385 }
2386
2387 pub fn with_capacity(capacity: usize) -> Self {
2389 Self {
2390 output: Vec::with_capacity(capacity),
2391 attributes: Default::default(),
2392 }
2393 }
2394}
2395
2396impl core::ops::Deref for MessageWriteVec {
2397 type Target = Vec<u8>;
2398 fn deref(&self) -> &Self::Target {
2399 &self.output
2400 }
2401}
2402
2403impl core::ops::DerefMut for MessageWriteVec {
2404 fn deref_mut(&mut self) -> &mut Self::Target {
2405 &mut self.output
2406 }
2407}
2408
2409impl MessageWrite for MessageWriteVec {
2410 type Output = Vec<u8>;
2411
2412 fn mut_data(&mut self) -> &mut [u8] {
2413 &mut self.output
2414 }
2415
2416 fn data(&self) -> &[u8] {
2417 &self.output
2418 }
2419
2420 fn len(&self) -> usize {
2421 self.output.len()
2422 }
2423
2424 fn push_data(&mut self, data: &[u8]) {
2425 self.output.extend(data)
2426 }
2427
2428 fn finish(self) -> Self::Output {
2429 self.output
2430 }
2431
2432 fn push_attribute_unchecked(&mut self, attr: &dyn AttributeWrite) {
2433 let offset = self.output.len();
2434 let padded_len = attr.padded_len();
2435 let expected = offset + padded_len;
2436 BigEndian::write_u16(
2437 &mut self.output[2..4],
2438 (expected - MessageHeader::LENGTH) as u16,
2439 );
2440 self.output.resize(expected, 0);
2441 attr.write_into_unchecked(&mut self.output[offset..]);
2442 self.attributes.push(attr.get_type());
2443 }
2444
2445 fn has_attribute(&self, atype: AttributeType) -> bool {
2446 self.attributes.contains(&atype)
2447 }
2448
2449 fn has_any_attribute(&self, atypes: &[AttributeType]) -> Option<AttributeType> {
2450 self.attributes
2451 .iter()
2452 .find(|&typ| atypes.contains(typ))
2453 .cloned()
2454 }
2455}
2456
2457#[derive(Debug, Default)]
2459pub struct MessageWriteMutSlice<'a> {
2460 output: &'a mut [u8],
2461 offset: usize,
2462 attributes: smallvec::SmallVec<[AttributeType; 16]>,
2463}
2464
2465impl<'a> MessageWriteMutSlice<'a> {
2466 pub fn new(data: &'a mut [u8]) -> Self {
2468 Self {
2469 output: data,
2470 offset: 0,
2471 attributes: Default::default(),
2472 }
2473 }
2474}
2475
2476impl core::ops::Deref for MessageWriteMutSlice<'_> {
2477 type Target = [u8];
2478 fn deref(&self) -> &Self::Target {
2479 self.output
2480 }
2481}
2482
2483impl core::ops::DerefMut for MessageWriteMutSlice<'_> {
2484 fn deref_mut(&mut self) -> &mut Self::Target {
2485 self.output
2486 }
2487}
2488
2489impl<'a> MessageWrite for MessageWriteMutSlice<'a> {
2490 type Output = usize;
2491
2492 fn max_size(&self) -> Option<usize> {
2493 Some(self.output.len())
2494 }
2495
2496 fn mut_data(&mut self) -> &mut [u8] {
2497 &mut self.output[..self.offset]
2498 }
2499
2500 fn data(&self) -> &[u8] {
2501 &self.output[..self.offset]
2502 }
2503
2504 fn len(&self) -> usize {
2505 self.offset
2506 }
2507
2508 fn push_data(&mut self, data: &[u8]) {
2509 let len = data.len();
2510 self.output[self.offset..self.offset + len].copy_from_slice(data);
2511 self.offset += len;
2512 }
2513
2514 fn push_attribute_unchecked(&mut self, attr: &dyn AttributeWrite) {
2515 let padded_len = attr.padded_len();
2516 let expected = self.offset + padded_len;
2517 BigEndian::write_u16(
2518 &mut self.output[2..4],
2519 (expected - MessageHeader::LENGTH) as u16,
2520 );
2521 self.attributes.push(attr.get_type());
2522 attr.write_into(&mut self.output[self.offset..self.offset + padded_len])
2523 .unwrap();
2524 self.offset += padded_len;
2525 }
2526
2527 fn finish(self) -> Self::Output {
2528 self.offset
2529 }
2530
2531 fn has_attribute(&self, atype: AttributeType) -> bool {
2532 self.attributes.contains(&atype)
2533 }
2534
2535 fn has_any_attribute(&self, atypes: &[AttributeType]) -> Option<AttributeType> {
2536 self.attributes
2537 .iter()
2538 .find(|&typ| atypes.contains(typ))
2539 .cloned()
2540 }
2541}
2542
2543fn check_attribute_can_fit<O, T: MessageWrite<Output = O> + ?Sized>(
2544 this: &mut T,
2545 attr: &dyn AttributeWrite,
2546) -> Result<usize, StunWriteError> {
2547 let len = attr.padded_len();
2548 let out_data = this.data();
2549 if out_data.len() < MessageHeader::LENGTH {
2550 return Err(StunWriteError::TooSmall {
2551 expected: 20,
2552 actual: out_data.len(),
2553 });
2554 }
2555 let expected = BigEndian::read_u16(&out_data[2..4]) as usize + MessageHeader::LENGTH + len;
2556 if let Some(max) = this.max_size() {
2557 if max < expected {
2558 return Err(StunWriteError::TooSmall {
2559 expected,
2560 actual: max,
2561 });
2562 }
2563 }
2564 Ok(expected)
2565}
2566
2567fn add_message_integrity_unchecked<O, T: MessageWrite<Output = O> + ?Sized>(
2568 this: &mut T,
2569 key: &IntegrityKey,
2570 algorithm: IntegrityAlgorithm,
2571) {
2572 match algorithm {
2575 IntegrityAlgorithm::Sha1 => {
2576 this.push_attribute_unchecked(&MessageIntegrity::new([0; 20]));
2577 let len = this.len();
2578 let data = this.mut_data();
2579 let integrity = MessageIntegrity::compute(&[&data[..len - 24]], key).unwrap();
2580 data[len - 20..].copy_from_slice(&integrity);
2581 }
2582 IntegrityAlgorithm::Sha256 => {
2583 this.push_attribute_unchecked(&MessageIntegritySha256::new(&[0; 32]).unwrap());
2584 let len = this.len();
2585 let data = this.mut_data();
2586 let integrity = MessageIntegritySha256::compute(&[&data[..len - 36]], key).unwrap();
2587 data[len - 32..].copy_from_slice(&integrity);
2588 }
2589 }
2590}
2591
2592fn add_fingerprint_unchecked<O, T: MessageWrite<Output = O> + ?Sized>(this: &mut T) {
2593 this.push_attribute_unchecked(&Fingerprint::new([0; 4]));
2596 let len = this.len();
2597 let data = this.mut_data();
2598 let fingerprint = Fingerprint::compute(&[&data[..len - 8]]);
2599 let fingerprint = Fingerprint::new(fingerprint);
2600 fingerprint.write_into(&mut data[len - 8..]).unwrap();
2601}
2602
2603#[cfg(test)]
2604mod tests {
2605 use alloc::borrow::ToOwned;
2606 use precis_profiles::precis_core::profile::Profile;
2607 use tracing::error;
2608
2609 use super::*;
2610
2611 #[test]
2612 #[should_panic(expected = "Method value is out of range")]
2613 fn method_value_out_of_range() {
2614 let _log = crate::tests::test_init_log();
2615 Method::new(0xf000);
2616 }
2617
2618 #[test]
2619 #[cfg(feature = "std")]
2620 fn method_name() {
2621 let _log = crate::tests::test_init_log();
2622 assert_eq!(BINDING.name(), "BINDING");
2623 let method = Method::new(0x111);
2624 method.add_name("SOME-NAME");
2625 assert_eq!(method.name(), "SOME-NAME");
2626 assert_eq!(Method::new(0x112).name(), "unknown");
2627 }
2628
2629 #[test]
2630 fn msg_type_roundtrip() {
2631 let _log = crate::tests::test_init_log();
2632 for m in 0..0xfff {
2634 let m = Method::new(m);
2635 let classes = vec![
2636 MessageClass::Request,
2637 MessageClass::Indication,
2638 MessageClass::Success,
2639 MessageClass::Error,
2640 ];
2641 for c in classes {
2642 let mtype = MessageType::from_class_method(c, m);
2643 trace!("{mtype}");
2644 assert_eq!(mtype.class(), c);
2645 assert!(mtype.has_class(c));
2646 assert_eq!(mtype.method(), m);
2647 assert!(mtype.has_method(m));
2648 let bytes = mtype.to_bytes();
2649 let ptype = MessageType::from_bytes(&bytes).unwrap();
2650 assert_eq!(mtype, ptype);
2651 }
2652 }
2653 }
2654
2655 #[test]
2656 fn msg_type_not_stun() {
2657 assert!(matches!(
2658 MessageType::from_bytes(&[0xc0, 0x00]),
2659 Err(StunParseError::NotStun)
2660 ));
2661 }
2662
2663 #[test]
2664 fn msg_roundtrip() {
2665 let _log = crate::tests::test_init_log();
2666 for m in (0x009..0x4ff).step_by(0x123) {
2668 let m = Method::new(m);
2669 let classes = vec![
2670 MessageClass::Request,
2671 MessageClass::Indication,
2672 MessageClass::Success,
2673 MessageClass::Error,
2674 ];
2675 for c in classes {
2676 let mtype = MessageType::from_class_method(c, m);
2677 for tid in (0x18..0xff_ffff_ffff_ffff_ffff).step_by(0xfedc_ba98_7654_3210) {
2678 let mut msg = Message::builder(mtype, tid.into(), MessageWriteVec::default());
2679 let attr = RawAttribute::new(1.into(), &[3]);
2680 assert!(msg.add_attribute(&attr).is_ok());
2681 let data = msg.finish();
2682
2683 let msg = Message::from_bytes(&data).unwrap();
2684 let msg_attr = msg.raw_attribute(1.into()).unwrap();
2685 assert_eq!(msg_attr, attr);
2686 assert_eq!(msg.get_type(), mtype);
2687 assert_eq!(msg.transaction_id(), tid.into());
2688 assert_eq!(msg.as_bytes(), &data);
2689 assert_eq!(msg.as_ref(), &data);
2690 }
2691 }
2692 }
2693 }
2694
2695 #[test]
2696 fn unknown_attributes() {
2697 let _log = crate::tests::test_init_log();
2698 let src = Message::builder_request(BINDING, MessageWriteVec::default()).finish();
2699 let src = Message::from_bytes(&src).unwrap();
2700 let msg =
2701 Message::unknown_attributes(&src, &[Software::TYPE], MessageWriteVec::new()).finish();
2702 let msg = Message::from_bytes(&msg).unwrap();
2703 assert_eq!(msg.transaction_id(), src.transaction_id());
2704 assert_eq!(msg.class(), MessageClass::Error);
2705 assert!(msg.has_class(MessageClass::Error));
2706 assert!(!msg.has_class(MessageClass::Success));
2707 assert_eq!(msg.method(), src.method());
2708 assert!(msg.has_method(src.method()));
2709 let err = msg.attribute::<ErrorCode>().unwrap();
2710 assert_eq!(err.code(), 420);
2711 let unknown_attrs = msg.attribute::<UnknownAttributes>().unwrap();
2712 assert!(unknown_attrs.has_attribute(Software::TYPE));
2713 }
2714
2715 #[test]
2716 fn bad_request() {
2717 let _log = crate::tests::test_init_log();
2718 let src = Message::builder_request(BINDING, MessageWriteVec::new()).finish();
2719 let src = Message::from_bytes(&src).unwrap();
2720 let msg = Message::bad_request(&src, MessageWriteVec::new());
2721 assert!(msg.has_class(MessageClass::Error));
2722 assert!(!msg.has_class(MessageClass::Success));
2723 assert!(msg.has_method(src.method()));
2724 assert!(!msg.has_method(Method::new(0x111)));
2725 assert!(msg.is_response());
2726 let msg = msg.finish();
2727 let msg = Message::from_bytes(&msg).unwrap();
2728 assert_eq!(msg.transaction_id(), src.transaction_id());
2729 assert_eq!(msg.class(), MessageClass::Error);
2730 assert_eq!(msg.method(), src.method());
2731 let err = msg.attribute::<ErrorCode>().unwrap();
2732 assert_eq!(err.code(), 400);
2733 }
2734
2735 #[test]
2736 fn fingerprint() {
2737 let _log = crate::tests::test_init_log();
2738 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2739 assert!(msg.has_class(MessageClass::Request));
2740 assert!(!msg.has_class(MessageClass::Success));
2741 assert!(msg.has_method(BINDING));
2742 assert!(!msg.has_method(Method::new(0x111)));
2743 let software = Software::new("s").unwrap();
2744 msg.add_attribute(&software).unwrap();
2745 msg.add_fingerprint().unwrap();
2746 let bytes = msg.finish();
2747 let new_msg = Message::from_bytes(&bytes).unwrap();
2749 let (offset, software) = new_msg.attribute_and_offset::<Software>().unwrap();
2750 assert_eq!(software.software(), "s");
2751 assert_eq!(offset, 20);
2752 let (offset, _new_fingerprint) =
2753 new_msg.raw_attribute_and_offset(Fingerprint::TYPE).unwrap();
2754 assert_eq!(offset, 28);
2755 }
2756
2757 #[test]
2758 fn integrity() {
2759 let _log = crate::tests::test_init_log();
2760 for algorithm in [IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256] {
2761 let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2762 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2763 let software = Software::new("s").unwrap();
2764 msg.add_attribute(&software).unwrap();
2765 msg.add_message_integrity(&credentials, algorithm).unwrap();
2766 let bytes = msg.finish();
2767 let new_msg = Message::from_bytes(&bytes).unwrap();
2769 new_msg.validate_integrity(&credentials).unwrap();
2770 let (offset, software) = new_msg.attribute_and_offset::<Software>().unwrap();
2771 assert_eq!(software.software(), "s");
2772 assert_eq!(offset, 20);
2773 }
2774 }
2775
2776 #[test]
2777 fn write_into_short_destination() {
2778 let _log = crate::tests::test_init_log();
2779 const LEN: usize = MessageHeader::LENGTH + 8;
2780 let mut data = [0; LEN - 1];
2781 let mut msg = Message::builder_request(BINDING, MessageWriteMutSlice::new(&mut data));
2782 let software = Software::new("s").unwrap();
2783 assert!(
2784 matches!(msg.add_attribute(&software), Err(StunWriteError::TooSmall { expected, actual }) if expected == LEN && actual == LEN - 1)
2785 );
2786 }
2787
2788 #[test]
2789 fn integrity_key() {
2790 let _log = crate::tests::test_init_log();
2791 let credentials1 = ShortTermCredentials::new("pass1".to_owned());
2792 let key1 =
2793 MessageIntegrityCredentials::from(credentials1).make_key(IntegrityAlgorithm::Sha1);
2794 let credentials2 = ShortTermCredentials::new("pass2".to_owned());
2795 let key2 =
2796 MessageIntegrityCredentials::from(credentials2).make_key(IntegrityAlgorithm::Sha1);
2797 assert_eq!(key1, key1);
2798 assert_eq!(key2, key2);
2799 assert_ne!(key1, key2);
2800 }
2801
2802 #[test]
2803 fn add_duplicate_integrity() {
2804 let _log = crate::tests::test_init_log();
2805 let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2806 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2807 msg.add_message_integrity(&credentials, IntegrityAlgorithm::Sha1)
2808 .unwrap();
2809 assert!(matches!(
2810 msg.add_message_integrity(&credentials, IntegrityAlgorithm::Sha1),
2811 Err(StunWriteError::AttributeExists(MessageIntegrity::TYPE))
2812 ));
2813 msg.add_message_integrity(&credentials, IntegrityAlgorithm::Sha256)
2814 .unwrap();
2815 assert!(matches!(
2816 msg.add_message_integrity(&credentials, IntegrityAlgorithm::Sha256),
2817 Err(StunWriteError::AttributeExists(
2818 MessageIntegritySha256::TYPE
2819 ))
2820 ));
2821 let software = Software::new("s").unwrap();
2822 assert!(matches!(
2823 msg.add_attribute(&software),
2824 Err(StunWriteError::MessageIntegrityExists)
2825 ));
2826 }
2827
2828 #[test]
2829 fn add_sha1_integrity_after_sha256() {
2830 let _log = crate::tests::test_init_log();
2831 let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2832 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2833 msg.add_message_integrity(&credentials, IntegrityAlgorithm::Sha256)
2834 .unwrap();
2835 assert!(matches!(
2836 msg.add_message_integrity(&credentials, IntegrityAlgorithm::Sha1),
2837 Err(StunWriteError::AttributeExists(
2838 MessageIntegritySha256::TYPE
2839 ))
2840 ));
2841 }
2842
2843 #[test]
2844 fn add_attribute_after_integrity() {
2845 let _log = crate::tests::test_init_log();
2846 for algorithm in [IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256] {
2847 let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2848 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2849 msg.add_message_integrity(&credentials, algorithm).unwrap();
2850 let software = Software::new("s").unwrap();
2851 assert!(matches!(
2852 msg.add_attribute(&software),
2853 Err(StunWriteError::MessageIntegrityExists)
2854 ));
2855 }
2856 }
2857
2858 #[test]
2859 fn add_raw_attribute_after_integrity() {
2860 let _log = crate::tests::test_init_log();
2861 for algorithm in [IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256] {
2862 let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2863 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2864 msg.add_message_integrity(&credentials, algorithm).unwrap();
2865 let software = Software::new("s").unwrap();
2866 let raw = software.to_raw();
2867 assert!(matches!(
2868 msg.add_attribute(&raw),
2869 Err(StunWriteError::MessageIntegrityExists)
2870 ));
2871 }
2872 }
2873
2874 #[test]
2875 fn add_integrity_after_fingerprint() {
2876 let _log = crate::tests::test_init_log();
2877 for algorithm in [IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256] {
2878 let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2879 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2880 msg.add_fingerprint().unwrap();
2881 assert!(matches!(
2882 msg.add_message_integrity(&credentials, algorithm),
2883 Err(StunWriteError::FingerprintExists)
2884 ));
2885 }
2886 }
2887
2888 #[test]
2889 fn duplicate_fingerprint() {
2890 let _log = crate::tests::test_init_log();
2891 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2892 msg.add_fingerprint().unwrap();
2893 assert!(matches!(
2894 msg.add_fingerprint(),
2895 Err(StunWriteError::AttributeExists(Fingerprint::TYPE))
2896 ));
2897 }
2898
2899 #[test]
2900 fn parse_invalid_fingerprint() {
2901 let _log = crate::tests::test_init_log();
2902 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2903 msg.add_fingerprint().unwrap();
2904 let mut bytes = msg.finish();
2905 bytes[24] = 0x80;
2906 bytes[25] = 0x80;
2907 bytes[26] = 0x80;
2908 bytes[27] = 0x80;
2909 assert!(matches!(
2910 Message::from_bytes(&bytes),
2911 Err(StunParseError::FingerprintMismatch)
2912 ));
2913 }
2914
2915 #[test]
2916 fn parse_wrong_magic() {
2917 let _log = crate::tests::test_init_log();
2918 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2919 msg.add_fingerprint().unwrap();
2920 let mut bytes = msg.finish();
2921 bytes[4] = 0x80;
2922 assert!(matches!(
2923 Message::from_bytes(&bytes),
2924 Err(StunParseError::NotStun)
2925 ));
2926 }
2927
2928 #[test]
2929 fn parse_attribute_after_integrity() {
2930 let _log = crate::tests::test_init_log();
2931 for algorithm in [IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256] {
2932 let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2933 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2934 msg.add_message_integrity(&credentials, algorithm).unwrap();
2935 let mut bytes = msg.finish();
2936 let software = Software::new("s").unwrap();
2937 let software_bytes = RawAttribute::from(&software).to_bytes();
2938 let software_len = software_bytes.len();
2939 bytes.extend(software_bytes);
2940 bytes[3] += software_len as u8;
2941 let msg = Message::from_bytes(&bytes).unwrap();
2942 assert!(msg.raw_attribute(Software::TYPE).is_none());
2943 }
2944 }
2945
2946 #[test]
2947 fn parse_duplicate_integrity_after_integrity() {
2948 let _log = crate::tests::test_init_log();
2949 for algorithm in [IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256] {
2950 let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2951 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2952 msg.add_message_integrity(&credentials, algorithm).unwrap();
2953 add_message_integrity_unchecked(
2955 &mut msg,
2956 &credentials.make_key(IntegrityAlgorithm::Sha1),
2957 algorithm,
2958 );
2959 let bytes = msg.finish();
2960 let integrity_type = match algorithm {
2961 IntegrityAlgorithm::Sha1 => MessageIntegrity::TYPE,
2962 IntegrityAlgorithm::Sha256 => MessageIntegritySha256::TYPE,
2963 };
2964 let msg = Message::from_bytes(&bytes).unwrap();
2965 msg.nth_raw_attribute(integrity_type, 0).unwrap();
2966 assert!(msg.nth_raw_attribute(integrity_type, 1).is_none());
2967 }
2968 }
2969
2970 #[test]
2971 fn parse_attribute_after_fingerprint() {
2972 let _log = crate::tests::test_init_log();
2973 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2974 msg.add_fingerprint().unwrap();
2975 let mut bytes = msg.finish();
2976 let software = Software::new("s").unwrap();
2977 let software_bytes = RawAttribute::from(&software).to_bytes();
2978 let software_len = software_bytes.len();
2979 bytes.extend(software_bytes);
2980 bytes[3] += software_len as u8;
2981 let msg = Message::from_bytes(&bytes).unwrap();
2982 assert!(msg.raw_attribute(Fingerprint::TYPE).is_some());
2983 assert!(msg.raw_attribute(Software::TYPE).is_none());
2984 }
2985
2986 #[test]
2987 fn parse_duplicate_fingerprint_after_fingerprint() {
2988 let _log = crate::tests::test_init_log();
2989 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2990 msg.add_fingerprint().unwrap();
2991 add_fingerprint_unchecked(&mut msg);
2992 let bytes = msg.finish();
2993 let msg = Message::from_bytes(&bytes).unwrap();
2994 assert!(msg.nth_raw_attribute(Fingerprint::TYPE, 0).is_some());
2995 assert!(msg.nth_raw_attribute(Fingerprint::TYPE, 1).is_none());
2996 }
2997
2998 #[test]
2999 fn add_attribute_after_fingerprint() {
3000 let _log = crate::tests::test_init_log();
3001 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3002 msg.add_fingerprint().unwrap();
3003 let software = Software::new("s").unwrap();
3004 assert!(matches!(
3005 msg.add_attribute(&software),
3006 Err(StunWriteError::FingerprintExists)
3007 ));
3008 }
3009
3010 #[test]
3011 fn add_raw_attribute_after_fingerprint() {
3012 let _log = crate::tests::test_init_log();
3013 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3014 msg.add_fingerprint().unwrap();
3015 let software = Software::new("s").unwrap();
3016 let raw = software.to_raw();
3017 assert!(matches!(
3018 msg.add_attribute(&raw),
3019 Err(StunWriteError::FingerprintExists)
3020 ));
3021 }
3022
3023 #[test]
3024 fn parse_truncated_message_header() {
3025 let _log = crate::tests::test_init_log();
3026 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3027 msg.add_fingerprint().unwrap();
3028 let bytes = msg.finish();
3029 assert!(matches!(
3030 Message::from_bytes(&bytes[..8]),
3031 Err(StunParseError::Truncated {
3032 expected: 20,
3033 actual: 8
3034 })
3035 ));
3036 }
3037
3038 #[test]
3039 fn parse_truncated_message() {
3040 let _log = crate::tests::test_init_log();
3041 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3042 msg.add_fingerprint().unwrap();
3043 let bytes = msg.finish();
3044 assert!(matches!(
3045 Message::from_bytes(&bytes[..24]),
3046 Err(StunParseError::Truncated {
3047 expected: 28,
3048 actual: 24
3049 })
3050 ));
3051 }
3052
3053 #[test]
3054 fn parse_truncated_message_attribute() {
3055 let _log = crate::tests::test_init_log();
3056 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3057 msg.add_fingerprint().unwrap();
3058 let mut bytes = msg.finish();
3059 bytes[3] = 4;
3061 assert!(matches!(
3062 Message::from_bytes(&bytes[..24]),
3063 Err(StunParseError::Truncated {
3064 expected: 28,
3065 actual: 24
3066 })
3067 ));
3068 }
3069
3070 #[test]
3071 fn parse_attribute_extends_past_message_end() {
3072 let _log = crate::tests::test_init_log();
3073 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3074 msg.add_attribute(&Software::new("a").unwrap()).unwrap();
3075 msg[23] += 1;
3076 let mut bytes = msg.finish();
3077 bytes[3] -= 1;
3078 error!("{bytes:x?}");
3079 error!("{:?}", Message::from_bytes(&bytes[..27]));
3080 assert!(matches!(
3081 Message::from_bytes(&bytes[..27]),
3082 Err(StunParseError::Truncated {
3083 expected: 28,
3084 actual: 27
3085 })
3086 ));
3087 }
3088
3089 #[test]
3090 fn valid_attributes() {
3091 let _log = crate::tests::test_init_log();
3092 let mut src = Message::builder_request(BINDING, MessageWriteVec::new());
3093 let username = Username::new("123").unwrap();
3094 src.add_attribute(&username).unwrap();
3095 let nonce = Nonce::new("nonce").unwrap();
3096 src.add_attribute(&nonce).unwrap();
3097 assert!(!src.has_attribute(Fingerprint::TYPE));
3098 assert!(src.has_attribute(Nonce::TYPE));
3099 let src = src.finish();
3100 let src = Message::from_bytes(&src).unwrap();
3101 assert!(!src.has_attribute(Fingerprint::TYPE));
3102 assert!(src.has_attribute(Nonce::TYPE));
3103
3104 let res = Message::check_attribute_types(
3106 &src,
3107 &[Username::TYPE, Nonce::TYPE],
3108 &[Username::TYPE],
3109 MessageWriteVec::new(),
3110 );
3111 assert!(res.is_none());
3112
3113 let res = Message::check_attribute_types(
3115 &src,
3116 &[Username::TYPE, Nonce::TYPE],
3117 &[Fingerprint::TYPE],
3118 MessageWriteVec::new(),
3119 );
3120 assert!(res.is_some());
3121 let res = res.unwrap();
3122 let res = res.finish();
3123 let res = Message::from_bytes(&res).unwrap();
3124 assert!(res.has_class(MessageClass::Error));
3125 assert!(res.has_method(src.method()));
3126 let err = res.attribute::<ErrorCode>().unwrap();
3127 assert_eq!(err.code(), 400);
3128
3129 let res =
3131 Message::check_attribute_types(&src, &[Username::TYPE], &[], MessageWriteVec::new());
3132 assert!(res.is_some());
3133 let res = res.unwrap();
3134 let data = res.finish();
3135 let res = Message::from_bytes(&data).unwrap();
3136 assert!(res.has_class(MessageClass::Error));
3137 assert!(res.has_method(src.method()));
3138 let err = res.attribute::<ErrorCode>().unwrap();
3139 assert_eq!(err.code(), 420);
3140 let unknown = res.attribute::<UnknownAttributes>().unwrap();
3141 assert!(unknown.has_attribute(Nonce::TYPE));
3142 }
3143
3144 #[test]
3145 fn attributes_iter_with_short_data() {
3146 let _log = crate::tests::test_init_log();
3147 assert_eq!(
3148 MessageAttributesIter::new(&[0x0, 0x1, 0x2, 0x3, 0x4]).next(),
3149 None
3150 );
3151 assert_eq!(
3152 MessageAttributesIter::new(&[
3153 0x0, 0x1, 0x2, 0x3, 0x21, 0x12, 0xa4, 0x42, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf,
3154 0x10, 0x11, 0x12, 0x13, 0x14,
3155 ])
3156 .next(),
3157 None
3158 );
3159 }
3160
3161 #[test]
3162 fn attributes_iter_software_after_fingerprint_ignored() {
3163 let _log = crate::tests::test_init_log();
3164 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3165 msg.add_fingerprint().unwrap();
3166 let mut bytes = msg.finish();
3167 let software = Software::new("s").unwrap();
3168 let software_bytes = RawAttribute::from(&software).to_bytes();
3169 let software_len = software_bytes.len();
3170 bytes.extend(software_bytes);
3171 bytes[3] += software_len as u8;
3172 let mut it = MessageAttributesIter::new(&bytes);
3173 let (_offset, fingerprint) = it.next().unwrap();
3174 assert_eq!(fingerprint.get_type(), Fingerprint::TYPE);
3175 assert_eq!(it.next(), None);
3176 }
3177
3178 #[test]
3179 fn attributes_iter_message_integrities_fingerprint() {
3180 let _log = crate::tests::test_init_log();
3181 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3182 let credentials = ShortTermCredentials::new("pass".to_owned());
3183 msg.add_message_integrity(&credentials.clone().into(), IntegrityAlgorithm::Sha1)
3184 .unwrap();
3185 msg.add_message_integrity(&credentials.clone().into(), IntegrityAlgorithm::Sha256)
3186 .unwrap();
3187 msg.add_fingerprint().unwrap();
3188 let mut bytes = msg.finish();
3189 let software = Software::new("s").unwrap();
3190 let software_bytes = RawAttribute::from(&software).to_bytes();
3191 let software_len = software_bytes.len();
3192 bytes.extend(software_bytes);
3193 bytes[3] += software_len as u8;
3194 let mut it = MessageAttributesIter::new(&bytes);
3195 assert_eq!(it.next().unwrap().1.get_type(), MessageIntegrity::TYPE);
3196 assert_eq!(
3197 it.next().unwrap().1.get_type(),
3198 MessageIntegritySha256::TYPE
3199 );
3200 assert_eq!(it.next().unwrap().1.get_type(), Fingerprint::TYPE);
3201 assert_eq!(it.next(), None);
3202 }
3203
3204 #[test]
3205 fn message_parse_multiple_integrities_fingerprint() {
3206 let _log = crate::tests::test_init_log();
3207 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3208 let credentials = ShortTermCredentials::new("pass".to_owned());
3209 msg.add_message_integrity(&credentials.clone().into(), IntegrityAlgorithm::Sha1)
3210 .unwrap();
3211 msg.add_message_integrity(&credentials.clone().into(), IntegrityAlgorithm::Sha256)
3212 .unwrap();
3213 msg.add_fingerprint().unwrap();
3214 let mut bytes = msg.finish();
3215 let software = Software::new("s").unwrap();
3216 let software_bytes = RawAttribute::from(&software).to_bytes();
3217 let software_len = software_bytes.len();
3218 bytes.extend(software_bytes);
3219 bytes[3] += software_len as u8;
3220 let msg = Message::from_bytes(&bytes).unwrap();
3221 assert!(msg.has_attribute(MessageIntegrity::TYPE));
3222 assert!(msg.has_attribute(MessageIntegritySha256::TYPE));
3223 assert!(!msg.has_attribute(Software::TYPE));
3224 assert_eq!(
3225 msg.validate_integrity(&credentials.clone().into()).unwrap(),
3226 IntegrityAlgorithm::Sha256
3227 );
3228 }
3229
3230 #[test]
3231 fn attributes_iter_fingerprint_after_fingerprint_ignored() {
3232 let _log = crate::tests::test_init_log();
3233 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3234 msg.add_fingerprint().unwrap();
3235 let mut bytes = msg.finish();
3236 let fingerprint = Fingerprint::new([bytes[bytes.len() - 1].wrapping_sub(1); 4]);
3237 let fingerprint_bytes = RawAttribute::from(&fingerprint).to_bytes();
3238 let fingerprint_len = fingerprint_bytes.len();
3239 bytes.extend(fingerprint_bytes);
3240 bytes[3] += fingerprint_len as u8;
3241 let mut it = MessageAttributesIter::new(&bytes);
3242 let (_offset, fingerprint) = it.next().unwrap();
3243 assert_eq!(fingerprint.get_type(), Fingerprint::TYPE);
3244 assert_eq!(it.next(), None);
3245 }
3246
3247 #[test]
3248 fn write_vec_state() {
3249 let _log = crate::tests::test_init_log();
3250 let mut src = Message::builder_request(BINDING, MessageWriteVec::with_capacity(0x10));
3251 assert_eq!(src.len(), 20);
3252 assert_eq!(src[4], 0x21);
3253 let username = Username::new("123").unwrap();
3254 src.add_attribute(&username).unwrap();
3255 let nonce = Nonce::new("nonce").unwrap();
3256 src.add_attribute(&nonce).unwrap();
3257
3258 assert!(src.has_attribute(Username::TYPE));
3259 assert!(src.has_attribute(Nonce::TYPE));
3260 assert_eq!(
3261 src.has_any_attribute(&[Username::TYPE, Nonce::TYPE]),
3262 Some(Username::TYPE)
3263 );
3264 assert_eq!(
3265 src.has_any_attribute(&[Nonce::TYPE, Username::TYPE]),
3266 Some(Username::TYPE)
3267 );
3268 assert!(src.has_class(MessageClass::Request));
3269 assert!(!src.is_response());
3270 assert!(src.has_method(BINDING));
3271 assert!(src.get_type().has_method(BINDING));
3272 assert!(src.get_type().has_class(MessageClass::Request));
3273 assert!(!src.has_method(Method::new(0x111)));
3274 assert!(!src.get_type().has_method(Method::new(0x111)));
3275 assert!(!src.get_type().has_class(MessageClass::Error));
3276 }
3277
3278 #[test]
3279 fn write_mut_slice_success() {
3280 let _log = crate::tests::test_init_log();
3281 let mut data = [0; 64];
3282 let mut src = Message::builder_request(BINDING, MessageWriteMutSlice::new(&mut data));
3283 assert_eq!(src.len(), 20);
3284 assert_eq!(src[4], 0x21);
3285 let username = Username::new("123").unwrap();
3286 src.add_attribute(&username).unwrap();
3287 let nonce = Nonce::new("nonce").unwrap();
3288 src.add_attribute(&nonce).unwrap();
3289 assert!(src.has_attribute(Username::TYPE));
3290 assert_eq!(
3291 src.has_any_attribute(&[Username::TYPE]),
3292 Some(Username::TYPE)
3293 );
3294 assert!(!src.has_attribute(Software::TYPE));
3295 assert_eq!(src.has_any_attribute(&[Realm::TYPE]), None);
3296 assert_eq!(src.mut_data().len(), src.len());
3297 assert_eq!(src.finish(), 40);
3298 let msg = Message::from_bytes(&data[..40]).unwrap();
3299 let u2 = msg.attribute::<Username>().unwrap();
3300 assert_eq!(u2.username(), "123");
3301 let n2 = msg.attribute::<Nonce>().unwrap();
3302 assert_eq!(n2.nonce(), "nonce");
3303 }
3304
3305 #[test]
3306 fn write_mut_slice_too_short() {
3307 let _log = crate::tests::test_init_log();
3308 let mut data = [0; 27];
3309 let mut src = Message::builder_request(BINDING, MessageWriteMutSlice::new(&mut data));
3310 assert!(matches!(
3311 src.add_attribute(&Username::new("123").unwrap()),
3312 Err(StunWriteError::TooSmall {
3313 expected: 28,
3314 actual: 27
3315 })
3316 ));
3317 }
3318
3319 #[test]
3320 #[should_panic(expected = "created from a non-request message")]
3321 fn builder_success_panic() {
3322 let _log = crate::tests::test_init_log();
3323 let msg = Message::builder(
3324 MessageType::from_class_method(MessageClass::Indication, BINDING),
3325 TransactionId::generate(),
3326 MessageWriteVec::new(),
3327 )
3328 .finish();
3329 let msg = Message::from_bytes(&msg).unwrap();
3330 let _builder = Message::builder_success(&msg, MessageWriteVec::new());
3331 }
3332
3333 #[test]
3334 #[should_panic(expected = "created from a non-request message")]
3335 fn builder_error_panic() {
3336 let _log = crate::tests::test_init_log();
3337 let msg = Message::builder(
3338 MessageType::from_class_method(MessageClass::Indication, BINDING),
3339 TransactionId::generate(),
3340 MessageWriteVec::new(),
3341 )
3342 .finish();
3343 let msg = Message::from_bytes(&msg).unwrap();
3344 let _builder = Message::builder_error(&msg, MessageWriteVec::new());
3345 }
3346
3347 #[test]
3348 #[should_panic(expected = "Use add_message_integrity() instead")]
3349 fn builder_add_attribute_integrity_panic() {
3350 let _log = crate::tests::test_init_log();
3351 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3352 let hmac = [2; 20];
3353 let integrity = MessageIntegrity::new(hmac);
3354 msg.add_attribute(&integrity).unwrap();
3355 }
3356
3357 #[test]
3358 #[should_panic(expected = "Use add_message_integrity() instead")]
3359 fn builder_add_raw_attribute_integrity_panic() {
3360 let _log = crate::tests::test_init_log();
3361 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3362 let hmac = [2; 20];
3363 let integrity = MessageIntegrity::new(hmac);
3364 let raw = integrity.to_raw();
3365 msg.add_attribute(&raw).unwrap();
3366 }
3367
3368 #[test]
3369 #[should_panic(expected = "Use add_message_integrity() instead")]
3370 fn builder_add_attribute_integrity_sha256_panic() {
3371 let _log = crate::tests::test_init_log();
3372 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3373 let hmac = [2; 16];
3374 let integrity = MessageIntegritySha256::new(&hmac).unwrap();
3375 msg.add_attribute(&integrity).unwrap();
3376 }
3377
3378 #[test]
3379 #[should_panic(expected = "Use add_message_integrity() instead")]
3380 fn builder_add_raw_attribute_integrity_sha256_panic() {
3381 let _log = crate::tests::test_init_log();
3382 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3383 let hmac = [2; 16];
3384 let integrity = MessageIntegritySha256::new(&hmac).unwrap();
3385 let raw = integrity.to_raw();
3386 msg.add_attribute(&raw).unwrap();
3387 }
3388
3389 #[test]
3390 #[should_panic(expected = "Use add_fingerprint() instead")]
3391 fn builder_add_attribute_fingerprint_panic() {
3392 let _log = crate::tests::test_init_log();
3393 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3394 let fingerprint = [2; 4];
3395 let fingerprint = Fingerprint::new(fingerprint);
3396 msg.add_attribute(&fingerprint).unwrap();
3397 }
3398
3399 #[test]
3400 #[should_panic(expected = "Use add_fingerprint() instead")]
3401 fn builder_add_raw_attribute_fingerprint_panic() {
3402 let _log = crate::tests::test_init_log();
3403 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3404 let fingerprint = [2; 4];
3405 let fingerprint = Fingerprint::new(fingerprint);
3406 let raw = fingerprint.to_raw();
3407 msg.add_attribute(&raw).unwrap();
3408 }
3409
3410 #[test]
3411 fn rfc5769_vector1() {
3412 let _log = crate::tests::test_init_log();
3413 let data = vec![
3415 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, ];
3443 let msg = Message::from_bytes(&data).unwrap();
3444 assert!(msg.has_class(MessageClass::Request));
3445 assert!(msg.has_method(BINDING));
3446 assert_eq!(msg.transaction_id(), 0xb7e7_a701_bc34_d686_fa87_dfae.into());
3447
3448 let mut builder = Message::builder(
3449 MessageType::from_class_method(MessageClass::Request, BINDING),
3450 msg.transaction_id(),
3451 MessageWriteVec::new(),
3452 );
3453
3454 assert!(msg.has_attribute(Software::TYPE));
3456 let raw = msg.raw_attribute(Software::TYPE).unwrap();
3457 assert!(Software::try_from(&raw).is_ok());
3458 let software = Software::try_from(&raw).unwrap();
3459 assert_eq!(software.software(), "STUN test client");
3460 builder.add_attribute(&software).unwrap();
3461
3462 builder
3464 .add_attribute(&RawAttribute::new(0x24.into(), &[0x6e, 0x00, 0x01, 0xff]))
3465 .unwrap();
3466
3467 builder
3469 .add_attribute(&RawAttribute::new(
3470 0x8029.into(),
3471 &[0x93, 0x2f, 0xf9, 0xb1, 0x51, 0x26, 0x3b, 0x36],
3472 ))
3473 .unwrap();
3474
3475 assert!(msg.has_attribute(Username::TYPE));
3477 let raw = msg.raw_attribute(Username::TYPE).unwrap();
3478 assert!(Username::try_from(&raw).is_ok());
3479 let username = Username::try_from(&raw).unwrap();
3480 assert_eq!(username.username(), "evtj:h6vY");
3481 builder.add_attribute(&username).unwrap();
3482
3483 let credentials = MessageIntegrityCredentials::ShortTerm(ShortTermCredentials {
3485 password: "VOkJxbRl1RmTxUk/WvJxBt".to_owned(),
3486 });
3487 assert!(matches!(
3488 msg.validate_integrity(&credentials),
3489 Ok(IntegrityAlgorithm::Sha1)
3490 ));
3491 builder
3492 .add_message_integrity(&credentials, IntegrityAlgorithm::Sha1)
3493 .unwrap();
3494
3495 assert!(msg.has_attribute(Fingerprint::TYPE));
3497 builder.add_fingerprint().unwrap();
3498
3499 let mut msg_data = builder.finish();
3501 msg_data[73] = 0x20;
3503 msg_data[74] = 0x20;
3504 msg_data[75] = 0x20;
3505 assert_eq!(msg_data[..80], data[..80]);
3508 }
3509
3510 #[test]
3511 fn rfc5769_vector2() {
3512 let _log = crate::tests::test_init_log();
3513 let data = vec![
3515 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, ];
3536
3537 let msg = Message::from_bytes(&data).unwrap();
3538 assert!(msg.has_class(MessageClass::Success));
3539 assert!(msg.has_method(BINDING));
3540 assert_eq!(msg.transaction_id(), 0xb7e7_a701_bc34_d686_fa87_dfae.into());
3541 let mut builder = Message::builder(
3542 MessageType::from_class_method(MessageClass::Success, BINDING),
3543 msg.transaction_id(),
3544 MessageWriteVec::new(),
3545 );
3546
3547 assert!(msg.has_attribute(Software::TYPE));
3549 let raw = msg.raw_attribute(Software::TYPE).unwrap();
3550 assert!(Software::try_from(&raw).is_ok());
3551 let software = Software::try_from(&raw).unwrap();
3552 assert_eq!(software.software(), "test vector");
3553 builder.add_attribute(&software).unwrap();
3554
3555 assert!(msg.has_attribute(XorMappedAddress::TYPE));
3557 let raw = msg.raw_attribute(XorMappedAddress::TYPE).unwrap();
3558 assert!(XorMappedAddress::try_from(&raw).is_ok());
3559 let xor_mapped_addres = XorMappedAddress::try_from(&raw).unwrap();
3560 assert_eq!(
3561 xor_mapped_addres.addr(msg.transaction_id()),
3562 "192.0.2.1:32853".parse().unwrap()
3563 );
3564 builder.add_attribute(&xor_mapped_addres).unwrap();
3565
3566 let credentials = MessageIntegrityCredentials::ShortTerm(ShortTermCredentials {
3568 password: "VOkJxbRl1RmTxUk/WvJxBt".to_owned(),
3569 });
3570 let ret = msg.validate_integrity(&credentials);
3571 warn!("{:?}", ret);
3572 assert!(matches!(ret, Ok(IntegrityAlgorithm::Sha1)));
3573 builder
3574 .add_message_integrity(&credentials, IntegrityAlgorithm::Sha1)
3575 .unwrap();
3576
3577 assert!(msg.has_attribute(Fingerprint::TYPE));
3579 builder.add_fingerprint().unwrap();
3580
3581 let mut msg_data = builder.finish();
3583 msg_data[35] = 0x20;
3585 assert_eq!(msg_data[..52], data[..52]);
3586 }
3587
3588 #[test]
3589 fn rfc5769_vector3() {
3590 let _log = crate::tests::test_init_log();
3591 let data = vec![
3593 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, ];
3617
3618 let msg = Message::from_bytes(&data).unwrap();
3619 assert!(msg.has_class(MessageClass::Success));
3620 assert!(msg.has_method(BINDING));
3621 assert_eq!(msg.transaction_id(), 0xb7e7_a701_bc34_d686_fa87_dfae.into());
3622 let mut builder = Message::builder(
3623 MessageType::from_class_method(MessageClass::Success, BINDING),
3624 msg.transaction_id(),
3625 MessageWriteVec::new(),
3626 );
3627
3628 assert!(msg.has_attribute(Software::TYPE));
3630 let raw = msg.raw_attribute(Software::TYPE).unwrap();
3631 assert!(Software::try_from(&raw).is_ok());
3632 let software = Software::try_from(&raw).unwrap();
3633 assert_eq!(software.software(), "test vector");
3634 builder.add_attribute(&software).unwrap();
3635
3636 assert!(msg.has_attribute(XorMappedAddress::TYPE));
3638 let raw = msg.raw_attribute(XorMappedAddress::TYPE).unwrap();
3639 assert!(XorMappedAddress::try_from(&raw).is_ok());
3640 let xor_mapped_addres = XorMappedAddress::try_from(&raw).unwrap();
3641 assert_eq!(
3642 xor_mapped_addres.addr(msg.transaction_id()),
3643 "[2001:db8:1234:5678:11:2233:4455:6677]:32853"
3644 .parse()
3645 .unwrap()
3646 );
3647 builder.add_attribute(&xor_mapped_addres).unwrap();
3648
3649 let credentials = MessageIntegrityCredentials::ShortTerm(ShortTermCredentials {
3651 password: "VOkJxbRl1RmTxUk/WvJxBt".to_owned(),
3652 });
3653 assert!(matches!(
3654 msg.validate_integrity(&credentials),
3655 Ok(IntegrityAlgorithm::Sha1)
3656 ));
3657 builder
3658 .add_message_integrity(&credentials, IntegrityAlgorithm::Sha1)
3659 .unwrap();
3660
3661 assert!(msg.has_attribute(Fingerprint::TYPE));
3663 builder.add_fingerprint().unwrap();
3664
3665 let mut msg_data = builder.finish();
3667 msg_data[35] = 0x20;
3669 assert_eq!(msg_data[..64], data[..64]);
3670 }
3671
3672 #[test]
3673 fn rfc5769_vector4() {
3674 let _log = crate::tests::test_init_log();
3675 let data = vec![
3677 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, ];
3707
3708 let msg = Message::from_bytes(&data).unwrap();
3709 assert!(msg.has_class(MessageClass::Request));
3710 assert!(msg.has_method(BINDING));
3711 assert_eq!(msg.transaction_id(), 0x78ad_3433_c6ad_72c0_29da_412e.into());
3712 let mut builder = Message::builder(
3713 MessageType::from_class_method(MessageClass::Request, BINDING),
3714 msg.transaction_id(),
3715 MessageWriteVec::new(),
3716 );
3717
3718 let username = stringprep::saslprep("\u{30DE}\u{30C8}\u{30EA}\u{30C3}\u{30AF}\u{30B9}")
3719 .unwrap()
3720 .into_owned();
3721 let password = stringprep::saslprep("The\u{00AD}M\u{00AA}tr\u{2168}")
3722 .unwrap()
3723 .into_owned();
3724 trace!("password: {password:?}");
3725
3726 let long_term = LongTermKeyCredentials {
3727 username,
3728 password,
3729 realm: "example.org".to_owned(),
3730 };
3731 assert!(msg.has_attribute(Username::TYPE));
3733 let raw = msg.raw_attribute(Username::TYPE).unwrap();
3734 assert!(Username::try_from(&raw).is_ok());
3735 let username = Username::try_from(&raw).unwrap();
3736 assert_eq!(username.username(), &long_term.username);
3737 builder.add_attribute(&username).unwrap();
3738
3739 let expected_nonce = "f//499k954d6OL34oL9FSTvy64sA";
3741 assert!(msg.has_attribute(Nonce::TYPE));
3742 let raw = msg.raw_attribute(Nonce::TYPE).unwrap();
3743 assert!(Nonce::try_from(&raw).is_ok());
3744 let nonce = Nonce::try_from(&raw).unwrap();
3745 assert_eq!(nonce.nonce(), expected_nonce);
3746 builder.add_attribute(&nonce).unwrap();
3747
3748 assert!(msg.has_attribute(Realm::TYPE));
3750 let raw = msg.raw_attribute(Realm::TYPE).unwrap();
3751 assert!(Realm::try_from(&raw).is_ok());
3752 let realm = Realm::try_from(&raw).unwrap();
3753 assert_eq!(realm.realm(), long_term.realm());
3754 builder.add_attribute(&realm).unwrap();
3755
3756 let credentials = MessageIntegrityCredentials::LongTerm(long_term);
3758 assert!(matches!(
3759 msg.validate_integrity(&credentials),
3760 Ok(IntegrityAlgorithm::Sha1)
3761 ));
3762 builder
3763 .add_message_integrity(&credentials, IntegrityAlgorithm::Sha1)
3764 .unwrap();
3765
3766 assert_eq!(builder.finish()[4..], data[4..]);
3767 }
3768
3769 #[test]
3770 fn rfc8489_vector1() {
3771 let _log = crate::tests::test_init_log();
3772 let data = vec![
3775 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, ];
3817 let msg = Message::from_bytes(&data).unwrap();
3818 assert!(msg.has_class(MessageClass::Request));
3819 assert!(msg.has_method(BINDING));
3820 assert_eq!(msg.transaction_id(), 0x78ad_3433_c6ad_72c0_29da_412e.into());
3821 let mut builder = Message::builder(
3822 MessageType::from_class_method(MessageClass::Request, BINDING),
3823 msg.transaction_id(),
3824 MessageWriteVec::new(),
3825 );
3826
3827 let opaque = precis_profiles::OpaqueString::new();
3828 let username = opaque
3829 .prepare("\u{30DE}\u{30C8}\u{30EA}\u{30C3}\u{30AF}\u{30B9}")
3830 .unwrap()
3831 .into_owned();
3832 let orig_password = "The\u{00AD}M\u{00AA}tr\u{2168}";
3833 trace!("password: {orig_password:?}");
3834 let sasl_password = stringprep::saslprep(orig_password).unwrap().into_owned();
3857 trace!("password (saslprep): {sasl_password}");
3858
3859 let long_term = LongTermKeyCredentials {
3862 username: username.clone(),
3863 password: sasl_password.clone(),
3864 realm: "example.org".to_owned(),
3865 };
3866 assert!(msg.has_attribute(Userhash::TYPE));
3868 let raw = msg.raw_attribute(Userhash::TYPE).unwrap();
3869 assert!(Userhash::try_from(&raw).is_ok());
3870 let userhash = Userhash::try_from(&raw).unwrap();
3871 builder.add_attribute(&userhash).unwrap();
3872
3873 let expected_nonce = "obMatJos2AAACf//499k954d6OL34oL9FSTvy64sA";
3875 assert!(msg.has_attribute(Nonce::TYPE));
3876 let raw = msg.raw_attribute(Nonce::TYPE).unwrap();
3877 assert!(Nonce::try_from(&raw).is_ok());
3878 let nonce = Nonce::try_from(&raw).unwrap();
3879 assert_eq!(nonce.nonce(), expected_nonce);
3880 builder.add_attribute(&nonce).unwrap();
3881
3882 assert!(msg.has_attribute(Realm::TYPE));
3884 let raw = msg.raw_attribute(Realm::TYPE).unwrap();
3885 assert!(Realm::try_from(&raw).is_ok());
3886 let realm = Realm::try_from(&raw).unwrap();
3887 assert_eq!(realm.realm(), long_term.realm);
3888 builder.add_attribute(&realm).unwrap();
3889
3890 assert!(msg.has_attribute(PasswordAlgorithm::TYPE));
3892 let raw = msg.raw_attribute(PasswordAlgorithm::TYPE).unwrap();
3893 assert!(PasswordAlgorithm::try_from(&raw).is_ok());
3894 let algo = PasswordAlgorithm::try_from(&raw).unwrap();
3895 assert_eq!(algo.algorithm(), PasswordAlgorithmValue::SHA256);
3896 builder.add_attribute(&algo).unwrap();
3897
3898 trace!("long term: {long_term:?}");
3919 let credentials = MessageIntegrityCredentials::LongTerm(long_term);
3920 assert!(matches!(
3921 msg.validate_integrity(&credentials),
3922 Ok(IntegrityAlgorithm::Sha256)
3923 ));
3924 builder
3925 .add_message_integrity(&credentials, IntegrityAlgorithm::Sha256)
3926 .unwrap();
3927
3928 assert_eq!(builder.finish()[4..], data[4..]);
3929 }
3930}