RFC 8489

Session Traversal Utilities for NAT (STUN)

๐Ÿ“… published February 2020, from ietf

Session Traversal Utilities for NAT (STUN) ๐Ÿฆ‹

okay so bestie, this is RFC 8489 ๐Ÿ’– It's an Internet Standards Track doc from the IETF (Internet Engineering Task Force), published February 2020. It's giving official protocol energy โœจ The authors are M. Petit-Huguenin (Impedance Mismatch), G. Salgueiro (Cisco), J. Rosenberg (Five9), D. Wing (Citrix), R. Mahy (Unaffiliated), and P. Matthews (Nokia) ๐Ÿซถ It's also the ISSN 2070-1721 one, and it obsoletes RFC 5389, so that older version is officially replaced now ๐Ÿ’…

Abstract ๐ŸŒธ

okay so Session Traversal Utilities for NAT (STUN) is a protocol that acts as a tool for other protocols dealing with NAT traversal ๐Ÿงš An endpoint can use it to find out the IP address and port a NAT allocated to it. It can also check connectivity between two endpoints, and it works as a keep-alive to keep NAT bindings alive ๐Ÿ”ฅ The best part is that STUN works with tons of existing NATs and doesn't need any special behavior from them. no cap, that's so iconic ๐Ÿ‘‘

STUN is not a NAT traversal solution by itself ๐Ÿ™ˆ It's a tool you use inside a NAT traversal solution, so think of it as a helper, not the whole main character ๐Ÿ’œ

This document obsoletes RFC 5389 โœจ

Status of This Memo ๐Ÿ’–

This is an Internet Standards Track document ๐ŸŽ€

It's a product of the IETF, and it represents the consensus of the IETF community ๐Ÿซถ It got public review and was approved for publication by the Internet Engineering Steering Group (IESG). If you want more info on Internet Standards, check out Section 2 of RFC 7841 ๐Ÿ“š

For the current status of this document, any errata, and how to give feedback, go to https://www.rfc-editor.org/info/rfc8489 ๐Ÿฆ‹

Copyright (c) 2020 IETF Trust and the persons identified as the document authors. All rights reserved ๐Ÿ’…

This document is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) as they stand on the date this document was published. Please read these carefully, bestie, because they explain your rights and restrictions for this document ๐Ÿ™ˆ Any Code Components pulled out of this document must include Simplified BSD License text, as described in Section 4.e of the Trust Legal Provisions. They come without warranty, as described in the Simplified BSD License โš ๏ธ

Table of Contents ๐Ÿงš

1. Introduction ....................................................4
2. Overview of Operation ...........................................5
3. Terminology .....................................................7
4. Definitions .....................................................7
5. STUN Message Structure ..........................................9
6. Base Protocol Procedures .......................................11
   6.1. Forming a Request or an Indication ........................11
   6.2. Sending the Request or Indication .........................12
        6.2.1. Sending over UDP or DTLS-over-UDP ..................13
        6.2.2. Sending over TCP or TLS-over-TCP ...................14
        6.2.3. Sending over TLS-over-TCP or DTLS-over-UDP .........15
   6.3. Receiving a STUN Message ..................................16
        6.3.1. Processing a Request ...............................17
               6.3.1.1. Forming a Success or Error Response .......17
               6.3.1.2. Sending the Success or Error Response .....18
        6.3.2. Processing an Indication ...........................18
        6.3.3. Processing a Success Response ......................19
        6.3.4. Processing an Error Response .......................19
7. FINGERPRINT Mechanism ..........................................20
8. DNS Discovery of a Server ......................................20
   8.1. STUN URI Scheme Semantics .................................21
9. Authentication and Message-Integrity Mechanisms ................22
   9.1. Short-Term Credential Mechanism ...........................23
        9.1.1. HMAC Key ...........................................23
        9.1.2. Forming a Request or Indication ....................23
        9.1.3. Receiving a Request or Indication ..................23
        9.1.4. Receiving a Response ...............................25
        9.1.5. Sending Subsequent Requests ........................25
   9.2. Long-Term Credential Mechanism ............................26
        9.2.1. Bid-Down Attack Prevention .........................27
        9.2.2. HMAC Key ...........................................27
        9.2.3. Forming a Request ..................................28
               9.2.3.1. First Request .............................28
               9.2.3.2. Subsequent Requests .......................29
        9.2.4. Receiving a Request ................................29
        9.2.5. Receiving a Response ...............................31
10. ALTERNATE-SERVER Mechanism ....................................33
11. Backwards Compatibility with RFC 3489 .........................34
12. Basic Server Behavior .........................................34
13. STUN Usages ...................................................35
14. STUN Attributes ...............................................36
   14.1. MAPPED-ADDRESS ...........................................37
   14.2. XOR-MAPPED-ADDRESS .......................................38
   14.3. USERNAME .................................................39
   14.4. USERHASH .................................................40
   14.5. MESSAGE-INTEGRITY ........................................40
   14.6. MESSAGE-INTEGRITY-SHA256 .................................41
   14.7. FINGERPRINT ..............................................41
   14.8. ERROR-CODE ...............................................42
   14.9. REALM ....................................................44
   14.10. NONCE ...................................................44
   14.11. PASSWORD-ALGORITHMS .....................................44
   14.12. PASSWORD-ALGORITHM ......................................45
   14.13. UNKNOWN-ATTRIBUTES ......................................45
   14.14. SOFTWARE ................................................46
   14.15. ALTERNATE-SERVER ........................................46
   14.16. ALTERNATE-DOMAIN ........................................46
15. Operational Considerations ....................................47
16. Security Considerations .......................................47
   16.1. Attacks against the Protocol .............................47
        16.1.1. Outside Attacks ...................................47
        16.1.2. Inside Attacks ....................................48
        16.1.3. Bid-Down Attacks ..................................48
   16.2. Attacks Affecting the Usage ..............................50
        16.2.1. Attack I: Distributed DoS (DDoS) against a
                Target ............................................51
        16.2.2. Attack II: Silencing a Client .....................51
        16.2.3. Attack III: Assuming the Identity of a Client .....52
        16.2.4. Attack IV: Eavesdropping ..........................52
   16.3. Hash Agility Plan ........................................52
17. IAB Considerations ............................................53
18. IANA Considerations ...........................................53
   18.1. STUN Security Features Registry ..........................53
   18.2. STUN Methods Registry ....................................54
   18.3. STUN Attributes Registry .................................54
        18.3.1. Updated Attributes ................................55
        18.3.2. New Attributes ....................................55
   18.4. STUN Error Codes Registry ................................56
   18.5. STUN Password Algorithms Registry ........................56
        18.5.1. Password Algorithms ...............................57
               18.5.1.1. MD5 ......................................57
               18.5.1.2. SHA-256 ..................................57
   18.6. STUN UDP and TCP Port Numbers ............................57
19. Changes since RFC 5389 ........................................57
20. References ....................................................58
   20.1. Normative References .....................................58
   20.2. Informative References ...................................61
Appendix A.  C Snippet to Determine STUN Message Types ............64
Appendix B.  Test Vectors .........................................64
  B.1.  Sample Request with Long-Term Authentication with
        MESSAGE-INTEGRITY-SHA256 and USERHASH .....................65
Acknowledgements ..................................................66
Contributors ......................................................66
Authors' Addresses ................................................67

1. Introduction โœจ

okay so this spec defines Session Traversal Utilities for NAT (STUN), and it's a tool for dealing with Network Address Translators (NATs) ๐Ÿงš It gives an endpoint a way to find out the IP address and port that a NAT allocated, matching its private IP address and port ๐Ÿฆ‹ It also gives endpoints a way to keep a NAT binding alive ๐Ÿ’– With some extensions, STUN can do connectivity checks between two endpoints [RFC8445] or relay packets between two endpoints [RFC5766] ๐Ÿ”ฅ

Staying true to its tool nature, this spec defines an extensible packet format, defines how it operates over several transport protocols, and provides two forms of authentication ๐Ÿ’…

STUN is meant to be used in the context of one or more NAT traversal solutions ๐ŸŒˆ These solutions are called "STUN Usages" โœจ Each usage describes how STUN gets used to achieve the NAT traversal solution ๐Ÿ‘‘ Usually, a usage says when STUN messages get sent, which optional attributes to include, what server gets used, and what authentication mechanism is to be used ๐Ÿซถ Interactive Connectivity Establishment (ICE) [RFC8445] is one usage of STUN ๐Ÿ’œ SIP Outbound [RFC5626] is another usage of STUN ๐ŸŽ€ In some cases, a usage will require extensions to STUN ๐Ÿ™ˆ A STUN extension can come in the form of new methods, attributes, or error response codes ๐Ÿ“ More info on STUN Usages is in Section 13 ๐Ÿ“š

2. Overview of Operation โœจ

This section is descriptive only. ๐ŸŽ€

                       /-----\
                     // STUN  \\
                    |   Server  |
                     \\       //
                       \-----/




                  +--------------+             Public Internet
  ................|     NAT 2    |.......................
                  +--------------+



                  +--------------+             Private Network 2
  ................|     NAT 1    |.......................
                  +--------------+




                       /-----\
                     // STUN  \\
                    |   Client  |
                     \\       //               Private Network 1
                       \-----/

             Figure 1: One Possible STUN Configuration

okay so bestie, look at Figure 1 ๐Ÿฆ‹ this is one possible STUN setup, and it's giving clean layout. There are two entities (called STUN agents) that implement the STUN protocol. The lower agent in the figure is the client, chilling on private network 1. That network connects to private network 2 through NAT 1, and private network 2 connects to the public Internet through NAT 2. The upper agent is the server, and it lives on the public Internet ๐ŸŒˆ

STUN is a client-server protocol, and it supports two types of transactions ๐Ÿ’… The first is a request/response transaction, where a client sends a request to a server and the server sends back a response. The second is an indication transaction, where either agent (client or server) sends an indication and it generates no response. Both types include a transaction ID, which is a randomly selected 96-bit number โœจ For request/response transactions, that ID lets the client match the response to the request that made it. For indications, the transaction ID is just a debugging aid ๐Ÿ™ˆ

Every STUN message starts with a fixed header that has a method, a class, and the transaction ID. The method tells you which request or indication this is. This specification defines just one method, Binding, but other methods are expected to be defined in other documents ๐Ÿงš The class tells you whether the message is a request, a success response, an error response, or an indication. After the fixed header come zero or more attributes, which are Type-Length-Value extensions that carry extra info for that specific message ๐Ÿ’œ

This document defines a single method called "Binding" ๐Ÿ‘‘ The Binding method can be used in request/response transactions or in indication transactions. In request/response transactions, it can be used to find out the particular binding a NAT has allocated to a STUN client. In either kind of transaction, it can also be used to keep those bindings alive ๐Ÿซถ

Here's the Binding flow, iykyk. A Binding request goes from a STUN client to a STUN server. When it arrives, it may have passed through one or more NATs between them (in Figure 1, there are two). As the request passes through a NAT, the NAT modifies the source transport address (that's the source IP address and source port) of the packet. So the source transport address the server receives will be the public IP address and port created by the NAT closest to the server. This is called a "reflexive transport address" ๐Ÿฆ‹ The STUN server copies that source transport address into an XOR-MAPPED-ADDRESS attribute in the Binding response and sends the response back to the client. On the way back through a NAT, the NAT modifies the destination transport address in the IP header, but the transport address inside the XOR-MAPPED-ADDRESS attribute in the body stays untouched ๐Ÿ’– So the client can learn its reflexive transport address, the one allocated by the outermost NAT with respect to the STUN server. Main character energy, literally ๐Ÿ‘‘

Some usages have to multiplex STUN with other protocols (e.g., [RFC8445] and [RFC5626]). In those usages, there has to be a way to inspect a packet and tell whether it's a STUN packet or not. STUN gives you three fields in the STUN header with fixed values that can be used for this purpose ๐ŸŒธ If that's not enough, STUN packets can also contain a FINGERPRINT value, which can further be used to tell packets apart ๐Ÿ”ฅ

STUN defines a set of optional procedures that a usage can choose to use, called "mechanisms" ๐Ÿ“ These include DNS discovery, a redirection technique to an alternate server, a fingerprint attribute for demultiplexing, and two authentication and message-integrity exchanges. The authentication mechanisms revolve around a username, a password, and a message-integrity value. Two of them, the long-term credential mechanism and the short-term credential mechanism, are defined in this specification. Each usage specifies which mechanisms are allowed with that usage ๐Ÿ’…

In the long-term credential mechanism, the client and server share a pre-provisioned username and password, and they do a digest challenge/response exchange inspired by the one defined for HTTP [RFC7616] but different in the details ๐ŸŽ€ In the short-term credential mechanism, the client and server swap a username and password through some out-of-band method before the STUN exchange. For example, in the ICE usage [RFC8445], the two endpoints use out-of-band signaling to exchange a username and password. These are used to integrity protect and authenticate the request and response. And there's no challenge or nonce used, so no extra back-and-forth ๐Ÿซง


3. Terminology ๐Ÿ’œ

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in BCP 14 [RFC2119] [RFC8174] when, and only when, they appear in all capitals, as shown here ๐Ÿ™โœจ

4. Definitions ๐Ÿ“–

Okay, let's get the vocab down so we're on the same page, bestie ๐Ÿซถ

STUN Agent: A STUN agent is an entity that implements the STUN protocol. The entity can be either a STUN client or a STUN server. ๐Ÿงš

STUN Client: A STUN client is an entity that sends STUN requests and receives STUN responses and STUN indications. A STUN client can also send indications. In this specification, the terms "STUN client" and "client" are synonymous. ๐Ÿฆ‹

STUN Server: A STUN server is an entity that receives STUN requests and STUN indications and that sends STUN responses. A STUN server can also send indications. In this specification, the terms "STUN server" and "server" are synonymous. ๐ŸŒˆ

Transport Address: The combination of an IP address and port number (such as a UDP or TCP port number). ๐ŸŒธ

Reflexive Transport Address: A transport address learned by a client that identifies that client as seen by another host on an IP network, typically a STUN server. When there is an intervening NAT between the client and the other host, the reflexive transport address represents the mapped address allocated to the client on the public side of the NAT. Reflexive transport addresses are learned from the mapped address attribute (MAPPED-ADDRESS or XOR-MAPPED-ADDRESS) in STUN responses. ๐Ÿ’–

Mapped Address: Same meaning as reflexive address. This term is retained only for historic reasons and due to the naming of the MAPPED-ADDRESS and XOR-MAPPED-ADDRESS attributes. ๐Ÿ™ˆ

Long-Term Credential: A username and associated password that represent a shared secret between client and server. Long-term credentials are generally granted to the client when a subscriber enrolls in a service and persist until the subscriber leaves the service or explicitly changes the credential. ๐Ÿ‘‘

Long-Term Password: The password from a long-term credential. ๐ŸŽ€

Short-Term Credential: A temporary username and associated password that represent a shared secret between client and server. Short-term credentials are obtained through some kind of protocol mechanism between the client and server, preceding the STUN exchange. A short-term credential has an explicit temporal scope, which may be based on a specific amount of time (such as 5 minutes) or on an event (such as termination of a Session Initiation Protocol (SIP) [RFC3261] dialog). The specific scope of a short-term credential is defined by the application usage. โณ

Short-Term Password: The password component of a short-term credential. ๐Ÿ”‘

STUN Indication: A STUN message that does not receive a response. ๐Ÿฆ‹

Attribute: The STUN term for a Type-Length-Value (TLV) object that can be added to a STUN message. Attributes are divided into two types: comprehension-required and comprehension-optional. STUN agents can safely ignore comprehension-optional attributes they don't understand, but they cannot successfully process a message if it contains comprehension-required attributes that are not understood. ๐Ÿงฉ

RTO: Retransmission TimeOut, which defines the initial period of time between transmission of a request and the first retransmit of that request. โฐ

5. STUN Message Structure โœจ

okay bestie, so STUN messages are encoded in binary using network order, which is big-endian. That means the most significant byte or octet goes first ๐Ÿ’… The full transmission order is in Appendix B of [RFC0791]. Unless it says otherwise, numeric constants are in decimal (base 10) ๐Ÿ”ข

Every STUN message is a 20-byte header followed by zero or more attributes ๐ŸŽ€ The header holds the message type, the message length, the magic cookie, and the transaction ID ๐Ÿ’–

      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |0 0|     STUN Message Type     |         Message Length        |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                         Magic Cookie                          |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                                                               |
     |                     Transaction ID (96 bits)                  |
     |                                                               |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Figure 2: Format of STUN Message Header ๐Ÿฆ‹

The most significant 2 bits of every STUN message MUST be zeroes ๐Ÿ”’ This is what lets you tell STUN packets apart from other protocols when STUN is multiplexed with them on the same port ๐Ÿ‘€

The message type tells you the message class (request, success response, error response, or indication) and the message method (the main job of the message) ๐Ÿง  There are four message classes, but there are only two kinds of transactions in STUN: request/response transactions (a request message plus a response message) and indication transactions (just one indication message). Response classes are split into error and success responses so the STUN message can be processed quickly โšก

The STUN Message Type field breaks down like this:

                   0                 1
                   2  3  4 5 6 7 8 9 0 1 2 3 4 5
                  +--+--+-+-+-+-+-+-+-+-+-+-+-+-+
                  |M |M |M|M|M|C|M|M|M|C|M|M|M|M|
                  |11|10|9|8|7|1|6|5|4|0|3|2|1|0|
                  +--+--+-+-+-+-+-+-+-+-+-+-+-+-+

Figure 3: Format of STUN Message Type Field ๐Ÿ’œ

Here the bits in the STUN Message Type field go from most significant (M11) down to least significant (M0). M11 through M0 are a 12-bit encoding of the method, and C1 and C0 are a 2-bit encoding of the class. A class of 0b00 is a request, 0b01 is an indication, 0b10 is a success response, and 0b11 is an error response. This specification defines just one method, Binding ๐ŸŒธ The method and class are orthogonal, which means every method can have a request, success response, error response, and indication all at once. Extensions that define new methods MUST indicate which classes are permitted for that method ๐Ÿ“

For example, a Binding request has class=0b00 (request) and method=0b000000000001 (Binding), and it gets encoded into the first 16 bits as 0x0001. A Binding response has class=0b10 (success response) and method=0b000000000001, and it gets encoded into the first 16 bits as 0x0101 โœจ

Note: This unfortunate encoding is due to assignment of values in [RFC3489] that did not consider encoding indication messages, success responses, and errors responses using bit fields. ๐Ÿ™ˆ

The Magic Cookie field MUST contain the fixed value 0x2112A442 in network byte order ๐Ÿ“ In [RFC3489], those 32 bits were part of the transaction ID. Putting the magic cookie in this spot lets a server detect whether the client will understand certain attributes that were added to STUN by [RFC5389]. It also helps tell STUN packets apart from packets of other protocols when STUN is multiplexed with them on the same port ๐Ÿซถ

The transaction ID is a 96-bit identifier that uniquely identifies STUN transactions ๐Ÿ†” For request/response transactions, the STUN client picks the transaction ID for the request, and the server echoes it back in the response. For indications, the agent sending the indication picks it. Its main job is matching requests with responses, though it also plays a small part in preventing certain kinds of attacks ๐Ÿ›ก๏ธ The server also uses the transaction ID as a key to identify each transaction uniquely across all clients. So the transaction ID MUST be uniformly and randomly chosen from the interval 0 .. 2**96-1 and MUST be cryptographically random ๐ŸŽฒ Resends of the same request reuse the same transaction ID, but the client MUST choose a new transaction ID for new transactions, unless the new request is bit-wise identical to the previous request and sent from the same transport address to the same IP address. Success and error responses MUST carry the same transaction ID as their corresponding request. When an agent is acting as a STUN server and a STUN client on the same port, the transaction IDs in the requests it sends have no relationship to the transaction IDs in the requests it receives ๐ŸŒˆ

The message length MUST contain the size of the message in bytes, not including the 20-byte STUN header ๐Ÿ“ All STUN attributes are padded to a multiple of 4 bytes, so the last 2 bits of this field are always zero. That's another handy way to tell STUN packets apart from packets of other protocols ๐Ÿ’…

After the fixed part of the header come zero or more attributes. Each attribute is TLV (Type-Length-Value) encoded ๐Ÿงฉ The details of the encoding, and the attributes themselves, are in Section 14 ๐Ÿ“š


6. Base Protocol Procedures ๐Ÿš€

This section lays out the base procedures of the STUN protocol. It covers how messages are formed, how they get sent, and how they're processed when they arrive ๐Ÿ“ฌ It also defines the detailed processing for the Binding method. Other sections in this document describe optional procedures that a usage may choose to use in certain situations. Other documents may define other STUN extensions by adding new methods, new attributes, or new error response codes ๐ŸŽ€

6.1. Forming a Request or an Indication ๐Ÿง

When you're putting together a request or indication, the agent MUST follow the rules in Section 5 when it creates the header ๐Ÿ“‹ On top of that, the message class MUST be either "Request" or "Indication" (whichever fits), and the method must be either Binding or some method defined in another document ๐Ÿ’–

Then the agent adds any attributes the method or the usage specifies. For example, some usages may say the agent has to use an authentication method (Section 9) or the FINGERPRINT attribute (Section 7) ๐Ÿ”

If the agent is sending a request, it SHOULD add a SOFTWARE attribute to the request. Agents MAY include a SOFTWARE attribute in indications, depending on the method. Extensions to STUN should discuss whether SOFTWARE is useful in new indications. Heads up, though: including a SOFTWARE attribute may have security implications, so check Section 16.1.2 for details ๐Ÿ™ˆ

For the Binding method with no authentication, no attributes are required unless the usage specifies otherwise โœจ

All STUN messages sent over UDP or DTLS-over-UDP [RFC6347] SHOULD be less than the path MTU, if it's known ๐Ÿ“ฆ

If the path MTU is unknown for UDP, messages SHOULD be the smaller of 576 bytes and the first-hop MTU for IPv4 [RFC1122], and 1280 bytes for IPv6 [RFC8200]. This value is the overall size of the IP packet. So for IPv4, the actual STUN message would need to be less than 548 bytes (576 minus the 20-byte IP header, minus the 8-byte UDP header, assuming no IP options are used) ๐Ÿงฎ

If the path MTU is unknown for DTLS-over-UDP, the rules in the previous paragraph need to be adjusted to account for the size of the (13-byte) DTLS Record header, the Message Authentication Code (MAC) size, and the padding size ๐Ÿ”ง

STUN has no way to handle the case where the request is smaller than the MTU but the response is larger than the MTU. It isn't expected to be a problem for STUN ๐Ÿคž The MTU limitation is a SHOULD, not a MUST, to cover cases where STUN itself is being used to probe for MTU characteristics [RFC5780]. See also [STUN-PMTUD] for a framework that uses STUN to add Path MTU Discovery to protocols that lack such a mechanism ๐Ÿ” Outside of this or similar applications, the MTU constraint MUST be followed ๐Ÿšจ

6.2. Sending the Request or Indication ๐Ÿ“ค

Next, the agent sends the request or indication ๐Ÿ’Œ This document specifies how to send STUN messages over UDP, TCP, TLS-over-TCP, or DTLS-over-UDP. Other transport protocols may be added in the future ๐ŸŒธ The STUN Usage must specify which transport protocol is used and how the agent works out the IP address and port of the recipient. Section 8 describes a DNS-based method of finding the IP address and port of a server, which a usage may choose to use ๐Ÿ—บ๏ธ

At any time, a client MAY have multiple outstanding STUN requests with the same STUN server (that is, multiple transactions in progress, each with a different transaction ID) ๐ŸŒ€ Absent other limits on the rate of new transactions (such as those specified by ICE for connectivity checks, or when STUN is run over TCP), a client SHOULD limit itself to ten outstanding transactions to the same server ๐Ÿ™Œ

6.2.1. Sending over UDP or DTLS-over-UDP

okay so bestie, when STUN runs over UDP or DTLS-over-UDP [RFC7350] ๐Ÿฆ‹, the network is allowed to just... drop the message ๐Ÿ˜ญ. So the way STUN gets reliability for request/response transactions is that the client app literally resends its own request ๐Ÿ”. Indications? Not retransmitted at all ๐Ÿ’€, so indication transactions over UDP or DTLS-over-UDP are not reliable. Know your limits, babe ๐Ÿซถ.

A client SHOULD retransmit a STUN request message starting with an interval of RTO ("Retransmission TimeOut"), doubling after each retransmission โœจ. The RTO is basically an estimate of the round-trip time (RTT) ๐ŸŒธ, and it gets computed as described in [RFC6298], with two exceptions ๐Ÿ‘‘. First, the initial value for RTO SHOULD be greater than or equal to 500 ms. The exceptions to this "SHOULD" are when other mechanisms are used to derive congestion thresholds (like the ones defined in ICE for fixed-rate streams) or when STUN is used in non-Internet environments with known network capacities ๐Ÿ™ˆ. On fixed-line access links, a value of 500 ms is RECOMMENDED ๐Ÿ’…. Second, the value of RTO SHOULD NOT be rounded up to the nearest second ๐Ÿ™…โ€โ™€๏ธ. Rather, a 1 ms accuracy SHOULD be maintained ๐ŸŽ€. Just like TCP, the usage of Karn's algorithm is RECOMMENDED [KARN87] ๐Ÿงš. When applied to STUN, it means RTT estimates SHOULD NOT be computed from STUN transactions that result in the retransmission of a request. Don't measure the RTT off a request you already resent, it's giving confusing data ๐Ÿ’€.

The value for RTO SHOULD be cached by a client after the completion of the transaction and used as the starting value for RTO for the next transaction to the same server (based on equality of IP address) ๐Ÿ“. The value SHOULD be considered stale and discarded if no transactions have occurred to the same server in the last 10 minutes โฐ. Mood: stale values are not it ๐Ÿฅ€.

Retransmissions continue until a response is received or until a total of Rc requests have been sent ๐Ÿ’–. Rc SHOULD be configurable and SHOULD have a default of 7. If, after the last request, a duration equal to Rm times the RTO has passed without a response (giving ample time to get a response if only this final request actually succeeds), the client SHOULD consider the transaction to have failed ๐Ÿ˜ค. Rm SHOULD be configurable and SHOULD have a default of 16. A STUN transaction over UDP or DTLS-over-UDP is also considered failed if there has been a hard ICMP error [RFC1122] ๐Ÿšจ. For example, assuming an RTO of 500 ms, requests would be sent at times 0 ms, 500 ms, 1500 ms, 3500 ms, 7500 ms, 15500 ms, and 31500 ms. If the client has not received a response after 39500 ms, the client will consider the transaction to have timed out โŒ›๐Ÿฆ‹.

0 ms      500 ms     1500 ms    3500 ms    7500 ms    15500 ms   31500 ms   39500 ms
|---------|----------|----------|----------|----------|----------|----------|
Request 1  Request 2  Request 3  Request 4  Request 5  Request 6  Request 7  Timeout

6.2.2. Sending over TCP or TLS-over-TCP

For TCP and TLS-over-TCP [RFC8446] ๐ŸŒˆ, the client opens a TCP connection to the server ๐Ÿ”Œ.

In some usages of STUN, STUN is the only protocol over the TCP connection. In that case, it can be sent without any extra framing or demultiplexing ๐ŸŽ€. In other usages, or with other extensions, it may be multiplexed with other data over a TCP connection. In that case, STUN MUST be run on top of some kind of framing protocol, specified by the usage or extension, which lets the agent pull out complete STUN messages and complete application-layer messages ๐Ÿ›‘. The STUN service running on the well-known port or ports discovered through the DNS procedures in Section 8 is for STUN alone, and not for STUN multiplexed with other data ๐Ÿง. So no framing protocols are used in connections to those servers ๐Ÿ™…โ€โ™€๏ธ. When additional framing is used, the usage will specify how the client knows to apply it and what port to connect to. For example, for ICE connectivity checks, this info is learned through out-of-band negotiation between client and server ๐Ÿค.

Reliability of STUN over TCP and TLS-over-TCP is handled by TCP itself, so there are no retransmissions at the STUN protocol level ๐Ÿ’…. However, for a request/response transaction, if the client has not received a response by Ti seconds after it sent the request message, it considers the transaction to have timed out โณ. Ti SHOULD be configurable and SHOULD have a default of 39.5 s. This value was chosen to equalize the TCP and UDP timeouts for the default initial RTO โš–๏ธ.

Also, if the client is unable to establish the TCP connection, or the TCP connection is reset or fails before a response is received, any request/response transaction in progress is considered to have failed ๐Ÿ’”.

The client MAY send multiple transactions over a single TCP (or TLS-over-TCP) connection, and it MAY send another request before receiving a response to the previous request ๐Ÿงƒ. The client SHOULD keep the connection open until it:

  • has no further STUN requests or indications to send over that connection,
  • has no plans to use any resources (such as a mapped address (MAPPED-ADDRESS or XOR-MAPPED-ADDRESS) or relayed address [RFC5766]) that were learned through STUN requests sent over that connection,
  • if multiplexing other application protocols over that port, has finished using those other protocols,
  • if using that learned port with a remote peer, has established communications with that remote peer, as is required by some TCP NAT traversal techniques (e.g., [RFC6544]).

The details of an eventual keep-alive mechanism are left to each STUN Usage ๐Ÿซง. In any case, if a transaction fails because an idle TCP connection doesn't work anymore, the client SHOULD send a RST and try to open a new TCP connection ๐Ÿ”„.

On the server end, the server SHOULD keep the connection open and let the client close it, unless the server has determined that the connection has timed out (for example, because the client disconnected from the network) ๐Ÿ‘€. Bindings learned by the client will remain valid in intervening NATs only while the connection remains open ๐ŸŒ‰. Only the client knows how long it needs the binding ๐Ÿ’œ. The server SHOULD NOT close a connection if a request was received over that connection for which a response was not sent ๐Ÿ™. A server MUST NOT ever open a connection back towards the client in order to send a response ๐Ÿšซ. Servers SHOULD follow best practices regarding connection management in cases of overload ๐Ÿงฏ.

6.2.3. Sending over TLS-over-TCP or DTLS-over-UDP

When STUN is run by itself over TLS-over-TCP or DTLS-over-UDP, the TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 and TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 ciphersuites MUST be implemented (for compatibility with older versions of this protocol), except if deprecated by rules of a specific STUN usage ๐Ÿ”. Other ciphersuites MAY be implemented ๐ŸŽ€. Note that STUN clients and servers that implement TLS version 1.3 [RFC8446] or subsequent versions are also required to implement mandatory ciphersuites from those specifications, and SHOULD disable usage of deprecated ciphersuites when they detect support for those specifications ๐Ÿง. Perfect Forward Secrecy (PFS) ciphersuites MUST be preferred over non-PFS ciphersuites ๐Ÿ’–. Ciphersuites with known weaknesses, such as those based on (single) DES and RC4, MUST NOT be used ๐Ÿšซ๐Ÿ’€. Implementations MUST disable TLS-level compression ๐Ÿ™…โ€โ™€๏ธ.

These recommendations are just part of the recommendations in [BCP195] that implementations and deployments of a STUN Usage using TLS or DTLS MUST follow ๐Ÿ“–.

When it receives the TLS Certificate message, the client MUST verify the certificate and inspect the site identified by the certificate ๐Ÿ•ต๏ธโ€โ™€๏ธ. If the certificate is invalid or revoked, or if it does not identify the appropriate party, the client MUST NOT send the STUN message or otherwise proceed with the STUN transaction ๐Ÿ›‘. The client MUST verify the identity of the server. To do that, it follows the identification procedures defined in [RFC6125], with a certificate containing an identifier of type DNS-ID or CN-ID, optionally with a wildcard character as the leftmost label, but not of type SRV-ID or URI-ID ๐Ÿชช.

When STUN is run multiplexed with other protocols over a TLS-over-TCP connection or a DTLS-over-UDP association, the mandatory ciphersuites and TLS handling procedures operate as defined by those protocols ๐Ÿงฉ.

6.3. Receiving a STUN Message

This section specifies the processing of a STUN message ๐Ÿ“ฌ. The processing specified here is for STUN messages as defined in this specification. Additional rules for backwards compatibility are defined in Section 11, and those additional procedures are optional, so usages can elect to use them ๐Ÿฆ‹. First, a set of processing operations is applied that is independent of the class ๐Ÿง . This is followed by class-specific processing, described in the subsections that follow ๐Ÿ‘‘.

When a STUN agent receives a STUN message, it first checks that the message obeys the rules of Section 5 ๐Ÿ”. It checks that the first two bits are 0, that the Magic Cookie field has the correct value, that the message length is sensible, and that the method value is a supported method. It checks that the message class is allowed for the particular method. If the message class is "Success Response" or "Error Response", the agent checks that the transaction ID matches a transaction that is still in progress. If the FINGERPRINT extension is being used, the agent checks that the FINGERPRINT attribute is present and contains the correct value. If any errors are detected, the message is silently discarded ๐Ÿคซ. In the case when STUN is being multiplexed with another protocol, an error may indicate that this is not really a STUN message; in this case, the agent should try to parse the message as a different protocol ๐Ÿ”€.

The STUN agent then does any checks that are required by an authentication mechanism that the usage has specified (see Section 9) ๐Ÿ”‘.

Once the authentication checks are done, the STUN agent checks for unknown attributes and known-but-unexpected attributes in the message. Unknown comprehension-optional attributes MUST be ignored by the agent ๐Ÿ™ˆ. Known-but-unexpected attributes SHOULD be ignored by the agent ๐Ÿ’…. Unknown comprehension-required attributes cause processing that depends on the message class, and that is described below ๐Ÿ“.

At this point, further processing depends on the message class of the request ๐ŸŽ€.

6.3.1. Processing a Request โœจ

okay so, if the request has one or more unknown comprehension-required attributes, the server replies with an error response with an error code of 420 (Unknown Attribute). It also includes an UNKNOWN-ATTRIBUTES attribute listing those unknown comprehension-required attributes ๐Ÿ™ˆ

Otherwise, the server does any extra checking that the method or the specific usage needs. If all the checks pass, the server formulates a success response, as described below ๐Ÿ’…

When this runs over UDP or DTLS-over-UDP, a request the server gets could be the first request of a transaction, or it could be a retransmission. The server MUST respond to retransmissions in a way that keeps this property: if the client gets the response to the retransmission and not the response to the original request, the overall state on the client and server is identical to the case where only the response to the original retransmission is received, or where both responses are received (in which case the client will use the first one). ๐Ÿฆ‹ The easiest way to meet this is for the server to remember all transaction IDs received over UDP or DTLS-over-UDP, and their corresponding responses, for the last 40 seconds. But this means the server has to hold state, which is inappropriate for any requests that are not authenticated ๐Ÿ˜ญ Another way is to reprocess the request and recompute the response. This latter technique MUST only be applied to requests that are idempotent (a request is considered idempotent when the same request can be safely repeated without impacting the overall state of the system) and that result in the same success response for the same request. The Binding method is considered to be idempotent ๐ŸŒธ Also, note that there are certain rare network events that could cause the reflexive transport address value to change, which means a different mapped address could show up in different success responses. Extensions to STUN MUST discuss the implications of request retransmissions on servers that do not store transaction state. ๐Ÿงš

6.3.1.1. Forming a Success or Error Response

When forming the response (success or error), the server follows the rules of Section 6. The method of the response is the same as that of the request, and the message class is either "Success Response" or "Error Response" ๐ŸŽ€

For an error response, the server MUST add an ERROR-CODE attribute containing the error code specified in the processing above. The reason phrase isn't fixed, but it SHOULD be something suitable for the error code โœจ For certain errors, additional attributes get added to the message. These are spelled out in the description where the error code is specified. For example, for an error code of 420 (Unknown Attribute), the server MUST include an UNKNOWN-ATTRIBUTES attribute. Certain authentication errors also cause attributes to be added (see Section 9). Extensions may define other errors and/or additional attributes to add in error cases ๐Ÿ‘‘

If the server authenticated the request using an authentication mechanism, then the server SHOULD add the appropriate authentication attributes to the response (see Section 9) ๐Ÿ”ฅ

The server also adds any attributes required by the specific method or usage. On top of that, the server SHOULD add a SOFTWARE attribute to the message ๐Ÿ’–

For the Binding method, no additional checking is required unless the usage says otherwise. When forming the success response, the server adds an XOR-MAPPED-ADDRESS attribute to the response. This attribute contains the source transport address of the request message. For UDP or DTLS-over-UDP, that's the source IP address and source UDP port of the request message. For TCP and TLS-over-TCP, it's the source IP address and source TCP port of the TCP connection as seen by the server ๐ŸŒˆ

6.3.1.2. Sending the Success or Error Response

The response (success or error) gets sent over the same transport the request was received on. If the request came in over UDP or DTLS-over-UDP, the destination IP address and port of the response are the source IP address and port of the received request message. The source IP address and port of the response are equal to the destination IP address and port of the received request message. If the request came in over TCP or TLS-over-TCP, the response goes back on the same TCP connection the request was received on ๐Ÿฆ‹

The server is allowed to send responses in a different order than it received the requests in โœจ

6.3.2. Processing an Indication

If the indication contains unknown comprehension-required attributes, the indication is discarded and processing ceases ๐Ÿ™ˆ

Otherwise, the agent does any extra checking that the method or the specific usage needs. If all the checks pass, the agent then processes the indication. No response is generated for an indication ๐Ÿ’…

For the Binding method, no additional checking or processing is required, unless the usage says otherwise. The mere receipt of the message by the agent has refreshed the bindings in the intervening NATs ๐ŸŒธ

Since indications are not re-transmitted over UDP or DTLS-over-UDP (unlike requests), there's no need to handle retransmissions of indications at the sending agent ๐Ÿซถ

6.3.3. Processing a Success Response

If the success response contains unknown comprehension-required attributes, the response is discarded and the transaction is considered to have failed ๐Ÿ˜ญ

Otherwise, the client does any extra checking that the method or the specific usage needs. If all the checks pass, the client then processes the success response ๐Ÿ’œ

For the Binding method, the client checks that the XOR-MAPPED-ADDRESS attribute is present in the response. The client also checks the address family specified. If it's an unsupported address family, the attribute SHOULD be ignored. If it's an unexpected but supported address family (for example, the Binding transaction was sent over IPv4, but the address family specified is IPv6), then the client MAY accept and use the value ๐ŸŒŸ

6.3.4. Processing an Error Response

If the error response contains unknown comprehension-required attributes, or if the error response does not contain an ERROR-CODE attribute, then the transaction is simply considered to have failed ๐Ÿ’€

Otherwise, the client does any processing specified by the authentication mechanism (see Section 9). This may result in a new transaction attempt ๐Ÿ”

The processing at this point depends on the error code, the method, and the usage. The following are the default rules:

  • If the error code is 300 through 399, the client SHOULD consider the transaction as failed unless the ALTERNATE-SERVER extension (Section 10) is being used.
  • If the error code is 400 through 499, the client declares the transaction failed. In the case of 420 (Unknown Attribute), the response should contain an UNKNOWN-ATTRIBUTES attribute that gives additional information.
  • If the error code is 500 through 599, the client MAY resend the request. Clients that do so MUST limit the number of times they do this. Unless a specific error code specifies a different value, the number of retransmissions SHOULD be limited to 4.

Any other error code causes the client to consider the transaction failed ๐Ÿ“


7. FINGERPRINT Mechanism โœจ

This section describes an optional mechanism for STUN that helps tell STUN messages apart from packets of other protocols when the two are multiplexed on the same transport address ๐ŸŽ€ This mechanism is optional, and a STUN Usage must describe if and when it's used. The FINGERPRINT mechanism is not backwards compatible with RFC 3489, so it can't be used in environments where that compatibility is required ๐Ÿ™…โ€โ™€๏ธ

In some usages, STUN messages are multiplexed on the same transport address as other protocols, such as the Real-Time Transport Protocol (RTP). To apply the processing described in Section 6, STUN messages must first be separated from the application packets ๐Ÿ’…

Section 5 describes three fixed fields in the STUN header that can be used for this purpose. In some cases, though, those three fixed fields might not be enough ๐Ÿค

When the FINGERPRINT extension is used, an agent includes the FINGERPRINT attribute in messages it sends to another agent. Section 14.7 describes the placement and value of this attribute ๐Ÿงš

When an agent receives what it believes is a STUN message, then, in addition to other basic checks, the agent also checks that the message contains a FINGERPRINT attribute and that the attribute contains the correct value. Section 6.3 describes when the FINGERPRINT check happens in the overall processing of a STUN message. This extra check helps the agent detect messages of other protocols that might otherwise look like STUN messages ๐Ÿ”


8. DNS Discovery of a Server

This section describes an optional procedure for STUN that lets a client use DNS to find the IP address and port of a server ๐ŸŒ A STUN Usage must describe if and when this extension is used. To use this procedure, the client must know a STUN URI [RFC7064], and the usage must also describe how the client obtains this URI. Hard-coding a STUN URI into software is NOT RECOMMENDED, in case the domain name is lost or needs to change for legal or other reasons ๐Ÿ™ˆ

When a client wants to find a STUN server on the public Internet that accepts Binding request/response transactions, the STUN URI scheme is stun. When it wants to find a STUN server that accepts Binding request/response transactions over a TLS or DTLS session, the URI scheme is stuns ๐Ÿ”

The syntax of the stun and stuns URIs is defined in Section 3.1 of [RFC7064]. STUN Usages MAY define additional URI schemes ๐Ÿ“

8.1. STUN URI Scheme Semantics

okay so if the <host> part of a "stun" URI has an IP address in it, that address gets used directly to contact the server ๐Ÿงš but a "stuns" URI with an IP address in it MUST be rejected ๐Ÿšซ no exceptions bestie. a future STUN extension or usage might relax this, but only if it shows how to authenticate the STUN server and stop man-in-the-middle attacks ๐Ÿ•ต๏ธโ€โ™€๏ธ (that's a big ask and I respect it).

if the URI doesn't have an IP address, the domain name in the <host> part gets turned into a transport address using the SRV procedures from [RFC2782] ๐ŸŒธ the DNS SRV service name is whatever the <scheme> part says, and the protocol in the SRV lookup is the transport the client is gonna run STUN over: "udp" for UDP and "tcp" for TCP ๐Ÿ’œ

the procedures of RFC 2782 get followed to pick the server. RFC 2782 explains how a set of SRV records gets sorted and then tried, which is so iconic ๐Ÿ“‹ but it only says the client should "try to connect to the (protocol, address, service)" and doesn't say what happens when something fails ๐Ÿ˜ญ so here's the add-on: if the STUN transaction times out without a response, the client SHOULD retry the request to the next server in the order defined by RFC 2782 ๐Ÿ” that retry only works for request/response transmissions, since indications don't get a response or a timeout (no answer, no retry, that's just how it goes ๐Ÿคทโ€โ™€๏ธ).

also, instead of only asking for the A or the AAAA records of a domain name, a dual-stack IPv4/IPv6 client MUST query both and try the requests with all the IP addresses it gets back, as specified in [RFC8305] ๐ŸŒˆ both tabs open, obsessed.

the default port for STUN requests is 3478, for both TCP and UDP ๐Ÿ“ the default port for STUN over TLS and STUN over DTLS requests is 5349 ๐Ÿ” servers can run STUN over DTLS on the same port as STUN over UDP if the server software can tell whether the first message is a DTLS message or a STUN message ๐Ÿฆ‹ and servers can run STUN over TLS on the same port as STUN over TCP if the software can tell whether the first message is a TLS message or a STUN message โœจ

administrators of STUN servers SHOULD use these ports in their SRV records for UDP and TCP ๐Ÿ’… and in every case, the port in DNS MUST reflect the one the server is actually listening on ๐Ÿซถ no mismatch allowed, periodt.

if no SRV records get found, the client does both an A and an AAAA lookup of the domain name, as described in [RFC8305] ๐ŸŒท the result is a list of IP addresses, and each one can be contacted at the default port over UDP or TCP at the same time, no matter which STUN Usage it is ๐Ÿ’ซ for usages that need TLS, the client connects to those IP addresses using the default STUN over TLS port ๐Ÿ”’ and for usages that need DTLS, it connects using the default STUN over DTLS port ๐Ÿ›ก๏ธ


9. Authentication and Message-Integrity Mechanisms โœจ

okay this section is the security glow-up ๐Ÿ’– it defines two mechanisms that a client and server can use to get authentication and message integrity: the short-term credential mechanism and the long-term credential mechanism ๐Ÿ”‘ both of them are optional, and each usage has to say whether and when they get used. so clients and servers always know which mechanism (if any) to follow, just from knowing which usage is in play ๐Ÿง  for example, a STUN server on the public Internet that supports ICE wouldn't have any authentication, whereas the STUN server bit inside an agent doing connectivity checks would use short-term credentials ๐Ÿ’œ you can get an overview of these two mechanisms in Section 2 ๐ŸŒธ

each mechanism spells out the extra processing it needs, on top of the processing from Section 6 ๐Ÿงฉ that extra processing happens in three spots: when forming a message, when receiving a message right after the basic checks are done, and when doing the detailed processing of error responses ๐ŸŽ€

now, the big rule ๐Ÿšจ agents MUST ignore all attributes that follow MESSAGE-INTEGRITY, except for the MESSAGE-INTEGRITY-SHA256 and FINGERPRINT attributes ๐Ÿ™…โ€โ™€๏ธ similarly, agents MUST ignore all attributes that follow the MESSAGE-INTEGRITY-SHA256 attribute if the MESSAGE-INTEGRITY attribute isn't present, except for the FINGERPRINT attribute ๐Ÿ‘€ read those twice bestie, they're load-bearing ๐Ÿ˜ญ


9.1. Short-Term Credential Mechanism

the short-term credential mechanism assumes that, before the STUN transaction happens, the client and server already used some other protocol to swap a credential, which is a username and a password ๐Ÿ—๏ธ this credential is time-limited, and the usage decides what the time limit is ๐Ÿ•ฐ๏ธ for example, in the ICE usage [RFC8445], the two endpoints use out-of-band signaling to agree on a username and password, and those stay valid for the whole media session ๐Ÿ“ž

this credential gets used to make a message-integrity check in every request and in a lot of responses ๐Ÿ” there's no challenge-and-response like in the long-term mechanism, so replay attacks are limited by the fact that the credential only lasts for a set time โณ clever, honestly.

9.1.1. HMAC Key

for short-term credentials, the Hash-Based Message Authentication Code (HMAC) key is defined like this ๐Ÿ’ซ

                   key = OpaqueString(password)

where the OpaqueString profile is defined in [RFC8265] ๐Ÿง the encoding used is UTF-8 [RFC3629] ๐ŸŒ

9.1.2. Forming a Request or Indication

for a request or indication message, the agent MUST include the USERNAME, MESSAGE-INTEGRITY-SHA256, and MESSAGE-INTEGRITY attributes in the message ๐Ÿ“จ unless the agent already knows from some external mechanism which message integrity algorithm both agents support ๐Ÿค in that case, either MESSAGE-INTEGRITY or MESSAGE-INTEGRITY-SHA256 MUST be included, along with USERNAME ๐ŸŽ€ the HMAC for the MESSAGE-INTEGRITY attribute gets computed as described in Section 14.5, and the HMAC for the MESSAGE-INTEGRITY-SHA256 attribute gets computed as described in Section 14.6 ๐Ÿงฎ and note that the password is never included in the request or indication, so it never leaves the room ๐Ÿคซ

