* RFC 6520 was published in February 2012. At that time Robin Seggelmann wasn't employed by T-Systems but was instead writing his dissertation at the University of Duisburg-Essen [1].
* His dissertation [2] actually gives an explanation for the payload:
"The payload of the HeartbeatRequest can be chosen by the implementation, for example simple sequence numbers or something more elaborate. 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."
[1] http://www.robin-seggelmann.de/
[2] http://duepublico.uni-duisburg-essen.de/servlets/DerivateSer...
The rationale for the payload for DTLS (sent over UDP) is reasonable, but I'm scratching my head over why the payload is even there for TLS. I guess there's some logic in making the protocol the same irrespective of underlying transport, but the payload is completely redundant for reliable protocols, which will handle any retransmission or reordering automatically.
Edit: Upon further (amateur and arguably ill-informed) reflection I'd argue that the heartbeat functionality shouldn't apply to TLS at all. It's needless complexity that can be handled by the underlying reliable transport. That doesn't change that the OpenSSL project clearly has code-quality issues, but it would have averted this particular fiasco, at least.
I am dismayed that a security-oriented protocol isn't focused on minimalast design. That seems very backward to me.
Not having heartbeats, you end up relying only on arbitrary timers to time out your connections, which are far from optimal, or you end up relying only on the underlying protocol which is not enough in most cases.
TCP doesn't provide that for you. (TCP does provide keepalives, intended for other means, they might be a poor mans substitute, but they arn't exposed to the TCP user in a particularly useful way - it's also the wrong layer for this problem)
They won't let you know if the application process is jammed up --- but TLS hearbeats won't do that for you either! (For example, it's common to have the crypto handled by front-end processes, with the application logic elsewhere.) So if that's what you want, then you need heartbeats at the application layer, not in TLS.
Given all that, the case for hearbeats at the TLS layer for TLS over TCP seems ... weak. Particularly since simply having them there violates the commonly cited best practice that security kernels should be kept small. And this violation has already had disastrous consequences.
Besides, for all the times I see people making this argument, I've yet to see them cite an example of a real problem in a real world deployment for which TLS hearbeats were used, and turned out to be the best solution.
I looked back to RFC1122 to get a feel for the nature of TCP keepalives, and I would agree that they're unsuitable for this application.
If we posit that a keepalive mechanism is useful for TLS I'd still argue that a payload is unnecessary because TCP will handle in-order delivery. A NOOP with some random-length padding would have worked just as well.
Given the rather dramatic differences that need to occur in a protocol designed to work over unreliable versus reliable transport, though, it seems like a bad idea to try to keep "parity" between DTLS and TLS. I can see how somebody might see it as "elegant" to do so, but I'd argue they're different animals solving different problems.
Why allow variable length payloads at all? Why allow more than about 128 bits of data for distinguishing responses? I guess you might argue a client might want to disguise the nature of these heartbeat packets from an eavesdropper, so they need to be variable in size - that's reasonable, but if it's a requirement, then surely you'd want to comment on the security risk of using a "simple sequence of numbers" rather than "something more elaborate". 64K of data, though? That seems like a lot of leeway to give an implementation - considerably more than enough to disambiguate heartbeat packets; implementations are going to keep 64K of data around and compare it byte for byte to check whether the echo they got back matches the payload they transmitted earlier?
I really don't mean to ascribe malice here; I tend to assume this is just a bug, and that the payload for heartbeat packets gets to be up to 64K because once you've decided to make something a variable length buffer, you're probably choosing between having a one byte or a two byte field for length, and 256 bytes seems like it might be too small so you figure 'why not make the length field two bytes?' and then... oops; someone makes a buffer overrun and suddenly we're faced with 64K at a time of data being ripped out of any old server's heap.
This bug is too general and too wide open to be deliberate. Any college student could write code this shitty. An engineered flaw would have to be more subtle.
* the protocol extension rfc and implementation are from the same person (who is now working for the largest German IT service contractor; formerly state owned T-Systems).
* the extension provides means for one party to send arbitrary data which needs to be returned - a keepalive mechanism would have worked with an empty packet
* there is no input validation on network originated data, in a crypto library, in 2011
This has huge implications on all of the Internet, while the individual parts being reasonably deniable.