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;
96use core::num::NonZeroUsize;
97#[cfg(feature = "std")]
98use std::sync::{Mutex, OnceLock};
99
100use byteorder::{BigEndian, ByteOrder};
101
102use crate::attribute::*;
103
104use tracing::{debug, trace, warn};
105
106use hmac::digest::core_api::CoreWrapper;
107use hmac::digest::CtOutput;
108use hmac::HmacCore;
109
110pub const MAGIC_COOKIE: u32 = 0x2112A442;
112
113#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
115pub struct Method(u16);
116
117impl core::fmt::Display for Method {
118 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
119 write!(f, "{}({:#x}: {})", self.0, self.0, self.name())
120 }
121}
122
123#[cfg(feature = "std")]
124static METHOD_NAME_MAP: OnceLock<Mutex<BTreeMap<Method, &'static str>>> = OnceLock::new();
125
126impl Method {
127 #[cfg(feature = "std")]
129 pub fn add_name(self, name: &'static str) {
130 let mut mnames = METHOD_NAME_MAP
131 .get_or_init(Default::default)
132 .lock()
133 .unwrap();
134 mnames.insert(self, name);
135 }
136
137 pub const fn new(val: u16) -> Self {
149 if val >= 0xf000 {
150 panic!("Method value is out of range!");
151 }
152 Self(val)
153 }
154
155 pub fn value(&self) -> u16 {
165 self.0
166 }
167
168 pub fn name(self) -> &'static str {
176 match self {
177 BINDING => "BINDING",
178 _ => {
179 #[cfg(feature = "std")]
180 {
181 let mnames = METHOD_NAME_MAP
182 .get_or_init(Default::default)
183 .lock()
184 .unwrap();
185 if let Some(name) = mnames.get(&self) {
186 return name;
187 }
188 }
189 "unknown"
190 }
191 }
192 }
193}
194
195pub const BINDING: Method = Method::new(0x0001);
198
199#[derive(Debug, thiserror::Error, Clone, Copy, PartialEq, Eq)]
201#[non_exhaustive]
202pub enum StunParseError {
203 #[error("The provided data is not a STUN message")]
205 NotStun,
206 #[error("Not enough data available to parse the packet, expected {}, actual {}", .expected, .actual)]
208 Truncated {
209 expected: usize,
211 actual: usize,
213 },
214 #[error("Too many bytes for this data, expected {}, actual {}", .expected, .actual)]
216 TooLarge {
217 expected: usize,
219 actual: usize,
221 },
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, thiserror::Error, Copy, Clone)]
291pub enum ValidateError {
292 #[error("The message failed to parse the relevant integrity attributes")]
294 Parse(StunParseError),
295 #[error("The message failed integrity checks")]
297 IntegrityFailed,
298}
299
300impl From<StunParseError> for ValidateError {
301 fn from(value: StunParseError) -> Self {
302 Self::Parse(value)
303 }
304}
305
306#[derive(Debug, Clone, PartialEq, Eq)]
308#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
309pub struct LongTermCredentials {
310 username: String,
311 password: String,
312}
313
314impl LongTermCredentials {
315 pub fn new(username: String, password: String) -> Self {
329 Self { username, password }
330 }
331
332 pub fn username(&self) -> &str {
334 &self.username
335 }
336
337 pub fn password(&self) -> &str {
339 &self.password
340 }
341
342 pub fn to_key(&self, realm: String) -> LongTermKeyCredentials {
344 LongTermKeyCredentials {
345 username: self.username.clone(),
346 password: self.password.clone(),
347 realm,
348 }
349 }
350}
351
352#[derive(Debug, Clone, PartialEq, Eq)]
354#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
355pub struct LongTermKeyCredentials {
356 username: String,
357 password: String,
358 realm: String,
359}
360
361impl LongTermKeyCredentials {
362 pub fn new(username: String, password: String, realm: String) -> Self {
378 Self {
379 username,
380 password,
381 realm,
382 }
383 }
384
385 pub fn username(&self) -> &str {
387 &self.username
388 }
389
390 pub fn password(&self) -> &str {
392 &self.password
393 }
394
395 pub fn realm(&self) -> &str {
397 &self.realm
398 }
399
400 pub fn make_key(&self, algorithm: IntegrityAlgorithm) -> IntegrityKey {
402 match algorithm {
403 IntegrityAlgorithm::Sha1 => {
404 use md5::{Digest, Md5};
405 let mut digest = Md5::new();
406 digest.update(self.username.as_bytes());
407 digest.update(":".as_bytes());
408 digest.update(self.realm.as_bytes());
409 digest.update(":".as_bytes());
410 digest.update(self.password.as_bytes());
411 IntegrityKey::new_with_algo(IntegrityAlgorithm::Sha1, digest.finalize().to_vec())
412 }
413 IntegrityAlgorithm::Sha256 => {
414 use sha2::{Digest, Sha256};
415 let mut digest = Sha256::new();
416 digest.update(self.username.as_bytes());
417 digest.update(":".as_bytes());
418 digest.update(self.realm.as_bytes());
419 digest.update(":".as_bytes());
420 digest.update(self.password.as_bytes());
421 IntegrityKey::new_with_algo(IntegrityAlgorithm::Sha256, digest.finalize().to_vec())
422 }
423 }
424 }
425}
426
427#[derive(Debug, Clone, PartialEq, Eq)]
429#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
430pub struct ShortTermCredentials {
431 password: String,
432}
433
434impl ShortTermCredentials {
435 pub fn new(password: String) -> Self {
445 Self { password }
446 }
447
448 pub fn password(&self) -> &str {
450 &self.password
451 }
452
453 pub fn make_key(&self) -> IntegrityKey {
455 IntegrityKey::new(self.password.as_bytes().to_vec())
456 }
457}
458
459#[derive(Debug, Clone, PartialEq, Eq)]
463#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
464pub enum MessageIntegrityCredentials {
465 ShortTerm(ShortTermCredentials),
467 LongTerm(LongTermKeyCredentials),
469}
470
471impl From<LongTermKeyCredentials> for MessageIntegrityCredentials {
472 fn from(value: LongTermKeyCredentials) -> Self {
473 MessageIntegrityCredentials::LongTerm(value)
474 }
475}
476
477impl From<ShortTermCredentials> for MessageIntegrityCredentials {
478 fn from(value: ShortTermCredentials) -> Self {
479 MessageIntegrityCredentials::ShortTerm(value)
480 }
481}
482
483impl MessageIntegrityCredentials {
484 pub fn make_key(&self, algorithm: IntegrityAlgorithm) -> IntegrityKey {
486 match self {
487 MessageIntegrityCredentials::ShortTerm(short) => short.make_key(),
488 MessageIntegrityCredentials::LongTerm(long) => long.make_key(algorithm),
489 }
490 }
491}
492
493type HmacSha1 = hmac::Hmac<sha1::Sha1>;
494type HmacSha256 = hmac::Hmac<sha2::Sha256>;
495
496#[derive(Debug, Clone)]
498pub struct IntegrityKey {
499 key_algorithm: Option<IntegrityAlgorithm>,
500 bytes: Vec<u8>,
501 #[cfg(feature = "std")]
502 sha1: Arc<Mutex<Option<HmacSha1>>>,
503 #[cfg(feature = "std")]
504 sha256: Arc<Mutex<Option<HmacSha256>>>,
505}
506
507impl PartialEq<IntegrityKey> for IntegrityKey {
508 fn eq(&self, other: &Self) -> bool {
509 self.bytes == other.bytes
510 }
511}
512
513impl Eq for IntegrityKey {}
514
515impl IntegrityKey {
516 fn new(bytes: Vec<u8>) -> Self {
517 Self {
518 key_algorithm: None,
519 bytes,
520 #[cfg(feature = "std")]
521 sha1: Default::default(),
522 #[cfg(feature = "std")]
523 sha256: Default::default(),
524 }
525 }
526 fn new_with_algo(key_algorithm: IntegrityAlgorithm, bytes: Vec<u8>) -> Self {
527 let mut ret = Self::new(bytes);
528 ret.key_algorithm = Some(key_algorithm);
529 ret
530 }
531 pub(crate) fn as_bytes(&self) -> &[u8] {
532 &self.bytes
533 }
534
535 pub(crate) fn verify_sha1(&self, data: &[&[u8]], expected: &[u8]) -> bool {
536 if self
537 .key_algorithm
538 .is_some_and(|algo| algo != IntegrityAlgorithm::Sha1)
539 {
540 return false;
541 }
542 use hmac::digest::Output;
543 let computed = self.compute_sha1(data);
544 #[allow(deprecated)]
546 {
547 computed == Output::<sha1::Sha1Core>::from_slice(expected).into()
548 }
549 }
550
551 pub(crate) fn compute_sha1(
552 &self,
553 data: &[&[u8]],
554 ) -> CtOutput<CoreWrapper<HmacCore<CoreWrapper<sha1::Sha1Core>>>> {
555 use hmac::Mac;
556 #[cfg(feature = "std")]
557 let mut sha1 = self.sha1.lock().unwrap();
558 #[cfg(feature = "std")]
559 let hmac = sha1.get_or_insert_with(|| HmacSha1::new_from_slice(self.as_bytes()).unwrap());
560 #[cfg(not(feature = "std"))]
561 let mut hmac = HmacSha1::new_from_slice(self.as_bytes()).unwrap();
562
563 for data in data {
564 hmac.update(data);
565 }
566 #[cfg(feature = "std")]
567 let ret = hmac.finalize_reset();
568 #[cfg(not(feature = "std"))]
569 let ret = hmac.finalize();
570 ret
571 }
572
573 pub(crate) fn verify_sha256(&self, data: &[&[u8]], expected: &[u8]) -> bool {
574 use subtle::ConstantTimeEq;
575 if self
576 .key_algorithm
577 .is_some_and(|algo| algo != IntegrityAlgorithm::Sha256)
578 {
579 return false;
580 }
581 if expected.is_empty() {
582 return false;
583 }
584 let computed = self.compute_sha256(data);
585 if computed.len() < expected.len() {
586 return false;
587 }
588 computed[..expected.len()].ct_eq(expected).into()
589 }
590
591 pub(crate) fn compute_sha256(&self, data: &[&[u8]]) -> [u8; 32] {
592 trace!("computing sha256 using {data:?}");
593 use hmac::Mac;
594 #[cfg(feature = "std")]
595 let mut sha256 = self.sha256.lock().unwrap();
596 #[cfg(feature = "std")]
597 let hmac =
598 sha256.get_or_insert_with(|| HmacSha256::new_from_slice(self.as_bytes()).unwrap());
599 #[cfg(not(feature = "std"))]
600 let mut hmac = HmacSha256::new_from_slice(self.as_bytes()).unwrap();
601
602 for data in data {
603 hmac.update(data);
604 }
605 #[cfg(feature = "std")]
606 let ret = hmac.finalize_reset();
607 #[cfg(not(feature = "std"))]
608 let ret = hmac.finalize();
609 ret.into_bytes().into()
610 }
611}
612
613#[derive(Copy, Clone, Debug, PartialEq, Eq)]
625pub enum MessageClass {
626 Request,
628 Indication,
630 Success,
632 Error,
634}
635
636impl MessageClass {
637 pub fn is_response(self) -> bool {
640 matches!(self, MessageClass::Success | MessageClass::Error)
641 }
642
643 fn to_bits(self) -> u16 {
644 match self {
645 MessageClass::Request => 0x000,
646 MessageClass::Indication => 0x010,
647 MessageClass::Success => 0x100,
648 MessageClass::Error => 0x110,
649 }
650 }
651}
652
653#[derive(Copy, Clone, Debug, PartialEq, Eq)]
655pub struct MessageType(u16);
656
657impl core::fmt::Display for MessageType {
658 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
659 write!(
660 f,
661 "MessageType(class: {:?}, method: {}",
662 self.class(),
663 self.method(),
664 )
665 }
666}
667
668impl MessageType {
669 pub fn from_class_method(class: MessageClass, method: Method) -> Self {
680 let class_bits = MessageClass::to_bits(class);
681 let method = method.value();
682 let method_bits = method & 0xf | (method & 0x70) << 1 | (method & 0xf80) << 2;
683 Self(class_bits | method_bits)
686 }
687
688 pub fn class(self) -> MessageClass {
698 let class = (self.0 & 0x10) >> 4 | (self.0 & 0x100) >> 7;
699 match class {
700 0x0 => MessageClass::Request,
701 0x1 => MessageClass::Indication,
702 0x2 => MessageClass::Success,
703 0x3 => MessageClass::Error,
704 _ => unreachable!(),
705 }
706 }
707
708 pub fn has_class(self, cls: MessageClass) -> bool {
718 self.class() == cls
719 }
720
721 pub fn is_response(self) -> bool {
737 self.class().is_response()
738 }
739
740 pub fn method(self) -> Method {
750 Method::new(self.0 & 0xf | (self.0 & 0xe0) >> 1 | (self.0 & 0x3e00) >> 2)
751 }
752
753 pub fn has_method(self, method: Method) -> bool {
763 self.method() == method
764 }
765
766 pub fn write_into(&self, dest: &mut [u8]) {
768 BigEndian::write_u16(dest, self.0);
769 }
770
771 pub fn to_bytes(self) -> Vec<u8> {
773 let mut ret = vec![0; 2];
774 BigEndian::write_u16(&mut ret[0..2], self.0);
775 ret
776 }
777
778 pub fn from_bytes(data: &[u8]) -> Result<Self, StunParseError> {
780 let data = BigEndian::read_u16(data);
781 if data & 0xc000 != 0x0 {
782 return Err(StunParseError::NotStun);
784 }
785 Ok(Self(data))
786 }
787}
788impl TryFrom<&[u8]> for MessageType {
789 type Error = StunParseError;
790
791 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
792 MessageType::from_bytes(value)
793 }
794}
795
796#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
798pub struct TransactionId {
799 id: u128,
800}
801
802impl TransactionId {
803 pub fn generate() -> TransactionId {
805 #[cfg(not(feature = "std"))]
806 {
807 use rand::TryRngCore;
808 let mut dest = [0; 16];
809 rand::rngs::OsRng
810 .try_fill_bytes(&mut dest)
811 .expect("Cannot generate random data");
812 u128::from_be_bytes(dest).into()
813 }
814 #[cfg(feature = "std")]
815 {
816 use rand::Rng;
817 let mut rng = rand::rng();
818 rng.random::<u128>().into()
819 }
820 }
821}
822
823impl From<u128> for TransactionId {
824 fn from(id: u128) -> Self {
825 Self {
826 id: id & 0xffff_ffff_ffff_ffff_ffff_ffff,
827 }
828 }
829}
830impl From<TransactionId> for u128 {
831 fn from(id: TransactionId) -> Self {
832 id.id
833 }
834}
835impl core::fmt::Display for TransactionId {
836 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
837 write!(f, "{:#x}", self.id)
838 }
839}
840
841#[derive(Debug)]
847pub struct MessageHeader {
848 mtype: MessageType,
849 transaction_id: TransactionId,
850 length: u16,
851}
852
853impl MessageHeader {
854 pub const LENGTH: usize = 20;
856
857 pub fn from_bytes(data: &[u8]) -> Result<Self, StunParseError> {
887 if data.len() < 20 {
888 if data.first().is_some_and(|&b| b & 0xc0 != 0) {
890 return Err(StunParseError::NotStun);
892 }
893 let cookie = &data[data.len().min(4)..data.len().min(8)];
894 let magic = MAGIC_COOKIE.to_be_bytes();
895 if cookie != &magic[..cookie.len()] {
896 debug!(
897 "malformed cookie constant {:?} != stored data {:?}",
898 &magic[..cookie.len()],
899 cookie
900 );
901 return Err(StunParseError::NotStun);
902 }
903 return Err(StunParseError::Truncated {
904 expected: 20,
905 actual: data.len(),
906 });
907 }
908 let mtype = MessageType::from_bytes(data)?;
909 let mlength = BigEndian::read_u16(&data[2..]);
910 let tid = BigEndian::read_u128(&data[4..]);
911 let cookie = (tid >> 96) as u32;
912 if cookie != MAGIC_COOKIE {
913 debug!(
914 "malformed cookie constant {:?} != stored data {:?}",
915 MAGIC_COOKIE, cookie
916 );
917 return Err(StunParseError::NotStun);
918 }
919
920 Ok(Self {
921 mtype,
922 transaction_id: tid.into(),
923 length: mlength,
924 })
925 }
926
927 pub fn data_length(&self) -> u16 {
930 self.length
931 }
932
933 pub fn transaction_id(&self) -> TransactionId {
935 self.transaction_id
936 }
937
938 pub fn get_type(&self) -> MessageType {
940 self.mtype
941 }
942
943 fn new(mtype: MessageType, transaction_id: TransactionId, length: u16) -> Self {
944 Self {
945 mtype,
946 transaction_id,
947 length,
948 }
949 }
950
951 fn write_into(&self, dest: &mut [u8]) {
952 self.mtype.write_into(&mut dest[..2]);
953 let transaction: u128 = self.transaction_id.into();
954 let tid = (MAGIC_COOKIE as u128) << 96 | transaction & 0xffff_ffff_ffff_ffff_ffff_ffff;
955 BigEndian::write_u128(&mut dest[4..20], tid);
956 BigEndian::write_u16(&mut dest[2..4], self.length);
957 }
958}
959
960#[derive(Debug, Clone, Copy)]
965pub struct Message<'a> {
966 data: &'a [u8],
967 integrity_offset: Option<NonZeroUsize>,
968}
969
970impl core::fmt::Display for Message<'_> {
971 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
972 write!(
973 f,
974 "Message(class: {:?}, method: {}, transaction: {}, attributes: ",
975 self.get_type().class(),
976 self.get_type().method(),
977 self.transaction_id()
978 )?;
979 let iter = self.iter_attributes();
980 write!(f, "[")?;
981 for (i, (_offset, a)) in iter.enumerate() {
982 if i > 0 {
983 write!(f, ", ")?;
984 }
985 write!(f, "{a}")?;
986 }
987 write!(f, "]")?;
988 write!(f, ")")
989 }
990}
991
992#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
994pub enum IntegrityAlgorithm {
995 Sha1,
997 Sha256,
999}
1000
1001impl<'a> Message<'a> {
1002 pub fn builder<B: MessageWrite>(
1018 mtype: MessageType,
1019 transaction_id: TransactionId,
1020 mut write: B,
1021 ) -> B {
1022 let mut data = [0; 20];
1023 MessageHeader::new(mtype, transaction_id, 0).write_into(&mut data);
1024 write.push_data(&data);
1025 write
1026 }
1027
1028 pub fn builder_request<B: MessageWrite>(method: Method, write: B) -> B {
1042 Message::builder(
1043 MessageType::from_class_method(MessageClass::Request, method),
1044 TransactionId::generate(),
1045 write,
1046 )
1047 }
1048
1049 pub fn builder_success<B: MessageWrite>(orig: &Message, write: B) -> B {
1069 if !orig.has_class(MessageClass::Request) {
1070 panic!(
1071 "A success response message was attempted to be created from a non-request message"
1072 );
1073 }
1074 Message::builder(
1075 MessageType::from_class_method(MessageClass::Success, orig.method()),
1076 orig.transaction_id(),
1077 write,
1078 )
1079 }
1080
1081 pub fn builder_error<B: MessageWrite>(orig: &Message, write: B) -> B {
1101 if !orig.has_class(MessageClass::Request) {
1102 panic!(
1103 "An error response message was attempted to be created from a non-request message"
1104 );
1105 }
1106 Message::builder(
1107 MessageType::from_class_method(MessageClass::Error, orig.method()),
1108 orig.transaction_id(),
1109 write,
1110 )
1111 }
1112
1113 pub fn builder_indication<B: MessageWrite>(method: Method, write: B) -> B {
1127 Message::builder(
1128 MessageType::from_class_method(MessageClass::Indication, method),
1129 TransactionId::generate(),
1130 write,
1131 )
1132 }
1133
1134 pub fn get_type(&self) -> MessageType {
1148 MessageType::try_from(&self.data[..2]).unwrap()
1149 }
1150
1151 pub fn class(&self) -> MessageClass {
1163 self.get_type().class()
1164 }
1165
1166 pub fn has_class(&self, cls: MessageClass) -> bool {
1178 self.class() == cls
1179 }
1180
1181 pub fn is_response(&self) -> bool {
1203 self.class().is_response()
1204 }
1205
1206 pub fn method(&self) -> Method {
1218 self.get_type().method()
1219 }
1220
1221 pub fn has_method(&self, method: Method) -> bool {
1234 self.method() == method
1235 }
1236
1237 pub fn transaction_id(&self) -> TransactionId {
1251 BigEndian::read_u128(&self.data[4..]).into()
1252 }
1253
1254 #[tracing::instrument(
1276 name = "message_from_bytes",
1277 level = "trace",
1278 skip(data),
1279 fields(
1280 data.len = data.len()
1281 )
1282 )]
1283 pub fn from_bytes(data: &'a [u8]) -> Result<Self, StunParseError> {
1284 let orig_data = data;
1285
1286 let header = MessageHeader::from_bytes(data)?;
1287 let mlength = header.data_length() as usize;
1288 if mlength + MessageHeader::LENGTH > data.len() {
1289 warn!(
1291 "malformed advertised size {} and data size {} don't match",
1292 mlength + 20,
1293 data.len()
1294 );
1295 return Err(StunParseError::Truncated {
1296 expected: mlength + MessageHeader::LENGTH,
1297 actual: data.len(),
1298 });
1299 }
1300
1301 let ending_attributes = [
1302 MessageIntegrity::TYPE,
1303 MessageIntegritySha256::TYPE,
1304 Fingerprint::TYPE,
1305 ];
1306 let mut seen_ending_attributes = [AttributeType::new(0); 3];
1308 let mut seen_ending_len = 0;
1309 let mut data_offset = MessageHeader::LENGTH;
1310 let mut integrity_offset = None;
1311 for attr in MessageRawAttributesIter::new(data) {
1312 let (_offset, attr) = attr.inspect_err(|e| {
1313 warn!("failed to parse message attribute at offset {data_offset}: {e}",);
1314 })?;
1315
1316 if seen_ending_len > 0 && !ending_attributes.contains(&attr.get_type()) {
1319 if seen_ending_attributes.contains(&Fingerprint::TYPE) {
1320 warn!("unexpected attribute {} after FINGERPRINT", attr.get_type());
1321 return Ok(Message {
1322 data: orig_data,
1323 integrity_offset,
1324 });
1325 } else {
1326 warn!(
1328 "unexpected attribute {} after MESSAGE_INTEGRITY",
1329 attr.get_type()
1330 );
1331 return Ok(Message {
1332 data: orig_data,
1333 integrity_offset,
1334 });
1335 }
1336 }
1337
1338 if ending_attributes.contains(&attr.get_type()) {
1339 if seen_ending_attributes.contains(&attr.get_type()) {
1340 if seen_ending_attributes.contains(&Fingerprint::TYPE) {
1341 warn!("unexpected attribute {} after FINGERPRINT", attr.get_type());
1342 return Ok(Message {
1343 data: orig_data,
1344 integrity_offset,
1345 });
1346 } else {
1347 warn!(
1349 "unexpected attribute {} after MESSAGE_INTEGRITY",
1350 attr.get_type()
1351 );
1352 return Ok(Message {
1353 data: orig_data,
1354 integrity_offset,
1355 });
1356 }
1357 } else {
1358 seen_ending_attributes[seen_ending_len] = attr.get_type();
1359 seen_ending_len += 1;
1360 integrity_offset.get_or_insert(NonZeroUsize::new(data_offset).unwrap());
1361 }
1363 }
1364 let padded_len = attr.padded_len();
1365 if attr.get_type() == Fingerprint::TYPE {
1366 let f = Fingerprint::from_raw_ref(&attr)?;
1367 let msg_fingerprint = f.fingerprint();
1368 let mut header = [0; 4];
1369 header[0] = orig_data[0];
1370 header[1] = orig_data[1];
1371 BigEndian::write_u16(
1372 &mut header[2..4],
1373 (data_offset + padded_len - MessageHeader::LENGTH) as u16,
1374 );
1375 let fingerprint_data = &orig_data[4..data_offset];
1376 let calculated_fingerprint = Fingerprint::compute(&[&header, fingerprint_data]);
1377 if &calculated_fingerprint != msg_fingerprint {
1378 warn!(
1379 "fingerprint mismatch {:?} != {:?}",
1380 calculated_fingerprint, msg_fingerprint
1381 );
1382 return Err(StunParseError::FingerprintMismatch);
1383 }
1384 }
1385 data_offset += padded_len;
1386 }
1387 Ok(Message {
1388 data: orig_data,
1389 integrity_offset,
1390 })
1391 }
1392
1393 pub fn validate_integrity(
1413 &self,
1414 credentials: &MessageIntegrityCredentials,
1415 ) -> Result<IntegrityAlgorithm, ValidateError> {
1416 let offset = self
1417 .integrity_offset
1418 .ok_or(ValidateError::Parse(StunParseError::MissingAttribute(
1419 MessageIntegrity::TYPE,
1420 )))?
1421 .get();
1422
1423 let iter = MessageAttributesIter::at_offset(self.data, offset);
1424 let mut raw_sha1 = None;
1425 let mut raw_sha256 = None;
1426 for (offset, raw_attr) in iter {
1427 match raw_attr.get_type() {
1428 MessageIntegrity::TYPE => {
1429 raw_sha1 = Some((offset, raw_attr));
1430 }
1431 MessageIntegritySha256::TYPE => {
1432 raw_sha256 = Some((offset, raw_attr));
1433 }
1434 _ => (),
1435 }
1436 }
1437
1438 let integrity_sha1;
1439 let integrity_sha256;
1440 let (algo, msg_hmac, offset) = match (raw_sha1, raw_sha256) {
1441 (_, Some((offset, sha256))) => {
1442 integrity_sha256 = MessageIntegritySha256::try_from(&sha256)?;
1443 (IntegrityAlgorithm::Sha256, integrity_sha256.hmac(), offset)
1444 }
1445 (Some((offset, sha1)), None) => {
1446 integrity_sha1 = MessageIntegrity::try_from(&sha1)?;
1447 (
1448 IntegrityAlgorithm::Sha1,
1449 integrity_sha1.hmac().as_slice(),
1450 offset,
1451 )
1452 }
1453 (None, None) => {
1454 return Err(StunParseError::MissingAttribute(MessageIntegrity::TYPE).into())
1455 }
1456 };
1457 let key = credentials.make_key(algo);
1458 self.validate_integrity_with_hmac(algo, msg_hmac, &key, offset)
1459 }
1460
1461 pub fn validate_integrity_with_key(
1463 &self,
1464 key: &IntegrityKey,
1465 ) -> Result<IntegrityAlgorithm, ValidateError> {
1466 let offset = self
1467 .integrity_offset
1468 .ok_or(ValidateError::Parse(StunParseError::MissingAttribute(
1469 MessageIntegrity::TYPE,
1470 )))?
1471 .get();
1472
1473 let iter = MessageAttributesIter::at_offset(self.data, offset);
1474 let mut raw_sha1 = None;
1475 let mut raw_sha256 = None;
1476 for (offset, raw_attr) in iter {
1477 match raw_attr.get_type() {
1478 MessageIntegrity::TYPE => {
1479 raw_sha1 = Some((offset, raw_attr));
1480 }
1481 MessageIntegritySha256::TYPE => {
1482 raw_sha256 = Some((offset, raw_attr));
1483 }
1484 _ => (),
1485 }
1486 }
1487
1488 let integrity_sha1;
1489 let integrity_sha256;
1490 let (algo, msg_hmac, offset) = if let Some(algo) = key.key_algorithm {
1491 match (algo, raw_sha1, raw_sha256) {
1492 (IntegrityAlgorithm::Sha256, _, Some((offset, sha256))) => {
1493 integrity_sha256 = MessageIntegritySha256::try_from(&sha256)?;
1494 (algo, integrity_sha256.hmac(), offset)
1495 }
1496 (IntegrityAlgorithm::Sha1, Some((offset, sha1)), _) => {
1497 integrity_sha1 = MessageIntegrity::try_from(&sha1)?;
1498 (algo, integrity_sha1.hmac().as_slice(), offset)
1499 }
1500 _ => return Err(StunParseError::MissingAttribute(MessageIntegrity::TYPE).into()),
1501 }
1502 } else {
1503 match (raw_sha1, raw_sha256) {
1504 (_, Some((offset, sha256))) => {
1505 integrity_sha256 = MessageIntegritySha256::try_from(&sha256)?;
1506 (IntegrityAlgorithm::Sha256, integrity_sha256.hmac(), offset)
1507 }
1508 (Some((offset, sha1)), None) => {
1509 integrity_sha1 = MessageIntegrity::try_from(&sha1)?;
1510 (
1511 IntegrityAlgorithm::Sha1,
1512 integrity_sha1.hmac().as_slice(),
1513 offset,
1514 )
1515 }
1516 (None, None) => {
1517 return Err(StunParseError::MissingAttribute(MessageIntegrity::TYPE).into())
1518 }
1519 }
1520 };
1521 self.validate_integrity_with_hmac(algo, msg_hmac, key, offset)
1522 }
1523
1524 #[tracing::instrument(
1525 name = "message_validate_integrity_with_hmac",
1526 level = "trace",
1527 skip(self, key, msg_hmac),
1528 fields(
1529 msg.transaction = %self.transaction_id(),
1530 )
1531 )]
1532 fn validate_integrity_with_hmac(
1533 &self,
1534 algo: IntegrityAlgorithm,
1535 msg_hmac: &[u8],
1536 key: &IntegrityKey,
1537 integrity_offset: usize,
1538 ) -> Result<IntegrityAlgorithm, ValidateError> {
1539 if key.key_algorithm.is_some_and(|key_algo| key_algo != algo) {
1540 debug!(
1541 "Key algorithm ({:?}) does not match algo ({algo:?})",
1542 key.key_algorithm
1543 );
1544 return Err(StunParseError::DataMismatch.into());
1545 }
1546 debug_assert!(self.data.len() >= MessageHeader::LENGTH);
1548 debug_assert!(integrity_offset >= MessageHeader::LENGTH);
1549 debug_assert!(integrity_offset < self.data.len());
1550 let mut data = &self.data[integrity_offset..];
1551 let mut data_offset = integrity_offset;
1552 while !data.is_empty() {
1553 let attr = RawAttribute::from_bytes(data)?;
1554 if algo == IntegrityAlgorithm::Sha1 && attr.get_type() == MessageIntegrity::TYPE {
1555 let msg = MessageIntegrity::try_from(&attr)?;
1556 debug_assert!(msg.hmac().as_slice() == msg_hmac);
1557
1558 let mut header = [0; 4];
1561 header[0] = self.data[0];
1562 header[1] = self.data[1];
1563 let hmac_data = &self.data[4..data_offset];
1564 BigEndian::write_u16(
1565 &mut header[2..4],
1566 data_offset as u16 + 24 - MessageHeader::LENGTH as u16,
1567 );
1568 if MessageIntegrity::verify(
1569 &[header.as_slice(), hmac_data],
1570 key,
1571 msg_hmac.try_into().unwrap(),
1572 ) {
1573 return Ok(algo);
1574 } else {
1575 return Err(ValidateError::IntegrityFailed);
1576 }
1577 } else if algo == IntegrityAlgorithm::Sha256
1578 && attr.get_type() == MessageIntegritySha256::TYPE
1579 {
1580 let msg = MessageIntegritySha256::try_from(&attr)?;
1581 debug_assert!(msg.hmac() == msg_hmac);
1582
1583 let mut header = [0; 4];
1586 header[0] = self.data[0];
1587 header[1] = self.data[1];
1588 let hmac_data = &self.data[4..data_offset];
1589 BigEndian::write_u16(
1590 &mut header[2..4],
1591 data_offset as u16 + attr.padded_len() as u16 - MessageHeader::LENGTH as u16,
1592 );
1593 if MessageIntegritySha256::verify(&[&header, hmac_data], key, msg_hmac) {
1594 return Ok(algo);
1595 } else {
1596 return Err(ValidateError::IntegrityFailed);
1597 }
1598 }
1599 let padded_len = attr.padded_len();
1600 debug_assert!(padded_len <= data.len());
1602 data = &data[padded_len..];
1603 data_offset += padded_len;
1604 }
1605
1606 unreachable!();
1609 }
1610
1611 pub fn nth_raw_attribute(&self, atype: AttributeType, n: usize) -> Option<RawAttribute<'_>> {
1630 self.nth_raw_attribute_and_offset(atype, n)
1631 .map(|(_offset, attr)| attr)
1632 }
1633
1634 pub fn raw_attribute(&self, atype: AttributeType) -> Option<RawAttribute<'_>> {
1638 self.nth_raw_attribute(atype, 0)
1639 }
1640
1641 #[tracing::instrument(
1663 name = "message_nth_raw_attribute_and_offset",
1664 level = "trace",
1665 skip(self, atype),
1666 fields(
1667 msg.transaction = %self.transaction_id(),
1668 attribute_type = %atype,
1669 )
1670 )]
1671 pub fn nth_raw_attribute_and_offset(
1672 &self,
1673 atype: AttributeType,
1674 n: usize,
1675 ) -> Option<(usize, RawAttribute<'_>)> {
1676 if let Some((offset, attr)) = self
1677 .iter_attributes()
1678 .filter(|(_offset, attr)| attr.get_type() == atype)
1679 .nth(n)
1680 {
1681 trace!("found attribute at offset: {offset}");
1682 Some((offset, attr))
1683 } else {
1684 trace!("could not find attribute");
1685 None
1686 }
1687 }
1688
1689 pub fn raw_attribute_and_offset(
1694 &self,
1695 atype: AttributeType,
1696 ) -> Option<(usize, RawAttribute<'_>)> {
1697 self.nth_raw_attribute_and_offset(atype, 0)
1698 }
1699
1700 pub fn nth_attribute<A: AttributeFromRaw<'a> + AttributeStaticType>(
1722 &'a self,
1723 n: usize,
1724 ) -> Result<A, StunParseError> {
1725 self.nth_attribute_and_offset(n).map(|(_offset, attr)| attr)
1726 }
1727
1728 pub fn attribute<A: AttributeFromRaw<'a> + AttributeStaticType>(
1732 &'a self,
1733 ) -> Result<A, StunParseError> {
1734 self.nth_attribute(0)
1735 }
1736
1737 pub fn nth_attribute_and_offset<A: AttributeFromRaw<'a> + AttributeStaticType>(
1763 &'a self,
1764 n: usize,
1765 ) -> Result<(usize, A), StunParseError> {
1766 self.nth_raw_attribute_and_offset(A::TYPE, n)
1767 .ok_or(StunParseError::MissingAttribute(A::TYPE))
1768 .and_then(|(offset, raw)| A::from_raw(raw).map(|attr| (offset, attr)))
1769 }
1770
1771 pub fn attribute_and_offset<A: AttributeFromRaw<'a> + AttributeStaticType>(
1776 &'a self,
1777 ) -> Result<(usize, A), StunParseError> {
1778 self.nth_attribute_and_offset(0)
1779 }
1780
1781 pub fn iter_attributes(&self) -> impl Iterator<Item = (usize, RawAttribute<'_>)> {
1783 MessageAttributesIter::new(self.data)
1784 }
1785
1786 #[tracing::instrument(
1835 level = "trace",
1836 skip(msg, write),
1837 fields(
1838 msg.transaction = %msg.transaction_id(),
1839 )
1840 )]
1841 pub fn check_attribute_types<B: MessageWrite>(
1842 msg: &Message,
1843 supported: &[AttributeType],
1844 required_in_msg: &[AttributeType],
1845 write: B,
1846 ) -> Option<B> {
1847 let unsupported: Vec<AttributeType> = msg
1849 .iter_attributes()
1850 .map(|(_offset, a)| a.get_type())
1851 .filter(|at| at.comprehension_required() && !supported.contains(at))
1853 .collect();
1854 if !unsupported.is_empty() {
1855 warn!(
1856 "Message contains unknown comprehension required attributes {:?}, returning unknown attributes",
1857 unsupported
1858 );
1859 return Some(Message::unknown_attributes(msg, &unsupported, write));
1860 }
1861 let has_required_attribute_missing = required_in_msg
1862 .iter()
1863 .any(|&at| {
1865 !msg.iter_attributes()
1866 .map(|(_offset, a)| a.get_type())
1867 .any(|a| a == at)
1868 });
1869 if has_required_attribute_missing {
1870 warn!("Message is missing required attributes, returning bad request");
1871 return Some(Message::bad_request(msg, write));
1872 }
1873 None
1874 }
1875
1876 pub fn unknown_attributes<B: MessageWrite>(
1897 src: &Message,
1898 attributes: &[AttributeType],
1899 write: B,
1900 ) -> B {
1901 let mut out = Message::builder_error(src, write);
1902 let software = Software::new("stun-types").unwrap();
1903 out.add_attribute(&software).unwrap();
1904 let error = ErrorCode::new(420, "Unknown Attributes").unwrap();
1905 out.add_attribute(&error).unwrap();
1906 let unknown = UnknownAttributes::new(attributes);
1907 if !attributes.is_empty() {
1908 out.add_attribute(&unknown).unwrap();
1909 }
1910 out
1911 }
1912
1913 pub fn bad_request<B: MessageWrite>(src: &Message, write: B) -> B {
1931 let mut out = Message::builder_error(src, write);
1932 let software = Software::new("stun-types").unwrap();
1933 out.add_attribute(&software).unwrap();
1934 let error = ErrorCode::new(400, "Bad Request").unwrap();
1935 out.add_attribute(&error).unwrap();
1936 out
1937 }
1938
1939 pub fn has_attribute(&self, atype: AttributeType) -> bool {
1955 self.iter_attributes()
1956 .any(|(_offset, attr)| attr.get_type() == atype)
1957 }
1958
1959 pub fn as_bytes(&self) -> &[u8] {
1961 self.data
1962 }
1963}
1964impl<'a> TryFrom<&'a [u8]> for Message<'a> {
1965 type Error = StunParseError;
1966
1967 fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {
1968 Message::from_bytes(value)
1969 }
1970}
1971
1972impl AsRef<[u8]> for Message<'_> {
1973 fn as_ref(&self) -> &[u8] {
1974 self.data
1975 }
1976}
1977
1978#[derive(Debug)]
1979struct MessageRawAttributesIter<'a> {
1980 data: &'a [u8],
1981 data_i: usize,
1982}
1983
1984impl<'a> MessageRawAttributesIter<'a> {
1985 fn new(data: &'a [u8]) -> Self {
1986 Self::at_offset(data, MessageHeader::LENGTH)
1987 }
1988
1989 fn at_offset(data: &'a [u8], offset: usize) -> Self {
1990 Self {
1991 data,
1992 data_i: offset,
1993 }
1994 }
1995}
1996
1997impl<'a> Iterator for MessageRawAttributesIter<'a> {
1998 type Item = Result<(usize, RawAttribute<'a>), StunParseError>;
1999
2000 fn next(&mut self) -> Option<Self::Item> {
2001 if self.data_i >= self.data.len() {
2002 return None;
2003 }
2004
2005 match RawAttribute::from_bytes(&self.data[self.data_i..]) {
2006 Ok(attr) => {
2007 let padded_len = attr.padded_len();
2008 self.data_i += padded_len;
2009 if self.data_i > self.data.len() {
2010 warn!(
2011 "attribute {} extends past the end of the data",
2012 attr.get_type()
2013 );
2014 return Some(Err(StunParseError::Truncated {
2015 expected: self.data_i,
2016 actual: self.data.len(),
2017 }));
2018 }
2019 Some(Ok((self.data_i - padded_len, attr)))
2020 }
2021 Err(e) => {
2022 let offset = self.data_i;
2023 self.data_i = self.data.len();
2024 let e = match e {
2025 StunParseError::Truncated { expected, actual } => StunParseError::Truncated {
2026 expected: expected + 4 + offset,
2027 actual: actual + 4 + offset,
2028 },
2029 StunParseError::TooLarge { expected, actual } => StunParseError::TooLarge {
2030 expected: expected + 4 + offset,
2031 actual: actual + 4 + offset,
2032 },
2033 e => e,
2034 };
2035 Some(Err(e))
2036 }
2037 }
2038 }
2039}
2040
2041#[doc(hidden)]
2042#[derive(Debug)]
2043pub struct MessageAttributesIter<'a> {
2044 header_parsed: bool,
2045 inner: MessageRawAttributesIter<'a>,
2046 last_attr_type: AttributeType,
2047 seen_message_integrity: bool,
2048}
2049
2050impl<'a> MessageAttributesIter<'a> {
2051 pub fn new(data: &'a [u8]) -> Self {
2060 Self {
2061 header_parsed: false,
2062 inner: MessageRawAttributesIter::new(data),
2063 seen_message_integrity: false,
2064 last_attr_type: AttributeType::new(0),
2065 }
2066 }
2067
2068 fn at_offset(data: &'a [u8], offset: usize) -> Self {
2069 Self {
2070 header_parsed: true,
2071 inner: MessageRawAttributesIter::at_offset(data, offset),
2072 seen_message_integrity: false,
2073 last_attr_type: AttributeType::new(0),
2074 }
2075 }
2076}
2077
2078impl<'a> Iterator for MessageAttributesIter<'a> {
2079 type Item = (usize, RawAttribute<'a>);
2080
2081 fn next(&mut self) -> Option<Self::Item> {
2082 if self.last_attr_type == Fingerprint::TYPE {
2084 return None;
2085 }
2086
2087 if !self.header_parsed {
2088 let Ok(hdr) = MessageHeader::from_bytes(self.inner.data) else {
2089 self.last_attr_type = Fingerprint::TYPE;
2090 return None;
2091 };
2092 if hdr.data_length() as usize + MessageHeader::LENGTH > self.inner.data.len() {
2093 self.last_attr_type = Fingerprint::TYPE;
2094 return None;
2095 }
2096 self.header_parsed = true;
2097 }
2098
2099 let (offset, attr) = self.inner.next()?.ok()?;
2100 let attr_type = attr.get_type();
2101 if self.seen_message_integrity {
2102 if self.last_attr_type != Fingerprint::TYPE && attr_type == Fingerprint::TYPE {
2103 self.last_attr_type = attr_type;
2104 return Some((offset, attr));
2105 }
2106 if self.last_attr_type == MessageIntegrity::TYPE
2107 && attr_type == MessageIntegritySha256::TYPE
2108 {
2109 self.last_attr_type = attr_type;
2110 return Some((offset, attr));
2111 }
2112 self.last_attr_type = Fingerprint::TYPE;
2113 return None;
2114 }
2115 if attr.get_type() == MessageIntegrity::TYPE
2116 || attr.get_type() == MessageIntegritySha256::TYPE
2117 || attr.get_type() == Fingerprint::TYPE
2118 {
2119 self.seen_message_integrity = true;
2120 }
2121 self.last_attr_type = attr.get_type();
2122
2123 Some((offset, attr))
2124 }
2125}
2126
2127#[allow(clippy::len_without_is_empty)]
2128pub trait MessageWrite {
2130 type Output;
2132 fn max_size(&self) -> Option<usize> {
2135 None
2136 }
2137
2138 fn mut_data(&mut self) -> &mut [u8];
2140 fn data(&self) -> &[u8];
2142 fn len(&self) -> usize;
2144 fn push_data(&mut self, data: &[u8]);
2146 fn push_attribute_unchecked(&mut self, attr: &dyn AttributeWrite);
2148
2149 fn has_attribute(&self, atype: AttributeType) -> bool;
2151
2152 fn has_any_attribute(&self, atypes: &[AttributeType]) -> Option<AttributeType>;
2155
2156 fn finish(self) -> Self::Output;
2158}
2159
2160pub trait MessageWriteExt: MessageWrite {
2162 fn get_type(&self) -> MessageType {
2174 MessageType::from_bytes(self.data()).unwrap()
2175 }
2176
2177 fn class(&self) -> MessageClass {
2189 self.get_type().class()
2190 }
2191
2192 fn has_class(&self, cls: MessageClass) -> bool {
2204 self.class() == cls
2205 }
2206
2207 fn is_response(&self) -> bool {
2229 self.class().is_response()
2230 }
2231
2232 fn method(&self) -> Method {
2244 self.get_type().method()
2245 }
2246
2247 fn has_method(&self, method: Method) -> bool {
2260 self.method() == method
2261 }
2262
2263 fn transaction_id(&self) -> TransactionId {
2277 BigEndian::read_u128(&self.data()[4..]).into()
2278 }
2279
2280 fn add_message_integrity(
2315 &mut self,
2316 credentials: &MessageIntegrityCredentials,
2317 algorithm: IntegrityAlgorithm,
2318 ) -> Result<(), StunWriteError> {
2319 let key = credentials.make_key(algorithm);
2320 self.add_message_integrity_with_key(&key, algorithm)
2321 }
2322
2323 #[tracing::instrument(
2325 name = "message_add_integrity_with_key",
2326 level = "trace",
2327 err,
2328 skip(self),
2329 fields(
2330 msg.transaction = %self.transaction_id(),
2331 )
2332 )]
2333 fn add_message_integrity_with_key(
2334 &mut self,
2335 key: &IntegrityKey,
2336 algorithm: IntegrityAlgorithm,
2337 ) -> Result<(), StunWriteError> {
2338 let mut atypes = [AttributeType::new(0); 3];
2339 let mut i = 0;
2340 atypes[i] = match algorithm {
2341 IntegrityAlgorithm::Sha1 => MessageIntegrity::TYPE,
2342 IntegrityAlgorithm::Sha256 => MessageIntegritySha256::TYPE,
2343 };
2344 i += 1;
2345 if algorithm == IntegrityAlgorithm::Sha1 {
2346 atypes[i] = MessageIntegritySha256::TYPE;
2347 i += 1;
2348 }
2349 atypes[i] = Fingerprint::TYPE;
2350 i += 1;
2351
2352 match self.has_any_attribute(&atypes[..i]) {
2353 Some(MessageIntegrity::TYPE) => {
2355 return Err(StunWriteError::AttributeExists(MessageIntegrity::TYPE))
2356 }
2357 Some(MessageIntegritySha256::TYPE) => {
2358 return Err(StunWriteError::AttributeExists(
2359 MessageIntegritySha256::TYPE,
2360 ));
2361 }
2362 Some(Fingerprint::TYPE) => return Err(StunWriteError::FingerprintExists),
2363 _ => (),
2364 }
2365 match algorithm {
2366 IntegrityAlgorithm::Sha1 => {
2367 check_attribute_can_fit(self, &MessageIntegrity::new([0; 20]))?
2368 }
2369 IntegrityAlgorithm::Sha256 => {
2370 check_attribute_can_fit(self, &MessageIntegritySha256::new(&[0; 32]).unwrap())?
2371 }
2372 };
2373
2374 unsafe { self.add_message_integrity_with_key_unchecked(key, algorithm) };
2375
2376 Ok(())
2377 }
2378
2379 unsafe fn add_message_integrity_with_key_unchecked(
2390 &mut self,
2391 key: &IntegrityKey,
2392 algorithm: IntegrityAlgorithm,
2393 ) {
2394 match algorithm {
2397 IntegrityAlgorithm::Sha1 => {
2398 self.push_attribute_unchecked(&MessageIntegrity::new([0; 20]));
2399 let len = self.len();
2400 let data = self.mut_data();
2401 let integrity = MessageIntegrity::compute(&[&data[..len - 24]], key).unwrap();
2402 data[len - 20..].copy_from_slice(&integrity);
2403 }
2404 IntegrityAlgorithm::Sha256 => {
2405 self.push_attribute_unchecked(&MessageIntegritySha256::new(&[0; 32]).unwrap());
2406 let len = self.len();
2407 let data = self.mut_data();
2408 let integrity = MessageIntegritySha256::compute(&[&data[..len - 36]], key).unwrap();
2409 data[len - 32..].copy_from_slice(&integrity);
2410 }
2411 }
2412 }
2413
2414 #[tracing::instrument(
2432 name = "message_add_fingerprint",
2433 level = "trace",
2434 skip(self),
2435 fields(
2436 msg.transaction = %self.transaction_id(),
2437 )
2438 )]
2439 fn add_fingerprint(&mut self) -> Result<(), StunWriteError> {
2440 if self.has_attribute(Fingerprint::TYPE) {
2441 return Err(StunWriteError::AttributeExists(Fingerprint::TYPE));
2442 }
2443
2444 check_attribute_can_fit(self, &Fingerprint::new([0; 4]))?;
2445 unsafe { self.add_fingerprint_unchecked() };
2446
2447 Ok(())
2448 }
2449
2450 unsafe fn add_fingerprint_unchecked(&mut self) {
2460 self.push_attribute_unchecked(&Fingerprint::new([0; 4]));
2463 let len = self.len();
2464 let data = self.mut_data();
2465 let fingerprint = Fingerprint::compute(&[&data[..len - 8]]);
2466 let fingerprint = Fingerprint::new(fingerprint);
2467 fingerprint.write_into(&mut data[len - 8..]).unwrap();
2468 }
2469
2470 #[tracing::instrument(
2499 name = "message_add_attribute",
2500 level = "trace",
2501 err,
2502 skip(self, attr),
2503 fields(
2504 msg.transaction = %self.transaction_id(),
2505 )
2506 )]
2507 fn add_attribute(&mut self, attr: &dyn AttributeWrite) -> Result<(), StunWriteError> {
2508 let ty = attr.get_type();
2509 match ty {
2510 MessageIntegrity::TYPE => {
2511 panic!("Cannot write MessageIntegrity with `add_attribute`. Use add_message_integrity() instead");
2512 }
2513 MessageIntegritySha256::TYPE => {
2514 panic!("Cannot write MessageIntegritySha256 with `add_attribute`. Use add_message_integrity() instead");
2515 }
2516 Fingerprint::TYPE => {
2517 panic!(
2518 "Cannot write Fingerprint with `add_attribute`. Use add_fingerprint() instead"
2519 );
2520 }
2521 _ => (),
2522 }
2523 match self.has_any_attribute(&[
2524 MessageIntegrity::TYPE,
2525 MessageIntegritySha256::TYPE,
2526 Fingerprint::TYPE,
2527 ]) {
2528 Some(MessageIntegrity::TYPE) => return Err(StunWriteError::MessageIntegrityExists),
2530 Some(MessageIntegritySha256::TYPE) => {
2531 return Err(StunWriteError::MessageIntegrityExists)
2532 }
2533 Some(Fingerprint::TYPE) => return Err(StunWriteError::FingerprintExists),
2534 _ => (),
2535 }
2536 check_attribute_can_fit(self, attr)?;
2537 self.push_attribute_unchecked(attr);
2538 Ok(())
2539 }
2540}
2541
2542impl<T: MessageWrite> MessageWriteExt for T {}
2543
2544#[derive(Debug, Default)]
2546pub struct MessageWriteVec {
2547 output: Vec<u8>,
2548 attributes: smallvec::SmallVec<[AttributeType; 16]>,
2549}
2550
2551impl MessageWriteVec {
2552 pub fn new() -> Self {
2554 Self::default()
2555 }
2556
2557 pub fn with_capacity(capacity: usize) -> Self {
2559 Self {
2560 output: Vec::with_capacity(capacity),
2561 attributes: Default::default(),
2562 }
2563 }
2564}
2565
2566impl core::ops::Deref for MessageWriteVec {
2567 type Target = Vec<u8>;
2568 fn deref(&self) -> &Self::Target {
2569 &self.output
2570 }
2571}
2572
2573impl core::ops::DerefMut for MessageWriteVec {
2574 fn deref_mut(&mut self) -> &mut Self::Target {
2575 &mut self.output
2576 }
2577}
2578
2579impl MessageWrite for MessageWriteVec {
2580 type Output = Vec<u8>;
2581
2582 fn mut_data(&mut self) -> &mut [u8] {
2583 &mut self.output
2584 }
2585
2586 fn data(&self) -> &[u8] {
2587 &self.output
2588 }
2589
2590 fn len(&self) -> usize {
2591 self.output.len()
2592 }
2593
2594 fn push_data(&mut self, data: &[u8]) {
2595 self.output.extend(data)
2596 }
2597
2598 fn finish(self) -> Self::Output {
2599 self.output
2600 }
2601
2602 fn push_attribute_unchecked(&mut self, attr: &dyn AttributeWrite) {
2603 let offset = self.output.len();
2604 let padded_len = attr.padded_len();
2605 let expected = offset + padded_len;
2606 BigEndian::write_u16(
2607 &mut self.output[2..4],
2608 (expected - MessageHeader::LENGTH) as u16,
2609 );
2610 self.output.resize(expected, 0);
2611 attr.write_into_unchecked(&mut self.output[offset..]);
2612 self.attributes.push(attr.get_type());
2613 }
2614
2615 fn has_attribute(&self, atype: AttributeType) -> bool {
2616 self.attributes.contains(&atype)
2617 }
2618
2619 fn has_any_attribute(&self, atypes: &[AttributeType]) -> Option<AttributeType> {
2620 self.attributes
2621 .iter()
2622 .find(|&typ| atypes.contains(typ))
2623 .cloned()
2624 }
2625}
2626
2627#[derive(Debug, Default)]
2629pub struct MessageWriteMutSlice<'a> {
2630 output: &'a mut [u8],
2631 offset: usize,
2632 attributes: smallvec::SmallVec<[AttributeType; 16]>,
2633}
2634
2635impl<'a> MessageWriteMutSlice<'a> {
2636 pub fn new(data: &'a mut [u8]) -> Self {
2638 Self {
2639 output: data,
2640 offset: 0,
2641 attributes: Default::default(),
2642 }
2643 }
2644}
2645
2646impl core::ops::Deref for MessageWriteMutSlice<'_> {
2647 type Target = [u8];
2648 fn deref(&self) -> &Self::Target {
2649 self.output
2650 }
2651}
2652
2653impl core::ops::DerefMut for MessageWriteMutSlice<'_> {
2654 fn deref_mut(&mut self) -> &mut Self::Target {
2655 self.output
2656 }
2657}
2658
2659impl<'a> MessageWrite for MessageWriteMutSlice<'a> {
2660 type Output = usize;
2661
2662 fn max_size(&self) -> Option<usize> {
2663 Some(self.output.len())
2664 }
2665
2666 fn mut_data(&mut self) -> &mut [u8] {
2667 &mut self.output[..self.offset]
2668 }
2669
2670 fn data(&self) -> &[u8] {
2671 &self.output[..self.offset]
2672 }
2673
2674 fn len(&self) -> usize {
2675 self.offset
2676 }
2677
2678 fn push_data(&mut self, data: &[u8]) {
2679 let len = data.len();
2680 self.output[self.offset..self.offset + len].copy_from_slice(data);
2681 self.offset += len;
2682 }
2683
2684 fn push_attribute_unchecked(&mut self, attr: &dyn AttributeWrite) {
2685 let padded_len = attr.padded_len();
2686 let expected = self.offset + padded_len;
2687 BigEndian::write_u16(
2688 &mut self.output[2..4],
2689 (expected - MessageHeader::LENGTH) as u16,
2690 );
2691 self.attributes.push(attr.get_type());
2692 attr.write_into(&mut self.output[self.offset..self.offset + padded_len])
2693 .unwrap();
2694 self.offset += padded_len;
2695 }
2696
2697 fn finish(self) -> Self::Output {
2698 self.offset
2699 }
2700
2701 fn has_attribute(&self, atype: AttributeType) -> bool {
2702 self.attributes.contains(&atype)
2703 }
2704
2705 fn has_any_attribute(&self, atypes: &[AttributeType]) -> Option<AttributeType> {
2706 self.attributes
2707 .iter()
2708 .find(|&typ| atypes.contains(typ))
2709 .cloned()
2710 }
2711}
2712
2713fn check_attribute_can_fit<O, T: MessageWrite<Output = O> + ?Sized>(
2714 this: &mut T,
2715 attr: &dyn AttributeWrite,
2716) -> Result<usize, StunWriteError> {
2717 let len = attr.padded_len();
2718 let out_data = this.data();
2719 if out_data.len() < MessageHeader::LENGTH {
2720 return Err(StunWriteError::TooSmall {
2721 expected: 20,
2722 actual: out_data.len(),
2723 });
2724 }
2725 let expected = BigEndian::read_u16(&out_data[2..4]) as usize + MessageHeader::LENGTH + len;
2726 if let Some(max) = this.max_size() {
2727 if max < expected {
2728 return Err(StunWriteError::TooSmall {
2729 expected,
2730 actual: max,
2731 });
2732 }
2733 }
2734 Ok(expected)
2735}
2736
2737#[cfg(test)]
2738mod tests {
2739 use alloc::borrow::ToOwned;
2740 use precis_profiles::precis_core::profile::Profile;
2741 use tracing::error;
2742
2743 use super::*;
2744
2745 #[test]
2746 #[should_panic(expected = "Method value is out of range")]
2747 fn method_value_out_of_range() {
2748 let _log = crate::tests::test_init_log();
2749 Method::new(0xf000);
2750 }
2751
2752 #[test]
2753 #[cfg(feature = "std")]
2754 fn method_name() {
2755 let _log = crate::tests::test_init_log();
2756 assert_eq!(BINDING.name(), "BINDING");
2757 let method = Method::new(0x111);
2758 method.add_name("SOME-NAME");
2759 assert_eq!(method.name(), "SOME-NAME");
2760 assert_eq!(Method::new(0x112).name(), "unknown");
2761 }
2762
2763 #[test]
2764 fn msg_type_roundtrip() {
2765 let _log = crate::tests::test_init_log();
2766 for m in 0..0xfff {
2768 let m = Method::new(m);
2769 let classes = vec![
2770 MessageClass::Request,
2771 MessageClass::Indication,
2772 MessageClass::Success,
2773 MessageClass::Error,
2774 ];
2775 for c in classes {
2776 let mtype = MessageType::from_class_method(c, m);
2777 trace!("{mtype}");
2778 assert_eq!(mtype.class(), c);
2779 assert!(mtype.has_class(c));
2780 assert_eq!(mtype.method(), m);
2781 assert!(mtype.has_method(m));
2782 let bytes = mtype.to_bytes();
2783 let ptype = MessageType::from_bytes(&bytes).unwrap();
2784 assert_eq!(mtype, ptype);
2785 }
2786 }
2787 }
2788
2789 #[test]
2790 fn msg_type_not_stun() {
2791 assert!(matches!(
2792 MessageType::from_bytes(&[0xc0, 0x00]),
2793 Err(StunParseError::NotStun)
2794 ));
2795 }
2796
2797 #[test]
2798 fn msg_roundtrip() {
2799 let _log = crate::tests::test_init_log();
2800 for m in (0x009..0x4ff).step_by(0x123) {
2802 let m = Method::new(m);
2803 let classes = vec![
2804 MessageClass::Request,
2805 MessageClass::Indication,
2806 MessageClass::Success,
2807 MessageClass::Error,
2808 ];
2809 for c in classes {
2810 let mtype = MessageType::from_class_method(c, m);
2811 for tid in (0x18..0xff_ffff_ffff_ffff_ffff).step_by(0xfedc_ba98_7654_3210) {
2812 let mut msg = Message::builder(mtype, tid.into(), MessageWriteVec::default());
2813 let attr = RawAttribute::new(1.into(), &[3]);
2814 assert!(msg.add_attribute(&attr).is_ok());
2815 let data = msg.finish();
2816
2817 let msg = Message::from_bytes(&data).unwrap();
2818 let msg_attr = msg.raw_attribute(1.into()).unwrap();
2819 assert_eq!(msg_attr, attr);
2820 assert_eq!(msg.get_type(), mtype);
2821 assert_eq!(msg.transaction_id(), tid.into());
2822 assert_eq!(msg.as_bytes(), &data);
2823 assert_eq!(msg.as_ref(), &data);
2824 }
2825 }
2826 }
2827 }
2828
2829 #[test]
2830 fn unknown_attributes() {
2831 let _log = crate::tests::test_init_log();
2832 let src = Message::builder_request(BINDING, MessageWriteVec::default()).finish();
2833 let src = Message::from_bytes(&src).unwrap();
2834 let msg =
2835 Message::unknown_attributes(&src, &[Software::TYPE], MessageWriteVec::new()).finish();
2836 let msg = Message::from_bytes(&msg).unwrap();
2837 assert_eq!(msg.transaction_id(), src.transaction_id());
2838 assert_eq!(msg.class(), MessageClass::Error);
2839 assert!(msg.has_class(MessageClass::Error));
2840 assert!(!msg.has_class(MessageClass::Success));
2841 assert_eq!(msg.method(), src.method());
2842 assert!(msg.has_method(src.method()));
2843 let err = msg.attribute::<ErrorCode>().unwrap();
2844 assert_eq!(err.code(), 420);
2845 let unknown_attrs = msg.attribute::<UnknownAttributes>().unwrap();
2846 assert!(unknown_attrs.has_attribute(Software::TYPE));
2847 }
2848
2849 #[test]
2850 fn bad_request() {
2851 let _log = crate::tests::test_init_log();
2852 let src = Message::builder_request(BINDING, MessageWriteVec::new()).finish();
2853 let src = Message::from_bytes(&src).unwrap();
2854 let msg = Message::bad_request(&src, MessageWriteVec::new());
2855 assert!(msg.has_class(MessageClass::Error));
2856 assert!(!msg.has_class(MessageClass::Success));
2857 assert!(msg.has_method(src.method()));
2858 assert!(!msg.has_method(Method::new(0x111)));
2859 assert!(msg.is_response());
2860 let msg = msg.finish();
2861 let msg = Message::from_bytes(&msg).unwrap();
2862 assert_eq!(msg.transaction_id(), src.transaction_id());
2863 assert_eq!(msg.class(), MessageClass::Error);
2864 assert_eq!(msg.method(), src.method());
2865 let err = msg.attribute::<ErrorCode>().unwrap();
2866 assert_eq!(err.code(), 400);
2867 }
2868
2869 #[test]
2870 fn fingerprint() {
2871 let _log = crate::tests::test_init_log();
2872 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2873 assert!(msg.has_class(MessageClass::Request));
2874 assert!(!msg.has_class(MessageClass::Success));
2875 assert!(msg.has_method(BINDING));
2876 assert!(!msg.has_method(Method::new(0x111)));
2877 let software = Software::new("s").unwrap();
2878 msg.add_attribute(&software).unwrap();
2879 msg.add_fingerprint().unwrap();
2880 let bytes = msg.finish();
2881 let new_msg = Message::from_bytes(&bytes).unwrap();
2883 let (offset, software) = new_msg.attribute_and_offset::<Software>().unwrap();
2884 assert_eq!(software.software(), "s");
2885 assert_eq!(offset, 20);
2886 let (offset, _new_fingerprint) =
2887 new_msg.raw_attribute_and_offset(Fingerprint::TYPE).unwrap();
2888 assert_eq!(offset, 28);
2889 }
2890
2891 #[test]
2892 fn integrity() {
2893 let _log = crate::tests::test_init_log();
2894 for algorithm in [IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256] {
2895 let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2896 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2897 let software = Software::new("s").unwrap();
2898 msg.add_attribute(&software).unwrap();
2899 msg.add_message_integrity(&credentials, algorithm).unwrap();
2900 let bytes = msg.finish();
2901 let new_msg = Message::from_bytes(&bytes).unwrap();
2903 new_msg.validate_integrity(&credentials).unwrap();
2904 let (offset, software) = new_msg.attribute_and_offset::<Software>().unwrap();
2905 assert_eq!(software.software(), "s");
2906 assert_eq!(offset, 20);
2907 }
2908 }
2909
2910 #[test]
2911 fn write_into_short_destination() {
2912 let _log = crate::tests::test_init_log();
2913 const LEN: usize = MessageHeader::LENGTH + 8;
2914 let mut data = [0; LEN - 1];
2915 let mut msg = Message::builder_request(BINDING, MessageWriteMutSlice::new(&mut data));
2916 let software = Software::new("s").unwrap();
2917 assert!(
2918 matches!(msg.add_attribute(&software), Err(StunWriteError::TooSmall { expected, actual }) if expected == LEN && actual == LEN - 1)
2919 );
2920 }
2921
2922 #[test]
2923 fn integrity_key() {
2924 let _log = crate::tests::test_init_log();
2925 let credentials1 = ShortTermCredentials::new("pass1".to_owned());
2926 let key1 =
2927 MessageIntegrityCredentials::from(credentials1).make_key(IntegrityAlgorithm::Sha1);
2928 let credentials2 = ShortTermCredentials::new("pass2".to_owned());
2929 let key2 =
2930 MessageIntegrityCredentials::from(credentials2).make_key(IntegrityAlgorithm::Sha1);
2931 assert_eq!(key1, key1);
2932 assert_eq!(key2, key2);
2933 assert_ne!(key1, key2);
2934 }
2935
2936 #[test]
2937 fn add_duplicate_integrity() {
2938 let _log = crate::tests::test_init_log();
2939 let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2940 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2941 msg.add_message_integrity(&credentials, IntegrityAlgorithm::Sha1)
2942 .unwrap();
2943 assert!(matches!(
2944 msg.add_message_integrity(&credentials, IntegrityAlgorithm::Sha1),
2945 Err(StunWriteError::AttributeExists(MessageIntegrity::TYPE))
2946 ));
2947 msg.add_message_integrity(&credentials, IntegrityAlgorithm::Sha256)
2948 .unwrap();
2949 assert!(matches!(
2950 msg.add_message_integrity(&credentials, IntegrityAlgorithm::Sha256),
2951 Err(StunWriteError::AttributeExists(
2952 MessageIntegritySha256::TYPE
2953 ))
2954 ));
2955 let software = Software::new("s").unwrap();
2956 assert!(matches!(
2957 msg.add_attribute(&software),
2958 Err(StunWriteError::MessageIntegrityExists)
2959 ));
2960 }
2961
2962 #[test]
2963 fn add_sha1_integrity_after_sha256() {
2964 let _log = crate::tests::test_init_log();
2965 let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2966 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2967 msg.add_message_integrity(&credentials, IntegrityAlgorithm::Sha256)
2968 .unwrap();
2969 assert!(matches!(
2970 msg.add_message_integrity(&credentials, IntegrityAlgorithm::Sha1),
2971 Err(StunWriteError::AttributeExists(
2972 MessageIntegritySha256::TYPE
2973 ))
2974 ));
2975 }
2976
2977 #[test]
2978 fn add_attribute_after_integrity() {
2979 let _log = crate::tests::test_init_log();
2980 for algorithm in [IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256] {
2981 let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2982 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2983 msg.add_message_integrity(&credentials, algorithm).unwrap();
2984 let software = Software::new("s").unwrap();
2985 assert!(matches!(
2986 msg.add_attribute(&software),
2987 Err(StunWriteError::MessageIntegrityExists)
2988 ));
2989 }
2990 }
2991
2992 #[test]
2993 fn add_raw_attribute_after_integrity() {
2994 let _log = crate::tests::test_init_log();
2995 for algorithm in [IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256] {
2996 let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2997 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2998 msg.add_message_integrity(&credentials, algorithm).unwrap();
2999 let software = Software::new("s").unwrap();
3000 let raw = software.to_raw();
3001 assert!(matches!(
3002 msg.add_attribute(&raw),
3003 Err(StunWriteError::MessageIntegrityExists)
3004 ));
3005 }
3006 }
3007
3008 #[test]
3009 fn add_integrity_after_fingerprint() {
3010 let _log = crate::tests::test_init_log();
3011 for algorithm in [IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256] {
3012 let credentials = ShortTermCredentials::new("secret".to_owned()).into();
3013 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3014 msg.add_fingerprint().unwrap();
3015 assert!(matches!(
3016 msg.add_message_integrity(&credentials, algorithm),
3017 Err(StunWriteError::FingerprintExists)
3018 ));
3019 }
3020 }
3021
3022 #[test]
3023 fn duplicate_fingerprint() {
3024 let _log = crate::tests::test_init_log();
3025 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3026 msg.add_fingerprint().unwrap();
3027 assert!(matches!(
3028 msg.add_fingerprint(),
3029 Err(StunWriteError::AttributeExists(Fingerprint::TYPE))
3030 ));
3031 }
3032
3033 #[test]
3034 fn parse_invalid_fingerprint() {
3035 let _log = crate::tests::test_init_log();
3036 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3037 msg.add_fingerprint().unwrap();
3038 let mut bytes = msg.finish();
3039 bytes[24] = 0x80;
3040 bytes[25] = 0x80;
3041 bytes[26] = 0x80;
3042 bytes[27] = 0x80;
3043 assert!(matches!(
3044 Message::from_bytes(&bytes),
3045 Err(StunParseError::FingerprintMismatch)
3046 ));
3047 }
3048
3049 #[test]
3050 fn parse_wrong_magic() {
3051 let _log = crate::tests::test_init_log();
3052 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3053 msg.add_fingerprint().unwrap();
3054 let mut bytes = msg.finish();
3055 bytes[4] = 0x80;
3056 assert!(matches!(
3057 Message::from_bytes(&bytes),
3058 Err(StunParseError::NotStun)
3059 ));
3060 }
3061
3062 #[test]
3063 fn parse_attribute_after_integrity() {
3064 let _log = crate::tests::test_init_log();
3065 for algorithm in [IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256] {
3066 let credentials = ShortTermCredentials::new("secret".to_owned()).into();
3067 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3068 msg.add_message_integrity(&credentials, algorithm).unwrap();
3069 let mut bytes = msg.finish();
3070 let software = Software::new("s").unwrap();
3071 let software_bytes = RawAttribute::from(&software).to_bytes();
3072 let software_len = software_bytes.len();
3073 bytes.extend(software_bytes);
3074 bytes[3] += software_len as u8;
3075 let msg = Message::from_bytes(&bytes).unwrap();
3076 assert!(msg.raw_attribute(Software::TYPE).is_none());
3077 }
3078 }
3079
3080 #[test]
3081 fn parse_duplicate_integrity_after_integrity() {
3082 let _log = crate::tests::test_init_log();
3083 for algorithm in [IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256] {
3084 let credentials = ShortTermCredentials::new("secret".to_owned()).into();
3085 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3086 msg.add_message_integrity(&credentials, algorithm).unwrap();
3087 unsafe {
3089 msg.add_message_integrity_with_key_unchecked(
3090 &credentials.make_key(IntegrityAlgorithm::Sha1),
3091 algorithm,
3092 )
3093 };
3094 let bytes = msg.finish();
3095 let integrity_type = match algorithm {
3096 IntegrityAlgorithm::Sha1 => MessageIntegrity::TYPE,
3097 IntegrityAlgorithm::Sha256 => MessageIntegritySha256::TYPE,
3098 };
3099 let msg = Message::from_bytes(&bytes).unwrap();
3100 msg.nth_raw_attribute(integrity_type, 0).unwrap();
3101 assert!(msg.nth_raw_attribute(integrity_type, 1).is_none());
3102 }
3103 }
3104
3105 #[test]
3106 fn parse_attribute_after_fingerprint() {
3107 let _log = crate::tests::test_init_log();
3108 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3109 msg.add_fingerprint().unwrap();
3110 let mut bytes = msg.finish();
3111 let software = Software::new("s").unwrap();
3112 let software_bytes = RawAttribute::from(&software).to_bytes();
3113 let software_len = software_bytes.len();
3114 bytes.extend(software_bytes);
3115 bytes[3] += software_len as u8;
3116 let msg = Message::from_bytes(&bytes).unwrap();
3117 assert!(msg.raw_attribute(Fingerprint::TYPE).is_some());
3118 assert!(msg.raw_attribute(Software::TYPE).is_none());
3119 }
3120
3121 #[test]
3122 fn parse_duplicate_fingerprint_after_fingerprint() {
3123 let _log = crate::tests::test_init_log();
3124 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3125 msg.add_fingerprint().unwrap();
3126 unsafe { msg.add_fingerprint_unchecked() };
3127 let bytes = msg.finish();
3128 let msg = Message::from_bytes(&bytes).unwrap();
3129 assert!(msg.nth_raw_attribute(Fingerprint::TYPE, 0).is_some());
3130 assert!(msg.nth_raw_attribute(Fingerprint::TYPE, 1).is_none());
3131 }
3132
3133 #[test]
3134 fn add_attribute_after_fingerprint() {
3135 let _log = crate::tests::test_init_log();
3136 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3137 msg.add_fingerprint().unwrap();
3138 let software = Software::new("s").unwrap();
3139 assert!(matches!(
3140 msg.add_attribute(&software),
3141 Err(StunWriteError::FingerprintExists)
3142 ));
3143 }
3144
3145 #[test]
3146 fn add_raw_attribute_after_fingerprint() {
3147 let _log = crate::tests::test_init_log();
3148 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3149 msg.add_fingerprint().unwrap();
3150 let software = Software::new("s").unwrap();
3151 let raw = software.to_raw();
3152 assert!(matches!(
3153 msg.add_attribute(&raw),
3154 Err(StunWriteError::FingerprintExists)
3155 ));
3156 }
3157
3158 #[test]
3159 fn parse_truncated_message_header() {
3160 let _log = crate::tests::test_init_log();
3161 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3162 msg.add_fingerprint().unwrap();
3163 let bytes = msg.finish();
3164 assert!(matches!(
3165 Message::from_bytes(&bytes[..8]),
3166 Err(StunParseError::Truncated {
3167 expected: 20,
3168 actual: 8
3169 })
3170 ));
3171 }
3172
3173 #[test]
3174 fn parse_truncated_message_header_prefix() {
3175 let _log = crate::tests::test_init_log();
3176 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3177 msg.add_fingerprint().unwrap();
3178 let bytes = msg.finish();
3179 for len in 0..MessageHeader::LENGTH {
3181 assert!(matches!(
3182 MessageHeader::from_bytes(&bytes[..len]),
3183 Err(StunParseError::Truncated {
3184 expected: 20,
3185 actual,
3186 }) if actual == len
3187 ));
3188 }
3189 assert!(MessageHeader::from_bytes(&bytes[..MessageHeader::LENGTH]).is_ok());
3190 }
3191
3192 #[test]
3193 fn parse_truncated_message_header_not_stun() {
3194 let _log = crate::tests::test_init_log();
3195 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3196 msg.add_fingerprint().unwrap();
3197 let bytes = msg.finish();
3198 for len in 1..=MessageHeader::LENGTH {
3199 for bit in [0x40, 0x80] {
3201 let mut data = bytes[..len].to_vec();
3202 data[0] |= bit;
3203 assert!(matches!(
3204 MessageHeader::from_bytes(&data),
3205 Err(StunParseError::NotStun)
3206 ));
3207 assert!(matches!(
3208 Message::from_bytes(&data),
3209 Err(StunParseError::NotStun)
3210 ));
3211 }
3212 for i in 4..len.min(8) {
3214 let mut data = bytes[..len].to_vec();
3215 data[i] ^= 0xff;
3216 assert!(matches!(
3217 MessageHeader::from_bytes(&data),
3218 Err(StunParseError::NotStun)
3219 ));
3220 assert!(matches!(
3221 Message::from_bytes(&data),
3222 Err(StunParseError::NotStun)
3223 ));
3224 }
3225 }
3226 }
3227
3228 #[test]
3229 fn parse_truncated_message() {
3230 let _log = crate::tests::test_init_log();
3231 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3232 msg.add_fingerprint().unwrap();
3233 let bytes = msg.finish();
3234 assert!(matches!(
3235 Message::from_bytes(&bytes[..24]),
3236 Err(StunParseError::Truncated {
3237 expected: 28,
3238 actual: 24
3239 })
3240 ));
3241 }
3242
3243 #[test]
3244 fn parse_truncated_message_attribute() {
3245 let _log = crate::tests::test_init_log();
3246 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3247 msg.add_fingerprint().unwrap();
3248 let mut bytes = msg.finish();
3249 bytes[3] = 4;
3251 assert!(matches!(
3252 Message::from_bytes(&bytes[..24]),
3253 Err(StunParseError::Truncated {
3254 expected: 28,
3255 actual: 24
3256 })
3257 ));
3258 }
3259
3260 #[test]
3261 fn parse_attribute_extends_past_message_end() {
3262 let _log = crate::tests::test_init_log();
3263 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3264 msg.add_attribute(&Software::new("a").unwrap()).unwrap();
3265 msg[23] += 1;
3266 let mut bytes = msg.finish();
3267 bytes[3] -= 1;
3268 error!("{bytes:x?}");
3269 error!("{:?}", Message::from_bytes(&bytes[..27]));
3270 assert!(matches!(
3271 Message::from_bytes(&bytes[..27]),
3272 Err(StunParseError::Truncated {
3273 expected: 28,
3274 actual: 27
3275 })
3276 ));
3277 }
3278
3279 #[test]
3280 fn valid_attributes() {
3281 let _log = crate::tests::test_init_log();
3282 let mut src = Message::builder_request(BINDING, MessageWriteVec::new());
3283 let username = Username::new("123").unwrap();
3284 src.add_attribute(&username).unwrap();
3285 let nonce = Nonce::new("nonce").unwrap();
3286 src.add_attribute(&nonce).unwrap();
3287 assert!(!src.has_attribute(Fingerprint::TYPE));
3288 assert!(src.has_attribute(Nonce::TYPE));
3289 let src = src.finish();
3290 let src = Message::from_bytes(&src).unwrap();
3291 assert!(!src.has_attribute(Fingerprint::TYPE));
3292 assert!(src.has_attribute(Nonce::TYPE));
3293
3294 let res = Message::check_attribute_types(
3296 &src,
3297 &[Username::TYPE, Nonce::TYPE],
3298 &[Username::TYPE],
3299 MessageWriteVec::new(),
3300 );
3301 assert!(res.is_none());
3302
3303 let res = Message::check_attribute_types(
3305 &src,
3306 &[Username::TYPE, Nonce::TYPE],
3307 &[Fingerprint::TYPE],
3308 MessageWriteVec::new(),
3309 );
3310 assert!(res.is_some());
3311 let res = res.unwrap();
3312 let res = res.finish();
3313 let res = Message::from_bytes(&res).unwrap();
3314 assert!(res.has_class(MessageClass::Error));
3315 assert!(res.has_method(src.method()));
3316 let err = res.attribute::<ErrorCode>().unwrap();
3317 assert_eq!(err.code(), 400);
3318
3319 let res =
3321 Message::check_attribute_types(&src, &[Username::TYPE], &[], MessageWriteVec::new());
3322 assert!(res.is_some());
3323 let res = res.unwrap();
3324 let data = res.finish();
3325 let res = Message::from_bytes(&data).unwrap();
3326 assert!(res.has_class(MessageClass::Error));
3327 assert!(res.has_method(src.method()));
3328 let err = res.attribute::<ErrorCode>().unwrap();
3329 assert_eq!(err.code(), 420);
3330 let unknown = res.attribute::<UnknownAttributes>().unwrap();
3331 assert!(unknown.has_attribute(Nonce::TYPE));
3332 }
3333
3334 #[test]
3335 fn attributes_iter_with_short_data() {
3336 let _log = crate::tests::test_init_log();
3337 assert_eq!(
3338 MessageAttributesIter::new(&[0x0, 0x1, 0x2, 0x3, 0x4]).next(),
3339 None
3340 );
3341 assert_eq!(
3342 MessageAttributesIter::new(&[
3343 0x0, 0x1, 0x2, 0x3, 0x21, 0x12, 0xa4, 0x42, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf,
3344 0x10, 0x11, 0x12, 0x13, 0x14,
3345 ])
3346 .next(),
3347 None
3348 );
3349 }
3350
3351 #[test]
3352 fn attributes_iter_software_after_fingerprint_ignored() {
3353 let _log = crate::tests::test_init_log();
3354 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3355 msg.add_fingerprint().unwrap();
3356 let mut bytes = msg.finish();
3357 let software = Software::new("s").unwrap();
3358 let software_bytes = RawAttribute::from(&software).to_bytes();
3359 let software_len = software_bytes.len();
3360 bytes.extend(software_bytes);
3361 bytes[3] += software_len as u8;
3362 let mut it = MessageAttributesIter::new(&bytes);
3363 let (_offset, fingerprint) = it.next().unwrap();
3364 assert_eq!(fingerprint.get_type(), Fingerprint::TYPE);
3365 assert_eq!(it.next(), None);
3366 }
3367
3368 #[test]
3369 fn attributes_iter_message_integrities_fingerprint() {
3370 let _log = crate::tests::test_init_log();
3371 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3372 let credentials = ShortTermCredentials::new("pass".to_owned());
3373 msg.add_message_integrity(&credentials.clone().into(), IntegrityAlgorithm::Sha1)
3374 .unwrap();
3375 msg.add_message_integrity(&credentials.clone().into(), IntegrityAlgorithm::Sha256)
3376 .unwrap();
3377 msg.add_fingerprint().unwrap();
3378 let mut bytes = msg.finish();
3379 let software = Software::new("s").unwrap();
3380 let software_bytes = RawAttribute::from(&software).to_bytes();
3381 let software_len = software_bytes.len();
3382 bytes.extend(software_bytes);
3383 bytes[3] += software_len as u8;
3384 let mut it = MessageAttributesIter::new(&bytes);
3385 assert_eq!(it.next().unwrap().1.get_type(), MessageIntegrity::TYPE);
3386 assert_eq!(
3387 it.next().unwrap().1.get_type(),
3388 MessageIntegritySha256::TYPE
3389 );
3390 assert_eq!(it.next().unwrap().1.get_type(), Fingerprint::TYPE);
3391 assert_eq!(it.next(), None);
3392 }
3393
3394 #[test]
3395 fn message_parse_multiple_integrities_fingerprint() {
3396 let _log = crate::tests::test_init_log();
3397 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3398 let credentials = ShortTermCredentials::new("pass".to_owned());
3399 msg.add_message_integrity(&credentials.clone().into(), IntegrityAlgorithm::Sha1)
3400 .unwrap();
3401 msg.add_message_integrity(&credentials.clone().into(), IntegrityAlgorithm::Sha256)
3402 .unwrap();
3403 msg.add_fingerprint().unwrap();
3404 let key = credentials.make_key();
3405 let bytes = msg.finish();
3406 let msg = Message::from_bytes(&bytes).unwrap();
3407 assert!(msg.has_attribute(MessageIntegrity::TYPE));
3408 assert!(msg.has_attribute(MessageIntegritySha256::TYPE));
3409 assert!(!msg.has_attribute(Software::TYPE));
3410 assert_eq!(
3411 msg.validate_integrity(&credentials.clone().into()).unwrap(),
3412 IntegrityAlgorithm::Sha256
3413 );
3414 assert_eq!(
3415 msg.validate_integrity_with_key(&key).unwrap(),
3416 IntegrityAlgorithm::Sha256
3417 );
3418 }
3419
3420 #[test]
3421 fn validate_integrity_missing_attribute() {
3422 let _log = crate::tests::test_init_log();
3423 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3424 msg.add_fingerprint().unwrap();
3425 let credentials = ShortTermCredentials::new("pass".to_owned());
3426 let key = credentials.make_key();
3427 let bytes = msg.finish();
3428 let msg = Message::from_bytes(&bytes).unwrap();
3429 assert!(matches!(
3430 msg.validate_integrity(&credentials.clone().into()),
3431 Err(ValidateError::Parse(StunParseError::MissingAttribute(
3432 MessageIntegrity::TYPE
3433 )))
3434 ));
3435 assert!(matches!(
3436 msg.validate_integrity_with_key(&key),
3437 Err(ValidateError::Parse(StunParseError::MissingAttribute(
3438 MessageIntegrity::TYPE
3439 )))
3440 ));
3441 }
3442
3443 #[test]
3444 fn attributes_iter_fingerprint_after_fingerprint_ignored() {
3445 let _log = crate::tests::test_init_log();
3446 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3447 msg.add_fingerprint().unwrap();
3448 let mut bytes = msg.finish();
3449 let fingerprint = Fingerprint::new([bytes[bytes.len() - 1].wrapping_sub(1); 4]);
3450 let fingerprint_bytes = RawAttribute::from(&fingerprint).to_bytes();
3451 let fingerprint_len = fingerprint_bytes.len();
3452 bytes.extend(fingerprint_bytes);
3453 bytes[3] += fingerprint_len as u8;
3454 let mut it = MessageAttributesIter::new(&bytes);
3455 let (_offset, fingerprint) = it.next().unwrap();
3456 assert_eq!(fingerprint.get_type(), Fingerprint::TYPE);
3457 assert_eq!(it.next(), None);
3458 }
3459
3460 #[test]
3461 fn write_vec_state() {
3462 let _log = crate::tests::test_init_log();
3463 let mut src = Message::builder_request(BINDING, MessageWriteVec::with_capacity(0x10));
3464 assert_eq!(src.len(), 20);
3465 assert_eq!(src[4], 0x21);
3466 let username = Username::new("123").unwrap();
3467 src.add_attribute(&username).unwrap();
3468 let nonce = Nonce::new("nonce").unwrap();
3469 src.add_attribute(&nonce).unwrap();
3470
3471 assert!(src.has_attribute(Username::TYPE));
3472 assert!(src.has_attribute(Nonce::TYPE));
3473 assert_eq!(
3474 src.has_any_attribute(&[Username::TYPE, Nonce::TYPE]),
3475 Some(Username::TYPE)
3476 );
3477 assert_eq!(
3478 src.has_any_attribute(&[Nonce::TYPE, Username::TYPE]),
3479 Some(Username::TYPE)
3480 );
3481 assert!(src.has_class(MessageClass::Request));
3482 assert!(!src.is_response());
3483 assert!(src.has_method(BINDING));
3484 assert!(src.get_type().has_method(BINDING));
3485 assert!(src.get_type().has_class(MessageClass::Request));
3486 assert!(!src.has_method(Method::new(0x111)));
3487 assert!(!src.get_type().has_method(Method::new(0x111)));
3488 assert!(!src.get_type().has_class(MessageClass::Error));
3489 }
3490
3491 #[test]
3492 fn write_mut_slice_success() {
3493 let _log = crate::tests::test_init_log();
3494 let mut data = [0; 64];
3495 let mut src = Message::builder_request(BINDING, MessageWriteMutSlice::new(&mut data));
3496 assert_eq!(src.len(), 20);
3497 assert_eq!(src[4], 0x21);
3498 let username = Username::new("123").unwrap();
3499 src.add_attribute(&username).unwrap();
3500 let nonce = Nonce::new("nonce").unwrap();
3501 src.add_attribute(&nonce).unwrap();
3502 assert!(src.has_attribute(Username::TYPE));
3503 assert_eq!(
3504 src.has_any_attribute(&[Username::TYPE]),
3505 Some(Username::TYPE)
3506 );
3507 assert!(!src.has_attribute(Software::TYPE));
3508 assert_eq!(src.has_any_attribute(&[Realm::TYPE]), None);
3509 assert_eq!(src.mut_data().len(), src.len());
3510 assert_eq!(src.finish(), 40);
3511 let msg = Message::from_bytes(&data[..40]).unwrap();
3512 let u2 = msg.attribute::<Username>().unwrap();
3513 assert_eq!(u2.username(), "123");
3514 let n2 = msg.attribute::<Nonce>().unwrap();
3515 assert_eq!(n2.nonce(), "nonce");
3516 }
3517
3518 #[test]
3519 fn write_mut_slice_too_short() {
3520 let _log = crate::tests::test_init_log();
3521 let mut data = [0; 27];
3522 let mut src = Message::builder_request(BINDING, MessageWriteMutSlice::new(&mut data));
3523 assert!(matches!(
3524 src.add_attribute(&Username::new("123").unwrap()),
3525 Err(StunWriteError::TooSmall {
3526 expected: 28,
3527 actual: 27
3528 })
3529 ));
3530 }
3531
3532 #[test]
3533 #[should_panic(expected = "created from a non-request message")]
3534 fn builder_success_panic() {
3535 let _log = crate::tests::test_init_log();
3536 let msg = Message::builder(
3537 MessageType::from_class_method(MessageClass::Indication, BINDING),
3538 TransactionId::generate(),
3539 MessageWriteVec::new(),
3540 )
3541 .finish();
3542 let msg = Message::from_bytes(&msg).unwrap();
3543 let _builder = Message::builder_success(&msg, MessageWriteVec::new());
3544 }
3545
3546 #[test]
3547 #[should_panic(expected = "created from a non-request message")]
3548 fn builder_error_panic() {
3549 let _log = crate::tests::test_init_log();
3550 let msg = Message::builder(
3551 MessageType::from_class_method(MessageClass::Indication, BINDING),
3552 TransactionId::generate(),
3553 MessageWriteVec::new(),
3554 )
3555 .finish();
3556 let msg = Message::from_bytes(&msg).unwrap();
3557 let _builder = Message::builder_error(&msg, MessageWriteVec::new());
3558 }
3559
3560 #[test]
3561 #[should_panic(expected = "Use add_message_integrity() instead")]
3562 fn builder_add_attribute_integrity_panic() {
3563 let _log = crate::tests::test_init_log();
3564 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3565 let hmac = [2; 20];
3566 let integrity = MessageIntegrity::new(hmac);
3567 msg.add_attribute(&integrity).unwrap();
3568 }
3569
3570 #[test]
3571 #[should_panic(expected = "Use add_message_integrity() instead")]
3572 fn builder_add_raw_attribute_integrity_panic() {
3573 let _log = crate::tests::test_init_log();
3574 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3575 let hmac = [2; 20];
3576 let integrity = MessageIntegrity::new(hmac);
3577 let raw = integrity.to_raw();
3578 msg.add_attribute(&raw).unwrap();
3579 }
3580
3581 #[test]
3582 #[should_panic(expected = "Use add_message_integrity() instead")]
3583 fn builder_add_attribute_integrity_sha256_panic() {
3584 let _log = crate::tests::test_init_log();
3585 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3586 let hmac = [2; 16];
3587 let integrity = MessageIntegritySha256::new(&hmac).unwrap();
3588 msg.add_attribute(&integrity).unwrap();
3589 }
3590
3591 #[test]
3592 #[should_panic(expected = "Use add_message_integrity() instead")]
3593 fn builder_add_raw_attribute_integrity_sha256_panic() {
3594 let _log = crate::tests::test_init_log();
3595 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3596 let hmac = [2; 16];
3597 let integrity = MessageIntegritySha256::new(&hmac).unwrap();
3598 let raw = integrity.to_raw();
3599 msg.add_attribute(&raw).unwrap();
3600 }
3601
3602 #[test]
3603 #[should_panic(expected = "Use add_fingerprint() instead")]
3604 fn builder_add_attribute_fingerprint_panic() {
3605 let _log = crate::tests::test_init_log();
3606 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3607 let fingerprint = [2; 4];
3608 let fingerprint = Fingerprint::new(fingerprint);
3609 msg.add_attribute(&fingerprint).unwrap();
3610 }
3611
3612 #[test]
3613 #[should_panic(expected = "Use add_fingerprint() instead")]
3614 fn builder_add_raw_attribute_fingerprint_panic() {
3615 let _log = crate::tests::test_init_log();
3616 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3617 let fingerprint = [2; 4];
3618 let fingerprint = Fingerprint::new(fingerprint);
3619 let raw = fingerprint.to_raw();
3620 msg.add_attribute(&raw).unwrap();
3621 }
3622
3623 #[test]
3624 fn rfc5769_vector1() {
3625 let _log = crate::tests::test_init_log();
3626 let data = vec![
3628 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, ];
3656 let msg = Message::from_bytes(&data).unwrap();
3657 assert!(msg.has_class(MessageClass::Request));
3658 assert!(msg.has_method(BINDING));
3659 assert_eq!(msg.transaction_id(), 0xb7e7_a701_bc34_d686_fa87_dfae.into());
3660
3661 let mut builder = Message::builder(
3662 MessageType::from_class_method(MessageClass::Request, BINDING),
3663 msg.transaction_id(),
3664 MessageWriteVec::new(),
3665 );
3666
3667 assert!(msg.has_attribute(Software::TYPE));
3669 let raw = msg.raw_attribute(Software::TYPE).unwrap();
3670 assert!(Software::try_from(&raw).is_ok());
3671 let software = Software::try_from(&raw).unwrap();
3672 assert_eq!(software.software(), "STUN test client");
3673 builder.add_attribute(&software).unwrap();
3674
3675 builder
3677 .add_attribute(&RawAttribute::new(0x24.into(), &[0x6e, 0x00, 0x01, 0xff]))
3678 .unwrap();
3679
3680 builder
3682 .add_attribute(&RawAttribute::new(
3683 0x8029.into(),
3684 &[0x93, 0x2f, 0xf9, 0xb1, 0x51, 0x26, 0x3b, 0x36],
3685 ))
3686 .unwrap();
3687
3688 assert!(msg.has_attribute(Username::TYPE));
3690 let raw = msg.raw_attribute(Username::TYPE).unwrap();
3691 assert!(Username::try_from(&raw).is_ok());
3692 let username = Username::try_from(&raw).unwrap();
3693 assert_eq!(username.username(), "evtj:h6vY");
3694 builder.add_attribute(&username).unwrap();
3695
3696 let credentials = MessageIntegrityCredentials::ShortTerm(ShortTermCredentials {
3698 password: "VOkJxbRl1RmTxUk/WvJxBt".to_owned(),
3699 });
3700 assert!(matches!(
3701 msg.validate_integrity(&credentials),
3702 Ok(IntegrityAlgorithm::Sha1)
3703 ));
3704 builder
3705 .add_message_integrity(&credentials, IntegrityAlgorithm::Sha1)
3706 .unwrap();
3707
3708 assert!(msg.has_attribute(Fingerprint::TYPE));
3710 builder.add_fingerprint().unwrap();
3711
3712 let mut msg_data = builder.finish();
3714 msg_data[73] = 0x20;
3716 msg_data[74] = 0x20;
3717 msg_data[75] = 0x20;
3718 assert_eq!(msg_data[..80], data[..80]);
3721 }
3722
3723 #[test]
3724 fn rfc5769_vector2() {
3725 let _log = crate::tests::test_init_log();
3726 let data = vec![
3728 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, ];
3749
3750 let msg = Message::from_bytes(&data).unwrap();
3751 assert!(msg.has_class(MessageClass::Success));
3752 assert!(msg.has_method(BINDING));
3753 assert_eq!(msg.transaction_id(), 0xb7e7_a701_bc34_d686_fa87_dfae.into());
3754 let mut builder = Message::builder(
3755 MessageType::from_class_method(MessageClass::Success, BINDING),
3756 msg.transaction_id(),
3757 MessageWriteVec::new(),
3758 );
3759
3760 assert!(msg.has_attribute(Software::TYPE));
3762 let raw = msg.raw_attribute(Software::TYPE).unwrap();
3763 assert!(Software::try_from(&raw).is_ok());
3764 let software = Software::try_from(&raw).unwrap();
3765 assert_eq!(software.software(), "test vector");
3766 builder.add_attribute(&software).unwrap();
3767
3768 assert!(msg.has_attribute(XorMappedAddress::TYPE));
3770 let raw = msg.raw_attribute(XorMappedAddress::TYPE).unwrap();
3771 assert!(XorMappedAddress::try_from(&raw).is_ok());
3772 let xor_mapped_addres = XorMappedAddress::try_from(&raw).unwrap();
3773 assert_eq!(
3774 xor_mapped_addres.addr(msg.transaction_id()),
3775 "192.0.2.1:32853".parse().unwrap()
3776 );
3777 builder.add_attribute(&xor_mapped_addres).unwrap();
3778
3779 let credentials = MessageIntegrityCredentials::ShortTerm(ShortTermCredentials {
3781 password: "VOkJxbRl1RmTxUk/WvJxBt".to_owned(),
3782 });
3783 let ret = msg.validate_integrity(&credentials);
3784 warn!("{:?}", ret);
3785 assert!(matches!(ret, Ok(IntegrityAlgorithm::Sha1)));
3786 builder
3787 .add_message_integrity(&credentials, IntegrityAlgorithm::Sha1)
3788 .unwrap();
3789
3790 assert!(msg.has_attribute(Fingerprint::TYPE));
3792 builder.add_fingerprint().unwrap();
3793
3794 let mut msg_data = builder.finish();
3796 msg_data[35] = 0x20;
3798 assert_eq!(msg_data[..52], data[..52]);
3799 }
3800
3801 #[test]
3802 fn rfc5769_vector3() {
3803 let _log = crate::tests::test_init_log();
3804 let data = vec![
3806 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, ];
3830
3831 let msg = Message::from_bytes(&data).unwrap();
3832 assert!(msg.has_class(MessageClass::Success));
3833 assert!(msg.has_method(BINDING));
3834 assert_eq!(msg.transaction_id(), 0xb7e7_a701_bc34_d686_fa87_dfae.into());
3835 let mut builder = Message::builder(
3836 MessageType::from_class_method(MessageClass::Success, BINDING),
3837 msg.transaction_id(),
3838 MessageWriteVec::new(),
3839 );
3840
3841 assert!(msg.has_attribute(Software::TYPE));
3843 let raw = msg.raw_attribute(Software::TYPE).unwrap();
3844 assert!(Software::try_from(&raw).is_ok());
3845 let software = Software::try_from(&raw).unwrap();
3846 assert_eq!(software.software(), "test vector");
3847 builder.add_attribute(&software).unwrap();
3848
3849 assert!(msg.has_attribute(XorMappedAddress::TYPE));
3851 let raw = msg.raw_attribute(XorMappedAddress::TYPE).unwrap();
3852 assert!(XorMappedAddress::try_from(&raw).is_ok());
3853 let xor_mapped_addres = XorMappedAddress::try_from(&raw).unwrap();
3854 assert_eq!(
3855 xor_mapped_addres.addr(msg.transaction_id()),
3856 "[2001:db8:1234:5678:11:2233:4455:6677]:32853"
3857 .parse()
3858 .unwrap()
3859 );
3860 builder.add_attribute(&xor_mapped_addres).unwrap();
3861
3862 let credentials = MessageIntegrityCredentials::ShortTerm(ShortTermCredentials {
3864 password: "VOkJxbRl1RmTxUk/WvJxBt".to_owned(),
3865 });
3866 assert!(matches!(
3867 msg.validate_integrity(&credentials),
3868 Ok(IntegrityAlgorithm::Sha1)
3869 ));
3870 builder
3871 .add_message_integrity(&credentials, IntegrityAlgorithm::Sha1)
3872 .unwrap();
3873
3874 assert!(msg.has_attribute(Fingerprint::TYPE));
3876 builder.add_fingerprint().unwrap();
3877
3878 let mut msg_data = builder.finish();
3880 msg_data[35] = 0x20;
3882 assert_eq!(msg_data[..64], data[..64]);
3883 }
3884
3885 #[test]
3886 fn rfc5769_vector4() {
3887 let _log = crate::tests::test_init_log();
3888 let data = vec![
3890 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, ];
3920
3921 let msg = Message::from_bytes(&data).unwrap();
3922 assert!(msg.has_class(MessageClass::Request));
3923 assert!(msg.has_method(BINDING));
3924 assert_eq!(msg.transaction_id(), 0x78ad_3433_c6ad_72c0_29da_412e.into());
3925 let mut builder = Message::builder(
3926 MessageType::from_class_method(MessageClass::Request, BINDING),
3927 msg.transaction_id(),
3928 MessageWriteVec::new(),
3929 );
3930
3931 let username = stringprep::saslprep("\u{30DE}\u{30C8}\u{30EA}\u{30C3}\u{30AF}\u{30B9}")
3932 .unwrap()
3933 .into_owned();
3934 let password = stringprep::saslprep("The\u{00AD}M\u{00AA}tr\u{2168}")
3935 .unwrap()
3936 .into_owned();
3937 trace!("password: {password:?}");
3938
3939 let long_term = LongTermKeyCredentials {
3940 username,
3941 password,
3942 realm: "example.org".to_owned(),
3943 };
3944 assert!(msg.has_attribute(Username::TYPE));
3946 let raw = msg.raw_attribute(Username::TYPE).unwrap();
3947 assert!(Username::try_from(&raw).is_ok());
3948 let username = Username::try_from(&raw).unwrap();
3949 assert_eq!(username.username(), &long_term.username);
3950 builder.add_attribute(&username).unwrap();
3951
3952 let expected_nonce = "f//499k954d6OL34oL9FSTvy64sA";
3954 assert!(msg.has_attribute(Nonce::TYPE));
3955 let raw = msg.raw_attribute(Nonce::TYPE).unwrap();
3956 assert!(Nonce::try_from(&raw).is_ok());
3957 let nonce = Nonce::try_from(&raw).unwrap();
3958 assert_eq!(nonce.nonce(), expected_nonce);
3959 builder.add_attribute(&nonce).unwrap();
3960
3961 assert!(msg.has_attribute(Realm::TYPE));
3963 let raw = msg.raw_attribute(Realm::TYPE).unwrap();
3964 assert!(Realm::try_from(&raw).is_ok());
3965 let realm = Realm::try_from(&raw).unwrap();
3966 assert_eq!(realm.realm(), long_term.realm());
3967 builder.add_attribute(&realm).unwrap();
3968
3969 let credentials = MessageIntegrityCredentials::LongTerm(long_term);
3971 assert!(matches!(
3972 msg.validate_integrity(&credentials),
3973 Ok(IntegrityAlgorithm::Sha1)
3974 ));
3975 builder
3976 .add_message_integrity(&credentials, IntegrityAlgorithm::Sha1)
3977 .unwrap();
3978
3979 assert_eq!(builder.finish()[4..], data[4..]);
3980 }
3981
3982 #[test]
3983 fn rfc8489_vector1() {
3984 let _log = crate::tests::test_init_log();
3985 let data = vec![
3988 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, ];
4030 let msg = Message::from_bytes(&data).unwrap();
4031 assert!(msg.has_class(MessageClass::Request));
4032 assert!(msg.has_method(BINDING));
4033 assert_eq!(msg.transaction_id(), 0x78ad_3433_c6ad_72c0_29da_412e.into());
4034 let mut builder = Message::builder(
4035 MessageType::from_class_method(MessageClass::Request, BINDING),
4036 msg.transaction_id(),
4037 MessageWriteVec::new(),
4038 );
4039
4040 let opaque = precis_profiles::OpaqueString::new();
4041 let username = opaque
4042 .prepare("\u{30DE}\u{30C8}\u{30EA}\u{30C3}\u{30AF}\u{30B9}")
4043 .unwrap()
4044 .into_owned();
4045 let orig_password = "The\u{00AD}M\u{00AA}tr\u{2168}";
4046 trace!("password: {orig_password:?}");
4047 let sasl_password = stringprep::saslprep(orig_password).unwrap().into_owned();
4070 trace!("password (saslprep): {sasl_password}");
4071
4072 let long_term = LongTermKeyCredentials {
4075 username: username.clone(),
4076 password: sasl_password.clone(),
4077 realm: "example.org".to_owned(),
4078 };
4079 assert!(msg.has_attribute(Userhash::TYPE));
4081 let raw = msg.raw_attribute(Userhash::TYPE).unwrap();
4082 assert!(Userhash::try_from(&raw).is_ok());
4083 let userhash = Userhash::try_from(&raw).unwrap();
4084 builder.add_attribute(&userhash).unwrap();
4085
4086 let expected_nonce = "obMatJos2AAACf//499k954d6OL34oL9FSTvy64sA";
4088 assert!(msg.has_attribute(Nonce::TYPE));
4089 let raw = msg.raw_attribute(Nonce::TYPE).unwrap();
4090 assert!(Nonce::try_from(&raw).is_ok());
4091 let nonce = Nonce::try_from(&raw).unwrap();
4092 assert_eq!(nonce.nonce(), expected_nonce);
4093 builder.add_attribute(&nonce).unwrap();
4094
4095 assert!(msg.has_attribute(Realm::TYPE));
4097 let raw = msg.raw_attribute(Realm::TYPE).unwrap();
4098 assert!(Realm::try_from(&raw).is_ok());
4099 let realm = Realm::try_from(&raw).unwrap();
4100 assert_eq!(realm.realm(), long_term.realm);
4101 builder.add_attribute(&realm).unwrap();
4102
4103 assert!(msg.has_attribute(PasswordAlgorithm::TYPE));
4105 let raw = msg.raw_attribute(PasswordAlgorithm::TYPE).unwrap();
4106 assert!(PasswordAlgorithm::try_from(&raw).is_ok());
4107 let algo = PasswordAlgorithm::try_from(&raw).unwrap();
4108 assert_eq!(algo.algorithm(), PasswordAlgorithmValue::SHA256);
4109 builder.add_attribute(&algo).unwrap();
4110
4111 trace!("long term: {long_term:?}");
4132 let credentials = MessageIntegrityCredentials::LongTerm(long_term);
4133 assert!(matches!(
4134 msg.validate_integrity(&credentials),
4135 Ok(IntegrityAlgorithm::Sha256)
4136 ));
4137 builder
4138 .add_message_integrity(&credentials, IntegrityAlgorithm::Sha256)
4139 .unwrap();
4140
4141 assert_eq!(builder.finish()[4..], data[4..]);
4142 }
4143}