
Hi everybody. My name's David Crawshaw. I'm CTO and co-founder of Tailscale and I'm here to do half of a talk today with I'm Maya Gadjoski. I'm a product manager at Tailscale. Uh Tailscale's a WireGuard-based mesh VPN and we're here to talk about WireGuard. Uh important point to note, WireGuard is the registered trademark of Jason A. Donenfeld and we aren't the creators of WireGuard, he is. Um so first off, uh we'll be talking about WireGuard from the ground up. We'll cover what WireGuard is and why it's different from other options for client-server communication. How WireGuard works, including an overview of the protocol, what cryptography is used and how key rotation and timers work. We'll step through the handshake and explain what
happens at each step. And we'll end with a demo of WireGuard in action so you can see how simple it is to use yourself. This talk is meant for software engineers or security engineers who have some understanding of network protocols and some cryptographic primitives but not a deep cryptographic background. And there's nothing that we're going to cover today that you can't read in the WireGuard white paper, but we get it. Not everyone wants to read a crypto heavy white paper. So we'll leave you with with a few links at the end where you can learn more. Let's jump in. So first off, what is WireGuard? Basically, it's a layer three tunneling protocol that lets two peers establish
uh an end-to-end encrypted connection. There's a couple of things worth highlighting specifically about WireGuard. WireGuard encapsulates both IPv4 and IPv6 traffic at layer three and only at layer three. It's opinionated. WireGuard is end-to-end encrypted using modern cryptography. Again, opinionated. There's nothing for the user to configure and there's no way for the user to downgrade the cryptography. And although the cryptography is modern, it's conservative and well-reviewed um using conservative well-reviewed protocols and ciphers. And WireGuard appears stateless to the user. They not only don't have any cryptography or cryptographic choices to make and configure they have very few other configurations to make as well. Um once connections are established, WireGuard handles key rotation and uses timers to ensure connections keep live.
Key exchanges, connections, reconnections disconnections and discovery all happen behind the scenes without the user needing to take explicit action. WireGuard uses public keys rather than uh public IP addresses to identify peers. So as peers move, connections can still persist. The only thing that you need to configure is what peers you want to communicate with. And so overall like WireGuard is explicitly designed to optimize for a couple of things, security, performance, and ease of use. We're not going to get much into this but that's where WireGuard really shines compared to say OpenVPN or IPsec. Okay, so I think it's useful to compare WireGuard to TLS and I think this is useful because we all think about TLS
all day every day. We use web browsers. Basically every connection we use over our web browsers today is TLS and so there are lots of like implicit ideas that we that we get from it that we then immediately try and associate with other protocols. And WireGuard is different in several ways. Uh the biggest one of these is it's a it's not a client-server protocol. There's not one uh one endpoint expecting to receive connections and another one that always sends connections. Instead, these are two peers. Either side can initiate a connection. And to do that, both sides need to be configured to know about the other side before a connection can even start. And that really leads into the second
point, which is there's no concept of a certificate authority root uh with WireGuard. So with TLS, our operating system has a long list of people it implicitly trusts to say who people are and everything is signed with one of effectively by one of those roots uh uh telling us who people are. Instead with WireGuard, uh after you generate a public-private key pair, you have to move the public keys of a peer to the other side of the connection beforehand. And the best way to think about this is it's like SSH without passwords. When you want to SSH into a machine, you already have to have moved your SSH public key into the authorized keys file
on the other end of the machine on the other machine you're connecting to. It's just the same with WireGuard. So another big difference is it's a UDP-based protocol, not TCP. Now with HTTP/3, there is a UDP of sort of TLS these days. Uh and there's the reason for using UDP has there's a lot of similar reasons for the uh why HTTP/3 uses UDP but in addition uh UDP is a much better transport for a layer three tunneling protocol because it helps avoid the sort of TCP in TCP issues when it comes to tunneling. Uh it's very difficult to get your window sizes right and deal with fragmentation of your internal TCP connection over another TCP connection.
Uh there's also no standardized port, which is very different from how we typically use TLS. We're usually connecting to 443 or some equivalent. Uh and uh as a a side benefit of this sort of noise-based protocol where everyone knows about each other before making a connection is uh there's no sort of advertising of what's going on. So if you if you connect to uh an SSH server of a netcat uh the first thing SSH does is it successfully creates a TCP connection and then the the server tells you what version precisely it's running and a lot of details about itself. With WireGuard, that very first packet you send only gets responded to if that packet has
proven that it's one of the peers uh of the machine you're talking to. So you only get a response if you're meant to see one. Uh finally, there's no protocol versioning, which Maya went into, which means that uh if something was going to change inside the WireGuard protocol, it would have to get a whole new name and would look radically different. And then most importantly for me compared to what it's compared to TLS, WireGuard's small. So the entire implementation of WireGuard in the Linux kernel, including its cryptographic primitives, fits in around 4,000 lines of C. If you look at the IPsec implementation in Linux, it's 100 times the size. This is really neat. It means you can put
WireGuard in all sorts of strange places. You can put an entire network stack in user space inside a process, which we do occasionally. It's a lot of fun. And you still end up with the network stack and WireGuard being much smaller than IPsec or some equivalent. So at a very high level, what does the WireGuard protocol do? Um it actually looks like a lot of other key exchange protocols but has some nice security properties and performance implications again because that's what it was optimized for. Um so let's take two peers, Alice and Bob, and they have pre-existing private-public key pairs for their hosts. In WireGuard as as Crawshaw just explained, each peer is identified by its public key and you
have to have those public keys shared with each other ahead of the protocol um as part of their WireGuard configurations. So then when you get into the WireGuard protocol itself, this starts with a key exchange. To initiate a new connection, WireGuard um uh to initiate a WireGuard connection, Alice, who's the initiator, generates an ephemeral session key uh to communicate with Bob. Now when I say generate, I don't mean that Alice generates, right? WireGuard generates for Alice. The only thing that Alice had to generate was her host private and public key. So she sends Bob Bob information about her ephemeral session public key. Upon receiving Alice's message, Bob verifies that Alice is a known host. Then he also generates, aka
WireGuard generates, an ephemeral session key pair and replies to Alice with some information about his ephemeral session public key. And then each side has enough information to complete multiple Diffie-Hellman key exchanges using as inputs the combinations of their public and private static and ephemeral keys um in order to generate session keys. And since it only takes one request and one response to actually generate those keys, it's a one round trip time um key exchange. And then Alice and Bob can use those session keys to send encrypted information uh to each other and that's it. So what's notably missing here? Um there's no kind of protocol negotiation. WireGuard is opinionated and it doesn't have to have Alice and Bob agree on what
cryptographic algorithms are going to be used as it's all decided ahead of time. And in order to ensure that Alice and Bob can stay connected even if they have nothing to say to each other, WireGuard has a has a keep-alive protocol. It also automatically rotates keys for forward secrecy. So let's step into the actual, you know, key exchange. So let's start a session and this is the very first packet that gets sent when someone has queued up a uh something to send over the WireGuard tunnel. And so there's a handshake initiation. And so to create this handshake initiation packet, Alice generates which Alice's software for her generates this uh this ephemeral uh public-private key pair that Maya mentioned. And the
first part of the packet is the ephemeral public key at the top. And then the rest of the packet is encrypted both with the ephemeral private key and with Bob's static public key. That's the key that Bob generated uh himself and shared with Alice earlier. This uh uh this contains uh enough information for uh Bob to determine it was Alice who sent the packet uh and to initiate uh a conversation. It also starts some timers uh on both ends uh when the packet is both sent and received uh which WireGuard will use to decide when the handshake has, you know, uh taken too long uh to succeed and when it should be updated. And then Bob can respond to Alice's
handshake. Um so to do so, Bob first generates his ephemeral public-private key pair for this session. Um his handshake response to Alice includes identifiers for both Alice and Bob so he can in his in his registry so he knows that he's talking to Alice and this is a session with Alice. Uh it includes his ephemeral public key um a key derived from his ephemeral private key and Alice's public static key, some hashes to verify all of it, uh and then also some some cookies to let Alice try to communicate with Bob again if he's under load. So this only happens if Bob is under load. He basically has a way to say, "Hey, I'm too busy to respond right
now." Um and WireGuard gives you a mechanism that adds another round trip and tells tells Bob that he should really respond to Alice next time she communicates with him again. So there's there's a way of kind of dealing with um servers that are under a load as well. And everything is chained and hashed a bunch. So, that reply that message does a couple of things. Bob shares his public ephemeral key, which Alice will then be able to use in the next step to generate a session key. It confirms that the session is with Alice. The identifiers let Bob know that that's the session he's replying to and the hashing and chaining make sure that he
those those messages are not replayable in in the future. And it ensures that only Alice can get this message again because it uses her public static key. What you don't see here is there's nothing here that explicitly authenticates Bob to Alice. Since Alice sent the first message to Bob to you know to Bob's static public key as part of her first message, the fact that Bob is replying at all the fact that he was able to decrypt and reply to the message identifies him as being Bob. There's no explicit other authentication. And so now we have what we need to be able to to generate some some session keys. So, both parties have their static
and ephemeral key pairs and the other parties static and ephemeral public keys. So, this is actually the easiest step to understand if you remember Diffie-Hellman key exchange. Diffie-Hellman key exchange gives you a way to combine Alice's private key with Bob's public key or Bob's private key with Alice's public key so that you get the same shared key out of it. In this case we're actually doing this a bunch with all the the chaining keys that they previously generated in the in the handshake and plugging that into an HMAC derived key function to get a shared transport key for this session. So, looking more specifically at the keys that Alice had previously generated, she has derived a key from her private
static key and Bob's public ephemeral key, from her private ephemeral key and Bob's public static key, and from her private ephemeral key and Bob's public ephemeral key. And that's enough for them to establish a common session key. She also derived a key from her private static key and Bob's public static key, but that's what let her authenticate the first message rather than needing another round trip just to do that. Okay, so now we've sent a handshake initiation and a handshake response and it's time for the first actual piece of data to be transferred by Alice to Bob and this is the data exchange. This is actually a component of the handshake because at this point Bob has responded
to Alice's handshake initiation but doesn't realize that Alice has received the response. This data exchange is the proof because it's UDP and packets can easily be lost. There's nothing underneath reconstructing the session. So the the data exchange first data exchange packet is very important for establishing the session. And this is just encrypted and sent with ChaCha20 and this is how most of the packets move. There's some per packet overhead, 60 or 80 bytes depending on whether it's IPv4 or IPv6. And this means you end up reducing your MTU slightly to make up for that difference. There's also a series of timers that are running as part of this. So, WireGuard follows the standard model of after a certain amount
of data has been transferred, the uh the session keys need to be rotated but it also starts wall timers for doing some of this rotation. This is to ensure that keys just don't linger for too long. So, every 2 minutes or so that handshake that we just saw happens again over a running connection to reestablish a new set of session keys. It's rather nice that it can use the same handshake that's used to establish connections as its reestablishment system. And if handshakes are lost, they can be resent after a certain amount of time. They're sent with some amount of jitter in case both sides are attempting to handshake simultaneously, which can cause them to race and then
they don't successfully move information around. This sort of constant refreshing ensures perfect forward secrecy. All right, so now that we've gone over the protocol and how timers work, let's cover the cryptography that's used in WireGuard. It's a long list of protocols and ciphers and honestly it overwhelmed me a little bit when I first saw it. So, the key exchange that we talked through in Alice and Bob's handshake follows the noise framework and specifically uses the noise IK protocol. Optionally you can use a pre-shared symmetric key as part of the key derivation. This is just a base64 encoded random 256 bits used to protect against potential advances in quantum computing. Given that the ciphers that you use the asymmetric crypto that you
use in WireGuard would be susceptible to quantum computers. So, we have 256 bits following Grover's algorithm to break that you need 2 to the 128 complexity which is sufficient for most users. Note that this pre-shared key if you're going to use it is only used in the key exchange process where the asymmetric crypto is. That's the part that's susceptible to to quantum computing here and it's not used as part of your your the encryption of your data your packets that are sent between users. So, what that means is that there's no there's no performance impact there's no overhead of actually adding in this pre-shared key. Um Next up the static and ephemeral keys that Alice and Bob use are both
Curve25519 an elliptic curve which allows us to use Diffie-Hellman afterwards as part of our key exchange. The key derivation function is an HMAC key derivation function. It's used to convert the shared secrets that we get out of Diffie-Hellman to key material that we can use for symmetric encryption. The symmetric encryption is done with an AEAD using the stream cipher ChaCha20 and for encryption and Poly1305 for authentication as Croshaw was just saying. And finally the hashing that we need as part of generating the HMACs and hashing a bunch of things throughout is Blake2s. So, that's a lot of detail. There's two things I really want you to get out of this slide. The first one is that all
the cryptography that's used in WireGuard is reviewed and modern but conservative. Curve25519 is considered a best-in-class elliptic curve and it's also very performant very fast. These ciphers are all more than a decade old. They're well reviewed in the industry, published IETF standards. Like there's nothing fishy going on with the crypto here. However, WireGuard won't meet your FIPS you know requirements because not all of the these have been pursued for FIPS compliance. The second thing I want to want you to get out of this slide is that all of the cryptography used in WireGuard and we said this a few times now is decided ahead of time. There's no cipher agility, no negotiation, and no way to
downgrade the cryptography that you use. And as Croshaw also mentioned briefly, if if something breaks if one of these protocols breaks, these ciphers break, there's there's a way for us to to potentially swap this out or update this in the future if there's an issue discovered. So, what you see at the bottom of the slide this like long string is part of the construction string that's actually passed in as part of the handshake used for computing keys. Not before the handshake, right? There's no negotiation. As part of the handshake. And so if something you know if a new version of WireGuard were to come out a new a new type of WireGuard would to be
to come out, you would know that you're communicating with something that's broken because you would know that the key the keys that you had were generated using these ciphers. Okay, let's try something that probably won't work which is always fun. Let's try a demo. Let's see if we can make WireGuard work. Now, let me just prep this off screen. Could you hold this for me Bob? Oh, thank you. I'm not. I just didn't want to embarrass myself too much. I thought I'd do the pre-work of establishing the SSH session beforehand. So, let's try No, it won't let me drag that across. Let's figure out how to stop the presentation. That worked.
Amazing. I found it. All right. This is always fun. It always breaks in new and interesting ways when you try and do any kind of live demo. So, what I've got here are two two virtual machines both Linux machines running on my Mac because I attempted to do this uh uh on the Mac and couldn't make it work. Uh let's see if I can type in a password. Don't worry, it's not a real password. I'll pass this back to you.
Okay so This is what a WireGuard configuration file looks like. It contains a definition of the machine that WireGuard is running on. So, it specifies the IP address in the tunnel that wants to use, the port to listen to on the physical IP address, and the private key of the the device. Then it specifies a set of peers that you want to connect to. In particular, it specifies one peer here and it lists the public key of that peer. And it lists uh Let me just see if I can show you the other side as well. And then it lists the physical IP endpoint that you can reach it at and the tunnel IP address you would
expect of that machine. So, in this case we have two virtual machines running on 10.2.1.155.3 and 55.4. And we're going to create these internal tunnel IPs of 10.9.9.3 and 10.9.9.4. And what we've got here so This machine which is machine number three has the public key that matches the private key of the other machine and this machine has the public key that matches the private key of the other machine. And so Let's see. What else do you need to know about this? That's enough to know. Let's let's see if we can actually make them talk.
I'm really impressed that you're typing like over your shoulder. It's the only way to do it. It's a it's really important you have as many things in a demo that can go wrong as possible because that's really the fun of watching a demo. So, what I've done now is I've turned on debugging mode on this virtual machine and we're we're trailing the output of WireGuard's kernel responses. And now we will try
So, what we have here is the virtual machine on the right is pinging the virtual machine on the left and the virtual machine on the left received a handshake initiation from the from the peer and it sent the handshake response and then the ping inside the the WireGuard tunnel is being relayed to the uh uh uh to the kernel of the machine and that's where you're getting the ping response from. Okay, that's how WireGuard works. It's actually pretty simple once it all works and fits together.
Amazing. So, let's recap what we covered today. Um so, to recap, um first we went over what WireGuard is. WireGuard is a layer 3 um tunneling protocol that lets two peers connect to each other in an end-to-end encrypted way. Um we talked about how WireGuard is uh different from other network protocols using UDP and using public IP addresses as your identity. Uh then we went step-by-step from the ground up through how WireGuard works. WireGuard is a one round trip time key exchange and the peers can uh use a shared session key that they derived to um for symmetric encryption to communicate directly with each other. WireGuard handles key rotation and uses various timers to keep connections alive
and WireGuard uses modern but conservative cryptography that is performant and well-reviewed. And lastly, we demoed WireGuard so you could see how to set it up yourself. Um there's lots more that we didn't cover about WireGuard like performance and the threat model and how it compares to IPsec and OpenVPN, formal verification. So, there's lots more that you can learn online. Um so, you should now have a better understanding of how WireGuard works and feel comfortable setting it up yourself. Um here's a couple links where to learn more to get more information. Uh if you're interested in some Tailscale stickers, we have some and check out the link at the very bottom there to get some Tailscale goodies.
Thanks. Thank you, everyone. Thank you for performing our presenting at BSides performing presenting. Yes, performing it. Um yes, we have uh this undisclosed uh brown um bag from Maltego. Uh you get one, too, as well. Um and uh thank you again. I appreciate that. We all do. Thank you. Thank you for joining us, you, too.