RFC 4347

Datagram Transport Layer Security

๐Ÿ“… published April 2006, from ietf

Network Working Group E. Rescorla Request for Comments: 4347 RTFM, Inc. Category: Standards Track N. Modadugu Stanford University April 2006

Okay bestie, let's get into it ๐ŸŽ€ This is RFC 4347, Datagram Transport Layer Security (DTLS) ๐Ÿฆ‹ It's a Standards Track doc, written by E. Rescorla (RTFM, Inc.) and N. Modadugu (Stanford University), dated April 2006. Nothing in the title block says it obsoletes or updates anything, so it stands on its own โœจ This is part 1 of 5, so more is coming!

Status of This Memo ๐Ÿ“œ

okay so this section is the official "here's what this doc is" part ๐Ÿ’… It says this is an Internet standards track protocol for the Internet community, and that it's asking for discussion and suggestions for improvements ๐Ÿ’ฌ For the current standardization state and status, you're supposed to check the current edition of "Internet Official Protocol Standards" (STD 1) ๐Ÿ“š And the memo can be distributed freely, no limits ๐ŸŒธ

Copyright (C) The Internet Society (2006) โœจ Legal stuff, but it's giving "we own the words, but you can share them" ๐Ÿซถ

Abstract ๐ŸŒˆ

okay the main vibe: this doc specifies Version 1.0 of Datagram Transport Layer Security (DTLS) ๐ŸŽ€ DTLS gives communications privacy for datagram protocols ๐Ÿ”’ It lets client/server apps talk in a way that's designed to stop eavesdropping, tampering, and message forgery ๐Ÿ™ˆ DTLS is based on Transport Layer Security (TLS) and gives you equivalent security guarantees, so it's basically TLS's security energy but for datagrams ๐Ÿ’– And the datagram semantics of the underlying transport are preserved by DTLS ๐Ÿฆ‹ That's the main character moment โœจ

Table of Contents ๐Ÿ—‚๏ธ

   1. Introduction ....................................................2
      1.1. Requirements Terminology ...................................3
   2. Usage Model .....................................................3
   3. Overview of DTLS ................................................4
      3.1. Loss-Insensitive Messaging .................................4
      3.2. Providing Reliability for Handshake ........................4
           3.2.1. Packet Loss .........................................5
           3.2.2. Reordering ..........................................5
           3.2.3. Message Size ........................................5
      3.3. Replay Detection ...........................................6
   4. Differences from TLS ............................................6
      4.1. Record Layer ...............................................6
           4.1.1. Transport Layer Mapping .............................7

                  4.1.1.1. PMTU Discovery .............................8
           4.1.2. Record Payload Protection ...........................9
                  4.1.2.1. MAC ........................................9
                  4.1.2.2. Null or Standard Stream Cipher .............9
                  4.1.2.3. Block Cipher ..............................10
                  4.1.2.4. New Cipher Suites .........................10
                  4.1.2.5. Anti-replay ...............................10
      4.2. The DTLS Handshake Protocol ...............................11
           4.2.1. Denial of Service Countermeasures ..................11
           4.2.2. Handshake Message Format ...........................13
           4.2.3. Message Fragmentation and Reassembly ...............15
           4.2.4. Timeout and Retransmission .........................15
                  4.2.4.1. Timer Values ..............................18
           4.2.5. ChangeCipherSpec ...................................19
           4.2.6. Finished Messages ..................................19
           4.2.7. Alert Messages .....................................19
      4.3. Summary of new syntax .....................................19
           4.3.1. Record Layer .......................................20
           4.3.2. Handshake Protocol .................................20
   5. Security Considerations ........................................21
   6. Acknowledgements ...............................................22
   7. IANA Considerations ............................................22
   8. References .....................................................22
      8.1. Normative References ......................................22
      8.2. Informative References ....................................23

1. Introduction ๐ŸŽ€

okay so TLS is the most widely deployed protocol for securing network traffic ๐Ÿ‘‘ It's everywhere, like Web traffic and email protocols such as IMAP [IMAP] and POP [POP] ๐Ÿ’… The big perk of TLS is that it gives you a transparent connection-oriented channel ๐Ÿฆ‹ So it's super easy to secure an app protocol by slotting TLS between the application layer and the transport layer โœจ BUT TLS has to run over a reliable transport channel, typically TCP [TCP] ๐Ÿ˜ญ That means it can't be used to secure unreliable datagram traffic ๐Ÿ’€

Over the past few years though, more and more application layer protocols have been designed to run on UDP ๐ŸŒˆ Things like the Session Initiation Protocol (SIP) [SIP] and electronic gaming protocols are getting super popular ๐ŸŽฎ (SIP can run over both TCP and UDP, but there are situations where UDP is preferable ๐Ÿ’œ) Right now, designers of these apps are stuck with some not-so-great options ๐Ÿ™ˆ First, they could use IPsec [RFC2401] ๐Ÿ” But for a bunch of reasons detailed in [WHYIPSEC], that's only suitable for some apps ๐Ÿซ  Second, they could design a custom application layer security protocol ๐Ÿ› ๏ธ SIP, for example, uses a subset of S/MIME to secure its traffic ๐Ÿ“จ The thing is, application layer security protocols usually have superior security properties (like end-to-end security in the case of S/MIME) ๐Ÿ”ฅ but they typically require a LOT of effort to design, compared to the relatively small effort of running the protocol over TLS ๐Ÿ˜ฉ

In lots of cases, the most desirable way to secure client/server apps would be to use TLS ๐Ÿ’– However, the requirement for datagram semantics automatically rules out TLS ๐Ÿ™…โ€โ™€๏ธ So a datagram-compatible variant of TLS would be super desirable ๐Ÿฆ‹ This memo describes exactly that: Datagram Transport Layer Security (DTLS) ๐ŸŽ€ DTLS is deliberately designed to be as similar to TLS as possible, both to minimize new security invention and to maximize code and infrastructure reuse ๐Ÿงš