9.1.3. Receiving a Request or Indication

after the agent does the basic processing of a message, it runs the checks below in the order listed ๐Ÿ“‹

  • if the message does not contain 1) a MESSAGE-INTEGRITY or a MESSAGE-INTEGRITY-SHA256 attribute and 2) a USERNAME attribute:
    • if the message is a request, the server MUST reject the request with an error response ๐Ÿ™…โ€โ™€๏ธ this response MUST use an error code of 400 (Bad Request) ๐Ÿ’€
    • if the message is an indication, the agent MUST silently discard the indication ๐Ÿซฅ
  • if the USERNAME doesn't contain a username value that's currently valid within the server:
    • if the message is a request, the server MUST reject the request with an error response, and this response MUST use an error code of 401 (Unauthenticated) ๐Ÿšช
    • if the message is an indication, the agent MUST silently discard the indication ๐Ÿซฅ
  • if the MESSAGE-INTEGRITY-SHA256 attribute is present, compute the value for the message integrity as described in Section 14.6, using the password tied to the username ๐Ÿ” if the MESSAGE-INTEGRITY-SHA256 attribute isn't present, use that same password to compute the value for the message integrity as described in Section 14.5 ๐Ÿง  if the result doesn't match the contents of the matching attribute (MESSAGE-INTEGRITY-SHA256 or MESSAGE-INTEGRITY):
    • if the message is a request, the server MUST reject the request with an error response, and this response MUST use an error code of 401 (Unauthenticated) ๐Ÿšซ
    • if the message is an indication, the agent MUST silently discard the indication ๐Ÿซฅ

if these checks all pass, the agent carries on and processes the request or indication ๐Ÿฅณ any response a server generates to a request that has a MESSAGE-INTEGRITY-SHA256 attribute MUST include the MESSAGE-INTEGRITY-SHA256 attribute, computed with the password used to authenticate the request ๐Ÿ” any response a server generates to a request that only has a MESSAGE-INTEGRITY attribute MUST include the MESSAGE-INTEGRITY attribute, computed with the password used to authenticate the request ๐Ÿ” this means only one of those attributes can show up in a response ๐Ÿซฐ and the response MUST NOT contain the USERNAME attribute ๐Ÿ™ˆ

if any of the checks fail, a server MUST NOT include a MESSAGE-INTEGRITY-SHA256, MESSAGE-INTEGRITY, or USERNAME attribute in the error response ๐Ÿ˜ญ the reason is that, in these failure cases, the server can't figure out the shared secret it needs to compute the MESSAGE-INTEGRITY-SHA256 or MESSAGE-INTEGRITY attributes ๐Ÿซ 

9.1.4. Receiving a Response

the client looks for the MESSAGE-INTEGRITY or the MESSAGE-INTEGRITY-SHA256 attribute in the response ๐Ÿ‘€ if it's there, and if the client only sent one of MESSAGE-INTEGRITY or MESSAGE-INTEGRITY-SHA256 in the request (because of the external indication in Section 9.1.2, or because this is a subsequent request as defined in Section 9.1.5), then the algorithm in the response has to match ๐Ÿงฉ otherwise, the response MUST be discarded ๐Ÿ—‘๏ธ

then the client computes the message integrity over the response, as defined in Section 14.5 for MESSAGE-INTEGRITY or Section 14.6 for MESSAGE-INTEGRITY-SHA256, using the same password it used for the request ๐Ÿงฎ if the result matches the contents of MESSAGE-INTEGRITY or MESSAGE-INTEGRITY-SHA256 respectively, the response is considered authenticated โœ… if it doesn't match, or if both MESSAGE-INTEGRITY and MESSAGE-INTEGRITY-SHA256 are absent, then what happens next depends on whether the request was sent over a reliable or an unreliable transport ๐Ÿšฆ

if the request was sent over an unreliable transport, the response MUST be discarded, as if it had never been received ๐Ÿ‘ป that means retransmits, if they apply, will keep going ๐Ÿ” and if all the responses received get discarded, then instead of signaling a timeout after ending the transaction, the layer MUST signal that the integrity protection was violated ๐Ÿšจ

if the request was sent over a reliable transport, the response MUST be discarded, and the layer MUST immediately end the transaction and signal that the integrity protection was violated ๐Ÿ’ฅ no second chances, bestie.

9.1.5. Sending Subsequent Requests

a client sending subsequent requests to the same server MUST send only the MESSAGE-INTEGRITY-SHA256 or the MESSAGE-INTEGRITY attribute that matches the attribute received in the response to the initial request ๐ŸŽฏ and here, "same server" means the same IP address and port number, not just the same URI or the same SRV lookup result ๐Ÿงšโ€โ™€๏ธ ๐Ÿ’–

9.2. Long-Term Credential Mechanism โœจ

okay so the long-term credential mechanism is giving "traditional login" energy ๐Ÿ” it runs on a username and password that the client and server both share. It's called long-term because the credential gets handed out to a user and stays valid until that user stops being a subscriber or the credential gets changed. Basically the same username and password people already use to log in to things ๐Ÿ’–

Since these usernames and passwords stick around for ages, replay prevention comes from a digest challenge ๐Ÿ›ก๏ธ Here's how it goes. The client starts by sending a request with no credentials and no integrity checks at all. The server says "nope" and rejects it, but it hands over a realm (which helps the user or agent pick the right username and password) and a nonce. The nonce gives limited replay protection. It's a cookie the server picks, encoded so it shows how long it's valid for or which client it's valid for. Only the server needs to understand what's inside the cookie, so don't worry about the client poking at it ๐Ÿช

Next, the client retries. This time it includes its username, the realm, and it echoes back the nonce the server gave it. It also adds one of the message-integrity attributes from this document, which is an HMAC over the entire request, nonce included ๐Ÿ”‘ The server checks the nonce and the message integrity. If both match, the request is authenticated and everyone's happy ๐ŸŽ‰ If the nonce has expired, it's called "stale," and the server rejects the request again, this time with a fresh nonce โฐ

For later requests to the same server, the client reuses the nonce, username, realm, and password from before. That means requests keep going through without getting bounced, until the server decides the nonce is no longer valid. Then it rejects the request and sends a new nonce so the client can keep going ๐Ÿ”

Heads up bestie: the long-term credential mechanism cannot be used to protect indications, because indications can't be challenged ๐Ÿ™…โ€โ™€๏ธ Any usage that sends indications has to either use a short-term credential or skip authentication and message integrity for them. No exceptions, iykyk ๐Ÿ’…

To show that it supports this spec, a server MUST prepend the NONCE attribute value with the string "obMatJos2", followed by the (4-character) base64 [RFC4648] encoding of the 24-bit STUN Security Features from Section 18.1 โœจ Those 24 bits are packed into 3 bytes, where bit 0 is the most significant bit of the first byte and bit 23 is the least significant bit of the third byte. If no security features are being used, the server MUST encode a byte array with all 24 bits set to zero instead ๐ŸŒธ From here on, the "nonce cookie" means that full 13-character string tacked onto the front of the NONCE value ๐Ÿงš

nonce cookie = "obMatJos2" || base64(24-bit STUN Security Features)
             = 9 characters + 4 characters = 13 characters

Okay now the security part, and it's serious ๐Ÿ˜ญ The long-term credential mechanism is open to offline dictionary attacks, so deployments SHOULD use passwords that are hard to guess ๐Ÿ™ˆ If the credentials aren't typed in by a user and are instead put on a client device during device provisioning, the password SHOULD have at least 128 bits of randomness ๐ŸŽ€ If a user is typing the credentials in, those passwords should follow current best practices for password structure ๐Ÿซถ


9.2.1. Bid-Down Attack Prevention

okay this section is about two brand new security features ๐Ÿฆ‹ One lets you pick the algorithm used to protect the password, and the other lets you use an anonymous username. Both are optional so that older versions of STUN still work the way they always have ๐Ÿ’œ

Here's the catch though: these features are vulnerable to bid-down attacks ๐Ÿ˜ฌ That's when someone sitting in the message path strips these capabilities out and forces weaker security onto everyone. To make sure that kind of sneaky move doesn't go unnoticed, the nonce gets extra information baked in ๐Ÿ•ต๏ธโ€โ™€๏ธ

The value of the "nonce cookie" changes depending on which STUN Security Feature bits are selected. Whenever this document mentions the "nonce cookie" in a section about a specific STUN Security Feature, it's understood that the matching STUN Security Feature bit in the "nonce cookie" is set to 1 โœจ

For example, when the PASSWORD-ALGORITHMS security feature (defined in Section 9.2.4) is used, the matching "Password algorithms" bit (defined in Section 18.1) is set to 1 in the "nonce cookie" ๐ŸŒˆ


9.2.2. HMAC Key

For long-term credentials that don't use a different algorithm (the kind you'd pick with the PASSWORD-ALGORITHM attribute), the key is 16 bytes ๐Ÿ”‘

            key = MD5(username ":" OpaqueString(realm)
              ":" OpaqueString(password))

Here MD5 comes from [RFC1321] and [RFC6151], and the OpaqueString profile is defined in [RFC8265]. The encoding is UTF-8 [RFC3629] ๐Ÿ’…

So the 16-byte key is the MD5 hash of five fields smooshed together ๐Ÿ“ (1) the username, with any quotes and trailing nulls stripped, taken from the USERNAME attribute (and OpaqueString has already been applied in that case); (2) a single colon; (3) the realm, with any quotes and trailing nulls stripped and then run through OpaqueString; (4) another single colon; and (5) the password, with any trailing nulls stripped and then run through OpaqueString. For example, if the username is 'user', the realm is 'realm', and the password is 'pass', then the 16-byte HMAC key is the MD5 hash of the string 'user:realm:pass', which comes out to 0x8493fbc53ba582fb4c044c456bdc40eb ๐ŸคŒ

This key structure is super handy for systems that also use SIP [RFC3261] ๐Ÿ“ž SIP systems that use its digest authentication usually don't store the actual password in the database. They store something called "H(A1)" instead, which is exactly the key we just defined. This mechanism can be used with the authentication extensions in [RFC5090] ๐Ÿ’œ

When a PASSWORD-ALGORITHM is used, the key length and algorithm to use are described in Section 18.5.1 โœจ


9.2.3. Forming a Request

The first request from the client to the server is handled by the rules in Section 9.2.3.1 ๐Ÿš€ The server is identified by hostname if the DNS procedures of Section 8 are used, and by IP address if they aren't. When the client starts a subsequent request after a previous request/response transaction finished successfully, it follows the rules in Section 9.2.3.2 ๐Ÿฆ‹ Forming a request because of a 401 (Unauthenticated) or 438 (Stale Nonce) error response is covered in Section 9.2.5, and it doesn't count as a "subsequent request," so the rules in Section 9.2.3.2 don't apply to it ๐Ÿ™…โ€โ™€๏ธ Each of these request types has its own different set of mandatory attributes ๐ŸŽ€

9.2.3.1. First Request

If the client hasn't completed a successful request/response transaction with the server yet, it MUST omit the USERNAME, USERHASH, MESSAGE-INTEGRITY, MESSAGE-INTEGRITY-SHA256, REALM, NONCE, PASSWORD-ALGORITHMS, and PASSWORD-ALGORITHM attributes ๐Ÿซ  Basically, the first request goes out as if there's no authentication or message integrity happening at all ๐Ÿ‘€

9.2.3.2. Subsequent Requests

Once a request/response transaction is complete, the client will have been given a realm and a nonce by the server, and it will have picked a username and password to authenticate with ๐Ÿ’– The client SHOULD cache the username, password, realm, and nonce for future communication with the server ๐Ÿง  When the client sends a subsequent request, it MUST include either the USERNAME or USERHASH, REALM, NONCE, and PASSWORD-ALGORITHM attributes with those cached values ๐Ÿญ It MUST also include a MESSAGE-INTEGRITY attribute or a MESSAGE-INTEGRITY-SHA256 attribute, computed as described in Sections 14.5 and 14.6 using the cached password โœจ Which of the two it uses depends on the attribute that came back in the response to the first request ๐Ÿซถ

9.2.4. Receiving a Request โœจ

okay bestie, once the server finishes the basic processing of a request, it runs through the checks below in the order listed ๐Ÿ’… Also, it is RECOMMENDED that the REALM value be the domain name of the provider of the STUN server ๐ŸŒธ

  • If the message does not contain a MESSAGE-INTEGRITY or MESSAGE-INTEGRITY-SHA256 attribute, the server MUST generate an error response with an error code of 401 (Unauthenticated) ๐Ÿ™ˆ This response MUST include a REALM value. It MUST also include a NONCE that the server picks itself. The server MUST NOT choose the same NONCE for two requests unless they have the same source IP address and port. The server MAY support alternate password algorithms, and if it does, it can list them in preferential order in a PASSWORD-ALGORITHMS attribute. If the server adds a PASSWORD-ALGORITHMS attribute, it MUST set the STUN Security Feature "Password algorithms" bit to 1. The server MAY support anonymous usernames, and if it does, it MUST set the STUN Security Feature "Username anonymity" bit to 1. The response SHOULD NOT contain a USERNAME, USERHASH, MESSAGE-INTEGRITY, or MESSAGE-INTEGRITY-SHA256 attribute.
Note: Reusing a NONCE for different source IP addresses or ports was not explicitly forbidden in [RFC5389]. ๐Ÿ‘€
  • If the message contains a MESSAGE-INTEGRITY or a MESSAGE-INTEGRITY-SHA256 attribute, but is missing either the USERNAME or USERHASH, REALM, or NONCE attribute, the server MUST generate an error response with an error code of 400 (Bad Request) ๐Ÿ’€ This response SHOULD NOT include a USERNAME, USERHASH, NONCE, or REALM attribute. The response cannot contain a MESSAGE-INTEGRITY or MESSAGE-INTEGRITY-SHA256 attribute, because the stuff needed to generate them is missing.
  • If the NONCE attribute starts with the "nonce cookie" and the STUN Security Feature "Password algorithms" bit is set to 1, the server performs these checks in the order specified:
    • If the request contains neither the PASSWORD-ALGORITHMS nor the PASSWORD-ALGORITHM attribute, then the request is processed as though PASSWORD-ALGORITHM were MD5 โœจ
    • Otherwise, unless (1) PASSWORD-ALGORITHM and PASSWORD-ALGORITHMS are both present, (2) PASSWORD-ALGORITHMS matches the value sent in the response that sent this NONCE, and (3) PASSWORD-ALGORITHM matches one of the entries in PASSWORD-ALGORITHMS, the server MUST generate an error response with an error code of 400 (Bad Request) ๐Ÿซถ
  • If the value of the USERNAME or USERHASH attribute is not valid, the server MUST generate an error response with an error code of 401 (Unauthenticated) ๐Ÿ˜ญ This response MUST include a REALM value. It MUST include a NONCE that the server picks. It MUST include a PASSWORD-ALGORITHMS attribute. The response SHOULD NOT contain a USERNAME or USERHASH attribute. The response MAY include a MESSAGE-INTEGRITY or MESSAGE-INTEGRITY-SHA256 attribute, calculated with the previous key.
  • If the MESSAGE-INTEGRITY-SHA256 attribute is present, compute the message integrity value as described in Section 14.6, using the password associated with the username. Otherwise, using that same password, compute the MESSAGE-INTEGRITY value as described in Section 14.5. If the result does not match the contents of the MESSAGE-INTEGRITY attribute or the MESSAGE-INTEGRITY-SHA256 attribute, the server MUST reject the request with an error response ๐Ÿ”ฅ That response MUST use an error code of 401 (Unauthenticated). It MUST include the REALM and NONCE attributes, and SHOULD NOT include the USERNAME, USERHASH, MESSAGE-INTEGRITY, or MESSAGE-INTEGRITY-SHA256 attribute.
  • If the NONCE is no longer valid, the server MUST generate an error response with an error code of 438 (Stale Nonce) ๐Ÿฅ€ This response MUST include NONCE, REALM, and PASSWORD-ALGORITHMS attributes, and SHOULD NOT include the USERNAME and USERHASH attributes. The NONCE attribute value MUST be valid. The response MAY include a MESSAGE-INTEGRITY or MESSAGE-INTEGRITY-SHA256 attribute, calculated with the previous NONCE. Servers can revoke nonces for extra security ๐Ÿ” For guidelines, check Section 5.4 of [RFC7616].

