All articles
Secure Socket Layer (SSL/TLS) with Rust: A Primer
Concurrency & Async

Secure Socket Layer (SSL/TLS) with Rust: A Primer

In this article, we will briefly introduce SSL/TLS and then delve into a working example of setting up a TLS server and client using Rust.

By Luis SoaresSeptember 18, 2023Original on Medium

In this article, we will briefly introduce SSL/TLS and then delve into a working example of setting up a TLS server and client using Rust.

A Brief Introduction to SSL/TLS

SSL and TLS provide encrypted communication and secure identification of networked devices. They are used in various applications, from web browsing to email to instant messaging. The basic premise is straightforward:

  1. A device (like a web server) has a public and private key.
  2. The public key is shared and can encrypt data that only the private key can decrypt.
  3. Devices establish a connection using a “handshake” where they agree on encryption settings.
  4. Data exchanged over this connection is encrypted.

Introduction to rustls

rustls is a TLS library that aims to provide a modern and safer alternative to existing C libraries like OpenSSL. It’s written entirely in Rust, a language that guarantees memory safety, preventing bugs that have historically been a significant source of vulnerabilities in networked applications.

Key Features of rustls

  1. Pure Rust: rustls doesn’t wrap or rely on C libraries, reducing the risk associated with unsafe C code.
  2. Forward Secrecy: By default, rustls supports only cypher suites with forward secrecy.
  3. No Legacy Protocols: rustls does not implement SSLv3 or earlier, which are fraught with vulnerabilities.
  4. Extensible: Being a Rust crate, extending and integrating it into other Rust projects is easy.
  5. Performance: Rust’s efficiency means that rustls doesn’t compromise on performance while offering safety.

Key Components of rustls

1. Server and Client Sessions

At the heart of rustls lies the notion of sessions, which are used to manage the state of a TLS connection:

  • ClientSession: Represents the client side of a TLS connection. It provides methods to handle key exchanges, authentication, and data encryption/decryption.
  • ServerSession: Represents the server side of a TLS connection, complementing ClientSession. It aids in managing server-specific details of the connection.

2. Configuration Objects

These objects control how sessions operate:

  • ClientConfig and ServerConfig: They define the cypher suites, key loggers, session persistence mechanisms, verification methods, and other configurations for the respective sessions.

3. Certificates and Keys

rustls has first-class support for managing certificates and private keys:

  • Certificate: Represents a parsed X.509v3 certificate.
  • PrivateKey: Represents a parsed private key, typically in PKCS#8 format.

4. Cipher Suites

Practice what you learned

Reinforce this article with hands-on coding exercises and AI-powered feedback.

View all exercises

Cipher suites define the combination of key exchange algorithms, bulk encryption algorithms, and message authentication codes:

  • SupportedCipherSuite: Represents a specific set of algorithms supported by rustls.

5. ALPN Protocol Negotiation

Application Layer Protocol Negotiation (ALPN) allows the application layer to negotiate which protocol should be performed over a secure connection:

  • ProtocolName: A representation of a protocol’s name that can be used in ALPN.

6. Error Handling

rustls offers a comprehensive set of error representations, making it easier to handle and respond to errors during various stages of the TLS handshake or session:

  • TLSError: Enumerates all the potential errors that can occur during TLS operations.

7. Utilities and Helpers

Apart from the core components, rustls offers a plethora of utility functions and helpers, such as:

  • pemfile: Functions to parse PEM-encoded files containing certificates and private keys.
  • read_buffer: A utility for buffered reading is used internally for various operations.

Setting up a TLS Server in Rust

To create a TLS server, you’ll first need some certificate files. For simplicity, we will use self-signed certificates in this example.

use rustls::{NoClientAuth, ServerConfig};
use tokio::net::TcpListener;
use tokio_rustls::TlsAcceptor;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Load server certificates
    let certs = rustls::internal::pemfile::certs(&mut std::io::Cursor::new(include_str!("cert.pem"))).unwrap();
    let mut keys = rustls::internal::pemfile::rsa_private_keys(&mut std::io::Cursor::new(include_str!("key.pem"))).unwrap();
    // Create server configuration
    let mut config = ServerConfig::new(NoClientAuth::new());
    config.set_single_cert(certs, keys.remove(0))?;
    // Create TCP listener and TLS acceptor
    let acceptor = TlsAcceptor::from(Arc::new(config));
    let listener = TcpListener::bind("127.0.0.1:8080").await?;

    loop {
        let (stream, _) = listener.accept().await?;
        tokio::spawn(handle_client(stream, acceptor.clone()));
    }
}
async fn handle_client(stream: TcpStream, acceptor: TlsAcceptor) -> Result<(), Box<dyn std::error::Error>> {
    let stream = acceptor.accept(stream).await?;
    // Handle the stream (read/write)
}

Setting up a TLS Client in Rust

Similarly, for the client:

use rustls::ClientConfig;
use tokio_rustls::rustls::ClientSession;
use tokio_rustls::TlsConnector;
use tokio::net::TcpStream;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let mut config = ClientConfig::new();
    let certs = rustls::internal::pemfile::certs(&mut std::io::Cursor::new(include_str!("cert.pem"))).unwrap();
    config.root_store.add(&certs[0]).unwrap();
    let connector = TlsConnector::from(Arc::new(config));
    let domain = webpki::DNSNameRef::try_from_ascii_str("localhost").unwrap();
    let stream = TcpStream::connect("127.0.0.1:8080").await?;
    let stream = connector.connect(domain, stream).await?;
    // Handle the stream (read/write)
}

Practice what you learned

Reinforce this article with hands-on coding exercises and AI-powered feedback.

View all exercises

Want to practice Rust hands-on?

Go beyond reading — solve interactive exercises with AI-powered code review on Rust Lab.