1.1. Requirements Terminology ๐Ÿ“

In this document, the keywords "MUST", "MUST NOT", "REQUIRED", "SHOULD", "SHOULD NOT", and "MAY" are to be interpreted as described in RFC 2119 [REQ] ๐Ÿ’… Those are the official requirement words, so read them carefully bestie ๐Ÿซถ

2. Usage Model ๐ŸŒธ

DTLS is designed to secure data between communicating applications ๐Ÿ” It runs in application space, so it doesn't need any kernel modifications ๐Ÿ™Œ

Datagram transport doesn't require or provide reliable or in-order delivery of data ๐Ÿ“ฆ DTLS keeps that property for payload data ๐Ÿ’… Apps like media streaming, Internet telephony, and online gaming use datagram transport because their data is delay-sensitive ๐ŸŽฎ Those apps behave the same when DTLS is securing the communication, since DTLS doesn't compensate for lost or re-ordered data traffic ๐Ÿฆ‹

3. Overview of DTLS ๐Ÿงš

The basic design philosophy of DTLS is to build "TLS over datagram" ๐Ÿ’– TLS can't be used directly in datagram environments simply because packets may be lost or reordered ๐Ÿ˜ญ TLS has no built-in way to handle that kind of unreliability, so TLS implementations break when they're rehosted on datagram transport ๐Ÿ’€ DTLS's whole purpose is to make only the minimal changes to TLS needed to fix this ๐ŸŽ€ To the greatest extent possible, DTLS is identical to TLS โœจ When new mechanisms are needed, they're invented in a way that keeps the style of TLS ๐Ÿซถ

Unreliability causes problems for TLS at two levels ๐Ÿ‘€

  1. TLS's traffic encryption layer doesn't allow independent decryption of individual records. If record N isn't received, then record N+1 can't be decrypted ๐Ÿ™ˆ
  2. The TLS handshake layer assumes handshake messages are delivered reliably, and it breaks if they get lost ๐Ÿ’€

The rest of this section describes how DTLS solves these problems ๐Ÿ’…

3.1. Loss-Insensitive Messaging ๐Ÿ“ฌ

In TLS's traffic encryption layer (called the TLS Record Layer), records aren't independent ๐Ÿ”— There are two kinds of inter-record dependency:

  1. Cryptographic context (CBC state, stream cipher key stream) is chained between records.
  2. Anti-replay and message reordering protection are provided by a MAC that includes a sequence number, but the sequence numbers are implicit in the records.

The fix for both of these is straightforward and well known from IPsec ESP [ESP]: add explicit state to the records ๐Ÿ’ก TLS 1.1 [TLS11] is already adding explicit CBC state to TLS records ๐Ÿ™Œ DTLS borrows that mechanism and adds explicit sequence numbers ๐Ÿ”ข

3.2. Providing Reliability for Handshake ๐Ÿค

The TLS handshake is a lockstep cryptographic handshake ๐Ÿ”’ Messages must be sent and received in a defined order, and any other order is an error ๐Ÿšซ Clearly, that's incompatible with reordering and message loss ๐Ÿ˜ญ On top of that, TLS handshake messages can be bigger than any given datagram, which creates the problem of fragmentation ๐Ÿ“ฆ DTLS must provide fixes for both of these problems ๐Ÿ’–

3.2.1. Packet Loss ๐Ÿ“‰

DTLS uses a simple retransmission timer to handle packet loss โฑ๏ธ The figure below shows the basic idea, using the first phase of the DTLS handshake:

   Client                                   Server
   ------                                   ------
   ClientHello           ------>

                           X<-- HelloVerifyRequest
                                            (lost)

   [Timer Expires]

   ClientHello           ------>
   (retransmit)

Once the client has sent the ClientHello message, it expects to see a HelloVerifyRequest from the server ๐Ÿ‘€ But if the server's message gets lost, the client knows that either the ClientHello or the HelloVerifyRequest was lost, so it retransmits ๐Ÿ” When the server receives the retransmission, it knows to retransmit too ๐Ÿซถ The server also keeps its own retransmission timer and retransmits when that timer expires โฐ

Note: timeout and retransmission do not apply to the HelloVerifyRequest, because this requires creating state on the server. ๐Ÿ™ˆ

3.2.2. Reordering ๐Ÿ”€

In DTLS, each handshake message gets a specific sequence number within that handshake ๐Ÿ”ข When a peer receives a handshake message, it can quickly tell whether that message is the next one it expects ๐Ÿ‘€ If it is, it gets processed ๐Ÿ’… If not, it gets queued up for future handling once all the previous messages have arrived ๐Ÿ“ฅ

3.2.3. Message Size ๐Ÿ“

TLS and DTLS handshake messages can be quite large (in theory up to 2^24-1 bytes, in practice many kilobytes) ๐Ÿ˜ณ By contrast, UDP datagrams are often limited to <1500 bytes if fragmentation isn't desired ๐Ÿ“‰ To compensate for this limitation, each DTLS handshake message may be fragmented over several DTLS records ๐Ÿงฉ Each DTLS handshake message contains both a fragment offset and a fragment length ๐Ÿ”ข So a recipient holding all the bytes of a handshake message can reassemble the original unfragmented message ๐ŸŽ€

That's the end of part 1 โœจ Keep an eye out for part 2 bestie ๐Ÿซถ

3.3. Replay Detection โœจ

okay so DTLS can optionally do replay detection ๐Ÿ›ก๏ธ and the trick is the same one IPsec AH/ESP uses: it keeps a bitmap window of the records it has already received. Anything too old to fit in the window gets silently dropped, and so does anything it has already seen ๐Ÿ™…โ€โ™€๏ธ. It's optional because duplicate packets aren't always an attack. Sometimes routing just messes up and sends copies, and apps can notice duplicates and adjust how they send data ๐Ÿ’…

4. Differences from TLS ๐ŸŽ€