If these checks pass, the server keeps processing the request โœจ Any response the server generates MUST include the MESSAGE-INTEGRITY-SHA256 attribute, computed with the username and password used to authenticate the request. The one exception is when the request was processed as though PASSWORD-ALGORITHM were MD5 (because it had neither PASSWORD-ALGORITHMS nor PASSWORD-ALGORITHM). In that case, the MESSAGE-INTEGRITY attribute MUST be used instead of MESSAGE-INTEGRITY-SHA256, and the REALM, NONCE, USERNAME, and USERHASH attributes SHOULD NOT be included ๐Ÿ’–


9.2.5. Receiving a Response โœจ

okay, this part is all about what the client does when a response comes back ๐Ÿฆ‹

If the response is an error response with an error code of 401 (Unauthenticated) or 438 (Stale Nonce), the client MUST check whether the NONCE attribute value starts with the "nonce cookie" ๐Ÿ‘€ If it does, and that "nonce cookie" has the STUN Security Feature "Password algorithms" bit set to 1 but no PASSWORD-ALGORITHMS attribute is present, then the client MUST NOT retry the request with a new transaction ๐Ÿšซ

If the response is an error response with an error code of 401 (Unauthenticated), the client SHOULD retry the request with a new transaction ๐Ÿ” This request MUST contain a USERNAME or a USERHASH, which the client works out as the right username for the REALM from the error response. If the "nonce cookie" is present and has the STUN Security Feature "Username anonymity" bit set to 1, then the USERHASH attribute MUST be used. Otherwise, the USERNAME attribute MUST be used. The request MUST contain the REALM, copied from the error response. The request MUST contain the NONCE, also copied from the error response. If the response contains a PASSWORD-ALGORITHMS attribute, the request MUST contain the PASSWORD-ALGORITHMS attribute with the same content. If the response contains a PASSWORD-ALGORITHMS attribute and that attribute has at least one algorithm the client supports, then the request MUST contain a PASSWORD-ALGORITHM attribute set to the first supported algorithm on the list ๐ŸŒˆ If the response contains a PASSWORD-ALGORITHMS attribute and none of the algorithms in it are supported by the client, then the client MUST NOT retry the request with a new transaction ๐Ÿ™…โ€โ™€๏ธ The client MUST NOT do this retry if it isn't changing the USERNAME, USERHASH, REALM, or its associated password from the previous attempt.

If the response is an error response with an error code of 438 (Stale Nonce), the client MUST retry the request using the new NONCE attribute from the 438 (Stale Nonce) response ๐Ÿ”„ This retry MUST also include either the USERNAME or USERHASH, the REALM, and either the MESSAGE-INTEGRITY or MESSAGE-INTEGRITY-SHA256 attribute.

For all other responses, if the NONCE attribute starts with the "nonce cookie" and the STUN Security Feature "Password algorithms" bit is set to 1 but PASSWORD-ALGORITHMS is not present, the response MUST be ignored ๐Ÿงš

If the response is an error response with an error code of 400 (Bad Request) and does not contain either the MESSAGE-INTEGRITY or MESSAGE-INTEGRITY-SHA256 attribute, then the response MUST be discarded, as if it were never received ๐Ÿซ  That means any retransmits, if they apply, will keep going.

Note: In this case, the 400 response will never reach the application, so you'll get a timeout instead. ๐Ÿ˜ญ

The client looks for a MESSAGE-INTEGRITY or MESSAGE-INTEGRITY-SHA256 attribute in the response, whether it's a success or a failure ๐Ÿ” If one is there, the client calculates the message integrity over the response as defined in Sections 14.5 or 14.6, using the same password it used for the request. If the result matches the contents of the MESSAGE-INTEGRITY or MESSAGE-INTEGRITY-SHA256 attribute, the response is considered authenticated โœ… If the value doesn't match, or if both MESSAGE-INTEGRITY and MESSAGE-INTEGRITY-SHA256 are absent, what happens next depends on whether the request was sent over a reliable or an unreliable transport.

If the request was sent over an unreliable transport, the response MUST be discarded, as if it had never been received. That means any retransmits, if they apply, will keep going. If every response received gets discarded, then instead of signaling a timeout after ending the transaction, the layer MUST signal that the integrity protection was violated ๐Ÿšจ

If the request was sent over a reliable transport, the response MUST be discarded, and the layer MUST immediately end the transaction and signal that the integrity protection was violated ๐Ÿ’ฅ

If the response contains a PASSWORD-ALGORITHMS attribute, all subsequent requests MUST be authenticated using MESSAGE-INTEGRITY-SHA256 only ๐Ÿ‘‘

10. ALTERNATE-SERVER Mechanism โœจ

okay so this section is all about how a STUN server can redirect a client to a different server ๐Ÿฆ‹ this extension is optional, and a usage has to define if and when it gets used. the ALTERNATE-SERVER attribute carries an IP address ๐Ÿ’…

a server using this extension redirects a client by answering a request with an error response that has error code 300 (Try Alternate) ๐Ÿ™ˆ the server MUST include at least one ALTERNATE-SERVER attribute in that error response, and it MUST contain an IP address of the same address family as the source IP address of the request message. the server SHOULD also add a second ALTERNATE-SERVER attribute after the mandatory one, containing an IP address from the other address family (the one that isn't the source IP address of the request). the error response MAY be authenticated ๐Ÿ’œ but there are use cases where authenticating it isn't possible or practical.

now the domain stuff ๐ŸŒธ if the transaction uses TLS or DTLS, if it's authenticated by a MESSAGE-INTEGRITY-SHA256 attribute, and if the server wants to redirect to a server that has a different certificate, then the server MUST include an ALTERNATE-DOMAIN attribute containing the name inside the subjectAltName of that certificate. those conditions on MESSAGE-INTEGRITY-SHA256 basically say "this transaction is authenticated, and the client implements this spec, so it can actually process ALTERNATE-DOMAIN" ๐Ÿซถ

a client using this extension handles a 300 (Try Alternate) error code like this ๐Ÿงš it looks for an ALTERNATE-SERVER attribute in the error response. if it finds one, it treats the current transaction as failed and retries the request with the server named in the attribute, using the same transport protocol as the previous request. if that retry is authenticated, it MUST utilize the same credentials the client would have used with the server that did the redirecting. if the transport protocol uses TLS or DTLS, the client looks for an ALTERNATE-DOMAIN attribute. if it finds one, that domain MUST be used to validate the certificate, following the recommendations in [RFC6125]. the certificate MUST contain an identifier of type DNS-ID or CN-ID (eventually with wildcards) but not of type SRV-ID or URI-ID. if there's no ALTERNATE-DOMAIN attribute, the same domain that was used for the original request MUST be used to validate the certificate.

and here's the loop-breaker ๐Ÿ” if the client has already sent this request to a server it's now being redirected to within the last five minutes, it MUST ignore the redirection and consider the transaction failed. this stops endless ping-ponging between servers when there's a redirection loop ๐Ÿ™…โ€โ™€๏ธ


11. Backwards Compatibility with RFC 3489 ๐Ÿ’–

on top of the backwards compatibility already covered in Section 12 of [RFC5389], there's one extra rule ๐Ÿ“ DTLS MUST NOT be used with [RFC3489] (referred to as "classic STUN"). any STUN request or indication without the magic cookie (see Section 6 of [RFC5389]) sent over DTLS MUST be considered invalid. so all requests MUST generate a 500 (Server Error) error response, and indications MUST be ignored ๐Ÿ’€


12. Basic Server Behavior ๐ŸŒˆ

this section defines the behavior of a basic, stand-alone STUN server โœจ

historically, "classic STUN" [RFC3489] only defined a server that gave clients server reflexive transport addresses by receiving and replying to STUN Binding requests. then [RFC5389] reimagined the protocol as an extensible framework, and the server job became the only STUN Usage defined in that document. this STUN Usage is also called "Basic STUN Server" ๐ŸŽ€

the STUN server MUST support the Binding method. it SHOULD NOT utilize the short-term or long-term credential mechanism, because authenticating the request takes more work than just processing it ๐Ÿ’… it SHOULD NOT utilize the ALTERNATE-SERVER mechanism for that same reason. it MUST support UDP and TCP. it MAY support STUN over TCP/TLS or STUN over UDP/DTLS, though DTLS and TLS give minimal security benefits in this basic mode ๐Ÿ” it doesn't require a keep-alive mechanism, because a TCP or TLS-over-TCP connection gets closed after the end of the Binding transaction. it MAY utilize the FINGERPRINT mechanism but MUST NOT require it. the stand-alone server only runs STUN, so FINGERPRINT gives no benefit there. requiring it would break compatibility with RFC 3489, and that compatibility is desirable in a stand-alone server ๐Ÿฆ‹ stand-alone STUN servers SHOULD support backwards compatibility with clients using [RFC3489], as described in Section 11.

it is RECOMMENDED that STUN server administrators provide DNS entries for those servers, as described in Section 8 ๐ŸŒธ if both A and AAAA resource records come back, the client can send STUN Binding requests to the IPv4 and IPv6 addresses at the same time (as specified in [RFC8305]), since the Binding request is idempotent. also, the MAPPED-ADDRESS or XOR-MAPPED-ADDRESS attributes that come back won't necessarily match the address family of the server address that was used ๐Ÿ™ˆ

a basic STUN server isn't a NAT traversal solution all by itself ๐Ÿ’œ but it can be part of a solution through STUN Usages. more on that in Section 13 ๐Ÿงš


13. STUN Usages ๐ŸŽ€

STUN by itself isn't a fix for the NAT traversal problem ๐Ÿ˜ญ instead, it's a tool you use inside a bigger solution. the term "STUN Usage" means any solution that uses STUN as a component ๐Ÿ‘‘

a STUN Usage defines how STUN actually gets used: when to send requests, what to do with the responses, and which optional procedures defined here (or in an extension to STUN) are used. a usage also defines:

  • Which STUN methods are used.
  • What transports are used. If DTLS-over-UDP is used, then implementing the denial-of-service countermeasure described in Section 4.2.1 of [RFC6347] is mandatory.
  • What authentication and message-integrity mechanisms are used.
  • The considerations around manual vs. automatic key derivation for the integrity mechanism, as discussed in [RFC4107].
  • What mechanisms are used to tell STUN messages apart from other messages. When STUN is run over TCP or TLS-over-TCP, a framing mechanism may be required.
  • How a STUN client figures out the IP address and port of the STUN server.
  • How simultaneous use of IPv4 and IPv6 addresses (Happy Eyeballs [RFC8305]) works with non-idempotent transactions when both address families are found for the STUN server.
  • Whether backwards compatibility to RFC 3489 is required.
  • What optional attributes defined here (such as FINGERPRINT and ALTERNATE-SERVER) or in other extensions are required.
  • If MESSAGE-INTEGRITY-SHA256 truncation is permitted, and the limits permitted for truncation.
  • The keep-alive mechanism if STUN is run over TCP or TLS-over-TCP.
  • If anycast addresses can be used for the server in case 1) TCP or TLS-over-TCP or 2) authentication is used.

on top of that, any STUN Usage must think about the security implications of using STUN in that usage ๐Ÿšจ a bunch of attacks against STUN are known (see the Security Considerations section in this document), and any usage must consider how to thwart or mitigate them. honestly, this part is serious business ๐Ÿ˜ญ

finally, a usage must consider whether it's an example of the Unilateral Self-Address Fixing approach to NAT traversal. if it is, it needs to address the questions raised in RFC 3424 [RFC3424] ๐Ÿ”


14. STUN Attributes ๐Ÿ’…

after the STUN header come zero or more attributes โœจ each attribute MUST be TLV encoded, with a 16-bit type, a 16-bit length, and a value. each STUN attribute MUST end on a 32-bit boundary. as mentioned above, all fields in an attribute are sent most significant bit first ๐Ÿง 

      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |         Type                  |            Length             |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                         Value (variable)                ....
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Figure 4: Format of STUN Attributes

the value in the Length field MUST contain the length of the Value part of the attribute, before padding, measured in bytes ๐Ÿ“ since STUN aligns attributes on 32-bit boundaries, any attribute whose content isn't a multiple of 4 bytes gets padded with 1, 2, or 3 bytes so the value is a multiple of 4 bytes. the padding bits MUST be set to zero when sending and MUST be ignored by the receiver ๐Ÿซถ

any attribute type MAY appear more than once in a STUN message ๐ŸŒ€ unless specified otherwise, the order of appearance matters: only the first occurrence needs to be processed by a receiver, and any duplicates MAY be ignored by a receiver.

to let future revisions add new attributes if needed, the attribute space is split into two ranges ๐Ÿฐ attributes with type values between 0x0000 and 0x7FFF are comprehension-required attributes, which means the STUN agent cannot successfully process the message unless it understands the attribute. attributes with type values between 0x8000 and 0xFFFF are comprehension-optional attributes, which means the STUN agent can ignore them if it doesn't understand them ๐ŸŒˆ

the set of STUN attribute types is maintained by IANA ๐Ÿ“‹ the initial set defined by this specification is found in Section 18.3.

the rest of this section describes the format of the various attributes defined in this specification ๐Ÿงš

14.1. MAPPED-ADDRESS

the MAPPED-ADDRESS attribute indicates a reflexive transport address of the client ๐Ÿชž it's made of an 8-bit address family and a 16-bit port, followed by a fixed-length value holding the IP address. if the address family is IPv4, the address MUST be 32 bits. if the address family is IPv6, the address MUST be 128 bits. all fields must be in network byte order.

the format of the MAPPED-ADDRESS attribute is:

      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |0 0 0 0 0 0 0 0|    Family     |           Port                |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                                                               |
     |                 Address (32 bits or 128 bits)                 |
     |                                                               |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Figure 5: Format of MAPPED-ADDRESS Attribute

the address family can be one of these values ๐ŸŽฏ

0x01:IPv4
0x02:IPv6

the first 8 bits of the MAPPED-ADDRESS MUST be set to 0 and MUST be ignored by receivers. these bits are there to line parameters up on natural 32-bit boundaries ๐Ÿ’œ

this attribute is only used by servers to achieve backwards compatibility with [RFC3489] clients ๐Ÿฅน

14.2. XOR-MAPPED-ADDRESS โœจ

okay so XOR-MAPPED-ADDRESS is basically MAPPED-ADDRESS's glow-up ๐Ÿ’… same exact job, except the reflexive transport address gets scrambled with the XOR function so nobody (including sketchy middleboxes) can just read it off the wire ๐Ÿ™ˆ

The format of the XOR-MAPPED-ADDRESS is:

      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |0 0 0 0 0 0 0 0|    Family     |         X-Port                |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                X-Address (Variable)
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

             Figure 6: Format of XOR-MAPPED-ADDRESS Attribute

The Family field is the IP address family, and it's encoded exactly the same way as the Family field in MAPPED-ADDRESS ๐ŸŒธ

Now the fun part, the XOR math ๐Ÿงฎ X-Port is the mapped port XOR'd with the most significant 16 bits of the magic cookie. If the family is IPv4, X-Address is the mapped IP address XOR'd with the magic cookie. If the family is IPv6, X-Address is the mapped IP address XOR'd with the magic cookie concatenated with the 96-bit transaction ID ๐Ÿฆ‹ And in every single case, the XOR works on its inputs in network byte order, which just means the order they'll be encoded in the message. No freestyling the byte order, bestie ๐Ÿ’€

The rules for encoding and processing the first 8 bits of the attribute's value, the rules for handling multiple occurrences of the attribute, and the rules for processing address families are all the same as for MAPPED-ADDRESS. Copy-paste energy, no notes ๐Ÿซถ

Note: XOR-MAPPED-ADDRESS and MAPPED-ADDRESS only differ in how they encode the transport address. XOR-MAPPED-ADDRESS XORs it with the magic cookie, and MAPPED-ADDRESS just stores it in plain binary. RFC 3489 originally only had MAPPED-ADDRESS ๐Ÿ“ But then deployment experience showed that some NATs rewrite the 32-bit binary payloads containing the NAT's public IP address, like STUN's MAPPED-ADDRESS attribute, in a well-meaning but misguided attempt at a generic Application Layer Gateway (ALG) function. ๐Ÿ˜ญ That kind of behavior messes with STUN and also makes STUN's message-integrity checking fail.

14.3. USERNAME ๐ŸŽ€

The USERNAME attribute is used for message integrity. It tells you which username and password combo was used in the message-integrity check, so it's basically the ID badge for the credentials ๐Ÿชช

The value of USERNAME is a variable-length value holding the authentication username. It MUST contain a UTF-8-encoded [RFC3629] sequence of fewer than 509 bytes, and it MUST have been processed using the OpaqueString profile [RFC8265]. A compliant implementation MUST be able to parse a UTF-8-encoded sequence of 763 or fewer octets so it stays compatible with [RFC5389] โœจ

Note: [RFC5389] accidentally pointed at the definition of UTF-8 in [RFC2279]. ๐Ÿ™ƒ [RFC2279] allowed up to 6 octets per encoded character, but it got replaced by [RFC3629], which only allows 4 octets per encoded character, matching changes made in Unicode 2.0 and ISO/IEC 10646.
Note: This spec uses the OpaqueString profile instead of the UsernameCasePreserved profile for username string processing, so it plays nicer with password stores that already exist ๐Ÿ’œ Lots of password databases used for HTTP and SIP Digest authentication store the MD5 hash of username:realm:password instead of a plain text password. [RFC3489] was designed so STUN authentication would be compatible with those databases as much as possible. It did no pre-processing of usernames and passwords, except banning non-space ASCII control characters, just like SIP and HTTP. The next revision, [RFC5389], used the SASLprep [RFC4013] stringprep [RFC3454] profile to pre-process usernames and passwords instead. SASLprep uses Unicode Normalization Form KC (Compatibility Decomposition, followed by Canonical Composition) [UAX15], and it prohibits various control, space, and non-text, deprecated, or inappropriate codepoints. Then the PRECIS framework [RFC8264] obsoleted stringprep, and PRECIS handling of usernames and passwords [RFC8265] uses Unicode Normalization Form C (Canonical Decomposition, followed by Canonical Composition).
Note (continued): Sure, there are a few specific cases where different username strings under HTTP Digest could get mapped to a single STUN username processed with OpaqueString, but those cases are super unlikely and easy to detect and fix ๐Ÿ” With a UsernameCasePreserved profile, it'd be way more likely that valid HTTP Digest usernames wouldn't match their processed forms, especially usernames with bidirectional text and compatibility forms. ๐Ÿ˜ฌ And operators are free to further restrict the allowed codepoints in usernames to dodge problematic characters.

14.4. USERHASH ๐Ÿ”

The USERHASH attribute is used as a replacement for the USERNAME attribute when username anonymity is supported. Basically, it hides the actual username from anyone snooping ๐Ÿฆ‹

The value of USERHASH has a fixed length of 32 bytes. The username MUST have been processed using the OpaqueString profile [RFC8265], and the realm MUST have been processed using the OpaqueString profile [RFC8265] before hashing. Both of those MUSTs are doing heavy lifting here ๐Ÿซถ

The following is the operation that the client will perform to hash the username:

userhash = SHA-256(OpaqueString(username) ":" OpaqueString(realm))

14.5. MESSAGE-INTEGRITY ๐Ÿ”ฅ

The MESSAGE-INTEGRITY attribute contains an HMAC-SHA1 [RFC2104] of the STUN message. It can show up in any STUN message type โœจ Since it uses the SHA-1 hash, the HMAC will be 20 bytes.

The key for the HMAC depends on which credential mechanism is in use. Section 9.1.1 defines the key for the short-term credential mechanism, and Section 9.2.2 defines the key for the long-term credential mechanism. Other credential mechanisms MUST define the key that gets used for the HMAC. Don't wing it, bestie ๐Ÿ™…โ€โ™€๏ธ

The text used as input to HMAC is the STUN message, up to and including the attribute right before the MESSAGE-INTEGRITY attribute. The Length field of the STUN message header gets adjusted to point to the end of the MESSAGE-INTEGRITY attribute, and the value of the MESSAGE-INTEGRITY attribute is set to a dummy value for now ๐Ÿง

Once the computation is done, the value of the MESSAGE-INTEGRITY attribute gets filled in, and the length in the STUN header is set to its correct value, which is the length of the entire message. When you're validating the MESSAGE-INTEGRITY, the Length field in the STUN header must be adjusted to point to the end of the MESSAGE-INTEGRITY attribute before you calculate the HMAC over the STUN message, up to and including the attribute right before MESSAGE-INTEGRITY. That adjustment is necessary when attributes like FINGERPRINT and MESSAGE-INTEGRITY-SHA256 show up after MESSAGE-INTEGRITY ๐ŸŒˆ See also [RFC5769] for examples of these calculations.

14.6. MESSAGE-INTEGRITY-SHA256 ๐ŸŒธ

The MESSAGE-INTEGRITY-SHA256 attribute contains an HMAC-SHA256 [RFC2104] of the STUN message. It can be present in any STUN message type. It actually contains an initial portion of the HMAC-SHA-256 [RFC2104] of the STUN message, not the whole thing ๐Ÿ‘€ The value will be at most 32 bytes, but it MUST be at least 16 bytes and MUST be a multiple of 4 bytes. The value must be the full 32 bytes unless the STUN Usage explicitly specifies that truncation is allowed. STUN Usages may specify a minimum length longer than 16 bytes, so check your usage spec, babe ๐Ÿ’…

The key for the HMAC depends on which credential mechanism is in use. Section 9.1.1 defines the key for the short-term credential mechanism, and Section 9.2.2 defines the key for the long-term credential mechanism. Other credential mechanism MUST define the key that is used for the HMAC ๐Ÿ”‘

The text used as input to HMAC is the STUN message, up to and including the attribute right before the MESSAGE-INTEGRITY-SHA256 attribute. The Length field of the STUN message header is adjusted to point to the end of the MESSAGE-INTEGRITY-SHA256 attribute, and the value of the MESSAGE-INTEGRITY-SHA256 attribute is set to a dummy value.

Once the computation is performed, the value of the MESSAGE-INTEGRITY-SHA256 attribute is filled in, and the length in the STUN header is set to its correct value, the length of the entire message. When validating the MESSAGE-INTEGRITY-SHA256, the Length field in the STUN header must be adjusted to point to the end of the MESSAGE-INTEGRITY-SHA256 attribute before calculating the HMAC over the STUN message, up to and including the attribute right before MESSAGE-INTEGRITY-SHA256. That adjustment is necessary when attributes like FINGERPRINT appear after MESSAGE-INTEGRITY-SHA256. See also Appendix B.1 for examples of these calculations ๐Ÿงฎ

14.7. FINGERPRINT ๐Ÿงš

The FINGERPRINT attribute MAY be present in all STUN messages. It's the optional little checksum charm that helps you tell STUN packets apart from everybody else's packets โœจ

The value of the attribute is the CRC-32 of the STUN message up to (but not including) the FINGERPRINT attribute itself, XOR'd with the 32-bit value 0x5354554e. ๐ŸŒŸ That XOR is there so the FINGERPRINT test won't report a false positive on a packet that has a CRC-32 generated by some other application protocol. The 32-bit CRC is the one defined in ITU V.42 [ITU.V42.2002], with the generator polynomial x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x + 1. If you want sample CRC-32 code, see Section 8 of [RFC1952] ๐Ÿซถ

When it's present, the FINGERPRINT attribute MUST be the last attribute in the message, so it'll show up after MESSAGE-INTEGRITY and MESSAGE-INTEGRITY-SHA256 ๐Ÿ’€

The FINGERPRINT attribute can help distinguish STUN packets from packets of other protocols. See Section 7 ๐Ÿฆ‹

Just like MESSAGE-INTEGRITY and MESSAGE-INTEGRITY-SHA256, the CRC used in the FINGERPRINT attribute covers the Length field from the STUN message header. So before you compute the CRC, that value must be correct and must include the CRC attribute as part of the message length ๐Ÿ™ˆ When you use the FINGERPRINT attribute in a message, the attribute first goes into the message with a dummy value. Then the CRC gets computed, and the attribute's value gets updated. If the MESSAGE-INTEGRITY or MESSAGE-INTEGRITY-SHA256 attribute is also present, it must already be there with the correct message-integrity value before the CRC is computed, since the CRC is done over the values of the MESSAGE-INTEGRITY and MESSAGE-INTEGRITY-SHA256 attributes too. Order of operations matters, bestie, no shortcuts ๐Ÿ‘‘

14.8. ERROR-CODE ๐Ÿšจ

okay so ERROR-CODE is the attribute that shows up whenever a request goes sideways ๐Ÿ’€ It carries a numeric error code in the range of 300 to 699, plus a text reason phrase encoded in UTF-8 [RFC3629]. It's also consistent with SIP [RFC3261] and HTTP [RFC7231] when it comes to code assignments and meanings, which is so iconic of it ๐Ÿซถ The reason phrase is just for diagnostics, so it can say whatever fits the code. The IANA registry for error codes lists recommended reason phrases for the defined codes. The reason phrase MUST be a UTF-8-encoded [RFC3629] sequence of fewer than 128 characters (it can be as long as 509 bytes when encoding and 763 bytes when decoding).

      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |           Reserved, should be 0         |Class|     Number    |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |      Reason Phrase (variable)                                ..
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Figure 7: Format of ERROR-CODE Attribute ๐ŸŽ€

To make processing easier, the class (the hundreds digit) gets its own slot, separate from the rest of the code, as you can see in Figure 7 โœจ

The Reserved bits SHOULD be 0 and are there for alignment on 32-bit boundaries. Receivers MUST ignore these bits. The Class is the hundreds digit of the error code, and its value MUST be between 3 and 6. The Number is the binary encoding of the error code modulo 100, and its value MUST be between 0 and 99.

The following error codes, along with their recommended reason phrases, are defined:

  • 300 Try Alternate: The client should contact an alternate server for this request. This error response MUST only be sent if the request included either a USERNAME or USERHASH attribute and a valid MESSAGE-INTEGRITY or MESSAGE-INTEGRITY-SHA256 attribute; otherwise, it MUST NOT be sent and error code 400 (Bad Request) is suggested. This error response MUST be protected with the MESSAGE-INTEGRITY or MESSAGE-INTEGRITY-SHA256 attribute, and receivers MUST validate the MESSAGE-INTEGRITY or MESSAGE-INTEGRITY-SHA256 of this response before redirecting themselves to an alternate server.
    • Note: Failure to generate and validate message integrity for a 300 response allows an on-path attacker to falsify a 300 response, thus causing subsequent STUN messages to be sent to a victim. ๐Ÿ˜ฑ
  • 400 Bad Request: The request was malformed. The client SHOULD NOT retry the request without modification from the previous attempt. The server may not be able to generate a valid MESSAGE-INTEGRITY or MESSAGE-INTEGRITY-SHA256 for this error, so the client MUST NOT expect a valid MESSAGE-INTEGRITY or MESSAGE-INTEGRITY-SHA256 attribute on this response. ๐Ÿ™ˆ
  • 401 Unauthenticated: The request did not contain the correct credentials to proceed. The client should retry the request with proper credentials. ๐Ÿ”‘
  • 420 Unknown Attribute: The server received a STUN packet containing a comprehension-required attribute that it did not understand. The server MUST put this unknown attribute in the UNKNOWN-ATTRIBUTE attribute of its error response. ๐Ÿงฉ
  • 438 Stale Nonce: The NONCE used by the client was no longer valid. The client should retry, using the NONCE provided in the response. โฐ
  • 500 Server Error: The server has suffered a temporary error. The client should try again. ๐Ÿฅบ

14.9. REALM ๐Ÿ‘‘

The REALM attribute may be present in requests and responses. It contains text that meets the grammar for "realm-value" as described in [RFC3261], just without the double quotes and their surrounding whitespace. So it's an unquoted realm-value, which means it's a sequence of qdtext or quoted-pair. It MUST be a UTF-8-encoded [RFC3629] sequence of fewer than 128 characters (as long as 509 bytes when encoding them and as long as 763 bytes when decoding them), and it MUST have been processed using the OpaqueString profile [RFC8265]. ๐Ÿ’…

Presence of the REALM attribute in a request means long-term credentials are being used for authentication. Presence in certain error responses means the server wants the client to use a long-term credential in that realm for authentication. very specific, very intentional ๐Ÿ’œ

14.10. NONCE ๐ŸŽ€

The NONCE attribute may be present in requests and responses. It contains a sequence of qdtext or quoted-pair, which are defined in [RFC3261]. Quick note: that means the NONCE attribute won't include the actual surrounding quote characters ๐Ÿซ  The NONCE attribute MUST be fewer than 128 characters (as long as 509 bytes when encoding them and as long as 763 bytes when decoding them). If you want guidance on picking nonce values as a server, check out Section 5.4 of [RFC7616] โœจ

14.11. PASSWORD-ALGORITHMS ๐Ÿ”

The PASSWORD-ALGORITHMS attribute may be present in requests and responses. It holds the list of algorithms the server can use to derive the long-term password. the vibe is "here are my options, bestie"

The set of known algorithms is maintained by IANA. The initial set defined by this spec is in Section 18.5.

The attribute holds a list of algorithm numbers and variable-length parameters. The algorithm number is a 16-bit value as defined in Section 18.5. Each parameters block starts with its length (before padding) as a 16-bit value, followed by the parameters specific to that algorithm. The parameters are padded to a 32-bit boundary, the same way an attribute is.

      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |         Algorithm 1           | Algorithm 1 Parameters Length |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                    Algorithm 1 Parameters (variable)
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |         Algorithm 2           | Algorithm 2 Parameters Length |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                    Algorithm 2 Parameters (variable)
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                                                             ...

Figure 8: Format of PASSWORD-ALGORITHMS Attribute ๐ŸŒˆ

14.12. PASSWORD-ALGORITHM ๐Ÿง

The PASSWORD-ALGORITHM attribute is present only in requests. It holds the algorithm that the server must use to derive a key from the long-term password. It's giving "one choice, no drama" ๐Ÿ’…

The set of known algorithms is maintained by IANA, and the initial set defined by this spec is in Section 18.5.

The attribute holds an algorithm number and variable-length parameters. The algorithm number is a 16-bit value as defined in Section 18.5. The parameters start with their length (before padding) as a 16-bit value, followed by the parameters specific to the algorithm. The parameters are padded to a 32-bit boundary, the same way an attribute is. Similarly, the padding bits MUST be set to zero on sending and MUST be ignored by the receiver. ๐Ÿซถ

      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |          Algorithm           |  Algorithm Parameters Length   |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |                    Algorithm Parameters (variable)
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Figure 9: Format of PASSWORD-ALGORITHM Attribute โœจ

14.13. UNKNOWN-ATTRIBUTES ๐Ÿงฉ

The UNKNOWN-ATTRIBUTES attribute is present only in an error response where the ERROR-CODE attribute's response code is 420 (Unknown Attribute).

It holds a list of 16-bit values, and each one is an attribute type the server didn't understand.

      0                   1                   2                   3
      0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |      Attribute 1 Type         |       Attribute 2 Type        |
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
     |      Attribute 3 Type         |       Attribute 4 Type    ...
     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Figure 10: Format of UNKNOWN-ATTRIBUTES Attribute ๐Ÿฆ‹

