stun_types/
message.rs

1// Copyright (C) 2020 Matthew Waters <matthew@centricular.com>
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9//! STUN Messages
10//!
11//! Provides types for generating, parsing, and manipulating STUN messages as specified in one of
12//! [RFC8489], [RFC5389], or [RFC3489].
13//!
14//! [RFC8489]: https://tools.ietf.org/html/rfc8489
15//! [RFC5389]: https://tools.ietf.org/html/rfc5389
16//! [RFC3489]: https://tools.ietf.org/html/rfc3489
17//!
18//! ## Examples
19//!
20//! ### Parse a STUN [`Message`]
21//!
22//! ```
23//! use stun_types::prelude::*;
24//! use stun_types::attribute::{RawAttribute, PasswordAlgorithm, PasswordAlgorithmValue};
25//! use stun_types::message::{Message, MessageType, MessageClass, BINDING};
26//!
27//! let msg_data = [
28//!     0x00, 0x01, 0x00, 0x08, // method, class and length
29//!     0x21, 0x12, 0xA4, 0x42, // Fixed STUN magic bytes
30//!     0x00, 0x00, 0x00, 0x00, // \
31//!     0x00, 0x00, 0x00, 0x00, // } transaction ID
32//!     0x00, 0x00, 0x73, 0x92, // /
33//!     0x00, 0x1D, 0x00, 0x04, // PasswordAlgorithm attribute header (type and length)
34//!     0x00, 0x02, 0x00, 0x00  // PasswordAlgorithm attribute value
35//! ];
36//! let msg = Message::from_bytes(&msg_data).unwrap();
37//!
38//! // the various parts of a message can be retreived
39//! assert_eq!(msg.get_type(), MessageType::from_class_method(MessageClass::Request, BINDING));
40//! assert_eq!(msg.transaction_id(), 0x7392.into());
41//!
42//! // Attributes can be retrieved as raw values.
43//! let msg_attr = msg.raw_attribute(0x1D.into()).unwrap();
44//! let attr = RawAttribute::new(0x1D.into(), &[0, 2, 0, 0]);
45//! assert_eq!(msg_attr, attr);
46//!
47//! // Or as typed values
48//! let attr = msg.attribute::<PasswordAlgorithm>().unwrap();
49//! assert_eq!(attr.algorithm(), PasswordAlgorithmValue::SHA256);
50//! ```
51//!
52//! ### Generating a [`Message`]
53//!
54//! ```
55//! use stun_types::prelude::*;
56//! use stun_types::attribute::Software;
57//! use stun_types::message::{Message, BINDING};
58//!
59//! // Automatically generates a transaction ID.
60//! let mut msg = Message::builder_request(BINDING);
61//!
62//! let software_name = "stun-types";
63//! let software = Software::new(software_name).unwrap();
64//! assert_eq!(software.software(), software_name);
65//! msg.add_attribute(&software).unwrap();
66//!
67//! let attribute_data = [
68//!     0x80, 0x22, 0x00, 0x0a, // attribute type (0x8022) and length (0x000a)
69//!     0x73, 0x74, 0x75, 0x6E, // s t u n
70//!     0x2D, 0x74, 0x79, 0x70, // - t y p
71//!     0x65, 0x73, 0x00, 0x00  // e s
72//! ];
73//!
74//! let msg_data = msg.build();
75//! // ignores the randomly generated transaction id
76//! assert_eq!(msg_data[20..], attribute_data);
77//! ```
78
79use std::convert::TryFrom;
80
81use byteorder::{BigEndian, ByteOrder};
82
83use crate::attribute::*;
84
85use tracing::{debug, warn};
86
87/// The value of the magic cookie (in network byte order) as specified in RFC5389, and RFC8489.
88pub const MAGIC_COOKIE: u32 = 0x2112A442;
89
90/// The value of the binding message type.  Can be used in either a request or an indication
91/// message.
92pub const BINDING: u16 = 0x0001;
93
94/// Possible errors when parsing a STUN message.
95#[derive(Debug, thiserror::Error)]
96pub enum StunParseError {
97    /// Not a STUN message.
98    #[error("The provided data is not a STUN message")]
99    NotStun,
100    /// The message has been truncated
101    #[error("Not enough data available to parse the packet, expected {}, actual {}", .expected, .actual)]
102    Truncated {
103        /// The expeced number of bytes
104        expected: usize,
105        /// The encountered number of bytes
106        actual: usize,
107    },
108    /// The message has been truncated
109    #[error("Too many bytes for this data, expected {}, actual {}", .expected, .actual)]
110    TooLarge {
111        /// The expeced number of bytes
112        expected: usize,
113        /// The encountered number of bytes
114        actual: usize,
115    },
116    /// Integrity value does not match computed value
117    #[error("Integrity value does not match")]
118    IntegrityCheckFailed,
119    /// An attribute was not found in the message
120    #[error("Missing attribute {:?}", .0)]
121    MissingAttribute(AttributeType),
122    /// An attribute was found after the message integrity attribute
123    #[error("An attribute {:?} was encountered after a message integrity attribute", .0)]
124    AttributeAfterIntegrity(AttributeType),
125    /// An attribute was found after the message integrity attribute
126    #[error("An attribute {:?} was encountered after a fingerprint attribute", .0)]
127    AttributeAfterFingerprint(AttributeType),
128    /// Fingerprint does not match the data.
129    #[error("Fingerprint does not match")]
130    FingerprintMismatch,
131    /// The provided data does not match the message
132    #[error("The provided data does not match the message")]
133    DataMismatch,
134    /// The attribute contains invalid data
135    #[error("The attribute contains invalid data")]
136    InvalidAttributeData,
137    /// The attribute does not parse this data
138    #[error("Cannot parse with this attribute")]
139    WrongAttributeImplementation,
140}
141
142/// Errors produced when writing a STUN message
143#[derive(Debug, thiserror::Error)]
144pub enum StunWriteError {
145    /// The message already has this attribute
146    #[error("The attribute already exists in the message")]
147    AttributeExists(AttributeType),
148    /// The fingerprint attribute already exists. Cannot write any further attributes
149    #[error("The message already contains a fingerprint attribute")]
150    FingerprintExists,
151    /// A message integrity attribute already exists. Cannot write any further attributes
152    #[error("The message already contains a message intregrity attribute")]
153    MessageIntegrityExists,
154    /// The message has been truncated
155    #[error("Too many bytes for this data, expected {}, actual {}", .expected, .actual)]
156    TooLarge {
157        /// The expeced number of bytes
158        expected: usize,
159        /// The encountered number of bytes
160        actual: usize,
161    },
162    /// The message has been truncated
163    #[error("Not enough data available to parse the packet, expected {}, actual {}", .expected, .actual)]
164    TooSmall {
165        /// The expected number of bytes
166        expected: usize,
167        /// The encountered number of bytes
168        actual: usize,
169    },
170    /// Failed to compute integrity
171    #[error("Failed to compute integrity")]
172    IntegrityFailed,
173    /// Out of range input provided
174    #[error("Out of range input provided")]
175    OutOfRange {
176        /// The value provided.
177        value: usize,
178        /// The minimum allowed value.
179        min: usize,
180        /// The maximum allowed value.
181        max: usize,
182    },
183}
184
185/// Structure for holding the required credentials for handling long-term STUN credentials
186#[derive(Debug, Clone, PartialEq, Eq)]
187#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
188pub struct LongTermCredentials {
189    username: String,
190    password: String,
191    realm: String,
192}
193
194impl LongTermCredentials {
195    /// Create a new set of [`LongTermCredentials`]
196    ///
197    /// # Examples
198    ///
199    /// ```
200    /// # use stun_types::message::LongTermCredentials;
201    /// let credentials = LongTermCredentials::new(
202    ///     "user".to_string(),
203    ///     "pass".to_string(),
204    ///     "realm".to_string(),
205    /// );
206    /// assert_eq!(credentials.username(), "user");
207    /// assert_eq!(credentials.password(), "pass");
208    /// assert_eq!(credentials.realm(), "realm");
209    /// ```
210    pub fn new(username: String, password: String, realm: String) -> Self {
211        Self {
212            username,
213            password,
214            realm,
215        }
216    }
217
218    /// The configured username
219    pub fn username(&self) -> &str {
220        &self.username
221    }
222
223    /// The configured password
224    pub fn password(&self) -> &str {
225        &self.password
226    }
227
228    /// The configured realm
229    pub fn realm(&self) -> &str {
230        &self.realm
231    }
232}
233
234/// Structure for holding the required credentials for handling short-term STUN credentials
235#[derive(Debug, Clone, PartialEq, Eq)]
236#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
237pub struct ShortTermCredentials {
238    password: String,
239}
240
241impl ShortTermCredentials {
242    /// Create a new set of [`ShortTermCredentials`]
243    ///
244    /// # Examples
245    ///
246    /// ```
247    /// # use stun_types::message::ShortTermCredentials;
248    /// let credentials = ShortTermCredentials::new("password".to_string());
249    /// assert_eq!(credentials.password(), "password");
250    /// ```
251    pub fn new(password: String) -> Self {
252        Self { password }
253    }
254
255    /// The configured password
256    pub fn password(&self) -> &str {
257        &self.password
258    }
259}
260
261/// Enum for holding the credentials used to sign or verify a [`Message`]
262///
263/// This can either be a set of [`ShortTermCredentials`] or [`LongTermCredentials`]`
264#[derive(Debug, Clone, PartialEq, Eq)]
265#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
266pub enum MessageIntegrityCredentials {
267    /// Short term integrity credentials.
268    ShortTerm(ShortTermCredentials),
269    /// Long term integrity credentials.
270    LongTerm(LongTermCredentials),
271}
272
273impl From<LongTermCredentials> for MessageIntegrityCredentials {
274    fn from(value: LongTermCredentials) -> Self {
275        MessageIntegrityCredentials::LongTerm(value)
276    }
277}
278
279impl From<ShortTermCredentials> for MessageIntegrityCredentials {
280    fn from(value: ShortTermCredentials) -> Self {
281        MessageIntegrityCredentials::ShortTerm(value)
282    }
283}
284
285impl MessageIntegrityCredentials {
286    fn make_hmac_key(&self) -> Vec<u8> {
287        match self {
288            MessageIntegrityCredentials::ShortTerm(short) => short.password.clone().into(),
289            MessageIntegrityCredentials::LongTerm(long) => {
290                use md5::{Digest, Md5};
291                let data = long.username.clone()
292                    + ":"
293                    + &long.realm.clone()
294                    + ":"
295                    + &long.password.clone();
296                let mut digest = Md5::new();
297                digest.update(&data);
298                digest.finalize().to_vec()
299            }
300        }
301    }
302}
303
304/// The class of a [`Message`].
305///
306/// There are four classes of [`Message`]s within the STUN protocol:
307///
308///  - [Request][`MessageClass::Request`] indicates that a request is being made and a
309///    response is expected.
310///  - An [Indication][`MessageClass::Indication`] is a fire and forget [`Message`] where
311///    no response is required or expected.
312///  - [Success][`MessageClass::Success`] indicates that a [Request][`MessageClass::Request`]
313///    was successfully handled and the
314///  - [Error][`MessageClass::Error`] class indicates that an error was produced.
315#[derive(Copy, Clone, Debug, PartialEq, Eq)]
316pub enum MessageClass {
317    /// A request that is expecting a response of either Success, or Error.
318    Request,
319    /// A request that does not expect a response.
320    Indication,
321    /// A success response to a previous Request.
322    Success,
323    /// An error response to a previous Request.
324    Error,
325}
326
327impl MessageClass {
328    /// Returns whether this [`MessageClass`] is of a response type.  i.e. is either
329    /// [`MessageClass::Success`] or [`MessageClass::Error`].
330    pub fn is_response(self) -> bool {
331        matches!(self, MessageClass::Success | MessageClass::Error)
332    }
333
334    fn to_bits(self) -> u16 {
335        match self {
336            MessageClass::Request => 0x000,
337            MessageClass::Indication => 0x010,
338            MessageClass::Success => 0x100,
339            MessageClass::Error => 0x110,
340        }
341    }
342}
343
344/// The type of a [`Message`].  A combination of a [`MessageClass`] and a STUN method.
345#[derive(Copy, Clone, Debug, PartialEq, Eq)]
346pub struct MessageType(u16);
347
348impl std::fmt::Display for MessageType {
349    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
350        write!(
351            f,
352            "MessageType(class: {:?}, method: {} ({:#x}))",
353            self.class(),
354            self.method(),
355            self.method()
356        )
357    }
358}
359
360impl MessageType {
361    /// Create a new [`MessageType`] from the provided [`MessageClass`] and method
362    ///
363    /// # Examples
364    ///
365    /// ```
366    /// # use stun_types::message::{MessageType, MessageClass, BINDING};
367    /// let mtype = MessageType::from_class_method(MessageClass::Indication, BINDING);
368    /// assert_eq!(mtype.has_class(MessageClass::Indication), true);
369    /// assert_eq!(mtype.has_method(BINDING), true);
370    /// ```
371    pub fn from_class_method(class: MessageClass, method: u16) -> Self {
372        let class_bits = MessageClass::to_bits(class);
373        let method_bits = method & 0xf | (method & 0x70) << 1 | (method & 0xf80) << 2;
374        // trace!("MessageType from class {:?} and method {:?} into {:?}", class, method,
375        //     class_bits | method_bits);
376        Self(class_bits | method_bits)
377    }
378
379    /// Retrieves the class of a [`MessageType`]
380    ///
381    /// # Examples
382    ///
383    /// ```
384    /// # use stun_types::message::{MessageType, MessageClass, BINDING};
385    /// let mtype = MessageType::from_class_method(MessageClass::Indication, BINDING);
386    /// assert_eq!(mtype.class(), MessageClass::Indication);
387    /// ```
388    pub fn class(self) -> MessageClass {
389        let class = (self.0 & 0x10) >> 4 | (self.0 & 0x100) >> 7;
390        match class {
391            0x0 => MessageClass::Request,
392            0x1 => MessageClass::Indication,
393            0x2 => MessageClass::Success,
394            0x3 => MessageClass::Error,
395            _ => unreachable!(),
396        }
397    }
398
399    /// Returns whether class of a [`MessageType`] is equal to the provided [`MessageClass`]
400    ///
401    /// # Examples
402    ///
403    /// ```
404    /// # use stun_types::message::{MessageType, MessageClass, BINDING};
405    /// let mtype = MessageType::from_class_method(MessageClass::Indication, BINDING);
406    /// assert!(mtype.has_class(MessageClass::Indication));
407    /// ```
408    pub fn has_class(self, cls: MessageClass) -> bool {
409        self.class() == cls
410    }
411
412    /// Returns whether the class of a [`MessageType`] indicates a response [`Message`]
413    ///
414    /// # Examples
415    ///
416    /// ```
417    /// # use stun_types::message::{MessageType, MessageClass, BINDING};
418    /// assert_eq!(MessageType::from_class_method(MessageClass::Indication, BINDING)
419    ///     .is_response(), false);
420    /// assert_eq!(MessageType::from_class_method(MessageClass::Request, BINDING)
421    ///     .is_response(), false);
422    /// assert_eq!(MessageType::from_class_method(MessageClass::Success, BINDING)
423    ///     .is_response(), true);
424    /// assert_eq!(MessageType::from_class_method(MessageClass::Error, BINDING)
425    ///     .is_response(), true);
426    /// ```
427    pub fn is_response(self) -> bool {
428        self.class().is_response()
429    }
430
431    /// Returns the method of a [`MessageType`]
432    ///
433    /// # Examples
434    ///
435    /// ```
436    /// # use stun_types::message::{MessageType, MessageClass, BINDING};
437    /// let mtype = MessageType::from_class_method(MessageClass::Indication, BINDING);
438    /// assert_eq!(mtype.method(), BINDING);
439    /// ```
440    pub fn method(self) -> u16 {
441        self.0 & 0xf | (self.0 & 0xe0) >> 1 | (self.0 & 0x3e00) >> 2
442    }
443
444    /// Returns whether the method of a [`MessageType`] is equal to the provided value
445    ///
446    /// # Examples
447    ///
448    /// ```
449    /// # use stun_types::message::{MessageType, MessageClass, BINDING};
450    /// let mtype = MessageType::from_class_method(MessageClass::Indication, BINDING);
451    /// assert_eq!(mtype.has_method(BINDING), true);
452    /// ```
453    pub fn has_method(self, method: u16) -> bool {
454        self.method() == method
455    }
456
457    /// Convert a [`MessageType`] to network bytes
458    pub fn write_into(&self, dest: &mut [u8]) {
459        BigEndian::write_u16(dest, self.0);
460    }
461
462    /// Convert a [`MessageType`] to network bytes
463    pub fn to_bytes(self) -> Vec<u8> {
464        let mut ret = vec![0; 2];
465        BigEndian::write_u16(&mut ret[0..2], self.0);
466        ret
467    }
468
469    /// Convert a set of network bytes into a [`MessageType`] or return an error
470    pub fn from_bytes(data: &[u8]) -> Result<Self, StunParseError> {
471        let data = BigEndian::read_u16(data);
472        if data & 0xc000 != 0x0 {
473            /* not a stun packet */
474            return Err(StunParseError::NotStun);
475        }
476        Ok(Self(data))
477    }
478}
479impl TryFrom<&[u8]> for MessageType {
480    type Error = StunParseError;
481
482    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
483        MessageType::from_bytes(value)
484    }
485}
486
487/// A unique transaction identifier for each message and it's (possible) response.
488#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
489pub struct TransactionId {
490    id: u128,
491}
492
493impl TransactionId {
494    /// Generate a new STUN transaction identifier.
495    pub fn generate() -> TransactionId {
496        use rand::{thread_rng, Rng};
497        let mut rng = thread_rng();
498        rng.gen::<u128>().into()
499    }
500}
501
502impl From<u128> for TransactionId {
503    fn from(id: u128) -> Self {
504        Self {
505            id: id & 0xffff_ffff_ffff_ffff_ffff_ffff,
506        }
507    }
508}
509impl From<TransactionId> for u128 {
510    fn from(id: TransactionId) -> Self {
511        id.id
512    }
513}
514impl std::fmt::Display for TransactionId {
515    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
516        write!(f, "{:#x}", self.id)
517    }
518}
519
520/// The fixed length header of a STUN message.  Allows reading the message header for a quick
521/// check if this message is a valid STUN message.  Can also be used to expose the length of the
522/// complete message without needing to receive the entire message.
523#[derive(Debug)]
524pub struct MessageHeader {
525    mtype: MessageType,
526    transaction_id: TransactionId,
527    length: u16,
528}
529
530impl MessageHeader {
531    /// The length of the STUN message header.
532    pub const LENGTH: usize = 20;
533
534    /// Deserialize a `MessageHeader`
535    ///
536    /// # Examples
537    ///
538    /// ```
539    /// # use stun_types::message::{MessageHeader, MessageType, MessageClass, BINDING};
540    /// let msg_data = [0, 1, 0, 8, 33, 18, 164, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 232];
541    /// let message = MessageHeader::from_bytes(&msg_data).unwrap();
542    /// assert_eq!(message.get_type(), MessageType::from_class_method(MessageClass::Request, BINDING));
543    /// assert_eq!(message.transaction_id(), 1000.into());
544    /// assert_eq!(message.data_length(), 8);
545    /// ```
546    pub fn from_bytes(data: &[u8]) -> Result<Self, StunParseError> {
547        if data.len() < 20 {
548            return Err(StunParseError::Truncated {
549                expected: 20,
550                actual: data.len(),
551            });
552        }
553        let mtype = MessageType::from_bytes(data)?;
554        let mlength = BigEndian::read_u16(&data[2..]);
555        let tid = BigEndian::read_u128(&data[4..]);
556        let cookie = (tid >> 96) as u32;
557        if cookie != MAGIC_COOKIE {
558            warn!(
559                "malformed cookie constant {:?} != stored data {:?}",
560                MAGIC_COOKIE, cookie
561            );
562            return Err(StunParseError::NotStun);
563        }
564
565        Ok(Self {
566            mtype,
567            transaction_id: tid.into(),
568            length: mlength,
569        })
570    }
571
572    /// The number of bytes of content in this [`MessageHeader`]. Adding both `data_length()`
573    /// and [`MessageHeader::LENGTH`] will result in the size of the complete STUN message.
574    pub fn data_length(&self) -> u16 {
575        self.length
576    }
577
578    /// The [`TransactionId`] of this [`MessageHeader`]
579    pub fn transaction_id(&self) -> TransactionId {
580        self.transaction_id
581    }
582
583    /// The [`MessageType`] of this [`MessageHeader`]
584    pub fn get_type(&self) -> MessageType {
585        self.mtype
586    }
587}
588
589/// The structure that encapsulates the entirety of a STUN message
590///
591/// Contains the [`MessageType`], a transaction ID, and a list of STUN
592/// [`Attribute`]
593#[derive(Debug, Clone)]
594pub struct Message<'a> {
595    data: &'a [u8],
596}
597
598impl<'a> std::fmt::Display for Message<'a> {
599    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
600        write!(
601            f,
602            "Message(class: {:?}, method: {} ({:#x}), transaction: {}, attributes: ",
603            self.get_type().class(),
604            self.get_type().method(),
605            self.get_type().method(),
606            self.transaction_id()
607        )?;
608        let iter = self.iter_attributes();
609        write!(f, "[")?;
610        for (i, a) in iter.enumerate() {
611            if i > 0 {
612                write!(f, ", ")?;
613            }
614            write!(f, "{}", a)?;
615        }
616        write!(f, "]")?;
617        write!(f, ")")
618    }
619}
620
621/// The supported hashing algorithms for ensuring integrity of a [`Message`]
622#[derive(Clone, Copy, Debug, PartialEq, Eq)]
623pub enum IntegrityAlgorithm {
624    /// SHA-1 algorithm
625    Sha1,
626    /// SHA-256 algorithm
627    Sha256,
628}
629
630impl<'a> Message<'a> {
631    /// Create a new [`Message`] with the provided [`MessageType`] and transaction ID
632    ///
633    /// Note you probably want to use one of the other helper constructors instead.
634    ///
635    /// # Examples
636    ///
637    /// ```
638    /// # use stun_types::message::{Message, MessageType, MessageClass, BINDING};
639    /// let mtype = MessageType::from_class_method(MessageClass::Indication, BINDING);
640    /// let message = Message::builder(mtype, 0.into()).build();
641    /// let message = Message::from_bytes(&message).unwrap();
642    /// assert!(message.has_class(MessageClass::Indication));
643    /// assert!(message.has_method(BINDING));
644    /// ```
645    pub fn builder<'b>(mtype: MessageType, transaction_id: TransactionId) -> MessageBuilder<'b> {
646        MessageBuilder {
647            msg_type: mtype,
648            transaction_id,
649            attributes: Vec::with_capacity(8),
650            attribute_types: smallvec::smallvec![],
651        }
652    }
653
654    /// Create a new request [`Message`] of the provided method
655    ///
656    /// # Examples
657    ///
658    /// ```
659    /// # use stun_types::message::{Message, MessageType, MessageClass, BINDING};
660    /// let message = Message::builder_request(BINDING);
661    /// let data = message.build();
662    /// let message = Message::from_bytes(&data).unwrap();
663    /// assert!(message.has_class(MessageClass::Request));
664    /// assert!(message.has_method(BINDING));
665    /// ```
666    pub fn builder_request<'b>(method: u16) -> MessageBuilder<'b> {
667        Message::builder(
668            MessageType::from_class_method(MessageClass::Request, method),
669            TransactionId::generate(),
670        )
671    }
672
673    /// Create a new success [`Message`] response from the provided request
674    ///
675    /// # Panics
676    ///
677    /// When a non-request [`Message`] is passed as the original input [`Message`]
678    ///
679    /// # Examples
680    ///
681    /// ```
682    /// # use stun_types::message::{Message, MessageType, MessageClass, BINDING};
683    /// let message = Message::builder_request(BINDING);
684    /// let data = message.build();
685    /// let message = Message::from_bytes(&data).unwrap();
686    /// let success = Message::builder_success(&message).build();
687    /// let success = Message::from_bytes(&success).unwrap();
688    /// assert!(success.has_class(MessageClass::Success));
689    /// assert!(success.has_method(BINDING));
690    /// ```
691    pub fn builder_success<'b>(orig: &Message) -> MessageBuilder<'b> {
692        if !orig.has_class(MessageClass::Request) {
693            panic!(
694                "A success response message was attempted to be created from a non-request message"
695            );
696        }
697        Message::builder(
698            MessageType::from_class_method(MessageClass::Success, orig.method()),
699            orig.transaction_id(),
700        )
701    }
702
703    /// Create a new error [`Message`] response from the provided request
704    ///
705    /// # Panics
706    ///
707    /// When a non-request [`Message`] is passed as the original input [`Message`]
708    ///
709    /// # Examples
710    ///
711    /// ```
712    /// # use stun_types::message::{Message, MessageType, MessageClass, BINDING};
713    /// let message = Message::builder_request(BINDING);
714    /// let data = message.build();
715    /// let message = Message::from_bytes(&data).unwrap();
716    /// let error = Message::builder_error(&message).build();
717    /// let error = Message::from_bytes(&error).unwrap();
718    /// assert!(error.has_class(MessageClass::Error));
719    /// assert!(error.has_method(BINDING));
720    /// ```
721    pub fn builder_error(orig: &Message) -> MessageBuilder<'a> {
722        if !orig.has_class(MessageClass::Request) {
723            panic!(
724                "An error response message was attempted to be created from a non-request message"
725            );
726        }
727        Message::builder(
728            MessageType::from_class_method(MessageClass::Error, orig.method()),
729            orig.transaction_id(),
730        )
731    }
732
733    /// Retrieve the [`MessageType`] of a [`Message`]
734    ///
735    /// # Examples
736    ///
737    /// ```
738    /// # use stun_types::message::{Message, MessageType, MessageClass, BINDING};
739    /// let message = Message::builder_request(BINDING);
740    /// let data = message.build();
741    /// let message = Message::from_bytes(&data).unwrap();
742    /// assert!(message.get_type().has_class(MessageClass::Request));
743    /// assert!(message.get_type().has_method(BINDING));
744    /// ```
745    pub fn get_type(&self) -> MessageType {
746        MessageType::try_from(&self.data[..2]).unwrap()
747    }
748
749    /// Retrieve the [`MessageClass`] of a [`Message`]
750    ///
751    /// # Examples
752    ///
753    /// ```
754    /// # use stun_types::message::{Message, MessageType, MessageClass, BINDING};
755    /// let message = Message::builder_request(BINDING).build();
756    /// let message = Message::from_bytes(&message).unwrap();
757    /// assert_eq!(message.class(), MessageClass::Request);
758    /// ```
759    pub fn class(&self) -> MessageClass {
760        self.get_type().class()
761    }
762
763    /// Returns whether the [`Message`] is of the specified [`MessageClass`]
764    ///
765    /// # Examples
766    ///
767    /// ```
768    /// # use stun_types::message::{Message, MessageType, MessageClass, BINDING};
769    /// let message = Message::builder_request(BINDING).build();
770    /// let message = Message::from_bytes(&message).unwrap();
771    /// assert!(message.has_class(MessageClass::Request));
772    /// ```
773    pub fn has_class(&self, cls: MessageClass) -> bool {
774        self.class() == cls
775    }
776
777    /// Returns whether the [`Message`] is a response
778    ///
779    /// This means that the [`Message`] has a class of either success or error
780    ///
781    /// # Examples
782    ///
783    /// ```
784    /// # use stun_types::message::{Message, MessageType, MessageClass, BINDING};
785    /// let message = Message::builder_request(BINDING).build();
786    /// let message = Message::from_bytes(&message).unwrap();
787    /// assert_eq!(message.is_response(), false);
788    ///
789    /// let error = Message::builder_error(&message).build();
790    /// let error = Message::from_bytes(&error).unwrap();
791    /// assert_eq!(error.is_response(), true);
792    ///
793    /// let success = Message::builder_success(&message).build();
794    /// let success = Message::from_bytes(&success).unwrap();
795    /// assert_eq!(success.is_response(), true);
796    /// ```
797    pub fn is_response(&self) -> bool {
798        self.class().is_response()
799    }
800
801    /// Retrieves the method of the [`Message`]
802    ///
803    /// # Examples
804    ///
805    /// ```
806    /// # use stun_types::message::{Message, MessageType, MessageClass, BINDING};
807    /// let message = Message::builder_request(BINDING).build();
808    /// let message = Message::from_bytes(&message).unwrap();
809    /// assert_eq!(message.method(), BINDING);
810    /// ```
811    pub fn method(&self) -> u16 {
812        self.get_type().method()
813    }
814
815    /// Returns whether the [`Message`] is of the specified method
816    ///
817    /// # Examples
818    ///
819    /// ```
820    /// # use stun_types::message::{Message, MessageType, MessageClass, BINDING};
821    /// let message = Message::builder_request(BINDING).build();
822    /// let message = Message::from_bytes(&message).unwrap();
823    /// assert_eq!(message.has_method(BINDING), true);
824    /// assert_eq!(message.has_method(0), false);
825    /// ```
826    pub fn has_method(&self, method: u16) -> bool {
827        self.method() == method
828    }
829
830    /// Retrieves the 96-bit transaction ID of the [`Message`]
831    ///
832    /// # Examples
833    ///
834    /// ```
835    /// # use stun_types::message::{Message, MessageType, MessageClass, BINDING, TransactionId};
836    /// let mtype = MessageType::from_class_method(MessageClass::Request, BINDING);
837    /// let transaction_id = TransactionId::generate();
838    /// let message = Message::builder(mtype, transaction_id).build();
839    /// let message = Message::from_bytes(&message).unwrap();
840    /// assert_eq!(message.transaction_id(), transaction_id);
841    /// ```
842    pub fn transaction_id(&self) -> TransactionId {
843        BigEndian::read_u128(&self.data[4..]).into()
844    }
845
846    /// Deserialize a `Message`
847    ///
848    /// # Examples
849    ///
850    /// ```
851    /// # use stun_types::attribute::{RawAttribute, Attribute};
852    /// # use stun_types::message::{Message, MessageType, MessageClass, BINDING};
853    /// let msg_data = vec![0, 1, 0, 8, 33, 18, 164, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 232, 0, 1, 0, 1, 3, 0, 0, 0];
854    /// let message = Message::from_bytes(&msg_data).unwrap();
855    /// let attr = RawAttribute::new(1.into(), &[3]);
856    /// let msg_attr = message.raw_attribute(1.into()).unwrap();
857    /// assert_eq!(msg_attr, attr);
858    /// assert_eq!(message.get_type(), MessageType::from_class_method(MessageClass::Request, BINDING));
859    /// assert_eq!(message.transaction_id(), 1000.into());
860    /// ```
861    #[tracing::instrument(
862        name = "message_from_bytes",
863        level = "trace",
864        skip(data),
865        fields(
866            data.len = data.len()
867        )
868    )]
869    pub fn from_bytes(data: &'a [u8]) -> Result<Self, StunParseError> {
870        let orig_data = data;
871
872        let header = MessageHeader::from_bytes(data)?;
873        let mlength = header.data_length() as usize;
874        if mlength + MessageHeader::LENGTH > data.len() {
875            // mlength + header
876            warn!(
877                "malformed advertised size {:?} and data size {:?} don't match",
878                mlength + 20,
879                data.len()
880            );
881            return Err(StunParseError::Truncated {
882                expected: mlength + MessageHeader::LENGTH,
883                actual: data.len(),
884            });
885        }
886
887        let mut data_offset = MessageHeader::LENGTH;
888        let mut data = &data[MessageHeader::LENGTH..];
889        let ending_attributes = [
890            MessageIntegrity::TYPE,
891            MessageIntegritySha256::TYPE,
892            Fingerprint::TYPE,
893        ];
894        // XXX: maybe use small/tinyvec?
895        let mut seen_ending_attributes = [AttributeType::new(0); 3];
896        let mut seen_ending_len = 0;
897        while !data.is_empty() {
898            let attr = RawAttribute::from_bytes(data).map_err(|e| {
899                warn!(
900                    "failed to parse message attribute at offset {data_offset}: {:?}",
901                    e
902                );
903                match e {
904                    StunParseError::Truncated { expected, actual } => StunParseError::Truncated {
905                        expected: expected + 4 + data_offset,
906                        actual: actual + 4 + data_offset,
907                    },
908                    StunParseError::TooLarge { expected, actual } => StunParseError::TooLarge {
909                        expected: expected + 4 + data_offset,
910                        actual: actual + 4 + data_offset,
911                    },
912                    e => e,
913                }
914            })?;
915
916            // if we have seen any ending attributes, then there is only a fixed set of attributes
917            // that are allowed.
918            if seen_ending_len > 0 && !ending_attributes.contains(&attr.get_type()) {
919                if seen_ending_attributes.contains(&Fingerprint::TYPE) {
920                    warn!("unexpected attribute {} after FINGERPRINT", attr.get_type());
921                    return Err(StunParseError::AttributeAfterFingerprint(attr.get_type()));
922                } else {
923                    // only attribute valid after MESSAGE_INTEGRITY is FINGERPRINT
924                    warn!(
925                        "unexpected attribute {} after MESSAGE_INTEGRITY",
926                        attr.get_type()
927                    );
928                    return Err(StunParseError::AttributeAfterIntegrity(attr.get_type()));
929                }
930            }
931
932            if ending_attributes.contains(&attr.get_type()) {
933                if seen_ending_attributes.contains(&attr.get_type()) {
934                    if seen_ending_attributes.contains(&Fingerprint::TYPE) {
935                        warn!("unexpected attribute {} after FINGERPRINT", attr.get_type());
936                        return Err(StunParseError::AttributeAfterFingerprint(attr.get_type()));
937                    } else {
938                        // only attribute valid after MESSAGE_INTEGRITY is FINGERPRINT
939                        warn!(
940                            "unexpected attribute {} after MESSAGE_INTEGRITY",
941                            attr.get_type()
942                        );
943                        return Err(StunParseError::AttributeAfterIntegrity(attr.get_type()));
944                    }
945                } else {
946                    seen_ending_attributes[seen_ending_len] = attr.get_type();
947                    seen_ending_len += 1;
948                    // need credentials to validate the integrity of the message
949                }
950            }
951            let padded_len = attr.padded_len();
952            if padded_len > data.len() {
953                warn!(
954                    "attribute {:?} extends past the end of the data",
955                    attr.get_type()
956                );
957                return Err(StunParseError::Truncated {
958                    expected: data_offset + padded_len,
959                    actual: data_offset + data.len(),
960                });
961            }
962            if attr.get_type() == Fingerprint::TYPE {
963                let f = Fingerprint::from_raw(&attr)?;
964                let msg_fingerprint = f.fingerprint();
965                let mut fingerprint_data = orig_data[..data_offset].to_vec();
966                BigEndian::write_u16(
967                    &mut fingerprint_data[2..4],
968                    (data_offset + padded_len - MessageHeader::LENGTH) as u16,
969                );
970                let calculated_fingerprint = Fingerprint::compute(&fingerprint_data);
971                if &calculated_fingerprint != msg_fingerprint {
972                    warn!(
973                        "fingerprint mismatch {:?} != {:?}",
974                        calculated_fingerprint, msg_fingerprint
975                    );
976                    return Err(StunParseError::FingerprintMismatch);
977                }
978            }
979            data = &data[padded_len..];
980            data_offset += padded_len;
981        }
982        Ok(Message { data: orig_data })
983    }
984
985    /// Validates the MESSAGE_INTEGRITY attribute with the provided credentials
986    ///
987    /// The Original data that was used to construct this [`Message`] must be provided in order
988    /// to successfully validate the [`Message`]
989    ///
990    /// # Examples
991    ///
992    /// ```
993    /// # use stun_types::message::{Message, MessageType, MessageClass, BINDING,
994    ///     MessageIntegrityCredentials, LongTermCredentials, IntegrityAlgorithm};
995    /// let mut message = Message::builder_request(BINDING);
996    /// let credentials = LongTermCredentials::new(
997    ///     "user".to_owned(),
998    ///     "pass".to_owned(),
999    ///     "realm".to_owned()
1000    /// ).into();
1001    /// assert!(message.add_message_integrity(&credentials, IntegrityAlgorithm::Sha256).is_ok());
1002    /// let data = message.build();
1003    /// let message = Message::from_bytes(&data).unwrap();
1004    /// assert!(message.validate_integrity(&credentials).is_ok());
1005    /// ```
1006    #[tracing::instrument(
1007        name = "message_validate_integrity",
1008        level = "trace",
1009        skip(self, credentials),
1010        fields(
1011            msg.transaction = %self.transaction_id(),
1012        )
1013    )]
1014    pub fn validate_integrity(
1015        &self,
1016        credentials: &MessageIntegrityCredentials,
1017    ) -> Result<IntegrityAlgorithm, StunParseError> {
1018        debug!("using credentials {credentials:?}");
1019        let raw_sha1 = self.raw_attribute(MessageIntegrity::TYPE);
1020        let raw_sha256 = self.raw_attribute(MessageIntegritySha256::TYPE);
1021        let (algo, msg_hmac) = match (raw_sha1, raw_sha256) {
1022            (_, Some(sha256)) => {
1023                let integrity = MessageIntegritySha256::try_from(&sha256)?;
1024                (IntegrityAlgorithm::Sha256, integrity.hmac().to_vec())
1025            }
1026            (Some(sha1), None) => {
1027                let integrity = MessageIntegrity::try_from(&sha1)?;
1028                (IntegrityAlgorithm::Sha1, integrity.hmac().to_vec())
1029            }
1030            (None, None) => return Err(StunParseError::MissingAttribute(MessageIntegrity::TYPE)),
1031        };
1032
1033        // find the location of the original MessageIntegrity attribute: XXX: maybe encode this into
1034        // the attribute instead?
1035        let data = self.data;
1036        debug_assert!(data.len() >= MessageHeader::LENGTH);
1037        let mut data = &data[MessageHeader::LENGTH..];
1038        let mut data_offset = MessageHeader::LENGTH;
1039        while !data.is_empty() {
1040            let attr = RawAttribute::from_bytes(data)?;
1041            if algo == IntegrityAlgorithm::Sha1 && attr.get_type() == MessageIntegrity::TYPE {
1042                let msg = MessageIntegrity::try_from(&attr)?;
1043                debug_assert!(msg.hmac().as_slice() == msg_hmac);
1044
1045                // HMAC is computed using all the data up to (exclusive of) the MESSAGE_INTEGRITY
1046                // but with a length field including the MESSAGE_INTEGRITY attribute...
1047                let key = credentials.make_hmac_key();
1048                let mut hmac_data = self.data[..data_offset].to_vec();
1049                BigEndian::write_u16(
1050                    &mut hmac_data[2..4],
1051                    data_offset as u16 + 24 - MessageHeader::LENGTH as u16,
1052                );
1053                MessageIntegrity::verify(
1054                    &hmac_data,
1055                    &key,
1056                    msg_hmac.as_slice().try_into().unwrap(),
1057                )?;
1058                return Ok(algo);
1059            } else if algo == IntegrityAlgorithm::Sha256
1060                && attr.get_type() == MessageIntegritySha256::TYPE
1061            {
1062                let msg = MessageIntegritySha256::try_from(&attr)?;
1063                debug_assert!(msg.hmac() == msg_hmac);
1064
1065                // HMAC is computed using all the data up to (exclusive of) the MESSAGE_INTEGRITY
1066                // but with a length field including the MESSAGE_INTEGRITY attribute...
1067                let key = credentials.make_hmac_key();
1068                let mut hmac_data = self.data[..data_offset].to_vec();
1069                BigEndian::write_u16(
1070                    &mut hmac_data[2..4],
1071                    data_offset as u16 + attr.length() + 4 - MessageHeader::LENGTH as u16,
1072                );
1073                MessageIntegritySha256::verify(&hmac_data, &key, &msg_hmac)?;
1074                return Ok(algo);
1075            }
1076            let padded_len = attr.padded_len();
1077            // checked when initially parsing.
1078            debug_assert!(padded_len <= data.len());
1079            data = &data[padded_len..];
1080            data_offset += padded_len;
1081        }
1082
1083        // Either there is no integrity (checked earlier), or the integrity was found and checked
1084        // by the loop above.
1085        unreachable!();
1086    }
1087
1088    /// Retrieve a `RawAttribute` from this `Message`.
1089    ///
1090    /// # Examples
1091    ///
1092    /// Retrieve a`RawAttribute`
1093    ///
1094    /// ```
1095    /// # use stun_types::attribute::{RawAttribute, Attribute};
1096    /// # use stun_types::message::{Message, MessageType, MessageClass, BINDING};
1097    /// let mut message = Message::builder_request(BINDING);
1098    /// let attr = RawAttribute::new(1.into(), &[3]);
1099    /// assert!(message.add_raw_attribute(attr.clone()).is_ok());
1100    /// let message = message.build();
1101    /// let message = Message::from_bytes(&message).unwrap();
1102    /// assert_eq!(message.raw_attribute(1.into()).unwrap(), attr);
1103    /// ```
1104    #[tracing::instrument(
1105        name = "message_get_raw_attribute",
1106        level = "trace",
1107        ret,
1108        skip(self, atype),
1109        fields(
1110            msg.transaction = %self.transaction_id(),
1111            attribute_type = %atype,
1112        )
1113    )]
1114    pub fn raw_attribute(&self, atype: AttributeType) -> Option<RawAttribute> {
1115        self.iter_attributes().find(|attr| attr.get_type() == atype)
1116    }
1117
1118    /// Retrieve a concrete `Attribute` from this `Message`.
1119    ///
1120    /// This will error with [`StunParseError::MissingAttribute`] if the attribute does not exist.
1121    /// Otherwise, other parsing errors of the data may be returned specific to the attribute
1122    /// implementation provided.
1123    ///
1124    /// # Examples
1125    ///
1126    /// Retrieve an `Attribute`
1127    ///
1128    /// ```
1129    /// # use stun_types::attribute::{Software, Attribute};
1130    /// # use stun_types::message::{Message, MessageType, MessageClass, BINDING};
1131    /// let mut message = Message::builder_request(BINDING);
1132    /// let attr = Software::new("stun-types").unwrap();
1133    /// assert!(message.add_attribute(&attr).is_ok());
1134    /// let message = message.build();
1135    /// let message = Message::from_bytes(&message).unwrap();
1136    /// assert_eq!(message.attribute::<Software>().unwrap(), attr);
1137    /// ```
1138    #[tracing::instrument(
1139        name = "message_get_attribute",
1140        level = "trace",
1141        ret,
1142        skip(self),
1143        fields(
1144            msg.transaction = %self.transaction_id(),
1145            attribute_type = %A::TYPE,
1146        )
1147    )]
1148    pub fn attribute<A: AttributeFromRaw<StunParseError> + AttributeStaticType>(
1149        &self,
1150    ) -> Result<A, StunParseError> {
1151        self.iter_attributes()
1152            .find(|attr| attr.get_type() == A::TYPE)
1153            .ok_or(StunParseError::MissingAttribute(A::TYPE))
1154            .and_then(|raw| A::from_raw(&raw))
1155    }
1156
1157    /// Returns an iterator over the attributes in the [`Message`].
1158    pub fn iter_attributes(&self) -> impl Iterator<Item = RawAttribute> {
1159        MessageAttributesIter {
1160            data: self.data,
1161            data_i: MessageHeader::LENGTH,
1162            seen_message_integrity: false,
1163        }
1164    }
1165
1166    /// Check that a message [`Message`] only contains required attributes that are supported and
1167    /// have at least some set of required attributes.  Returns an appropriate error message on
1168    /// failure to meet these requirements.
1169    ///
1170    /// # Examples
1171    ///
1172    /// ```
1173    /// # use stun_types::attribute::*;
1174    /// # use stun_types::message::{Message, MessageType, MessageClass, BINDING};
1175    /// # use std::convert::TryInto;
1176    /// let mut builder = Message::builder_request(BINDING);
1177    /// let message = builder.build();
1178    /// let message = Message::from_bytes(&message).unwrap();
1179    /// // If nothing is required, no error response is returned
1180    /// assert!(matches!(Message::check_attribute_types(&message, &[], &[]), None));
1181    ///
1182    /// // If an atttribute is required that is not in the message, then an error response message
1183    /// // is generated
1184    /// let error_msg = Message::check_attribute_types(
1185    ///     &message,
1186    ///     &[],
1187    ///     &[Software::TYPE]
1188    /// ).unwrap();
1189    /// assert!(error_msg.has_attribute(ErrorCode::TYPE));
1190    /// let error_msg = error_msg.build();
1191    /// let error_msg = Message::from_bytes(&error_msg).unwrap();
1192    /// let error_code = error_msg.attribute::<ErrorCode>().unwrap();
1193    /// assert_eq!(error_code.code(), 400);
1194    ///
1195    /// let username = Username::new("user").unwrap();
1196    /// builder.add_attribute(&username).unwrap();
1197    /// let message = builder.build();
1198    /// let message = Message::from_bytes(&message).unwrap();
1199    /// // If a Username is in the message but is not advertised as supported then an
1200    /// // 'UNKNOWN-ATTRIBUTES' error response is returned
1201    /// let error_msg = Message::check_attribute_types(&message, &[], &[]).unwrap();
1202    /// let error_msg = error_msg.build();
1203    /// let error_msg = Message::from_bytes(&error_msg).unwrap();
1204    /// assert!(error_msg.is_response());
1205    /// assert!(error_msg.has_attribute(ErrorCode::TYPE));
1206    /// let error_code : ErrorCode = error_msg.attribute::<ErrorCode>().unwrap();
1207    /// assert_eq!(error_code.code(), 420);
1208    /// assert!(error_msg.has_attribute(UnknownAttributes::TYPE));
1209    /// ```
1210    #[tracing::instrument(
1211        level = "trace",
1212        skip(msg),
1213        fields(
1214            msg.transaction = %msg.transaction_id(),
1215        )
1216    )]
1217    pub fn check_attribute_types<'b>(
1218        msg: &Message,
1219        supported: &[AttributeType],
1220        required_in_msg: &[AttributeType],
1221    ) -> Option<MessageBuilder<'b>> {
1222        // Attribute -> AttributeType
1223        let unsupported: Vec<AttributeType> = msg
1224            .iter_attributes()
1225            .map(|a| a.get_type())
1226            // attribute types that require comprehension but are not supported by the caller
1227            .filter(|&at| at.comprehension_required() && !supported.iter().any(|&a| a == at))
1228            .collect();
1229        if !unsupported.is_empty() {
1230            warn!(
1231                "Message contains unknown comprehension required attributes {:?}, returning unknown attributes",
1232                unsupported
1233            );
1234            return Some(Message::unknown_attributes(msg, &unsupported));
1235        }
1236        let has_required_attribute_missing = required_in_msg
1237            .iter()
1238            // attribute types we need in the message -> failure -> Bad Request
1239            .any(|&at| !msg.iter_attributes().map(|a| a.get_type()).any(|a| a == at));
1240        if has_required_attribute_missing {
1241            warn!("Message is missing required attributes, returning bad request");
1242            return Some(Message::bad_request(msg));
1243        }
1244        None
1245    }
1246
1247    /// Generate an error message with an [`ErrorCode`] attribute signalling 'Unknown Attribute'
1248    /// and an [`UnknownAttributes`] attribute containing the attributes that are unknown.
1249    ///
1250    /// # Examples
1251    ///
1252    /// ```
1253    /// # use stun_types::message::{Message, BINDING};
1254    /// # use stun_types::attribute::*;
1255    /// # use std::convert::TryInto;
1256    /// let msg = Message::builder_request(BINDING).build();
1257    /// let msg = Message::from_bytes(&msg).unwrap();
1258    /// let error_msg = Message::unknown_attributes(&msg, &[Username::TYPE]).build();
1259    /// let error_msg = Message::from_bytes(&error_msg).unwrap();
1260    /// assert!(error_msg.is_response());
1261    /// assert!(error_msg.has_attribute(ErrorCode::TYPE));
1262    /// let error_code = error_msg.attribute::<ErrorCode>().unwrap();
1263    /// assert_eq!(error_code.code(), 420);
1264    /// let unknown = error_msg.attribute::<UnknownAttributes>().unwrap();
1265    /// assert!(unknown.has_attribute(Username::TYPE));
1266    /// ```
1267    pub fn unknown_attributes<'b>(
1268        src: &Message,
1269        attributes: &[AttributeType],
1270    ) -> MessageBuilder<'b> {
1271        let mut out = Message::builder_error(src);
1272        let software = Software::new("stun-types").unwrap();
1273        out.add_attribute(&software).unwrap();
1274        let error = ErrorCode::new(420, "Unknown Attributes").unwrap();
1275        out.add_attribute(&error).unwrap();
1276        let unknown = UnknownAttributes::new(attributes);
1277        if !attributes.is_empty() {
1278            out.add_attribute(&unknown).unwrap();
1279        }
1280        out.into_owned()
1281    }
1282
1283    /// Generate an error message with an [`ErrorCode`] attribute signalling a 'Bad Request'
1284    ///
1285    /// # Examples
1286    ///
1287    /// ```
1288    /// # use stun_types::message::{Message, MessageType, MessageClass, BINDING};
1289    /// # use stun_types::attribute::*;
1290    /// # use std::convert::TryInto;
1291    /// let msg = Message::builder_request(BINDING).build();
1292    /// let msg = Message::from_bytes(&msg).unwrap();
1293    /// let error_msg = Message::bad_request(&msg).build();
1294    /// let error_msg = Message::from_bytes(&error_msg).unwrap();
1295    /// assert!(error_msg.has_attribute(ErrorCode::TYPE));
1296    /// let error_code =  error_msg.attribute::<ErrorCode>().unwrap();
1297    /// assert_eq!(error_code.code(), 400);
1298    /// ```
1299    pub fn bad_request<'b>(src: &'a Message) -> MessageBuilder<'b> {
1300        let mut out = Message::builder_error(src);
1301        let software = Software::new("stun-types").unwrap();
1302        out.add_attribute(&software).unwrap();
1303        let error = ErrorCode::new(400, "Bad Request").unwrap();
1304        out.add_attribute(&error).unwrap();
1305        out.into_owned()
1306    }
1307
1308    /// Whether this message contains an attribute of the specified type.
1309    ///
1310    /// # Examples
1311    ///
1312    /// ```
1313    /// # use stun_types::message::{Message, MessageType, MessageClass, BINDING};
1314    /// # use stun_types::attribute::{Software, Attribute, AttributeStaticType};
1315    /// let mut msg = Message::builder_request(BINDING);
1316    /// let attr = Software::new("stun-types").unwrap();
1317    /// assert!(msg.add_attribute(&attr).is_ok());
1318    /// let msg = msg.build();
1319    /// let msg = Message::from_bytes(&msg).unwrap();
1320    /// assert!(msg.has_attribute(Software::TYPE));
1321    /// ```
1322    pub fn has_attribute(&self, atype: AttributeType) -> bool {
1323        self.iter_attributes().any(|attr| attr.get_type() == atype)
1324    }
1325}
1326impl<'a> TryFrom<&'a [u8]> for Message<'a> {
1327    type Error = StunParseError;
1328
1329    fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {
1330        Message::from_bytes(value)
1331    }
1332}
1333
1334#[doc(hidden)]
1335#[derive(Debug)]
1336pub struct MessageAttributesIter<'a> {
1337    data: &'a [u8],
1338    data_i: usize,
1339    seen_message_integrity: bool,
1340}
1341
1342impl<'a> Iterator for MessageAttributesIter<'a> {
1343    type Item = RawAttribute<'a>;
1344
1345    fn next(&mut self) -> Option<Self::Item> {
1346        if self.data_i >= self.data.len() {
1347            return None;
1348        }
1349
1350        let Ok(attr) = RawAttribute::from_bytes(&self.data[self.data_i..]) else {
1351            self.data_i = self.data.len();
1352            return None;
1353        };
1354        let padded_len = attr.padded_len();
1355        self.data_i += padded_len;
1356        if self.seen_message_integrity {
1357            if attr.get_type() == Fingerprint::TYPE {
1358                return Some(attr);
1359            }
1360            return None;
1361        }
1362        if attr.get_type() == MessageIntegrity::TYPE
1363            || attr.get_type() == MessageIntegritySha256::TYPE
1364        {
1365            self.seen_message_integrity = true;
1366        }
1367
1368        Some(attr)
1369    }
1370}
1371
1372#[derive(Clone, Debug)]
1373enum AttrOrRaw<'a> {
1374    Attr(&'a dyn AttributeWrite),
1375    Raw(RawAttribute<'a>),
1376}
1377
1378impl<'a> AttrOrRaw<'a> {
1379    fn into_owned<'b>(self) -> AttrOrRaw<'b> {
1380        match self {
1381            AttrOrRaw::Raw(raw) => AttrOrRaw::Raw(raw.into_owned()),
1382            AttrOrRaw::Attr(attr) => AttrOrRaw::Raw(attr.to_raw().into_owned()),
1383        }
1384    }
1385
1386    fn write_into(&self, dest: &mut [u8]) -> Result<usize, StunWriteError> {
1387        match self {
1388            AttrOrRaw::Raw(raw) => raw.write_into(dest),
1389            AttrOrRaw::Attr(attr) => attr.write_into(dest),
1390        }
1391    }
1392}
1393
1394impl<'a> Attribute for AttrOrRaw<'a> {
1395    fn length(&self) -> u16 {
1396        match self {
1397            Self::Attr(attr) => attr.length(),
1398            Self::Raw(raw) => raw.length(),
1399        }
1400    }
1401
1402    fn get_type(&self) -> AttributeType {
1403        match self {
1404            Self::Attr(attr) => attr.get_type(),
1405            Self::Raw(raw) => raw.get_type(),
1406        }
1407    }
1408}
1409
1410/// A builder of a STUN Message to a sequence of bytes.
1411#[derive(Clone, Debug)]
1412pub struct MessageBuilder<'a> {
1413    msg_type: MessageType,
1414    transaction_id: TransactionId,
1415    attributes: Vec<AttrOrRaw<'a>>,
1416    attribute_types: smallvec::SmallVec<[AttributeType; 16]>,
1417}
1418
1419impl<'a> MessageBuilder<'a> {
1420    /// Consume this builder and produce a new owned version.
1421    pub fn into_owned<'b>(self) -> MessageBuilder<'b> {
1422        MessageBuilder {
1423            msg_type: self.msg_type,
1424            transaction_id: self.transaction_id,
1425            attributes: self
1426                .attributes
1427                .into_iter()
1428                .map(|attr| attr.into_owned())
1429                .collect(),
1430            attribute_types: self.attribute_types.clone(),
1431        }
1432    }
1433
1434    /// Retrieves the 96-bit transaction ID of the [`Message`]
1435    ///
1436    /// # Examples
1437    ///
1438    /// ```
1439    /// # use stun_types::message::{Message, MessageType, MessageClass, BINDING, TransactionId};
1440    /// let mtype = MessageType::from_class_method(MessageClass::Request, BINDING);
1441    /// let transaction_id = TransactionId::generate();
1442    /// let message = Message::builder(mtype, transaction_id).build();
1443    /// let message = Message::from_bytes(&message).unwrap();
1444    /// assert_eq!(message.transaction_id(), transaction_id);
1445    /// ```
1446    pub fn transaction_id(&self) -> TransactionId {
1447        self.transaction_id
1448    }
1449
1450    /// Whether this [`MessageBuilder`] is for a particular [`MessageClass`]
1451    pub fn has_class(&self, cls: MessageClass) -> bool {
1452        self.msg_type.class() == cls
1453    }
1454
1455    /// Serialize a `MessageBuilder` to network bytes
1456    ///
1457    /// # Examples
1458    ///
1459    /// ```
1460    /// # use stun_types::attribute::{RawAttribute, Attribute};
1461    /// # use stun_types::message::{Message, MessageType, MessageClass, BINDING};
1462    /// let mut message = Message::builder(MessageType::from_class_method(MessageClass::Request, BINDING), 1000.into());
1463    /// let attr = RawAttribute::new(1.into(), &[3]);
1464    /// assert!(message.add_raw_attribute(attr).is_ok());
1465    /// assert_eq!(message.build(), vec![0, 1, 0, 8, 33, 18, 164, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 232, 0, 1, 0, 1, 3, 0, 0, 0]);
1466    /// ```
1467    #[tracing::instrument(
1468        name = "message_build",
1469        level = "trace",
1470        skip(self),
1471        fields(
1472            msg.transaction_id = %self.transaction_id()
1473        )
1474    )]
1475    pub fn build(&self) -> Vec<u8> {
1476        let attr_size = self
1477            .attributes
1478            .iter()
1479            .map(|attr| attr.padded_len())
1480            .sum::<usize>();
1481        let mut ret = vec![0; MessageHeader::LENGTH + attr_size];
1482        let _ = self.write_into(&mut ret);
1483        ret
1484    }
1485
1486    /// Write this builder into the provided destination buffer returning the length in bytes that
1487    /// has been written, or an error.
1488    #[tracing::instrument(
1489        name = "message_build",
1490        level = "trace",
1491        skip(self),
1492        fields(
1493            msg.transaction_id = %self.transaction_id()
1494        )
1495    )]
1496    pub fn write_into(&self, dest: &mut [u8]) -> Result<usize, StunWriteError> {
1497        let len = self.byte_len();
1498        if len > dest.len() {
1499            return Err(StunWriteError::TooSmall {
1500                expected: len,
1501                actual: dest.len(),
1502            });
1503        }
1504        self.msg_type.write_into(&mut dest[..2]);
1505        let transaction: u128 = self.transaction_id.into();
1506        let tid = (MAGIC_COOKIE as u128) << 96 | transaction & 0xffff_ffff_ffff_ffff_ffff_ffff;
1507        BigEndian::write_u128(&mut dest[4..20], tid);
1508        BigEndian::write_u16(&mut dest[2..4], (len - MessageHeader::LENGTH) as u16);
1509        let mut offset = MessageHeader::LENGTH;
1510        for attr in &self.attributes {
1511            offset += attr.write_into(&mut dest[offset..])?;
1512        }
1513        Ok(offset)
1514    }
1515
1516    /// The length in bytes this [`MessageBuilder`] would require to successfully construct
1517    /// a message.
1518    pub fn byte_len(&self) -> usize {
1519        MessageHeader::LENGTH
1520            + self
1521                .attributes
1522                .iter()
1523                .map(|attr| attr.padded_len())
1524                .sum::<usize>()
1525    }
1526
1527    // message-integrity is computed using all the data up to (exclusive of) the
1528    // MESSAGE-INTEGRITY but with a length field including the MESSAGE-INTEGRITY attribute...
1529    fn integrity_bytes_from_message(&self, extra_len: u16) -> Vec<u8> {
1530        let mut bytes = self.build();
1531        // rewrite the length to include the message-integrity attribute
1532        let existing_len = BigEndian::read_u16(&bytes[2..4]);
1533        BigEndian::write_u16(&mut bytes[2..4], existing_len + extra_len);
1534        bytes
1535    }
1536
1537    /// Adds MESSAGE_INTEGRITY attribute to a [`Message`] using the provided credentials
1538    ///
1539    /// # Errors
1540    ///
1541    /// - If a [`MessageIntegrity`] attribute is already present
1542    /// - If a [`MessageIntegritySha256`] attribute is already present
1543    /// - If a [`Fingerprint`] attribute is already present
1544    ///
1545    /// # Examples
1546    ///
1547    /// ```
1548    /// # use stun_types::message::{Message, MessageType, MessageClass, BINDING,
1549    ///     MessageIntegrityCredentials, ShortTermCredentials, IntegrityAlgorithm, StunWriteError};
1550    /// # use stun_types::attribute::{Attribute, AttributeStaticType, MessageIntegrity,
1551    ///     MessageIntegritySha256};
1552    /// let mut message = Message::builder_request(BINDING);
1553    /// let credentials = ShortTermCredentials::new("pass".to_owned()).into();
1554    /// assert!(message.add_message_integrity(&credentials, IntegrityAlgorithm::Sha1).is_ok());
1555    ///
1556    /// // duplicate MessageIntegrity is an error
1557    /// assert!(matches!(
1558    ///     message.add_message_integrity(&credentials, IntegrityAlgorithm::Sha1),
1559    ///     Err(StunWriteError::AttributeExists(MessageIntegrity::TYPE)),
1560    /// ));
1561    ///
1562    /// // both MessageIntegrity, and MessageIntegritySha256 are allowed, however Sha256 must be
1563    /// // after Sha1
1564    /// assert!(message.add_message_integrity(&credentials, IntegrityAlgorithm::Sha256).is_ok());
1565    ///
1566    /// let data = message.build();
1567    /// let message = Message::from_bytes(&data).unwrap();
1568    /// assert!(message.validate_integrity(&credentials).is_ok());
1569    /// ```
1570    #[tracing::instrument(
1571        name = "message_add_integrity",
1572        level = "trace",
1573        err,
1574        skip(self),
1575        fields(
1576            msg.transaction = %self.transaction_id(),
1577        )
1578    )]
1579    pub fn add_message_integrity(
1580        &mut self,
1581        credentials: &MessageIntegrityCredentials,
1582        algorithm: IntegrityAlgorithm,
1583    ) -> Result<(), StunWriteError> {
1584        let mut atypes = [AttributeType::new(0); 3];
1585        let mut i = 0;
1586        atypes[i] = match algorithm {
1587            IntegrityAlgorithm::Sha1 => MessageIntegrity::TYPE,
1588            IntegrityAlgorithm::Sha256 => MessageIntegritySha256::TYPE,
1589        };
1590        i += 1;
1591        if algorithm == IntegrityAlgorithm::Sha1 {
1592            atypes[i] = MessageIntegritySha256::TYPE;
1593            i += 1;
1594        }
1595        atypes[i] = Fingerprint::TYPE;
1596        i += 1;
1597
1598        match self.has_any_attribute(&atypes[..i]) {
1599            // can't validly add generic attributes after message integrity or fingerprint
1600            Some(MessageIntegrity::TYPE) => {
1601                return Err(StunWriteError::AttributeExists(MessageIntegrity::TYPE))
1602            }
1603            Some(MessageIntegritySha256::TYPE) => {
1604                return Err(StunWriteError::AttributeExists(
1605                    MessageIntegritySha256::TYPE,
1606                ));
1607            }
1608            Some(Fingerprint::TYPE) => return Err(StunWriteError::FingerprintExists),
1609            _ => (),
1610        }
1611
1612        self.add_message_integrity_unchecked(credentials, algorithm);
1613
1614        Ok(())
1615    }
1616
1617    fn add_message_integrity_unchecked(
1618        &mut self,
1619        credentials: &MessageIntegrityCredentials,
1620        algorithm: IntegrityAlgorithm,
1621    ) {
1622        let key = credentials.make_hmac_key();
1623        match algorithm {
1624            IntegrityAlgorithm::Sha1 => {
1625                let bytes = self.integrity_bytes_from_message(24);
1626                let integrity = MessageIntegrity::compute(&bytes, &key).unwrap();
1627                self.attributes.push(
1628                    AttrOrRaw::Raw(RawAttribute::from(&MessageIntegrity::new(integrity)))
1629                        .into_owned(),
1630                );
1631                self.attribute_types.push(MessageIntegrity::TYPE);
1632            }
1633            IntegrityAlgorithm::Sha256 => {
1634                let bytes = self.integrity_bytes_from_message(36);
1635                let integrity = MessageIntegritySha256::compute(&bytes, &key).unwrap();
1636                self.attributes.push(AttrOrRaw::Raw(
1637                    RawAttribute::from(&MessageIntegritySha256::new(integrity.as_slice()).unwrap())
1638                        .into_owned(),
1639                ));
1640                self.attribute_types.push(MessageIntegritySha256::TYPE);
1641            }
1642        }
1643    }
1644
1645    /// Adds [`Fingerprint`] attribute to a [`Message`]
1646    ///
1647    /// # Errors
1648    ///
1649    /// - If a [`Fingerprint`] attribute is already present
1650    ///
1651    /// # Examples
1652    ///
1653    /// ```
1654    /// # use stun_types::message::{Message, MessageType, MessageClass, BINDING};
1655    /// let mut message = Message::builder_request(BINDING);
1656    /// assert!(message.add_fingerprint().is_ok());
1657    ///
1658    /// // duplicate FINGERPRINT is an error
1659    /// assert!(message.add_fingerprint().is_err());
1660    /// ```
1661    #[tracing::instrument(
1662        name = "message_add_fingerprint",
1663        level = "trace",
1664        skip(self),
1665        fields(
1666            msg.transaction = %self.transaction_id(),
1667        )
1668    )]
1669    pub fn add_fingerprint(&mut self) -> Result<(), StunWriteError> {
1670        if self.has_attribute(Fingerprint::TYPE) {
1671            return Err(StunWriteError::AttributeExists(Fingerprint::TYPE));
1672        }
1673
1674        self.add_fingerprint_unchecked();
1675
1676        Ok(())
1677    }
1678
1679    fn add_fingerprint_unchecked(&mut self) {
1680        // fingerprint is computed using all the data up to (exclusive of) the FINGERPRINT
1681        // but with a length field including the FINGERPRINT attribute...
1682        let mut bytes = self.build();
1683        // rewrite the length to include the fingerprint attribute
1684        let existing_len = BigEndian::read_u16(&bytes[2..4]);
1685        BigEndian::write_u16(&mut bytes[2..4], existing_len + 8);
1686        let fingerprint = Fingerprint::compute(&bytes);
1687        self.attributes
1688            .push(AttrOrRaw::Attr(&Fingerprint::new(fingerprint)).into_owned());
1689        self.attribute_types.push(Fingerprint::TYPE);
1690    }
1691
1692    /// Add a `Attribute` to this `Message`.  Only one `AttributeType` can be added for each
1693    /// `Attribute.  Attempting to add multiple `Atribute`s of the same `AttributeType` will fail.
1694    ///
1695    /// # Errors
1696    ///
1697    /// - If the attribute already exists within the message
1698    /// - If attempting to add attributes when [`MessageIntegrity`], [`MessageIntegritySha256`] or
1699    /// [`Fingerprint`] atributes already exist.
1700    ///
1701    /// # Panics
1702    ///
1703    /// - if a [`MessageIntegrity`] or [`MessageIntegritySha256`] attribute is attempted to be added.  Use
1704    /// `Message::add_message_integrity` instead.
1705    /// - if a [`Fingerprint`] attribute is attempted to be added. Use
1706    /// `Message::add_fingerprint` instead.
1707    ///
1708    /// # Examples
1709    ///
1710    /// Add an `Attribute`
1711    ///
1712    /// ```
1713    /// # use stun_types::attribute::RawAttribute;
1714    /// # use stun_types::message::{Message, MessageType, MessageClass, BINDING};
1715    /// let mut message = Message::builder_request(BINDING);
1716    /// let attr = RawAttribute::new(1.into(), &[3]);
1717    /// assert!(message.add_raw_attribute(attr.clone()).is_ok());
1718    /// assert!(message.add_raw_attribute(attr).is_err());
1719    /// ```
1720    #[tracing::instrument(
1721        name = "message_add_attribute",
1722        level = "trace",
1723        err,
1724        skip(self, attr),
1725        fields(
1726            msg.transaction = %self.transaction_id(),
1727        )
1728    )]
1729    pub fn add_attribute(&mut self, attr: &'a dyn AttributeWrite) -> Result<(), StunWriteError> {
1730        let ty = attr.get_type();
1731        //trace!("adding attribute {:?}", attr);
1732        match ty {
1733            MessageIntegrity::TYPE => {
1734                panic!("Cannot write MessageIntegrity with `add_attribute`.  Use add_message_integrity() instead");
1735            }
1736            MessageIntegritySha256::TYPE => {
1737                panic!("Cannot write MessageIntegritySha256 with `add_attribute`.  Use add_message_integrity() instead");
1738            }
1739            Fingerprint::TYPE => {
1740                panic!(
1741                    "Cannot write Fingerprint with `add_attribute`.  Use add_fingerprint() instead"
1742                );
1743            }
1744            _ => (),
1745        }
1746        match self.has_any_attribute(&[
1747            ty,
1748            MessageIntegrity::TYPE,
1749            MessageIntegritySha256::TYPE,
1750            Fingerprint::TYPE,
1751        ]) {
1752            // can't validly add generic attributes after message integrity or fingerprint
1753            Some(MessageIntegrity::TYPE) => return Err(StunWriteError::MessageIntegrityExists),
1754            Some(MessageIntegritySha256::TYPE) => {
1755                return Err(StunWriteError::MessageIntegrityExists)
1756            }
1757            Some(Fingerprint::TYPE) => return Err(StunWriteError::FingerprintExists),
1758            Some(typ) if typ == ty => return Err(StunWriteError::AttributeExists(ty)),
1759            _ => (),
1760        }
1761        self.attributes.push(AttrOrRaw::Attr(attr));
1762        self.attribute_types.push(ty);
1763        Ok(())
1764    }
1765
1766    /// Add  `RawAttribute` to this `Message`.  Only one `AttributeType` can be added for each
1767    /// `Attribute.  Attempting to add multiple `Atribute`s of the same `AttributeType` will fail.
1768    ///
1769    /// # Errors
1770    ///
1771    /// - If the attribute already exists within the message
1772    /// - If attempting to add attributes when [`MessageIntegrity`], [`MessageIntegritySha256`] or
1773    /// [`Fingerprint`] atributes already exist.
1774    ///
1775    /// # Panics
1776    ///
1777    /// - if a [`MessageIntegrity`] or [`MessageIntegritySha256`] attribute is attempted to be added.  Use
1778    /// `Message::add_message_integrity` instead.
1779    /// - if a [`Fingerprint`] attribute is attempted to be added. Use
1780    /// `Message::add_fingerprint` instead.
1781    #[tracing::instrument(
1782        name = "message_add_raw_attribute",
1783        level = "trace",
1784        err,
1785        skip(self, attr),
1786        fields(
1787            msg.transaction = %self.transaction_id(),
1788        )
1789    )]
1790    pub fn add_raw_attribute(&mut self, attr: RawAttribute<'a>) -> Result<(), StunWriteError> {
1791        let ty = attr.get_type();
1792        //trace!("adding raw attribute {:?}", attr);
1793        match ty {
1794            MessageIntegrity::TYPE => {
1795                panic!("Cannot write MessageIntegrity with `add_raw_attribute`.  Use add_message_integrity() instead");
1796            }
1797            MessageIntegritySha256::TYPE => {
1798                panic!("Cannot write MessageIntegritySha256 with `add_raw_attribute`.  Use add_message_integrity() instead");
1799            }
1800            Fingerprint::TYPE => {
1801                panic!("Cannot write Fingerprint with `add_raw_attribute`.  Use add_fingerprint() instead");
1802            }
1803            _ => (),
1804        }
1805        match self.has_any_attribute(&[
1806            ty,
1807            MessageIntegrity::TYPE,
1808            MessageIntegritySha256::TYPE,
1809            Fingerprint::TYPE,
1810        ]) {
1811            // can't validly add generic attributes after message integrity or fingerprint
1812            Some(MessageIntegrity::TYPE) => return Err(StunWriteError::MessageIntegrityExists),
1813            Some(MessageIntegritySha256::TYPE) => {
1814                return Err(StunWriteError::MessageIntegrityExists)
1815            }
1816            Some(Fingerprint::TYPE) => return Err(StunWriteError::FingerprintExists),
1817            Some(typ) if typ == ty => return Err(StunWriteError::AttributeExists(ty)),
1818            _ => (),
1819        }
1820        self.attributes.push(AttrOrRaw::Raw(attr));
1821        self.attribute_types.push(ty);
1822        Ok(())
1823    }
1824
1825    /// Return whether this [`MessageBuilder`] contains a particular attribute.
1826    pub fn has_attribute(&self, atype: AttributeType) -> bool {
1827        self.attribute_types.iter().any(|&ty| ty == atype)
1828    }
1829
1830    /// Return whether this [`MessageBuilder`] contains any of the provided attributes and
1831    /// returns the attribute found.
1832    pub fn has_any_attribute(&self, atypes: &[AttributeType]) -> Option<AttributeType> {
1833        self.attribute_types
1834            .iter()
1835            .find(|&ty| atypes.contains(ty))
1836            .cloned()
1837    }
1838}
1839
1840#[cfg(test)]
1841mod tests {
1842    use super::*;
1843
1844    #[test]
1845    fn msg_type_roundtrip() {
1846        let _log = crate::tests::test_init_log();
1847        /* validate that all methods/classes survive a roundtrip */
1848        for m in 0..0xfff {
1849            let classes = vec![
1850                MessageClass::Request,
1851                MessageClass::Indication,
1852                MessageClass::Success,
1853                MessageClass::Error,
1854            ];
1855            for c in classes {
1856                let mtype = MessageType::from_class_method(c, m);
1857                assert_eq!(mtype.class(), c);
1858                assert_eq!(mtype.method(), m);
1859                let bytes = mtype.to_bytes();
1860                let ptype = MessageType::from_bytes(&bytes).unwrap();
1861                assert_eq!(mtype, ptype);
1862            }
1863        }
1864    }
1865
1866    #[test]
1867    fn msg_type_not_stun() {
1868        assert!(matches!(
1869            MessageType::from_bytes(&[0xc0, 0x00]),
1870            Err(StunParseError::NotStun)
1871        ));
1872    }
1873
1874    #[test]
1875    fn msg_roundtrip() {
1876        let _log = crate::tests::test_init_log();
1877        /* validate that all methods/classes survive a roundtrip */
1878        for m in (0x009..0x4ff).step_by(0x123) {
1879            let classes = vec![
1880                MessageClass::Request,
1881                MessageClass::Indication,
1882                MessageClass::Success,
1883                MessageClass::Error,
1884            ];
1885            for c in classes {
1886                let mtype = MessageType::from_class_method(c, m);
1887                for tid in (0x18..0xff_ffff_ffff_ffff_ffff).step_by(0xfedc_ba98_7654_3210) {
1888                    let mut msg = Message::builder(mtype, tid.into());
1889                    let attr = RawAttribute::new(1.into(), &[3]);
1890                    assert!(msg.add_raw_attribute(attr.clone()).is_ok());
1891                    let data = msg.build();
1892
1893                    let msg = Message::from_bytes(&data).unwrap();
1894                    let msg_attr = msg.raw_attribute(1.into()).unwrap();
1895                    assert_eq!(msg_attr, attr);
1896                    assert_eq!(msg.get_type(), mtype);
1897                    assert_eq!(msg.transaction_id(), tid.into());
1898                }
1899            }
1900        }
1901    }
1902
1903    #[test]
1904    fn unknown_attributes() {
1905        let _log = crate::tests::test_init_log();
1906        let src = Message::builder_request(BINDING).build();
1907        let src = Message::from_bytes(&src).unwrap();
1908        let msg = Message::unknown_attributes(&src, &[Software::TYPE]).build();
1909        let msg = Message::from_bytes(&msg).unwrap();
1910        assert_eq!(msg.transaction_id(), src.transaction_id());
1911        assert_eq!(msg.class(), MessageClass::Error);
1912        assert_eq!(msg.method(), src.method());
1913        let err = msg.attribute::<ErrorCode>().unwrap();
1914        assert_eq!(err.code(), 420);
1915        let unknown_attrs = msg.attribute::<UnknownAttributes>().unwrap();
1916        assert!(unknown_attrs.has_attribute(Software::TYPE));
1917    }
1918
1919    #[test]
1920    fn bad_request() {
1921        let _log = crate::tests::test_init_log();
1922        let src = Message::builder_request(BINDING).build();
1923        let src = Message::from_bytes(&src).unwrap();
1924        let msg = Message::bad_request(&src).build();
1925        let msg = Message::from_bytes(&msg).unwrap();
1926        assert_eq!(msg.transaction_id(), src.transaction_id());
1927        assert_eq!(msg.class(), MessageClass::Error);
1928        assert_eq!(msg.method(), src.method());
1929        let err = msg.attribute::<ErrorCode>().unwrap();
1930        assert_eq!(err.code(), 400);
1931    }
1932
1933    #[test]
1934    fn fingerprint() {
1935        let _log = crate::tests::test_init_log();
1936        let mut msg = Message::builder_request(BINDING);
1937        let software = Software::new("s").unwrap();
1938        msg.add_attribute(&software).unwrap();
1939        msg.add_fingerprint().unwrap();
1940        let bytes = msg.build();
1941        // validates the fingerprint of the data when available
1942        let new_msg = Message::from_bytes(&bytes).unwrap();
1943        let software = new_msg.attribute::<Software>().unwrap();
1944        assert_eq!(software.software(), "s");
1945        let _new_fingerprint = new_msg.attribute::<Fingerprint>().unwrap();
1946    }
1947
1948    #[test]
1949    fn integrity() {
1950        let _log = crate::tests::test_init_log();
1951        for algorithm in [IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256] {
1952            let credentials = ShortTermCredentials::new("secret".to_owned()).into();
1953            let mut msg = Message::builder_request(BINDING);
1954            let software = Software::new("s").unwrap();
1955            msg.add_attribute(&software).unwrap();
1956            msg.add_message_integrity(&credentials, algorithm).unwrap();
1957            let bytes = msg.build();
1958            // validates the fingerprint of the data when available
1959            let new_msg = Message::from_bytes(&bytes).unwrap();
1960            new_msg.validate_integrity(&credentials).unwrap();
1961            let software = new_msg.attribute::<Software>().unwrap();
1962            assert_eq!(software.software(), "s");
1963        }
1964    }
1965
1966    #[test]
1967    fn write_into_short_destination() {
1968        let _log = crate::tests::test_init_log();
1969        let mut msg = Message::builder_request(BINDING);
1970        let software = Software::new("s").unwrap();
1971        msg.add_attribute(&software).unwrap();
1972        let len = msg.byte_len();
1973        let mut dest = vec![0; len - 1];
1974        assert!(
1975            matches!(msg.write_into(&mut dest), Err(StunWriteError::TooSmall {
1976            expected,
1977            actual,
1978        }) if expected == len && actual == len - 1)
1979        );
1980    }
1981
1982    #[test]
1983    fn add_duplicate_integrity() {
1984        let _log = crate::tests::test_init_log();
1985        let credentials = ShortTermCredentials::new("secret".to_owned()).into();
1986        let mut msg = Message::builder_request(BINDING);
1987        msg.add_message_integrity(&credentials, IntegrityAlgorithm::Sha1)
1988            .unwrap();
1989        assert!(matches!(
1990            msg.add_message_integrity(&credentials, IntegrityAlgorithm::Sha1),
1991            Err(StunWriteError::AttributeExists(MessageIntegrity::TYPE))
1992        ));
1993        msg.add_message_integrity(&credentials, IntegrityAlgorithm::Sha256)
1994            .unwrap();
1995        assert!(matches!(
1996            msg.add_message_integrity(&credentials, IntegrityAlgorithm::Sha256),
1997            Err(StunWriteError::AttributeExists(
1998                MessageIntegritySha256::TYPE
1999            ))
2000        ));
2001        let software = Software::new("s").unwrap();
2002        assert!(matches!(
2003            msg.add_attribute(&software),
2004            Err(StunWriteError::MessageIntegrityExists)
2005        ));
2006    }
2007
2008    #[test]
2009    fn add_sha1_integrity_after_sha256() {
2010        let _log = crate::tests::test_init_log();
2011        let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2012        let mut msg = Message::builder_request(BINDING);
2013        msg.add_message_integrity(&credentials, IntegrityAlgorithm::Sha256)
2014            .unwrap();
2015        assert!(matches!(
2016            msg.add_message_integrity(&credentials, IntegrityAlgorithm::Sha1),
2017            Err(StunWriteError::AttributeExists(
2018                MessageIntegritySha256::TYPE
2019            ))
2020        ));
2021    }
2022
2023    #[test]
2024    fn add_attribute_after_integrity() {
2025        let _log = crate::tests::test_init_log();
2026        for algorithm in [IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256] {
2027            let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2028            let mut msg = Message::builder_request(BINDING);
2029            msg.add_message_integrity(&credentials, algorithm).unwrap();
2030            let software = Software::new("s").unwrap();
2031            assert!(matches!(
2032                msg.add_attribute(&software),
2033                Err(StunWriteError::MessageIntegrityExists)
2034            ));
2035        }
2036    }
2037
2038    #[test]
2039    fn add_raw_attribute_after_integrity() {
2040        let _log = crate::tests::test_init_log();
2041        for algorithm in [IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256] {
2042            let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2043            let mut msg = Message::builder_request(BINDING);
2044            msg.add_message_integrity(&credentials, algorithm).unwrap();
2045            let software = Software::new("s").unwrap();
2046            let raw = software.to_raw();
2047            assert!(matches!(
2048                msg.add_raw_attribute(raw),
2049                Err(StunWriteError::MessageIntegrityExists)
2050            ));
2051        }
2052    }
2053
2054    #[test]
2055    fn add_integrity_after_fingerprint() {
2056        let _log = crate::tests::test_init_log();
2057        for algorithm in [IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256] {
2058            let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2059            let mut msg = Message::builder_request(BINDING);
2060            msg.add_fingerprint().unwrap();
2061            assert!(matches!(
2062                msg.add_message_integrity(&credentials, algorithm),
2063                Err(StunWriteError::FingerprintExists)
2064            ));
2065        }
2066    }
2067
2068    #[test]
2069    fn duplicate_add_attribute() {
2070        let _log = crate::tests::test_init_log();
2071        let mut msg = Message::builder_request(BINDING);
2072        let software = Software::new("s").unwrap();
2073        msg.add_attribute(&software).unwrap();
2074        assert!(matches!(
2075            msg.add_attribute(&software),
2076            Err(StunWriteError::AttributeExists(ty)) if ty == Software::TYPE
2077        ));
2078    }
2079
2080    #[test]
2081    fn duplicate_add_raw_attribute() {
2082        let _log = crate::tests::test_init_log();
2083        let mut msg = Message::builder_request(BINDING);
2084        let software = Software::new("s").unwrap();
2085        let raw = software.to_raw();
2086        msg.add_raw_attribute(raw.clone()).unwrap();
2087        assert!(matches!(
2088            msg.add_raw_attribute(raw),
2089            Err(StunWriteError::AttributeExists(ty)) if ty == Software::TYPE
2090        ));
2091    }
2092
2093    #[test]
2094    fn duplicate_fingerprint() {
2095        let _log = crate::tests::test_init_log();
2096        let mut msg = Message::builder_request(BINDING);
2097        msg.add_fingerprint().unwrap();
2098        assert!(matches!(
2099            msg.add_fingerprint(),
2100            Err(StunWriteError::AttributeExists(Fingerprint::TYPE))
2101        ));
2102    }
2103
2104    #[test]
2105    fn parse_invalid_fingerprint() {
2106        let _log = crate::tests::test_init_log();
2107        let mut msg = Message::builder_request(BINDING);
2108        msg.add_fingerprint().unwrap();
2109        let mut bytes = msg.build();
2110        bytes[24] = 0x80;
2111        bytes[25] = 0x80;
2112        bytes[26] = 0x80;
2113        bytes[27] = 0x80;
2114        assert!(matches!(
2115            Message::from_bytes(&bytes),
2116            Err(StunParseError::FingerprintMismatch)
2117        ));
2118    }
2119
2120    #[test]
2121    fn parse_wrong_magic() {
2122        let _log = crate::tests::test_init_log();
2123        let mut msg = Message::builder_request(BINDING);
2124        msg.add_fingerprint().unwrap();
2125        let mut bytes = msg.build();
2126        bytes[4] = 0x80;
2127        assert!(matches!(
2128            Message::from_bytes(&bytes),
2129            Err(StunParseError::NotStun)
2130        ));
2131    }
2132
2133    #[test]
2134    fn parse_attribute_after_integrity() {
2135        let _log = crate::tests::test_init_log();
2136        for algorithm in [IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256] {
2137            let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2138            let mut msg = Message::builder_request(BINDING);
2139            msg.add_message_integrity(&credentials, algorithm).unwrap();
2140            let mut bytes = msg.build();
2141            let software = Software::new("s").unwrap();
2142            let software_bytes = RawAttribute::from(&software).to_bytes();
2143            let software_len = software_bytes.len();
2144            bytes.extend(software_bytes);
2145            bytes[3] += software_len as u8;
2146            assert!(matches!(
2147                Message::from_bytes(&bytes),
2148                Err(StunParseError::AttributeAfterIntegrity(Software::TYPE))
2149            ));
2150        }
2151    }
2152
2153    #[test]
2154    fn parse_duplicate_integrity_after_integrity() {
2155        let _log = crate::tests::test_init_log();
2156        for algorithm in [IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256] {
2157            let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2158            let mut msg = Message::builder_request(BINDING);
2159            msg.add_message_integrity(&credentials, algorithm).unwrap();
2160            // duplicate integrity attribute. Don't do this in real code!
2161            msg.add_message_integrity_unchecked(&credentials, algorithm);
2162            let bytes = msg.build();
2163            let integrity_type = match algorithm {
2164                IntegrityAlgorithm::Sha1 => MessageIntegrity::TYPE,
2165                IntegrityAlgorithm::Sha256 => MessageIntegritySha256::TYPE,
2166            };
2167            let Err(StunParseError::AttributeAfterIntegrity(err_integrity_type)) =
2168                Message::from_bytes(&bytes)
2169            else {
2170                unreachable!();
2171            };
2172            assert_eq!(integrity_type, err_integrity_type);
2173        }
2174    }
2175
2176    #[test]
2177    fn parse_attribute_after_fingerprint() {
2178        let _log = crate::tests::test_init_log();
2179        let mut msg = Message::builder_request(BINDING);
2180        msg.add_fingerprint().unwrap();
2181        let mut bytes = msg.build();
2182        let software = Software::new("s").unwrap();
2183        let software_bytes = RawAttribute::from(&software).to_bytes();
2184        let software_len = software_bytes.len();
2185        bytes.extend(software_bytes);
2186        bytes[3] += software_len as u8;
2187        assert!(matches!(
2188            Message::from_bytes(&bytes),
2189            Err(StunParseError::AttributeAfterFingerprint(Software::TYPE))
2190        ));
2191    }
2192
2193    #[test]
2194    fn parse_duplicate_fingerprint_after_fingerprint() {
2195        let _log = crate::tests::test_init_log();
2196        let mut msg = Message::builder_request(BINDING);
2197        msg.add_fingerprint().unwrap();
2198        msg.add_fingerprint_unchecked();
2199        let bytes = msg.build();
2200        assert!(matches!(
2201            Message::from_bytes(&bytes),
2202            Err(StunParseError::AttributeAfterFingerprint(Fingerprint::TYPE))
2203        ));
2204    }
2205
2206    #[test]
2207    fn add_attribute_after_fingerprint() {
2208        let _log = crate::tests::test_init_log();
2209        let mut msg = Message::builder_request(BINDING);
2210        msg.add_fingerprint().unwrap();
2211        let software = Software::new("s").unwrap();
2212        assert!(matches!(
2213            msg.add_attribute(&software),
2214            Err(StunWriteError::FingerprintExists)
2215        ));
2216    }
2217
2218    #[test]
2219    fn add_raw_attribute_after_fingerprint() {
2220        let _log = crate::tests::test_init_log();
2221        let mut msg = Message::builder_request(BINDING);
2222        msg.add_fingerprint().unwrap();
2223        let software = Software::new("s").unwrap();
2224        let raw = software.to_raw();
2225        assert!(matches!(
2226            msg.add_raw_attribute(raw),
2227            Err(StunWriteError::FingerprintExists)
2228        ));
2229    }
2230
2231    #[test]
2232    fn parse_truncated_message_header() {
2233        let _log = crate::tests::test_init_log();
2234        let mut msg = Message::builder_request(BINDING);
2235        msg.add_fingerprint().unwrap();
2236        let bytes = msg.build();
2237        assert!(matches!(
2238            Message::from_bytes(&bytes[..8]),
2239            Err(StunParseError::Truncated {
2240                expected: 20,
2241                actual: 8
2242            })
2243        ));
2244    }
2245
2246    #[test]
2247    fn parse_truncated_message() {
2248        let _log = crate::tests::test_init_log();
2249        let mut msg = Message::builder_request(BINDING);
2250        msg.add_fingerprint().unwrap();
2251        let bytes = msg.build();
2252        assert!(matches!(
2253            Message::from_bytes(&bytes[..24]),
2254            Err(StunParseError::Truncated {
2255                expected: 28,
2256                actual: 24
2257            })
2258        ));
2259    }
2260
2261    #[test]
2262    fn parse_truncated_message_attribute() {
2263        let _log = crate::tests::test_init_log();
2264        let mut msg = Message::builder_request(BINDING);
2265        msg.add_fingerprint().unwrap();
2266        let mut bytes = msg.build();
2267        // rewrite message header to support the truncated length, but not the attribute.
2268        bytes[3] = 4;
2269        assert!(matches!(
2270            Message::from_bytes(&bytes[..24]),
2271            Err(StunParseError::Truncated {
2272                expected: 28,
2273                actual: 24
2274            })
2275        ));
2276    }
2277
2278    #[test]
2279    fn valid_attributes() {
2280        let _log = crate::tests::test_init_log();
2281        let mut src = Message::builder_request(BINDING);
2282        let username = Username::new("123").unwrap();
2283        src.add_attribute(&username).unwrap();
2284        let priority = Priority::new(123);
2285        src.add_attribute(&priority).unwrap();
2286        let src = src.build();
2287        let src = Message::from_bytes(&src).unwrap();
2288
2289        // success case
2290        let res = Message::check_attribute_types(
2291            &src,
2292            &[Username::TYPE, Priority::TYPE],
2293            &[Username::TYPE],
2294        );
2295        assert!(res.is_none());
2296
2297        // fingerprint required but not present
2298        let res = Message::check_attribute_types(
2299            &src,
2300            &[Username::TYPE, Priority::TYPE],
2301            &[Fingerprint::TYPE],
2302        );
2303        assert!(res.is_some());
2304        let res = res.unwrap();
2305        let res = res.build();
2306        let res = Message::from_bytes(&res).unwrap();
2307        assert!(res.has_class(MessageClass::Error));
2308        assert!(res.has_method(src.method()));
2309        let err = res.attribute::<ErrorCode>().unwrap();
2310        assert_eq!(err.code(), 400);
2311
2312        // priority unsupported
2313        let res = Message::check_attribute_types(&src, &[Username::TYPE], &[]);
2314        assert!(res.is_some());
2315        let res = res.unwrap();
2316        let data = res.build();
2317        let res = Message::from_bytes(&data).unwrap();
2318        assert!(res.has_class(MessageClass::Error));
2319        assert!(res.has_method(src.method()));
2320        let err = res.attribute::<ErrorCode>().unwrap();
2321        assert_eq!(err.code(), 420);
2322        let unknown = res.attribute::<UnknownAttributes>().unwrap();
2323        assert!(unknown.has_attribute(Priority::TYPE));
2324    }
2325
2326    #[test]
2327    #[should_panic(expected = "created from a non-request message")]
2328    fn builder_success_panic() {
2329        let _log = crate::tests::test_init_log();
2330        let msg = Message::builder(
2331            MessageType::from_class_method(MessageClass::Indication, BINDING),
2332            TransactionId::generate(),
2333        )
2334        .build();
2335        let msg = Message::from_bytes(&msg).unwrap();
2336        let _builder = Message::builder_success(&msg);
2337    }
2338
2339    #[test]
2340    #[should_panic(expected = "created from a non-request message")]
2341    fn builder_error_panic() {
2342        let _log = crate::tests::test_init_log();
2343        let msg = Message::builder(
2344            MessageType::from_class_method(MessageClass::Indication, BINDING),
2345            TransactionId::generate(),
2346        )
2347        .build();
2348        let msg = Message::from_bytes(&msg).unwrap();
2349        let _builder = Message::builder_error(&msg);
2350    }
2351
2352    #[test]
2353    #[should_panic(expected = "Use add_message_integrity() instead")]
2354    fn builder_add_attribute_integrity_panic() {
2355        let _log = crate::tests::test_init_log();
2356        let mut msg = Message::builder_request(BINDING);
2357        let hmac = [2; 20];
2358        let integrity = MessageIntegrity::new(hmac);
2359        msg.add_attribute(&integrity).unwrap();
2360    }
2361
2362    #[test]
2363    #[should_panic(expected = "Use add_message_integrity() instead")]
2364    fn builder_add_raw_attribute_integrity_panic() {
2365        let _log = crate::tests::test_init_log();
2366        let mut msg = Message::builder_request(BINDING);
2367        let hmac = [2; 20];
2368        let integrity = MessageIntegrity::new(hmac);
2369        let raw = integrity.to_raw();
2370        msg.add_raw_attribute(raw).unwrap();
2371    }
2372
2373    #[test]
2374    #[should_panic(expected = "Use add_message_integrity() instead")]
2375    fn builder_add_attribute_integrity_sha256_panic() {
2376        let _log = crate::tests::test_init_log();
2377        let mut msg = Message::builder_request(BINDING);
2378        let hmac = [2; 16];
2379        let integrity = MessageIntegritySha256::new(&hmac).unwrap();
2380        msg.add_attribute(&integrity).unwrap();
2381    }
2382
2383    #[test]
2384    #[should_panic(expected = "Use add_message_integrity() instead")]
2385    fn builder_add_raw_attribute_integrity_sha256_panic() {
2386        let _log = crate::tests::test_init_log();
2387        let mut msg = Message::builder_request(BINDING);
2388        let hmac = [2; 16];
2389        let integrity = MessageIntegritySha256::new(&hmac).unwrap();
2390        let raw = integrity.to_raw();
2391        msg.add_raw_attribute(raw).unwrap();
2392    }
2393
2394    #[test]
2395    #[should_panic(expected = "Use add_fingerprint() instead")]
2396    fn builder_add_attribute_fingerprint_panic() {
2397        let _log = crate::tests::test_init_log();
2398        let mut msg = Message::builder_request(BINDING);
2399        let fingerprint = [2; 4];
2400        let fingerprint = Fingerprint::new(fingerprint);
2401        msg.add_attribute(&fingerprint).unwrap();
2402    }
2403
2404    #[test]
2405    #[should_panic(expected = "Use add_fingerprint() instead")]
2406    fn builder_add_raw_attribute_fingerprint_panic() {
2407        let _log = crate::tests::test_init_log();
2408        let mut msg = Message::builder_request(BINDING);
2409        let fingerprint = [2; 4];
2410        let fingerprint = Fingerprint::new(fingerprint);
2411        let raw = fingerprint.to_raw();
2412        msg.add_raw_attribute(raw).unwrap();
2413    }
2414
2415    #[test]
2416    fn rfc5769_vector1() {
2417        let _log = crate::tests::test_init_log();
2418        // https://tools.ietf.org/html/rfc5769#section-2.1
2419        let data = vec![
2420            0x00, 0x01, 0x00, 0x58, // Request type message length
2421            0x21, 0x12, 0xa4, 0x42, // Magic cookie
2422            0xb7, 0xe7, 0xa7, 0x01, // }
2423            0xbc, 0x34, 0xd6, 0x86, // } Transaction ID
2424            0xfa, 0x87, 0xdf, 0xae, // }
2425            0x80, 0x22, 0x00, 0x10, // SOFTWARE header
2426            0x53, 0x54, 0x55, 0x4e, //   }
2427            0x20, 0x74, 0x65, 0x73, //   }  User-agent...
2428            0x74, 0x20, 0x63, 0x6c, //   }  ...name
2429            0x69, 0x65, 0x6e, 0x74, //   }
2430            0x00, 0x24, 0x00, 0x04, // PRIORITY header
2431            0x6e, 0x00, 0x01, 0xff, //   PRIORITY value
2432            0x80, 0x29, 0x00, 0x08, // ICE_CONTROLLED header
2433            0x93, 0x2f, 0xf9, 0xb1, //   Pseudo random number
2434            0x51, 0x26, 0x3b, 0x36, //   ... for tie breaker
2435            0x00, 0x06, 0x00, 0x09, // USERNAME header
2436            0x65, 0x76, 0x74, 0x6a, //   Username value
2437            0x3a, 0x68, 0x36, 0x76, //   (9 bytes)
2438            0x59, 0x20, 0x20, 0x20, //   (3 bytes padding)
2439            0x00, 0x08, 0x00, 0x14, // MESSAGE-INTEGRITY header
2440            0x9a, 0xea, 0xa7, 0x0c, //   }
2441            0xbf, 0xd8, 0xcb, 0x56, //   }
2442            0x78, 0x1e, 0xf2, 0xb5, //   } HMAC-SHA1 fingerprint
2443            0xb2, 0xd3, 0xf2, 0x49, //   }
2444            0xc1, 0xb5, 0x71, 0xa2, //   }
2445            0x80, 0x28, 0x00, 0x04, // FINGERPRINT header
2446            0xe5, 0x7a, 0x3b, 0xcf, //   CRC32 fingerprint
2447        ];
2448        let msg = Message::from_bytes(&data).unwrap();
2449        assert!(msg.has_class(MessageClass::Request));
2450        assert!(msg.has_method(BINDING));
2451        assert_eq!(msg.transaction_id(), 0xb7e7_a701_bc34_d686_fa87_dfae.into());
2452
2453        let mut builder = Message::builder(
2454            MessageType::from_class_method(MessageClass::Request, BINDING),
2455            msg.transaction_id(),
2456        );
2457
2458        // SOFTWARE
2459        assert!(msg.has_attribute(Software::TYPE));
2460        let raw = msg.raw_attribute(Software::TYPE).unwrap();
2461        assert!(matches!(Software::try_from(&raw), Ok(_)));
2462        let software = Software::try_from(&raw).unwrap();
2463        assert_eq!(software.software(), "STUN test client");
2464        builder.add_attribute(&software).unwrap();
2465
2466        // PRIORITY
2467        assert!(msg.has_attribute(Priority::TYPE));
2468        let raw = msg.raw_attribute(Priority::TYPE).unwrap();
2469        assert!(matches!(Priority::try_from(&raw), Ok(_)));
2470        let priority = Priority::try_from(&raw).unwrap();
2471        assert_eq!(priority.priority(), 0x6e0001ff);
2472        builder.add_attribute(&priority).unwrap();
2473
2474        // ICE-CONTROLLED
2475        assert!(msg.has_attribute(IceControlled::TYPE));
2476        let raw = msg.raw_attribute(IceControlled::TYPE).unwrap();
2477        assert!(matches!(IceControlled::try_from(&raw), Ok(_)));
2478        let ice = IceControlled::try_from(&raw).unwrap();
2479        assert_eq!(ice.tie_breaker(), 0x932f_f9b1_5126_3b36);
2480        builder.add_attribute(&ice).unwrap();
2481
2482        // USERNAME
2483        assert!(msg.has_attribute(Username::TYPE));
2484        let raw = msg.raw_attribute(Username::TYPE).unwrap();
2485        assert!(matches!(Username::try_from(&raw), Ok(_)));
2486        let username = Username::try_from(&raw).unwrap();
2487        assert_eq!(username.username(), "evtj:h6vY");
2488        builder.add_attribute(&username).unwrap();
2489
2490        // MESSAGE_INTEGRITY
2491        let credentials = MessageIntegrityCredentials::ShortTerm(ShortTermCredentials {
2492            password: "VOkJxbRl1RmTxUk/WvJxBt".to_owned(),
2493        });
2494        assert!(matches!(
2495            msg.validate_integrity(&credentials),
2496            Ok(IntegrityAlgorithm::Sha1)
2497        ));
2498        builder
2499            .add_message_integrity(&credentials, IntegrityAlgorithm::Sha1)
2500            .unwrap();
2501
2502        // FINGERPRINT is checked by Message::from_bytes() when present
2503        assert!(msg.has_attribute(Fingerprint::TYPE));
2504        builder.add_fingerprint().unwrap();
2505
2506        // assert that we produce the same output as we parsed in this case
2507        let mut msg_data = builder.build();
2508        // match the padding bytes with the original
2509        msg_data[73] = 0x20;
2510        msg_data[74] = 0x20;
2511        msg_data[75] = 0x20;
2512        // as a result of the padding difference, the message integrity and fingerpinrt values will
2513        // be different
2514        assert_eq!(msg_data[..80], data[..80]);
2515    }
2516
2517    #[test]
2518    fn rfc5769_vector2() {
2519        let _log = crate::tests::test_init_log();
2520        // https://tools.ietf.org/html/rfc5769#section-2.2
2521        let data = vec![
2522            0x01, 0x01, 0x00, 0x3c, // Response type message length
2523            0x21, 0x12, 0xa4, 0x42, // Magic cookie
2524            0xb7, 0xe7, 0xa7, 0x01, // }
2525            0xbc, 0x34, 0xd6, 0x86, // }  Transaction ID
2526            0xfa, 0x87, 0xdf, 0xae, // }
2527            0x80, 0x22, 0x00, 0x0b, // SOFTWARE attribute header
2528            0x74, 0x65, 0x73, 0x74, //   }
2529            0x20, 0x76, 0x65, 0x63, //   }  UTF-8 server name
2530            0x74, 0x6f, 0x72, 0x20, //   }
2531            0x00, 0x20, 0x00, 0x08, // XOR-MAPPED-ADDRESS attribute header
2532            0x00, 0x01, 0xa1, 0x47, //   Address family (IPv4) and xor'd mapped port number
2533            0xe1, 0x12, 0xa6, 0x43, //   Xor'd mapped IPv4 address
2534            0x00, 0x08, 0x00, 0x14, //   MESSAGE-INTEGRITY attribute header
2535            0x2b, 0x91, 0xf5, 0x99, // }
2536            0xfd, 0x9e, 0x90, 0xc3, // }
2537            0x8c, 0x74, 0x89, 0xf9, // }  HMAC-SHA1 fingerprint
2538            0x2a, 0xf9, 0xba, 0x53, // }
2539            0xf0, 0x6b, 0xe7, 0xd7, // }
2540            0x80, 0x28, 0x00, 0x04, //  FINGERPRINT attribute header
2541            0xc0, 0x7d, 0x4c, 0x96, //  CRC32 fingerprint
2542        ];
2543
2544        let msg = Message::from_bytes(&data).unwrap();
2545        assert!(msg.has_class(MessageClass::Success));
2546        assert!(msg.has_method(BINDING));
2547        assert_eq!(msg.transaction_id(), 0xb7e7_a701_bc34_d686_fa87_dfae.into());
2548        let mut builder = Message::builder(
2549            MessageType::from_class_method(MessageClass::Success, BINDING),
2550            msg.transaction_id(),
2551        );
2552
2553        // SOFTWARE
2554        assert!(msg.has_attribute(Software::TYPE));
2555        let raw = msg.raw_attribute(Software::TYPE).unwrap();
2556        assert!(matches!(Software::try_from(&raw), Ok(_)));
2557        let software = Software::try_from(&raw).unwrap();
2558        assert_eq!(software.software(), "test vector");
2559        builder.add_attribute(&software).unwrap();
2560
2561        // XOR_MAPPED_ADDRESS
2562        assert!(msg.has_attribute(XorMappedAddress::TYPE));
2563        let raw = msg.raw_attribute(XorMappedAddress::TYPE).unwrap();
2564        assert!(matches!(XorMappedAddress::try_from(&raw), Ok(_)));
2565        let xor_mapped_addres = XorMappedAddress::try_from(&raw).unwrap();
2566        assert_eq!(
2567            xor_mapped_addres.addr(msg.transaction_id()),
2568            "192.0.2.1:32853".parse().unwrap()
2569        );
2570        builder.add_attribute(&xor_mapped_addres).unwrap();
2571
2572        // MESSAGE_INTEGRITY
2573        let credentials = MessageIntegrityCredentials::ShortTerm(ShortTermCredentials {
2574            password: "VOkJxbRl1RmTxUk/WvJxBt".to_owned(),
2575        });
2576        let ret = msg.validate_integrity(&credentials);
2577        debug!("{:?}", ret);
2578        assert!(matches!(ret, Ok(IntegrityAlgorithm::Sha1)));
2579        builder
2580            .add_message_integrity(&credentials, IntegrityAlgorithm::Sha1)
2581            .unwrap();
2582
2583        // FINGERPRINT is checked by Message::from_bytes() when present
2584        assert!(msg.has_attribute(Fingerprint::TYPE));
2585        builder.add_fingerprint().unwrap();
2586
2587        // assert that we produce the same output as we parsed in this case
2588        let mut msg_data = builder.build();
2589        // match the padding bytes with the original
2590        msg_data[35] = 0x20;
2591        assert_eq!(msg_data[..52], data[..52]);
2592    }
2593
2594    #[test]
2595    fn rfc5769_vector3() {
2596        let _log = crate::tests::test_init_log();
2597        // https://tools.ietf.org/html/rfc5769#section-2.3
2598        let data = vec![
2599            0x01, 0x01, 0x00, 0x48, // Response type and message length
2600            0x21, 0x12, 0xa4, 0x42, // Magic cookie
2601            0xb7, 0xe7, 0xa7, 0x01, // }
2602            0xbc, 0x34, 0xd6, 0x86, // }  Transaction ID
2603            0xfa, 0x87, 0xdf, 0xae, // }
2604            0x80, 0x22, 0x00, 0x0b, //    SOFTWARE attribute header
2605            0x74, 0x65, 0x73, 0x74, // }
2606            0x20, 0x76, 0x65, 0x63, // }  UTF-8 server name
2607            0x74, 0x6f, 0x72, 0x20, // }
2608            0x00, 0x20, 0x00, 0x14, //    XOR-MAPPED-ADDRESS attribute header
2609            0x00, 0x02, 0xa1, 0x47, //    Address family (IPv6) and xor'd mapped port number
2610            0x01, 0x13, 0xa9, 0xfa, // }
2611            0xa5, 0xd3, 0xf1, 0x79, // }  Xor'd mapped IPv6 address
2612            0xbc, 0x25, 0xf4, 0xb5, // }
2613            0xbe, 0xd2, 0xb9, 0xd9, // }
2614            0x00, 0x08, 0x00, 0x14, //    MESSAGE-INTEGRITY attribute header
2615            0xa3, 0x82, 0x95, 0x4e, // }
2616            0x4b, 0xe6, 0x7b, 0xf1, // }
2617            0x17, 0x84, 0xc9, 0x7c, // }  HMAC-SHA1 fingerprint
2618            0x82, 0x92, 0xc2, 0x75, // }
2619            0xbf, 0xe3, 0xed, 0x41, // }
2620            0x80, 0x28, 0x00, 0x04, //    FINGERPRINT attribute header
2621            0xc8, 0xfb, 0x0b, 0x4c, //    CRC32 fingerprint
2622        ];
2623
2624        let msg = Message::from_bytes(&data).unwrap();
2625        assert!(msg.has_class(MessageClass::Success));
2626        assert!(msg.has_method(BINDING));
2627        assert_eq!(msg.transaction_id(), 0xb7e7_a701_bc34_d686_fa87_dfae.into());
2628        let mut builder = Message::builder(
2629            MessageType::from_class_method(MessageClass::Success, BINDING),
2630            msg.transaction_id(),
2631        );
2632
2633        // SOFTWARE
2634        assert!(msg.has_attribute(Software::TYPE));
2635        let raw = msg.raw_attribute(Software::TYPE).unwrap();
2636        assert!(matches!(Software::try_from(&raw), Ok(_)));
2637        let software = Software::try_from(&raw).unwrap();
2638        assert_eq!(software.software(), "test vector");
2639        builder.add_attribute(&software).unwrap();
2640
2641        // XOR_MAPPED_ADDRESS
2642        assert!(msg.has_attribute(XorMappedAddress::TYPE));
2643        let raw = msg.raw_attribute(XorMappedAddress::TYPE).unwrap();
2644        assert!(matches!(XorMappedAddress::try_from(&raw), Ok(_)));
2645        let xor_mapped_addres = XorMappedAddress::try_from(&raw).unwrap();
2646        assert_eq!(
2647            xor_mapped_addres.addr(msg.transaction_id()),
2648            "[2001:db8:1234:5678:11:2233:4455:6677]:32853"
2649                .parse()
2650                .unwrap()
2651        );
2652        builder.add_attribute(&xor_mapped_addres).unwrap();
2653
2654        // MESSAGE_INTEGRITY
2655        let credentials = MessageIntegrityCredentials::ShortTerm(ShortTermCredentials {
2656            password: "VOkJxbRl1RmTxUk/WvJxBt".to_owned(),
2657        });
2658        assert!(matches!(
2659            msg.validate_integrity(&credentials),
2660            Ok(IntegrityAlgorithm::Sha1)
2661        ));
2662        builder
2663            .add_message_integrity(&credentials, IntegrityAlgorithm::Sha1)
2664            .unwrap();
2665
2666        // FINGERPRINT is checked by Message::from_bytes() when present
2667        assert!(msg.has_attribute(Fingerprint::TYPE));
2668        builder.add_fingerprint().unwrap();
2669
2670        // assert that we produce the same output as we parsed in this case
2671        let mut msg_data = builder.build();
2672        // match the padding bytes with the original
2673        msg_data[35] = 0x20;
2674        assert_eq!(msg_data[..64], data[..64]);
2675    }
2676
2677    #[test]
2678    fn rfc5769_vector4() {
2679        let _log = crate::tests::test_init_log();
2680        // https://tools.ietf.org/html/rfc5769#section-2.4
2681        let data = vec![
2682            0x00, 0x01, 0x00, 0x60, //    Request type and message length
2683            0x21, 0x12, 0xa4, 0x42, //    Magic cookie
2684            0x78, 0xad, 0x34, 0x33, // }
2685            0xc6, 0xad, 0x72, 0xc0, // }  Transaction ID
2686            0x29, 0xda, 0x41, 0x2e, // }
2687            0x00, 0x06, 0x00, 0x12, //    USERNAME attribute header
2688            0xe3, 0x83, 0x9e, 0xe3, // }
2689            0x83, 0x88, 0xe3, 0x83, // }
2690            0xaa, 0xe3, 0x83, 0x83, // }  Username value (18 bytes) and padding (2 bytes)
2691            0xe3, 0x82, 0xaf, 0xe3, // }
2692            0x82, 0xb9, 0x00, 0x00, // }
2693            0x00, 0x15, 0x00, 0x1c, //    NONCE attribute header
2694            0x66, 0x2f, 0x2f, 0x34, // }
2695            0x39, 0x39, 0x6b, 0x39, // }
2696            0x35, 0x34, 0x64, 0x36, // }
2697            0x4f, 0x4c, 0x33, 0x34, // }  Nonce value
2698            0x6f, 0x4c, 0x39, 0x46, // }
2699            0x53, 0x54, 0x76, 0x79, // }
2700            0x36, 0x34, 0x73, 0x41, // }
2701            0x00, 0x14, 0x00, 0x0b, //    REALM attribute header
2702            0x65, 0x78, 0x61, 0x6d, // }
2703            0x70, 0x6c, 0x65, 0x2e, // }  Realm value (11 bytes) and padding (1 byte)
2704            0x6f, 0x72, 0x67, 0x00, // }
2705            0x00, 0x08, 0x00, 0x14, //    MESSAGE-INTEGRITY attribute header
2706            0xf6, 0x70, 0x24, 0x65, // }
2707            0x6d, 0xd6, 0x4a, 0x3e, // }
2708            0x02, 0xb8, 0xe0, 0x71, // }  HMAC-SHA1 fingerprint
2709            0x2e, 0x85, 0xc9, 0xa2, // }
2710            0x8c, 0xa8, 0x96, 0x66, // }
2711        ];
2712
2713        let msg = Message::from_bytes(&data).unwrap();
2714        assert!(msg.has_class(MessageClass::Request));
2715        assert!(msg.has_method(BINDING));
2716        assert_eq!(msg.transaction_id(), 0x78ad_3433_c6ad_72c0_29da_412e.into());
2717        let mut builder = Message::builder(
2718            MessageType::from_class_method(MessageClass::Request, BINDING),
2719            msg.transaction_id(),
2720        );
2721
2722        let long_term = LongTermCredentials {
2723            username: "\u{30DE}\u{30C8}\u{30EA}\u{30C3}\u{30AF}\u{30B9}".to_owned(),
2724            password: "The\u{00AD}M\u{00AA}tr\u{2168}".to_owned(),
2725            realm: "example.org".to_owned(),
2726        };
2727        // USERNAME
2728        assert!(msg.has_attribute(Username::TYPE));
2729        let raw = msg.raw_attribute(Username::TYPE).unwrap();
2730        assert!(matches!(Username::try_from(&raw), Ok(_)));
2731        let username = Username::try_from(&raw).unwrap();
2732        assert_eq!(username.username(), &long_term.username);
2733        builder.add_attribute(&username).unwrap();
2734
2735        // NONCE
2736        let expected_nonce = "f//499k954d6OL34oL9FSTvy64sA";
2737        assert!(msg.has_attribute(Nonce::TYPE));
2738        let raw = msg.raw_attribute(Nonce::TYPE).unwrap();
2739        assert!(matches!(Nonce::try_from(&raw), Ok(_)));
2740        let nonce = Nonce::try_from(&raw).unwrap();
2741        assert_eq!(nonce.nonce(), expected_nonce);
2742        builder.add_attribute(&nonce).unwrap();
2743
2744        // REALM
2745        assert!(msg.has_attribute(Realm::TYPE));
2746        let raw = msg.raw_attribute(Realm::TYPE).unwrap();
2747        assert!(matches!(Realm::try_from(&raw), Ok(_)));
2748        let realm = Realm::try_from(&raw).unwrap();
2749        assert_eq!(realm.realm(), long_term.realm());
2750        builder.add_attribute(&realm).unwrap();
2751
2752        // MESSAGE_INTEGRITY
2753        /* XXX: the password needs SASLPrep-ing to be useful here
2754        let credentials = MessageIntegrityCredentials::LongTerm(long_term);
2755        assert!(matches!(msg.validate_integrity(&data, &credentials), Ok(())));
2756        */
2757        //builder.add_attribute(msg.raw_attribute(MessageIntegrity::TYPE).unwrap()).unwrap();
2758
2759        assert_eq!(builder.build()[4..], data[4..92]);
2760    }
2761
2762    #[test]
2763    fn rfc8489_vector1() {
2764        let _log = crate::tests::test_init_log();
2765        // https://www.rfc-editor.org/rfc/rfc8489#appendix-B.1
2766        // https://www.rfc-editor.org/errata/eid6268
2767        let data = vec![
2768            0x00, 0x01, 0x00, 0x90, //     Request type and message length
2769            0x21, 0x12, 0xa4, 0x42, //     Magic cookie
2770            0x78, 0xad, 0x34, 0x33, //  }
2771            0xc6, 0xad, 0x72, 0xc0, //  }  Transaction ID
2772            0x29, 0xda, 0x41, 0x2e, //  }
2773            0x00, 0x1e, 0x00, 0x20, //     USERHASH attribute header
2774            0x4a, 0x3c, 0xf3, 0x8f, //  }
2775            0xef, 0x69, 0x92, 0xbd, //  }
2776            0xa9, 0x52, 0xc6, 0x78, //  }
2777            0x04, 0x17, 0xda, 0x0f, //  }  Userhash value (32 bytes)
2778            0x24, 0x81, 0x94, 0x15, //  }
2779            0x56, 0x9e, 0x60, 0xb2, //  }
2780            0x05, 0xc4, 0x6e, 0x41, //  }
2781            0x40, 0x7f, 0x17, 0x04, //  }
2782            0x00, 0x15, 0x00, 0x29, //     NONCE attribute header
2783            0x6f, 0x62, 0x4d, 0x61, //  }
2784            0x74, 0x4a, 0x6f, 0x73, //  }
2785            0x32, 0x41, 0x41, 0x41, //  }
2786            0x43, 0x66, 0x2f, 0x2f, //  }
2787            0x34, 0x39, 0x39, 0x6b, //  }  Nonce value and padding (3 bytes)
2788            0x39, 0x35, 0x34, 0x64, //  }
2789            0x36, 0x4f, 0x4c, 0x33, //  }
2790            0x34, 0x6f, 0x4c, 0x39, //  }
2791            0x46, 0x53, 0x54, 0x76, //  }
2792            0x79, 0x36, 0x34, 0x73, //  }
2793            0x41, 0x00, 0x00, 0x00, //  }
2794            0x00, 0x14, 0x00, 0x0b, //     REALM attribute header
2795            0x65, 0x78, 0x61, 0x6d, //  }
2796            0x70, 0x6c, 0x65, 0x2e, //  }  Realm value (11 bytes) and padding (1 byte)
2797            0x6f, 0x72, 0x67, 0x00, //  }
2798            0x00, 0x1d, 0x00, 0x04, //    PASSWORD-ALGORITHM attribute header
2799            0x00, 0x02, 0x00, 0x00, //    PASSWORD-ALGORITHM value (4 bytes)
2800            0x00, 0x1c, 0x00, 0x20, //    MESSAGE-INTEGRITY-SHA256 attribute header
2801            0xb5, 0xc7, 0xbf, 0x00, // }
2802            0x5b, 0x6c, 0x52, 0xa2, // }
2803            0x1c, 0x51, 0xc5, 0xe8, // }
2804            0x92, 0xf8, 0x19, 0x24, // }  HMAC-SHA256 value
2805            0x13, 0x62, 0x96, 0xcb, // }
2806            0x92, 0x7c, 0x43, 0x14, // }
2807            0x93, 0x09, 0x27, 0x8c, // }
2808            0xc6, 0x51, 0x8e, 0x65, // }
2809        ];
2810
2811        let msg = Message::from_bytes(&data).unwrap();
2812        assert!(msg.has_class(MessageClass::Request));
2813        assert!(msg.has_method(BINDING));
2814        assert_eq!(msg.transaction_id(), 0x78ad_3433_c6ad_72c0_29da_412e.into());
2815        let mut builder = Message::builder(
2816            MessageType::from_class_method(MessageClass::Success, BINDING),
2817            msg.transaction_id(),
2818        );
2819
2820        let long_term = LongTermCredentials {
2821            username: "\u{30DE}\u{30C8}\u{30EA}\u{30C3}\u{30AF}\u{30B9}".to_owned(),
2822            password: "The\u{00AD}M\u{00AA}tr\u{2168}".to_owned(),
2823            realm: "example.org".to_owned(),
2824        };
2825        // USERHASH
2826        assert!(msg.has_attribute(Userhash::TYPE));
2827        let raw = msg.raw_attribute(Userhash::TYPE).unwrap();
2828        assert!(matches!(Userhash::try_from(&raw), Ok(_)));
2829        let userhash = Userhash::try_from(&raw).unwrap();
2830        builder.add_attribute(&userhash).unwrap();
2831
2832        // NONCE
2833        let expected_nonce = "obMatJos2AAACf//499k954d6OL34oL9FSTvy64sA";
2834        assert!(msg.has_attribute(Nonce::TYPE));
2835        let raw = msg.raw_attribute(Nonce::TYPE).unwrap();
2836        assert!(matches!(Nonce::try_from(&raw), Ok(_)));
2837        let nonce = Nonce::try_from(&raw).unwrap();
2838        assert_eq!(nonce.nonce(), expected_nonce);
2839        builder.add_attribute(&nonce).unwrap();
2840
2841        // REALM
2842        assert!(msg.has_attribute(Realm::TYPE));
2843        let raw = msg.raw_attribute(Realm::TYPE).unwrap();
2844        assert!(matches!(Realm::try_from(&raw), Ok(_)));
2845        let realm = Realm::try_from(&raw).unwrap();
2846        assert_eq!(realm.realm(), long_term.realm);
2847        builder.add_attribute(&realm).unwrap();
2848
2849        // PASSWORD_ALGORITHM
2850        assert!(msg.has_attribute(PasswordAlgorithm::TYPE));
2851        let raw = msg.raw_attribute(PasswordAlgorithm::TYPE).unwrap();
2852        assert!(matches!(PasswordAlgorithm::try_from(&raw), Ok(_)));
2853        let algo = PasswordAlgorithm::try_from(&raw).unwrap();
2854        assert_eq!(algo.algorithm(), PasswordAlgorithmValue::SHA256);
2855        builder.add_attribute(&algo).unwrap();
2856
2857        // MESSAGE_INTEGRITY_SHA256
2858        /* XXX: the password needs SASLPrep-ing to be useful here
2859        let credentials = MessageIntegrityCredentials::LongTerm(long_term);
2860        assert!(matches!(msg.validate_integrity(&data, &credentials), Ok(())));
2861        */
2862        //builder.add_attribute(msg.raw_attribute(MessageIntegritySha256::TYPE).unwrap()).unwrap();
2863
2864        assert_eq!(builder.build()[4..], data[4..128]);
2865    }
2866}