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