Note: In [RFC3489], this field was padded to 32 by duplicating the last attribute. In this version of the specification, the normal padding rules for attributes are used instead. ๐Ÿ™ƒ

14.14. SOFTWARE ๐Ÿ’ป

The SOFTWARE attribute holds a text description of the software the sending agent is running. Clients and servers both use it. Its value SHOULD include the manufacturer and version number. It has zero impact on how the protocol works and is purely a diagnostic and debugging tool ๐Ÿ” The value is variable length. It MUST be a UTF-8-encoded [RFC3629] sequence of fewer than 128 characters (as long as 509 when encoding them and as long as 763 bytes when decoding them).

14.15. ALTERNATE-SERVER ๐Ÿงš

The alternate server is a transport address pointing to a different STUN server that the STUN client should try. It's encoded the same way as MAPPED-ADDRESS, so it refers to one server by IP address. Basically a "try my friend instead" card ๐Ÿซถ

14.16. ALTERNATE-DOMAIN ๐ŸŒธ

The alternate domain is the domain name used to verify the IP address in the ALTERNATE-SERVER attribute when the transport uses TLS or DTLS.

The value is variable length. It MUST be a valid DNS name [RFC1123] (including A-labels [RFC5890]) of 255 or fewer ASCII characters. ๐Ÿ’–


15. Operational Considerations โญ

STUN MAY be used with anycast addresses, but only with UDP and only in STUN Usages where authentication is not used. anycast is a whole mood, but the rules are strict ๐ŸŒˆ

16. Security Considerations ๐Ÿ’€

Okay, this section is serious business, so no skipping ๐Ÿšจ

Implementations and deployments of a STUN Usage using TLS or DTLS MUST follow the recommendations in [BCP195].

Implementations and deployments of a STUN Usage using the long-term credential mechanism (Section 9.2) MUST follow the recommendations in Section 5 of [RFC7616]. this is not optional, bestie ๐Ÿ”ฅ

16.1. Attacks against the Protocol ๐Ÿ›ก๏ธ

16.1.1. Outside Attacks โœจ

okay bestie, let's talk about the scary people on the network ๐Ÿ‘€๐Ÿ’… so an attacker can try to mess with STUN messages while they're in transit ๐Ÿšš to make the STUN thing fail. these attacks get caught for both requests and responses thanks to the message-integrity mechanism, using either a short-term or long-term credential ๐Ÿ” and once it's caught, the messed-up packets get dropped, so the STUN transaction just kinda fizzles out ๐Ÿ’€ this only works for an on-path attacker, so they have to be sitting right in the middle of the route ๐Ÿ›ค๏ธ

now the sneakier one: an attacker that can watch STUN messages but not change them (think somebody chilling on the same Wi-Fi ๐Ÿ“ถ) can spot a STUN request and then instantly send back a STUN response, usually an error response, to mess up STUN processing ๐Ÿ™ˆ message-integrity also stops this for messages that use MESSAGE-INTEGRITY โœ… BUT some error responses, especially the ones about authentication, can't be protected by MESSAGE-INTEGRITY ๐Ÿ˜ญ and when STUN itself runs over a secure transport like TLS, these attacks are completely mitigated ๐Ÿซถ๐Ÿ”’

it depends on the STUN Usage how bad this stuff is ๐ŸŽ€ some of these attacks are super minor, so they don't need message integrity to deal with them ๐ŸŒธ like, if STUN is used to talk to a basic STUN server to find a server reflexive candidate for ICE, authentication and message integrity aren't required, because those attacks get caught during the connectivity check phase ๐Ÿฆ‹ BUT the connectivity checks themselves do need protection so ICE works properly overall ๐Ÿ’– as Section 13 explains, STUN Usages describe when authentication and message integrity are needed ๐Ÿ“–

since STUN uses the HMAC of a shared secret for authentication and integrity protection, it's open to offline dictionary attacks ๐Ÿซฃ when authentication is used, it SHOULD be with a strong password that isn't easy to crack offline ๐Ÿ’ช and protecting the channel itself with TLS or DTLS helps mitigate these attacks ๐Ÿ”โœจ

STUN supports both MESSAGE-INTEGRITY and MESSAGE-INTEGRITY-SHA256, which makes it vulnerable to bid-down attacks from an on-path attacker ๐Ÿ˜ฑ the attacker could strip the MESSAGE-INTEGRITY-SHA256 attribute, leaving only MESSAGE-INTEGRITY, and then exploit a potential vulnerability there ๐Ÿ’€ again, protecting the channel with TLS or DTLS mitigates these attacks ๐Ÿซถ and removing support for MESSAGE-INTEGRITY in a future version of STUN is necessary, so it needs to happen on time โฐ

Note: using SHA-256 for password hashing doesn't meet modern standards ๐Ÿšจ modern standards want password hashing to be slow, so that exhaustive password searches take a long time to compute the hash ๐Ÿข better algorithms like Argon2 [Argon2] exist, but SHA-256 was picked for consistency with [RFC7616] ๐ŸŒˆ

16.1.2. Inside Attacks ๐Ÿ•ต๏ธโ€โ™€๏ธ

okay so a rogue client might try a DoS attack on a server by sending it a huge pile of STUN requests ๐Ÿ“ฆ luckily, a server can process STUN requests statelessly, which makes these attacks hard to pull off effectively ๐Ÿ’ชโœจ

a rogue client can also use a STUN server as a reflector ๐Ÿชž by sending it requests with a falsified source IP address and port, the response gets delivered to that source IP and port ๐Ÿ“ฌ there's no amplification of the number of packets here (the STUN server sends one packet for each packet the client sends) ๐Ÿ™Œ BUT there's a small bump in the amount of data, since STUN responses are usually bigger than requests ๐Ÿ“ˆ this attack gets mitigated by ingress source address filtering ๐Ÿ›ก๏ธ

revealing the exact software version of the agent through the SOFTWARE attribute might make them more vulnerable to attacks on software that's known to have security holes ๐Ÿ˜ฌ implementers SHOULD make using the SOFTWARE attribute a configurable option โš™๏ธ๐Ÿ’–


16.1.3. Bid-Down Attacks ๐Ÿ“

this document adds the ability to pick different algorithms to protect the confidentiality of passwords stored on the server side when using the long-term credential mechanism ๐Ÿ”‘ while still staying compatible with MD5, which was the algorithm used in [RFC5389] ๐Ÿง the way it works is the server sends the client a list of supported algorithms in a PASSWORD-ALGORITHMS attribute, and the client sends back a PASSWORD-ALGORITHM attribute with the one it picked ๐Ÿค

okay here's the catch ๐Ÿ™€ the PASSWORD-ALGORITHMS attribute has to be sent in an unauthenticated response, so an on-path attacker who wants to exploit an eventual MD5 vulnerability can just strip PASSWORD-ALGORITHMS out of the unprotected response ๐Ÿ˜ˆ and then the server acts like the client is using the version of this protocol defined in [RFC5389] ๐Ÿ’€

to protect against this and other similar bid-down attacks, the nonce gets extra security bits that show which security features are in use ๐Ÿ”โœจ for password algorithm selection, the matching bit gets set in the nonce the server returns in the same response that has the PASSWORD-ALGORITHMS attribute ๐ŸŽ€ the nonce in later authenticated transactions gets checked by the server to be identical to what it originally sent, so an on-path attacker can't modify it ๐Ÿ™…โ€โ™€๏ธ also, the client is required to copy the received PASSWORD-ALGORITHMS attribute into the next authenticated transaction to that server ๐Ÿ“‹

if an on-path attacker removes PASSWORD-ALGORITHMS, it gets detected, because the client won't be able to send it back in the next authenticated transaction ๐Ÿšจ the client catches it since the security bit is set but the matching attribute is missing, and that ends the session ๐Ÿ›‘ a client using an older version of this protocol won't send PASSWORD-ALGORITHMS back, but it can only use MD5 anyway, so the attack doesn't matter here ๐Ÿคทโ€โ™€๏ธ

the on-path attacker might also try removing the security bit along with PASSWORD-ALGORITHMS, but the server will catch that when the next authenticated transaction has an invalid nonce ๐Ÿ•ต๏ธโ€โ™€๏ธ

if an on-path attacker removes some algorithms from PASSWORD-ALGORITHMS, that also fails, because the attribute will be different from the original one when the server checks it in the next authenticated transaction ๐Ÿ™…โ€โ™€๏ธ๐Ÿ’…

note that the bid-down protection in this document has a built-in limit ๐Ÿฅบ an attack can't be detected until the server gets the second request after the 401 (Unauthenticated) response ๐Ÿ˜ญ

SHA-256 was picked as the new default for password hashing for its compatibility with [RFC7616] ๐ŸŒธ but SHA-256 (like MD5) is comparatively fast, so it doesn't do much to stop brute-force attacks ๐Ÿซ  this means that if the user has a weak password, an attacker who captures a single exchange can brute-force it to learn the password, then possibly impersonate the user to the server and to other servers where the same password was used ๐Ÿšจ and yep, that attacker can impersonate the user to the server itself without any brute-force at all ๐Ÿ’€

a stronger (aka slower) algorithm, like Argon2 [Argon2], would help both of these cases ๐Ÿ’ช but in the first case, it would only help after the database entry for this user gets updated to use only that stronger mechanism ๐Ÿ”„

the bid-down defenses in this protocol stop an attacker from forcing the client and server to finish a handshake with weaker algorithms than they both support ๐Ÿ™Œ but only if the weakest shared algorithm is strong enough that brute force can't crack it ๐Ÿงฑ this doesn't defend against lots of attacks on those algorithms though ๐Ÿ˜ฌ for example, an on-path attacker might bid-down a client that supports both Argon2 [Argon2] and SHA-256 for password hashing, then use that to collect a MESSAGE-INTEGRITY-SHA256 value for an offline brute-force attack ๐Ÿ’€ the server would detect this when it gets the second request, but that doesn't stop the attacker from getting the MESSAGE-INTEGRITY-SHA256 value ๐Ÿ˜ญ

same deal with the USERHASH mechanism ๐Ÿ™ˆ an attack on it won't succeed in setting up a session, since the server will notice the feature was dropped on path ๐Ÿ›‘ but the client would still have been tricked into sending its username in the clear in the USERNAME attribute, which discloses it to the attacker ๐Ÿ˜ฑ

finally, when the bid-down protection is used for a future upgrade of the HMAC algorithm that protects messages, it only offers limited protection if the current HMAC algorithm is already compromised ๐Ÿฅ€


16.2. Attacks Affecting the Usage ๐ŸŽ€

this section lists attacks that might be launched against a usage of STUN ๐Ÿ‘€ every STUN Usage has to think about whether these attacks apply to it and, if they do, talk about countermeasures ๐Ÿ“

most of the attacks in this section are about an attacker messing with the reflexive address a STUN client learns through a Binding request/response transaction ๐Ÿชž since how the reflexive address is used depends on the usage, whether these attacks apply and how to fix them are usage-specific ๐Ÿงฉ in common situations, changing the reflexive address with an on-path attacker is super easy ๐Ÿ˜ฉ for example, in the common case where STUN runs directly over UDP, an on-path attacker can change the source IP address of the Binding request before it arrives at the STUN server ๐Ÿฅท the STUN server then returns that IP address in the XOR-MAPPED-ADDRESS attribute to the client and sends the response back to that falsified IP address and port ๐Ÿ“ญ if the attacker can also intercept this response, they can send it back toward the client ๐Ÿƒโ€โ™€๏ธ

message-integrity can't protect against this one ๐Ÿ™…โ€โ™€๏ธ a message-integrity value can't cover the source IP address, and the intervening NAT has to be able to modify that value anyway ๐ŸŒ€ so one solution to prevent the attacks listed below is for the client to verify the reflexive address it learned, the same way ICE [RFC8445] does โœ…

other usages might use other ways to prevent these attacks ๐Ÿ’…


16.2.1. Attack I: Distributed DoS (DDoS) against a Target ๐Ÿ’ฅ

in this attack, the attacker gives one or more clients the same faked reflexive address that points at the intended target ๐ŸŽฏ this tricks the STUN clients into thinking their reflexive addresses are equal to the target's ๐Ÿคก if the clients hand out that reflexive address to receive traffic on it (for example, in SIP messages), the traffic gets sent to the target instead ๐Ÿ˜ฑ this attack can provide substantial amplification, especially with clients using STUN for multimedia applications ๐Ÿ“ˆ BUT it can only be launched against targets where packets from the STUN server to the target pass through the attacker, so it's limited to certain cases ๐Ÿ™Œโœจ

16.2.2. Attack II: Silencing a Client

Okay so in this one, the attacker gives a STUN client a faked reflexive address ๐Ÿ’€. That fake address routes to absolutely nowhere, so once the client hands it out, it never gets the packets it's waiting for ๐Ÿ™ˆ. Honestly, it's not the most iconic move for an attacker ๐Ÿฅฑ. It only takes out one client, and that client usually isn't the actual target. Plus, anyone who can pull this off could just shut the client down in other ways, like stopping it from hearing back from the STUN server or even from a DHCP server ๐Ÿ’…. Same as the attack in Section 16.2.1, this only works when the attacker is on path for packets going from the STUN server toward this unused IP address ๐Ÿ›ค๏ธ.

16.2.3. Attack III: Assuming the Identity of a Client

This one is giving Attack II vibes, but with a twist โœจ. The faked reflexive address points to the attacker themselves ๐Ÿ˜ˆ. That means the attacker gets to receive traffic that was meant for the client. Main character energy for the wrong reasons ๐Ÿ’€.

16.2.4. Attack IV: Eavesdropping

In this attack, the attacker tricks the client into using a reflexive address that routes right back to them ๐Ÿ‘€. Then they just forward whatever packets they catch on to the client ๐Ÿ“ฆ. This lets the attacker see every packet sent to the client ๐Ÿ˜ญ. BUT, to pull this off, the attacker already has to be able to watch packets going from the client to the STUN server. In most cases (like when the attack happens from an access network), that means they could already see packets sent to the client anyway ๐Ÿ™ƒ. So this attack is only really useful for spying on attackers who sit on the path from the client to the STUN server, not on the path of packets being routed toward the client ๐Ÿง.

Note that this attack can be trivially launched by the STUN server itself ๐Ÿšจ. So users of STUN servers should trust the users of STUN servers as much as they'd trust any other node that can insert itself into the communication flow ๐Ÿซถ.

16.3. Hash Agility Plan

Okay, let's plan for the day HMAC-SHA256 gets cracked ๐Ÿ”. This spec uses HMAC-SHA256 for message integrity, sometimes paired with HMAC-SHA1. If HMAC-SHA256 ever turns out to be compromised, the fix should look like this:

  • A new message-integrity attribute and a new STUN Security Feature bit will both get allocated in a Standards Track document ๐Ÿ“œ. The new message-integrity attribute's value will be computed with a brand new hash. The STUN Security Feature bit will do two jobs at once: 1) it tells a STUN client using the long-term credential mechanism that this server supports the new hash algorithm, and 2) it prevents bid-down attacks on the new message-integrity attribute ๐Ÿ›ก๏ธ.
  • STUN clients and servers using the short-term credential mechanism will need to update the external mechanism they use to signal which message-integrity attributes are in use ๐Ÿ”„.

The bid-down protection in this document is brand new ๐Ÿ†•, so it can't yet stop a bid-down attack that drops the hash algorithm all the way down to HMAC-SHA1 ๐Ÿ˜ฌ. That's why, after a transition period, a new document updating this one will assign a new STUN Security Feature bit for deprecating HMAC-SHA1. When that bit is used, it signals that HMAC-SHA1 is deprecated and should no longer be used ๐Ÿšซ.

