TCP, TLS, IPSec and OpenSSL: The Old Dinosaurs Need Replaced? Meet WireGuard

In the mid-1960s, Larry Roberts sketched out a plan for a packet-switched network named ARPANET. In a matter of half a century, this has…

TCP, TLS, IPSec and OpenSSL: The Old Dinosaurs Need Replaced? Meet WireGuard

In the mid-1960s, Larry Roberts sketched out a plan for a packet-switched network named ARPANET. In a matter of half a century, this has grown into the most amazing machine ever seen on this planet: The Internet. But, it has never really been properly designed, and most of its protocols hark back to the days of congested and error-prone networks. The software that supports it has also become verbose and cumbersome.

One great decision that was made for ARPANET was that the IP (Internet Protocol) protocol would basically just deliver packets of data from one machine to another. It was then up to the higher level protocol (TCP) to reassemble the packets into data streams. And, so, while IP has done us well in finding routes through a network, it is the TCP protocol which is looking rather out-of-touch.

The whole concept of TCP (Transport Control Protocol) is built on data packets taking different routes to get through a network and then being reassembled at the other end. In-built were mechanisms that allowed slow devices with limited memory to pause the communication while the data was processed.

Possibly the greatest flaw of the Internet is that it was designed with little in the way of inherent security. In fact, it took until 2003 before RFC 3552 gave a proper definition of what security actually meant for the Internet, and with a definition of communication security (confidentiality, data integrity and peer authentication), non-repudiation and system security (unauthorized usage, inappropriate usage and Denial of Service).

TCP — Designed in the time of the Dinosaur?

But why do we even need TCP anymore? It has a silly three-way handshake which slows down the whole connection. In a world of almost instant connectivity, we are still using a method that says, “Do you want to connect?”, “Yes. I want to connect”, “Okay, let’s go”. Of course, though, TCP was designed to cope with error-prone and congested networks, and where packets were often dropped or had errors in them. It was also designed in a time when devices had to buffer data and had limited memory for this. A device thus had to send back a message saying, “Hold on. Let me process this data first, before you send any more!” These days, though, virtually no packets have errors or get dropped, and where we can have a latency of less than one millisecond.

Basically, TCP needs to hand over control to its more nibble sibling UDP. While not perfect, it is so much better matched to our modern networks than TCP. Within UDP, there’s none of that setting up connections and sending acknowledgements over the line; it just gets on with wrapping the data and sending it out.

The sticking plaster

The sticking plaster for security on the Internet became SSL (Secure Sockets Layer). It was designed and developed by Paul Kocher and Tahir ElGamal. SSL 2.0 was released in 1995 and integrated into the Netscape browser. It was followed by SSL 3.0 in 1996. Unfortunately, it took until 2011 before it was finally published as a standard with RFC 6101 [here]. Without the push from Google on migrating towards SSL/TLS communications within HTTP accesses, we would possibly still be mainly using insecure communications for our Web accesses.

Over the past decade, though, we have integrated many new cryptography methods but have left very little behind. For example, RC4 has a known weakness, but you will still find that it is supported in OpenSSL. Overall, the industry has kept going with old standards, and there is little to stop someone from selecting MD5 as a hashing method, Diffie-Hellman key exchange, and 56-bit DES for their encryption tunnel. And it is well known that the support for so many different methods increases the surface area for attack, and OpenSSL provides a classic example of a package which just has too much legacy code contained in it.

SSL/TLS and IPSec

SSL/TLS is a poor security protocol, and where the secure tunnel can often be broken with a proxy/smart firewall. Those working in a secure environment should thus not rely on SSL/TLS to provide a secure environment. The solution for many, then, is to use IPSec in order to create a proper VPN tunnel.

IPSec involves the negotiation of a tunnel policy, such as for the encryption method used, the key exchange method, the hashing method, and so on. There are normally two phases to this, where in the first phase, we define the methods to be used, and the second phase involves the actual handshaking of the encryption key to be used and the policy involved with the tunnel. But IPSec is overblown and contains many legacy cryptography methods. With this, an intruder could pull down the security of a tunnel to an unacceptable level and break it.

So what’s the solution? Well, one method that can be used is WireGuard. With WireGuard, we have a simpler solution than packages such as IKEv2 and OpenVPN, and which is more lightweight. It also encapsulates IP packets within UDP and removes the overhead that TCP brings. And, while other packages need 100s of thousands of lines of code, WireGuard only requires only around 4,000 lines of code [here]:

WireGuard

WireGuard was created by Jason A. Donenfeld in 2016 and has now been ported to Windows, Linux, Android and iOS. At its core is the usage of the more modern cryptography methods such as Curve25519 (for ECDH — Elliptic Curve Diffie Hellman — key exchange), ChaCha20 (for fast symmetric key encryption), Poly1305 (for AEAD methods), BLAKE2s (for hashing), SipHash25 (for hashtables) and HKDF (for key derivations). It also uses a connection-less approach (with UDP), and which is generally faster than TCP-based methods.

Initially, there is a connection request from an initiator, which has the following format:

msg = handshake_initiation {
u8 message_type
u8 reserved_zero[3]
u32 sender_index
u8 unencrypted_ephemeral[32]
u8 encrypted_static[AEAD_LEN(32)]
u8 encrypted_timestamp[AEAD_LEN(12)]
u8 mac1[16]
u8 mac2[16]
}

We can see a practical example here, and where there is a sender index (0xc1039c02), an unencrypted ephemeral value, an encrypted static value, an encrypted timestamp, and two HMAC values:

This is the first part of the ECDH key exchange and where unencrypted_ephemeral is Bob’s public key for the session. Next, Alice will send back a message in the following format:

msg = handshake_response {
u8 message_type
u8 reserved_zero[3]
u32 sender_index
u32 receiver_index
u8 unencrypted_ephemeral[32]
u8 encrypted_nothing[AEAD_LEN(0)]
u8 mac1[16]
u8 mac2[16]
}

The second part of the response is the closing part of the ECDH handshake, and where the receiver now defines the receiver index value (0xdce3fa01). The sender and the receiver IDs now will match the session connection (in a similar way to TCP ports and IP addresses). The unencrypted_ephemeral field defines the public key of Alice for the session, and when Bob receives this, he can compute the shared key:

After this, Bob and Alice will have the same shared key and will then use ChaCha20 and Poly1305 to create an encryption tunnel. Overall, for the ECDH handshake, Bob and Alice will use Curve 25519 to produce the shared key.

The packets that come after this are then encrypted with the shared key and contain a message type, a receiver index (to match the session), a counter, and the encrypted content:

msg = packet_data {
u8 message_type
u8 reserved_zero[3]
u32 receiver_index
u64 counter
u8 encrypted_encapsulated_packet[]
}

In the following, we have an example of Transport Data for a receiver of 0xAB7DF406:

For the next packet sent by the same host, we see that the counter value has been incremented:

In this way, the sender and receiver can keep track of the packets (in a similar way to the TCP segment number).

Conclusions

Our existing tunnelling methods are perhaps overblown. They contain many old methods and are often resource inefficient and potentially insecure. One only has to look at SSLLabs to see that many Web sites still support out-of-date methods.

With WireGuard, we have only one selection for the methods, but it is a good selection. ChaCha20 and Poly1305 provide AEAD support, Curve 25519 is a fast and secure curve for key exchange methods, Blake2s is one of the fastest cryptography hashing methods around, and HKDF is a fast and secure method of generating encryption keys. So rather than having 100s of thousands of lines of code to implement the tunnel, WireGuard just needs a few thousand lines of code. And the smaller the code footprint, the more likely that it will be free of code bugs.

For the final comment:

“Can I just once again state my love for [WireGuard] and hope it gets merged soon? Maybe the code isn’t perfect, but I’ve skimmed it, and compared to the horrors that are OpenVPN and IPSec, it’s a work of art.”

— Linus Torvalds