You may have heard quite a bit in the news recently about a security issue with something called OpenSSL: the exploit has been rather dramatically referred to as Heartbleed.
So what is OpenSSL, and what is “Heartbleed”, exactly?
OpenSSL is an open source – that is freely downloadable – security suite for providing security and encryption across network links, mainly to secure websites on the internet. It does this by using the SSL (Secure Sockets Layer) and TLS (Transport Layer Security) to encrypt data between a client and a server, ensuring that traffic cannot be intercepted or read by a snooper. Its useful to keep your banking details and logon credentials secure.
Heartbleed is an exploit that has become known due to a change in the TLS protocol, and it affects all versions of OpenSSL from the release of 1.0.1 to 1.0.1f. This change was first discussed in RFC 6520. This introduced the concept of “heartbeats” into the TLS protocol. For those who don’t know, a “heartbeat” is kind of data packet exchanged across a network link between a client and a server to ensure the connection remains open as long as necessary. The data packet contains a header describing what it is, and some “padding” data which is returned by the server to the client in order to show that it has been correctly received and understood.
The RFC describing the change limits the size of the heartbeat packet to 16KB, but generally OpenSSL generates far shorter packets using the following code:
unsigned int payload = 18; /* Sequence number + random bytes */
unsigned int padding = 16; /* Use minimum padding */
/* Check if padding is too long, payload and padding
* must not exceed 2^14 - 3 = 16381 bytes in total.
OPENSSL_assert(payload + padding <= 16381);
/* Create HeartBeat message, we just use a sequence number
* as payload to distuingish different messages and add
* some random stuff.
* - Message Type, 1 byte
* - Payload Length, 2 bytes (unsigned int)
* - Payload, the sequence number (2 bytes uint)
* - Payload, random bytes (16 bytes uint)
* - Padding
buf = OPENSSL_malloc(1 + 2 + payload + padding);
p = buf;
/* Message Type */
*p++ = TLS1_HB_REQUEST;
/* Payload length (18 bytes here) */
/* Sequence number */
/* 16 random bytes */
p += 16;
/* Random padding */
ret = dtls1_write_bytes(s, TLS1_RT_HEARTBEAT, buf, 3 + payload + padding);
Don’t worry if you don’t understand C…
The reason the code says that the payload and padding must not exceed 16381 bytes in total is because the 16KB (16384 byte) packet includes one byte to signal that the transmission is a TLS1_HB_REQUEST and two bytes to denote the length of the payload in the request. This means that the line OPENSSL_assert(payload + padding <= 16381); is redundant because the payload size is hard-wired to 18 bytes and the padding to 16 bytes. The programmer has tried to do the right thing, though, by including this check, just in case someone changes the payload or padding sizes in the future without consideration for any possible consequences.
The code then transmits the heartbeat request, which when completed consists of:
- A single byte 0×01 denoting that this is a TLS1_HB_REQUEST packet
- Two bytes containing the 32-bit representation of 34 (the size of the payload and the padding)
- Two bytes of payload consisting of a 16bit sequence number
- 16 bytes of further random data to make up the remainder of the 18 byte payload
- 16 bytes of further random padding data required by the standard
Unfortunately, when the server replies to a heartbeat, the programmers weren’t so careful about how it handles and validates its data. As noted above, heartbeat replies are meant to include a copy of the payload data in order to confirm that both ends of the connection are open and that the two machines can understand each other. Well, it turns out that you can sneakily send a small payload packet in your heartbeat request, but set your payload size field to 0xFFFF (65535 bytes), and the server will return this much information!
/* Allocate memory for the response, size is 1 byte
* message type, plus 2 bytes payload length, plus
* payload, plus padding
buffer = OPENSSL_malloc(1 + 2 + payload + padding);
bp = buffer;
/* Enter response type, length and copy payload */
*bp++ = TLS1_HB_RESPONSE;
memcpy(bp, pl, payload);
bp += payload;
/* Random padding */
r = dtls1_write_bytes(s, TLS1_RT_HEARTBEAT, buffer, 3 + payload + padding);
This means that OpenSSL runs off the end of your payload packet and scoops up whatever else might be next in memory space and returns that as part of the packet. This data could potentially include user names, passwords, other message contents or even private keys!
The new version of OpenSSL includes a check on the server’s side to validate the length of the received data before replying, meaning the memory “bleed” effect no longer happens. Administrators whose servers run on an affected version of OpenSSL are strongly advised to upgrade to the latest release to remove the potential effects of this bug. If you can’t upgrade for any reason, recompiling the source code of your current version using the -DOPENSSL_NO_HEARTBEATS switch is strongly advised: this option does not include the heartbeat code in the compiled programs, meaning the feature with the exploit is not available.
So as a user, do you need to worry? Well, potentially.
There is always a risk, however small, that someone could have been maliciously using this vulnerability in order to hoover up potentially sensitive information that should never have been exposed. The risks might be tiny (after all, with all the millions of users accessing various servers on the internet, what are the chances that your account details were compromised?) but its better to be safe than sorry.
If you’re concerned about your account security, Mashable has been keeping a list of services running compromised versions of OpenSSL. If you suspect that your account may have been accessed improperly before you have been able to change your password, you should contact the help and support/administration staff of the website in question.