Same deal if HMAC-SHA256 is ever found to be compromised as a userhash: a new userhash attribute and a new STUN Security Feature bit will be allocated in a Standards Track document ๐Ÿงฉ. The new userhash attribute's value will be computed using a new hash. The STUN Security Feature bit will simultaneously 1) signal to a STUN client using the long-term credential mechanism that this server supports this new hash algorithm for the userhash attribute, and 2) prevent bid-down attacks on the new userhash attribute ๐Ÿ’–.

17. IAB Considerations

The IAB has looked into Unilateral Self-Address Fixing (UNSAF) ๐Ÿ”. That's the general process where a client tries to figure out its address in another realm on the far side of a NAT, using a collaborative protocol reflection mechanism [RFC3424]. STUN can handle this job with a Binding request/response transaction, as long as one agent is behind a NAT and the other is on the public side of that NAT ๐ŸŒˆ.

The IAB has suggested that protocols built for this purpose document a specific set of considerations ๐Ÿ“. Some STUN Usages provide UNSAF functions (like ICE [RFC8445]) and some don't (like SIP Outbound [RFC5626]). So those usages need to address these considerations themselves ๐Ÿ’….

18. IANA Considerations

18.1. STUN Security Features Registry

A STUN Security Feature set defines 24 bits as flags ๐Ÿšฉ.

IANA has created a new registry for the STUN Security Features that are protected by the bid-down attack prevention mechanism in Section 9.2.1 ๐ŸŽ€. The initial STUN Security Features are:

Bit 0: Password algorithms
Bit 1: Username anonymity
Bit 2-23: Unassigned

Bits get assigned starting from the most significant side of the bit set, so Bit 0 is the leftmost bit and Bit 23 is the rightmost bit ๐Ÿง . New Security Features are assigned by Standards Action [RFC8126].

18.2. STUN Methods Registry

A STUN method is a hex number in the range 0x000-0x0FF ๐Ÿ”ข. The encoding of a STUN method into a STUN message is described in Section 5 โœจ.

STUN methods in the range 0x000-0x07F are assigned by IETF Review [RFC8126]. STUN methods in the range 0x080-0x0FF are assigned by Expert Review [RFC8126]. The expert's job is to check that the selected codepoint(s) aren't already in use and that the request isn't for an abnormally large number of codepoints ๐Ÿง‘โ€๐Ÿ’ผ. Technical review of the extension itself is outside the expert's scope ๐Ÿ™…โ€โ™€๏ธ.

IANA has updated the name for method 0x002 (more on that below) and updated the reference from RFC 5389 to RFC 8489 for the following STUN methods:

0x000: Reserved
0x001: Binding
0x002: Reserved; was SharedSecret prior to [RFC5389]

18.3. STUN Attributes Registry

A STUN attribute type is a hex number in the range 0x0000-0xFFFF ๐Ÿ”ข. Attribute types in the range 0x0000-0x7FFF are considered comprehension-required, and attribute types in the range 0x8000-0xFFFF are considered comprehension-optional ๐Ÿง. A STUN agent handles unknown comprehension-required and comprehension-optional attributes differently ๐Ÿค”.

Attribute types in the first half of the comprehension-required range (0x0000-0x3FFF) and in the first half of the comprehension-optional range (0x8000-0xBFFF) are assigned by IETF Review [RFC8126]. Attribute types in the second half of the comprehension-required range (0x4000-0x7FFF) and in the second half of the comprehension-optional range (0xC000-0xFFFF) are assigned by Expert Review [RFC8126]. The expert verifies that the selected codepoint(s) are not in use and that the request isn't for an abnormally large number of codepoints. Technical review of the extension itself is outside the expert's scope ๐Ÿง‘โ€๐Ÿ’ผ.

18.3.1. Updated Attributes

IANA has updated the names for attributes 0x0002, 0x0004, 0x0005, 0x0007, and 0x000B, and updated the reference from RFC 5389 to RFC 8489 for each of the following STUN methods ๐Ÿ”„.

Also, [RFC5389] made a mistake with the name of attribute 0x0003 ๐Ÿ™ˆ. It called it CHANGE-ADDRESS when it was actually previously called CHANGE-REQUEST. So IANA has updated the description for 0x0003 to read "Reserved; was CHANGE-REQUEST prior to [RFC5389]" ๐Ÿ› ๏ธ.

Comprehension-required range (0x0000-0x7FFF):
0x0000: Reserved
0x0001: MAPPED-ADDRESS
0x0002: Reserved; was RESPONSE-ADDRESS prior to [RFC5389]
0x0003: Reserved; was CHANGE-REQUEST prior to [RFC5389]
0x0004: Reserved; was SOURCE-ADDRESS prior to [RFC5389]
0x0005: Reserved; was CHANGED-ADDRESS prior to [RFC5389]
0x0006: USERNAME
0x0007: Reserved; was PASSWORD prior to [RFC5389]
0x0008: MESSAGE-INTEGRITY
0x0009: ERROR-CODE
0x000A: UNKNOWN-ATTRIBUTES
0x000B: Reserved; was REFLECTED-FROM prior to [RFC5389]
0x0014: REALM
0x0015: NONCE
0x0020: XOR-MAPPED-ADDRESS

Comprehension-optional range (0x8000-0xFFFF)
0x8022: SOFTWARE
0x8023: ALTERNATE-SERVER
0x8028: FINGERPRINT

18.3.2. New Attributes

IANA has added the following attributes to the "STUN Attributes" registry โœจ:

Comprehension-required range (0x0000-0x7FFF):
0x001C: MESSAGE-INTEGRITY-SHA256
0x001D: PASSWORD-ALGORITHM
0x001E: USERHASH

Comprehension-optional range (0x8000-0xFFFF)
0x8002: PASSWORD-ALGORITHMS
0x8003: ALTERNATE-DOMAIN

18.4. STUN Error Codes Registry

A STUN error code is a number in the range 0-699 ๐Ÿ”ข. Each one comes with a textual reason phrase in UTF-8 [RFC3629]. That phrase is only meant for human eyes and can say whatever's appropriate, though this document only proposes suggested values ๐Ÿ’ฌ.

STUN error codes match SIP [RFC3261] and HTTP [RFC7231] in codepoint assignments and semantics ๐Ÿค.

New STUN error codes are assigned based on IETF Review [RFC8126]. The specification must carefully consider how clients that don't understand the error code will process it before granting the request. See the rules in Section 6.3.4 ๐Ÿงพ.

IANA has updated the reference from RFC 5389 to RFC 8489 for the error codes defined in Section 14.8 ๐Ÿ“Œ. IANA has also changed the name of the 401 error code from "Unauthorized" to "Unauthenticated" ๐Ÿ™Œ.

18.5. STUN Password Algorithms Registry

IANA has created a new registry titled "STUN Password Algorithms" ๐Ÿ”.

A password algorithm is a hex number in the range 0x0000-0xFFFF ๐Ÿ”ข.

The initial contents of the "Password Algorithm" registry are:

0x0000: Reserved
0x0001: MD5
0x0002: SHA-256
0x0003-0xFFFF: Unassigned

Password algorithms in the first half of the range (0x0000-0x7FFF) are assigned by IETF Review [RFC8126]. Password algorithms in the second half of the range (0x8000-0xFFFF) are assigned by Expert Review [RFC8126] ๐Ÿง‘โ€๐Ÿ’ผ.

18.5.1. Password Algorithms

18.5.1.1. MD5

This password algorithm is taken from [RFC1321] ๐Ÿ“.

The key length is 16 bytes, and the parameters value is empty.

Note: This algorithm MUST only be used for compatibility with legacy systems ๐Ÿšจ.
key = MD5(username ":" OpaqueString(realm)
  ":" OpaqueString(password))

18.5.1.2. SHA-256

This password algorithm is taken from [RFC7616] ๐ŸŒธ.

The key length is 32 bytes, and the parameters value is empty.

key = SHA-256(username ":" OpaqueString(realm)
  ":" OpaqueString(password))

18.6. STUN UDP and TCP Port Numbers

IANA has updated the reference from RFC 5389 to RFC 8489 for the following ports in the "Service Name and Transport Protocol Port Number Registry" ๐Ÿฆ‹.

stun   3478/tcp   Session Traversal Utilities for NAT (STUN) port
stun   3478/udp   Session Traversal Utilities for NAT (STUN) port
stuns  5349/tcp   Session Traversal Utilities for NAT (STUN) port

19. Changes since RFC 5389 ๐Ÿ’…

okay so this spec obsoletes [RFC5389], which means it's the glow-up of the old one ๐Ÿฆ‹ here's everything that's different:

  • Added support for DTLS-over-UDP [RFC6347] โœจ
  • Made it super clear that the RTO counts as stale if there are no transactions with the server ๐Ÿซถ
  • Lined up the RTO calculation with [RFC6298] ๐Ÿ“
  • Updated the ciphersuites for TLS ๐Ÿ”
  • Added support for STUN URI [RFC7064] ๐ŸŒธ
  • Added support for SHA256 message integrity ๐Ÿ”ฅ
  • Updated the Preparation, Enforcement, and Comparison of Internationalized Strings (PRECIS) support to [RFC8265] ๐Ÿ’œ
  • Added a protocol and a registry for choosing the password encryption algorithm ๐ŸŽ€
  • Added support for anonymous username ๐Ÿงš
  • Added a protocol and a registry for preventing bid-down attacks ๐Ÿ›ก๏ธ
  • Specified that sharing a NONCE is no longer permitted ๐Ÿ™ˆ
  • Added the possibility of using a domain name in the alternate server mechanism ๐ŸŒˆ
  • Added more C snippets ๐Ÿ’ป
  • Added test vector ๐Ÿ“

20. References

20.1. Normative References

the normative refs are the ones you truly need to read before this spec makes sense, so here they are, every single one ๐Ÿ“š

20.2. Informative References โœจ

okay so these are the informative references, the "good to know" reading list ๐Ÿ“š. Nothing here is required reading to implement the protocol, but it's where all the backstory lives ๐Ÿ’…


Appendix A. C Snippet to Determine STUN Message Types ๐Ÿงฉ

okay this one's my favourite ๐Ÿค“ it's a tiny bit of C that lets you figure out what kind of STUN message you're looking at ๐Ÿ’œ

Given a 16-bit STUN message type value in host byte order in msg_type parameter, below are C macros to determine the STUN message types:

#define IS_REQUEST(msg_type)       (((msg_type) & 0x0110) == 0x0000)
#define IS_INDICATION(msg_type)    (((msg_type) & 0x0110) == 0x0010)
#define IS_SUCCESS_RESP(msg_type)  (((msg_type) & 0x0110) == 0x0100)
#define IS_ERR_RESP(msg_type)      (((msg_type) & 0x0110) == 0x0110)

A function to convert method and class into a message type:

int type(int method, int cls) {
  return (method & 0x1F80) << 2 | (method & 0x0070) << 1
    | (method & 0x000F) | (cls & 0x0002) << 7
    | (cls & 0x0001) << 4;
  }

A function to extract the method from the message type:

int method(int type) {
  return (type & 0x3E00) >> 2 | (type & 0x00E0) >> 1
    | (type & 0x000F);
  }

A function to extract the class from the message type:

int cls(int type) {
  return (type & 0x0100) >> 7 | (type & 0x0010) >> 4;
  }

Appendix B. Test Vectors ๐Ÿงช

this section adds MESSAGE-INTEGRITY-SHA256 to the test vectors from [RFC5769] ๐ŸŽ€ so you can check your code against known-good bytes โœจ

All the formats and definitions listed in Section 2 of [RFC5769] apply here.

B.1. Sample Request with Long-Term Authentication with MESSAGE-INTEGRITY-SHA256 and USERHASH ๐ŸŒธ

this request is the main character ๐Ÿ‘‘ here are the parameters it uses:

  • Username: "<U+30DE><U+30C8><U+30EA><U+30C3><U+30AF><U+30B9>" (without quotes) unaffected by OpaqueString [RFC8265] processing
  • Password: "The<U+00AD>M<U+00AA>tr<U+2168>" and "TheMatrIX" (without quotes) respectively before and after OpaqueString [RFC8265] processing
  • Nonce: "obMatJos2AAACf//499k954d6OL34oL9FSTvy64sA" (without quotes)
  • Realm: "example.org" (without quotes)

And here's the full message, byte by byte ๐Ÿ“

00 01 00 9c      Request type and message length
21 12 a4 42      Magic cookie
78 ad 34 33   }
c6 ad 72 c0   }  Transaction ID
29 da 41 2e   }
00 1e 00 20      USERHASH attribute header
4a 3c f3 8f   }
ef 69 92 bd   }
a9 52 c6 78   }
04 17 da 0f   }  Userhash value (32 bytes)
24 81 94 15   }
56 9e 60 b2   }
05 c4 6e 41   }
40 7f 17 04   }
00 15 00 29      NONCE attribute header
6f 62 4d 61   }
74 4a 6f 73   }
32 41 41 41   }
43 66 2f 2f   }
34 39 39 6b   }  Nonce value and padding (3 bytes)
39 35 34 64   }
36 4f 4c 33   }
34 6f 4c 39   }
46 53 54 76   }
79 36 34 73   }
41 00 00 00   }
00 14 00 0b      REALM attribute header
65 78 61 6d   }
70 6c 65 2e   }  Realm value (11 bytes) and padding (1 byte)
6f 72 67 00   }
00 1c 00 20      MESSAGE-INTEGRITY-SHA256 attribute header
e4 68 6c 8f   }
0e de b5 90   }
13 e0 70 90   }
01 0a 93 ef   }  HMAC-SHA256 value
cc bc cc 54   }
4c 0a 45 d9   }
f8 30 aa 6d   }
6f 73 5a 01   }

Acknowledgements ๐Ÿ’–

huge thanks to everyone who dropped comments, suggestions, and questions that made this doc better ๐Ÿซถ you're all iconic ๐Ÿฅน

Thanks to Michael Tuexen, Tirumaleswar Reddy, Oleg Moskalenko, Simon Perreault, Benjamin Schwartz, Rifaat Shekh-Yusef, Alan Johnston, Jonathan Lennox, Brandon Williams, Olle Johansson, Martin Thomson, Mihaly Meszaros, Tolga Asveren, Noriyuki Torii, Spencer Dawkins, Dale Worley, Matthew Miller, Peter Saint-Andre, Julien Elie, Mirja Kuehlewind, Eric Rescorla, Ben Campbell, Adam Roach, Alexey Melnikov, and Benjamin Kaduk for the comments, suggestions, and questions that helped improve this document.

The Acknowledgements section of RFC 5389 appeared as follows:

The authors would like to thank Cedric Aoun, Pete Cordell, Cullen Jennings, Bob Penfield, Xavier Marjou, Magnus Westerlund, Miguel Garcia, Bruce Lowekamp, and Chris Sullivan for their comments, and Baruch Sterman and Alan Hawrylyshen for initial implementations. Thanks for Leslie Daigle, Allison Mankin, Eric Rescorla, and Henning Schulzrinne for IESG and IAB input on this work.


Contributors ๐Ÿงš

the OG crew ๐Ÿ•ฐ๏ธโœจ

Christian Huitema and Joel Weinberger were original coauthors of RFC 3489.


Authors' Addresses ๐Ÿ“ฎ

the people behind the protocol ๐Ÿ’… here's how to reach them ๐Ÿฆ‹

Marc Petit-Huguenin Impedance Mismatch

Email: marc@petit-huguenin.org

Gonzalo Salgueiro Cisco 7200-12 Kit Creek Road Research Triangle Park, NC 27709 United States of America

Email: gsalguei@cisco.com

Jonathan Rosenberg Five9 Edison, NJ United States of America

Email: jdrosen@jdrosen.net URI: http://www.jdrosen.net

Dan Wing Citrix Systems, Inc. United States of America

Email: dwing-ietf@fuggles.com

Rohan Mahy Unaffiliated

Email: rohan.ietf@gmail.com

Philip Matthews Nokia 600 March Road Ottawa, Ontario K2K 2T6 Canada

Phone: 613-784-3139 Email: philip_matthews@magma.ca

๐Ÿ“ฆ where this page comes from