Skip to main content

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// SPDX-License-Identifier: MIT OR Apache-2.0
10
11//! STUN Messages
12//!
13//! Provides types for generating, parsing, and manipulating STUN messages as specified in one of
14//! [RFC8489], [RFC5389], or [RFC3489].
15//!
16//! Message parsing is zerocopy by default through the [`RawAttribute`] struct. Converting to a
17//! concrete attribute implementation (e.g. [`Software`]) may incur a
18//! copy depending on the attribute implementation.
19//!
20//! The destination for a written Message is completely customizable through the [`MessageWrite`]
21//! trait. It is therefore possible to write directly into network provided buffers for increased
22//! performance and throughput.
23//!
24//! [RFC8489]: https://tools.ietf.org/html/rfc8489
25//! [RFC5389]: https://tools.ietf.org/html/rfc5389
26//! [RFC3489]: https://tools.ietf.org/html/rfc3489
27//!
28//! ## Examples
29//!
30//! ### Parse a STUN [`Message`]
31//!
32//! ```
33//! use stun_types::prelude::*;
34//! use stun_types::attribute::{RawAttribute, PasswordAlgorithm, PasswordAlgorithmValue};
35//! use stun_types::message::{Message, MessageType, MessageClass, BINDING};
36//!
37//! let msg_data = [
38//!     0x00, 0x01, 0x00, 0x08, // method, class and length
39//!     0x21, 0x12, 0xA4, 0x42, // Fixed STUN magic bytes
40//!     0x00, 0x00, 0x00, 0x00, // \
41//!     0x00, 0x00, 0x00, 0x00, // } transaction ID
42//!     0x00, 0x00, 0x73, 0x92, // /
43//!     0x00, 0x1D, 0x00, 0x04, // PasswordAlgorithm attribute header (type and length)
44//!     0x00, 0x02, 0x00, 0x00  // PasswordAlgorithm attribute value
45//! ];
46//! let msg = Message::from_bytes(&msg_data).unwrap();
47//!
48//! // the various parts of a message can be retreived
49//! assert_eq!(msg.get_type(), MessageType::from_class_method(MessageClass::Request, BINDING));
50//! assert_eq!(msg.transaction_id(), 0x7392.into());
51//!
52//! // Attributes can be retrieved as raw values.
53//! let msg_attr = msg.raw_attribute(0x1D.into()).unwrap();
54//! let attr = RawAttribute::new(0x1D.into(), &[0, 2, 0, 0]);
55//! assert_eq!(msg_attr, attr);
56//!
57//! // Or as typed values
58//! let attr = msg.attribute::<PasswordAlgorithm>().unwrap();
59//! assert_eq!(attr.algorithm(), PasswordAlgorithmValue::SHA256);
60//! ```
61//!
62//! ### Generating a [`Message`]
63//!
64//! ```
65//! use stun_types::prelude::*;
66//! use stun_types::attribute::Software;
67//! use stun_types::message::{Message, MessageWriteVec, BINDING};
68//!
69//! // Automatically generates a transaction ID.
70//! let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
71//!
72//! let software_name = "stun-types";
73//! let software = Software::new(software_name).unwrap();
74//! assert_eq!(software.software(), software_name);
75//! msg.add_attribute(&software).unwrap();
76//!
77//! let attribute_data = [
78//!     0x80, 0x22, 0x00, 0x0a, // attribute type (0x8022) and length (0x000a)
79//!     0x73, 0x74, 0x75, 0x6E, // s t u n
80//!     0x2D, 0x74, 0x79, 0x70, // - t y p
81//!     0x65, 0x73, 0x00, 0x00  // e s
82//! ];
83//!
84//! let msg_data = msg.finish();
85//! // ignores the randomly generated transaction id
86//! assert_eq!(msg_data[20..], attribute_data);
87//! ```
88
89#[cfg(feature = "std")]
90use alloc::collections::BTreeMap;
91use alloc::string::String;
92use alloc::sync::Arc;
93use alloc::vec;
94use alloc::vec::Vec;
95use core::convert::TryFrom;
96#[cfg(feature = "std")]
97use std::sync::{Mutex, OnceLock};
98
99use byteorder::{BigEndian, ByteOrder};
100
101use crate::attribute::*;
102
103use tracing::{debug, trace, warn};
104
105use hmac::digest::core_api::CoreWrapper;
106use hmac::digest::CtOutput;
107use hmac::HmacCore;
108
109/// The value of the magic cookie (in network byte order) as specified in RFC5389, and RFC8489.
110pub const MAGIC_COOKIE: u32 = 0x2112A442;
111
112/// The method in a STUN [`Message`]
113#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
114pub struct Method(u16);
115
116impl core::fmt::Display for Method {
117    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
118        write!(f, "{}({:#x}: {})", self.0, self.0, self.name())
119    }
120}
121
122#[cfg(feature = "std")]
123static METHOD_NAME_MAP: OnceLock<Mutex<BTreeMap<Method, &'static str>>> = OnceLock::new();
124
125impl Method {
126    /// Add the name for a particular [`Method`] for formatting purposes.
127    #[cfg(feature = "std")]
128    pub fn add_name(self, name: &'static str) {
129        let mut mnames = METHOD_NAME_MAP
130            .get_or_init(Default::default)
131            .lock()
132            .unwrap();
133        mnames.insert(self, name);
134    }
135
136    /// Create a new [`Method`] from an existing value
137    ///
138    /// Note: the value passed in is not encoded as in a stun message
139    ///
140    /// Panics if the value is out of range (>= 0xf000)
141    ///
142    /// # Examples
143    /// ```
144    /// # use stun_types::message::Method;
145    /// assert_eq!(Method::new(0x123).value(), 0x123);
146    /// ```
147    pub const fn new(val: u16) -> Self {
148        if val >= 0xf000 {
149            panic!("Method value is out of range!");
150        }
151        Self(val)
152    }
153
154    /// Return the integer value of this [`Method`]
155    ///
156    /// Note: the value returned is not encoded as in a stun message
157    ///
158    /// # Examples
159    /// ```
160    /// # use stun_types::message::Method;
161    /// assert_eq!(Method::new(0x123).value(), 0x123);
162    /// ```
163    pub fn value(&self) -> u16 {
164        self.0
165    }
166
167    /// Returns a human readable name of this `Method` or "unknown"
168    ///
169    /// # Examples
170    /// ```
171    /// # use stun_types::attribute::*;
172    /// assert_eq!(XorMappedAddress::TYPE.name(), "XOR-MAPPED-ADDRESS");
173    /// ```
174    pub fn name(self) -> &'static str {
175        match self {
176            BINDING => "BINDING",
177            _ => {
178                #[cfg(feature = "std")]
179                {
180                    let mnames = METHOD_NAME_MAP
181                        .get_or_init(Default::default)
182                        .lock()
183                        .unwrap();
184                    if let Some(name) = mnames.get(&self) {
185                        return name;
186                    }
187                }
188                "unknown"
189            }
190        }
191    }
192}
193
194/// The value of the binding message type.  Can be used in either a request or an indication
195/// message.
196pub const BINDING: Method = Method::new(0x0001);
197
198/// Possible errors when parsing a STUN message.
199#[derive(Debug, thiserror::Error, Clone, Copy, PartialEq, Eq)]
200#[non_exhaustive]
201pub enum StunParseError {
202    /// Not a STUN message.
203    #[error("The provided data is not a STUN message")]
204    NotStun,
205    /// The message has been truncated
206    #[error("Not enough data available to parse the packet, expected {}, actual {}", .expected, .actual)]
207    Truncated {
208        /// The expeced number of bytes
209        expected: usize,
210        /// The encountered number of bytes
211        actual: usize,
212    },
213    /// The message has been truncated
214    #[error("Too many bytes for this data, expected {}, actual {}", .expected, .actual)]
215    TooLarge {
216        /// The expeced number of bytes
217        expected: usize,
218        /// The encountered number of bytes
219        actual: usize,
220    },
221    /// An attribute was not found in the message
222    #[error("Missing attribute {}", .0)]
223    MissingAttribute(AttributeType),
224    /// An attribute was found after the message integrity attribute
225    #[error("An attribute {} was encountered after a message integrity attribute", .0)]
226    AttributeAfterIntegrity(AttributeType),
227    /// An attribute was found after the message integrity attribute
228    #[error("An attribute {} was encountered after a fingerprint attribute", .0)]
229    AttributeAfterFingerprint(AttributeType),
230    /// Fingerprint does not match the data.
231    #[error("Fingerprint does not match")]
232    FingerprintMismatch,
233    /// The provided data does not match the message
234    #[error("The provided data does not match the message")]
235    DataMismatch,
236    /// The attribute contains invalid data
237    #[error("The attribute contains invalid data")]
238    InvalidAttributeData,
239    /// The attribute does not parse this data
240    #[error("Cannot parse with this attribute")]
241    WrongAttributeImplementation,
242}
243
244/// Errors produced when writing a STUN message
245#[derive(Debug, thiserror::Error)]
246#[non_exhaustive]
247pub enum StunWriteError {
248    /// The message already has this attribute
249    #[error("The attribute already exists in the message")]
250    AttributeExists(AttributeType),
251    /// The fingerprint attribute already exists. Cannot write any further attributes
252    #[error("The message already contains a fingerprint attribute")]
253    FingerprintExists,
254    /// A message integrity attribute already exists. Cannot write any further attributes
255    #[error("The message already contains a message intregrity attribute")]
256    MessageIntegrityExists,
257    /// The message has been truncated
258    #[error("Too many bytes for this data, expected {}, actual {}", .expected, .actual)]
259    TooLarge {
260        /// The expeced number of bytes
261        expected: usize,
262        /// The encountered number of bytes
263        actual: usize,
264    },
265    /// The message has been truncated
266    #[error("Not enough data available to parse the packet, expected {}, actual {}", .expected, .actual)]
267    TooSmall {
268        /// The expected number of bytes
269        expected: usize,
270        /// The encountered number of bytes
271        actual: usize,
272    },
273    /// Failed to compute integrity
274    #[error("Failed to compute integrity")]
275    IntegrityFailed,
276    /// Out of range input provided
277    #[error("Out of range input provided")]
278    OutOfRange {
279        /// The value provided.
280        value: usize,
281        /// The minimum allowed value.
282        min: usize,
283        /// The maximum allowed value.
284        max: usize,
285    },
286}
287
288/// Errors produced when validating a STUN message
289#[derive(Debug, thiserror::Error, Copy, Clone)]
290pub enum ValidateError {
291    /// The message failed to parse the relevant integrity attributes.
292    #[error("The message failed to parse the relevant integrity attributes")]
293    Parse(StunParseError),
294    /// The message failed integrity checks.
295    #[error("The message failed integrity checks")]
296    IntegrityFailed,
297}
298
299impl From<StunParseError> for ValidateError {
300    fn from(value: StunParseError) -> Self {
301        Self::Parse(value)
302    }
303}
304
305/// Structure for holding the required credentials for long-term STUN credentials.
306#[derive(Debug, Clone, PartialEq, Eq)]
307#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
308pub struct LongTermCredentials {
309    username: String,
310    password: String,
311}
312
313impl LongTermCredentials {
314    /// Create a new set of [`LongTermCredentials`]
315    ///
316    /// # Examples
317    ///
318    /// ```
319    /// # use stun_types::message::LongTermCredentials;
320    /// let credentials = LongTermCredentials::new(
321    ///     "user".to_string(),
322    ///     "pass".to_string(),
323    /// );
324    /// assert_eq!(credentials.username(), "user");
325    /// assert_eq!(credentials.password(), "pass");
326    /// ```
327    pub fn new(username: String, password: String) -> Self {
328        Self { username, password }
329    }
330
331    /// The configured username
332    pub fn username(&self) -> &str {
333        &self.username
334    }
335
336    /// The configured password
337    pub fn password(&self) -> &str {
338        &self.password
339    }
340
341    /// Construct credentials suitable for signing STUN messages.
342    pub fn to_key(&self, realm: String) -> LongTermKeyCredentials {
343        LongTermKeyCredentials {
344            username: self.username.clone(),
345            password: self.password.clone(),
346            realm,
347        }
348    }
349}
350
351/// Structure for holding the required credentials for signing STUN messages
352#[derive(Debug, Clone, PartialEq, Eq)]
353#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
354pub struct LongTermKeyCredentials {
355    username: String,
356    password: String,
357    realm: String,
358}
359
360impl LongTermKeyCredentials {
361    /// Create a new set of [`LongTermCredentials`]
362    ///
363    /// # Examples
364    ///
365    /// ```
366    /// # use stun_types::message::LongTermKeyCredentials;
367    /// let credentials = LongTermKeyCredentials::new(
368    ///     "user".to_string(),
369    ///     "pass".to_string(),
370    ///     "realm".to_string(),
371    /// );
372    /// assert_eq!(credentials.username(), "user");
373    /// assert_eq!(credentials.password(), "pass");
374    /// assert_eq!(credentials.realm(), "realm");
375    /// ```
376    pub fn new(username: String, password: String, realm: String) -> Self {
377        Self {
378            username,
379            password,
380            realm,
381        }
382    }
383
384    /// The configured username
385    pub fn username(&self) -> &str {
386        &self.username
387    }
388
389    /// The configured password
390    pub fn password(&self) -> &str {
391        &self.password
392    }
393
394    /// The configured realm
395    pub fn realm(&self) -> &str {
396        &self.realm
397    }
398
399    /// Compute a key for caching purposes.
400    pub fn make_key(&self, algorithm: IntegrityAlgorithm) -> IntegrityKey {
401        match algorithm {
402            IntegrityAlgorithm::Sha1 => {
403                use md5::{Digest, Md5};
404                let mut digest = Md5::new();
405                digest.update(self.username.as_bytes());
406                digest.update(":".as_bytes());
407                digest.update(self.realm.as_bytes());
408                digest.update(":".as_bytes());
409                digest.update(self.password.as_bytes());
410                IntegrityKey::new_with_algo(IntegrityAlgorithm::Sha1, digest.finalize().to_vec())
411            }
412            IntegrityAlgorithm::Sha256 => {
413                use sha2::{Digest, Sha256};
414                let mut digest = Sha256::new();
415                digest.update(self.username.as_bytes());
416                digest.update(":".as_bytes());
417                digest.update(self.realm.as_bytes());
418                digest.update(":".as_bytes());
419                digest.update(self.password.as_bytes());
420                IntegrityKey::new_with_algo(IntegrityAlgorithm::Sha256, digest.finalize().to_vec())
421            }
422        }
423    }
424}
425
426/// Structure for holding the required credentials for handling short-term STUN credentials
427#[derive(Debug, Clone, PartialEq, Eq)]
428#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
429pub struct ShortTermCredentials {
430    password: String,
431}
432
433impl ShortTermCredentials {
434    /// Create a new set of [`ShortTermCredentials`]
435    ///
436    /// # Examples
437    ///
438    /// ```
439    /// # use stun_types::message::ShortTermCredentials;
440    /// let credentials = ShortTermCredentials::new("password".to_string());
441    /// assert_eq!(credentials.password(), "password");
442    /// ```
443    pub fn new(password: String) -> Self {
444        Self { password }
445    }
446
447    /// The configured password
448    pub fn password(&self) -> &str {
449        &self.password
450    }
451
452    /// Compute a key for caching purposes.
453    pub fn make_key(&self) -> IntegrityKey {
454        IntegrityKey::new(self.password.as_bytes().to_vec())
455    }
456}
457
458/// Enum for holding the credentials used to sign or verify a [`Message`]
459///
460/// This can either be a set of [`ShortTermCredentials`] or [`LongTermCredentials`]`
461#[derive(Debug, Clone, PartialEq, Eq)]
462#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
463pub enum MessageIntegrityCredentials {
464    /// Short term integrity credentials.
465    ShortTerm(ShortTermCredentials),
466    /// Long term integrity credentials.
467    LongTerm(LongTermKeyCredentials),
468}
469
470impl From<LongTermKeyCredentials> for MessageIntegrityCredentials {
471    fn from(value: LongTermKeyCredentials) -> Self {
472        MessageIntegrityCredentials::LongTerm(value)
473    }
474}
475
476impl From<ShortTermCredentials> for MessageIntegrityCredentials {
477    fn from(value: ShortTermCredentials) -> Self {
478        MessageIntegrityCredentials::ShortTerm(value)
479    }
480}
481
482impl MessageIntegrityCredentials {
483    /// Compute a key for caching purposes.
484    pub fn make_key(&self, algorithm: IntegrityAlgorithm) -> IntegrityKey {
485        match self {
486            MessageIntegrityCredentials::ShortTerm(short) => short.make_key(),
487            MessageIntegrityCredentials::LongTerm(long) => long.make_key(algorithm),
488        }
489    }
490}
491
492type HmacSha1 = hmac::Hmac<sha1::Sha1>;
493type HmacSha256 = hmac::Hmac<sha2::Sha256>;
494
495/// A cached key for a particular set of credentials.
496#[derive(Debug, Clone)]
497pub struct IntegrityKey {
498    key_algorithm: Option<IntegrityAlgorithm>,
499    bytes: Vec<u8>,
500    #[cfg(feature = "std")]
501    sha1: Arc<Mutex<Option<HmacSha1>>>,
502    #[cfg(feature = "std")]
503    sha256: Arc<Mutex<Option<HmacSha256>>>,
504}
505
506impl PartialEq<IntegrityKey> for IntegrityKey {
507    fn eq(&self, other: &Self) -> bool {
508        self.bytes == other.bytes
509    }
510}
511
512impl Eq for IntegrityKey {}
513
514impl IntegrityKey {
515    fn new(bytes: Vec<u8>) -> Self {
516        Self {
517            key_algorithm: None,
518            bytes,
519            #[cfg(feature = "std")]
520            sha1: Default::default(),
521            #[cfg(feature = "std")]
522            sha256: Default::default(),
523        }
524    }
525    fn new_with_algo(key_algorithm: IntegrityAlgorithm, bytes: Vec<u8>) -> Self {
526        let mut ret = Self::new(bytes);
527        ret.key_algorithm = Some(key_algorithm);
528        ret
529    }
530    pub(crate) fn as_bytes(&self) -> &[u8] {
531        &self.bytes
532    }
533
534    pub(crate) fn verify_sha1(&self, data: &[&[u8]], expected: &[u8]) -> bool {
535        if self
536            .key_algorithm
537            .is_some_and(|algo| algo != IntegrityAlgorithm::Sha1)
538        {
539            return false;
540        }
541        use hmac::digest::Output;
542        let computed = self.compute_sha1(data);
543        // FIXME: ignore deprecation due to needing to update to generic-array 1.x
544        #[allow(deprecated)]
545        {
546            computed == Output::<sha1::Sha1Core>::from_slice(expected).into()
547        }
548    }
549
550    pub(crate) fn compute_sha1(
551        &self,
552        data: &[&[u8]],
553    ) -> CtOutput<CoreWrapper<HmacCore<CoreWrapper<sha1::Sha1Core>>>> {
554        use hmac::Mac;
555        #[cfg(feature = "std")]
556        let mut sha1 = self.sha1.lock().unwrap();
557        #[cfg(feature = "std")]
558        let hmac = sha1.get_or_insert_with(|| HmacSha1::new_from_slice(self.as_bytes()).unwrap());
559        #[cfg(not(feature = "std"))]
560        let mut hmac = HmacSha1::new_from_slice(self.as_bytes()).unwrap();
561
562        for data in data {
563            hmac.update(data);
564        }
565        #[cfg(feature = "std")]
566        let ret = hmac.finalize_reset();
567        #[cfg(not(feature = "std"))]
568        let ret = hmac.finalize();
569        ret
570    }
571
572    pub(crate) fn verify_sha256(&self, data: &[&[u8]], expected: &[u8]) -> bool {
573        use subtle::ConstantTimeEq;
574        if self
575            .key_algorithm
576            .is_some_and(|algo| algo != IntegrityAlgorithm::Sha256)
577        {
578            return false;
579        }
580        if expected.is_empty() {
581            return false;
582        }
583        let computed = self.compute_sha256(data);
584        if computed.len() < expected.len() {
585            return false;
586        }
587        computed[..expected.len()].ct_eq(expected).into()
588    }
589
590    pub(crate) fn compute_sha256(&self, data: &[&[u8]]) -> [u8; 32] {
591        trace!("computing sha256 using {data:?}");
592        use hmac::Mac;
593        #[cfg(feature = "std")]
594        let mut sha256 = self.sha256.lock().unwrap();
595        #[cfg(feature = "std")]
596        let hmac =
597            sha256.get_or_insert_with(|| HmacSha256::new_from_slice(self.as_bytes()).unwrap());
598        #[cfg(not(feature = "std"))]
599        let mut hmac = HmacSha256::new_from_slice(self.as_bytes()).unwrap();
600
601        for data in data {
602            hmac.update(data);
603        }
604        #[cfg(feature = "std")]
605        let ret = hmac.finalize_reset();
606        #[cfg(not(feature = "std"))]
607        let ret = hmac.finalize();
608        ret.into_bytes().into()
609    }
610}
611
612/// The class of a [`Message`].
613///
614/// There are four classes of [`Message`]s within the STUN protocol:
615///
616///  - [Request][`MessageClass::Request`] indicates that a request is being made and a
617///    response is expected.
618///  - An [Indication][`MessageClass::Indication`] is a fire and forget [`Message`] where
619///    no response is required or expected.
620///  - [Success][`MessageClass::Success`] indicates that a [Request][`MessageClass::Request`]
621///    was successfully handled and the
622///  - [Error][`MessageClass::Error`] class indicates that an error was produced.
623#[derive(Copy, Clone, Debug, PartialEq, Eq)]
624pub enum MessageClass {
625    /// A request that is expecting a response of either Success, or Error.
626    Request,
627    /// A request that does not expect a response.
628    Indication,
629    /// A success response to a previous Request.
630    Success,
631    /// An error response to a previous Request.
632    Error,
633}
634
635impl MessageClass {
636    /// Returns whether this [`MessageClass`] is of a response type.  i.e. is either
637    /// [`MessageClass::Success`] or [`MessageClass::Error`].
638    pub fn is_response(self) -> bool {
639        matches!(self, MessageClass::Success | MessageClass::Error)
640    }
641
642    fn to_bits(self) -> u16 {
643        match self {
644            MessageClass::Request => 0x000,
645            MessageClass::Indication => 0x010,
646            MessageClass::Success => 0x100,
647            MessageClass::Error => 0x110,
648        }
649    }
650}
651
652/// The type of a [`Message`].  A combination of a [`MessageClass`] and a STUN method.
653#[derive(Copy, Clone, Debug, PartialEq, Eq)]
654pub struct MessageType(u16);
655
656impl core::fmt::Display for MessageType {
657    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
658        write!(
659            f,
660            "MessageType(class: {:?}, method: {}",
661            self.class(),
662            self.method(),
663        )
664    }
665}
666
667impl MessageType {
668    /// Create a new [`MessageType`] from the provided [`MessageClass`] and method
669    ///
670    /// # Examples
671    ///
672    /// ```
673    /// # use stun_types::message::{MessageType, MessageClass, BINDING};
674    /// let mtype = MessageType::from_class_method(MessageClass::Indication, BINDING);
675    /// assert_eq!(mtype.has_class(MessageClass::Indication), true);
676    /// assert_eq!(mtype.has_method(BINDING), true);
677    /// ```
678    pub fn from_class_method(class: MessageClass, method: Method) -> Self {
679        let class_bits = MessageClass::to_bits(class);
680        let method = method.value();
681        let method_bits = method & 0xf | (method & 0x70) << 1 | (method & 0xf80) << 2;
682        // trace!("MessageType from class {:?} and method {:?} into {:?}", class, method,
683        //     class_bits | method_bits);
684        Self(class_bits | method_bits)
685    }
686
687    /// Retrieves the class of a [`MessageType`]
688    ///
689    /// # Examples
690    ///
691    /// ```
692    /// # use stun_types::message::{MessageType, MessageClass, BINDING};
693    /// let mtype = MessageType::from_class_method(MessageClass::Indication, BINDING);
694    /// assert_eq!(mtype.class(), MessageClass::Indication);
695    /// ```
696    pub fn class(self) -> MessageClass {
697        let class = (self.0 & 0x10) >> 4 | (self.0 & 0x100) >> 7;
698        match class {
699            0x0 => MessageClass::Request,
700            0x1 => MessageClass::Indication,
701            0x2 => MessageClass::Success,
702            0x3 => MessageClass::Error,
703            _ => unreachable!(),
704        }
705    }
706
707    /// Returns whether class of a [`MessageType`] is equal to the provided [`MessageClass`]
708    ///
709    /// # Examples
710    ///
711    /// ```
712    /// # use stun_types::message::{MessageType, MessageClass, BINDING};
713    /// let mtype = MessageType::from_class_method(MessageClass::Indication, BINDING);
714    /// assert!(mtype.has_class(MessageClass::Indication));
715    /// ```
716    pub fn has_class(self, cls: MessageClass) -> bool {
717        self.class() == cls
718    }
719
720    /// Returns whether the class of a [`MessageType`] indicates a response [`Message`]
721    ///
722    /// # Examples
723    ///
724    /// ```
725    /// # use stun_types::message::{MessageType, MessageClass, BINDING};
726    /// assert_eq!(MessageType::from_class_method(MessageClass::Indication, BINDING)
727    ///     .is_response(), false);
728    /// assert_eq!(MessageType::from_class_method(MessageClass::Request, BINDING)
729    ///     .is_response(), false);
730    /// assert_eq!(MessageType::from_class_method(MessageClass::Success, BINDING)
731    ///     .is_response(), true);
732    /// assert_eq!(MessageType::from_class_method(MessageClass::Error, BINDING)
733    ///     .is_response(), true);
734    /// ```
735    pub fn is_response(self) -> bool {
736        self.class().is_response()
737    }
738
739    /// Returns the method of a [`MessageType`]
740    ///
741    /// # Examples
742    ///
743    /// ```
744    /// # use stun_types::message::{MessageType, MessageClass, BINDING};
745    /// let mtype = MessageType::from_class_method(MessageClass::Indication, BINDING);
746    /// assert_eq!(mtype.method(), BINDING);
747    /// ```
748    pub fn method(self) -> Method {
749        Method::new(self.0 & 0xf | (self.0 & 0xe0) >> 1 | (self.0 & 0x3e00) >> 2)
750    }
751
752    /// Returns whether the method of a [`MessageType`] is equal to the provided value
753    ///
754    /// # Examples
755    ///
756    /// ```
757    /// # use stun_types::message::{MessageType, MessageClass, BINDING};
758    /// let mtype = MessageType::from_class_method(MessageClass::Indication, BINDING);
759    /// assert_eq!(mtype.has_method(BINDING), true);
760    /// ```
761    pub fn has_method(self, method: Method) -> bool {
762        self.method() == method
763    }
764
765    /// Convert a [`MessageType`] to network bytes
766    pub fn write_into(&self, dest: &mut [u8]) {
767        BigEndian::write_u16(dest, self.0);
768    }
769
770    /// Convert a [`MessageType`] to network bytes
771    pub fn to_bytes(self) -> Vec<u8> {
772        let mut ret = vec![0; 2];
773        BigEndian::write_u16(&mut ret[0..2], self.0);
774        ret
775    }
776
777    /// Convert a set of network bytes into a [`MessageType`] or return an error
778    pub fn from_bytes(data: &[u8]) -> Result<Self, StunParseError> {
779        let data = BigEndian::read_u16(data);
780        if data & 0xc000 != 0x0 {
781            /* not a stun packet */
782            return Err(StunParseError::NotStun);
783        }
784        Ok(Self(data))
785    }
786}
787impl TryFrom<&[u8]> for MessageType {
788    type Error = StunParseError;
789
790    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
791        MessageType::from_bytes(value)
792    }
793}
794
795/// A unique transaction identifier for each message and it's (possible) response.
796#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
797pub struct TransactionId {
798    id: u128,
799}
800
801impl TransactionId {
802    /// Generate a new STUN transaction identifier.
803    pub fn generate() -> TransactionId {
804        #[cfg(not(feature = "std"))]
805        {
806            use rand::TryRngCore;
807            let mut dest = [0; 16];
808            rand::rngs::OsRng
809                .try_fill_bytes(&mut dest)
810                .expect("Cannot generate random data");
811            u128::from_be_bytes(dest).into()
812        }
813        #[cfg(feature = "std")]
814        {
815            use rand::Rng;
816            let mut rng = rand::rng();
817            rng.random::<u128>().into()
818        }
819    }
820}
821
822impl From<u128> for TransactionId {
823    fn from(id: u128) -> Self {
824        Self {
825            id: id & 0xffff_ffff_ffff_ffff_ffff_ffff,
826        }
827    }
828}
829impl From<TransactionId> for u128 {
830    fn from(id: TransactionId) -> Self {
831        id.id
832    }
833}
834impl core::fmt::Display for TransactionId {
835    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
836        write!(f, "{:#x}", self.id)
837    }
838}
839
840/// The fixed length header of a STUN message.  Allows reading the message header for a quick
841/// check if this message is a valid STUN message.  Can also be used to expose the length of the
842/// complete message without needing to receive the entire message.
843#[derive(Debug)]
844pub struct MessageHeader {
845    mtype: MessageType,
846    transaction_id: TransactionId,
847    length: u16,
848}
849
850impl MessageHeader {
851    /// The length of the STUN message header.
852    pub const LENGTH: usize = 20;
853
854    /// Deserialize a `MessageHeader`
855    ///
856    /// # Examples
857    ///
858    /// ```
859    /// # use stun_types::message::{MessageHeader, MessageType, MessageClass, BINDING};
860    /// let msg_data = [0, 1, 0, 8, 33, 18, 164, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 232];
861    /// let message = MessageHeader::from_bytes(&msg_data).unwrap();
862    /// assert_eq!(message.get_type(), MessageType::from_class_method(MessageClass::Request, BINDING));
863    /// assert_eq!(message.transaction_id(), 1000.into());
864    /// assert_eq!(message.data_length(), 8);
865    /// ```
866    pub fn from_bytes(data: &[u8]) -> Result<Self, StunParseError> {
867        if data.len() < 20 {
868            return Err(StunParseError::Truncated {
869                expected: 20,
870                actual: data.len(),
871            });
872        }
873        let mtype = MessageType::from_bytes(data)?;
874        let mlength = BigEndian::read_u16(&data[2..]);
875        let tid = BigEndian::read_u128(&data[4..]);
876        let cookie = (tid >> 96) as u32;
877        if cookie != MAGIC_COOKIE {
878            warn!(
879                "malformed cookie constant {:?} != stored data {:?}",
880                MAGIC_COOKIE, cookie
881            );
882            return Err(StunParseError::NotStun);
883        }
884
885        Ok(Self {
886            mtype,
887            transaction_id: tid.into(),
888            length: mlength,
889        })
890    }
891
892    /// The number of bytes of content in this [`MessageHeader`]. Adding both `data_length()`
893    /// and [`MessageHeader::LENGTH`] will result in the size of the complete STUN message.
894    pub fn data_length(&self) -> u16 {
895        self.length
896    }
897
898    /// The [`TransactionId`] of this [`MessageHeader`]
899    pub fn transaction_id(&self) -> TransactionId {
900        self.transaction_id
901    }
902
903    /// The [`MessageType`] of this [`MessageHeader`]
904    pub fn get_type(&self) -> MessageType {
905        self.mtype
906    }
907
908    fn new(mtype: MessageType, transaction_id: TransactionId, length: u16) -> Self {
909        Self {
910            mtype,
911            transaction_id,
912            length,
913        }
914    }
915
916    fn write_into(&self, dest: &mut [u8]) {
917        self.mtype.write_into(&mut dest[..2]);
918        let transaction: u128 = self.transaction_id.into();
919        let tid = (MAGIC_COOKIE as u128) << 96 | transaction & 0xffff_ffff_ffff_ffff_ffff_ffff;
920        BigEndian::write_u128(&mut dest[4..20], tid);
921        BigEndian::write_u16(&mut dest[2..4], self.length);
922    }
923}
924
925/// The structure that encapsulates the entirety of a STUN message
926///
927/// Contains the [`MessageType`], a transaction ID, and a list of STUN
928/// [`Attribute`]
929#[derive(Debug, Clone, Copy)]
930pub struct Message<'a> {
931    data: &'a [u8],
932}
933
934impl core::fmt::Display for Message<'_> {
935    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
936        write!(
937            f,
938            "Message(class: {:?}, method: {}, transaction: {}, attributes: ",
939            self.get_type().class(),
940            self.get_type().method(),
941            self.transaction_id()
942        )?;
943        let iter = self.iter_attributes();
944        write!(f, "[")?;
945        for (i, (_offset, a)) in iter.enumerate() {
946            if i > 0 {
947                write!(f, ", ")?;
948            }
949            write!(f, "{a}")?;
950        }
951        write!(f, "]")?;
952        write!(f, ")")
953    }
954}
955
956/// The supported hashing algorithms for ensuring integrity of a [`Message`]
957#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
958pub enum IntegrityAlgorithm {
959    /// SHA-1 algorithm
960    Sha1,
961    /// SHA-256 algorithm
962    Sha256,
963}
964
965impl<'a> Message<'a> {
966    /// Create a new [`Message`] with the provided [`MessageType`] and transaction ID
967    ///
968    /// Note you probably want to use one of the other helper constructors instead.
969    ///
970    /// # Examples
971    ///
972    /// ```
973    /// # use stun_types::message::{Message, MessageType, MessageClass, MessageWriteVec,
974    /// #     MessageWrite, BINDING};
975    /// let mtype = MessageType::from_class_method(MessageClass::Indication, BINDING);
976    /// let message = Message::builder(mtype, 0.into(), MessageWriteVec::new()).finish();
977    /// let message = Message::from_bytes(&message).unwrap();
978    /// assert!(message.has_class(MessageClass::Indication));
979    /// assert!(message.has_method(BINDING));
980    /// ```
981    pub fn builder<B: MessageWrite>(
982        mtype: MessageType,
983        transaction_id: TransactionId,
984        mut write: B,
985    ) -> B {
986        let mut data = [0; 20];
987        MessageHeader::new(mtype, transaction_id, 0).write_into(&mut data);
988        write.push_data(&data);
989        write
990    }
991
992    /// Create a new request [`Message`] of the provided method
993    ///
994    /// # Examples
995    ///
996    /// ```
997    /// # use stun_types::message::{Message, MessageType, MessageClass, MessageWriteVec,
998    /// #     MessageWrite, BINDING};
999    /// let message = Message::builder_request(BINDING, MessageWriteVec::new());
1000    /// let data = message.finish();
1001    /// let message = Message::from_bytes(&data).unwrap();
1002    /// assert!(message.has_class(MessageClass::Request));
1003    /// assert!(message.has_method(BINDING));
1004    /// ```
1005    pub fn builder_request<B: MessageWrite>(method: Method, write: B) -> B {
1006        Message::builder(
1007            MessageType::from_class_method(MessageClass::Request, method),
1008            TransactionId::generate(),
1009            write,
1010        )
1011    }
1012
1013    /// Create a new success [`Message`] response from the provided request
1014    ///
1015    /// # Panics
1016    ///
1017    /// When a non-request [`Message`] is passed as the original input [`Message`]
1018    ///
1019    /// # Examples
1020    ///
1021    /// ```
1022    /// # use stun_types::message::{Message, MessageType, MessageClass, MessageWriteVec,
1023    /// #      MessageWrite, BINDING};
1024    /// let message = Message::builder_request(BINDING, MessageWriteVec::new());
1025    /// let data = message.finish();
1026    /// let message = Message::from_bytes(&data).unwrap();
1027    /// let success = Message::builder_success(&message, MessageWriteVec::new()).finish();
1028    /// let success = Message::from_bytes(&success).unwrap();
1029    /// assert!(success.has_class(MessageClass::Success));
1030    /// assert!(success.has_method(BINDING));
1031    /// ```
1032    pub fn builder_success<B: MessageWrite>(orig: &Message, write: B) -> B {
1033        if !orig.has_class(MessageClass::Request) {
1034            panic!(
1035                "A success response message was attempted to be created from a non-request message"
1036            );
1037        }
1038        Message::builder(
1039            MessageType::from_class_method(MessageClass::Success, orig.method()),
1040            orig.transaction_id(),
1041            write,
1042        )
1043    }
1044
1045    /// Create a new error [`Message`] response from the provided request
1046    ///
1047    /// # Panics
1048    ///
1049    /// When a non-request [`Message`] is passed as the original input [`Message`]
1050    ///
1051    /// # Examples
1052    ///
1053    /// ```
1054    /// # use stun_types::message::{Message, MessageType, MessageClass, MessageWriteVec,
1055    /// #     MessageWrite, BINDING};
1056    /// let message = Message::builder_request(BINDING, MessageWriteVec::new());
1057    /// let data = message.finish();
1058    /// let message = Message::from_bytes(&data).unwrap();
1059    /// let error = Message::builder_error(&message, MessageWriteVec::new()).finish();
1060    /// let error = Message::from_bytes(&error).unwrap();
1061    /// assert!(error.has_class(MessageClass::Error));
1062    /// assert!(error.has_method(BINDING));
1063    /// ```
1064    pub fn builder_error<B: MessageWrite>(orig: &Message, write: B) -> B {
1065        if !orig.has_class(MessageClass::Request) {
1066            panic!(
1067                "An error response message was attempted to be created from a non-request message"
1068            );
1069        }
1070        Message::builder(
1071            MessageType::from_class_method(MessageClass::Error, orig.method()),
1072            orig.transaction_id(),
1073            write,
1074        )
1075    }
1076
1077    /// Create a new indication [`Message`] of the provided method.
1078    ///
1079    /// # Examples
1080    ///
1081    /// ```
1082    /// # use stun_types::message::{Message, MessageType, MessageClass, MessageWriteVec,
1083    /// #     MessageWrite, BINDING};
1084    /// let message = Message::builder_indication(BINDING, MessageWriteVec::new());
1085    /// let data = message.finish();
1086    /// let message = Message::from_bytes(&data).unwrap();
1087    /// assert!(message.has_class(MessageClass::Indication));
1088    /// assert!(message.has_method(BINDING));
1089    /// ```
1090    pub fn builder_indication<B: MessageWrite>(method: Method, write: B) -> B {
1091        Message::builder(
1092            MessageType::from_class_method(MessageClass::Indication, method),
1093            TransactionId::generate(),
1094            write,
1095        )
1096    }
1097
1098    /// Retrieve the [`MessageType`] of a [`Message`]
1099    ///
1100    /// # Examples
1101    ///
1102    /// ```
1103    /// # use stun_types::message::{Message, MessageType, MessageClass, MessageWriteVec,
1104    /// #     MessageWrite, BINDING};
1105    /// let message = Message::builder_request(BINDING, MessageWriteVec::new());
1106    /// let data = message.finish();
1107    /// let message = Message::from_bytes(&data).unwrap();
1108    /// assert!(message.get_type().has_class(MessageClass::Request));
1109    /// assert!(message.get_type().has_method(BINDING));
1110    /// ```
1111    pub fn get_type(&self) -> MessageType {
1112        MessageType::try_from(&self.data[..2]).unwrap()
1113    }
1114
1115    /// Retrieve the [`MessageClass`] of a [`Message`]
1116    ///
1117    /// # Examples
1118    ///
1119    /// ```
1120    /// # use stun_types::message::{Message, MessageType, MessageClass, MessageWriteVec,
1121    /// #     MessageWrite, BINDING};
1122    /// let message = Message::builder_request(BINDING, MessageWriteVec::new()).finish();
1123    /// let message = Message::from_bytes(&message).unwrap();
1124    /// assert_eq!(message.class(), MessageClass::Request);
1125    /// ```
1126    pub fn class(&self) -> MessageClass {
1127        self.get_type().class()
1128    }
1129
1130    /// Returns whether the [`Message`] is of the specified [`MessageClass`]
1131    ///
1132    /// # Examples
1133    ///
1134    /// ```
1135    /// # use stun_types::message::{Message, MessageType, MessageClass, MessageWriteVec,
1136    /// #     MessageWrite, BINDING};
1137    /// let message = Message::builder_request(BINDING, MessageWriteVec::new()).finish();
1138    /// let message = Message::from_bytes(&message).unwrap();
1139    /// assert!(message.has_class(MessageClass::Request));
1140    /// ```
1141    pub fn has_class(&self, cls: MessageClass) -> bool {
1142        self.class() == cls
1143    }
1144
1145    /// Returns whether the [`Message`] is a response
1146    ///
1147    /// This means that the [`Message`] has a class of either success or error
1148    ///
1149    /// # Examples
1150    ///
1151    /// ```
1152    /// # use stun_types::message::{Message, MessageType, MessageClass, MessageWriteVec,
1153    /// #     MessageWrite, BINDING};
1154    /// let message = Message::builder_request(BINDING, MessageWriteVec::new()).finish();
1155    /// let message = Message::from_bytes(&message).unwrap();
1156    /// assert_eq!(message.is_response(), false);
1157    ///
1158    /// let error = Message::builder_error(&message, MessageWriteVec::new()).finish();
1159    /// let error = Message::from_bytes(&error).unwrap();
1160    /// assert_eq!(error.is_response(), true);
1161    ///
1162    /// let success = Message::builder_success(&message, MessageWriteVec::new()).finish();
1163    /// let success = Message::from_bytes(&success).unwrap();
1164    /// assert_eq!(success.is_response(), true);
1165    /// ```
1166    pub fn is_response(&self) -> bool {
1167        self.class().is_response()
1168    }
1169
1170    /// Retrieves the method of the [`Message`]
1171    ///
1172    /// # Examples
1173    ///
1174    /// ```
1175    /// # use stun_types::message::{Message, MessageType, MessageClass, MessageWriteVec,
1176    /// #     MessageWrite, BINDING};
1177    /// let message = Message::builder_request(BINDING, MessageWriteVec::new()).finish();
1178    /// let message = Message::from_bytes(&message).unwrap();
1179    /// assert_eq!(message.method(), BINDING);
1180    /// ```
1181    pub fn method(&self) -> Method {
1182        self.get_type().method()
1183    }
1184
1185    /// Returns whether the [`Message`] is of the specified method
1186    ///
1187    /// # Examples
1188    ///
1189    /// ```
1190    /// # use stun_types::message::{Message, MessageType, MessageClass, MessageWriteVec,
1191    /// #     Method, MessageWrite, BINDING};
1192    /// let message = Message::builder_request(BINDING, MessageWriteVec::new()).finish();
1193    /// let message = Message::from_bytes(&message).unwrap();
1194    /// assert!(message.has_method(BINDING));
1195    /// assert!(!message.has_method(Method::new(0)));
1196    /// ```
1197    pub fn has_method(&self, method: Method) -> bool {
1198        self.method() == method
1199    }
1200
1201    /// Retrieves the 96-bit transaction ID of the [`Message`]
1202    ///
1203    /// # Examples
1204    ///
1205    /// ```
1206    /// # use stun_types::message::{Message, MessageType, MessageClass, MessageWriteVec,
1207    /// #     MessageWrite, BINDING, TransactionId};
1208    /// let mtype = MessageType::from_class_method(MessageClass::Request, BINDING);
1209    /// let transaction_id = TransactionId::generate();
1210    /// let message = Message::builder(mtype, transaction_id, MessageWriteVec::new()).finish();
1211    /// let message = Message::from_bytes(&message).unwrap();
1212    /// assert_eq!(message.transaction_id(), transaction_id);
1213    /// ```
1214    pub fn transaction_id(&self) -> TransactionId {
1215        BigEndian::read_u128(&self.data[4..]).into()
1216    }
1217
1218    /// Deserialize a `Message` from its network bytes.
1219    ///
1220    /// This function will ensure that any fingerprint contained within matches the message
1221    /// contents and return errors on failure.
1222    ///
1223    /// Any message integrity value (as required by the STUN usage) should be checked in addition
1224    /// by calling [`Message::validate_integrity`].
1225    ///
1226    /// # Examples
1227    ///
1228    /// ```
1229    /// # use stun_types::attribute::{RawAttribute, Attribute};
1230    /// # use stun_types::message::{Message, MessageType, MessageClass, BINDING};
1231    /// let msg_data = [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];
1232    /// let message = Message::from_bytes(&msg_data).unwrap();
1233    /// let attr = RawAttribute::new(1.into(), &[3]);
1234    /// let msg_attr = message.raw_attribute(1.into()).unwrap();
1235    /// assert_eq!(msg_attr, attr);
1236    /// assert_eq!(message.get_type(), MessageType::from_class_method(MessageClass::Request, BINDING));
1237    /// assert_eq!(message.transaction_id(), 1000.into());
1238    /// ```
1239    #[tracing::instrument(
1240        name = "message_from_bytes",
1241        level = "trace",
1242        skip(data),
1243        fields(
1244            data.len = data.len()
1245        )
1246    )]
1247    pub fn from_bytes(data: &'a [u8]) -> Result<Self, StunParseError> {
1248        let orig_data = data;
1249
1250        let header = MessageHeader::from_bytes(data)?;
1251        let mlength = header.data_length() as usize;
1252        if mlength + MessageHeader::LENGTH > data.len() {
1253            // mlength + header
1254            warn!(
1255                "malformed advertised size {} and data size {} don't match",
1256                mlength + 20,
1257                data.len()
1258            );
1259            return Err(StunParseError::Truncated {
1260                expected: mlength + MessageHeader::LENGTH,
1261                actual: data.len(),
1262            });
1263        }
1264
1265        let ending_attributes = [
1266            MessageIntegrity::TYPE,
1267            MessageIntegritySha256::TYPE,
1268            Fingerprint::TYPE,
1269        ];
1270        // XXX: maybe use small/tinyvec?
1271        let mut seen_ending_attributes = [AttributeType::new(0); 3];
1272        let mut seen_ending_len = 0;
1273        let mut data_offset = MessageHeader::LENGTH;
1274        for attr in MessageRawAttributesIter::new(data) {
1275            let (_offset, attr) = attr.inspect_err(|e| {
1276                warn!("failed to parse message attribute at offset {data_offset}: {e}",);
1277            })?;
1278
1279            // if we have seen any ending attributes, then there is only a fixed set of attributes
1280            // that are allowed.
1281            if seen_ending_len > 0 && !ending_attributes.contains(&attr.get_type()) {
1282                if seen_ending_attributes.contains(&Fingerprint::TYPE) {
1283                    warn!("unexpected attribute {} after FINGERPRINT", attr.get_type());
1284                    return Ok(Message { data: orig_data });
1285                } else {
1286                    // only attribute valid after MESSAGE_INTEGRITY is FINGERPRINT
1287                    warn!(
1288                        "unexpected attribute {} after MESSAGE_INTEGRITY",
1289                        attr.get_type()
1290                    );
1291                    return Ok(Message { data: orig_data });
1292                }
1293            }
1294
1295            if ending_attributes.contains(&attr.get_type()) {
1296                if seen_ending_attributes.contains(&attr.get_type()) {
1297                    if seen_ending_attributes.contains(&Fingerprint::TYPE) {
1298                        warn!("unexpected attribute {} after FINGERPRINT", attr.get_type());
1299                        return Ok(Message { data: orig_data });
1300                    } else {
1301                        // only attribute valid after MESSAGE_INTEGRITY is FINGERPRINT
1302                        warn!(
1303                            "unexpected attribute {} after MESSAGE_INTEGRITY",
1304                            attr.get_type()
1305                        );
1306                        return Ok(Message { data: orig_data });
1307                    }
1308                } else {
1309                    seen_ending_attributes[seen_ending_len] = attr.get_type();
1310                    seen_ending_len += 1;
1311                    // need credentials to validate the integrity of the message
1312                }
1313            }
1314            let padded_len = attr.padded_len();
1315            if attr.get_type() == Fingerprint::TYPE {
1316                let f = Fingerprint::from_raw_ref(&attr)?;
1317                let msg_fingerprint = f.fingerprint();
1318                let mut header = [0; 4];
1319                header[0] = orig_data[0];
1320                header[1] = orig_data[1];
1321                BigEndian::write_u16(
1322                    &mut header[2..4],
1323                    (data_offset + padded_len - MessageHeader::LENGTH) as u16,
1324                );
1325                let fingerprint_data = &orig_data[4..data_offset];
1326                let calculated_fingerprint = Fingerprint::compute(&[&header, fingerprint_data]);
1327                if &calculated_fingerprint != msg_fingerprint {
1328                    warn!(
1329                        "fingerprint mismatch {:?} != {:?}",
1330                        calculated_fingerprint, msg_fingerprint
1331                    );
1332                    return Err(StunParseError::FingerprintMismatch);
1333                }
1334            }
1335            data_offset += padded_len;
1336        }
1337        Ok(Message { data: orig_data })
1338    }
1339
1340    /// Validates the MESSAGE_INTEGRITY attribute with the provided credentials
1341    ///
1342    /// The Original data that was used to construct this [`Message`] must be provided in order
1343    /// to successfully validate the [`Message`]
1344    ///
1345    /// # Examples
1346    ///
1347    /// ```
1348    /// # use stun_types::message::{Message, MessageType, MessageClass, MessageWriteVec,
1349    /// #     MessageWrite, MessageWriteExt, BINDING, MessageIntegrityCredentials,
1350    /// #     LongTermKeyCredentials, IntegrityAlgorithm};
1351    /// let mut message = Message::builder_request(BINDING, MessageWriteVec::new());
1352    /// let credentials = LongTermKeyCredentials::new(
1353    ///     "user".to_owned(),
1354    ///     "pass".to_owned(),
1355    ///     "realm".to_owned()
1356    /// ).into();
1357    /// assert!(message.add_message_integrity(&credentials, IntegrityAlgorithm::Sha256).is_ok());
1358    /// let data = message.finish();
1359    /// let message = Message::from_bytes(&data).unwrap();
1360    /// assert!(message.validate_integrity(&credentials).is_ok());
1361    /// ```
1362    pub fn validate_integrity(
1363        &self,
1364        credentials: &MessageIntegrityCredentials,
1365    ) -> Result<IntegrityAlgorithm, ValidateError> {
1366        let raw_sha1 = self.raw_attribute(MessageIntegrity::TYPE);
1367        let raw_sha256 = self.raw_attribute(MessageIntegritySha256::TYPE);
1368        let (algo, msg_hmac) = match (raw_sha1, raw_sha256) {
1369            (_, Some(sha256)) => {
1370                let integrity = MessageIntegritySha256::try_from(&sha256)?;
1371                (IntegrityAlgorithm::Sha256, integrity.hmac().to_vec())
1372            }
1373            (Some(sha1), None) => {
1374                let integrity = MessageIntegrity::try_from(&sha1)?;
1375                (IntegrityAlgorithm::Sha1, integrity.hmac().to_vec())
1376            }
1377            (None, None) => {
1378                return Err(StunParseError::MissingAttribute(MessageIntegrity::TYPE).into())
1379            }
1380        };
1381        let key = credentials.make_key(algo);
1382        self.validate_integrity_with_hmac(algo, &msg_hmac, &key)
1383    }
1384
1385    /// Validates the MESSAGE_INTEGRITY attribute with the provided credentials key.
1386    pub fn validate_integrity_with_key(
1387        &self,
1388        key: &IntegrityKey,
1389    ) -> Result<IntegrityAlgorithm, ValidateError> {
1390        let raw_sha1 = self.raw_attribute(MessageIntegrity::TYPE);
1391        let raw_sha256 = self.raw_attribute(MessageIntegritySha256::TYPE);
1392        let (algo, msg_hmac) = if let Some(algo) = key.key_algorithm {
1393            match (algo, raw_sha1, raw_sha256) {
1394                (IntegrityAlgorithm::Sha256, _, Some(sha256)) => {
1395                    let integrity = MessageIntegritySha256::try_from(&sha256)?;
1396                    (algo, integrity.hmac().to_vec())
1397                }
1398                (IntegrityAlgorithm::Sha1, Some(sha1), _) => {
1399                    let integrity = MessageIntegrity::try_from(&sha1)?;
1400                    (algo, integrity.hmac().to_vec())
1401                }
1402                _ => return Err(StunParseError::MissingAttribute(MessageIntegrity::TYPE).into()),
1403            }
1404        } else {
1405            match (raw_sha1, raw_sha256) {
1406                (_, Some(sha256)) => {
1407                    let integrity = MessageIntegritySha256::try_from(&sha256)?;
1408                    (IntegrityAlgorithm::Sha256, integrity.hmac().to_vec())
1409                }
1410                (Some(sha1), None) => {
1411                    let integrity = MessageIntegrity::try_from(&sha1)?;
1412                    (IntegrityAlgorithm::Sha1, integrity.hmac().to_vec())
1413                }
1414                (None, None) => {
1415                    return Err(StunParseError::MissingAttribute(MessageIntegrity::TYPE).into())
1416                }
1417            }
1418        };
1419        self.validate_integrity_with_hmac(algo, &msg_hmac, key)
1420    }
1421
1422    #[tracing::instrument(
1423        name = "message_validate_integrity_with_hmac",
1424        level = "trace",
1425        skip(self, key, msg_hmac),
1426        fields(
1427            msg.transaction = %self.transaction_id(),
1428        )
1429    )]
1430    fn validate_integrity_with_hmac(
1431        &self,
1432        algo: IntegrityAlgorithm,
1433        msg_hmac: &[u8],
1434        key: &IntegrityKey,
1435    ) -> Result<IntegrityAlgorithm, ValidateError> {
1436        if key.key_algorithm.is_some_and(|key_algo| key_algo != algo) {
1437            debug!(
1438                "Key algorithm ({:?}) does not match algo ({algo:?})",
1439                key.key_algorithm
1440            );
1441            return Err(StunParseError::DataMismatch.into());
1442        }
1443        // find the location of the original MessageIntegrity attribute: XXX: maybe encode this into
1444        // the attribute instead?
1445        let data = self.data;
1446        debug_assert!(data.len() >= MessageHeader::LENGTH);
1447        let mut data = &data[MessageHeader::LENGTH..];
1448        let mut data_offset = MessageHeader::LENGTH;
1449        while !data.is_empty() {
1450            let attr = RawAttribute::from_bytes(data)?;
1451            if algo == IntegrityAlgorithm::Sha1 && attr.get_type() == MessageIntegrity::TYPE {
1452                let msg = MessageIntegrity::try_from(&attr)?;
1453                debug_assert!(msg.hmac().as_slice() == msg_hmac);
1454
1455                // HMAC is computed using all the data up to (exclusive of) the MESSAGE_INTEGRITY
1456                // but with a length field including the MESSAGE_INTEGRITY attribute...
1457                let mut header = [0; 4];
1458                header[0] = self.data[0];
1459                header[1] = self.data[1];
1460                let hmac_data = &self.data[4..data_offset];
1461                BigEndian::write_u16(
1462                    &mut header[2..4],
1463                    data_offset as u16 + 24 - MessageHeader::LENGTH as u16,
1464                );
1465                if MessageIntegrity::verify(
1466                    &[header.as_slice(), hmac_data],
1467                    key,
1468                    msg_hmac.try_into().unwrap(),
1469                ) {
1470                    return Ok(algo);
1471                } else {
1472                    return Err(ValidateError::IntegrityFailed);
1473                }
1474            } else if algo == IntegrityAlgorithm::Sha256
1475                && attr.get_type() == MessageIntegritySha256::TYPE
1476            {
1477                let msg = MessageIntegritySha256::try_from(&attr)?;
1478                debug_assert!(msg.hmac() == msg_hmac);
1479
1480                // HMAC is computed using all the data up to (exclusive of) the MESSAGE_INTEGRITY
1481                // but with a length field including the MESSAGE_INTEGRITY attribute...
1482                let mut header = [0; 4];
1483                header[0] = self.data[0];
1484                header[1] = self.data[1];
1485                let hmac_data = &self.data[4..data_offset];
1486                BigEndian::write_u16(
1487                    &mut header[2..4],
1488                    data_offset as u16 + attr.padded_len() as u16 - MessageHeader::LENGTH as u16,
1489                );
1490                if MessageIntegritySha256::verify(&[&header, hmac_data], key, msg_hmac) {
1491                    return Ok(algo);
1492                } else {
1493                    return Err(ValidateError::IntegrityFailed);
1494                }
1495            }
1496            let padded_len = attr.padded_len();
1497            // checked when initially parsing.
1498            debug_assert!(padded_len <= data.len());
1499            data = &data[padded_len..];
1500            data_offset += padded_len;
1501        }
1502
1503        // Either there is no integrity (checked earlier), or the integrity was found and checked
1504        // by the loop above.
1505        unreachable!();
1506    }
1507
1508    /// Retrieve the nth `RawAttribute` with a particular [`AttributeType`] from this `Message`.
1509    ///
1510    /// # Examples
1511    ///
1512    /// Retrieve a`RawAttribute`
1513    ///
1514    /// ```
1515    /// # use stun_types::attribute::{RawAttribute, Attribute};
1516    /// # use stun_types::message::{Message, MessageType, MessageClass, MessageWriteVec,
1517    /// #     MessageWrite, MessageWriteExt, BINDING};
1518    /// let mut message = Message::builder_request(BINDING, MessageWriteVec::new());
1519    /// let attr = RawAttribute::new(1.into(), &[3]);
1520    /// assert!(message.add_attribute(&attr).is_ok());
1521    /// assert!(message.add_attribute(&attr).is_ok());
1522    /// let message = message.finish();
1523    /// let message = Message::from_bytes(&message).unwrap();
1524    /// assert_eq!(message.nth_raw_attribute(1.into(), 1).unwrap(), attr);
1525    /// ```
1526    pub fn nth_raw_attribute(&self, atype: AttributeType, n: usize) -> Option<RawAttribute<'_>> {
1527        self.nth_raw_attribute_and_offset(atype, n)
1528            .map(|(_offset, attr)| attr)
1529    }
1530
1531    /// Retrieve the first `RawAttribute` of a particular `AttributeTye` from this `Message`.
1532    ///
1533    /// The is equivalent to `Message::nth_raw_attribute(0)`.
1534    pub fn raw_attribute(&self, atype: AttributeType) -> Option<RawAttribute<'_>> {
1535        self.nth_raw_attribute(atype, 0)
1536    }
1537
1538    /// Retrieve the nth `RawAttribute` of a particular `AttributeType` from this `Message` with
1539    /// it's byte offset.
1540    ///
1541    /// The offset is from the start of the 4 byte Attribute header.
1542    ///
1543    /// # Examples
1544    ///
1545    /// Retrieve a`RawAttribute`
1546    ///
1547    /// ```
1548    /// # use stun_types::attribute::{RawAttribute, Attribute};
1549    /// # use stun_types::message::{Message, MessageType, MessageClass, MessageWriteVec,
1550    /// #     MessageWrite, MessageWriteExt, BINDING};
1551    /// let mut message = Message::builder_request(BINDING, MessageWriteVec::new());
1552    /// let attr = RawAttribute::new(1.into(), &[3]);
1553    /// assert!(message.add_attribute(&attr).is_ok());
1554    /// assert!(message.add_attribute(&attr).is_ok());
1555    /// let message = message.finish();
1556    /// let message = Message::from_bytes(&message).unwrap();
1557    /// assert_eq!(message.nth_raw_attribute_and_offset(1.into(), 1).unwrap(), (28, attr));
1558    /// ```
1559    #[tracing::instrument(
1560        name = "message_nth_raw_attribute_and_offset",
1561        level = "trace",
1562        skip(self, atype),
1563        fields(
1564            msg.transaction = %self.transaction_id(),
1565            attribute_type = %atype,
1566        )
1567    )]
1568    pub fn nth_raw_attribute_and_offset(
1569        &self,
1570        atype: AttributeType,
1571        n: usize,
1572    ) -> Option<(usize, RawAttribute<'_>)> {
1573        if let Some((offset, attr)) = self
1574            .iter_attributes()
1575            .filter(|(_offset, attr)| attr.get_type() == atype)
1576            .nth(n)
1577        {
1578            trace!("found attribute at offset: {offset}");
1579            Some((offset, attr))
1580        } else {
1581            trace!("could not find attribute");
1582            None
1583        }
1584    }
1585
1586    /// Retrieve the first `RawAttribute` of a particular `AttributeType` from this `Message` with
1587    /// it's byte offset.
1588    ///
1589    /// This equivalent to calling `Message::nth_raw_attribute_and_offset(0)`.
1590    pub fn raw_attribute_and_offset(
1591        &self,
1592        atype: AttributeType,
1593    ) -> Option<(usize, RawAttribute<'_>)> {
1594        self.nth_raw_attribute_and_offset(atype, 0)
1595    }
1596
1597    /// Retrieve the nth `Attribute` of a particular `AttributeType` from this `Message`.
1598    ///
1599    /// This will error with [`StunParseError::MissingAttribute`] if the attribute does not exist.
1600    /// Otherwise, other parsing errors of the data may be returned specific to the attribute
1601    /// implementation provided.
1602    ///
1603    /// # Examples
1604    ///
1605    /// Retrieve an `Attribute`
1606    ///
1607    /// ```
1608    /// # use stun_types::attribute::{Software, Attribute};
1609    /// # use stun_types::message::{Message, MessageType, MessageClass, MessageWriteVec,
1610    /// #     MessageWrite, MessageWriteExt, BINDING};
1611    /// let mut message = Message::builder_request(BINDING, MessageWriteVec::new());
1612    /// let attr = Software::new("stun-types").unwrap();
1613    /// assert!(message.add_attribute(&attr).is_ok());
1614    /// let message = message.finish();
1615    /// let message = Message::from_bytes(&message).unwrap();
1616    /// assert_eq!(message.attribute::<Software>().unwrap(), attr);
1617    /// ```
1618    pub fn nth_attribute<A: AttributeFromRaw<'a> + AttributeStaticType>(
1619        &'a self,
1620        n: usize,
1621    ) -> Result<A, StunParseError> {
1622        self.nth_attribute_and_offset(n).map(|(_offset, attr)| attr)
1623    }
1624
1625    /// Retrieve the first `Attribute` of a particular `AttributeType` from this `Message`.
1626    ///
1627    /// This equivalent to calling `Message::nth_attribute(0)`.
1628    pub fn attribute<A: AttributeFromRaw<'a> + AttributeStaticType>(
1629        &'a self,
1630    ) -> Result<A, StunParseError> {
1631        self.nth_attribute(0)
1632    }
1633
1634    /// Retrieve the nth `Attribute` of a particular `AttributeType` from this `Message` and it's
1635    /// offset in the original data.
1636    ///
1637    /// This will error with [`StunParseError::MissingAttribute`] if the attribute does not exist.
1638    /// Otherwise, other parsing errors of the data may be returned specific to the attribute
1639    /// implementation provided.
1640    ///
1641    /// The offset is from the start of the 4 byte [`Attribute`] header.
1642    ///
1643    /// # Examples
1644    ///
1645    /// Retrieve an `Attribute`
1646    ///
1647    /// ```
1648    /// # use stun_types::attribute::{Software, Attribute};
1649    /// # use stun_types::message::{Message, MessageType, MessageClass, MessageWriteVec,
1650    /// #     MessageWrite, MessageWriteExt, BINDING};
1651    /// let mut message = Message::builder_request(BINDING, MessageWriteVec::new());
1652    /// let attr = Software::new("stun-types").unwrap();
1653    /// assert!(message.add_attribute(&attr).is_ok());
1654    /// assert!(message.add_attribute(&attr).is_ok());
1655    /// let message = message.finish();
1656    /// let message = Message::from_bytes(&message).unwrap();
1657    /// assert_eq!(message.nth_attribute_and_offset::<Software>(1).unwrap(), (36, attr));
1658    /// ```
1659    pub fn nth_attribute_and_offset<A: AttributeFromRaw<'a> + AttributeStaticType>(
1660        &'a self,
1661        n: usize,
1662    ) -> Result<(usize, A), StunParseError> {
1663        self.nth_raw_attribute_and_offset(A::TYPE, n)
1664            .ok_or(StunParseError::MissingAttribute(A::TYPE))
1665            .and_then(|(offset, raw)| A::from_raw(raw).map(|attr| (offset, attr)))
1666    }
1667
1668    /// Retrieve the first `Attribute` of a particular `AttributeType` from this `Message` and it's
1669    /// offset in the original data.
1670    ///
1671    /// This equivalent to calling `Message::nth_attribute_and_offset(0)`.
1672    pub fn attribute_and_offset<A: AttributeFromRaw<'a> + AttributeStaticType>(
1673        &'a self,
1674    ) -> Result<(usize, A), StunParseError> {
1675        self.nth_attribute_and_offset(0)
1676    }
1677
1678    /// Returns an iterator over the attributes (with their byte offset) in the [`Message`].
1679    pub fn iter_attributes(&self) -> impl Iterator<Item = (usize, RawAttribute<'_>)> {
1680        MessageAttributesIter::new(self.data)
1681    }
1682
1683    /// Check that a message [`Message`] only contains required attributes that are supported and
1684    /// have at least some set of required attributes.  Returns an appropriate error message on
1685    /// failure to meet these requirements.
1686    ///
1687    /// # Examples
1688    ///
1689    /// ```
1690    /// # use stun_types::attribute::*;
1691    /// # use stun_types::message::{Message, MessageType, MessageClass, MessageWriteVec,
1692    /// #     MessageWrite, MessageWriteExt, BINDING};
1693    /// # use core::convert::TryInto;
1694    /// let mut builder = Message::builder_request(BINDING, MessageWriteVec::new());
1695    /// let message = builder.finish();
1696    /// let message = Message::from_bytes(&message).unwrap();
1697    /// // If nothing is required, no error response is returned
1698    /// assert!(matches!(Message::check_attribute_types(&message, &[], &[], MessageWriteVec::new()), None));
1699    ///
1700    /// // If an atttribute is required that is not in the message, then an error response message
1701    /// // is generated
1702    /// let error_msg = Message::check_attribute_types(
1703    ///     &message,
1704    ///     &[],
1705    ///     &[Software::TYPE],
1706    ///     MessageWriteVec::new(),
1707    /// ).unwrap();
1708    /// assert!(error_msg.has_attribute(ErrorCode::TYPE));
1709    /// let error_msg = error_msg.finish();
1710    /// let error_msg = Message::from_bytes(&error_msg).unwrap();
1711    /// let error_code = error_msg.attribute::<ErrorCode>().unwrap();
1712    /// assert_eq!(error_code.code(), 400);
1713    ///
1714    /// let mut builder = Message::builder_request(BINDING, MessageWriteVec::new());
1715    /// let username = Username::new("user").unwrap();
1716    /// builder.add_attribute(&username).unwrap();
1717    /// let message = builder.finish();
1718    /// let message = Message::from_bytes(&message).unwrap();
1719    /// // If a Username is in the message but is not advertised as supported then an
1720    /// // 'UNKNOWN-ATTRIBUTES' error response is returned
1721    /// let error_msg = Message::check_attribute_types(&message, &[], &[], MessageWriteVec::new()).unwrap();
1722    /// let error_msg = error_msg.finish();
1723    /// let error_msg = Message::from_bytes(&error_msg).unwrap();
1724    /// assert!(error_msg.is_response());
1725    /// assert!(error_msg.has_attribute(ErrorCode::TYPE));
1726    /// let error_code = error_msg.attribute::<ErrorCode>().unwrap();
1727    /// assert_eq!(error_code.code(), 420);
1728    /// assert!(error_msg.has_attribute(UnknownAttributes::TYPE));
1729    /// ```
1730    #[tracing::instrument(
1731        level = "trace",
1732        skip(msg, write),
1733        fields(
1734            msg.transaction = %msg.transaction_id(),
1735        )
1736    )]
1737    pub fn check_attribute_types<B: MessageWrite>(
1738        msg: &Message,
1739        supported: &[AttributeType],
1740        required_in_msg: &[AttributeType],
1741        write: B,
1742    ) -> Option<B> {
1743        // Attribute -> AttributeType
1744        let unsupported: Vec<AttributeType> = msg
1745            .iter_attributes()
1746            .map(|(_offset, a)| a.get_type())
1747            // attribute types that require comprehension but are not supported by the caller
1748            .filter(|at| at.comprehension_required() && !supported.contains(at))
1749            .collect();
1750        if !unsupported.is_empty() {
1751            warn!(
1752                "Message contains unknown comprehension required attributes {:?}, returning unknown attributes",
1753                unsupported
1754            );
1755            return Some(Message::unknown_attributes(msg, &unsupported, write));
1756        }
1757        let has_required_attribute_missing = required_in_msg
1758            .iter()
1759            // attribute types we need in the message -> failure -> Bad Request
1760            .any(|&at| {
1761                !msg.iter_attributes()
1762                    .map(|(_offset, a)| a.get_type())
1763                    .any(|a| a == at)
1764            });
1765        if has_required_attribute_missing {
1766            warn!("Message is missing required attributes, returning bad request");
1767            return Some(Message::bad_request(msg, write));
1768        }
1769        None
1770    }
1771
1772    /// Generate an error message with an [`ErrorCode`] attribute signalling 'Unknown Attribute'
1773    /// and an [`UnknownAttributes`] attribute containing the attributes that are unknown.
1774    ///
1775    /// # Examples
1776    ///
1777    /// ```
1778    /// # use stun_types::message::{Message, MessageWriteVec, MessageWrite, BINDING};
1779    /// # use stun_types::attribute::*;
1780    /// # use core::convert::TryInto;
1781    /// let msg = Message::builder_request(BINDING, MessageWriteVec::new()).finish();
1782    /// let msg = Message::from_bytes(&msg).unwrap();
1783    /// let error_msg = Message::unknown_attributes(&msg, &[Username::TYPE], MessageWriteVec::new()).finish();
1784    /// let error_msg = Message::from_bytes(&error_msg).unwrap();
1785    /// assert!(error_msg.is_response());
1786    /// assert!(error_msg.has_attribute(ErrorCode::TYPE));
1787    /// let error_code = error_msg.attribute::<ErrorCode>().unwrap();
1788    /// assert_eq!(error_code.code(), 420);
1789    /// let unknown = error_msg.attribute::<UnknownAttributes>().unwrap();
1790    /// assert!(unknown.has_attribute(Username::TYPE));
1791    /// ```
1792    pub fn unknown_attributes<B: MessageWrite>(
1793        src: &Message,
1794        attributes: &[AttributeType],
1795        write: B,
1796    ) -> B {
1797        let mut out = Message::builder_error(src, write);
1798        let software = Software::new("stun-types").unwrap();
1799        out.add_attribute(&software).unwrap();
1800        let error = ErrorCode::new(420, "Unknown Attributes").unwrap();
1801        out.add_attribute(&error).unwrap();
1802        let unknown = UnknownAttributes::new(attributes);
1803        if !attributes.is_empty() {
1804            out.add_attribute(&unknown).unwrap();
1805        }
1806        out
1807    }
1808
1809    /// Generate an error message with an [`ErrorCode`] attribute signalling a 'Bad Request'
1810    ///
1811    /// # Examples
1812    ///
1813    /// ```
1814    /// # use stun_types::message::{Message, MessageType, MessageClass, MessageWriteVec,
1815    /// #     MessageWrite, BINDING};
1816    /// # use stun_types::attribute::*;
1817    /// # use core::convert::TryInto;
1818    /// let msg = Message::builder_request(BINDING, MessageWriteVec::new()).finish();
1819    /// let msg = Message::from_bytes(&msg).unwrap();
1820    /// let error_msg = Message::bad_request(&msg, MessageWriteVec::new()).finish();
1821    /// let error_msg = Message::from_bytes(&error_msg).unwrap();
1822    /// assert!(error_msg.has_attribute(ErrorCode::TYPE));
1823    /// let error_code =  error_msg.attribute::<ErrorCode>().unwrap();
1824    /// assert_eq!(error_code.code(), 400);
1825    /// ```
1826    pub fn bad_request<B: MessageWrite>(src: &Message, write: B) -> B {
1827        let mut out = Message::builder_error(src, write);
1828        let software = Software::new("stun-types").unwrap();
1829        out.add_attribute(&software).unwrap();
1830        let error = ErrorCode::new(400, "Bad Request").unwrap();
1831        out.add_attribute(&error).unwrap();
1832        out
1833    }
1834
1835    /// Whether this message contains an attribute of the specified type.
1836    ///
1837    /// # Examples
1838    ///
1839    /// ```
1840    /// # use stun_types::message::{Message, MessageType, MessageClass, MessageWriteVec,
1841    /// #     MessageWrite, MessageWriteExt, BINDING};
1842    /// # use stun_types::attribute::{Software, Attribute, AttributeStaticType};
1843    /// let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
1844    /// let attr = Software::new("stun-types").unwrap();
1845    /// assert!(msg.add_attribute(&attr).is_ok());
1846    /// let msg = msg.finish();
1847    /// let msg = Message::from_bytes(&msg).unwrap();
1848    /// assert!(msg.has_attribute(Software::TYPE));
1849    /// ```
1850    pub fn has_attribute(&self, atype: AttributeType) -> bool {
1851        self.iter_attributes()
1852            .any(|(_offset, attr)| attr.get_type() == atype)
1853    }
1854
1855    /// Returns the underlying slice.
1856    pub fn as_bytes(&self) -> &[u8] {
1857        self.data
1858    }
1859}
1860impl<'a> TryFrom<&'a [u8]> for Message<'a> {
1861    type Error = StunParseError;
1862
1863    fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {
1864        Message::from_bytes(value)
1865    }
1866}
1867
1868impl AsRef<[u8]> for Message<'_> {
1869    fn as_ref(&self) -> &[u8] {
1870        self.data
1871    }
1872}
1873
1874#[derive(Debug)]
1875struct MessageRawAttributesIter<'a> {
1876    data: &'a [u8],
1877    data_i: usize,
1878}
1879
1880impl<'a> MessageRawAttributesIter<'a> {
1881    fn new(data: &'a [u8]) -> Self {
1882        Self {
1883            data,
1884            data_i: MessageHeader::LENGTH,
1885        }
1886    }
1887}
1888
1889impl<'a> Iterator for MessageRawAttributesIter<'a> {
1890    type Item = Result<(usize, RawAttribute<'a>), StunParseError>;
1891
1892    fn next(&mut self) -> Option<Self::Item> {
1893        if self.data_i >= self.data.len() {
1894            return None;
1895        }
1896
1897        match RawAttribute::from_bytes(&self.data[self.data_i..]) {
1898            Ok(attr) => {
1899                let padded_len = attr.padded_len();
1900                self.data_i += padded_len;
1901                if self.data_i > self.data.len() {
1902                    warn!(
1903                        "attribute {} extends past the end of the data",
1904                        attr.get_type()
1905                    );
1906                    return Some(Err(StunParseError::Truncated {
1907                        expected: self.data_i,
1908                        actual: self.data.len(),
1909                    }));
1910                }
1911                Some(Ok((self.data_i - padded_len, attr)))
1912            }
1913            Err(e) => {
1914                let offset = self.data_i;
1915                self.data_i = self.data.len();
1916                let e = match e {
1917                    StunParseError::Truncated { expected, actual } => StunParseError::Truncated {
1918                        expected: expected + 4 + offset,
1919                        actual: actual + 4 + offset,
1920                    },
1921                    StunParseError::TooLarge { expected, actual } => StunParseError::TooLarge {
1922                        expected: expected + 4 + offset,
1923                        actual: actual + 4 + offset,
1924                    },
1925                    e => e,
1926                };
1927                Some(Err(e))
1928            }
1929        }
1930    }
1931}
1932
1933#[doc(hidden)]
1934#[derive(Debug)]
1935pub struct MessageAttributesIter<'a> {
1936    header_parsed: bool,
1937    inner: MessageRawAttributesIter<'a>,
1938    last_attr_type: AttributeType,
1939    seen_message_integrity: bool,
1940}
1941
1942impl<'a> MessageAttributesIter<'a> {
1943    /// Construct an Iterator over the attributes of a [`Message`].
1944    ///
1945    /// The provided data is the entirety of the message data.
1946    ///
1947    /// Note: this entry point does not verify that the message passes integrity and fingerprint
1948    /// checks and therefore must be used with care on untrusted data. You should use
1949    /// [`Message::from_bytes`] and [`Message::validate_integrity`] to validate the integrity of a
1950    /// STUN [`Message`].
1951    pub fn new(data: &'a [u8]) -> Self {
1952        Self {
1953            header_parsed: false,
1954            inner: MessageRawAttributesIter::new(data),
1955            seen_message_integrity: false,
1956            last_attr_type: AttributeType::new(0),
1957        }
1958    }
1959}
1960
1961impl<'a> Iterator for MessageAttributesIter<'a> {
1962    type Item = (usize, RawAttribute<'a>);
1963
1964    fn next(&mut self) -> Option<Self::Item> {
1965        // nothing further to parse after Fingerprint
1966        if self.last_attr_type == Fingerprint::TYPE {
1967            return None;
1968        }
1969
1970        if !self.header_parsed {
1971            let Ok(hdr) = MessageHeader::from_bytes(self.inner.data) else {
1972                self.last_attr_type = Fingerprint::TYPE;
1973                return None;
1974            };
1975            if hdr.data_length() as usize + MessageHeader::LENGTH > self.inner.data.len() {
1976                self.last_attr_type = Fingerprint::TYPE;
1977                return None;
1978            }
1979            self.header_parsed = true;
1980        }
1981
1982        let (offset, attr) = self.inner.next()?.ok()?;
1983        let attr_type = attr.get_type();
1984        if self.seen_message_integrity {
1985            if self.last_attr_type != Fingerprint::TYPE && attr_type == Fingerprint::TYPE {
1986                self.last_attr_type = attr_type;
1987                return Some((offset, attr));
1988            }
1989            if self.last_attr_type == MessageIntegrity::TYPE
1990                && attr_type == MessageIntegritySha256::TYPE
1991            {
1992                self.last_attr_type = attr_type;
1993                return Some((offset, attr));
1994            }
1995            self.last_attr_type = Fingerprint::TYPE;
1996            return None;
1997        }
1998        if attr.get_type() == MessageIntegrity::TYPE
1999            || attr.get_type() == MessageIntegritySha256::TYPE
2000            || attr.get_type() == Fingerprint::TYPE
2001        {
2002            self.seen_message_integrity = true;
2003        }
2004        self.last_attr_type = attr.get_type();
2005
2006        Some((offset, attr))
2007    }
2008}
2009
2010#[allow(clippy::len_without_is_empty)]
2011/// Trait for implementing a writer for [`Message`]s.
2012pub trait MessageWrite {
2013    /// The output of this [`MessageWrite`]
2014    type Output;
2015    /// Return the maximum size of the output.  If the output data is not bound to a fixed size,
2016    /// `None` should be returned.
2017    fn max_size(&self) -> Option<usize> {
2018        None
2019    }
2020
2021    /// A mutable reference to the contained data.
2022    fn mut_data(&mut self) -> &mut [u8];
2023    /// A reference to the contained data.
2024    fn data(&self) -> &[u8];
2025    /// The length of the currently written data.
2026    fn len(&self) -> usize;
2027    /// Append the provided data to the end of the output.
2028    fn push_data(&mut self, data: &[u8]);
2029    /// Write an attribute to the end of the Message.
2030    fn push_attribute_unchecked(&mut self, attr: &dyn AttributeWrite);
2031
2032    /// Return whether this [`MessageWrite`] contains a particular attribute.
2033    fn has_attribute(&self, atype: AttributeType) -> bool;
2034
2035    /// Return whether this [`MessageWrite`] contains any of the provided attributes and
2036    /// returns the attribute found.
2037    fn has_any_attribute(&self, atypes: &[AttributeType]) -> Option<AttributeType>;
2038
2039    /// Finishes and returns the built Message.
2040    fn finish(self) -> Self::Output;
2041}
2042
2043/// Extension trait for [`MessageWrite`] providing helper functions.
2044pub trait MessageWriteExt: MessageWrite {
2045    /// Retrieve the [`MessageClass`] of a [`Message`]
2046    ///
2047    /// # Examples
2048    ///
2049    /// ```
2050    /// # use stun_types::message::{Message, MessageType, MessageClass, MessageWriteVec,
2051    /// #     MessageWrite, BINDING};
2052    /// let message = Message::builder_request(BINDING, MessageWriteVec::new()).finish();
2053    /// let message = Message::from_bytes(&message).unwrap();
2054    /// assert_eq!(message.class(), MessageClass::Request);
2055    /// ```
2056    fn get_type(&self) -> MessageType {
2057        MessageType::from_bytes(self.data()).unwrap()
2058    }
2059
2060    /// Retrieve the [`MessageClass`] of a [`Message`]
2061    ///
2062    /// # Examples
2063    ///
2064    /// ```
2065    /// # use stun_types::message::{Message, MessageType, MessageClass, MessageWriteVec,
2066    /// #     MessageWrite, BINDING};
2067    /// let message = Message::builder_request(BINDING, MessageWriteVec::new()).finish();
2068    /// let message = Message::from_bytes(&message).unwrap();
2069    /// assert_eq!(message.class(), MessageClass::Request);
2070    /// ```
2071    fn class(&self) -> MessageClass {
2072        self.get_type().class()
2073    }
2074
2075    /// Returns whether the [`Message`] is of the specified [`MessageClass`]
2076    ///
2077    /// # Examples
2078    ///
2079    /// ```
2080    /// # use stun_types::message::{Message, MessageType, MessageClass, MessageWriteVec,
2081    /// #     MessageWrite, BINDING};
2082    /// let message = Message::builder_request(BINDING, MessageWriteVec::new()).finish();
2083    /// let message = Message::from_bytes(&message).unwrap();
2084    /// assert!(message.has_class(MessageClass::Request));
2085    /// ```
2086    fn has_class(&self, cls: MessageClass) -> bool {
2087        self.class() == cls
2088    }
2089
2090    /// Returns whether the [`Message`] is a response
2091    ///
2092    /// This means that the [`Message`] has a class of either success or error
2093    ///
2094    /// # Examples
2095    ///
2096    /// ```
2097    /// # use stun_types::message::{Message, MessageType, MessageClass, MessageWriteVec,
2098    /// #     MessageWrite, BINDING};
2099    /// let message = Message::builder_request(BINDING, MessageWriteVec::new()).finish();
2100    /// let message = Message::from_bytes(&message).unwrap();
2101    /// assert_eq!(message.is_response(), false);
2102    ///
2103    /// let error = Message::builder_error(&message, MessageWriteVec::new()).finish();
2104    /// let error = Message::from_bytes(&error).unwrap();
2105    /// assert_eq!(error.is_response(), true);
2106    ///
2107    /// let success = Message::builder_success(&message, MessageWriteVec::new()).finish();
2108    /// let success = Message::from_bytes(&success).unwrap();
2109    /// assert_eq!(success.is_response(), true);
2110    /// ```
2111    fn is_response(&self) -> bool {
2112        self.class().is_response()
2113    }
2114
2115    /// Retrieves the method of the [`Message`]
2116    ///
2117    /// # Examples
2118    ///
2119    /// ```
2120    /// # use stun_types::message::{Message, MessageType, MessageClass, MessageWriteVec,
2121    /// #     MessageWrite, BINDING};
2122    /// let message = Message::builder_request(BINDING, MessageWriteVec::new()).finish();
2123    /// let message = Message::from_bytes(&message).unwrap();
2124    /// assert_eq!(message.method(), BINDING);
2125    /// ```
2126    fn method(&self) -> Method {
2127        self.get_type().method()
2128    }
2129
2130    /// Returns whether the [`Message`] is of the specified method
2131    ///
2132    /// # Examples
2133    ///
2134    /// ```
2135    /// # use stun_types::message::{Message, MessageType, MessageClass, MessageWriteVec,
2136    /// #     Method, MessageWrite, BINDING};
2137    /// let message = Message::builder_request(BINDING, MessageWriteVec::new()).finish();
2138    /// let message = Message::from_bytes(&message).unwrap();
2139    /// assert!(message.has_method(BINDING));
2140    /// assert!(!message.has_method(Method::new(0)));
2141    /// ```
2142    fn has_method(&self, method: Method) -> bool {
2143        self.method() == method
2144    }
2145
2146    /// Retrieves the 96-bit transaction ID of the [`Message`]
2147    ///
2148    /// # Examples
2149    ///
2150    /// ```
2151    /// # use stun_types::message::{Message, MessageType, MessageClass, MessageWriteVec,
2152    /// #     MessageWrite, BINDING, TransactionId};
2153    /// let mtype = MessageType::from_class_method(MessageClass::Request, BINDING);
2154    /// let transaction_id = TransactionId::generate();
2155    /// let message = Message::builder(mtype, transaction_id, MessageWriteVec::new()).finish();
2156    /// let message = Message::from_bytes(&message).unwrap();
2157    /// assert_eq!(message.transaction_id(), transaction_id);
2158    /// ```
2159    fn transaction_id(&self) -> TransactionId {
2160        BigEndian::read_u128(&self.data()[4..]).into()
2161    }
2162
2163    /// Adds MESSAGE_INTEGRITY attribute to a [`Message`] using the provided credentials
2164    ///
2165    /// # Errors
2166    ///
2167    /// - If a [`MessageIntegrity`] attribute is already present
2168    /// - If a [`MessageIntegritySha256`] attribute is already present
2169    /// - If a [`Fingerprint`] attribute is already present
2170    ///
2171    /// # Examples
2172    ///
2173    /// ```
2174    /// # use stun_types::message::{Message, MessageType, MessageClass, MessageWriteVec,
2175    /// #     MessageWrite, MessageWriteExt, BINDING, MessageIntegrityCredentials,
2176    /// #     ShortTermCredentials, IntegrityAlgorithm, StunWriteError};
2177    /// # use stun_types::attribute::{Attribute, AttributeStaticType, MessageIntegrity,
2178    /// #     MessageIntegritySha256};
2179    /// let mut message = Message::builder_request(BINDING, MessageWriteVec::new());
2180    /// let credentials = ShortTermCredentials::new("pass".to_owned()).into();
2181    /// assert!(message.add_message_integrity(&credentials, IntegrityAlgorithm::Sha1).is_ok());
2182    ///
2183    /// // duplicate MessageIntegrity is an error
2184    /// assert!(matches!(
2185    ///     message.add_message_integrity(&credentials, IntegrityAlgorithm::Sha1),
2186    ///     Err(StunWriteError::AttributeExists(MessageIntegrity::TYPE)),
2187    /// ));
2188    ///
2189    /// // both MessageIntegrity, and MessageIntegritySha256 are allowed, however Sha256 must be
2190    /// // after Sha1
2191    /// assert!(message.add_message_integrity(&credentials, IntegrityAlgorithm::Sha256).is_ok());
2192    ///
2193    /// let data = message.finish();
2194    /// let message = Message::from_bytes(&data).unwrap();
2195    /// assert!(message.validate_integrity(&credentials).is_ok());
2196    /// ```
2197    fn add_message_integrity(
2198        &mut self,
2199        credentials: &MessageIntegrityCredentials,
2200        algorithm: IntegrityAlgorithm,
2201    ) -> Result<(), StunWriteError> {
2202        let key = credentials.make_key(algorithm);
2203        self.add_message_integrity_with_key(&key, algorithm)
2204    }
2205
2206    /// Adds MESSAGE_INTEGRITY attribute to a [`Message`] using the provided credential key.
2207    #[tracing::instrument(
2208        name = "message_add_integrity_with_key",
2209        level = "trace",
2210        err,
2211        skip(self),
2212        fields(
2213            msg.transaction = %self.transaction_id(),
2214        )
2215    )]
2216    fn add_message_integrity_with_key(
2217        &mut self,
2218        key: &IntegrityKey,
2219        algorithm: IntegrityAlgorithm,
2220    ) -> Result<(), StunWriteError> {
2221        let mut atypes = [AttributeType::new(0); 3];
2222        let mut i = 0;
2223        atypes[i] = match algorithm {
2224            IntegrityAlgorithm::Sha1 => MessageIntegrity::TYPE,
2225            IntegrityAlgorithm::Sha256 => MessageIntegritySha256::TYPE,
2226        };
2227        i += 1;
2228        if algorithm == IntegrityAlgorithm::Sha1 {
2229            atypes[i] = MessageIntegritySha256::TYPE;
2230            i += 1;
2231        }
2232        atypes[i] = Fingerprint::TYPE;
2233        i += 1;
2234
2235        match self.has_any_attribute(&atypes[..i]) {
2236            // can't validly add generic attributes after message integrity or fingerprint
2237            Some(MessageIntegrity::TYPE) => {
2238                return Err(StunWriteError::AttributeExists(MessageIntegrity::TYPE))
2239            }
2240            Some(MessageIntegritySha256::TYPE) => {
2241                return Err(StunWriteError::AttributeExists(
2242                    MessageIntegritySha256::TYPE,
2243                ));
2244            }
2245            Some(Fingerprint::TYPE) => return Err(StunWriteError::FingerprintExists),
2246            _ => (),
2247        }
2248        match algorithm {
2249            IntegrityAlgorithm::Sha1 => {
2250                check_attribute_can_fit(self, &MessageIntegrity::new([0; 20]))?
2251            }
2252            IntegrityAlgorithm::Sha256 => {
2253                check_attribute_can_fit(self, &MessageIntegritySha256::new(&[0; 32]).unwrap())?
2254            }
2255        };
2256
2257        add_message_integrity_unchecked(self, key, algorithm);
2258
2259        Ok(())
2260    }
2261
2262    /// Adds [`Fingerprint`] attribute to a [`Message`]
2263    ///
2264    /// # Errors
2265    ///
2266    /// - If a [`Fingerprint`] attribute is already present
2267    ///
2268    /// # Examples
2269    ///
2270    /// ```
2271    /// # use stun_types::message::{Message, MessageType, MessageClass, MessageWriteVec,
2272    /// #     MessageWriteExt, BINDING};
2273    /// let mut message = Message::builder_request(BINDING, MessageWriteVec::new());
2274    /// assert!(message.add_fingerprint().is_ok());
2275    ///
2276    /// // duplicate FINGERPRINT is an error
2277    /// assert!(message.add_fingerprint().is_err());
2278    /// ```
2279    #[tracing::instrument(
2280        name = "message_add_fingerprint",
2281        level = "trace",
2282        skip(self),
2283        fields(
2284            msg.transaction = %self.transaction_id(),
2285        )
2286    )]
2287    fn add_fingerprint(&mut self) -> Result<(), StunWriteError> {
2288        if self.has_attribute(Fingerprint::TYPE) {
2289            return Err(StunWriteError::AttributeExists(Fingerprint::TYPE));
2290        }
2291
2292        check_attribute_can_fit(self, &Fingerprint::new([0; 4]))?;
2293        add_fingerprint_unchecked(self);
2294
2295        Ok(())
2296    }
2297
2298    /// Add a `Attribute` to this `Message`.  Only one `AttributeType` can be added for each
2299    /// `Attribute.  Attempting to add multiple `Atribute`s of the same `AttributeType` will fail.
2300    ///
2301    /// # Errors
2302    ///
2303    /// - If the attribute already exists within the message
2304    /// - If attempting to add attributes when [`MessageIntegrity`], [`MessageIntegritySha256`] or
2305    /// [`Fingerprint`] atributes already exist.
2306    ///
2307    /// # Panics
2308    ///
2309    /// - if a [`MessageIntegrity`] or [`MessageIntegritySha256`] attribute is attempted to be added.  Use
2310    /// `Message::add_message_integrity` instead.
2311    /// - if a [`Fingerprint`] attribute is attempted to be added. Use
2312    /// `Message::add_fingerprint` instead.
2313    ///
2314    /// # Examples
2315    ///
2316    /// Add an `Attribute`
2317    ///
2318    /// ```
2319    /// # use stun_types::attribute::RawAttribute;
2320    /// # use stun_types::message::{Message, MessageType, MessageClass, MessageWriteVec,
2321    /// #     MessageWriteExt, BINDING};
2322    /// let mut message = Message::builder_request(BINDING, MessageWriteVec::new());
2323    /// let attr = RawAttribute::new(1.into(), &[3]);
2324    /// assert!(message.add_attribute(&attr).is_ok());
2325    /// // Duplicate attributes are allowed, however semantically, the protocol may not allow them.
2326    /// assert!(message.add_attribute(&attr).is_ok());
2327    /// ```
2328    #[tracing::instrument(
2329        name = "message_add_attribute",
2330        level = "trace",
2331        err,
2332        skip(self, attr),
2333        fields(
2334            msg.transaction = %self.transaction_id(),
2335        )
2336    )]
2337    fn add_attribute(&mut self, attr: &dyn AttributeWrite) -> Result<(), StunWriteError> {
2338        let ty = attr.get_type();
2339        match ty {
2340            MessageIntegrity::TYPE => {
2341                panic!("Cannot write MessageIntegrity with `add_attribute`.  Use add_message_integrity() instead");
2342            }
2343            MessageIntegritySha256::TYPE => {
2344                panic!("Cannot write MessageIntegritySha256 with `add_attribute`.  Use add_message_integrity() instead");
2345            }
2346            Fingerprint::TYPE => {
2347                panic!(
2348                    "Cannot write Fingerprint with `add_attribute`.  Use add_fingerprint() instead"
2349                );
2350            }
2351            _ => (),
2352        }
2353        match self.has_any_attribute(&[
2354            MessageIntegrity::TYPE,
2355            MessageIntegritySha256::TYPE,
2356            Fingerprint::TYPE,
2357        ]) {
2358            // can't validly add generic attributes after message integrity or fingerprint
2359            Some(MessageIntegrity::TYPE) => return Err(StunWriteError::MessageIntegrityExists),
2360            Some(MessageIntegritySha256::TYPE) => {
2361                return Err(StunWriteError::MessageIntegrityExists)
2362            }
2363            Some(Fingerprint::TYPE) => return Err(StunWriteError::FingerprintExists),
2364            _ => (),
2365        }
2366        check_attribute_can_fit(self, attr)?;
2367        self.push_attribute_unchecked(attr);
2368        Ok(())
2369    }
2370}
2371
2372impl<T: MessageWrite> MessageWriteExt for T {}
2373
2374/// A [`MessageWrite`] implementation that writes into a `Vec<u8>`.
2375#[derive(Debug, Default)]
2376pub struct MessageWriteVec {
2377    output: Vec<u8>,
2378    attributes: smallvec::SmallVec<[AttributeType; 16]>,
2379}
2380
2381impl MessageWriteVec {
2382    /// Construct a new [`MessageWriteVec`].
2383    pub fn new() -> Self {
2384        Self::default()
2385    }
2386
2387    /// Allocate a new [`MessageWriteVec`] with a preallocated capacity
2388    pub fn with_capacity(capacity: usize) -> Self {
2389        Self {
2390            output: Vec::with_capacity(capacity),
2391            attributes: Default::default(),
2392        }
2393    }
2394}
2395
2396impl core::ops::Deref for MessageWriteVec {
2397    type Target = Vec<u8>;
2398    fn deref(&self) -> &Self::Target {
2399        &self.output
2400    }
2401}
2402
2403impl core::ops::DerefMut for MessageWriteVec {
2404    fn deref_mut(&mut self) -> &mut Self::Target {
2405        &mut self.output
2406    }
2407}
2408
2409impl MessageWrite for MessageWriteVec {
2410    type Output = Vec<u8>;
2411
2412    fn mut_data(&mut self) -> &mut [u8] {
2413        &mut self.output
2414    }
2415
2416    fn data(&self) -> &[u8] {
2417        &self.output
2418    }
2419
2420    fn len(&self) -> usize {
2421        self.output.len()
2422    }
2423
2424    fn push_data(&mut self, data: &[u8]) {
2425        self.output.extend(data)
2426    }
2427
2428    fn finish(self) -> Self::Output {
2429        self.output
2430    }
2431
2432    fn push_attribute_unchecked(&mut self, attr: &dyn AttributeWrite) {
2433        let offset = self.output.len();
2434        let padded_len = attr.padded_len();
2435        let expected = offset + padded_len;
2436        BigEndian::write_u16(
2437            &mut self.output[2..4],
2438            (expected - MessageHeader::LENGTH) as u16,
2439        );
2440        self.output.resize(expected, 0);
2441        attr.write_into_unchecked(&mut self.output[offset..]);
2442        self.attributes.push(attr.get_type());
2443    }
2444
2445    fn has_attribute(&self, atype: AttributeType) -> bool {
2446        self.attributes.contains(&atype)
2447    }
2448
2449    fn has_any_attribute(&self, atypes: &[AttributeType]) -> Option<AttributeType> {
2450        self.attributes
2451            .iter()
2452            .find(|&typ| atypes.contains(typ))
2453            .cloned()
2454    }
2455}
2456
2457/// A [`MessageWrite`] implementation that writes into a mutable slice.
2458#[derive(Debug, Default)]
2459pub struct MessageWriteMutSlice<'a> {
2460    output: &'a mut [u8],
2461    offset: usize,
2462    attributes: smallvec::SmallVec<[AttributeType; 16]>,
2463}
2464
2465impl<'a> MessageWriteMutSlice<'a> {
2466    /// Construct a new [`MessageWriteMutSlice`] using the provided mutbale slice.
2467    pub fn new(data: &'a mut [u8]) -> Self {
2468        Self {
2469            output: data,
2470            offset: 0,
2471            attributes: Default::default(),
2472        }
2473    }
2474}
2475
2476impl core::ops::Deref for MessageWriteMutSlice<'_> {
2477    type Target = [u8];
2478    fn deref(&self) -> &Self::Target {
2479        self.output
2480    }
2481}
2482
2483impl core::ops::DerefMut for MessageWriteMutSlice<'_> {
2484    fn deref_mut(&mut self) -> &mut Self::Target {
2485        self.output
2486    }
2487}
2488
2489impl<'a> MessageWrite for MessageWriteMutSlice<'a> {
2490    type Output = usize;
2491
2492    fn max_size(&self) -> Option<usize> {
2493        Some(self.output.len())
2494    }
2495
2496    fn mut_data(&mut self) -> &mut [u8] {
2497        &mut self.output[..self.offset]
2498    }
2499
2500    fn data(&self) -> &[u8] {
2501        &self.output[..self.offset]
2502    }
2503
2504    fn len(&self) -> usize {
2505        self.offset
2506    }
2507
2508    fn push_data(&mut self, data: &[u8]) {
2509        let len = data.len();
2510        self.output[self.offset..self.offset + len].copy_from_slice(data);
2511        self.offset += len;
2512    }
2513
2514    fn push_attribute_unchecked(&mut self, attr: &dyn AttributeWrite) {
2515        let padded_len = attr.padded_len();
2516        let expected = self.offset + padded_len;
2517        BigEndian::write_u16(
2518            &mut self.output[2..4],
2519            (expected - MessageHeader::LENGTH) as u16,
2520        );
2521        self.attributes.push(attr.get_type());
2522        attr.write_into(&mut self.output[self.offset..self.offset + padded_len])
2523            .unwrap();
2524        self.offset += padded_len;
2525    }
2526
2527    fn finish(self) -> Self::Output {
2528        self.offset
2529    }
2530
2531    fn has_attribute(&self, atype: AttributeType) -> bool {
2532        self.attributes.contains(&atype)
2533    }
2534
2535    fn has_any_attribute(&self, atypes: &[AttributeType]) -> Option<AttributeType> {
2536        self.attributes
2537            .iter()
2538            .find(|&typ| atypes.contains(typ))
2539            .cloned()
2540    }
2541}
2542
2543fn check_attribute_can_fit<O, T: MessageWrite<Output = O> + ?Sized>(
2544    this: &mut T,
2545    attr: &dyn AttributeWrite,
2546) -> Result<usize, StunWriteError> {
2547    let len = attr.padded_len();
2548    let out_data = this.data();
2549    if out_data.len() < MessageHeader::LENGTH {
2550        return Err(StunWriteError::TooSmall {
2551            expected: 20,
2552            actual: out_data.len(),
2553        });
2554    }
2555    let expected = BigEndian::read_u16(&out_data[2..4]) as usize + MessageHeader::LENGTH + len;
2556    if let Some(max) = this.max_size() {
2557        if max < expected {
2558            return Err(StunWriteError::TooSmall {
2559                expected,
2560                actual: max,
2561            });
2562        }
2563    }
2564    Ok(expected)
2565}
2566
2567fn add_message_integrity_unchecked<O, T: MessageWrite<Output = O> + ?Sized>(
2568    this: &mut T,
2569    key: &IntegrityKey,
2570    algorithm: IntegrityAlgorithm,
2571) {
2572    // message-integrity is computed using all the data up to (exclusive of) the
2573    // MESSAGE-INTEGRITY but with a length field including the MESSAGE-INTEGRITY attribute...
2574    match algorithm {
2575        IntegrityAlgorithm::Sha1 => {
2576            this.push_attribute_unchecked(&MessageIntegrity::new([0; 20]));
2577            let len = this.len();
2578            let data = this.mut_data();
2579            let integrity = MessageIntegrity::compute(&[&data[..len - 24]], key).unwrap();
2580            data[len - 20..].copy_from_slice(&integrity);
2581        }
2582        IntegrityAlgorithm::Sha256 => {
2583            this.push_attribute_unchecked(&MessageIntegritySha256::new(&[0; 32]).unwrap());
2584            let len = this.len();
2585            let data = this.mut_data();
2586            let integrity = MessageIntegritySha256::compute(&[&data[..len - 36]], key).unwrap();
2587            data[len - 32..].copy_from_slice(&integrity);
2588        }
2589    }
2590}
2591
2592fn add_fingerprint_unchecked<O, T: MessageWrite<Output = O> + ?Sized>(this: &mut T) {
2593    // fingerprint is computed using all the data up to (exclusive of) the FINGERPRINT
2594    // but with a length field including the FINGERPRINT attribute...
2595    this.push_attribute_unchecked(&Fingerprint::new([0; 4]));
2596    let len = this.len();
2597    let data = this.mut_data();
2598    let fingerprint = Fingerprint::compute(&[&data[..len - 8]]);
2599    let fingerprint = Fingerprint::new(fingerprint);
2600    fingerprint.write_into(&mut data[len - 8..]).unwrap();
2601}
2602
2603#[cfg(test)]
2604mod tests {
2605    use alloc::borrow::ToOwned;
2606    use precis_profiles::precis_core::profile::Profile;
2607    use tracing::error;
2608
2609    use super::*;
2610
2611    #[test]
2612    #[should_panic(expected = "Method value is out of range")]
2613    fn method_value_out_of_range() {
2614        let _log = crate::tests::test_init_log();
2615        Method::new(0xf000);
2616    }
2617
2618    #[test]
2619    #[cfg(feature = "std")]
2620    fn method_name() {
2621        let _log = crate::tests::test_init_log();
2622        assert_eq!(BINDING.name(), "BINDING");
2623        let method = Method::new(0x111);
2624        method.add_name("SOME-NAME");
2625        assert_eq!(method.name(), "SOME-NAME");
2626        assert_eq!(Method::new(0x112).name(), "unknown");
2627    }
2628
2629    #[test]
2630    fn msg_type_roundtrip() {
2631        let _log = crate::tests::test_init_log();
2632        /* validate that all methods/classes survive a roundtrip */
2633        for m in 0..0xfff {
2634            let m = Method::new(m);
2635            let classes = vec![
2636                MessageClass::Request,
2637                MessageClass::Indication,
2638                MessageClass::Success,
2639                MessageClass::Error,
2640            ];
2641            for c in classes {
2642                let mtype = MessageType::from_class_method(c, m);
2643                trace!("{mtype}");
2644                assert_eq!(mtype.class(), c);
2645                assert!(mtype.has_class(c));
2646                assert_eq!(mtype.method(), m);
2647                assert!(mtype.has_method(m));
2648                let bytes = mtype.to_bytes();
2649                let ptype = MessageType::from_bytes(&bytes).unwrap();
2650                assert_eq!(mtype, ptype);
2651            }
2652        }
2653    }
2654
2655    #[test]
2656    fn msg_type_not_stun() {
2657        assert!(matches!(
2658            MessageType::from_bytes(&[0xc0, 0x00]),
2659            Err(StunParseError::NotStun)
2660        ));
2661    }
2662
2663    #[test]
2664    fn msg_roundtrip() {
2665        let _log = crate::tests::test_init_log();
2666        /* validate that all methods/classes survive a roundtrip */
2667        for m in (0x009..0x4ff).step_by(0x123) {
2668            let m = Method::new(m);
2669            let classes = vec![
2670                MessageClass::Request,
2671                MessageClass::Indication,
2672                MessageClass::Success,
2673                MessageClass::Error,
2674            ];
2675            for c in classes {
2676                let mtype = MessageType::from_class_method(c, m);
2677                for tid in (0x18..0xff_ffff_ffff_ffff_ffff).step_by(0xfedc_ba98_7654_3210) {
2678                    let mut msg = Message::builder(mtype, tid.into(), MessageWriteVec::default());
2679                    let attr = RawAttribute::new(1.into(), &[3]);
2680                    assert!(msg.add_attribute(&attr).is_ok());
2681                    let data = msg.finish();
2682
2683                    let msg = Message::from_bytes(&data).unwrap();
2684                    let msg_attr = msg.raw_attribute(1.into()).unwrap();
2685                    assert_eq!(msg_attr, attr);
2686                    assert_eq!(msg.get_type(), mtype);
2687                    assert_eq!(msg.transaction_id(), tid.into());
2688                    assert_eq!(msg.as_bytes(), &data);
2689                    assert_eq!(msg.as_ref(), &data);
2690                }
2691            }
2692        }
2693    }
2694
2695    #[test]
2696    fn unknown_attributes() {
2697        let _log = crate::tests::test_init_log();
2698        let src = Message::builder_request(BINDING, MessageWriteVec::default()).finish();
2699        let src = Message::from_bytes(&src).unwrap();
2700        let msg =
2701            Message::unknown_attributes(&src, &[Software::TYPE], MessageWriteVec::new()).finish();
2702        let msg = Message::from_bytes(&msg).unwrap();
2703        assert_eq!(msg.transaction_id(), src.transaction_id());
2704        assert_eq!(msg.class(), MessageClass::Error);
2705        assert!(msg.has_class(MessageClass::Error));
2706        assert!(!msg.has_class(MessageClass::Success));
2707        assert_eq!(msg.method(), src.method());
2708        assert!(msg.has_method(src.method()));
2709        let err = msg.attribute::<ErrorCode>().unwrap();
2710        assert_eq!(err.code(), 420);
2711        let unknown_attrs = msg.attribute::<UnknownAttributes>().unwrap();
2712        assert!(unknown_attrs.has_attribute(Software::TYPE));
2713    }
2714
2715    #[test]
2716    fn bad_request() {
2717        let _log = crate::tests::test_init_log();
2718        let src = Message::builder_request(BINDING, MessageWriteVec::new()).finish();
2719        let src = Message::from_bytes(&src).unwrap();
2720        let msg = Message::bad_request(&src, MessageWriteVec::new());
2721        assert!(msg.has_class(MessageClass::Error));
2722        assert!(!msg.has_class(MessageClass::Success));
2723        assert!(msg.has_method(src.method()));
2724        assert!(!msg.has_method(Method::new(0x111)));
2725        assert!(msg.is_response());
2726        let msg = msg.finish();
2727        let msg = Message::from_bytes(&msg).unwrap();
2728        assert_eq!(msg.transaction_id(), src.transaction_id());
2729        assert_eq!(msg.class(), MessageClass::Error);
2730        assert_eq!(msg.method(), src.method());
2731        let err = msg.attribute::<ErrorCode>().unwrap();
2732        assert_eq!(err.code(), 400);
2733    }
2734
2735    #[test]
2736    fn fingerprint() {
2737        let _log = crate::tests::test_init_log();
2738        let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2739        assert!(msg.has_class(MessageClass::Request));
2740        assert!(!msg.has_class(MessageClass::Success));
2741        assert!(msg.has_method(BINDING));
2742        assert!(!msg.has_method(Method::new(0x111)));
2743        let software = Software::new("s").unwrap();
2744        msg.add_attribute(&software).unwrap();
2745        msg.add_fingerprint().unwrap();
2746        let bytes = msg.finish();
2747        // validates the fingerprint of the data when available
2748        let new_msg = Message::from_bytes(&bytes).unwrap();
2749        let (offset, software) = new_msg.attribute_and_offset::<Software>().unwrap();
2750        assert_eq!(software.software(), "s");
2751        assert_eq!(offset, 20);
2752        let (offset, _new_fingerprint) =
2753            new_msg.raw_attribute_and_offset(Fingerprint::TYPE).unwrap();
2754        assert_eq!(offset, 28);
2755    }
2756
2757    #[test]
2758    fn integrity() {
2759        let _log = crate::tests::test_init_log();
2760        for algorithm in [IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256] {
2761            let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2762            let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2763            let software = Software::new("s").unwrap();
2764            msg.add_attribute(&software).unwrap();
2765            msg.add_message_integrity(&credentials, algorithm).unwrap();
2766            let bytes = msg.finish();
2767            // validates the fingerprint of the data when available
2768            let new_msg = Message::from_bytes(&bytes).unwrap();
2769            new_msg.validate_integrity(&credentials).unwrap();
2770            let (offset, software) = new_msg.attribute_and_offset::<Software>().unwrap();
2771            assert_eq!(software.software(), "s");
2772            assert_eq!(offset, 20);
2773        }
2774    }
2775
2776    #[test]
2777    fn write_into_short_destination() {
2778        let _log = crate::tests::test_init_log();
2779        const LEN: usize = MessageHeader::LENGTH + 8;
2780        let mut data = [0; LEN - 1];
2781        let mut msg = Message::builder_request(BINDING, MessageWriteMutSlice::new(&mut data));
2782        let software = Software::new("s").unwrap();
2783        assert!(
2784            matches!(msg.add_attribute(&software), Err(StunWriteError::TooSmall { expected, actual }) if expected == LEN && actual == LEN - 1)
2785        );
2786    }
2787
2788    #[test]
2789    fn integrity_key() {
2790        let _log = crate::tests::test_init_log();
2791        let credentials1 = ShortTermCredentials::new("pass1".to_owned());
2792        let key1 =
2793            MessageIntegrityCredentials::from(credentials1).make_key(IntegrityAlgorithm::Sha1);
2794        let credentials2 = ShortTermCredentials::new("pass2".to_owned());
2795        let key2 =
2796            MessageIntegrityCredentials::from(credentials2).make_key(IntegrityAlgorithm::Sha1);
2797        assert_eq!(key1, key1);
2798        assert_eq!(key2, key2);
2799        assert_ne!(key1, key2);
2800    }
2801
2802    #[test]
2803    fn add_duplicate_integrity() {
2804        let _log = crate::tests::test_init_log();
2805        let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2806        let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2807        msg.add_message_integrity(&credentials, IntegrityAlgorithm::Sha1)
2808            .unwrap();
2809        assert!(matches!(
2810            msg.add_message_integrity(&credentials, IntegrityAlgorithm::Sha1),
2811            Err(StunWriteError::AttributeExists(MessageIntegrity::TYPE))
2812        ));
2813        msg.add_message_integrity(&credentials, IntegrityAlgorithm::Sha256)
2814            .unwrap();
2815        assert!(matches!(
2816            msg.add_message_integrity(&credentials, IntegrityAlgorithm::Sha256),
2817            Err(StunWriteError::AttributeExists(
2818                MessageIntegritySha256::TYPE
2819            ))
2820        ));
2821        let software = Software::new("s").unwrap();
2822        assert!(matches!(
2823            msg.add_attribute(&software),
2824            Err(StunWriteError::MessageIntegrityExists)
2825        ));
2826    }
2827
2828    #[test]
2829    fn add_sha1_integrity_after_sha256() {
2830        let _log = crate::tests::test_init_log();
2831        let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2832        let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2833        msg.add_message_integrity(&credentials, IntegrityAlgorithm::Sha256)
2834            .unwrap();
2835        assert!(matches!(
2836            msg.add_message_integrity(&credentials, IntegrityAlgorithm::Sha1),
2837            Err(StunWriteError::AttributeExists(
2838                MessageIntegritySha256::TYPE
2839            ))
2840        ));
2841    }
2842
2843    #[test]
2844    fn add_attribute_after_integrity() {
2845        let _log = crate::tests::test_init_log();
2846        for algorithm in [IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256] {
2847            let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2848            let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2849            msg.add_message_integrity(&credentials, algorithm).unwrap();
2850            let software = Software::new("s").unwrap();
2851            assert!(matches!(
2852                msg.add_attribute(&software),
2853                Err(StunWriteError::MessageIntegrityExists)
2854            ));
2855        }
2856    }
2857
2858    #[test]
2859    fn add_raw_attribute_after_integrity() {
2860        let _log = crate::tests::test_init_log();
2861        for algorithm in [IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256] {
2862            let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2863            let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2864            msg.add_message_integrity(&credentials, algorithm).unwrap();
2865            let software = Software::new("s").unwrap();
2866            let raw = software.to_raw();
2867            assert!(matches!(
2868                msg.add_attribute(&raw),
2869                Err(StunWriteError::MessageIntegrityExists)
2870            ));
2871        }
2872    }
2873
2874    #[test]
2875    fn add_integrity_after_fingerprint() {
2876        let _log = crate::tests::test_init_log();
2877        for algorithm in [IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256] {
2878            let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2879            let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2880            msg.add_fingerprint().unwrap();
2881            assert!(matches!(
2882                msg.add_message_integrity(&credentials, algorithm),
2883                Err(StunWriteError::FingerprintExists)
2884            ));
2885        }
2886    }
2887
2888    #[test]
2889    fn duplicate_fingerprint() {
2890        let _log = crate::tests::test_init_log();
2891        let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2892        msg.add_fingerprint().unwrap();
2893        assert!(matches!(
2894            msg.add_fingerprint(),
2895            Err(StunWriteError::AttributeExists(Fingerprint::TYPE))
2896        ));
2897    }
2898
2899    #[test]
2900    fn parse_invalid_fingerprint() {
2901        let _log = crate::tests::test_init_log();
2902        let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2903        msg.add_fingerprint().unwrap();
2904        let mut bytes = msg.finish();
2905        bytes[24] = 0x80;
2906        bytes[25] = 0x80;
2907        bytes[26] = 0x80;
2908        bytes[27] = 0x80;
2909        assert!(matches!(
2910            Message::from_bytes(&bytes),
2911            Err(StunParseError::FingerprintMismatch)
2912        ));
2913    }
2914
2915    #[test]
2916    fn parse_wrong_magic() {
2917        let _log = crate::tests::test_init_log();
2918        let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2919        msg.add_fingerprint().unwrap();
2920        let mut bytes = msg.finish();
2921        bytes[4] = 0x80;
2922        assert!(matches!(
2923            Message::from_bytes(&bytes),
2924            Err(StunParseError::NotStun)
2925        ));
2926    }
2927
2928    #[test]
2929    fn parse_attribute_after_integrity() {
2930        let _log = crate::tests::test_init_log();
2931        for algorithm in [IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256] {
2932            let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2933            let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2934            msg.add_message_integrity(&credentials, algorithm).unwrap();
2935            let mut bytes = msg.finish();
2936            let software = Software::new("s").unwrap();
2937            let software_bytes = RawAttribute::from(&software).to_bytes();
2938            let software_len = software_bytes.len();
2939            bytes.extend(software_bytes);
2940            bytes[3] += software_len as u8;
2941            let msg = Message::from_bytes(&bytes).unwrap();
2942            assert!(msg.raw_attribute(Software::TYPE).is_none());
2943        }
2944    }
2945
2946    #[test]
2947    fn parse_duplicate_integrity_after_integrity() {
2948        let _log = crate::tests::test_init_log();
2949        for algorithm in [IntegrityAlgorithm::Sha1, IntegrityAlgorithm::Sha256] {
2950            let credentials = ShortTermCredentials::new("secret".to_owned()).into();
2951            let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2952            msg.add_message_integrity(&credentials, algorithm).unwrap();
2953            // duplicate integrity attribute. Don't do this in real code!
2954            add_message_integrity_unchecked(
2955                &mut msg,
2956                &credentials.make_key(IntegrityAlgorithm::Sha1),
2957                algorithm,
2958            );
2959            let bytes = msg.finish();
2960            let integrity_type = match algorithm {
2961                IntegrityAlgorithm::Sha1 => MessageIntegrity::TYPE,
2962                IntegrityAlgorithm::Sha256 => MessageIntegritySha256::TYPE,
2963            };
2964            let msg = Message::from_bytes(&bytes).unwrap();
2965            msg.nth_raw_attribute(integrity_type, 0).unwrap();
2966            assert!(msg.nth_raw_attribute(integrity_type, 1).is_none());
2967        }
2968    }
2969
2970    #[test]
2971    fn parse_attribute_after_fingerprint() {
2972        let _log = crate::tests::test_init_log();
2973        let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2974        msg.add_fingerprint().unwrap();
2975        let mut bytes = msg.finish();
2976        let software = Software::new("s").unwrap();
2977        let software_bytes = RawAttribute::from(&software).to_bytes();
2978        let software_len = software_bytes.len();
2979        bytes.extend(software_bytes);
2980        bytes[3] += software_len as u8;
2981        let msg = Message::from_bytes(&bytes).unwrap();
2982        assert!(msg.raw_attribute(Fingerprint::TYPE).is_some());
2983        assert!(msg.raw_attribute(Software::TYPE).is_none());
2984    }
2985
2986    #[test]
2987    fn parse_duplicate_fingerprint_after_fingerprint() {
2988        let _log = crate::tests::test_init_log();
2989        let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
2990        msg.add_fingerprint().unwrap();
2991        add_fingerprint_unchecked(&mut msg);
2992        let bytes = msg.finish();
2993        let msg = Message::from_bytes(&bytes).unwrap();
2994        assert!(msg.nth_raw_attribute(Fingerprint::TYPE, 0).is_some());
2995        assert!(msg.nth_raw_attribute(Fingerprint::TYPE, 1).is_none());
2996    }
2997
2998    #[test]
2999    fn add_attribute_after_fingerprint() {
3000        let _log = crate::tests::test_init_log();
3001        let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3002        msg.add_fingerprint().unwrap();
3003        let software = Software::new("s").unwrap();
3004        assert!(matches!(
3005            msg.add_attribute(&software),
3006            Err(StunWriteError::FingerprintExists)
3007        ));
3008    }
3009
3010    #[test]
3011    fn add_raw_attribute_after_fingerprint() {
3012        let _log = crate::tests::test_init_log();
3013        let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3014        msg.add_fingerprint().unwrap();
3015        let software = Software::new("s").unwrap();
3016        let raw = software.to_raw();
3017        assert!(matches!(
3018            msg.add_attribute(&raw),
3019            Err(StunWriteError::FingerprintExists)
3020        ));
3021    }
3022
3023    #[test]
3024    fn parse_truncated_message_header() {
3025        let _log = crate::tests::test_init_log();
3026        let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3027        msg.add_fingerprint().unwrap();
3028        let bytes = msg.finish();
3029        assert!(matches!(
3030            Message::from_bytes(&bytes[..8]),
3031            Err(StunParseError::Truncated {
3032                expected: 20,
3033                actual: 8
3034            })
3035        ));
3036    }
3037
3038    #[test]
3039    fn parse_truncated_message() {
3040        let _log = crate::tests::test_init_log();
3041        let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3042        msg.add_fingerprint().unwrap();
3043        let bytes = msg.finish();
3044        assert!(matches!(
3045            Message::from_bytes(&bytes[..24]),
3046            Err(StunParseError::Truncated {
3047                expected: 28,
3048                actual: 24
3049            })
3050        ));
3051    }
3052
3053    #[test]
3054    fn parse_truncated_message_attribute() {
3055        let _log = crate::tests::test_init_log();
3056        let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3057        msg.add_fingerprint().unwrap();
3058        let mut bytes = msg.finish();
3059        // rewrite message header to support the truncated length, but not the attribute.
3060        bytes[3] = 4;
3061        assert!(matches!(
3062            Message::from_bytes(&bytes[..24]),
3063            Err(StunParseError::Truncated {
3064                expected: 28,
3065                actual: 24
3066            })
3067        ));
3068    }
3069
3070    #[test]
3071    fn parse_attribute_extends_past_message_end() {
3072        let _log = crate::tests::test_init_log();
3073        let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3074        msg.add_attribute(&Software::new("a").unwrap()).unwrap();
3075        msg[23] += 1;
3076        let mut bytes = msg.finish();
3077        bytes[3] -= 1;
3078        error!("{bytes:x?}");
3079        error!("{:?}", Message::from_bytes(&bytes[..27]));
3080        assert!(matches!(
3081            Message::from_bytes(&bytes[..27]),
3082            Err(StunParseError::Truncated {
3083                expected: 28,
3084                actual: 27
3085            })
3086        ));
3087    }
3088
3089    #[test]
3090    fn valid_attributes() {
3091        let _log = crate::tests::test_init_log();
3092        let mut src = Message::builder_request(BINDING, MessageWriteVec::new());
3093        let username = Username::new("123").unwrap();
3094        src.add_attribute(&username).unwrap();
3095        let nonce = Nonce::new("nonce").unwrap();
3096        src.add_attribute(&nonce).unwrap();
3097        assert!(!src.has_attribute(Fingerprint::TYPE));
3098        assert!(src.has_attribute(Nonce::TYPE));
3099        let src = src.finish();
3100        let src = Message::from_bytes(&src).unwrap();
3101        assert!(!src.has_attribute(Fingerprint::TYPE));
3102        assert!(src.has_attribute(Nonce::TYPE));
3103
3104        // success case
3105        let res = Message::check_attribute_types(
3106            &src,
3107            &[Username::TYPE, Nonce::TYPE],
3108            &[Username::TYPE],
3109            MessageWriteVec::new(),
3110        );
3111        assert!(res.is_none());
3112
3113        // fingerprint required but not present
3114        let res = Message::check_attribute_types(
3115            &src,
3116            &[Username::TYPE, Nonce::TYPE],
3117            &[Fingerprint::TYPE],
3118            MessageWriteVec::new(),
3119        );
3120        assert!(res.is_some());
3121        let res = res.unwrap();
3122        let res = res.finish();
3123        let res = Message::from_bytes(&res).unwrap();
3124        assert!(res.has_class(MessageClass::Error));
3125        assert!(res.has_method(src.method()));
3126        let err = res.attribute::<ErrorCode>().unwrap();
3127        assert_eq!(err.code(), 400);
3128
3129        // nonce unsupported
3130        let res =
3131            Message::check_attribute_types(&src, &[Username::TYPE], &[], MessageWriteVec::new());
3132        assert!(res.is_some());
3133        let res = res.unwrap();
3134        let data = res.finish();
3135        let res = Message::from_bytes(&data).unwrap();
3136        assert!(res.has_class(MessageClass::Error));
3137        assert!(res.has_method(src.method()));
3138        let err = res.attribute::<ErrorCode>().unwrap();
3139        assert_eq!(err.code(), 420);
3140        let unknown = res.attribute::<UnknownAttributes>().unwrap();
3141        assert!(unknown.has_attribute(Nonce::TYPE));
3142    }
3143
3144    #[test]
3145    fn attributes_iter_with_short_data() {
3146        let _log = crate::tests::test_init_log();
3147        assert_eq!(
3148            MessageAttributesIter::new(&[0x0, 0x1, 0x2, 0x3, 0x4]).next(),
3149            None
3150        );
3151        assert_eq!(
3152            MessageAttributesIter::new(&[
3153                0x0, 0x1, 0x2, 0x3, 0x21, 0x12, 0xa4, 0x42, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf,
3154                0x10, 0x11, 0x12, 0x13, 0x14,
3155            ])
3156            .next(),
3157            None
3158        );
3159    }
3160
3161    #[test]
3162    fn attributes_iter_software_after_fingerprint_ignored() {
3163        let _log = crate::tests::test_init_log();
3164        let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3165        msg.add_fingerprint().unwrap();
3166        let mut bytes = msg.finish();
3167        let software = Software::new("s").unwrap();
3168        let software_bytes = RawAttribute::from(&software).to_bytes();
3169        let software_len = software_bytes.len();
3170        bytes.extend(software_bytes);
3171        bytes[3] += software_len as u8;
3172        let mut it = MessageAttributesIter::new(&bytes);
3173        let (_offset, fingerprint) = it.next().unwrap();
3174        assert_eq!(fingerprint.get_type(), Fingerprint::TYPE);
3175        assert_eq!(it.next(), None);
3176    }
3177
3178    #[test]
3179    fn attributes_iter_message_integrities_fingerprint() {
3180        let _log = crate::tests::test_init_log();
3181        let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3182        let credentials = ShortTermCredentials::new("pass".to_owned());
3183        msg.add_message_integrity(&credentials.clone().into(), IntegrityAlgorithm::Sha1)
3184            .unwrap();
3185        msg.add_message_integrity(&credentials.clone().into(), IntegrityAlgorithm::Sha256)
3186            .unwrap();
3187        msg.add_fingerprint().unwrap();
3188        let mut bytes = msg.finish();
3189        let software = Software::new("s").unwrap();
3190        let software_bytes = RawAttribute::from(&software).to_bytes();
3191        let software_len = software_bytes.len();
3192        bytes.extend(software_bytes);
3193        bytes[3] += software_len as u8;
3194        let mut it = MessageAttributesIter::new(&bytes);
3195        assert_eq!(it.next().unwrap().1.get_type(), MessageIntegrity::TYPE);
3196        assert_eq!(
3197            it.next().unwrap().1.get_type(),
3198            MessageIntegritySha256::TYPE
3199        );
3200        assert_eq!(it.next().unwrap().1.get_type(), Fingerprint::TYPE);
3201        assert_eq!(it.next(), None);
3202    }
3203
3204    #[test]
3205    fn message_parse_multiple_integrities_fingerprint() {
3206        let _log = crate::tests::test_init_log();
3207        let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3208        let credentials = ShortTermCredentials::new("pass".to_owned());
3209        msg.add_message_integrity(&credentials.clone().into(), IntegrityAlgorithm::Sha1)
3210            .unwrap();
3211        msg.add_message_integrity(&credentials.clone().into(), IntegrityAlgorithm::Sha256)
3212            .unwrap();
3213        msg.add_fingerprint().unwrap();
3214        let mut bytes = msg.finish();
3215        let software = Software::new("s").unwrap();
3216        let software_bytes = RawAttribute::from(&software).to_bytes();
3217        let software_len = software_bytes.len();
3218        bytes.extend(software_bytes);
3219        bytes[3] += software_len as u8;
3220        let msg = Message::from_bytes(&bytes).unwrap();
3221        assert!(msg.has_attribute(MessageIntegrity::TYPE));
3222        assert!(msg.has_attribute(MessageIntegritySha256::TYPE));
3223        assert!(!msg.has_attribute(Software::TYPE));
3224        assert_eq!(
3225            msg.validate_integrity(&credentials.clone().into()).unwrap(),
3226            IntegrityAlgorithm::Sha256
3227        );
3228    }
3229
3230    #[test]
3231    fn attributes_iter_fingerprint_after_fingerprint_ignored() {
3232        let _log = crate::tests::test_init_log();
3233        let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3234        msg.add_fingerprint().unwrap();
3235        let mut bytes = msg.finish();
3236        let fingerprint = Fingerprint::new([bytes[bytes.len() - 1].wrapping_sub(1); 4]);
3237        let fingerprint_bytes = RawAttribute::from(&fingerprint).to_bytes();
3238        let fingerprint_len = fingerprint_bytes.len();
3239        bytes.extend(fingerprint_bytes);
3240        bytes[3] += fingerprint_len as u8;
3241        let mut it = MessageAttributesIter::new(&bytes);
3242        let (_offset, fingerprint) = it.next().unwrap();
3243        assert_eq!(fingerprint.get_type(), Fingerprint::TYPE);
3244        assert_eq!(it.next(), None);
3245    }
3246
3247    #[test]
3248    fn write_vec_state() {
3249        let _log = crate::tests::test_init_log();
3250        let mut src = Message::builder_request(BINDING, MessageWriteVec::with_capacity(0x10));
3251        assert_eq!(src.len(), 20);
3252        assert_eq!(src[4], 0x21);
3253        let username = Username::new("123").unwrap();
3254        src.add_attribute(&username).unwrap();
3255        let nonce = Nonce::new("nonce").unwrap();
3256        src.add_attribute(&nonce).unwrap();
3257
3258        assert!(src.has_attribute(Username::TYPE));
3259        assert!(src.has_attribute(Nonce::TYPE));
3260        assert_eq!(
3261            src.has_any_attribute(&[Username::TYPE, Nonce::TYPE]),
3262            Some(Username::TYPE)
3263        );
3264        assert_eq!(
3265            src.has_any_attribute(&[Nonce::TYPE, Username::TYPE]),
3266            Some(Username::TYPE)
3267        );
3268        assert!(src.has_class(MessageClass::Request));
3269        assert!(!src.is_response());
3270        assert!(src.has_method(BINDING));
3271        assert!(src.get_type().has_method(BINDING));
3272        assert!(src.get_type().has_class(MessageClass::Request));
3273        assert!(!src.has_method(Method::new(0x111)));
3274        assert!(!src.get_type().has_method(Method::new(0x111)));
3275        assert!(!src.get_type().has_class(MessageClass::Error));
3276    }
3277
3278    #[test]
3279    fn write_mut_slice_success() {
3280        let _log = crate::tests::test_init_log();
3281        let mut data = [0; 64];
3282        let mut src = Message::builder_request(BINDING, MessageWriteMutSlice::new(&mut data));
3283        assert_eq!(src.len(), 20);
3284        assert_eq!(src[4], 0x21);
3285        let username = Username::new("123").unwrap();
3286        src.add_attribute(&username).unwrap();
3287        let nonce = Nonce::new("nonce").unwrap();
3288        src.add_attribute(&nonce).unwrap();
3289        assert!(src.has_attribute(Username::TYPE));
3290        assert_eq!(
3291            src.has_any_attribute(&[Username::TYPE]),
3292            Some(Username::TYPE)
3293        );
3294        assert!(!src.has_attribute(Software::TYPE));
3295        assert_eq!(src.has_any_attribute(&[Realm::TYPE]), None);
3296        assert_eq!(src.mut_data().len(), src.len());
3297        assert_eq!(src.finish(), 40);
3298        let msg = Message::from_bytes(&data[..40]).unwrap();
3299        let u2 = msg.attribute::<Username>().unwrap();
3300        assert_eq!(u2.username(), "123");
3301        let n2 = msg.attribute::<Nonce>().unwrap();
3302        assert_eq!(n2.nonce(), "nonce");
3303    }
3304
3305    #[test]
3306    fn write_mut_slice_too_short() {
3307        let _log = crate::tests::test_init_log();
3308        let mut data = [0; 27];
3309        let mut src = Message::builder_request(BINDING, MessageWriteMutSlice::new(&mut data));
3310        assert!(matches!(
3311            src.add_attribute(&Username::new("123").unwrap()),
3312            Err(StunWriteError::TooSmall {
3313                expected: 28,
3314                actual: 27
3315            })
3316        ));
3317    }
3318
3319    #[test]
3320    #[should_panic(expected = "created from a non-request message")]
3321    fn builder_success_panic() {
3322        let _log = crate::tests::test_init_log();
3323        let msg = Message::builder(
3324            MessageType::from_class_method(MessageClass::Indication, BINDING),
3325            TransactionId::generate(),
3326            MessageWriteVec::new(),
3327        )
3328        .finish();
3329        let msg = Message::from_bytes(&msg).unwrap();
3330        let _builder = Message::builder_success(&msg, MessageWriteVec::new());
3331    }
3332
3333    #[test]
3334    #[should_panic(expected = "created from a non-request message")]
3335    fn builder_error_panic() {
3336        let _log = crate::tests::test_init_log();
3337        let msg = Message::builder(
3338            MessageType::from_class_method(MessageClass::Indication, BINDING),
3339            TransactionId::generate(),
3340            MessageWriteVec::new(),
3341        )
3342        .finish();
3343        let msg = Message::from_bytes(&msg).unwrap();
3344        let _builder = Message::builder_error(&msg, MessageWriteVec::new());
3345    }
3346
3347    #[test]
3348    #[should_panic(expected = "Use add_message_integrity() instead")]
3349    fn builder_add_attribute_integrity_panic() {
3350        let _log = crate::tests::test_init_log();
3351        let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3352        let hmac = [2; 20];
3353        let integrity = MessageIntegrity::new(hmac);
3354        msg.add_attribute(&integrity).unwrap();
3355    }
3356
3357    #[test]
3358    #[should_panic(expected = "Use add_message_integrity() instead")]
3359    fn builder_add_raw_attribute_integrity_panic() {
3360        let _log = crate::tests::test_init_log();
3361        let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3362        let hmac = [2; 20];
3363        let integrity = MessageIntegrity::new(hmac);
3364        let raw = integrity.to_raw();
3365        msg.add_attribute(&raw).unwrap();
3366    }
3367
3368    #[test]
3369    #[should_panic(expected = "Use add_message_integrity() instead")]
3370    fn builder_add_attribute_integrity_sha256_panic() {
3371        let _log = crate::tests::test_init_log();
3372        let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3373        let hmac = [2; 16];
3374        let integrity = MessageIntegritySha256::new(&hmac).unwrap();
3375        msg.add_attribute(&integrity).unwrap();
3376    }
3377
3378    #[test]
3379    #[should_panic(expected = "Use add_message_integrity() instead")]
3380    fn builder_add_raw_attribute_integrity_sha256_panic() {
3381        let _log = crate::tests::test_init_log();
3382        let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3383        let hmac = [2; 16];
3384        let integrity = MessageIntegritySha256::new(&hmac).unwrap();
3385        let raw = integrity.to_raw();
3386        msg.add_attribute(&raw).unwrap();
3387    }
3388
3389    #[test]
3390    #[should_panic(expected = "Use add_fingerprint() instead")]
3391    fn builder_add_attribute_fingerprint_panic() {
3392        let _log = crate::tests::test_init_log();
3393        let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3394        let fingerprint = [2; 4];
3395        let fingerprint = Fingerprint::new(fingerprint);
3396        msg.add_attribute(&fingerprint).unwrap();
3397    }
3398
3399    #[test]
3400    #[should_panic(expected = "Use add_fingerprint() instead")]
3401    fn builder_add_raw_attribute_fingerprint_panic() {
3402        let _log = crate::tests::test_init_log();
3403        let mut msg = Message::builder_request(BINDING, MessageWriteVec::new());
3404        let fingerprint = [2; 4];
3405        let fingerprint = Fingerprint::new(fingerprint);
3406        let raw = fingerprint.to_raw();
3407        msg.add_attribute(&raw).unwrap();
3408    }
3409
3410    #[test]
3411    fn rfc5769_vector1() {
3412        let _log = crate::tests::test_init_log();
3413        // https://tools.ietf.org/html/rfc5769#section-2.1
3414        let data = vec![
3415            0x00, 0x01, 0x00, 0x58, // Request type message length
3416            0x21, 0x12, 0xa4, 0x42, // Magic cookie
3417            0xb7, 0xe7, 0xa7, 0x01, // }
3418            0xbc, 0x34, 0xd6, 0x86, // } Transaction ID
3419            0xfa, 0x87, 0xdf, 0xae, // }
3420            0x80, 0x22, 0x00, 0x10, // SOFTWARE header
3421            0x53, 0x54, 0x55, 0x4e, //   }
3422            0x20, 0x74, 0x65, 0x73, //   }  User-agent...
3423            0x74, 0x20, 0x63, 0x6c, //   }  ...name
3424            0x69, 0x65, 0x6e, 0x74, //   }
3425            0x00, 0x24, 0x00, 0x04, // PRIORITY header
3426            0x6e, 0x00, 0x01, 0xff, //   PRIORITY value
3427            0x80, 0x29, 0x00, 0x08, // ICE_CONTROLLED header
3428            0x93, 0x2f, 0xf9, 0xb1, //   Pseudo random number
3429            0x51, 0x26, 0x3b, 0x36, //   ... for tie breaker
3430            0x00, 0x06, 0x00, 0x09, // USERNAME header
3431            0x65, 0x76, 0x74, 0x6a, //   Username value
3432            0x3a, 0x68, 0x36, 0x76, //   (9 bytes)
3433            0x59, 0x20, 0x20, 0x20, //   (3 bytes padding)
3434            0x00, 0x08, 0x00, 0x14, // MESSAGE-INTEGRITY header
3435            0x9a, 0xea, 0xa7, 0x0c, //   }
3436            0xbf, 0xd8, 0xcb, 0x56, //   }
3437            0x78, 0x1e, 0xf2, 0xb5, //   } HMAC-SHA1 fingerprint
3438            0xb2, 0xd3, 0xf2, 0x49, //   }
3439            0xc1, 0xb5, 0x71, 0xa2, //   }
3440            0x80, 0x28, 0x00, 0x04, // FINGERPRINT header
3441            0xe5, 0x7a, 0x3b, 0xcf, //   CRC32 fingerprint
3442        ];
3443        let msg = Message::from_bytes(&data).unwrap();
3444        assert!(msg.has_class(MessageClass::Request));
3445        assert!(msg.has_method(BINDING));
3446        assert_eq!(msg.transaction_id(), 0xb7e7_a701_bc34_d686_fa87_dfae.into());
3447
3448        let mut builder = Message::builder(
3449            MessageType::from_class_method(MessageClass::Request, BINDING),
3450            msg.transaction_id(),
3451            MessageWriteVec::new(),
3452        );
3453
3454        // SOFTWARE
3455        assert!(msg.has_attribute(Software::TYPE));
3456        let raw = msg.raw_attribute(Software::TYPE).unwrap();
3457        assert!(Software::try_from(&raw).is_ok());
3458        let software = Software::try_from(&raw).unwrap();
3459        assert_eq!(software.software(), "STUN test client");
3460        builder.add_attribute(&software).unwrap();
3461
3462        // PRIORITY handled elswhere
3463        builder
3464            .add_attribute(&RawAttribute::new(0x24.into(), &[0x6e, 0x00, 0x01, 0xff]))
3465            .unwrap();
3466
3467        // ICE-CONTROLLED handled elswhere
3468        builder
3469            .add_attribute(&RawAttribute::new(
3470                0x8029.into(),
3471                &[0x93, 0x2f, 0xf9, 0xb1, 0x51, 0x26, 0x3b, 0x36],
3472            ))
3473            .unwrap();
3474
3475        // USERNAME
3476        assert!(msg.has_attribute(Username::TYPE));
3477        let raw = msg.raw_attribute(Username::TYPE).unwrap();
3478        assert!(Username::try_from(&raw).is_ok());
3479        let username = Username::try_from(&raw).unwrap();
3480        assert_eq!(username.username(), "evtj:h6vY");
3481        builder.add_attribute(&username).unwrap();
3482
3483        // MESSAGE_INTEGRITY
3484        let credentials = MessageIntegrityCredentials::ShortTerm(ShortTermCredentials {
3485            password: "VOkJxbRl1RmTxUk/WvJxBt".to_owned(),
3486        });
3487        assert!(matches!(
3488            msg.validate_integrity(&credentials),
3489            Ok(IntegrityAlgorithm::Sha1)
3490        ));
3491        builder
3492            .add_message_integrity(&credentials, IntegrityAlgorithm::Sha1)
3493            .unwrap();
3494
3495        // FINGERPRINT is checked by Message::from_bytes() when present
3496        assert!(msg.has_attribute(Fingerprint::TYPE));
3497        builder.add_fingerprint().unwrap();
3498
3499        // assert that we produce the same output as we parsed in this case
3500        let mut msg_data = builder.finish();
3501        // match the padding bytes with the original
3502        msg_data[73] = 0x20;
3503        msg_data[74] = 0x20;
3504        msg_data[75] = 0x20;
3505        // as a result of the padding difference, the message integrity and fingerpinrt values will
3506        // be different
3507        assert_eq!(msg_data[..80], data[..80]);
3508    }
3509
3510    #[test]
3511    fn rfc5769_vector2() {
3512        let _log = crate::tests::test_init_log();
3513        // https://tools.ietf.org/html/rfc5769#section-2.2
3514        let data = vec![
3515            0x01, 0x01, 0x00, 0x3c, // Response type message length
3516            0x21, 0x12, 0xa4, 0x42, // Magic cookie
3517            0xb7, 0xe7, 0xa7, 0x01, // }
3518            0xbc, 0x34, 0xd6, 0x86, // }  Transaction ID
3519            0xfa, 0x87, 0xdf, 0xae, // }
3520            0x80, 0x22, 0x00, 0x0b, // SOFTWARE attribute header
3521            0x74, 0x65, 0x73, 0x74, //   }
3522            0x20, 0x76, 0x65, 0x63, //   }  UTF-8 server name
3523            0x74, 0x6f, 0x72, 0x20, //   }
3524            0x00, 0x20, 0x00, 0x08, // XOR-MAPPED-ADDRESS attribute header
3525            0x00, 0x01, 0xa1, 0x47, //   Address family (IPv4) and xor'd mapped port number
3526            0xe1, 0x12, 0xa6, 0x43, //   Xor'd mapped IPv4 address
3527            0x00, 0x08, 0x00, 0x14, //   MESSAGE-INTEGRITY attribute header
3528            0x2b, 0x91, 0xf5, 0x99, // }
3529            0xfd, 0x9e, 0x90, 0xc3, // }
3530            0x8c, 0x74, 0x89, 0xf9, // }  HMAC-SHA1 fingerprint
3531            0x2a, 0xf9, 0xba, 0x53, // }
3532            0xf0, 0x6b, 0xe7, 0xd7, // }
3533            0x80, 0x28, 0x00, 0x04, //  FINGERPRINT attribute header
3534            0xc0, 0x7d, 0x4c, 0x96, //  CRC32 fingerprint
3535        ];
3536
3537        let msg = Message::from_bytes(&data).unwrap();
3538        assert!(msg.has_class(MessageClass::Success));
3539        assert!(msg.has_method(BINDING));
3540        assert_eq!(msg.transaction_id(), 0xb7e7_a701_bc34_d686_fa87_dfae.into());
3541        let mut builder = Message::builder(
3542            MessageType::from_class_method(MessageClass::Success, BINDING),
3543            msg.transaction_id(),
3544            MessageWriteVec::new(),
3545        );
3546
3547        // SOFTWARE
3548        assert!(msg.has_attribute(Software::TYPE));
3549        let raw = msg.raw_attribute(Software::TYPE).unwrap();
3550        assert!(Software::try_from(&raw).is_ok());
3551        let software = Software::try_from(&raw).unwrap();
3552        assert_eq!(software.software(), "test vector");
3553        builder.add_attribute(&software).unwrap();
3554
3555        // XOR_MAPPED_ADDRESS
3556        assert!(msg.has_attribute(XorMappedAddress::TYPE));
3557        let raw = msg.raw_attribute(XorMappedAddress::TYPE).unwrap();
3558        assert!(XorMappedAddress::try_from(&raw).is_ok());
3559        let xor_mapped_addres = XorMappedAddress::try_from(&raw).unwrap();
3560        assert_eq!(
3561            xor_mapped_addres.addr(msg.transaction_id()),
3562            "192.0.2.1:32853".parse().unwrap()
3563        );
3564        builder.add_attribute(&xor_mapped_addres).unwrap();
3565
3566        // MESSAGE_INTEGRITY
3567        let credentials = MessageIntegrityCredentials::ShortTerm(ShortTermCredentials {
3568            password: "VOkJxbRl1RmTxUk/WvJxBt".to_owned(),
3569        });
3570        let ret = msg.validate_integrity(&credentials);
3571        warn!("{:?}", ret);
3572        assert!(matches!(ret, Ok(IntegrityAlgorithm::Sha1)));
3573        builder
3574            .add_message_integrity(&credentials, IntegrityAlgorithm::Sha1)
3575            .unwrap();
3576
3577        // FINGERPRINT is checked by Message::from_bytes() when present
3578        assert!(msg.has_attribute(Fingerprint::TYPE));
3579        builder.add_fingerprint().unwrap();
3580
3581        // assert that we produce the same output as we parsed in this case
3582        let mut msg_data = builder.finish();
3583        // match the padding bytes with the original
3584        msg_data[35] = 0x20;
3585        assert_eq!(msg_data[..52], data[..52]);
3586    }
3587
3588    #[test]
3589    fn rfc5769_vector3() {
3590        let _log = crate::tests::test_init_log();
3591        // https://tools.ietf.org/html/rfc5769#section-2.3
3592        let data = vec![
3593            0x01, 0x01, 0x00, 0x48, // Response type and message length
3594            0x21, 0x12, 0xa4, 0x42, // Magic cookie
3595            0xb7, 0xe7, 0xa7, 0x01, // }
3596            0xbc, 0x34, 0xd6, 0x86, // }  Transaction ID
3597            0xfa, 0x87, 0xdf, 0xae, // }
3598            0x80, 0x22, 0x00, 0x0b, //    SOFTWARE attribute header
3599            0x74, 0x65, 0x73, 0x74, // }
3600            0x20, 0x76, 0x65, 0x63, // }  UTF-8 server name
3601            0x74, 0x6f, 0x72, 0x20, // }
3602            0x00, 0x20, 0x00, 0x14, //    XOR-MAPPED-ADDRESS attribute header
3603            0x00, 0x02, 0xa1, 0x47, //    Address family (IPv6) and xor'd mapped port number
3604            0x01, 0x13, 0xa9, 0xfa, // }
3605            0xa5, 0xd3, 0xf1, 0x79, // }  Xor'd mapped IPv6 address
3606            0xbc, 0x25, 0xf4, 0xb5, // }
3607            0xbe, 0xd2, 0xb9, 0xd9, // }
3608            0x00, 0x08, 0x00, 0x14, //    MESSAGE-INTEGRITY attribute header
3609            0xa3, 0x82, 0x95, 0x4e, // }
3610            0x4b, 0xe6, 0x7b, 0xf1, // }
3611            0x17, 0x84, 0xc9, 0x7c, // }  HMAC-SHA1 fingerprint
3612            0x82, 0x92, 0xc2, 0x75, // }
3613            0xbf, 0xe3, 0xed, 0x41, // }
3614            0x80, 0x28, 0x00, 0x04, //    FINGERPRINT attribute header
3615            0xc8, 0xfb, 0x0b, 0x4c, //    CRC32 fingerprint
3616        ];
3617
3618        let msg = Message::from_bytes(&data).unwrap();
3619        assert!(msg.has_class(MessageClass::Success));
3620        assert!(msg.has_method(BINDING));
3621        assert_eq!(msg.transaction_id(), 0xb7e7_a701_bc34_d686_fa87_dfae.into());
3622        let mut builder = Message::builder(
3623            MessageType::from_class_method(MessageClass::Success, BINDING),
3624            msg.transaction_id(),
3625            MessageWriteVec::new(),
3626        );
3627
3628        // SOFTWARE
3629        assert!(msg.has_attribute(Software::TYPE));
3630        let raw = msg.raw_attribute(Software::TYPE).unwrap();
3631        assert!(Software::try_from(&raw).is_ok());
3632        let software = Software::try_from(&raw).unwrap();
3633        assert_eq!(software.software(), "test vector");
3634        builder.add_attribute(&software).unwrap();
3635
3636        // XOR_MAPPED_ADDRESS
3637        assert!(msg.has_attribute(XorMappedAddress::TYPE));
3638        let raw = msg.raw_attribute(XorMappedAddress::TYPE).unwrap();
3639        assert!(XorMappedAddress::try_from(&raw).is_ok());
3640        let xor_mapped_addres = XorMappedAddress::try_from(&raw).unwrap();
3641        assert_eq!(
3642            xor_mapped_addres.addr(msg.transaction_id()),
3643            "[2001:db8:1234:5678:11:2233:4455:6677]:32853"
3644                .parse()
3645                .unwrap()
3646        );
3647        builder.add_attribute(&xor_mapped_addres).unwrap();
3648
3649        // MESSAGE_INTEGRITY
3650        let credentials = MessageIntegrityCredentials::ShortTerm(ShortTermCredentials {
3651            password: "VOkJxbRl1RmTxUk/WvJxBt".to_owned(),
3652        });
3653        assert!(matches!(
3654            msg.validate_integrity(&credentials),
3655            Ok(IntegrityAlgorithm::Sha1)
3656        ));
3657        builder
3658            .add_message_integrity(&credentials, IntegrityAlgorithm::Sha1)
3659            .unwrap();
3660
3661        // FINGERPRINT is checked by Message::from_bytes() when present
3662        assert!(msg.has_attribute(Fingerprint::TYPE));
3663        builder.add_fingerprint().unwrap();
3664
3665        // assert that we produce the same output as we parsed in this case
3666        let mut msg_data = builder.finish();
3667        // match the padding bytes with the original
3668        msg_data[35] = 0x20;
3669        assert_eq!(msg_data[..64], data[..64]);
3670    }
3671
3672    #[test]
3673    fn rfc5769_vector4() {
3674        let _log = crate::tests::test_init_log();
3675        // https://tools.ietf.org/html/rfc5769#section-2.4
3676        let data = vec![
3677            0x00, 0x01, 0x00, 0x60, //    Request type and message length
3678            0x21, 0x12, 0xa4, 0x42, //    Magic cookie
3679            0x78, 0xad, 0x34, 0x33, // }
3680            0xc6, 0xad, 0x72, 0xc0, // }  Transaction ID
3681            0x29, 0xda, 0x41, 0x2e, // }
3682            0x00, 0x06, 0x00, 0x12, //    USERNAME attribute header
3683            0xe3, 0x83, 0x9e, 0xe3, // }
3684            0x83, 0x88, 0xe3, 0x83, // }
3685            0xaa, 0xe3, 0x83, 0x83, // }  Username value (18 bytes) and padding (2 bytes)
3686            0xe3, 0x82, 0xaf, 0xe3, // }
3687            0x82, 0xb9, 0x00, 0x00, // }
3688            0x00, 0x15, 0x00, 0x1c, //    NONCE attribute header
3689            0x66, 0x2f, 0x2f, 0x34, // }
3690            0x39, 0x39, 0x6b, 0x39, // }
3691            0x35, 0x34, 0x64, 0x36, // }
3692            0x4f, 0x4c, 0x33, 0x34, // }  Nonce value
3693            0x6f, 0x4c, 0x39, 0x46, // }
3694            0x53, 0x54, 0x76, 0x79, // }
3695            0x36, 0x34, 0x73, 0x41, // }
3696            0x00, 0x14, 0x00, 0x0b, //    REALM attribute header
3697            0x65, 0x78, 0x61, 0x6d, // }
3698            0x70, 0x6c, 0x65, 0x2e, // }  Realm value (11 bytes) and padding (1 byte)
3699            0x6f, 0x72, 0x67, 0x00, // }
3700            0x00, 0x08, 0x00, 0x14, //    MESSAGE-INTEGRITY attribute header
3701            0xf6, 0x70, 0x24, 0x65, // }
3702            0x6d, 0xd6, 0x4a, 0x3e, // }
3703            0x02, 0xb8, 0xe0, 0x71, // }  HMAC-SHA1 fingerprint
3704            0x2e, 0x85, 0xc9, 0xa2, // }
3705            0x8c, 0xa8, 0x96, 0x66, // }
3706        ];
3707
3708        let msg = Message::from_bytes(&data).unwrap();
3709        assert!(msg.has_class(MessageClass::Request));
3710        assert!(msg.has_method(BINDING));
3711        assert_eq!(msg.transaction_id(), 0x78ad_3433_c6ad_72c0_29da_412e.into());
3712        let mut builder = Message::builder(
3713            MessageType::from_class_method(MessageClass::Request, BINDING),
3714            msg.transaction_id(),
3715            MessageWriteVec::new(),
3716        );
3717
3718        let username = stringprep::saslprep("\u{30DE}\u{30C8}\u{30EA}\u{30C3}\u{30AF}\u{30B9}")
3719            .unwrap()
3720            .into_owned();
3721        let password = stringprep::saslprep("The\u{00AD}M\u{00AA}tr\u{2168}")
3722            .unwrap()
3723            .into_owned();
3724        trace!("password: {password:?}");
3725
3726        let long_term = LongTermKeyCredentials {
3727            username,
3728            password,
3729            realm: "example.org".to_owned(),
3730        };
3731        // USERNAME
3732        assert!(msg.has_attribute(Username::TYPE));
3733        let raw = msg.raw_attribute(Username::TYPE).unwrap();
3734        assert!(Username::try_from(&raw).is_ok());
3735        let username = Username::try_from(&raw).unwrap();
3736        assert_eq!(username.username(), &long_term.username);
3737        builder.add_attribute(&username).unwrap();
3738
3739        // NONCE
3740        let expected_nonce = "f//499k954d6OL34oL9FSTvy64sA";
3741        assert!(msg.has_attribute(Nonce::TYPE));
3742        let raw = msg.raw_attribute(Nonce::TYPE).unwrap();
3743        assert!(Nonce::try_from(&raw).is_ok());
3744        let nonce = Nonce::try_from(&raw).unwrap();
3745        assert_eq!(nonce.nonce(), expected_nonce);
3746        builder.add_attribute(&nonce).unwrap();
3747
3748        // REALM
3749        assert!(msg.has_attribute(Realm::TYPE));
3750        let raw = msg.raw_attribute(Realm::TYPE).unwrap();
3751        assert!(Realm::try_from(&raw).is_ok());
3752        let realm = Realm::try_from(&raw).unwrap();
3753        assert_eq!(realm.realm(), long_term.realm());
3754        builder.add_attribute(&realm).unwrap();
3755
3756        // MESSAGE_INTEGRITY
3757        let credentials = MessageIntegrityCredentials::LongTerm(long_term);
3758        assert!(matches!(
3759            msg.validate_integrity(&credentials),
3760            Ok(IntegrityAlgorithm::Sha1)
3761        ));
3762        builder
3763            .add_message_integrity(&credentials, IntegrityAlgorithm::Sha1)
3764            .unwrap();
3765
3766        assert_eq!(builder.finish()[4..], data[4..]);
3767    }
3768
3769    #[test]
3770    fn rfc8489_vector1() {
3771        let _log = crate::tests::test_init_log();
3772        // https://www.rfc-editor.org/rfc/rfc8489#appendix-B.1
3773        // https://www.rfc-editor.org/errata/eid6268
3774        let data = vec![
3775            0x00, 0x01, 0x00, 0x90, //     Request type and message length
3776            0x21, 0x12, 0xa4, 0x42, //     Magic cookie
3777            0x78, 0xad, 0x34, 0x33, //  }
3778            0xc6, 0xad, 0x72, 0xc0, //  }  Transaction ID
3779            0x29, 0xda, 0x41, 0x2e, //  }
3780            0x00, 0x1e, 0x00, 0x20, //     USERHASH attribute header
3781            0x4a, 0x3c, 0xf3, 0x8f, //  }
3782            0xef, 0x69, 0x92, 0xbd, //  }
3783            0xa9, 0x52, 0xc6, 0x78, //  }
3784            0x04, 0x17, 0xda, 0x0f, //  }  Userhash value (32 bytes)
3785            0x24, 0x81, 0x94, 0x15, //  }
3786            0x56, 0x9e, 0x60, 0xb2, //  }
3787            0x05, 0xc4, 0x6e, 0x41, //  }
3788            0x40, 0x7f, 0x17, 0x04, //  }
3789            0x00, 0x15, 0x00, 0x29, //     NONCE attribute header
3790            0x6f, 0x62, 0x4d, 0x61, //  }
3791            0x74, 0x4a, 0x6f, 0x73, //  }
3792            0x32, 0x41, 0x41, 0x41, //  }
3793            0x43, 0x66, 0x2f, 0x2f, //  }
3794            0x34, 0x39, 0x39, 0x6b, //  }  Nonce value and padding (3 bytes)
3795            0x39, 0x35, 0x34, 0x64, //  }
3796            0x36, 0x4f, 0x4c, 0x33, //  }
3797            0x34, 0x6f, 0x4c, 0x39, //  }
3798            0x46, 0x53, 0x54, 0x76, //  }
3799            0x79, 0x36, 0x34, 0x73, //  }
3800            0x41, 0x00, 0x00, 0x00, //  }
3801            0x00, 0x14, 0x00, 0x0b, //     REALM attribute header
3802            0x65, 0x78, 0x61, 0x6d, //  }
3803            0x70, 0x6c, 0x65, 0x2e, //  }  Realm value (11 bytes) and padding (1 byte)
3804            0x6f, 0x72, 0x67, 0x00, //  }
3805            0x00, 0x1d, 0x00, 0x04, //    PASSWORD-ALGORITHM attribute header
3806            0x00, 0x02, 0x00, 0x00, //    PASSWORD-ALGORITHM value (4 bytes)
3807            0x00, 0x1c, 0x00, 0x20, //    MESSAGE-INTEGRITY-SHA256 attribute header
3808            0xb5, 0xc7, 0xbf, 0x00, // }
3809            0x5b, 0x6c, 0x52, 0xa2, // }
3810            0x1c, 0x51, 0xc5, 0xe8, // }
3811            0x92, 0xf8, 0x19, 0x24, // }  HMAC-SHA256 value
3812            0x13, 0x62, 0x96, 0xcb, // }
3813            0x92, 0x7c, 0x43, 0x14, // }
3814            0x93, 0x09, 0x27, 0x8c, // }
3815            0xc6, 0x51, 0x8e, 0x65, // }
3816        ];
3817        let msg = Message::from_bytes(&data).unwrap();
3818        assert!(msg.has_class(MessageClass::Request));
3819        assert!(msg.has_method(BINDING));
3820        assert_eq!(msg.transaction_id(), 0x78ad_3433_c6ad_72c0_29da_412e.into());
3821        let mut builder = Message::builder(
3822            MessageType::from_class_method(MessageClass::Request, BINDING),
3823            msg.transaction_id(),
3824            MessageWriteVec::new(),
3825        );
3826
3827        let opaque = precis_profiles::OpaqueString::new();
3828        let username = opaque
3829            .prepare("\u{30DE}\u{30C8}\u{30EA}\u{30C3}\u{30AF}\u{30B9}")
3830            .unwrap()
3831            .into_owned();
3832        let orig_password = "The\u{00AD}M\u{00AA}tr\u{2168}";
3833        trace!("password: {orig_password:?}");
3834        /*
3835        let additional_password = opaque
3836            .additional_mapping_rule(orig_password)
3837            .unwrap()
3838            .into_owned();
3839        trace!("password (additional): {additional_password}");
3840        let normalized_password = opaque
3841            .normalization_rule(orig_password)
3842            .unwrap()
3843            .into_owned();
3844        trace!("password (normalized): {normalized_password}");
3845        let additional_then_normalized_password = opaque
3846            .normalization_rule(&additional_password)
3847            .unwrap()
3848            .into_owned();
3849        trace!("password (additional-then-normalized): {additional_then_normalized_password}");
3850        let normalized_then_additional_password = opaque
3851            .additional_mapping_rule(&normalized_password)
3852            .unwrap()
3853            .into_owned();
3854        trace!("password (normalized-then-additional): {normalized_then_additional_password}");
3855        */
3856        let sasl_password = stringprep::saslprep(orig_password).unwrap().into_owned();
3857        trace!("password (saslprep): {sasl_password}");
3858
3859        // XXX: should really be the OpaqueString value however that does not correctly remove
3860        // \u{00AD} that SASLprep did as required by RFC8489.
3861        let long_term = LongTermKeyCredentials {
3862            username: username.clone(),
3863            password: sasl_password.clone(),
3864            realm: "example.org".to_owned(),
3865        };
3866        // USERHASH
3867        assert!(msg.has_attribute(Userhash::TYPE));
3868        let raw = msg.raw_attribute(Userhash::TYPE).unwrap();
3869        assert!(Userhash::try_from(&raw).is_ok());
3870        let userhash = Userhash::try_from(&raw).unwrap();
3871        builder.add_attribute(&userhash).unwrap();
3872
3873        // NONCE
3874        let expected_nonce = "obMatJos2AAACf//499k954d6OL34oL9FSTvy64sA";
3875        assert!(msg.has_attribute(Nonce::TYPE));
3876        let raw = msg.raw_attribute(Nonce::TYPE).unwrap();
3877        assert!(Nonce::try_from(&raw).is_ok());
3878        let nonce = Nonce::try_from(&raw).unwrap();
3879        assert_eq!(nonce.nonce(), expected_nonce);
3880        builder.add_attribute(&nonce).unwrap();
3881
3882        // REALM
3883        assert!(msg.has_attribute(Realm::TYPE));
3884        let raw = msg.raw_attribute(Realm::TYPE).unwrap();
3885        assert!(Realm::try_from(&raw).is_ok());
3886        let realm = Realm::try_from(&raw).unwrap();
3887        assert_eq!(realm.realm(), long_term.realm);
3888        builder.add_attribute(&realm).unwrap();
3889
3890        // PASSWORD_ALGORITHM
3891        assert!(msg.has_attribute(PasswordAlgorithm::TYPE));
3892        let raw = msg.raw_attribute(PasswordAlgorithm::TYPE).unwrap();
3893        assert!(PasswordAlgorithm::try_from(&raw).is_ok());
3894        let algo = PasswordAlgorithm::try_from(&raw).unwrap();
3895        assert_eq!(algo.algorithm(), PasswordAlgorithmValue::SHA256);
3896        builder.add_attribute(&algo).unwrap();
3897
3898        // MESSAGE_INTEGRITY_SHA256
3899        /*
3900        for pass in [
3901            orig_password.to_owned(),
3902            sasl_password,
3903            normalized_password,
3904            additional_password,
3905            additional_then_normalized_password,
3906            normalized_then_additional_password,
3907        ] {
3908            let long_term = LongTermCredentials {
3909                username: username.clone(),
3910                password: pass,
3911                realm: "example.org".to_owned(),
3912            };
3913            trace!("long term: {long_term:?}");
3914            let credentials = MessageIntegrityCredentials::LongTerm(long_term);
3915            trace!("{:?}", msg.validate_integrity(&credentials));
3916        }
3917        */
3918        trace!("long term: {long_term:?}");
3919        let credentials = MessageIntegrityCredentials::LongTerm(long_term);
3920        assert!(matches!(
3921            msg.validate_integrity(&credentials),
3922            Ok(IntegrityAlgorithm::Sha256)
3923        ));
3924        builder
3925            .add_message_integrity(&credentials, IntegrityAlgorithm::Sha256)
3926            .unwrap();
3927
3928        assert_eq!(builder.finish()[4..], data[4..]);
3929    }
3930}