 So this is on WireGuard, which is a new VPN, which aims to be fast, modern, secure. So first, a little bit of background about myself. My background is in exploitation, in kernel vulnerabilities, in offensive securities, finding bugs, exploiting bugs. But I've done a lot of development as well. And in researching other projects, I see the same types of bugs come up over and over, same types of fundamental problems. And seeing that secure tunnels are such an important element to have in networks, I decided to take what I've learned from doing offensive security and try and make something really simple and nice that you can use. So what is WireGuard? It's a layer three network tunnel. So it's for only IP, not for layer two, not for ethernet, just a layer three network tunnel. And as we'll see throughout this presentation, it makes a lot of choices like that. It's only for layer three. It only does particular things because it's opinionated. It's made with a series of design considerations where the choice has been made for you in a lot of ways. But from these boiled down choices, we make nice building blocks that then you can make big complicated systems out of. It lives in the Linux kernel for performance and for good integration, but we've got some cross-platform implementations in the works in languages like Rust and Go. But for the moment, it lives in the Linux kernel written in C. It's UDP-based, and so it can live on the real internet punching through firewalls. We use modern cryptography, but we're very careful to use conservative cryptography, proven principles, nothing too new-fangled. And the project as a whole has a real emphasis on being very simple, easy to understand concepts, easy to understand code, and just trying to make a nice minimal structure. The authentication model aims to be like SSH. In SSH, you usually share keys by sending your public key through an encrypted email or through some other mechanism, and you have simple public keys that you copy and paste around. I'm sure all you guys use SSH. So WireGuard tries to be as easy as that, but for VPN. In general, it aims to be a replacement for OpenVPN in IPsec and the various other VPN technologies that are out there, some that live in kernels, some that live in user space. WireGuard tries to replace most of that with something a lot simpler. Most of all, WireGuard is easily auditable. When you look at OpenVPN, it says 116,000 lines of code, plus all of OpenSSL. And so maybe you could make that code base secure eventually, maybe you need to pay a lot of people, a lot of money to read all that and audit a big project. The Linux XFRM layer, which does IPsec, is 13,000 lines of code plus something like Strong Swan for the Key Exchange, which itself is 405,000 lines of code. And I mean, these are great projects with smart people who have worked on them, but this is a lot of code to read. And we're talking about C code, and so this is hard to really be sure that you're using something secure. SoftEther is kind of a jack of all trades solution that supports OpenVPN, supports IPsec, supports all sorts of things. 329,000 lines of code. WireGuard is under 4,000 lines of code, which means everybody in this room can sit down and read the entire code base in one sitting in an afternoon, understand it. Security experts can read it just for fun because it's short enough that it's still fun, so that it actually gets some eyeballs. So just to put this in perspective, in the solar system of VPNs, I guess we're Pluto. It's also really simple to use. Rather than say the complicated IPsec XFRM system or OpenVPN daemons, with WireGuard you just get a normal network interface that you can administer using all the tools you already know, with the IP routes, et cetera. So to add a WireGuard interface, IP link add, just like you would with any other kind of virtual interface. To set the address, IP address, or IF config if you like that. Routing is the same way, and you can use IP tables. If you're into old style, host-based authentication, you can even use Etsy hosts. You can bind to the addresses of that interface. Because with WireGuard you just have the interface. It's a simple, fundamental concept, and it allows you to use all the things that you already know about. So everything that ordinarily builds on top of a network interface like ETH0, WLAN0, you can build on top of WG0 for WireGuard. So you don't really have to learn that much that's new. On the other hand, WireGuard is a bit blasphemous. IPsec is nice in a lot of ways. It was made by a big committee. It was engineered by a lot of people, and it does all the nice layering in a very pristine way. A lot of people looked into which component should have which responsibility, how to separate all this out. And it's nice, but it's also super complicated. Hard to implement, prone to bugs. If you ever tried to set it up, you can't even wrap your mind around all the different layers. And so WireGuard actually breaks these networking assumptions from the 90s where you have these nice layers. And instead we do something that's on the surface wrong. We smush everything together. And then from there we try and come up with good engineering solutions to regain the coherence. And so that way it remains simple, but it still works and it still has a solid foundation. So how do we do this? The fundamental idea of WireGuard is crypto key routing. So the idea here is you have a peer and you have a list of IP addresses that that peer is allowed to be. And the peer is identified by a public key. And so you have a mapping always between public keys that are used and IP addresses that are used. So more generally the WireGuard interface, WG0 itself has its own private key. It has a listening UDP port. And it has a list of peers that it can talk to. Then each peer is identified by its public key. This list of allowed IPs that that public key is allowed to be. And optionally, as we'll see later, the endpoint on the internet of the other UDP port that you're talking to. So just to drive this home, the fundamental idea here is a relation between the public key and the IP address. Super important. So here's what a configuration might look like. A server has the interface section with its private key and its listening port. And then this happens to have two peers. And for the first peer, it's allowed to be that 10.192 address. And the other 10.192 address but slash 24. So the whole subnet. The next peer gets its slash 32 and a slash 16. And so those public keys when talking to the server can only send IP addresses, can only send packets as IP addresses in those range. On the other side, a client has a configuration with again interface that has a private key and a listening port. And it has a block for a peer that's the server. And so it has the server's public key. It has the endpoint of the server. And it trusts the server to send it any IP. For example, maybe the server is a gateway to the internet. And so it's forwarding packets from any IP address on the internet. In that case, it wants to allow any IP from the server. Now you'll notice that the server doesn't list any endpoints of the peers because it doesn't know them, it's the server. It's waiting for the client to connect to it. But what happens is whenever the server gets an authenticated message from a client, then it'll learn the latest endpoint of that client for sending reply packets. So in that way, clients can roam freely from different source IP addresses. If you've ever used Mosh, it works exactly like that. So how does this work at the API level? User space sends a packet using the send syscall. Then it goes to the ordinary Linux networking layer that decides, okay, this packet should go to the WG0 interface. So now it's in our code. Now it's in the WireGuard driver. WireGuard looks at the destination IP address of that packet and says, ah, that destination IP address corresponds to this public key. Then it looks up what current session is used with that public key and encrypts it for that and sends it off to the endpoint. In the reverse direction, when the UDP socket receives an encrypted packet, it decrypts it and learns for which public key it should use a key session for. Then it inspects the source IP of that decrypted packet and says, is that public key allowed to be sending packets as that source IP? And if it is, then it goes onto the interface and if not, then it's dropped. So all of this can be configured with very easy command line tools. Right now it's the WG utility. At some point this will be folded into the IP route to IP utility. For now it's just WG, very simple. WG set, WG0, you give the listen port, the private key, the peer plus its public key. It's the loud IP is the endpoint and so forth. It has that very simple configuration syntax as we saw before kind of the any syntax and so you can set config and get config. WG show gives you the nice colorized ASCII output and there are also various sub commands of that to get output that's good for parsing and scripts. For generating keys, just WG gen key. To make a public key from a private key, you pipe the private key into WG pub key and you get out the public key. So very simple basic interface. But from that you can set up tunnels to all sorts of peers in a super easy, straightforward way. And all the issues of cryptography, session management, et cetera are just handled transparently under the surface for you. So to the system admin, the whole interface appears stateless. You just set it up, hear the peers and then it works. And so because we have this relation between the public keys and the IP addresses, we know that if it comes from the WG zero interface and it's from this particular IP address then it must be from Yoshi through the tunnel. It must be because it's from his public key. So then with IP tables you can already start to imagine what your firewall rules are like. You match on the input device of WG zero on the source address and then that's all you need. So all the things you already know just layer nicely on top of this. So as I said, it's totally stateless. You set it up and it works. You just add the interface. You can add as many interfaces as you want. You can configure multiple peers per interface. As I mentioned, the end points just roam. So on 3G this is especially nice when you're going between different IP addresses. Your connections keep working. On the laptop it's nice if you put your laptop to sleep in one network and turn on on the other. It just starts working again automatically and you have the same IP addresses before inside the tunnel. And the identity is these public keys are really short. They're 32 bytes and we encode it as base 64. So I think that's 44 characters. And so you can paste them around for doing key exchange through any out of band mechanism. We're not trying to handle that problem here because people are already doing that with things like SSH and GPG and all sorts of other mechanisms for that. Okay, so before we go deep into how all this works, I just wanna show a demo of what it looks like to set up a wire guard interface. You get the idea. So we have peer A on the left, peer B on the right, and they're connected using virtual ethernet so you can pretend that's the internet and we'll set up some tunnels. So what's this look like? Okay, so we generate a private key over there. We generate a private key over there and when we cat it, that's the private key, super short. We derive the public key from the private key. We do the same over there. And now we add the wire guard interface. We set an IP for the wire guard interface. Which again, using the IP route to tool things, every system admin already knows. Now we set up the peer. So we give the private key of our interface as private and then we set the interface up. Now we'll do the exact same thing over here. We add the WG0 interface. We give it the IP address. We give it the private key of its interface and we set it up. Okay, so now we have to tell the two peers about each other. So first, when we type IP address, we see that it's just WG0 there. It's just a normal interface. ETH0 is our internet interface, our external interface if you will. And so it's all in there just like another interface that you've seen before, nothing too remarkable. Okay, so we type WG and we get the information each currently has about itself but now we tell it about the other. So first we copy the public key from one as a peer for the other and we say that that peer is allowed to be 10.0.2 and its internet endpoint is 192.168.1.251820. We do the reverse thing on the other side. We make a peer, we copy and paste the public key for that peer. We give it the allowed IP address for inside the tunnel and we give it the internet endpoint 192.168.1.1.51820. So now the peers are set up, they know about each other and now we can simply ping within the interface and it works and that's it. We didn't have to set a daemon, we didn't have to set a state, it just works and now they know about each other, they've done the handshake. So pretty simple situation and that's about it to the interface of WireGuard. There's not a whole lot more than that but from that very basic building block you can start layering some really neat things. So as I mentioned, simple composable tool, this WG utility, it's already started to get integration to the various network management utilities. There's an IF up-down plugin for it. It's already in OpenWRT in LEED. It's, there's a nice luchi web interface for it there. OpenRC supports it with NetIFRC. It's part of the whole NixOS system. There's a work in progress to integrate it into SystemD NetworkD and there's also another work in progress to integrate it into NetworkManager, if that's your thing. And so it's being integrated. I wrote a very simple shell script called WGQuick which is not a sophisticated tool. It's just quick and dirty bash script that I use on a daily basis for connecting to VPNs. You just have WGQuick up and WGQuick down and then you define this config file which is the same for syntax as WG but we add a couple keys. Like we can run a post up and a post down script for DNS and it lives in SC WireGuard and then the name of your interface.conf. But again, this is not a sophisticated utility, a simple bash script that just uses all the other things and I like this and I distribute it and other people use it but because the building blocks are so basic, you have more than enough license to make whatever other complex tool you want. There are also some nice network namespace tricks that you can do with WireGuard. The WireGuard interface can live in one network namespace. Well, the UDP socket that it uses to send the encrypted packets to the internet lives in another namespace. So a couple uses, you could let a Docker container connect via WireGuard. You could only let your DHCP client touch to your physical interfaces but then your web browser can only see the WireGuard interface. And this is a nice alternative to the routing tricks which of course WireGuard also supports but this is a nice alternative if you want some high security. So for containers it would look like this, you have your container namespace running whatever Docker rocket and spawn stuff and you ping from that and then the WG0 interface encrypts it and it sends the UDP ciphertext out of the namespace in the in a namespace through your actual ethernet adapter. And so to the container namespace itself all it sees is WG0 and local host of course but it doesn't see any other way of getting to the internet. Conversely if you just want a leak free personal VPN for your web browser in the init namespace that you're doing all your work in you only have WG0 and then you move your physical interfaces to some other namespace where the socket lives. And this is really nice because it guarantees that there won't be any leaks from your web browser outside of the WireGuard interface because your web browser can't see any other interfaces and packets on. All right so there are a lot of security principles that have gone into making WireGuard to make it both small and simple as we've discussed but also I hope a well written piece of code. All the state that's required for WireGuard to work is allocated when you add peers not when you're getting packets. So this eliminates a huge class of dynamic memory vulnerabilities. WireGuard simply just doesn't have them because we just don't use that programming technique that's prone to that vulnerabilities. Likewise all packet headers are fixed in length and each field has a fixed length and so we don't have to parse anything. There's nothing to parse so there are no parser bugs because we have no parser. This is so ridiculously simple but in doing so we just eliminate a massive class of vulnerabilities. And then the last one is a little bit more sophisticated to implement. We don't want to modify any state of the program any type of state in response to unauthenticated packets and this is important for preventing a lot of logic based vulnerabilities. If a packet isn't authenticated we just don't want to change any variables. We want to reject it as soon as possible and move on. So we'll go into how we accomplish all this. Another principle is we want WireGuard to be stealthy. As mentioned in the introduction I do a lot of offensive security and WireGuard actually grew out of an exfiltration method of a root kit I was working on. So it needed to be super stealthy, hide packets, not be discoverable by scanners and so WireGuard inherits all of this. It turns out that a lot of those principles that are applied to offensive security are actually really good too in defending a network. So WireGuard doesn't reply to any unauthenticated packets. So it's completely invisible to port scanners on the network. If you don't know it's there then you won't know it's there. It's also not chatty. So when two peers aren't sending data to each other it just goes to sleep and it doesn't send anything. Okay, of course all of this wouldn't matter at all if the crypto was bad. So we put a lot of effort into ensuring it's solid crypto. We use Trevor Perrin's noise protocol framework which is now used by WhatsApp and is starting to get some steam. It has perfect forward secrecy so there's a new key every two minutes. So if the computers are compromised you can't get the static keys and then go back to see the information that was transferred because there's a new ephemeral key that's generated every two minutes. It avoids key compromise impersonation which is important quality. If someone steals your private key they can't impersonate anybody to you even though they have your private key. So this is important crypto principle. There's identity hiding. So when you identify yourself to another peer you don't actually send your public key in clear text. It's actually encrypted so that only the recipient of your public key can read it. So it's impossible to tell who's actually sending the message unless you're expecting the message. Of course we use authenticated encryption so not only is all the information private but we also ensure the integrity. There's replay attack prevention while still allowing for the network to reorder packets as networks do but we prevent against replay. And we use modern primitives. We use curve 25519 for elliptic curve Diffy Hellman. We use Blake 2S for hashing. Cha Cha 20, Poly 135 for authenticated encryption and we use SIP hash for the hash tables. Now importantly there's no cipher agility. This is what we use and many of you who have set up I don't know TLS servers maybe some of you are happy to read this now that you don't have to set anything up maybe other of you think well maybe we want the choice of using broken ciphers. No, you don't want the choice of using broken ciphers. If a cipher is broken then you upgrade and you don't allow broken ciphers on your secure network. So I think this idea of cipher agility is and the cipher negotiation is really a concept from the 90s that has seen its course. Of course there'll be paths to upgrade in new versions if necessary but mixing primitives and allowing negotiation allowing insecure primitives is really not a good policy. So these are the nicest ones for now and if they're ever not nice we'll change it. Okay so the key exchange, we're running a little bit low on time so I'll go through this quickly here. The key exchange is a one round trip key exchange. So the initiator sends a message to the responder. The responder sends a message back to the initiator. Using these messages they do some calculation and they come up with a pair of symmetric keys for Chacha 20, one for sending and one for receiving and then they can start to exchange transport data and because it's just one round trip either side can initiate this at any point. If your laptop's just woken up from sleep it can just immediately fire it off and start again. So there's no session state that needs to be maintained long term because a new session can just be created super simply because it's one round trip. Okay so we have in this several sets of keys that are used. There's the static public and private keys as we saw from the screencast. But during the key exchange both sides generate an ephemeral key pair. So this ensures the perfect forward secrecy. The key exchange in general is important that we keep this idea of not modifying anything if we don't get an authenticated packet. We wanna keep fixed length headers and we want both sides to be able to change roles if necessary and we wanna ignore all invalid handshake messages. And so the way this is accomplished is by combining in some method the output of four elliptic curve Diffie-Hellman operations. The first three make up what's called the triple Diffie-Hellman. Some of you might be familiar with if you've ever read the spec for the signal protocol. And then we have a static static Diffie-Hellman in the first message so that it can be one round trip. And so without going in too much depth on this it might seem like it's really complicated but in fact it's super easily implemented. The key exchange itself is only 441 lines. It compared to the strongest one which I think we said was 40,000 lines, 400,000 lines, really big. So 441 lines for the key exchange. Very simple and as you might have noticed we don't have any X509. We don't have certificates. There's no ASN1 parsing. We just have these very simple keys that we can paste around. So how do we appear to be stateless to the administrator? Obviously the protocol itself can't be completely stateless. You need state in order to have certain security properties but to the administrator it appears stateless. So we have a series of timers to make things just work. And so we have for this a very simple state machine that accounts for every possibility in state transitions. Simple enough that I was able to write down the entire matrix of state transitions so that we don't have any undefined situations. So how does this work? When user space sends a packet, if we don't have a current session from a key exchange in the last two minutes, then we send a handshake initiation. If there's no handshake response after five seconds then we just send it again. Every time we get an authenticated incoming packet then we set a timer for 10 seconds from now. And every time we get a new authenticated packet we move that timer another 10 seconds into the future. So that means if we never get an authenticated packet, if we stop receiving data then we suppose oh maybe the other side there's a problem and so we should reinitiate a handshake. And so after 15 seconds we reinitiate a handshake. Now if the other side just isn't responding at all then we go to sleep. So we remain stealthy and not chatty. But all of this amounts to an interface that you don't have to care is it up, is it down, is it running, when was the last connection made? Now the admin doesn't see that. It's just you have an interface and you send packets. And this very simple set of timers ensures that there's always a session. There's also what's called the poor man's post-quantum resistance. Now there's a lot of new crypto coming out to protect against quantum computers, but it's very new. And WireGuard is trying to be conservative with the primitives it chooses. So it's not choosing one of these new, heavily researched and debated post-quantum primitives. Instead we allow for an optional pre-shared key. And pre-shared key we can mix into the initial key exchange. And because of Grover's algorithm, a post-quantum computer can do a brute force search of a 256 bit symmetric key. With the time it would take a classic algorithm to do this in 128 bit symmetric key. And it was proved that this speedup is actually optimal. There won't be a better algorithm than this for symmetric cryptography with a quantum computer. So by mixing in a pre-shared key optionally, if you want it, if you're paranoid, if an adversary is recording all of your traffic now in 100 years when they finally make a quantum computer, it won't be decryptable. So this is a feature put in there for the extremely paranoid. Most people won't really need this because depending on who you talk to, a quantum computer capable of breaking elliptic curves are still far way off, but it's in there if you'd like it. There's also a denial of service resistance. So hashing in symmetric crypto are really fast, but pubkey crypto is slow. Even curve 5519, which has great speed records for elliptic curve cryptography, is a lot slower than symmetric key cryptography. That's just how it is. And in fact, you can overwhelm a machine by just asking it to compute different helmet over and over. And a lot of protocols fail miserably to this. UDP also makes the situation a little bit difficult because you can spoof your source address. So WireGuard uses a unique cookie solution to solve this. So we're running a bit low on time, but we'll try and get through this. So brief history of cookies, the TCP like cookies, there's a dialogue where initiator says, compute this Diffie helmet, the responder says, okay, your magic word is waffle. Now ask me again with the magic word. Initiator says, okay, my magic word is waffle. Now will you do it? And then it does it. This proves IP ownership, but you still have to store a state that waffle is associated with a particular IP address. And also this results in dynamic allocations. And this also always responds to a message so we violate our stealth principle. And of course the magic word can be intercepted. Okay, DTLS and Ikev2 style cookies are a little bit more sophisticated. Initiator says, compute this Diffie helmet, responder says, okay, your magic word is some big hash. Ask me again with the magic word. Initiator says, okay, magic word is the big hash. Now will you compute it? And it turns out that this big hash is actually a Mac of the initiator's IP address using some responder's secret. So then no state needs to be stored. And you can still prove IP ownership. So this is clever, but again, it violates stealth because there's always a response to the message. And of course the initiator himself can then be doused by just sending a bunch of garbage magic words to the initiator. So as an aside, another solution to this is the Bitcoin like or host identity protocol like where initiator says compute this Diffie helmet, responder says, do some proof of work mind of Bitcoin. And initiator says, all right, I found a Bitcoin, now will you do it? And this works great except because in WireGuard we want both roles to be symmetric. Server and client can switch sides. Now there's a DOS by just making the server compute tons and tons of this proof of work for many clients. And so that doesn't fit us. So WireGuard variant is a little bit like the DTLS one except each message has two Macs. The first is a hash of the handshake and the responder's public key. So this means that in order to respond to a message the initiator needs to know who it's talking to and prove that with this hash. So the responder won't respond just to any packet and will only respond to packets that have a proof that oh I know who you are, I know that you're already on the network. So we don't give up the stealth principle. So if the responder isn't under a load then it just proceeds normally and we don't need an agent denial of service stack. But if it is under a load that is if it is experiencing denial of services tech then it will respond with a cookie message. And we compute this cookie doing the same DTLS trick where we take a hash of the initiator's IP address and it's a keyed hash with some responder's secret except this time we encrypt that cookie when we send it using as the key the responder's public key and using as the additional data that's authenticated in it the original message. So this now binds the original message to the cookie response while still encrypting it. So now it's harder to be intercepted and we can't DOS the initiator. Then the initiator receives this, it can compute the second Mac using as its key the cookie that it just received. Okay so all of this essentially just gets us IP address attribution and then you open a networking book and you learn about token bucket rate limiting. This has been worked out extensively and so we just apply that to prevent the DOS at that point. Performance-wise WireGuard is faster than anything else I've found. It's in kernel space so fast in a little latency we don't need to copy packets to and from user space like say OpenVPN or other TUN-based solutions. We use Chatcha 20 Poly 1 305 which is really fast and it's fast on all hardware and this is a big deal. On some hardware there's AESNI which is very fast but it's not on all hardware and on the other hardware it's very hard to implement AES in a way that doesn't have side channel attacks. Well it's still fast and furthermore as vector instructions on processors get faster and faster and wider and wider I think Chatcha 20 is going to be faster than AES eventually. Right now already WireGuard for other reasons it performs faster and I think on the latest Skylake processors Chatcha 20 is already faster than AES. In general the simple design of WireGuard means there's less code and as a friend here in the audience when it's told me well when you have less code you have a faster program. Not always true but here I think this basic principle actually works out. So when we look at the performance measurements you can see we're ahead of IPsec in both AES and IPsec Chatcha Poly. We're way ahead of OpenVPN and in the ping time we have better latency than any of them. So just to recap less than 4,000 lines of code which means all of you can read it and I would be very happy if you read it. Found feedback, audited it. It can be easily implemented with basic data structures the design patterns that you need are simple and lead to secure programming. It's stealthy, they're solid crypto. We have the crypto key routing which is really a great simplification and we can get rid of a lot of the layering assumptions that we needed prior. We have an ordinary network interface so you can use all the things you already know about. It's very fast and a lot of choices have been made for you, it's opinionated. For more information you can go to wireguard.io. It's already in many of the distros, there are packages, it's in Debian, Gentoo, there's a Fedora package, et cetera. And we have quite a few stickers so if you haven't gotten one you should come up after and I'll open it up to questions. Thanks.