okay bestie, DTLS is basically TLS's twin ๐Ÿ‘ฏโ€โ™€๏ธ so instead of introducing it as some brand-new protocol, the doc walks through it as a list of deltas from TLS 1.1 [TLS11]. If a difference isn't called out, assume DTLS works exactly like the TLS 1.1 version in [TLS11] ๐Ÿ’–

4.1. Record Layer ๐Ÿ“ฆ

the DTLS record layer is almost identical to TLS 1.1's ๐Ÿฅฐ the one real change is an explicit sequence number in each record. That's what lets the recipient verify the TLS MAC correctly ๐Ÿ” Here's the record format:

   struct {
     ContentType type;
     ProtocolVersion version;
     uint16 epoch;                                    // New field
     uint48 sequence_number;                          // New field
     uint16 length;
     opaque fragment[DTLSPlaintext.length];
   } DTLSPlaintext;
  • type: same as the type field in a TLS 1.1 record ๐Ÿซถ
  • version: the protocol version in use. This doc describes DTLS Version 1.0, which is { 254, 255 }. The value 254.255 is the 1's complement of DTLS Version 1.0, and that maximal spacing between TLS and DTLS version numbers means records from the two protocols are super easy to tell apart ๐Ÿ” Also, future on-the-wire DTLS version numbers go down in value while the true version number goes up ๐Ÿ™ƒ
  • epoch: a counter that goes up every time the cipher state changes ๐Ÿ”„
  • sequence_number: the sequence number for this record ๐Ÿ”ข
  • length: identical to the length field in a TLS 1.1 record. Like TLS 1.1, it should not exceed 2^14 ๐Ÿ“
  • fragment: identical to the fragment field of a TLS 1.1 record ๐Ÿงฉ

DTLS uses an explicit sequence number, stored in the sequence_number field, instead of an implicit one ๐Ÿ™Œ Same as TLS, the sequence number gets reset to zero after each ChangeCipherSpec message is sent.

if a bunch of handshakes happen back to back, you could end up with multiple records on the wire sharing a sequence number but coming from different cipher states ๐Ÿ˜ณ That's what the epoch field is for: it lets recipients tell those packets apart ๐Ÿ’œ The epoch starts at zero and goes up each time a ChangeCipherSpec message is sent. To make sure any sequence/epoch pair is unique, implementations MUST NOT allow the same epoch value to be reused within two times the TCP maximum segment lifetime. In practice TLS implementations rarely rehandshake, so the doc doesn't expect this to be a problem ๐ŸŒธ

4.1.1. Transport Layer Mapping ๐Ÿšš

every DTLS record MUST fit inside a single datagram ๐Ÿ“ฎ To dodge IP fragmentation [MOGUL], DTLS implementations SHOULD figure out the MTU and send records smaller than it ๐Ÿ™ˆ They SHOULD also give applications a way to find out the PMTU (or, alternatively, the maximum application datagram size, which is the PMTU minus the DTLS per-record overhead) ๐Ÿ“ If an app tries to send a record bigger than the MTU, the DTLS implementation SHOULD throw an error, so it never sends a packet that's going to get fragmented ๐Ÿšซ

unlike IPsec, DTLS records don't carry any association identifiers ๐Ÿ™…โ€โ™€๏ธ So apps have to handle multiplexing between associations themselves. With UDP, that's presumably done with the host/port number ๐Ÿ”€

you can stick multiple DTLS records in one datagram ๐Ÿฑ They're just encoded back to back, and the DTLS record framing is enough to find where each one ends. BUT the very first byte of the datagram payload must be the start of a record, and records may not span datagrams ๐Ÿšง

some transports, like DCCP [DCCP], bring their own sequence numbers. When DTLS rides on those, both sets of sequence numbers show up in the packet ๐Ÿ“š That's a little bit inefficient, but the transport-layer and DTLS sequence numbers do different jobs, so for conceptual simplicity using both is the better move ๐Ÿง  Future DTLS extensions might allow using just one set in constrained environments ๐Ÿ”ฎ

also, some transports like DCCP have congestion control for the traffic they carry ๐Ÿšฆ If the congestion window is really narrow, DTLS handshake retransmissions might get held back instead of sent right away, which could lead to timeouts and spurious retransmissions ๐Ÿ˜ฌ So when DTLS runs over those transports, care should be taken not to overrun the likely congestion window. A DTLS-DCCP mapping might get specified later to make this interaction work better โœจ

4.1.1.1. PMTU Discovery ๐Ÿ”Ž

DTLS generally tries not to deal with PMTU issues at all ๐Ÿ™ƒ The usual plan is to start with a conservative MTU and only update it if something during the handshake or the actual application data phase says it needs to change ๐ŸŒฟ

the PMTU SHOULD be initialized from the interface MTU that's going to be used to send packets ๐Ÿ’ป If the DTLS implementation gets an RFC 1191 [RFC1191] ICMP Destination Unreachable message with the "fragmentation needed and DF set" Code (also known as Datagram Too Big), it should lower its PMTU estimate to whatever the ICMP message says ๐Ÿ“‰ A DTLS implementation SHOULD let the application reset its PMTU estimate now and then ๐Ÿ”„ It SHOULD also let applications control the DF bit. Those controls let the app do PMTU discovery ๐Ÿ•ต๏ธโ€โ™€๏ธ For IPv6, RFC 1981 [RFC1981] procedures SHOULD be followed ๐ŸŒˆ

one special case is the DTLS handshake system ๐Ÿค Handshake messages should be sent with DF set. The problem: some firewalls and routers screen out ICMP messages, so the handshake layer can't easily tell packet loss apart from an overlarge PMTU estimate ๐Ÿ˜ญ To get connections working in that situation, DTLS implementations SHOULD back off handshake packet size during the retransmit backoff described in Section 4.2.4. For example, if a large packet is being sent, the handshake layer might choose to fragment the handshake message on retransmission after 3 retransmits. In general, picking a conservative initial MTU will avoid this problem ๐Ÿซง

4.1.2. Record Payload Protection ๐Ÿ”

just like TLS, DTLS sends data as a series of protected records ๐Ÿ’Œ The rest of this section gets into the details of that format.

4.1.2.1. MAC ๐Ÿงพ

the DTLS MAC is the same as TLS 1.1's. The difference is that instead of TLS's implicit sequence number, the sequence number used to compute the MAC is the 64-bit value you get by concatenating the epoch and the sequence number, in the order they appear on the wire ๐Ÿชก The DTLS epoch + sequence number is the same length as the TLS sequence number, so it fits right in ๐Ÿ‘Œ

TLS MAC calculation depends on the protocol version number, which for DTLS is the on-the-wire version, so {254, 255 } for DTLS 1.0 ๐Ÿ”ข

the big difference between DTLS and TLS MAC handling is this: in TLS, a MAC error must end the connection. In DTLS, the receiving implementation MAY just discard the bad record and keep the connection going ๐Ÿ™Œ That works because DTLS records don't depend on each other the way TLS records do ๐Ÿงฉ

in general, DTLS implementations SHOULD silently discard data with bad MACs ๐Ÿคซ If a DTLS implementation decides to send an alert when it gets a message with an invalid MAC, it MUST generate a bad_record_mac alert with level fatal and terminate its connection state ๐Ÿ’€

4.1.2.2. Null or Standard Stream Cipher ๐ŸŒŠ

the DTLS NULL cipher works exactly like the TLS 1.1 NULL cipher ๐Ÿซฅ

the only stream cipher described in TLS 1.1 is RC4, and RC4 can't be randomly accessed. RC4 MUST NOT be used with DTLS ๐Ÿšซ no RC4 for you, bestie ๐Ÿ™…โ€โ™€๏ธ

4.1.2.3. Block Cipher ๐Ÿงฑ

DTLS block cipher encryption and decryption are performed exactly as they are in TLS 1.1 โœ…

4.1.2.4. New Cipher Suites ๐Ÿ†•

when new TLS cipher suites get registered, they MUST say whether they're suitable for DTLS usage and what adaptations, if any, need to be made ๐Ÿ“

4.1.2.5. Anti-replay ๐Ÿชž

DTLS records carry a sequence number for replay protection ๐Ÿ›ก๏ธ Sequence number verification SHOULD use the sliding window procedure below, borrowed from Section 3.4.3 of [RFC 2402] ๐ŸชŸ

the receiver's packet counter for a session MUST be set to zero when the session is established. For each record received, the receiver MUST verify that the record's Sequence Number doesn't duplicate the Sequence Number of any other record received during the life of the session ๐Ÿ” This SHOULD be the first check applied to a packet after it's been matched to a session, so duplicates get rejected quickly โšก

duplicates are rejected with a sliding receive window ๐ŸชŸ How the window is implemented is up to the implementer, but the text below describes the behaviour the implementation must show. A minimum window size of 32 MUST be supported, but a window size of 64 is preferred and SHOULD be used as the default ๐Ÿ“ The receiver MAY pick a larger window size instead. The receiver doesn't tell the sender what window size it's using ๐Ÿค

the "right" edge of the window is the highest validated Sequence Number received on this session ๐Ÿ‘‰ Records with Sequence Numbers lower than the "left" edge of the window get rejected. Packets inside the window get checked against a list of packets already received in that window. An efficient way to do that check, using a bit mask, is described in Appendix C of [RFC 2401] ๐ŸŽญ

if the received record falls inside the window and is new, or if the packet is to the right of the window, the receiver goes on to MAC verification ๐Ÿ” If MAC validation fails, the receiver MUST discard the received record as invalid. The receive window only gets updated if MAC verification succeeds ๐Ÿ’–

4.2. The DTLS Handshake Protocol ๐Ÿค

DTLS uses all the same handshake messages and flows as TLS, with three main changes ๐Ÿ’…

  1. A stateless cookie exchange has been added to prevent denial of service attacks ๐Ÿช
  2. The handshake header has been modified to handle message loss, reordering, and fragmentation ๐Ÿงฉ
  3. Retransmission timers handle message loss โฐ

apart from those, the DTLS message formats, flows, and logic are the same as TLS 1.1's ๐ŸŽ€

4.2.1. Denial of Service Countermeasures โœจ

okay bestie, datagram security protocols are SO vulnerable to denial of service (DoS) attacks ๐Ÿ˜ญ like, it's giving "someone is trying to ruin the party." Two attacks are the big concerns ๐Ÿ’€:

  1. An attacker can eat up all the server's resources by sending a pile of handshake initiation requests. Now the server is allocating state and maybe doing expensive crypto operations ๐Ÿ™ˆ
  2. An attacker can use the server as an amplifier by sending connection initiation messages with a forged source address, which belongs to the victim. The server then sends its next message (in DTLS, a Certificate message, which can be quite large) to the victim, and now the victim is getting flooded ๐ŸŒŠ

To shut down both of these, DTLS borrows the stateless cookie technique from Photuris [PHOTURIS] and IKE [IKE] ๐ŸŽ€. When the client sends its ClientHello message to the server, the server MAY respond with a HelloVerifyRequest message. That message contains a stateless cookie made using the technique in [PHOTURIS]. The client MUST retransmit the ClientHello with the cookie added. Then the server verifies the cookie and only keeps going with the handshake if the cookie is valid. This forces the attacker/client to actually be able to receive the cookie, which makes DoS attacks with spoofed IP addresses way harder ๐Ÿ’…. Just know this doesn't protect against DoS attacks that come from valid IP addresses ๐Ÿฅฒ.

Here's how the exchange goes:

      Client                                   Server
      ------                                   ------
      ClientHello           ------>

                            <----- HelloVerifyRequest
                                   (contains cookie)

      ClientHello           ------>
      (with cookie)

      [Rest of handshake]

