How Java™ Could Have Prevented Heartbleed

Heartbleed

OpenSSL continues to cast a shadow over the IT industry’s poor choice of programming languages for developing secure software. Neils Ferguson and Bruce Schneier’s mantra, that using a programming language without protection against buffer overflows is tantamount to criminal negligence, is a continuous reminder of memory related security bugs that plague our industry.

Before going any further, it’s important to understand how Heartbleed has the potential to leak sensitive data. OpenSSL is written in C, which is not a memory safe programming language. The vulnerable C-library call in OpenSSL looks like this:

memcpy(bp, pl, payload);1

Heartbleed-written-in-C-v2

There are three variables in OpenSSL C-library that play a key role in this bug:

  • pl, a pointer that references the location in memory of the server that contains request message content “HELLO”. The memory size reference by pl is 5 bytes since “HELLO” contains 5 letters as shown in the request message in the figure above.
  • payload, a variable that is set to 25 because the attacker had crafted the malicious message to set the payload to 25. It is greater than the actual length of “HELLO” (size 5 bytes).
  • bp, is a pointer to an allocated buffer of memory that contains the response to the client. The size of bp is dictated by the attacker and a few other bytes needed for the protocol2.

In the above call, the attacker would receive an extra 20 bytes of memory beyond the memory buffer referenced by pl from the exposed server. Remember, only pl references memory location of 5 bytes. The information exposed would depend on how the memory was allocated and what information was in the memory at the time of the attack.

If OpenSSL were written in Java, the Heartbleed bug would have never existed. In Java, the vulnerable line of code would be written as follows:

System.arraycopy(pl, 0, bp, 0, payload);3

Heartbleed-written-in-Java-v2

In the case of the Heartbleed bug, since pl is 5, and payload is 25, the method call would result in an IndexOutOfBoundsException. Since Java checks for boundaries, as soon as the length of pl is reached, no more data would be written and an exception would be thrown. This method would also protect the coder if bp would have been smaller than payload. An additional safety of the language is that the contents of a byte array are explicitly initialized to zero. Even if the method called would not have thrown an exception, no memory from the server would have ever been compromised, just zeros. Given the availability of safe languages like Java, it is irresponsible and negligent to “protect” an infrastructure with systems running vulnerable languages such as C.

1. The memcpy() function copies n bytes from memory area src to memory area destination
2. The exact size of bp is 1 byte for the message type, 2 bytes for the payload length, the bytes to include the payload, and the padding. (1 + 2 + 65535 + 16)
3. Copies an array from the specified source array, beginning at the specified position, to the specified position of the destination array.