Thank you everybody for your patience. Thank you for coming to the Crypto and Privacy Village today. We have a bunch of great talks today so far and I'd like you all to welcome our next speaker. He'll be talking about Rust TLS, modern, fast, safer TLS. Please give a warm welcome to Joseph Burr-Pixton. Thanks very much. Does everyone hear me at the back? Okay. So my name is Joe. I'm a I come from Cambridge in England. This is a project I've been doing for about the last year in my spare time. It's not really a work thing. So what I'm going to be talking about is a little bit of memory safety evangelism, not specifically Rust, but, you know, memory safety. And then I'll go through what is currently implemented in Rust. Rust TLS or Rustles is however you want to pronounce it. And then I'll be kind of justifying some of the things I haven't implemented with respect to well-known TLS vulnerabilities. And then there's a bit of performance testing and future work at the end. So Rustles is a TLS 1.2 TLS 1.3 Draft 18 TLS library written in Rust. Triple licensed. So it's quite as open source as you really would want. And, yeah, it's a little bit over a year. First proper release was kind of a few weeks after DEF CON. I did quite a lot of work on it on the plane here and back. Last year. But let's talk about memory safety. It's a problem and it's kind of like software engineering industry is kind of in a bit of a rut with it. So let's assume that the last IOS update is typical of a large complex software project which is kind of more of a modern. It's not like from the 80s. Well, some of it is. But most of it has been written in the last 10 to 20 years. And so these releases get done every month, every couple of months. And as you can see from this fair. So I'm not presenting this as real research. It's kind of lazy. But hopefully you can see, well, two, three, four, five, six, seven, 10, 11, 12, 13, 14, 15, 16, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 30, 27, 30, 31, 32, 33, 34, 35, 36, 37, 38, 38, 39, 40, 40, 41, 42, 42, 43, 44, 45, 45, 46, 47, 41, 42, 43, 44, 45, 46, 47, 48, 49, 49, 50, 51, 52, 57, 56, 57, 57, 58, 58, 59, 59, 60. And what I mean by software engineering industry is stuck in a rut is this is kind of personified by this line here where they're saying we had a memory corruption issue and we kind of fixed it but there's nothing systematic being changed here they're very much in penetrate and patch penetrate and patch month upon month um so yeah this isn't working um it hasn't been working for well maybe since the early 90s it wasn't working before then but no one was really really cared um so um that slight um there is a little bit of rust evangelism but i'm trying to tone it down because people basically coming and telling people to rewrite everything in rust is at best counterproductive um it's also not actually necessary um if you choose which bits you're going to rewrite in in whatever memory safe language you're going to write in whatever language you like um then it's you you know you can choose your attack surface you you say oh tls is an important attack surface which it is um then re-implement that in rust and stick it in front of your random thing like apache or nginx which is all written in c or c++ or whatever um uh so there's there's it's not a case of it's not a case of it's not a case of a total case of just choosing a programming language as well um it gets more complicated like node.js only recently um removed an api which was like the heartbeat heartbleed primitive that you'd want um and actual real javascript um uh projects had cvs as a result of this this terribly insane api they implemented so yeah it needs more attention than just write everything in rewrite everything in rust or go or javascript but um you know rewrite everything in rust is a good first step um so rust for people who haven't come across it is a um programming language which came out of mozilla um it's memory safe and concurrency safe and what i mean by that is when you have um a whole class of vulnerabilities are basically impossible um uh uh to achieve if you were thinking that a vulnerability was something that you wanted to have um there is a an unsafe subset so there's an unsafe um keyword which introduces basically unconstrained memory access um calling into c libraries all this kind of thing so that's that's a good um trapdoor to um do function interfaces so calling into libraries written in c c++ and and the other way it's got a really good type system so in terms of like there's like a trade-off between how good your type system is and how complex it is rust is i would say um it's more complicated than go it's more complicated than c it's less complicated than go it's less complicated than c it's less complicated than go it's less complicated than c plus plus um so i've been writing c plus plus since about 1998 something like that and i still could not claim to know the whole language i've been writing rust for maybe a year and a half and well i feel like i'm closer to that maybe not totally there but you know um the other important thing is um it's got no rust it's got no code it's got no code it's got no code it's got no workspaces it's got no shortcuts it's got textures orě 데j and it's quite quick as well It can be quicker than C in some certain circumstances, mainly due to aliasing. So there's this thing in C called aliasing where basically if you've got a function with two arguments of the same type, then they can, in fact, overlap, and writes to one can invalidate the other. That can't happen in safe Rust, and so there's a whole slew of other optimizations that the compiler can take advantage of. So, apart from all the memory safety stuff, I've also been trying to learn from some of the slightly poor API designs that have been... kind of a common feature of other TLS libraries. And so the inspiration here is this paper from, well, five years ago now, from Dan Bernay. The last paragraph is the one that you should read if you're just going to read any of it, but that's what I've been trying to go for. So my... my kind of use case here is you have a program, you want to call an API, say GitHub or AWS or something like that, but you don't... you're not interested in TLS. You're more interested in talking to GitHub, talking to AWS, something like that. And because TLS, H3S, is such a given these days, there's a lot of such users who just don't know how to use it. They don't want to... It really shouldn't be tasked with working out what host name verification actually means and certificate verification, all this stuff that is necessary but redundant if 100 people do it all different ways. Also, the security outcomes of making everyone do it are poor. So this is what is currently implemented. I've gone for a quite conservative set of features. I should say TLS 1.3 is still not standardized, but it's been progressing in drafts. Draft 18 is the most common current one. So if you see TLS 1.3 on the public internet at the minute, it will be draft 18. Draft 19, 20, and now 20. Draft 21 are all kind of minor tweaks. They're incompatible, but they're minor tweaks, and so it doesn't actually make sense to break compatibility with the rest of the internet at the minute while people are doing testing. The other thing is Rustle always does forward secrecy. So there's no implementation of RSA key and cap secrecy. So there's no implementation of Cipher Suites, which are, well, very kind of crap. The other thing, well, there's a slide later, but TLS 1.3 has also abolished this, so it's kind of similar. And the other thing is server authentication is basically non-negotiable. So you both don't need to do anything, and also it's kind of hard to turn off. The other thing is, the other thing which is very, very recent is OCSP and SET pinning. SET is related to certificate transparency. So this is basically a proof that the certificate you've just been given by a server has been included on a certificate transparency log. And I think sometime later this year, Chrome will be requiring that... all servers provide at least two valid SCTs along with the certificate to prove that certificate transparency is in play. Yeah. So this is what the dependencies look like. So there's Russell's down at the bottom there. For users of... So first of all, setback. Russ has a package manager called Cargo. All these orange boxes are crates, so they're individually versioned separate modules, all stored in their own version history and everything. So at the bottom here, CT logs is a list of all the valid CT logs from Google. WebPKI routes is all Mozilla's. Route CA is minus a bunch, which have been bad. And SCT.RS is a very recent SCT validation library, which I wrote. WebPKI is a cert validation thing written by Brian Smith. And then at the top, which is the kind of apex of all these, there's Ring, which is also written by Brian Smith. And that's got a lineage from Boring SSL, so some of the crypto comes from Boring SSL, pretty much unchanged. Some of it has been re-implemented in Rust, in the Ring project by Brian Smith and others. But yeah, I trust Brian Smith. If anyone doesn't know Brian Smith, well, I guess his claim to fame was he single-handedly rewrote the whole of certificate validation for Mozilla and then he wrote a certificate validation for Mozilla in C++ and WebPKI is kind of like not a direct transcription, but it comes from the same place. So there's that. And now I'm going to go through some old TLS problems. So this is going to go quite quickly because you'll notice a pattern as we go through. I'm splitting this into protocol versus implementation. I'm splitting this into protocol versus implementation. But this is the approach. Basically, don't implement things which are broken. So particularly, I mean, I think these are fairly, well, no one's going to argue with me, maybe on discrete log Diffie-Hellman, but in fact, discrete log Diffie-Hellman, you can't negotiate it properly in TLS 1.2, which means it's basically impossible to do that. To deploy and have people talk to you at an acceptable security level without having interop failures. Okay. Is that better? Okay. Sorry? Okay. So the next is a, well, there's more of this. GCM nonces. Well, that was, I think, disclosed last year here and at Black Hat by Hannah Bock and co., I think. I've put this as part of, as a protocol problem rather than an implementation problem. What they reported was implementations which got this wrong, but I think it's a protocol problem because the protocol allowed them to make such a poor decision. And so this counter from a random start point has a security proof. It's exactly what is required in TLS 1.3. And then all the rest are, again, not very controversial. And then triple handshake and renegotiation. Well, there's not a single renegotiation vulnerability. There's a whole stack. And the answer is, don't do renegotiation. It doesn't end well. Well, it hasn't ended well about three times now. And so this is what I was talking about earlier, which was comparing the subset of TLS 1.2 that I've implemented versus the design of TLS 1.3. And you see there's a quite nice overlap there. And then implementation problems. I'm sure everyone knows about these. The middle two are very similar. They're basically like implementations. Do things wrong if you miss out messages or you send messages in the wrong order. And yeah, so for Hartley particularly, because it's all... It's all anyone ever talks about in terms of TLS implementation vulnerabilities, memory safety gets you most of the way. Not implementing random kind of pointless extensions like the heartbeat extension, which was solely really used for DTLS. Implementing that as well for TLS. It's a bit weird. And also always doing performance... It's a bit weird for perfect forward secrecy because no leak of a private key should compromise past traffic. It's just a terrible idea. So I thought I'd talk about marker types. This is something I did on the plane here. So it's kind of new, but I'm not sure whether it's an actual new idea. I haven't seen it in other TLS or crypto libraries. So the whole problem with go to fail was... I don't know if you've seen it, but I don't know if you've seen it. But there was a function. It did some signature verification, but due to an accident, half of the signature verification got missed off. And so there was a jump from halfway through the function to the end, and at the end, there was just like a return with a there's no error return code. But actually, saying there's no error is not a positive... affirmation that, yes, I have verified the signature you asked me to. It's more like it was fine. Or maybe, you know... So you can delete the whole function body and still end up with something that seems to work, but obviously is terribly vulnerable. So the idea here is instead of having the absence of error, you have a specific type which has no size at all, so it's totally free. It's just a figment of the compiler's imagination. And then you reduce the problem to just checking that there's only one route to making these types, and that that route goes through all the steps that you want to do in the signature validation. So there's... There's no concept of missing out steps. And so this is some code from Russell. So the top is us verifying a TLS finished message. So this is just like a check that both sides in the protocol saw the same handshake. And if that's true, if that matches, then we produce one of these values. And then at the bottom, we've got the protocol state which you really want to end up in because this is the state where you can send application data back and forth. That means... So these types at the bottom mean by construction, the compiler will prevent you from getting to that state unless you've been through all these... all these... checks and produce the right types and then pass them through. So there's no... There's no possibility of skipping a state which produced... which say validated the service up because the thing just won't compile. So yeah, there's some stuff about testing. The one thing about testing I would say is BOGO. Which is the boring SSL test suite. That's been super useful. They basically took the Golang TLS library and then made it really, really, really evil. Configurably evil. So it could do a whole suite of subtly different but broken handshakes. And that's pretty cool. It found some good bugs. Most of these bugs were like I didn't send an alert in a particular place when I was meant to. I sent the wrong alert. That kind of thing. There's some places where I sent the wrong alert. I sent a different alert to boring SSL. But in fact, the library just... The TLS 1.2 spec says send an alert and not what kind of alert to send. So I kind of aligned with boring SSL at that point because just well, life just goes on. It's too short. The other thing is performance. So the important number down here. This is just on my random machine at home. OpenSSL can do raw AS128 GCM at 37 gigabits per second on that machine. The library started out quite slowly. It was very copy heavy. So it would copy the data you wanted to send a whole bunch while encrypting it, fragmenting it and so on. Those copies got removed as time went on. And I think 22 gigabits per second per core is reasonably good. What I haven't done is measure OpenSSL in a similar phase. Because the difference between 37 and 22 is basically going to be all the protocol framing and parsing. So I expect OpenSSL to be somewhere between those numbers. But yeah, I think 22 gigs per second per core is pretty reasonable at this point. The other thing was, so TLS 1.3, as it got mentioned yesterday, has this new and exciting feature coming to a DEF CON near you called zero RTT. In the protocol it's called early data, which is a much better name, frankly. This is when you're resuming a connection, you can start sending data with the resumption on the assumption that the resumption will work. The problem with that is that first message you send, that resumption and the data is replayable. And there are some limitations to that replay, time-based. And there's a new thing added to the RFC saying, well, you should probably prevent people from doing this kind of replay. But not, yeah, it seems like, a very, very tricky thing to actually get right. The other thing, applications have to know this is happening because they can, in some circumstances, servers at least, can receive duplicate requests under attacker control, basically. So that's not great. On the other hand, it's basically in a state where it can't really be deployed because the RFC, it says you have to have a profile saying, so there might be a profile for HTTPS which says, well, you know, get requests without any cookies can be sent like this or something like that. There isn't such any, there aren't any profiles like that at all at the minute. So I'm aware that some people have deployed it, but it's largely in a testing capacity rather than an actual production. So it's a very, very tricky system because that would be crazy. The other thing is, finishing off OCSP verifications. That's on the client side, checking that a staple OCSP response is valid and that your certificate that you've just got hasn't been revoked. And there's PSK support, that's kind of been bubbling over for a long time, but in TLS 1.3, PSK and resumption are, basically the same mechanism. So with resumption working, PSK is a mere matter of making the API exposed to the rest of the world and implementing it in TLS 1.2. And then the other thing I'd like to do is stop this library from being kind of rust-centric. So it would be really nice if this could be, you know, compiled into like an Apache module to terminate TLS, or an Nginx module or whatever. And the LibreSSL people came up with a nice C library, C interface I should say, which, it looks quite nice. It doesn't make me retch, so that might be a good choice. And hopefully by the time I get back to work, I'll be able to really do some more stuff around doing that. There'll be integrations with things like Apache and Nginx. And then a third party audit would be nice once everything, you know, once TLS 1.3 has been finalized, and once I'm fairly sure I'm not gonna add, you know, more features. So that's that. I did have some extra slides, but there. that kind of screwed up. So, any questions? Yeah. So, you mentioned a lot of the vulnerabilities of other TLS libraries and how you avoided them through non-inputting broken features and the type system, but of course you mentioned that there were some bugs that you wrote in your implementation which kind of by definition are bugs that were not prevented by those vendors. So, what were the kind of classes of bugs that did get written in Rustles and how can we improve our compiler and type system tooling to prevent those kinds of bugs as well? Okay, so I'll just repeat the question. The question was roughly what kind of bugs did I find in Rustles having written it and how could they be prevented? So, as I said, most of the bugs I found were spec non-compliance, not in a security, so they weren't necessarily vulnerabilities, but they could cause interrupt problems. So, I feel reasonably confident about the security of Rustles. What I'm not totally confident about is that it would be as interop as well as say OpenSSL or NSS or BoringSSL. So, those kinds of bugs, those interop kind of bugs, which I'm more worried about, BOGO found some of those, but I'm sure there are some still there. I think really most of those get squeezed out either through use or some kind of formal analysis. There is a project called Mount Everest, Project Everest, I think, being done by a bunch of people, including Microsoft Research, and that is gonna produce a full end-to-end, formally verified TLS 1.3 stack. So, hopefully I can use some of the results of that to either generate test cases, or generate some of the code that I've written from their formally verified protocol implementation. And I think that would be pretty cool. Any other questions? I'm looking at you, because you asked me a question. Thank you very much. Thank you.