So DTLS modifies the ClientHello message to add the cookie value ๐Ÿงš:

   struct {
     ProtocolVersion client_version;
     Random random;
     SessionID session_id;
     opaque cookie<0..32>;                             // New field
     CipherSuite cipher_suites<2..2^16-1>;
     CompressionMethod compression_methods<1..2^8-1>;
   } ClientHello;

When the client sends its very first ClientHello, it doesn't have a cookie yet, so the Cookie field is left empty (zero length) ๐Ÿ“.

Here's the definition of HelloVerifyRequest:

   struct {
     ProtocolVersion server_version;
     opaque cookie<0..32>;
   } HelloVerifyRequest;

The HelloVerifyRequest message type is hello_verify_request(3) โœจ.

The server_version field is defined as in TLS ๐ŸŒธ.

Okay, the rules for the cookie dance are super important, so listen up ๐Ÿ‘‘. When responding to a HelloVerifyRequest, the client MUST use the same parameter values (version, random, session_id, cipher_suites, compression_method) as it did in the original ClientHello. The server SHOULD use those values to generate its cookie and verify that they're correct when the cookie comes back. The server MUST use the same version number in the HelloVerifyRequest that it would use when sending a ServerHello. And when the client gets the ServerHello, it MUST verify that the server version values match ๐Ÿ”ฅ.

The DTLS server SHOULD generate cookies in a way that lets it verify them without keeping any per-client state around ๐Ÿซถ. One technique is to have a randomly generated secret and make cookies like this:

Cookie = HMAC(Secret, Client-IP, Client-Parameters)

When the second ClientHello shows up, the server can check that the Cookie is valid and that the client can actually receive packets at that IP address โœจ.

Now for the plot twist ๐Ÿ˜ˆ: an attacker could collect a bunch of cookies from different addresses and then reuse them to attack the server. The server can fight back by changing the Secret value often, which invalidates those old cookies ๐Ÿ’…. But if the server wants legit clients to still be able to finish their handshake through the transition (say a client got a cookie with Secret 1 and then sent its second ClientHello after the server switched to Secret 2), the server can keep a limited window where it accepts both secrets ๐Ÿฆ‹. [IKEv2] suggests adding a version number to cookies so you can detect this case. Another option is to just try verifying with both secrets ๐Ÿ™Œ.

DTLS servers SHOULD perform a cookie exchange whenever a new handshake is happening ๐ŸŒˆ. If the server runs in an environment where amplification isn't a problem, the server MAY be configured not to do a cookie exchange. The default SHOULD be that the exchange happens though ๐Ÿ’œ. The server MAY also choose not to do a cookie exchange when a session is resumed. And clients MUST be ready to do a cookie exchange with every handshake ๐ŸŽ€.

If HelloVerifyRequest is used, the initial ClientHello and HelloVerifyRequest are NOT included in the calculation of the verify_data for the Finished message ๐Ÿ™ˆ.

4.2.2. Handshake Message Format ๐Ÿฆ‹

So to support message loss, reordering, and fragmentation, DTLS modifies the TLS 1.1 handshake header ๐Ÿงš:

   struct {
     HandshakeType msg_type;
     uint24 length;
     uint16 message_seq;                               // New field
     uint24 fragment_offset;                           // New field
     uint24 fragment_length;                           // New field
     select (HandshakeType) {
       case hello_request: HelloRequest;
       case client_hello:  ClientHello;
       case hello_verify_request: HelloVerifyRequest;  // New type
       case server_hello:  ServerHello;
       case certificate:Certificate;
       case server_key_exchange: ServerKeyExchange;
       case certificate_request: CertificateRequest;
       case server_hello_done:ServerHelloDone;
       case certificate_verify:  CertificateVerify;
       case client_key_exchange: ClientKeyExchange;
       case finished:Finished;
     } body;
   } Handshake;

The first message each side sends in each handshake always has message_seq = 0. Every time a new message gets generated, the message_seq value goes up by one. When a message is retransmitted, it keeps the same message_seq value ๐Ÿญ. Here's an example:

   Client                             Server
   ------                             ------
   ClientHello (seq=0)  ------>

                           X<-- HelloVerifyRequest (seq=0)
                                           (lost)

   [Timer Expires]

   ClientHello (seq=0)  ------>
   (retransmit)

                        <------ HelloVerifyRequest (seq=0)

   ClientHello (seq=1)  ------>
   (with cookie)

                        <------        ServerHello (seq=1)
                        <------        Certificate (seq=2)
                        <------    ServerHelloDone (seq=3)

   [Rest of handshake]

BUT here's the catch ๐Ÿ‘€: from the DTLS record layer's point of view, the retransmission is a brand new record. That record will have a new DTLSPlaintext.sequence_number value ๐Ÿ’€.

DTLS implementations keep track of (at least in theory) a next_receive_seq counter ๐Ÿง . It starts at zero. When a message comes in, if its sequence number matches next_receive_seq, the counter goes up and the message gets processed โœจ. If the sequence number is less than next_receive_seq, the message MUST be discarded ๐Ÿ—‘๏ธ. If the sequence number is greater than next_receive_seq, the implementation SHOULD queue the message, but it MAY discard it instead. (This is a simple space/bandwidth tradeoff ๐Ÿซถ.)

4.2.3. Message Fragmentation and Reassembly ๐Ÿงฉ

As noted in Section 4.1.1, each DTLS message MUST fit within a single transport layer datagram ๐Ÿ“ฆ. But handshake messages can be way bigger than the maximum record size ๐Ÿ˜ญ. So DTLS gives us a way to fragment a handshake message across a bunch of records ๐Ÿ’–.

When sending a handshake message, the sender splits it into a series of N contiguous data ranges. These ranges MUST NOT be larger than the maximum handshake fragment size, and they MUST together contain the entire handshake message ๐ŸŒท. The ranges SHOULD NOT overlap. Then the sender makes N handshake messages, all with the same message_seq value as the original. Each fragment gets labelled with its fragment_offset (the number of bytes in previous fragments) and its fragment_length (the length of this fragment) ๐Ÿ“. The length field is the same in all of them, matching the original message's length. And an unfragmented message is just a degenerate case where fragment_offset=0 and fragment_length=length โœจ.

