RFC 4347
Datagram Transport Layer Security
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 Notice ๐
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 ๐
- 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 ๐
- 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:
- Cryptographic context (CBC state, stream cipher key stream) is chained between records.
- 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 value254.255is 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 exceed2^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 ๐
- A stateless cookie exchange has been added to prevent denial of service attacks ๐ช
- The handshake header has been modified to handle message loss, reordering, and fragmentation ๐งฉ
- 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 ๐:
- 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 ๐
- 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 ๐
- the retransmit timer expires: the implementation moves to SENDING, retransmits the flight, resets the retransmit timer, and goes back to WAITING.
- 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 ๐ญ
- 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
Full Copyright Statement ยฉ
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
- ietf: rfc4347 2006-04
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms