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> {
870 if data.len() < 20 {
871 return Err(StunParseError::Truncated {
872 expected: 20,
873 actual: data.len(),
874 });
875 }
876 let mtype = MessageType::from_bytes(data)?;
877 let mlength = BigEndian::read_u16(&data[2..]);
878 let tid = BigEndian::read_u128(&data[4..]);
879 let cookie = (tid >> 96) as u32;
880 if cookie != MAGIC_COOKIE {
881 debug!(
882 "malformed cookie constant {:?} != stored data {:?}",
883 MAGIC_COOKIE, cookie
884 );
885 return Err(StunParseError::NotStun);
886 }
887
888 Ok(Self {
889 mtype,
890 transaction_id: tid.into(),
891 length: mlength,
892 })
893 }
894
895 pub fn data_length(&self) -> u16 {
898 self.length
899 }
900
901 pub fn transaction_id(&self) -> TransactionId {
903 self.transaction_id
904 }
905
906 pub fn get_type(&self) -> MessageType {
908 self.mtype
909 }
910
911 fn new(mtype: MessageType, transaction_id: TransactionId, length: u16) -> Self {
912 Self {
913 mtype,
914 transaction_id,
915 length,
916 }
917 }
918
919 fn write_into(&self, dest: &mut [u8]) {
920 self.mtype.write_into(&mut dest[..2]);
921 let transaction: u128 = self.transaction_id.into();
922 let tid = (MAGIC_COOKIE as u128) << 96 | transaction & 0xffff_ffff_ffff_ffff_ffff_ffff;
923 BigEndian::write_u128(&mut dest[4..20], tid);
924 BigEndian::write_u16(&mut dest[2..4], self.length);
925 }
926}
927
928#[derive(Debug, Clone, Copy)]
933pub struct Message<'a> {
934 data: &'a [u8],
935 integrity_offset: Option<NonZeroUsize>,
936}
937
938impl core::fmt::Display for Message<'_> {
939 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
940 write!(
941 f,
942 "Message(class: {:?}, method: {}, transaction: {}, attributes: ",
943 self.get_type().class(),
944 self.get_type().method(),
945 self.transaction_id()
946 )?;
947 let iter = self.iter_attributes();
948 write!(f, "[")?;
949 for (i, (_offset, a)) in iter.enumerate() {
950 if i > 0 {
951 write!(f, ", ")?;
952 }
953 write!(f, "{a}")?;
954 }
955 write!(f, "]")?;
956 write!(f, ")")
957 }
958}
959
960#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
962pub enum IntegrityAlgorithm {
963 Sha1,
965 Sha256,
967}
968
969impl<'a> Message<'a> {
970 pub fn builder<B: MessageWrite>(
986 mtype: MessageType,
987 transaction_id: TransactionId,
988 mut write: B,
989 ) -> B {
990 let mut data = [0; 20];
991 MessageHeader::new(mtype, transaction_id, 0).write_into(&mut data);
992 write.push_data(&data);
993 write
994 }
995
996 pub fn builder_request<B: MessageWrite>(method: Method, write: B) -> B {
1010 Message::builder(
1011 MessageType::from_class_method(MessageClass::Request, method),
1012 TransactionId::generate(),
1013 write,
1014 )
1015 }
1016
1017 pub fn builder_success<B: MessageWrite>(orig: &Message, write: B) -> B {
1037 if !orig.has_class(MessageClass::Request) {
1038 panic!(
1039 "A success response message was attempted to be created from a non-request message"
1040 );
1041 }
1042 Message::builder(
1043 MessageType::from_class_method(MessageClass::Success, orig.method()),
1044 orig.transaction_id(),
1045 write,
1046 )
1047 }
1048
1049 pub fn builder_error<B: MessageWrite>(orig: &Message, write: B) -> B {
1069 if !orig.has_class(MessageClass::Request) {
1070 panic!(
1071 "An error response message was attempted to be created from a non-request message"
1072 );
1073 }
1074 Message::builder(
1075 MessageType::from_class_method(MessageClass::Error, orig.method()),
1076 orig.transaction_id(),
1077 write,
1078 )
1079 }
1080
1081 pub fn builder_indication<B: MessageWrite>(method: Method, write: B) -> B {
1095 Message::builder(
1096 MessageType::from_class_method(MessageClass::Indication, method),
1097 TransactionId::generate(),
1098 write,
1099 )
1100 }
1101
1102 pub fn get_type(&self) -> MessageType {
1116 MessageType::try_from(&self.data[..2]).unwrap()
1117 }
1118
1119 pub fn class(&self) -> MessageClass {
1131 self.get_type().class()
1132 }
1133
1134 pub fn has_class(&self, cls: MessageClass) -> bool {
1146 self.class() == cls
1147 }
1148
1149 pub fn is_response(&self) -> bool {
1171 self.class().is_response()
1172 }
1173
1174 pub fn method(&self) -> Method {
1186 self.get_type().method()
1187 }
1188
1189 pub fn has_method(&self, method: Method) -> bool {
1202 self.method() == method
1203 }
1204
1205 pub fn transaction_id(&self) -> TransactionId {
1219 BigEndian::read_u128(&self.data[4..]).into()
1220 }
1221
1222 #[tracing::instrument(
1244 name = "message_from_bytes",
1245 level = "trace",
1246 skip(data),
1247 fields(
1248 data.len = data.len()
1249 )
1250 )]
1251 pub fn from_bytes(data: &'a [u8]) -> Result<Self, StunParseError> {
1252 let orig_data = data;
1253
1254 let header = MessageHeader::from_bytes(data)?;
1255 let mlength = header.data_length() as usize;
1256 if mlength + MessageHeader::LENGTH > data.len() {
1257 warn!(
1259 "malformed advertised size {} and data size {} don't match",
1260 mlength + 20,
1261 data.len()
1262 );
1263 return Err(StunParseError::Truncated {
1264 expected: mlength + MessageHeader::LENGTH,
1265 actual: data.len(),
1266 });
1267 }
1268
1269 let ending_attributes = [
1270 MessageIntegrity::TYPE,
1271 MessageIntegritySha256::TYPE,
1272 Fingerprint::TYPE,
1273 ];
1274 let mut seen_ending_attributes = [AttributeType::new(0); 3];
1276 let mut seen_ending_len = 0;
1277 let mut data_offset = MessageHeader::LENGTH;
1278 let mut integrity_offset = None;
1279 for attr in MessageRawAttributesIter::new(data) {
1280 let (_offset, attr) = attr.inspect_err(|e| {
1281 warn!("failed to parse message attribute at offset {data_offset}: {e}",);
1282 })?;
1283
1284 if seen_ending_len > 0 && !ending_attributes.contains(&attr.get_type()) {
1287 if seen_ending_attributes.contains(&Fingerprint::TYPE) {
1288 warn!("unexpected attribute {} after FINGERPRINT", attr.get_type());
1289 return Ok(Message {
1290 data: orig_data,
1291 integrity_offset,
1292 });
1293 } else {
1294 warn!(
1296 "unexpected attribute {} after MESSAGE_INTEGRITY",
1297 attr.get_type()
1298 );
1299 return Ok(Message {
1300 data: orig_data,
1301 integrity_offset,
1302 });
1303 }
1304 }
1305
1306 if ending_attributes.contains(&attr.get_type()) {
1307 if seen_ending_attributes.contains(&attr.get_type()) {
1308 if seen_ending_attributes.contains(&Fingerprint::TYPE) {
1309 warn!("unexpected attribute {} after FINGERPRINT", attr.get_type());
1310 return Ok(Message {
1311 data: orig_data,
1312 integrity_offset,
1313 });
1314 } else {
1315 warn!(
1317 "unexpected attribute {} after MESSAGE_INTEGRITY",
1318 attr.get_type()
1319 );
1320 return Ok(Message {
1321 data: orig_data,
1322 integrity_offset,
1323 });
1324 }
1325 } else {
1326 seen_ending_attributes[seen_ending_len] = attr.get_type();
1327 seen_ending_len += 1;
1328 integrity_offset.get_or_insert(NonZeroUsize::new(data_offset).unwrap());
1329 }
1331 }
1332 let padded_len = attr.padded_len();
1333 if attr.get_type() == Fingerprint::TYPE {
1334 let f = Fingerprint::from_raw_ref(&attr)?;
1335 let msg_fingerprint = f.fingerprint();
1336 let mut header = [0; 4];
1337 header[0] = orig_data[0];
1338 header[1] = orig_data[1];
1339 BigEndian::write_u16(
1340 &mut header[2..4],
1341 (data_offset + padded_len - MessageHeader::LENGTH) as u16,
1342 );
1343 let fingerprint_data = &orig_data[4..data_offset];
1344 let calculated_fingerprint = Fingerprint::compute(&[&header, fingerprint_data]);
1345 if &calculated_fingerprint != msg_fingerprint {
1346 warn!(
1347 "fingerprint mismatch {:?} != {:?}",
1348 calculated_fingerprint, msg_fingerprint
1349 );
1350 return Err(StunParseError::FingerprintMismatch);
1351 }
1352 }
1353 data_offset += padded_len;
1354 }
1355 Ok(Message {
1356 data: orig_data,
1357 integrity_offset,
1358 })
1359 }
1360
1361 pub fn validate_integrity(
1381 &self,
1382 credentials: &MessageIntegrityCredentials,
1383 ) -> Result<IntegrityAlgorithm, ValidateError> {
1384 let offset = self
1385 .integrity_offset
1386 .ok_or(ValidateError::Parse(StunParseError::MissingAttribute(
1387 MessageIntegrity::TYPE,
1388 )))?
1389 .get();
1390
1391 let iter = MessageAttributesIter::at_offset(self.data, offset);
1392 let mut raw_sha1 = None;
1393 let mut raw_sha256 = None;
1394 for (offset, raw_attr) in iter {
1395 match raw_attr.get_type() {
1396 MessageIntegrity::TYPE => {
1397 raw_sha1 = Some((offset, raw_attr));
1398 }
1399 MessageIntegritySha256::TYPE => {
1400 raw_sha256 = Some((offset, raw_attr));
1401 }
1402 _ => (),
1403 }
1404 }
1405
1406 let integrity_sha1;
1407 let integrity_sha256;
1408 let (algo, msg_hmac, offset) = match (raw_sha1, raw_sha256) {
1409 (_, Some((offset, sha256))) => {
1410 integrity_sha256 = MessageIntegritySha256::try_from(&sha256)?;
1411 (IntegrityAlgorithm::Sha256, integrity_sha256.hmac(), offset)
1412 }
1413 (Some((offset, sha1)), None) => {
1414 integrity_sha1 = MessageIntegrity::try_from(&sha1)?;
1415 (
1416 IntegrityAlgorithm::Sha1,
1417 integrity_sha1.hmac().as_slice(),
1418 offset,
1419 )
1420 }
1421 (None, None) => {
1422 return Err(StunParseError::MissingAttribute(MessageIntegrity::TYPE).into())
1423 }
1424 };
1425 let key = credentials.make_key(algo);
1426 self.validate_integrity_with_hmac(algo, msg_hmac, &key, offset)
1427 }
1428
1429 pub fn validate_integrity_with_key(
1431 &self,
1432 key: &IntegrityKey,
1433 ) -> Result<IntegrityAlgorithm, ValidateError> {
1434 let offset = self
1435 .integrity_offset
1436 .ok_or(ValidateError::Parse(StunParseError::MissingAttribute(
1437 MessageIntegrity::TYPE,
1438 )))?
1439 .get();
1440
1441 let iter = MessageAttributesIter::at_offset(self.data, offset);
1442 let mut raw_sha1 = None;
1443 let mut raw_sha256 = None;
1444 for (offset, raw_attr) in iter {
1445 match raw_attr.get_type() {
1446 MessageIntegrity::TYPE => {
1447 raw_sha1 = Some((offset, raw_attr));
1448 }
1449 MessageIntegritySha256::TYPE => {
1450 raw_sha256 = Some((offset, raw_attr));
1451 }
1452 _ => (),
1453 }
1454 }
1455
1456 let integrity_sha1;
1457 let integrity_sha256;
1458 let (algo, msg_hmac, offset) = if let Some(algo) = key.key_algorithm {
1459 match (algo, raw_sha1, raw_sha256) {
1460 (IntegrityAlgorithm::Sha256, _, Some((offset, sha256))) => {
1461 integrity_sha256 = MessageIntegritySha256::try_from(&sha256)?;
1462 (algo, integrity_sha256.hmac(), offset)
1463 }
1464 (IntegrityAlgorithm::Sha1, Some((offset, sha1)), _) => {
1465 integrity_sha1 = MessageIntegrity::try_from(&sha1)?;
1466 (algo, integrity_sha1.hmac().as_slice(), offset)
1467 }
1468 _ => return Err(StunParseError::MissingAttribute(MessageIntegrity::TYPE).into()),
1469 }
1470 } else {
1471 match (raw_sha1, raw_sha256) {
1472 (_, Some((offset, sha256))) => {
1473 integrity_sha256 = MessageIntegritySha256::try_from(&sha256)?;
1474 (IntegrityAlgorithm::Sha256, integrity_sha256.hmac(), offset)
1475 }
1476 (Some((offset, sha1)), None) => {
1477 integrity_sha1 = MessageIntegrity::try_from(&sha1)?;
1478 (
1479 IntegrityAlgorithm::Sha1,
1480 integrity_sha1.hmac().as_slice(),
1481 offset,
1482 )
1483 }
1484 (None, None) => {
1485 return Err(StunParseError::MissingAttribute(MessageIntegrity::TYPE).into())
1486 }
1487 }
1488 };
1489 self.validate_integrity_with_hmac(algo, msg_hmac, key, offset)
1490 }
1491
1492 #[tracing::instrument(
1493 name = "message_validate_integrity_with_hmac",
1494 level = "trace",
1495 skip(self, key, msg_hmac),
1496 fields(
1497 msg.transaction = %self.transaction_id(),
1498 )
1499 )]
1500 fn validate_integrity_with_hmac(
1501 &self,
1502 algo: IntegrityAlgorithm,
1503 msg_hmac: &[u8],
1504 key: &IntegrityKey,
1505 integrity_offset: usize,
1506 ) -> Result<IntegrityAlgorithm, ValidateError> {
1507 if key.key_algorithm.is_some_and(|key_algo| key_algo != algo) {
1508 debug!(
1509 "Key algorithm ({:?}) does not match algo ({algo:?})",
1510 key.key_algorithm
1511 );
1512 return Err(StunParseError::DataMismatch.into());
1513 }
1514 debug_assert!(self.data.len() >= MessageHeader::LENGTH);
1516 debug_assert!(integrity_offset >= MessageHeader::LENGTH);
1517 debug_assert!(integrity_offset < self.data.len());
1518 let mut data = &self.data[integrity_offset..];
1519 let mut data_offset = integrity_offset;
1520 while !data.is_empty() {
1521 let attr = RawAttribute::from_bytes(data)?;
1522 if algo == IntegrityAlgorithm::Sha1 && attr.get_type() == MessageIntegrity::TYPE {
1523 let msg = MessageIntegrity::try_from(&attr)?;
1524 debug_assert!(msg.hmac().as_slice() == msg_hmac);
1525
1526 let mut header = [0; 4];
1529 header[0] = self.data[0];
1530 header[1] = self.data[1];
1531 let hmac_data = &self.data[4..data_offset];
1532 BigEndian::write_u16(
1533 &mut header[2..4],
1534 data_offset as u16 + 24 - MessageHeader::LENGTH as u16,
1535 );
1536 if MessageIntegrity::verify(
1537 &[header.as_slice(), hmac_data],
1538 key,
1539 msg_hmac.try_into().unwrap(),
1540 ) {
1541 return Ok(algo);
1542 } else {
1543 return Err(ValidateError::IntegrityFailed);
1544 }
1545 } else if algo == IntegrityAlgorithm::Sha256
1546 && attr.get_type() == MessageIntegritySha256::TYPE
1547 {
1548 let msg = MessageIntegritySha256::try_from(&attr)?;
1549 debug_assert!(msg.hmac() == msg_hmac);
1550
1551 let mut header = [0; 4];
1554 header[0] = self.data[0];
1555 header[1] = self.data[1];
1556 let hmac_data = &self.data[4..data_offset];
1557 BigEndian::write_u16(
1558 &mut header[2..4],
1559 data_offset as u16 + attr.padded_len() as u16 - MessageHeader::LENGTH as u16,
1560 );
1561 if MessageIntegritySha256::verify(&[&header, hmac_data], key, msg_hmac) {
1562 return Ok(algo);
1563 } else {
1564 return Err(ValidateError::IntegrityFailed);
1565 }
1566 }
1567 let padded_len = attr.padded_len();
1568 debug_assert!(padded_len <= data.len());
1570 data = &data[padded_len..];
1571 data_offset += padded_len;
1572 }
1573
1574 unreachable!();
1577 }
1578
1579 pub fn nth_raw_attribute(&self, atype: AttributeType, n: usize) -> Option<RawAttribute<'_>> {
1598 self.nth_raw_attribute_and_offset(atype, n)
1599 .map(|(_offset, attr)| attr)
1600 }
1601
1602 pub fn raw_attribute(&self, atype: AttributeType) -> Option<RawAttribute<'_>> {
1606 self.nth_raw_attribute(atype, 0)
1607 }
1608
1609 #[tracing::instrument(
1631 name = "message_nth_raw_attribute_and_offset",
1632 level = "trace",
1633 skip(self, atype),
1634 fields(
1635 msg.transaction = %self.transaction_id(),
1636 attribute_type = %atype,
1637 )
1638 )]
1639 pub fn nth_raw_attribute_and_offset(
1640 &self,
1641 atype: AttributeType,
1642 n: usize,
1643 ) -> Option<(usize, RawAttribute<'_>)> {
1644 if let Some((offset, attr)) = self
1645 .iter_attributes()
1646 .filter(|(_offset, attr)| attr.get_type() == atype)
1647 .nth(n)
1648 {
1649 trace!("found attribute at offset: {offset}");
1650 Some((offset, attr))
1651 } else {
1652 trace!("could not find attribute");
1653 None
1654 }
1655 }
1656
1657 pub fn raw_attribute_and_offset(
1662 &self,
1663 atype: AttributeType,
1664 ) -> Option<(usize, RawAttribute<'_>)> {
1665 self.nth_raw_attribute_and_offset(atype, 0)
1666 }
1667
1668 pub fn nth_attribute<A: AttributeFromRaw<'a> + AttributeStaticType>(
1690 &'a self,
1691 n: usize,
1692 ) -> Result<A, StunParseError> {
1693 self.nth_attribute_and_offset(n).map(|(_offset, attr)| attr)
1694 }
1695
1696 pub fn attribute<A: AttributeFromRaw<'a> + AttributeStaticType>(
1700 &'a self,
1701 ) -> Result<A, StunParseError> {
1702 self.nth_attribute(0)
1703 }
1704
1705 pub fn nth_attribute_and_offset<A: AttributeFromRaw<'a> + AttributeStaticType>(
1731 &'a self,
1732 n: usize,
1733 ) -> Result<(usize, A), StunParseError> {
1734 self.nth_raw_attribute_and_offset(A::TYPE, n)
1735 .ok_or(StunParseError::MissingAttribute(A::TYPE))
1736 .and_then(|(offset, raw)| A::from_raw(raw).map(|attr| (offset, attr)))
1737 }
1738
1739 pub fn attribute_and_offset<A: AttributeFromRaw<'a> + AttributeStaticType>(
1744 &'a self,
1745 ) -> Result<(usize, A), StunParseError> {
1746 self.nth_attribute_and_offset(0)
1747 }
1748
1749 pub fn iter_attributes(&self) -> impl Iterator<Item = (usize, RawAttribute<'_>)> {
1751 MessageAttributesIter::new(self.data)
1752 }
1753
1754 #[tracing::instrument(
1803 level = "trace",
1804 skip(msg, write),
1805 fields(
1806 msg.transaction = %msg.transaction_id(),
1807 )
1808 )]
1809 pub fn check_attribute_types<B: MessageWrite>(
1810 msg: &Message,
1811 supported: &[AttributeType],
1812 required_in_msg: &[AttributeType],
1813 write: B,
1814 ) -> Option<B> {
1815 let unsupported: Vec<AttributeType> = msg
1817 .iter_attributes()
1818 .map(|(_offset, a)| a.get_type())
1819 .filter(|at| at.comprehension_required() && !supported.contains(at))
1821 .collect();
1822 if !unsupported.is_empty() {
1823 warn!(
1824 "Message contains unknown comprehension required attributes {:?}, returning unknown attributes",
1825 unsupported
1826 );
1827 return Some(Message::unknown_attributes(msg, &unsupported, write));
1828 }
1829 let has_required_attribute_missing = required_in_msg
1830 .iter()
1831 .any(|&at| {
1833 !msg.iter_attributes()
1834 .map(|(_offset, a)| a.get_type())
1835 .any(|a| a == at)
1836 });
1837 if has_required_attribute_missing {
1838 warn!("Message is missing required attributes, returning bad request");
1839 return Some(Message::bad_request(msg, write));
1840 }
1841 None
1842 }
1843
1844 pub fn unknown_attributes<B: MessageWrite>(
1865 src: &Message,
1866 attributes: &[AttributeType],
1867 write: B,
1868 ) -> B {
1869 let mut out = Message::builder_error(src, write);
1870 let software = Software::new("stun-types").unwrap();
1871 out.add_attribute(&software).unwrap();
1872 let error = ErrorCode::new(420, "Unknown Attributes").unwrap();
1873 out.add_attribute(&error).unwrap();
1874 let unknown = UnknownAttributes::new(attributes);
1875 if !attributes.is_empty() {
1876 out.add_attribute(&unknown).unwrap();
1877 }
1878 out
1879 }
1880
1881 pub fn bad_request<B: MessageWrite>(src: &Message, write: B) -> B {
1899 let mut out = Message::builder_error(src, write);
1900 let software = Software::new("stun-types").unwrap();
1901 out.add_attribute(&software).unwrap();
1902 let error = ErrorCode::new(400, "Bad Request").unwrap();
1903 out.add_attribute(&error).unwrap();
1904 out
1905 }
1906
1907 pub fn has_attribute(&self, atype: AttributeType) -> bool {
1923 self.iter_attributes()
1924 .any(|(_offset, attr)| attr.get_type() == atype)
1925 }
1926
1927 pub fn as_bytes(&self) -> &[u8] {
1929 self.data
1930 }
1931}
1932impl<'a> TryFrom<&'a [u8]> for Message<'a> {
1933 type Error = StunParseError;
1934
1935 fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {
1936 Message::from_bytes(value)
1937 }
1938}
1939
1940impl AsRef<[u8]> for Message<'_> {
1941 fn as_ref(&self) -> &[u8] {
1942 self.data
1943 }
1944}
1945
1946#[derive(Debug)]
1947struct MessageRawAttributesIter<'a> {
1948 data: &'a [u8],
1949 data_i: usize,
1950}
1951
1952impl<'a> MessageRawAttributesIter<'a> {
1953 fn new(data: &'a [u8]) -> Self {
1954 Self::at_offset(data, MessageHeader::LENGTH)
1955 }
1956
1957 fn at_offset(data: &'a [u8], offset: usize) -> Self {
1958 Self {
1959 data,
1960 data_i: offset,
1961 }
1962 }
1963}
1964
1965impl<'a> Iterator for MessageRawAttributesIter<'a> {
1966 type Item = Result<(usize, RawAttribute<'a>), StunParseError>;
1967
1968 fn next(&mut self) -> Option<Self::Item> {
1969 if self.data_i >= self.data.len() {
1970 return None;
1971 }
1972
1973 match RawAttribute::from_bytes(&self.data[self.data_i..]) {
1974 Ok(attr) => {
1975 let padded_len = attr.padded_len();
1976 self.data_i += padded_len;
1977 if self.data_i > self.data.len() {
1978 warn!(
1979 "attribute {} extends past the end of the data",
1980 attr.get_type()
1981 );
1982 return Some(Err(StunParseError::Truncated {
1983 expected: self.data_i,
1984 actual: self.data.len(),
1985 }));
1986 }
1987 Some(Ok((self.data_i - padded_len, attr)))
1988 }
1989 Err(e) => {
1990 let offset = self.data_i;
1991 self.data_i = self.data.len();
1992 let e = match e {
1993 StunParseError::Truncated { expected, actual } => StunParseError::Truncated {
1994 expected: expected + 4 + offset,
1995 actual: actual + 4 + offset,
1996 },
1997 StunParseError::TooLarge { expected, actual } => StunParseError::TooLarge {
1998 expected: expected + 4 + offset,
1999 actual: actual + 4 + offset,
2000 },
2001 e => e,
2002 };
2003 Some(Err(e))
2004 }
2005 }
2006 }
2007}
2008
2009#[doc(hidden)]
2010#[derive(Debug)]
2011pub struct MessageAttributesIter<'a> {
2012 header_parsed: bool,
2013 inner: MessageRawAttributesIter<'a>,
2014 last_attr_type: AttributeType,
2015 seen_message_integrity: bool,
2016}
2017
2018impl<'a> MessageAttributesIter<'a> {
2019 pub fn new(data: &'a [u8]) -> Self {
2028 Self {
2029 header_parsed: false,
2030 inner: MessageRawAttributesIter::new(data),
2031 seen_message_integrity: false,
2032 last_attr_type: AttributeType::new(0),
2033 }
2034 }
2035
2036 fn at_offset(data: &'a [u8], offset: usize) -> Self {
2037 Self {
2038 header_parsed: true,
2039 inner: MessageRawAttributesIter::at_offset(data, offset),
2040 seen_message_integrity: false,
2041 last_attr_type: AttributeType::new(0),
2042 }
2043 }
2044}
2045
2046impl<'a> Iterator for MessageAttributesIter<'a> {
2047 type Item = (usize, RawAttribute<'a>);
2048
2049 fn next(&mut self) -> Option<Self::Item> {
2050 if self.last_attr_type == Fingerprint::TYPE {
2052 return None;
2053 }
2054
2055 if !self.header_parsed {
2056 let Ok(hdr) = MessageHeader::from_bytes(self.inner.data) else {
2057 self.last_attr_type = Fingerprint::TYPE;
2058 return None;
2059 };
2060 if hdr.data_length() as usize + MessageHeader::LENGTH > self.inner.data.len() {
2061 self.last_attr_type = Fingerprint::TYPE;
2062 return None;
2063 }
2064 self.header_parsed = true;
2065 }
2066
2067 let (offset, attr) = self.inner.next()?.ok()?;
2068 let attr_type = attr.get_type();
2069 if self.seen_message_integrity {
2070 if self.last_attr_type != Fingerprint::TYPE && attr_type == Fingerprint::TYPE {
2071 self.last_attr_type = attr_type;
2072 return Some((offset, attr));
2073 }
2074 if self.last_attr_type == MessageIntegrity::TYPE
2075 && attr_type == MessageIntegritySha256::TYPE
2076 {
2077 self.last_attr_type = attr_type;
2078 return Some((offset, attr));
2079 }
2080 self.last_attr_type = Fingerprint::TYPE;
2081 return None;
2082 }
2083 if attr.get_type() == MessageIntegrity::TYPE
2084 || attr.get_type() == MessageIntegritySha256::TYPE
2085 || attr.get_type() == Fingerprint::TYPE
2086 {
2087 self.seen_message_integrity = true;
2088 }
2089 self.last_attr_type = attr.get_type();
2090
2091 Some((offset, attr))
2092 }
2093}
2094
2095#[allow(clippy::len_without_is_empty)]
2096pub trait MessageWrite {
2098 type Output;
2100 fn max_size(&self) -> Option<usize> {
2103 None
2104 }
2105
2106 fn mut_data(&mut self) -> &mut [u8];
2108 fn data(&self) -> &[u8];
2110 fn len(&self) -> usize;
2112 fn push_data(&mut self, data: &[u8]);
2114 fn push_attribute_unchecked(&mut self, attr: &dyn AttributeWrite);
2116
2117 fn has_attribute(&self, atype: AttributeType) -> bool;
2119
2120 fn has_any_attribute(&self, atypes: &[AttributeType]) -> Option<AttributeType>;
2123
2124 fn finish(self) -> Self::Output;
2126}
2127
2128pub trait MessageWriteExt: MessageWrite {
2130 fn get_type(&self) -> MessageType {
2142 MessageType::from_bytes(self.data()).unwrap()
2143 }
2144
2145 fn class(&self) -> MessageClass {
2157 self.get_type().class()
2158 }
2159
2160 fn has_class(&self, cls: MessageClass) -> bool {
2172 self.class() == cls
2173 }
2174
2175 fn is_response(&self) -> bool {
2197 self.class().is_response()
2198 }
2199
2200 fn method(&self) -> Method {
2212 self.get_type().method()
2213 }
2214
2215 fn has_method(&self, method: Method) -> bool {
2228 self.method() == method
2229 }
2230
2231 fn transaction_id(&self) -> TransactionId {
2245 BigEndian::read_u128(&self.data()[4..]).into()
2246 }
2247
2248 fn add_message_integrity(
2283 &mut self,
2284 credentials: &MessageIntegrityCredentials,
2285 algorithm: IntegrityAlgorithm,
2286 ) -> Result<(), StunWriteError> {
2287 let key = credentials.make_key(algorithm);
2288 self.add_message_integrity_with_key(&key, algorithm)
2289 }
2290
2291 #[tracing::instrument(
2293 name = "message_add_integrity_with_key",
2294 level = "trace",
2295 err,
2296 skip(self),
2297 fields(
2298 msg.transaction = %self.transaction_id(),
2299 )
2300 )]
2301 fn add_message_integrity_with_key(
2302 &mut self,
2303 key: &IntegrityKey,
2304 algorithm: IntegrityAlgorithm,
2305 ) -> Result<(), StunWriteError> {
2306 let mut atypes = [AttributeType::new(0); 3];
2307 let mut i = 0;
2308 atypes[i] = match algorithm {
2309 IntegrityAlgorithm::Sha1 => MessageIntegrity::TYPE,
2310 IntegrityAlgorithm::Sha256 => MessageIntegritySha256::TYPE,
2311 };
2312 i += 1;
2313 if algorithm == IntegrityAlgorithm::Sha1 {
2314 atypes[i] = MessageIntegritySha256::TYPE;
2315 i += 1;
2316 }
2317 atypes[i] = Fingerprint::TYPE;
2318 i += 1;
2319
2320 match self.has_any_attribute(&atypes[..i]) {
2321 Some(MessageIntegrity::TYPE) => {
2323 return Err(StunWriteError::AttributeExists(MessageIntegrity::TYPE))
2324 }
2325 Some(MessageIntegritySha256::TYPE) => {
2326 return Err(StunWriteError::AttributeExists(
2327 MessageIntegritySha256::TYPE,
2328 ));
2329 }
2330 Some(Fingerprint::TYPE) => return Err(StunWriteError::FingerprintExists),
2331 _ => (),
2332 }
2333 match algorithm {
2334 IntegrityAlgorithm::Sha1 => {
2335 check_attribute_can_fit(self, &MessageIntegrity::new([0; 20]))?
2336 }
2337 IntegrityAlgorithm::Sha256 => {
2338 check_attribute_can_fit(self, &MessageIntegritySha256::new(&[0; 32]).unwrap())?
2339 }
2340 };
2341
2342 unsafe { self.add_message_integrity_with_key_unchecked(key, algorithm) };
2343
2344 Ok(())
2345 }
2346
2347 unsafe fn add_message_integrity_with_key_unchecked(
2358 &mut self,
2359 key: &IntegrityKey,
2360 algorithm: IntegrityAlgorithm,
2361 ) {
2362 match algorithm {
2365 IntegrityAlgorithm::Sha1 => {
2366 self.push_attribute_unchecked(&MessageIntegrity::new([0; 20]));
2367 let len = self.len();
2368 let data = self.mut_data();
2369 let integrity = MessageIntegrity::compute(&[&data[..len - 24]], key).unwrap();
2370 data[len - 20..].copy_from_slice(&integrity);
2371 }
2372 IntegrityAlgorithm::Sha256 => {
2373 self.push_attribute_unchecked(&MessageIntegritySha256::new(&[0; 32]).unwrap());
2374 let len = self.len();
2375 let data = self.mut_data();
2376 let integrity = MessageIntegritySha256::compute(&[&data[..len - 36]], key).unwrap();
2377 data[len - 32..].copy_from_slice(&integrity);
2378 }
2379 }
2380 }
2381
2382 #[tracing::instrument(
2400 name = "message_add_fingerprint",
2401 level = "trace",
2402 skip(self),
2403 fields(
2404 msg.transaction = %self.transaction_id(),
2405 )
2406 )]
2407 fn add_fingerprint(&mut self) -> Result<(), StunWriteError> {
2408 if self.has_attribute(Fingerprint::TYPE) {
2409 return Err(StunWriteError::AttributeExists(Fingerprint::TYPE));
2410 }
2411
2412 check_attribute_can_fit(self, &Fingerprint::new([0; 4]))?;
2413 unsafe { self.add_fingerprint_unchecked() };
2414
2415 Ok(())
2416 }
2417
2418 unsafe fn add_fingerprint_unchecked(&mut self) {
2428 self.push_attribute_unchecked(&Fingerprint::new([0; 4]));
2431 let len = self.len();
2432 let data = self.mut_data();
2433 let fingerprint = Fingerprint::compute(&[&data[..len - 8]]);
2434 let fingerprint = Fingerprint::new(fingerprint);
2435 fingerprint.write_into(&mut data[len - 8..]).unwrap();
2436 }
2437
2438 #[tracing::instrument(
2467 name = "message_add_attribute",
2468 level = "trace",
2469 err,
2470 skip(self, attr),
2471 fields(
2472 msg.transaction = %self.transaction_id(),
2473 )
2474 )]
2475 fn add_attribute(&mut self, attr: &dyn AttributeWrite) -> Result<(), StunWriteError> {
2476 let ty = attr.get_type();
2477 match ty {
2478 MessageIntegrity::TYPE => {
2479 panic!("Cannot write MessageIntegrity with `add_attribute`. Use add_message_integrity() instead");
2480 }
2481 MessageIntegritySha256::TYPE => {
2482 panic!("Cannot write MessageIntegritySha256 with `add_attribute`. Use add_message_integrity() instead");
2483 }
2484 Fingerprint::TYPE => {
2485 panic!(
2486 "Cannot write Fingerprint with `add_attribute`. Use add_fingerprint() instead"
2487 );
2488 }
2489 _ => (),
2490 }
2491 match self.has_any_attribute(&[
2492 MessageIntegrity::TYPE,
2493 MessageIntegritySha256::TYPE,
2494 Fingerprint::TYPE,
2495 ]) {
2496 Some(MessageIntegrity::TYPE) => return Err(StunWriteError::MessageIntegrityExists),
2498 Some(MessageIntegritySha256::TYPE) => {
2499 return Err(StunWriteError::MessageIntegrityExists)
2500 }
2501 Some(Fingerprint::TYPE) => return Err(StunWriteError::FingerprintExists),
2502 _ => (),
2503 }
2504 check_attribute_can_fit(self, attr)?;
2505 self.push_attribute_unchecked(attr);
2506 Ok(())
2507 }
2508}
2509
2510impl<T: MessageWrite> MessageWriteExt for T {}
2511
2512#[derive(Debug, Default)]
2514pub struct MessageWriteVec {
2515 output: Vec<u8>,
2516 attributes: smallvec::SmallVec<[AttributeType; 16]>,
2517}
2518
2519impl MessageWriteVec {
2520 pub fn new() -> Self {
2522 Self::default()
2523 }
2524
2525 pub fn with_capacity(capacity: usize) -> Self {
2527 Self {
2528 output: Vec::with_capacity(capacity),
2529 attributes: Default::default(),
2530 }
2531 }
2532}
2533
2534impl core::ops::Deref for MessageWriteVec {
2535 type Target = Vec<u8>;
2536 fn deref(&self) -> &Self::Target {
2537 &self.output
2538 }
2539}
2540
2541impl core::ops::DerefMut for MessageWriteVec {
2542 fn deref_mut(&mut self) -> &mut Self::Target {
2543 &mut self.output
2544 }
2545}
2546
2547impl MessageWrite for MessageWriteVec {
2548 type Output = Vec<u8>;
2549
2550 fn mut_data(&mut self) -> &mut [u8] {
2551 &mut self.output
2552 }
2553
2554 fn data(&self) -> &[u8] {
2555 &self.output
2556 }
2557
2558 fn len(&self) -> usize {
2559 self.output.len()
2560 }
2561
2562 fn push_data(&mut self, data: &[u8]) {
2563 self.output.extend(data)
2564 }
2565
2566 fn finish(self) -> Self::Output {
2567 self.output
2568 }
2569
2570 fn push_attribute_unchecked(&mut self, attr: &dyn AttributeWrite) {
2571 let offset = self.output.len();
2572 let padded_len = attr.padded_len();
2573 let expected = offset + padded_len;
2574 BigEndian::write_u16(
2575 &mut self.output[2..4],
2576 (expected - MessageHeader::LENGTH) as u16,
2577 );
2578 self.output.resize(expected, 0);
2579 attr.write_into_unchecked(&mut self.output[offset..]);
2580 self.attributes.push(attr.get_type());
2581 }
2582
2583 fn has_attribute(&self, atype: AttributeType) -> bool {
2584 self.attributes.contains(&atype)
2585 }
2586
2587 fn has_any_attribute(&self, atypes: &[AttributeType]) -> Option<AttributeType> {
2588 self.attributes
2589 .iter()
2590 .find(|&typ| atypes.contains(typ))
2591 .cloned()
2592 }
2593}
2594
2595#[derive(Debug, Default)]
2597pub struct MessageWriteMutSlice<'a> {
2598 output: &'a mut [u8],
2599 offset: usize,
2600 attributes: smallvec::SmallVec<[AttributeType; 16]>,
2601}
2602
2603impl<'a> MessageWriteMutSlice<'a> {
2604 pub fn new(data: &'a mut [u8]) -> Self {
2606 Self {
2607 output: data,
2608 offset: 0,
2609 attributes: Default::default(),
2610 }
2611 }
2612}
2613
2614impl core::ops::Deref for MessageWriteMutSlice<'_> {
2615 type Target = [u8];
2616 fn deref(&self) -> &Self::Target {
2617 self.output
2618 }
2619}
2620
2621impl core::ops::DerefMut for MessageWriteMutSlice<'_> {
2622 fn deref_mut(&mut self) -> &mut Self::Target {
2623 self.output
2624 }
2625}
2626
2627impl<'a> MessageWrite for MessageWriteMutSlice<'a> {
2628 type Output = usize;
2629
2630 fn max_size(&self) -> Option<usize> {
2631 Some(self.output.len())
2632 }
2633
2634 fn mut_data(&mut self) -> &mut [u8] {
2635 &mut self.output[..self.offset]
2636 }
2637
2638 fn data(&self) -> &[u8] {
2639 &self.output[..self.offset]
2640 }
2641
2642 fn len(&self) -> usize {
2643 self.offset
2644 }
2645
2646 fn push_data(&mut self, data: &[u8]) {
2647 let len = data.len();
2648 self.output[self.offset..self.offset + len].copy_from_slice(data);
2649 self.offset += len;
2650 }
2651
2652 fn push_attribute_unchecked(&mut self, attr: &dyn AttributeWrite) {
2653 let padded_len = attr.padded_len();
2654 let expected = self.offset + padded_len;
2655 BigEndian::write_u16(
2656 &mut self.output[2..4],
2657 (expected - MessageHeader::LENGTH) as u16,
2658 );
2659 self.attributes.push(attr.get_type());
2660 attr.write_into(&mut self.output[self.offset..self.offset + padded_len])
2661 .unwrap();
2662 self.offset += padded_len;
2663 }
2664
2665 fn finish(self) -> Self::Output {
2666 self.offset
2667 }
2668
2669 fn has_attribute(&self, atype: AttributeType) -> bool {
2670 self.attributes.contains(&atype)
2671 }
2672
2673 fn has_any_attribute(&self, atypes: &[AttributeType]) -> Option<AttributeType> {
2674 self.attributes
2675 .iter()
2676 .find(|&typ| atypes.contains(typ))
2677 .cloned()
2678 }
2679}
2680
2681fn check_attribute_can_fit<O, T: MessageWrite<Output = O> + ?Sized>(
2682 this: &mut T,
2683 attr: &dyn AttributeWrite,
2684) -> Result<usize, StunWriteError> {
2685 let len = attr.padded_len();
2686 let out_data = this.data();
2687 if out_data.len() < MessageHeader::LENGTH {
2688 return Err(StunWriteError::TooSmall {
2689 expected: 20,
2690 actual: out_data.len(),
2691 });
2692 }
2693 let expected = BigEndian::read_u16(&out_data[2..4]) as usize + MessageHeader::LENGTH + len;
2694 if let Some(max) = this.max_size() {
2695 if max < expected {
2696 return Err(StunWriteError::TooSmall {
2697 expected,
2698 actual: max,
2699 });
2700 }
2701 }
2702 Ok(expected)
2703}
2704
2705#[cfg(test)]
2706mod tests {
2707 use alloc::borrow::ToOwned;
2708 use precis_profiles::precis_core::profile::Profile;
2709 use tracing::error;
2710
2711 use super::*;
2712
2713 #[test]
2714 #[should_panic(expected = "Method value is out of range")]
2715 fn method_value_out_of_range() {
2716 let _log = crate::tests::test_init_log();
2717 Method::new(0xf000);
2718 }
2719
2720 #[test]
2721 #[cfg(feature = "std")]
2722 fn method_name() {
2723 let _log = crate::tests::test_init_log();
2724 assert_eq!(BINDING.name(), "BINDING");
2725 let method = Method::new(0x111);
2726 method.add_name("SOME-NAME");
2727 assert_eq!(method.name(), "SOME-NAME");
2728 assert_eq!(Method::new(0x112).name(), "unknown");
2729 }
2730
2731 #[test]
2732 fn msg_type_roundtrip() {
2733 let _log = crate::tests::test_init_log();
2734 for m in 0..0xfff {
2736 let m = Method::new(m);
2737 let classes = vec![
2738 MessageClass::Request,
2739 MessageClass::Indication,
2740 MessageClass::Success,
2741 MessageClass::Error,
2742 ];
2743 for c in classes {
2744 let mtype = MessageType::from_class_method(c, m);
2745 trace!("{mtype}");
2746 assert_eq!(mtype.class(), c);
2747 assert!(mtype.has_class(c));
2748 assert_eq!(mtype.method(), m);
2749 assert!(mtype.has_method(m));
2750 let bytes = mtype.to_bytes();
2751 let ptype = MessageType::from_bytes(&bytes).unwrap();
2752 assert_eq!(mtype, ptype);
2753 }
2754 }
2755 }
2756
2757 #[test]
2758 fn msg_type_not_stun() {
2759 assert!(matches!(
2760 MessageType::from_bytes(&[0xc0, 0x00]),
2761 Err(StunParseError::NotStun)
2762 ));
2763 }
2764
2765 #[test]
2766 fn msg_roundtrip() {
2767 let _log = crate::tests::test_init_log();
2768 for m in (0x009..0x4ff).step_by(0x123) {
2770 let m = Method::new(m);
2771 let classes = vec![
2772 MessageClass::Request,
2773 MessageClass::Indication,
2774 MessageClass::Success,
2775 MessageClass::Error,
2776 ];
2777 for c in classes {
2778 let mtype = MessageType::from_class_method(c, m);
2779 for tid in (0x18..0xff_ffff_ffff_ffff_ffff).step_by(0xfedc_ba98_7654_3210) {
2780 let mut msg = Message::builder(mtype, tid.into(), MessageWriteVec::default());
2781 let attr = RawAttribute::new(1.into(), &[3]);
2782 assert!(msg.add_attribute(&attr).is_ok());
2783 let data = msg.finish();
2784
2785 let msg = Message::from_bytes(&data).unwrap();
2786 let msg_attr = msg.raw_attribute(1.into()).unwrap();
2787 assert_eq!(msg_attr, attr);
2788 assert_eq!(msg.get_type(), mtype);
2789 assert_eq!(msg.transaction_id(), tid.into());
2790 assert_eq!(msg.as_bytes(), &data);
2791 assert_eq!(msg.as_ref(), &data);
2792 }
2793 }
2794 }
2795 }
2796
2797 #[test]
2798 fn unknown_attributes() {
2799 let _log = crate::tests::test_init_log();
2800 let src = Message::builder_request(BINDING, MessageWriteVec::default()).finish();
2801 let src = Message::from_bytes(&src).unwrap();
2802 let msg =
2803 Message::unknown_attributes(&src, &[Software::TYPE], MessageWriteVec::new()).finish();
2804 let msg = Message::from_bytes(&msg).unwrap();
2805 assert_eq!(msg.transaction_id(), src.transaction_id());
2806 assert_eq!(msg.class(), MessageClass::Error);
2807 assert!(msg.has_class(MessageClass::Error));
2808 assert!(!msg.has_class(MessageClass::Success));
2809 assert_eq!(msg.method(), src.method());
2810 assert!(msg.has_method(src.method()));
2811 let err = msg.attribute::<ErrorCode>().unwrap();
2812 assert_eq!(err.code(), 420);
2813 let unknown_attrs = msg.attribute::<UnknownAttributes>().unwrap();
2814 assert!(unknown_attrs.has_attribute(Software::TYPE));
2815 }
2816
2817 #[test]
2818 fn bad_request() {
2819 let _log = crate::tests::test_init_log();
2820 let src = Message::builder_request(BINDING, MessageWriteVec::new()).finish();
2821 let src = Message::from_bytes(&src).unwrap();
2822 let msg = Message::bad_request(&src, MessageWriteVec::new());
2823 assert!(msg.has_class(MessageClass::Error));
2824 assert!(!msg.has_class(MessageClass::Success));
2825 assert!(msg.has_method(src.method()));
2826 assert!(!msg.has_method(Method::new(0x111)));
2827 assert!(msg.is_response());
2828 let msg = msg.finish();
2829 let msg = Message::from_bytes(&msg).unwrap();
2830 assert_eq!(msg.transaction_id(), src.transaction_id());
2831 assert_eq!(msg.class(), MessageClass::Error);
2832 assert_eq!(msg.method(), src.method());
2833 let err = msg.attribute::<ErrorCode>().unwrap();
2834 assert_eq!(err.code(), 400);
2835 }
2836
2837 #[test]
2838 fn fingerprint() {
2839 let _log = crate::tests::test_init_log();
2840 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2841 assert!(msg.has_class(MessageClass::Request));
2842 assert!(!msg.has_class(MessageClass::Success));
2843 assert!(msg.has_method(BINDING));
2844 assert!(!msg.has_method(Method::new(0x111)));
2845 let software = Software::new("s").unwrap();
2846 msg.add_attribute(&software).unwrap();
2847 msg.add_fingerprint().unwrap();
2848 let bytes = msg.finish();
2849 let new_msg = Message::from_bytes(&bytes).unwrap();
2851 let (offset, software) = new_msg.attribute_and_offset::<Software>().unwrap();
2852 assert_eq!(software.software(), "s");
2853 assert_eq!(offset, 20);
2854 let (offset, _new_fingerprint) =
2855 new_msg.raw_attribute_and_offset(Fingerprint::TYPE).unwrap();
2856 assert_eq!(offset, 28);
2857 }
2858
2859 #[test]
2860 fn integrity() {
2861 let _log = crate::tests::test_init_log();
2862 for algorithm in [IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256] {
2863 let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2864 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2865 let software = Software::new("s").unwrap();
2866 msg.add_attribute(&software).unwrap();
2867 msg.add_message_integrity(&credentials, algorithm).unwrap();
2868 let bytes = msg.finish();
2869 let new_msg = Message::from_bytes(&bytes).unwrap();
2871 new_msg.validate_integrity(&credentials).unwrap();
2872 let (offset, software) = new_msg.attribute_and_offset::<Software>().unwrap();
2873 assert_eq!(software.software(), "s");
2874 assert_eq!(offset, 20);
2875 }
2876 }
2877
2878 #[test]
2879 fn write_into_short_destination() {
2880 let _log = crate::tests::test_init_log();
2881 const LEN: usize = MessageHeader::LENGTH + 8;
2882 let mut data = [0; LEN - 1];
2883 let mut msg = Message::builder_request(BINDING, MessageWriteMutSlice::new(&mut data));
2884 let software = Software::new("s").unwrap();
2885 assert!(
2886 matches!(msg.add_attribute(&software), Err(StunWriteError::TooSmall { expected, actual }) if expected == LEN && actual == LEN - 1)
2887 );
2888 }
2889
2890 #[test]
2891 fn integrity_key() {
2892 let _log = crate::tests::test_init_log();
2893 let credentials1 = ShortTermCredentials::new("pass1".to_owned());
2894 let key1 =
2895 MessageIntegrityCredentials::from(credentials1).make_key(IntegrityAlgorithm::Sha1);
2896 let credentials2 = ShortTermCredentials::new("pass2".to_owned());
2897 let key2 =
2898 MessageIntegrityCredentials::from(credentials2).make_key(IntegrityAlgorithm::Sha1);
2899 assert_eq!(key1, key1);
2900 assert_eq!(key2, key2);
2901 assert_ne!(key1, key2);
2902 }
2903
2904 #[test]
2905 fn add_duplicate_integrity() {
2906 let _log = crate::tests::test_init_log();
2907 let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2908 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2909 msg.add_message_integrity(&credentials, IntegrityAlgorithm::Sha1)
2910 .unwrap();
2911 assert!(matches!(
2912 msg.add_message_integrity(&credentials, IntegrityAlgorithm::Sha1),
2913 Err(StunWriteError::AttributeExists(MessageIntegrity::TYPE))
2914 ));
2915 msg.add_message_integrity(&credentials, IntegrityAlgorithm::Sha256)
2916 .unwrap();
2917 assert!(matches!(
2918 msg.add_message_integrity(&credentials, IntegrityAlgorithm::Sha256),
2919 Err(StunWriteError::AttributeExists(
2920 MessageIntegritySha256::TYPE
2921 ))
2922 ));
2923 let software = Software::new("s").unwrap();
2924 assert!(matches!(
2925 msg.add_attribute(&software),
2926 Err(StunWriteError::MessageIntegrityExists)
2927 ));
2928 }
2929
2930 #[test]
2931 fn add_sha1_integrity_after_sha256() {
2932 let _log = crate::tests::test_init_log();
2933 let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2934 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2935 msg.add_message_integrity(&credentials, IntegrityAlgorithm::Sha256)
2936 .unwrap();
2937 assert!(matches!(
2938 msg.add_message_integrity(&credentials, IntegrityAlgorithm::Sha1),
2939 Err(StunWriteError::AttributeExists(
2940 MessageIntegritySha256::TYPE
2941 ))
2942 ));
2943 }
2944
2945 #[test]
2946 fn add_attribute_after_integrity() {
2947 let _log = crate::tests::test_init_log();
2948 for algorithm in [IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256] {
2949 let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2950 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2951 msg.add_message_integrity(&credentials, algorithm).unwrap();
2952 let software = Software::new("s").unwrap();
2953 assert!(matches!(
2954 msg.add_attribute(&software),
2955 Err(StunWriteError::MessageIntegrityExists)
2956 ));
2957 }
2958 }
2959
2960 #[test]
2961 fn add_raw_attribute_after_integrity() {
2962 let _log = crate::tests::test_init_log();
2963 for algorithm in [IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256] {
2964 let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2965 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2966 msg.add_message_integrity(&credentials, algorithm).unwrap();
2967 let software = Software::new("s").unwrap();
2968 let raw = software.to_raw();
2969 assert!(matches!(
2970 msg.add_attribute(&raw),
2971 Err(StunWriteError::MessageIntegrityExists)
2972 ));
2973 }
2974 }
2975
2976 #[test]
2977 fn add_integrity_after_fingerprint() {
2978 let _log = crate::tests::test_init_log();
2979 for algorithm in [IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256] {
2980 let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2981 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2982 msg.add_fingerprint().unwrap();
2983 assert!(matches!(
2984 msg.add_message_integrity(&credentials, algorithm),
2985 Err(StunWriteError::FingerprintExists)
2986 ));
2987 }
2988 }
2989
2990 #[test]
2991 fn duplicate_fingerprint() {
2992 let _log = crate::tests::test_init_log();
2993 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2994 msg.add_fingerprint().unwrap();
2995 assert!(matches!(
2996 msg.add_fingerprint(),
2997 Err(StunWriteError::AttributeExists(Fingerprint::TYPE))
2998 ));
2999 }
3000
3001 #[test]
3002 fn parse_invalid_fingerprint() {
3003 let _log = crate::tests::test_init_log();
3004 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3005 msg.add_fingerprint().unwrap();
3006 let mut bytes = msg.finish();
3007 bytes[24] = 0x80;
3008 bytes[25] = 0x80;
3009 bytes[26] = 0x80;
3010 bytes[27] = 0x80;
3011 assert!(matches!(
3012 Message::from_bytes(&bytes),
3013 Err(StunParseError::FingerprintMismatch)
3014 ));
3015 }
3016
3017 #[test]
3018 fn parse_wrong_magic() {
3019 let _log = crate::tests::test_init_log();
3020 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3021 msg.add_fingerprint().unwrap();
3022 let mut bytes = msg.finish();
3023 bytes[4] = 0x80;
3024 assert!(matches!(
3025 Message::from_bytes(&bytes),
3026 Err(StunParseError::NotStun)
3027 ));
3028 }
3029
3030 #[test]
3031 fn parse_attribute_after_integrity() {
3032 let _log = crate::tests::test_init_log();
3033 for algorithm in [IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256] {
3034 let credentials = ShortTermCredentials::new("secret".to_owned()).into();
3035 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3036 msg.add_message_integrity(&credentials, algorithm).unwrap();
3037 let mut bytes = msg.finish();
3038 let software = Software::new("s").unwrap();
3039 let software_bytes = RawAttribute::from(&software).to_bytes();
3040 let software_len = software_bytes.len();
3041 bytes.extend(software_bytes);
3042 bytes[3] += software_len as u8;
3043 let msg = Message::from_bytes(&bytes).unwrap();
3044 assert!(msg.raw_attribute(Software::TYPE).is_none());
3045 }
3046 }
3047
3048 #[test]
3049 fn parse_duplicate_integrity_after_integrity() {
3050 let _log = crate::tests::test_init_log();
3051 for algorithm in [IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256] {
3052 let credentials = ShortTermCredentials::new("secret".to_owned()).into();
3053 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3054 msg.add_message_integrity(&credentials, algorithm).unwrap();
3055 unsafe {
3057 msg.add_message_integrity_with_key_unchecked(
3058 &credentials.make_key(IntegrityAlgorithm::Sha1),
3059 algorithm,
3060 )
3061 };
3062 let bytes = msg.finish();
3063 let integrity_type = match algorithm {
3064 IntegrityAlgorithm::Sha1 => MessageIntegrity::TYPE,
3065 IntegrityAlgorithm::Sha256 => MessageIntegritySha256::TYPE,
3066 };
3067 let msg = Message::from_bytes(&bytes).unwrap();
3068 msg.nth_raw_attribute(integrity_type, 0).unwrap();
3069 assert!(msg.nth_raw_attribute(integrity_type, 1).is_none());
3070 }
3071 }
3072
3073 #[test]
3074 fn parse_attribute_after_fingerprint() {
3075 let _log = crate::tests::test_init_log();
3076 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3077 msg.add_fingerprint().unwrap();
3078 let mut bytes = msg.finish();
3079 let software = Software::new("s").unwrap();
3080 let software_bytes = RawAttribute::from(&software).to_bytes();
3081 let software_len = software_bytes.len();
3082 bytes.extend(software_bytes);
3083 bytes[3] += software_len as u8;
3084 let msg = Message::from_bytes(&bytes).unwrap();
3085 assert!(msg.raw_attribute(Fingerprint::TYPE).is_some());
3086 assert!(msg.raw_attribute(Software::TYPE).is_none());
3087 }
3088
3089 #[test]
3090 fn parse_duplicate_fingerprint_after_fingerprint() {
3091 let _log = crate::tests::test_init_log();
3092 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3093 msg.add_fingerprint().unwrap();
3094 unsafe { msg.add_fingerprint_unchecked() };
3095 let bytes = msg.finish();
3096 let msg = Message::from_bytes(&bytes).unwrap();
3097 assert!(msg.nth_raw_attribute(Fingerprint::TYPE, 0).is_some());
3098 assert!(msg.nth_raw_attribute(Fingerprint::TYPE, 1).is_none());
3099 }
3100
3101 #[test]
3102 fn add_attribute_after_fingerprint() {
3103 let _log = crate::tests::test_init_log();
3104 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3105 msg.add_fingerprint().unwrap();
3106 let software = Software::new("s").unwrap();
3107 assert!(matches!(
3108 msg.add_attribute(&software),
3109 Err(StunWriteError::FingerprintExists)
3110 ));
3111 }
3112
3113 #[test]
3114 fn add_raw_attribute_after_fingerprint() {
3115 let _log = crate::tests::test_init_log();
3116 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3117 msg.add_fingerprint().unwrap();
3118 let software = Software::new("s").unwrap();
3119 let raw = software.to_raw();
3120 assert!(matches!(
3121 msg.add_attribute(&raw),
3122 Err(StunWriteError::FingerprintExists)
3123 ));
3124 }
3125
3126 #[test]
3127 fn parse_truncated_message_header() {
3128 let _log = crate::tests::test_init_log();
3129 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3130 msg.add_fingerprint().unwrap();
3131 let bytes = msg.finish();
3132 assert!(matches!(
3133 Message::from_bytes(&bytes[..8]),
3134 Err(StunParseError::Truncated {
3135 expected: 20,
3136 actual: 8
3137 })
3138 ));
3139 }
3140
3141 #[test]
3142 fn parse_truncated_message() {
3143 let _log = crate::tests::test_init_log();
3144 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3145 msg.add_fingerprint().unwrap();
3146 let bytes = msg.finish();
3147 assert!(matches!(
3148 Message::from_bytes(&bytes[..24]),
3149 Err(StunParseError::Truncated {
3150 expected: 28,
3151 actual: 24
3152 })
3153 ));
3154 }
3155
3156 #[test]
3157 fn parse_truncated_message_attribute() {
3158 let _log = crate::tests::test_init_log();
3159 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3160 msg.add_fingerprint().unwrap();
3161 let mut bytes = msg.finish();
3162 bytes[3] = 4;
3164 assert!(matches!(
3165 Message::from_bytes(&bytes[..24]),
3166 Err(StunParseError::Truncated {
3167 expected: 28,
3168 actual: 24
3169 })
3170 ));
3171 }
3172
3173 #[test]
3174 fn parse_attribute_extends_past_message_end() {
3175 let _log = crate::tests::test_init_log();
3176 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3177 msg.add_attribute(&Software::new("a").unwrap()).unwrap();
3178 msg[23] += 1;
3179 let mut bytes = msg.finish();
3180 bytes[3] -= 1;
3181 error!("{bytes:x?}");
3182 error!("{:?}", Message::from_bytes(&bytes[..27]));
3183 assert!(matches!(
3184 Message::from_bytes(&bytes[..27]),
3185 Err(StunParseError::Truncated {
3186 expected: 28,
3187 actual: 27
3188 })
3189 ));
3190 }
3191
3192 #[test]
3193 fn valid_attributes() {
3194 let _log = crate::tests::test_init_log();
3195 let mut src = Message::builder_request(BINDING, MessageWriteVec::new());
3196 let username = Username::new("123").unwrap();
3197 src.add_attribute(&username).unwrap();
3198 let nonce = Nonce::new("nonce").unwrap();
3199 src.add_attribute(&nonce).unwrap();
3200 assert!(!src.has_attribute(Fingerprint::TYPE));
3201 assert!(src.has_attribute(Nonce::TYPE));
3202 let src = src.finish();
3203 let src = Message::from_bytes(&src).unwrap();
3204 assert!(!src.has_attribute(Fingerprint::TYPE));
3205 assert!(src.has_attribute(Nonce::TYPE));
3206
3207 let res = Message::check_attribute_types(
3209 &src,
3210 &[Username::TYPE, Nonce::TYPE],
3211 &[Username::TYPE],
3212 MessageWriteVec::new(),
3213 );
3214 assert!(res.is_none());
3215
3216 let res = Message::check_attribute_types(
3218 &src,
3219 &[Username::TYPE, Nonce::TYPE],
3220 &[Fingerprint::TYPE],
3221 MessageWriteVec::new(),
3222 );
3223 assert!(res.is_some());
3224 let res = res.unwrap();
3225 let res = res.finish();
3226 let res = Message::from_bytes(&res).unwrap();
3227 assert!(res.has_class(MessageClass::Error));
3228 assert!(res.has_method(src.method()));
3229 let err = res.attribute::<ErrorCode>().unwrap();
3230 assert_eq!(err.code(), 400);
3231
3232 let res =
3234 Message::check_attribute_types(&src, &[Username::TYPE], &[], MessageWriteVec::new());
3235 assert!(res.is_some());
3236 let res = res.unwrap();
3237 let data = res.finish();
3238 let res = Message::from_bytes(&data).unwrap();
3239 assert!(res.has_class(MessageClass::Error));
3240 assert!(res.has_method(src.method()));
3241 let err = res.attribute::<ErrorCode>().unwrap();
3242 assert_eq!(err.code(), 420);
3243 let unknown = res.attribute::<UnknownAttributes>().unwrap();
3244 assert!(unknown.has_attribute(Nonce::TYPE));
3245 }
3246
3247 #[test]
3248 fn attributes_iter_with_short_data() {
3249 let _log = crate::tests::test_init_log();
3250 assert_eq!(
3251 MessageAttributesIter::new(&[0x0, 0x1, 0x2, 0x3, 0x4]).next(),
3252 None
3253 );
3254 assert_eq!(
3255 MessageAttributesIter::new(&[
3256 0x0, 0x1, 0x2, 0x3, 0x21, 0x12, 0xa4, 0x42, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf,
3257 0x10, 0x11, 0x12, 0x13, 0x14,
3258 ])
3259 .next(),
3260 None
3261 );
3262 }
3263
3264 #[test]
3265 fn attributes_iter_software_after_fingerprint_ignored() {
3266 let _log = crate::tests::test_init_log();
3267 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3268 msg.add_fingerprint().unwrap();
3269 let mut bytes = msg.finish();
3270 let software = Software::new("s").unwrap();
3271 let software_bytes = RawAttribute::from(&software).to_bytes();
3272 let software_len = software_bytes.len();
3273 bytes.extend(software_bytes);
3274 bytes[3] += software_len as u8;
3275 let mut it = MessageAttributesIter::new(&bytes);
3276 let (_offset, fingerprint) = it.next().unwrap();
3277 assert_eq!(fingerprint.get_type(), Fingerprint::TYPE);
3278 assert_eq!(it.next(), None);
3279 }
3280
3281 #[test]
3282 fn attributes_iter_message_integrities_fingerprint() {
3283 let _log = crate::tests::test_init_log();
3284 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3285 let credentials = ShortTermCredentials::new("pass".to_owned());
3286 msg.add_message_integrity(&credentials.clone().into(), IntegrityAlgorithm::Sha1)
3287 .unwrap();
3288 msg.add_message_integrity(&credentials.clone().into(), IntegrityAlgorithm::Sha256)
3289 .unwrap();
3290 msg.add_fingerprint().unwrap();
3291 let mut bytes = msg.finish();
3292 let software = Software::new("s").unwrap();
3293 let software_bytes = RawAttribute::from(&software).to_bytes();
3294 let software_len = software_bytes.len();
3295 bytes.extend(software_bytes);
3296 bytes[3] += software_len as u8;
3297 let mut it = MessageAttributesIter::new(&bytes);
3298 assert_eq!(it.next().unwrap().1.get_type(), MessageIntegrity::TYPE);
3299 assert_eq!(
3300 it.next().unwrap().1.get_type(),
3301 MessageIntegritySha256::TYPE
3302 );
3303 assert_eq!(it.next().unwrap().1.get_type(), Fingerprint::TYPE);
3304 assert_eq!(it.next(), None);
3305 }
3306
3307 #[test]
3308 fn message_parse_multiple_integrities_fingerprint() {
3309 let _log = crate::tests::test_init_log();
3310 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3311 let credentials = ShortTermCredentials::new("pass".to_owned());
3312 msg.add_message_integrity(&credentials.clone().into(), IntegrityAlgorithm::Sha1)
3313 .unwrap();
3314 msg.add_message_integrity(&credentials.clone().into(), IntegrityAlgorithm::Sha256)
3315 .unwrap();
3316 msg.add_fingerprint().unwrap();
3317 let key = credentials.make_key();
3318 let bytes = msg.finish();
3319 let msg = Message::from_bytes(&bytes).unwrap();
3320 assert!(msg.has_attribute(MessageIntegrity::TYPE));
3321 assert!(msg.has_attribute(MessageIntegritySha256::TYPE));
3322 assert!(!msg.has_attribute(Software::TYPE));
3323 assert_eq!(
3324 msg.validate_integrity(&credentials.clone().into()).unwrap(),
3325 IntegrityAlgorithm::Sha256
3326 );
3327 assert_eq!(
3328 msg.validate_integrity_with_key(&key).unwrap(),
3329 IntegrityAlgorithm::Sha256
3330 );
3331 }
3332
3333 #[test]
3334 fn validate_integrity_missing_attribute() {
3335 let _log = crate::tests::test_init_log();
3336 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3337 msg.add_fingerprint().unwrap();
3338 let credentials = ShortTermCredentials::new("pass".to_owned());
3339 let key = credentials.make_key();
3340 let bytes = msg.finish();
3341 let msg = Message::from_bytes(&bytes).unwrap();
3342 assert!(matches!(
3343 msg.validate_integrity(&credentials.clone().into()),
3344 Err(ValidateError::Parse(StunParseError::MissingAttribute(
3345 MessageIntegrity::TYPE
3346 )))
3347 ));
3348 assert!(matches!(
3349 msg.validate_integrity_with_key(&key),
3350 Err(ValidateError::Parse(StunParseError::MissingAttribute(
3351 MessageIntegrity::TYPE
3352 )))
3353 ));
3354 }
3355
3356 #[test]
3357 fn attributes_iter_fingerprint_after_fingerprint_ignored() {
3358 let _log = crate::tests::test_init_log();
3359 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3360 msg.add_fingerprint().unwrap();
3361 let mut bytes = msg.finish();
3362 let fingerprint = Fingerprint::new([bytes[bytes.len() - 1].wrapping_sub(1); 4]);
3363 let fingerprint_bytes = RawAttribute::from(&fingerprint).to_bytes();
3364 let fingerprint_len = fingerprint_bytes.len();
3365 bytes.extend(fingerprint_bytes);
3366 bytes[3] += fingerprint_len as u8;
3367 let mut it = MessageAttributesIter::new(&bytes);
3368 let (_offset, fingerprint) = it.next().unwrap();
3369 assert_eq!(fingerprint.get_type(), Fingerprint::TYPE);
3370 assert_eq!(it.next(), None);
3371 }
3372
3373 #[test]
3374 fn write_vec_state() {
3375 let _log = crate::tests::test_init_log();
3376 let mut src = Message::builder_request(BINDING, MessageWriteVec::with_capacity(0x10));
3377 assert_eq!(src.len(), 20);
3378 assert_eq!(src[4], 0x21);
3379 let username = Username::new("123").unwrap();
3380 src.add_attribute(&username).unwrap();
3381 let nonce = Nonce::new("nonce").unwrap();
3382 src.add_attribute(&nonce).unwrap();
3383
3384 assert!(src.has_attribute(Username::TYPE));
3385 assert!(src.has_attribute(Nonce::TYPE));
3386 assert_eq!(
3387 src.has_any_attribute(&[Username::TYPE, Nonce::TYPE]),
3388 Some(Username::TYPE)
3389 );
3390 assert_eq!(
3391 src.has_any_attribute(&[Nonce::TYPE, Username::TYPE]),
3392 Some(Username::TYPE)
3393 );
3394 assert!(src.has_class(MessageClass::Request));
3395 assert!(!src.is_response());
3396 assert!(src.has_method(BINDING));
3397 assert!(src.get_type().has_method(BINDING));
3398 assert!(src.get_type().has_class(MessageClass::Request));
3399 assert!(!src.has_method(Method::new(0x111)));
3400 assert!(!src.get_type().has_method(Method::new(0x111)));
3401 assert!(!src.get_type().has_class(MessageClass::Error));
3402 }
3403
3404 #[test]
3405 fn write_mut_slice_success() {
3406 let _log = crate::tests::test_init_log();
3407 let mut data = [0; 64];
3408 let mut src = Message::builder_request(BINDING, MessageWriteMutSlice::new(&mut data));
3409 assert_eq!(src.len(), 20);
3410 assert_eq!(src[4], 0x21);
3411 let username = Username::new("123").unwrap();
3412 src.add_attribute(&username).unwrap();
3413 let nonce = Nonce::new("nonce").unwrap();
3414 src.add_attribute(&nonce).unwrap();
3415 assert!(src.has_attribute(Username::TYPE));
3416 assert_eq!(
3417 src.has_any_attribute(&[Username::TYPE]),
3418 Some(Username::TYPE)
3419 );
3420 assert!(!src.has_attribute(Software::TYPE));
3421 assert_eq!(src.has_any_attribute(&[Realm::TYPE]), None);
3422 assert_eq!(src.mut_data().len(), src.len());
3423 assert_eq!(src.finish(), 40);
3424 let msg = Message::from_bytes(&data[..40]).unwrap();
3425 let u2 = msg.attribute::<Username>().unwrap();
3426 assert_eq!(u2.username(), "123");
3427 let n2 = msg.attribute::<Nonce>().unwrap();
3428 assert_eq!(n2.nonce(), "nonce");
3429 }
3430
3431 #[test]
3432 fn write_mut_slice_too_short() {
3433 let _log = crate::tests::test_init_log();
3434 let mut data = [0; 27];
3435 let mut src = Message::builder_request(BINDING, MessageWriteMutSlice::new(&mut data));
3436 assert!(matches!(
3437 src.add_attribute(&Username::new("123").unwrap()),
3438 Err(StunWriteError::TooSmall {
3439 expected: 28,
3440 actual: 27
3441 })
3442 ));
3443 }
3444
3445 #[test]
3446 #[should_panic(expected = "created from a non-request message")]
3447 fn builder_success_panic() {
3448 let _log = crate::tests::test_init_log();
3449 let msg = Message::builder(
3450 MessageType::from_class_method(MessageClass::Indication, BINDING),
3451 TransactionId::generate(),
3452 MessageWriteVec::new(),
3453 )
3454 .finish();
3455 let msg = Message::from_bytes(&msg).unwrap();
3456 let _builder = Message::builder_success(&msg, MessageWriteVec::new());
3457 }
3458
3459 #[test]
3460 #[should_panic(expected = "created from a non-request message")]
3461 fn builder_error_panic() {
3462 let _log = crate::tests::test_init_log();
3463 let msg = Message::builder(
3464 MessageType::from_class_method(MessageClass::Indication, BINDING),
3465 TransactionId::generate(),
3466 MessageWriteVec::new(),
3467 )
3468 .finish();
3469 let msg = Message::from_bytes(&msg).unwrap();
3470 let _builder = Message::builder_error(&msg, MessageWriteVec::new());
3471 }
3472
3473 #[test]
3474 #[should_panic(expected = "Use add_message_integrity() instead")]
3475 fn builder_add_attribute_integrity_panic() {
3476 let _log = crate::tests::test_init_log();
3477 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3478 let hmac = [2; 20];
3479 let integrity = MessageIntegrity::new(hmac);
3480 msg.add_attribute(&integrity).unwrap();
3481 }
3482
3483 #[test]
3484 #[should_panic(expected = "Use add_message_integrity() instead")]
3485 fn builder_add_raw_attribute_integrity_panic() {
3486 let _log = crate::tests::test_init_log();
3487 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3488 let hmac = [2; 20];
3489 let integrity = MessageIntegrity::new(hmac);
3490 let raw = integrity.to_raw();
3491 msg.add_attribute(&raw).unwrap();
3492 }
3493
3494 #[test]
3495 #[should_panic(expected = "Use add_message_integrity() instead")]
3496 fn builder_add_attribute_integrity_sha256_panic() {
3497 let _log = crate::tests::test_init_log();
3498 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3499 let hmac = [2; 16];
3500 let integrity = MessageIntegritySha256::new(&hmac).unwrap();
3501 msg.add_attribute(&integrity).unwrap();
3502 }
3503
3504 #[test]
3505 #[should_panic(expected = "Use add_message_integrity() instead")]
3506 fn builder_add_raw_attribute_integrity_sha256_panic() {
3507 let _log = crate::tests::test_init_log();
3508 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3509 let hmac = [2; 16];
3510 let integrity = MessageIntegritySha256::new(&hmac).unwrap();
3511 let raw = integrity.to_raw();
3512 msg.add_attribute(&raw).unwrap();
3513 }
3514
3515 #[test]
3516 #[should_panic(expected = "Use add_fingerprint() instead")]
3517 fn builder_add_attribute_fingerprint_panic() {
3518 let _log = crate::tests::test_init_log();
3519 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3520 let fingerprint = [2; 4];
3521 let fingerprint = Fingerprint::new(fingerprint);
3522 msg.add_attribute(&fingerprint).unwrap();
3523 }
3524
3525 #[test]
3526 #[should_panic(expected = "Use add_fingerprint() instead")]
3527 fn builder_add_raw_attribute_fingerprint_panic() {
3528 let _log = crate::tests::test_init_log();
3529 let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3530 let fingerprint = [2; 4];
3531 let fingerprint = Fingerprint::new(fingerprint);
3532 let raw = fingerprint.to_raw();
3533 msg.add_attribute(&raw).unwrap();
3534 }
3535
3536 #[test]
3537 fn rfc5769_vector1() {
3538 let _log = crate::tests::test_init_log();
3539 let data = vec![
3541 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, ];
3569 let msg = Message::from_bytes(&data).unwrap();
3570 assert!(msg.has_class(MessageClass::Request));
3571 assert!(msg.has_method(BINDING));
3572 assert_eq!(msg.transaction_id(), 0xb7e7_a701_bc34_d686_fa87_dfae.into());
3573
3574 let mut builder = Message::builder(
3575 MessageType::from_class_method(MessageClass::Request, BINDING),
3576 msg.transaction_id(),
3577 MessageWriteVec::new(),
3578 );
3579
3580 assert!(msg.has_attribute(Software::TYPE));
3582 let raw = msg.raw_attribute(Software::TYPE).unwrap();
3583 assert!(Software::try_from(&raw).is_ok());
3584 let software = Software::try_from(&raw).unwrap();
3585 assert_eq!(software.software(), "STUN test client");
3586 builder.add_attribute(&software).unwrap();
3587
3588 builder
3590 .add_attribute(&RawAttribute::new(0x24.into(), &[0x6e, 0x00, 0x01, 0xff]))
3591 .unwrap();
3592
3593 builder
3595 .add_attribute(&RawAttribute::new(
3596 0x8029.into(),
3597 &[0x93, 0x2f, 0xf9, 0xb1, 0x51, 0x26, 0x3b, 0x36],
3598 ))
3599 .unwrap();
3600
3601 assert!(msg.has_attribute(Username::TYPE));
3603 let raw = msg.raw_attribute(Username::TYPE).unwrap();
3604 assert!(Username::try_from(&raw).is_ok());
3605 let username = Username::try_from(&raw).unwrap();
3606 assert_eq!(username.username(), "evtj:h6vY");
3607 builder.add_attribute(&username).unwrap();
3608
3609 let credentials = MessageIntegrityCredentials::ShortTerm(ShortTermCredentials {
3611 password: "VOkJxbRl1RmTxUk/WvJxBt".to_owned(),
3612 });
3613 assert!(matches!(
3614 msg.validate_integrity(&credentials),
3615 Ok(IntegrityAlgorithm::Sha1)
3616 ));
3617 builder
3618 .add_message_integrity(&credentials, IntegrityAlgorithm::Sha1)
3619 .unwrap();
3620
3621 assert!(msg.has_attribute(Fingerprint::TYPE));
3623 builder.add_fingerprint().unwrap();
3624
3625 let mut msg_data = builder.finish();
3627 msg_data[73] = 0x20;
3629 msg_data[74] = 0x20;
3630 msg_data[75] = 0x20;
3631 assert_eq!(msg_data[..80], data[..80]);
3634 }
3635
3636 #[test]
3637 fn rfc5769_vector2() {
3638 let _log = crate::tests::test_init_log();
3639 let data = vec![
3641 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, ];
3662
3663 let msg = Message::from_bytes(&data).unwrap();
3664 assert!(msg.has_class(MessageClass::Success));
3665 assert!(msg.has_method(BINDING));
3666 assert_eq!(msg.transaction_id(), 0xb7e7_a701_bc34_d686_fa87_dfae.into());
3667 let mut builder = Message::builder(
3668 MessageType::from_class_method(MessageClass::Success, BINDING),
3669 msg.transaction_id(),
3670 MessageWriteVec::new(),
3671 );
3672
3673 assert!(msg.has_attribute(Software::TYPE));
3675 let raw = msg.raw_attribute(Software::TYPE).unwrap();
3676 assert!(Software::try_from(&raw).is_ok());
3677 let software = Software::try_from(&raw).unwrap();
3678 assert_eq!(software.software(), "test vector");
3679 builder.add_attribute(&software).unwrap();
3680
3681 assert!(msg.has_attribute(XorMappedAddress::TYPE));
3683 let raw = msg.raw_attribute(XorMappedAddress::TYPE).unwrap();
3684 assert!(XorMappedAddress::try_from(&raw).is_ok());
3685 let xor_mapped_addres = XorMappedAddress::try_from(&raw).unwrap();
3686 assert_eq!(
3687 xor_mapped_addres.addr(msg.transaction_id()),
3688 "192.0.2.1:32853".parse().unwrap()
3689 );
3690 builder.add_attribute(&xor_mapped_addres).unwrap();
3691
3692 let credentials = MessageIntegrityCredentials::ShortTerm(ShortTermCredentials {
3694 password: "VOkJxbRl1RmTxUk/WvJxBt".to_owned(),
3695 });
3696 let ret = msg.validate_integrity(&credentials);
3697 warn!("{:?}", ret);
3698 assert!(matches!(ret, Ok(IntegrityAlgorithm::Sha1)));
3699 builder
3700 .add_message_integrity(&credentials, IntegrityAlgorithm::Sha1)
3701 .unwrap();
3702
3703 assert!(msg.has_attribute(Fingerprint::TYPE));
3705 builder.add_fingerprint().unwrap();
3706
3707 let mut msg_data = builder.finish();
3709 msg_data[35] = 0x20;
3711 assert_eq!(msg_data[..52], data[..52]);
3712 }
3713
3714 #[test]
3715 fn rfc5769_vector3() {
3716 let _log = crate::tests::test_init_log();
3717 let data = vec![
3719 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, ];
3743
3744 let msg = Message::from_bytes(&data).unwrap();
3745 assert!(msg.has_class(MessageClass::Success));
3746 assert!(msg.has_method(BINDING));
3747 assert_eq!(msg.transaction_id(), 0xb7e7_a701_bc34_d686_fa87_dfae.into());
3748 let mut builder = Message::builder(
3749 MessageType::from_class_method(MessageClass::Success, BINDING),
3750 msg.transaction_id(),
3751 MessageWriteVec::new(),
3752 );
3753
3754 assert!(msg.has_attribute(Software::TYPE));
3756 let raw = msg.raw_attribute(Software::TYPE).unwrap();
3757 assert!(Software::try_from(&raw).is_ok());
3758 let software = Software::try_from(&raw).unwrap();
3759 assert_eq!(software.software(), "test vector");
3760 builder.add_attribute(&software).unwrap();
3761
3762 assert!(msg.has_attribute(XorMappedAddress::TYPE));
3764 let raw = msg.raw_attribute(XorMappedAddress::TYPE).unwrap();
3765 assert!(XorMappedAddress::try_from(&raw).is_ok());
3766 let xor_mapped_addres = XorMappedAddress::try_from(&raw).unwrap();
3767 assert_eq!(
3768 xor_mapped_addres.addr(msg.transaction_id()),
3769 "[2001:db8:1234:5678:11:2233:4455:6677]:32853"
3770 .parse()
3771 .unwrap()
3772 );
3773 builder.add_attribute(&xor_mapped_addres).unwrap();
3774
3775 let credentials = MessageIntegrityCredentials::ShortTerm(ShortTermCredentials {
3777 password: "VOkJxbRl1RmTxUk/WvJxBt".to_owned(),
3778 });
3779 assert!(matches!(
3780 msg.validate_integrity(&credentials),
3781 Ok(IntegrityAlgorithm::Sha1)
3782 ));
3783 builder
3784 .add_message_integrity(&credentials, IntegrityAlgorithm::Sha1)
3785 .unwrap();
3786
3787 assert!(msg.has_attribute(Fingerprint::TYPE));
3789 builder.add_fingerprint().unwrap();
3790
3791 let mut msg_data = builder.finish();
3793 msg_data[35] = 0x20;
3795 assert_eq!(msg_data[..64], data[..64]);
3796 }
3797
3798 #[test]
3799 fn rfc5769_vector4() {
3800 let _log = crate::tests::test_init_log();
3801 let data = vec![
3803 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, ];
3833
3834 let msg = Message::from_bytes(&data).unwrap();
3835 assert!(msg.has_class(MessageClass::Request));
3836 assert!(msg.has_method(BINDING));
3837 assert_eq!(msg.transaction_id(), 0x78ad_3433_c6ad_72c0_29da_412e.into());
3838 let mut builder = Message::builder(
3839 MessageType::from_class_method(MessageClass::Request, BINDING),
3840 msg.transaction_id(),
3841 MessageWriteVec::new(),
3842 );
3843
3844 let username = stringprep::saslprep("\u{30DE}\u{30C8}\u{30EA}\u{30C3}\u{30AF}\u{30B9}")
3845 .unwrap()
3846 .into_owned();
3847 let password = stringprep::saslprep("The\u{00AD}M\u{00AA}tr\u{2168}")
3848 .unwrap()
3849 .into_owned();
3850 trace!("password: {password:?}");
3851
3852 let long_term = LongTermKeyCredentials {
3853 username,
3854 password,
3855 realm: "example.org".to_owned(),
3856 };
3857 assert!(msg.has_attribute(Username::TYPE));
3859 let raw = msg.raw_attribute(Username::TYPE).unwrap();
3860 assert!(Username::try_from(&raw).is_ok());
3861 let username = Username::try_from(&raw).unwrap();
3862 assert_eq!(username.username(), &long_term.username);
3863 builder.add_attribute(&username).unwrap();
3864
3865 let expected_nonce = "f//499k954d6OL34oL9FSTvy64sA";
3867 assert!(msg.has_attribute(Nonce::TYPE));
3868 let raw = msg.raw_attribute(Nonce::TYPE).unwrap();
3869 assert!(Nonce::try_from(&raw).is_ok());
3870 let nonce = Nonce::try_from(&raw).unwrap();
3871 assert_eq!(nonce.nonce(), expected_nonce);
3872 builder.add_attribute(&nonce).unwrap();
3873
3874 assert!(msg.has_attribute(Realm::TYPE));
3876 let raw = msg.raw_attribute(Realm::TYPE).unwrap();
3877 assert!(Realm::try_from(&raw).is_ok());
3878 let realm = Realm::try_from(&raw).unwrap();
3879 assert_eq!(realm.realm(), long_term.realm());
3880 builder.add_attribute(&realm).unwrap();
3881
3882 let credentials = MessageIntegrityCredentials::LongTerm(long_term);
3884 assert!(matches!(
3885 msg.validate_integrity(&credentials),
3886 Ok(IntegrityAlgorithm::Sha1)
3887 ));
3888 builder
3889 .add_message_integrity(&credentials, IntegrityAlgorithm::Sha1)
3890 .unwrap();
3891
3892 assert_eq!(builder.finish()[4..], data[4..]);
3893 }
3894
3895 #[test]
3896 fn rfc8489_vector1() {
3897 let _log = crate::tests::test_init_log();
3898 let data = vec![
3901 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, ];
3943 let msg = Message::from_bytes(&data).unwrap();
3944 assert!(msg.has_class(MessageClass::Request));
3945 assert!(msg.has_method(BINDING));
3946 assert_eq!(msg.transaction_id(), 0x78ad_3433_c6ad_72c0_29da_412e.into());
3947 let mut builder = Message::builder(
3948 MessageType::from_class_method(MessageClass::Request, BINDING),
3949 msg.transaction_id(),
3950 MessageWriteVec::new(),
3951 );
3952
3953 let opaque = precis_profiles::OpaqueString::new();
3954 let username = opaque
3955 .prepare("\u{30DE}\u{30C8}\u{30EA}\u{30C3}\u{30AF}\u{30B9}")
3956 .unwrap()
3957 .into_owned();
3958 let orig_password = "The\u{00AD}M\u{00AA}tr\u{2168}";
3959 trace!("password: {orig_password:?}");
3960 let sasl_password = stringprep::saslprep(orig_password).unwrap().into_owned();
3983 trace!("password (saslprep): {sasl_password}");
3984
3985 let long_term = LongTermKeyCredentials {
3988 username: username.clone(),
3989 password: sasl_password.clone(),
3990 realm: "example.org".to_owned(),
3991 };
3992 assert!(msg.has_attribute(Userhash::TYPE));
3994 let raw = msg.raw_attribute(Userhash::TYPE).unwrap();
3995 assert!(Userhash::try_from(&raw).is_ok());
3996 let userhash = Userhash::try_from(&raw).unwrap();
3997 builder.add_attribute(&userhash).unwrap();
3998
3999 let expected_nonce = "obMatJos2AAACf//499k954d6OL34oL9FSTvy64sA";
4001 assert!(msg.has_attribute(Nonce::TYPE));
4002 let raw = msg.raw_attribute(Nonce::TYPE).unwrap();
4003 assert!(Nonce::try_from(&raw).is_ok());
4004 let nonce = Nonce::try_from(&raw).unwrap();
4005 assert_eq!(nonce.nonce(), expected_nonce);
4006 builder.add_attribute(&nonce).unwrap();
4007
4008 assert!(msg.has_attribute(Realm::TYPE));
4010 let raw = msg.raw_attribute(Realm::TYPE).unwrap();
4011 assert!(Realm::try_from(&raw).is_ok());
4012 let realm = Realm::try_from(&raw).unwrap();
4013 assert_eq!(realm.realm(), long_term.realm);
4014 builder.add_attribute(&realm).unwrap();
4015
4016 assert!(msg.has_attribute(PasswordAlgorithm::TYPE));
4018 let raw = msg.raw_attribute(PasswordAlgorithm::TYPE).unwrap();
4019 assert!(PasswordAlgorithm::try_from(&raw).is_ok());
4020 let algo = PasswordAlgorithm::try_from(&raw).unwrap();
4021 assert_eq!(algo.algorithm(), PasswordAlgorithmValue::SHA256);
4022 builder.add_attribute(&algo).unwrap();
4023
4024 trace!("long term: {long_term:?}");
4045 let credentials = MessageIntegrityCredentials::LongTerm(long_term);
4046 assert!(matches!(
4047 msg.validate_integrity(&credentials),
4048 Ok(IntegrityAlgorithm::Sha256)
4049 ));
4050 builder
4051 .add_message_integrity(&credentials, IntegrityAlgorithm::Sha256)
4052 .unwrap();
4053
4054 assert_eq!(builder.finish()[4..], data[4..]);
4055 }
4056}