When a DTLS implementation receives a handshake message fragment, it MUST buffer it until it has the whole handshake message ๐Ÿซง. DTLS implementations MUST be able to handle overlapping fragment ranges too ๐Ÿ™Œ. This lets senders retransmit handshake messages with smaller fragment sizes during path MTU discovery ๐Ÿฆ‹.

Also, just like with TLS, multiple handshake messages can go in the same DTLS record, as long as there's room and they're part of the same flight ๐Ÿงš. So there are two acceptable ways to pack two DTLS messages into the same datagram: in the same record, or in separate records ๐Ÿ’….

4.2.4. Timeout and Retransmission โœจ

okay so DTLS groups its messages into flights ๐ŸŽ€ (the diagrams below show exactly which ones go where). A flight can have a bunch of messages inside it, but for timeouts and retransmits you treat the whole flight as one lump, no splitting it up ๐Ÿงš

    Client                                          Server
    ------                                          ------

    ClientHello             -------->                           Flight 1

                            <-------    HelloVerifyRequest      Flight 2

   ClientHello              -------->                           Flight 3

                                               ServerHello    \
                                              Certificate*     \
                                        ServerKeyExchange*      Flight 4
                                       CertificateRequest*     /
                            <--------      ServerHelloDone    /

    Certificate*                                              \
    ClientKeyExchange                                          \
    CertificateVerify*                                          Flight 5
    [ChangeCipherSpec]                                         /
    Finished                -------->                         /

                                        [ChangeCipherSpec]    \ Flight 6
                            <--------             Finished    /

          Figure 1. Message flights for full handshake


    Client                                           Server
    ------                                           ------

    ClientHello             -------->                          Flight 1

                                               ServerHello    \
                                        [ChangeCipherSpec]     Flight 2
                             <--------             Finished    /

    [ChangeCipherSpec]                                         \Flight 3
    Finished                 -------->                         /

   Figure 2. Message flights for session-resuming handshake
                           (no cookie exchange)

ok now the state machine ๐Ÿฆ‹ DTLS uses a simple timeout-and-retransmit setup with the diagram below. Clients send ClientHello first, so they start out in PREPARING. Servers start in WAITING, but with empty buffers and no retransmit timer ๐Ÿ’…

                   +-----------+
                   | PREPARING |
             +---> |           | <--------------------+
             |     |           |                      |
             |     +-----------+                      |
             |           |                            |
             |           |                            |
             |           | Buffer next flight         |
             |           |                            |
             |          \|/                           |
             |     +-----------+                      |
             |     |           |                      |
             |     |  SENDING  |<------------------+  |
             |     |           |                   |  | Send
             |     +-----------+                   |  | HelloRequest
     Receive |           |                         |  |
        next |           | Send flight             |  | or
      flight |  +--------+                         |  |
             |  |        | Set retransmit timer    |  | Receive
             |  |       \|/                        |  | HelloRequest
             |  |  +-----------+                   |  | Send
             |  |  |           |                   |  | ClientHello
             +--)--|  WAITING  |-------------------+  |
             |  |  |           |   Timer expires   |  |
             |  |  +-----------+                   |  |
             |  |         |                        |  |
             |  |         |                        |  |
             |  |         +------------------------+  |
             |  |                Read retransmit      |
     Receive |  |                                     |
        last |  |                                     |
      flight |  |                                     |
             |  |                                     |
            \|/\|/                                    |
                                                      |
         +-----------+                                |
         |           |                                |
         | FINISHED  | -------------------------------+
         |           |
         +-----------+

        Figure 3. DTLS timeout and retransmission state machine

the machine has three basic states ๐ŸŒธ

  • PREPARING ๐Ÿง: the implementation does whatever computations it needs to get the next flight ready. Then it buffers those messages for sending (emptying the buffer first) and moves on to SENDING.
  • SENDING ๐Ÿ“ค: the implementation transmits the buffered flight. Once that's sent, it goes to FINISHED if this was the last flight of the handshake. Otherwise, if it expects more messages, it sets a retransmit timer and goes to WAITING.
  • WAITING โณ: there are three ways out of this one, bestie ๐Ÿ‘‘
  1. the retransmit timer expires: the implementation moves to SENDING, retransmits the flight, resets the retransmit timer, and goes back to WAITING.
  2. the implementation reads a retransmitted flight from its peer: it moves to SENDING, retransmits the flight, resets the retransmit timer, and goes back to WAITING. the reasoning is that getting a duplicate message is probably because the peer's timer went off, so it's a sign that part of your previous flight got lost ๐Ÿ˜ญ
  3. the implementation receives the next flight of messages: if this is the final flight, it moves to FINISHED. If it needs to send a new flight, it moves to PREPARING. Partial reads (whether that's partial messages or only some of the messages in the flight) don't cause any state transitions or timer resets ๐Ÿ™ˆ
Clients start in PREPARING because they send the first message (ClientHello), and servers start in WAITING with empty buffers and no retransmit timer. Same setup as before, just making sure you saw it ๐Ÿ’œ

when the server wants a rehandshake, it goes from FINISHED to PREPARING so it can send the HelloRequest. When the client gets a HelloRequest, it goes from FINISHED to PREPARING so it can send the ClientHello ๐Ÿ”ฅ

4.2.4.1. Timer Values

timer values are up to the implementation ๐Ÿงš but mishandling them can cause serious congestion problems. For example, if a bunch of DTLS instances time out early and retransmit too fast on a congested link, everything gets worse ๐Ÿ’€ Implementations SHOULD start with an initial timer value of 1 second (the minimum defined in RFC 2988 [RFC2988]) and double it at each retransmission, up to no less than the RFC 2988 maximum of 60 seconds. We recommend a 1-second timer instead of the 3-second RFC 2988 default, because it helps latency for time-sensitive apps โฑ๏ธ And since DTLS only retransmits for the handshake and not for dataflow, the effect on congestion should be minimal ๐ŸŒˆ

Implementations SHOULD keep the current timer value until a transmission goes through without loss, and only then may it be reset to the initial value. After a long stretch of idleness, no less than 10 times the current timer value, implementations may reset the timer to the initial value. One situation where this might happen is when a rehandshake comes after a lot of data transfer ๐Ÿ“

4.2.5. ChangeCipherSpec

just like in TLS, the ChangeCipherSpec message isn't technically a handshake message, but it MUST be treated as part of the same flight as the Finished message it goes with for timeout and retransmission purposes ๐Ÿซถ

4.2.6. Finished Messages

Finished messages have the same format as in TLS ๐Ÿ’… But to make things less sensitive to fragmentation, the Finished MAC MUST be computed as if each handshake message had been sent as a single fragment โœจ Also, if the cookie exchange is used, the initial ClientHello and HelloVerifyRequest MUST NOT be included in the Finished MAC ๐Ÿ™…โ€โ™€๏ธ

4.2.7. Alert Messages

okay, the vibe here is that Alert messages are never retransmitted, even when they show up during a handshake ๐Ÿ™ˆ Still, a DTLS implementation SHOULD generate a new alert message if the offending record gets received again (for example, as a retransmitted handshake message). And implementations SHOULD detect when a peer keeps sending bad messages, and terminate the local connection state once that misbehavior is detected ๐Ÿšซ

4.3. Summary of new syntax

this section has the specs for the data structures that changed between TLS 1.1 and DTLS ๐Ÿ“‹

4.3.1. Record Layer

      struct {
        ContentType type;
        ProtocolVersion version;
        uint16 epoch;                                     // New field
        uint48 sequence_number;                           // New field
        uint16 length;
        opaque fragment[DTLSPlaintext.length];
      } DTLSPlaintext;

      struct {
        ContentType type;
        ProtocolVersion version;
        uint16 epoch;                                     // New field
        uint48 sequence_number;                           // New field
        uint16 length;
        opaque fragment[DTLSCompressed.length];
      } DTLSCompressed;

      struct {
        ContentType type;
        ProtocolVersion version;
        uint16 epoch;                                     // New field
        uint48 sequence_number;                           // New field
        uint16 length;
        select (CipherSpec.cipher_type) {
          case block:  GenericBlockCipher;
        } fragment;
      } DTLSCiphertext;

4.3.2. Handshake Protocol

      enum {
        hello_request(0), client_hello(1), server_hello(2),
        hello_verify_request(3),                          // New field
        certificate(11), server_key_exchange (12),
        certificate_request(13), server_hello_done(14),
        certificate_verify(15), client_key_exchange(16),
        finished(20), (255)
      } HandshakeType;

      struct {
        HandshakeType msg_type;
        uint24 length;
        uint16 message_seq;                               // New field
        uint24 fragment_offset;                           // New field
        uint24 fragment_length;                           // New field
        select (HandshakeType) {
          case hello_request: HelloRequest;
          case client_hello:  ClientHello;
          case server_hello:  ServerHello;
          case hello_verify_request: HelloVerifyRequest;  // New field
          case certificate:Certificate;
          case server_key_exchange: ServerKeyExchange;
          case certificate_request: CertificateRequest;
          case server_hello_done:ServerHelloDone;
          case certificate_verify:  CertificateVerify;
          case client_key_exchange: ClientKeyExchange;
          case finished:Finished;
        } body;
      } Handshake;

      struct {
        ProtocolVersion client_version;
        Random random;
        SessionID session_id;
        opaque cookie<0..32>;                             // New field
        CipherSuite cipher_suites<2..2^16-1>;
        CompressionMethod compression_methods<1..2^8-1>;
      } ClientHello;

      struct {
        ProtocolVersion server_version;
        opaque cookie<0..32>;
      } HelloVerifyRequest;

5. Security Considerations โœจ

okay bestie, so this doc is a variant of TLS 1.1 ๐ŸŽ€ which means most of the security stuff is the same as TLS 1.1 [TLS11] ๐Ÿ’…, and you'll find the details in Appendices D, E, and F. no cap, go read those too ๐Ÿ“š

the main NEW security worry that DTLS brings is denial of service ๐Ÿ˜ญ๐Ÿ”ฅ. DTLS has a cookie exchange that's built to protect against DoS ๐Ÿช, but ngl, implementations that skip the cookie exchange are still vulnerable to DoS ๐Ÿ’€. like, DTLS servers that don't use the cookie exchange can get used as attack amplifiers ๐Ÿ“ข, even if they themselves aren't being DoS'd at all ๐Ÿ™ˆ. so the rule is: DTLS servers SHOULD use the cookie exchange ๐Ÿซถ, unless there's good reason to believe amplification isn't a threat in their environment ๐ŸŒธ. and clients MUST be prepared to do a cookie exchange with every handshake ๐Ÿ’–. periodt ๐Ÿ‘‘

6. Acknowledgements ๐ŸŒˆ

the authors wanna thank Dan Boneh, Eu-Jin Goh, Russ Housley, Constantine Sapuntzakis, and Hovav Shacham for chatting and giving feedback on the design of DTLS ๐Ÿงš๐Ÿ’œ. thanks to the anonymous NDSS reviewers of the original NDSS paper on DTLS [DTLS] for their comments ๐Ÿฆ‹. also big thanks to Steve Kent for feedback that helped clarify a bunch of points ๐Ÿ’…. the section on PMTU was cribbed from the DCCP specification [DCCP] ๐Ÿ“. Pasi Eronen gave a super detailed review of this spec ๐Ÿ”ฅ. and helpful comments came in from Mark Allman, Jari Arkko, Joel Halpern, Ted Hardie, and Allison Mankin ๐ŸŒธโœจ. iconic squad ๐Ÿ‘‘

7. IANA Considerations ๐ŸŽ€

this doc uses the same identifier space as TLS [TLS11], so no new IANA registries are needed ๐Ÿ™Œ. when new identifiers get assigned for TLS, authors MUST specify whether they're suitable for DTLS ๐Ÿ’…. this doc defines a new handshake message, hello_verify_request, and its value was allocated from the TLS HandshakeType registry defined in [TLS11] ๐Ÿ“. the value "3" was assigned by the IANA ๐Ÿฆ‹.

8. References ๐Ÿ“š

8.1. Normative References ๐Ÿ’œ

[RFC1191]  Mogul, J. and S. Deering, "Path MTU discovery", RFC 1191,
           November 1990.

[RFC1981]  McCann, J., Deering, S., and J. Mogul, "Path MTU Discovery
           for IP version 6", RFC 1981, August 1996.

[RFC2401]  Kent, S. and R. Atkinson, "Security Architecture for the
           Internet Protocol", RFC 2401, November 1998.

[RFC2988]  Paxson, V. and M. Allman, "Computing TCP's Retransmission
           Timer", RFC 2988, November 2000.

[TCP]      Postel, J., "Transmission Control Protocol", STD 7, RFC
           793, September 1981.

[TLS11]    Dierks, T. and E. Rescorla, "The Transport Layer Security
           (TLS) Protocol Version 1.1", RFC 4346, April 2006.

8.2. Informative References ๐ŸŒท

[AESCACHE] Bernstein, D.J., "Cache-timing attacks on AES"
           http://cr.yp.to/antiforgery/cachetiming-20050414.pdf.

[AH]       Kent, S. and R. Atkinson, "IP Authentication Header", RFC
           2402, November 1998.

[DCCP]     Kohler, E., Handley, M., Floyd, S., Padhye, J., "Datagram
           Congestion Control Protocol", Work in Progress, 10 March
           2005.

[DNS]      Mockapetris, P., "Domain names - implementation and
           specification", STD 13, RFC 1035, November 1987.

[DTLS]     Modadugu, N., Rescorla, E., "The Design and Implementation
           of Datagram TLS", Proceedings of ISOC NDSS 2004, February
           2004.

[ESP]      Kent, S. and R. Atkinson, "IP Encapsulating Security
           Payload (ESP)", RFC 2406, November 1998.

[IKE]      Harkins, D. and D. Carrel, "The Internet Key Exchange
           (IKE)", RFC 2409, November 1998.

           Kaufman, C., "Internet Key Exchange (IKEv2) Protocol", RFC 4306,
           December 2005.

[IMAP]     Crispin, M., "INTERNET MESSAGE ACCESS PROTOCOL - VERSION
           4rev1", RFC 3501, March 2003.

[PHOTURIS] Karn, P. and W. Simpson, "ICMP Security Failures
           Messages", RFC 2521, March 1999.

[POP]      Myers, J. and M. Rose, "Post Office Protocol - Version 3",
           STD 53, RFC 1939, May 1996.

[REQ]      Bradner, S., "Key words for use in RFCs to Indicate
           Requirement Levels", BCP 14, RFC 2119, March 1997.

[SCTP]     Stewart, R., Xie, Q., Morneault, K., Sharp, C.,
           Schwarzbauer, H., Taylor, T., Rytina, I., Kalla, M.,
           Zhang, L., and V. Paxson, "Stream Control Transmission
           Protocol", RFC 2960, October 2000.

[SIP]      Rosenberg, J., Schulzrinne, H., Camarillo, G., Johnston,
           A., Peterson, J., Sparks, R., Handley, M., and E.
           Schooler, "SIP:  Session Initiation Protocol", RFC 3261,
           June 2002.

[TLS]      Dierks, T. and C. Allen, "The TLS Protocol Version 1.0",
           RFC 2246, January 1999.

[WHYIPSEC] Bellovin, S., "Guidelines for Mandating the Use of IPsec",
           Work in Progress, October 2003.

Authors' Addresses ๐Ÿ’Œ

Eric Rescorla
RTFM, Inc.
2064 Edgewood Drive
Palo Alto, CA 94303

EMail: ekr@rtfm.com


Nagendra Modadugu
Computer Science Department
Stanford University
353 Serra Mall
Stanford, CA 94305

EMail: nagendra@cs.stanford.edu

copyright (C) The Internet Society (2006) ๐Ÿซง

this document is subject to the rights, licenses and restrictions contained in BCP 78, and except as set forth therein, the authors retain all their rights ๐Ÿ’œ.

this document and the information contained herein are provided on an "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE ๐Ÿ™ƒ.

Intellectual Property ๐Ÿ”

the IETF takes no position regarding the validity or scope of any Intellectual Property Rights or other rights that might be claimed to pertain to the implementation or use of the technology described in this document, or the extent to which any license under such rights might or might not be available; nor does it represent that it has made any independent effort to identify any such rights ๐Ÿคทโ€โ™€๏ธ. information on the procedures with respect to rights in RFC documents can be found in BCP 78 and BCP 79 ๐Ÿ“–.

copies of IPR disclosures made to the IETF Secretariat and any assurances of licenses to be made available, or the result of an attempt made to obtain a general license or permission for the use of such proprietary rights by implementers or users of this specification can be obtained from the IETF on-line IPR repository at http://www.ietf.org/ipr ๐Ÿ”—.

the IETF invites any interested party to bring to its attention any copyrights, patents or patent applications, or other proprietary rights that may cover technology that may be required to implement this standard. please address the information to the IETF at ietf-ipr@ietf.org ๐Ÿ’Œ.

Acknowledgement ๐ŸŒธ

funding for the RFC Editor function is provided by the IETF Administrative Support Activity (IASA) ๐Ÿ’–.

๐Ÿ“ฆ where this page comes from