Linux 5.6, released today, ships WireGuard in the mainline kernel: the wireguard driver is no longer an out-of-tree module to compile with DKMS, but code that arrives together with the kernel. This is the moment a VPN protocol born outside the official tree becomes part of Linux’s standard networking interface.
Context
The two most common VPNs in 2020 carry plenty of years and plenty of code. IPsec is a set of RFCs (ESP, IKEv1, IKEv2, transport and tunnel modes) implemented by stacks such as strongSwan and libreswan. OpenVPN, from 2001, runs in userspace on top of OpenSSL and carries TLS inside a UDP or TCP tunnel. Both work and are widely reviewed, but their flexibility — cipher-suite negotiation, multiple modes, configuration options by the dozen — is also their attack surface.
WireGuard, written by Jason A. Donenfeld, starts from the opposite constraint: no negotiation. The first academic paper, WireGuard: Next Generation Kernel Network Tunnel, dates from 2017 and describes a tunnel that lives in the kernel as an ordinary network interface (wg0), where forwarding is handled by the system routing table rather than by a separate daemon. The kernel core sits in a few thousand lines, against the hundreds of thousands of the traditional stacks: less code to read before you can pronounce on its security.
Cryptographic architecture
WireGuard fixes its primitives inside the protocol. There is no phase in which the parties agree on an algorithm:
- Curve25519 for elliptic-curve Diffie-Hellman key exchange
- ChaCha20-Poly1305 as the AEAD (Authenticated Encryption with Associated Data) cipher for transport data
- BLAKE2s for hashing and for key derivation (HKDF, Hash-based Key Derivation Function)
The handshake rests on Trevor Perrin’s Noise Protocol Framework, specifically the IKpsk2 pattern: the initiator already knows the responder’s static public key (K), immediately sends its own static key encrypted (I), and an optional pre-shared key enters the last message (psk2). In practice this is two messages — handshake initiation and handshake response — followed by transport data. The initiator can send data as soon as it receives the response; the responder waits for a first transport data message from the initiator before treating the handshake as confirmed.
Having no negotiation has a direct consequence: there is no downgrade attack toward a weaker cipher, because there is no alternative cipher to force. When a primitive needs changing, the protocol version changes; nothing is renegotiated at runtime. It is a choice that removes options, and with them the combinations to analyse.
The critical point
The part that, in my view, deserves more attention than it gets is load handling. A responder that runs an expensive asymmetric operation for every incoming packet is exposed to a flood: the attacker spends little, the defender a lot. WireGuard deals with it through the MACs and cookies described in the paper.
Every message carries two authentication fields, mac1 and mac2. mac1 is computed over the recipient’s static public key and immediately drops packets from anyone who does not know it, before any asymmetric cryptography is touched. Under load, the responder can answer with a cookie reply instead of processing the handshake: the cookie is tied to the sender’s source IP address, which must then include it in mac2 on the next attempt. This forces the initiator to prove it can really receive traffic at the address it claims, and spoofing becomes more expensive. The cookie is itself encrypted, so it does not turn into an oracle revealing whether a given IP runs WireGuard.
On the client side there is one detail easy to get wrong when reimplementing the protocol: on receiving a cookie reply, the peer must not resend at once, but store the decrypted cookie and wait for the Rekey-Timeout to expire before the next attempt, so as not to amplify traffic in turn.
Operational implications
A typical configuration fits in about ten lines: an [Interface] section with a private key and an address, one [Peer] per counterpart with its public key, AllowedIPs, and an optional Endpoint. AllowedIPs serves two purposes at once: it is the routing table for that peer and it is the inbound cryptographic filter. A packet encrypted by a key is accepted only if its source falls within the AllowedIPs bound to that key. This is the cryptokey routing described in the paper, and it moves access control from the application layer to a direct binding between key and prefix.
The model is symmetric: the protocol has no client and server role, only peers with keys. Endpoints can change IP address — a mobile peer moving from Wi-Fi to cellular keeps the session without renegotiating — because identity is the public key, not the address. The interface is also quiet: with no legitimate traffic it does not respond, and a blind scan struggles to spot it.
Before 5.6, anyone wanting WireGuard used the out-of-tree module with DKMS, or the userspace implementations: wireguard-go in Go as the reference, and boringtun in Rust published by Cloudflare. The road to mainline took more than one review round; the first submission carried its own crypto library, zinc, and the merge came after the code was rewritten on top of the crypto API already present in the kernel.
Limits
Access control stays bound to the key-prefix pair. The protocol has no user or role authentication: distributing keys, revoking them, mapping a person to a peer are tasks to build on top, with external tooling. Anyone with compliance constraints that mandate a specific cipher — FIPS validation, keys in an HSM — has to check that WireGuard’s fixed set is admissible, since it cannot be changed from within. NAT traversal is more bare-bones than what OpenVPN over UDP or IPsec with NAT-T offer, and in awkward NAT scenarios it needs a peer with a stable endpoint as a rendezvous point. Logging is minimal by design: observability has to be added. Reaching mainline, finally, is the start of a phase, not the end: the code is now exposed to a far wider review audience, and it is from that sustained exposure that the soundness of the choices will be measured, not from inclusion alone.
https://www.wireguard.com/papers/wireguard.pdf https://www.wireguard.com/protocol/ https://noiseprotocol.org/noise.html https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tag/?h=v5.6 https://www.noze.it/en/insights/wireguard-kernel/
Cover image: WireGuard logo: a stylised red-and-black serpentine dragon next to the bold “WireGuard” wordmark — logo by WireGuard LLC, public domain — https://commons.wikimedia.org/wiki/File:Logo_of_WireGuard.png