Hacker News new | comments | show | ask | jobs | submit login
Ask HN: What's the purpose of the "payload" in SSL TLS/DTLS Heartbeat anyway?
14 points by JoelJacobson on Apr 9, 2014 | hide | past | web | favorite | 10 comments
Having read through RFC 6520, I don't understand why the payload is necessary. Neither the server nor the client appears to be using it for anything?

Wouldn't it have been simpler and more secure to skip the payload altogether?

In a security protocol it seems strange the designers of the protocol opted for a more complex protocol than necessary.

> Having read through RFC 6520, I don't understand why the payload is necessary. Neither the server nor the client appears to be using it for anything?

RFC 6520:

  "To perform PMTU discovery, HeartbeatRequest messages
   containing padding can be used as probe packets, as described in

  "In particular, after a number of retransmissions without
   receiving a corresponding HeartbeatResponse message having the
   expected payload, the DTLS connection SHOULD be terminated. "

  "When a HeartbeatRequest message is received and sending a
   HeartbeatResponse is not prohibited as described elsewhere in this
   document, the receiver MUST send a corresponding HeartbeatResponse
   message carrying an exact copy of the payload of the received

   If a received HeartbeatResponse message does not contain the expected
   payload, the message MUST be discarded silently.  If it does contain
   the expected payload, the retransmission timer MUST be stopped."
The "use" of the payload is in the RFC. What the RFC omits is the "why" for why the payload exists in the first place. Omission of this "why" is likely because the authors expected that their readers would inherently understand why given that the RFC is for network protocols and meant to be read by those understanding network protocols.

The "why" is that networks are subject to packet loss, and to timing delays. If you send out two heartbeats 10s apart, and only receive one reply back, then is the reply responsive to the first heartbeat, or to the second 10s later? Without some unique data in each of the packets you send, which is echoed by the other end, you can not disambiguate this question.

Now, one could argue that a simple sequence counter defined by the protocol would suffice. But that is open to exploit by a misbehaving server because once the server recognizes your heartbeat counter pattern, it can issue anticipatory heartbeat replies with the proper sequence number that you will accept as valid. By making the payload arbitrary bytes, then you have the option of sending a sequence number, or generating random data (and tracking it yourself), or both. The random data aspect thwarts misbehaving servers from determining your pattern and replying with the right data without ever receiving your requests. The arbitrary sized payload also makes the packet useful for path MTU discovery as the first paragraph I quoted from the RFC indicates.

For TLS, which runs on top of TCP, this is a non-issue, as TCP enforces complete, in-order delivery of the data.


   This document describes the Heartbeat Extension for the Transport
   Layer Security (TLS) and Datagram Transport Layer Security (DTLS)
   protocols [...] DTLS is designed to secure traffic running on top
   of unreliable transport protocols.
The payload is necessary because this extension can be used with DTLS, which runs on top of UDP, which does not enforce complete or in-order delivery.

I wonder if the payload should have been specified only for use with DTLS, not TLS.

The whole extension was originally specified only for DTLS. Then the working group started suggesting reasons that an app-layer liveness check would be useful in TLS. At some point, it became easier simply to add the feature in both places than to hash out the argument. That's how standards processes work: it's easier to say "yes" to a new feature than "no".

All protocols are full of cruft like that. It's not that different from the Bitcoin "malleability" attack which also originated in a feature that has no practical use but the protocol designers thought might be handy to have in the future. Many people think it is a good idea to build extension points into your systems because that increases the flexibility of it. In reality it just makes the system harder to use and more prone to bugs.

to quote from [0,p67], which is the dissertation of the guy writing it:

The HeartbeatResponse must contain the same payload as the request it answers, which allows the requesting peer to verify it. This is necessary to distinguish expected responses from delayed ones of previous requests, which can occur because of the unreliable transport.

[0] http://duepublico.uni-duisburg-essen.de/servlets/DerivateSer...

Ok but is there any evidence that anyone has a practical use for distinguishing the order of received heartbeat response packets? Otherwise it is still a complete YAGNI feature. And if so, why wouldn't a simple 32 bit sequence number suffice?

Having studied this for many hours now... and also having read part of that dissertation... and knowing something about block ciphers...

I don't think it is probable that any peer will want to know the order of the "ping" replies. A heartbeat is not used to diagnose anything. Any heartbeat response will suffice to keep the connection alive.

The need for a payload/sequence number is presented as a "truth" of networking but it seems to be invalid here.

A 32 bit sequence number would suffice, except for the fact that DTLS also uses this packet for path MTU discovery. Strangely, an IP packet cannot exceed the ethernet MTU of 1500 bytes anyway and at present I have no idea how this DTLS MTU discovery is supposed to work. Supposedly, the only way to check for MTU limits on routers is to set a bit in the IP header that says "do not fragment" and then wait for possible ICMP replies. This should work for UDP as well. But perhaps you can also discover UDP fragmentation at the receiving end since UDP might not automatically recombine the fragments. Then, any protocol on top of UDP would be able to do this as well. It was introduced in DTLS so that any applications using DTLS wouldn't need to do it themselves.

Whatever the case may be, and however useful or stupid the design, these messages could not exceed 1500 bytes. So why 64k? Probably just because a byte is max 255 which is too low, a word (2 bytes) is max 65535 which is enough. I don't know what features UDP/DTLS have for reassembling packets, but apparently they thought it easier to make $FFFF the max value than to impose a better limit on this number.

Also the padding is required just in case some peer sends simple sequence numbers as payload. A 32-bit sequence number + 3 bytes of header would be 7 bytes. Adding a 16 byte padding of random data would scramble the plaintext so the plaintext of the encryption (all of this is encrypted) could not be guessed.

In the unlikely case that some implementation uses 13 bytes of payload with 16 bytes of padding, and the block cipher uses 128-bit blocks, which is 16 bytes, then this whole security measure is voided since the block cipher simply encrypts bocks of 128 bits in serial.

All in all it doesn't sound like it's very well thought out.

That's just sad. I might buy the argument for protocols in general, but for a super important security protocol like SSL, that's just ridiculous.

I might use a different word than "ridiculous", but, here's a news flash for you: that's how standards groups work. Look at DNSSEC for this phenomenon writ-large.

When you're paying your 107,000 workers $53bn to insert backdoors into everything, finding new and interesting ways to hide exploits in source code becomes an art form. Of course you can't find any reason why a payload for a "keepalive" was necessary... because it simply wasn't, but absent some data, you can't insert the exploit.

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact