Help needed about tokio-rustls usage

Hi fellow rust users!

I want to use the tokio-rustls crate for encrypting traffic between client and sever for my chat-server client project 8080_msg. However I can't figure out how you go from a regular async TcpStream, to a tls connection. Could anyone help me with this? (also are there other ways to encrypt client server traffic?)

Have you tried using the tokio-rustls examples as a starting point?

I know that some people prefer being able to build things from docs alone, but I would really recommend you use the examples in the case of (tokio-)rustls. These examples aren't minimal, but they are very easy to strip down if you want to get to the bare bones of getting a TLS connection up and running. (On the other hand, in your code, you'll probably end up wanting timeouts and such, so might just as well start looking at those now).

Very basically, you perform the low-level (plain) connection as usual, and then you wrap the low-level connection in tokio-rustls wrappers.

Thanks for sharing those examples! That really helped me! The only thing I still don't understand is where the certificates come from. And do the client and server need to have the same certificate?

Well, it depends.

In the basic, and I would say common, configuration the client just needs to know that it is authenticating against what was intended. For this configuration:

  • The client needs the CA certificate (chain) (and the specific name of the server against which it is connecting).
  • The server needs a server certificate and its private key. These must be signed by the same CA.

There's another configuration where you have mutual authentication. In this configuration the client needs a client certificate and its key as well (this too must be signed by the same CA). I would suggest you ignore mutual authentication for now.

tokio-rustls tries to be the glue between tokio and rustls, but it does not strive to be more than it needs to be. That is to say, many of the operations that doesn't actually involve concrete communication is done via rustls. So you're basically going to keep to keep both tokio-rustls and rustls documentation open, side-by-side.

To answer your specific question. Rather than have the rustls runtime fetch the required PKI files, you instead load them into a root certificate store. The rustls documentation has a good section on this.

Also, I strongly suggest you look at the rustls examples (Note: The API for rustls is changing, so you should probably look at an older tagged version of the example). More to the point: Look at simple-client.rs and simple-server.rs. They are quite minimal, and demonstrate how to set up the appropriate PKI files.

If you need to actually create dummy certificates, you can use the qcert crate (which is a command line tool) or quickcert if you want to add test certificate generation to your application/library. (These are for testing only, when you're putting it into production you should probably use Let's Encrypt).

Thanks for giving such detailed info! :slight_smile: This is what I love about this forum!

After lots of procrastination, I finally added tls support! But now my (last) question is, how do I ship the certs? Do I make users self generate the certs or do I provide a cert?

Normally you do not ship certificates[*]. So the good news is that it's not your problem.

If you want a chain-of-logic reasoning behind this: In order for TLS to fulfill its function, at least the server needs a private key. The private key's public part is part of the certificate (that is to say, the private key and the public certificate are paired). So if you would distribute a server certificate you'd need to distribute the private key as well, which is a big no-no. (Edge-cases aside, like passing along test PKI files, or hard-coded default PKI files (which is generally not a good idea)).

There's a saying in security that I don't have memorized, but it's something along the line of: The system's design should never need to be a secret, only the passwords and keys should be secret in order to secure the system. (It follows that private keys must be kept private).

Your role as a TLS-enabled application developer is to chose how keys/certificates are configured (should the user specify paths, or should it read from the system's credential store), how TLS parameters are configured, make sure you use validation correctly and choose whether to support mutual authentication or not. Beyond that (i.e. setting up the actual PKI) is up to the user.

As a service to the users, if the application is meant to be publicly deployed you could point them to Let's Encrypt. But truth be told, I think that these days most people who will be setting up public TLS servers probably already know about them, or will soon find out, whether you mention them or not.

Also, test your TLS server's configuration using https://www.ssllabs.com/ (This is generally seen as a deployment test, but there are things you - as a developer - can do with the results). (Don't worry about getting a horrible grade because you're using self-signed test certificates, look at recommended TLS parameter changes). If my memory serves me correctly, rustls's defaults tended to yield a pretty good score.


[*] Unless you're acting as a CA and you intend to create certificates for your users under your CA, then you could distribute your root CA (chain). This is opening a mind-numbingly magnificent can of worms, so please do not have those plans.