#crypto #tls #ssl #libressl #openbsd

libtls

Rust bindings for LibreSSL’s libtls

4 releases (2 stable)

✓ Uses Rust 2018 edition

new 1.1.0 Dec 6, 2019
1.1.0-beta.6 Dec 4, 2019
1.1.0-alpha1 Nov 11, 2019
0.0.1 May 7, 2016

#98 in Cryptography

Download history 7/week @ 2019-08-23 2/week @ 2019-08-30 5/week @ 2019-09-06 5/week @ 2019-09-13 12/week @ 2019-09-20 1/week @ 2019-09-27 1/week @ 2019-10-04 2/week @ 2019-10-18 4/week @ 2019-10-25 128/week @ 2019-11-01 59/week @ 2019-11-08 41/week @ 2019-11-15 51/week @ 2019-11-22 139/week @ 2019-11-29

150 downloads per month
Used in 1 crate

ISC license

4MB
1.5K SLoC

Rust bindings for LibreSSL's libtls.

Crates.IO docs.rs Build Status License

Documentation, Changelog

The LibreSSL project provides a free TLS and crypto stack that was forked from OpenSSL in 2014. The goals are to provide a modernized codebase, improved security, and to apply best practice development processes.

LibreSSL provides C APIs that are compatible to OpenSSL's libssl and libcrypto libraries. It also provides libtls, a new TLS library that is designed to make it easier to write foolproof applications.

This workspace of Rust crates provides language bindings for libtls only, as the other LibreSSL APIs can be used with the existing rust-openssl crate. LibreSSL versions 2.9.0 through 3.0.2 (or later) are supported.

The following crates are included:

Minimum Rust version

Async I/O with tokio-libtls requires Rust 1.39 or later for async-await. This crate does not provide any backwards compatibility but you can use version 1.0.0 on older Rust versions.

Examples

use libtls::{config::{self, TlsConfig}, error};

fn tls_server_config() -> error::Result<TlsConfig> {
    let mut tls_config = TlsConfig::new()?;
    tls_config.set_keypair_file("tests/eccert.crt", "tests/eccert.key")?;
    tls_config.set_protocols(libtls_sys::TLS_PROTOCOL_TLSv1_2);
    Ok(tls_config)
}

fn main() {
    let tls_config = tls_server_config().unwrap();
}

The same configuration can be created using the TlsConfigBuilder builder pattern:

fn tls_server_config() -> error::Result<TlsConfig> {
    let tls_config = TlsConfigBuilder::new()
        .keypair_file("tests/eccert.crt", "tests/eccert.key", None)
        .protocols(libtls_sys::TLS_PROTOCOL_TLSv1_2)
        .build()?;
    Ok(tls_config)
}

A TLS connection:

use libtls::{config::TlsConfigBuilder, error};
use std::io::{Read, Write};

fn sync_https_connect(servername: &str) -> error::Result<()> {
    let addr = &(servername.to_owned() + ":443");

    let request = format!(
        "GET / HTTP/1.1\r\n\
         Host: {}\r\n\
         Connection: close\r\n\r\n",
        servername
    );

    let mut tls = TlsConfigBuilder::new().client()?;

    tls.connect(addr, None)?;
    tls.write(request.as_bytes())?;

    let mut buf = vec![0u8; 1024];
    tls.read(&mut buf)?;

    let ok = b"HTTP/1.1 200 OK\r\n";
    assert_eq!(&buf[..ok.len()], ok);

    Ok(())
}

fn main() {
    sync_https_connect("www.example.com").unwrap();
}

A non-blocking and asynchronous TLS connection using Tokio and the tokio-libtls crate:

use std::io;
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio_libtls::prelude::*;

async fn async_https_connect(servername: String) -> io::Result<()> {
    let request = format!(
        "GET / HTTP/1.1\r\n\
         Host: {}\r\n\
         Connection: close\r\n\r\n",
        servername
    );

    let config = TlsConfigBuilder::new().build()?;
    let mut tls = AsyncTls::connect(&(servername + ":443"), &config, None).await?;
    tls.write_all(request.as_bytes()).await?;

    let mut buf = vec![0u8; 1024];
    tls.read_exact(&mut buf).await?;

    let ok = b"HTTP/1.1 200 OK\r\n";
    assert_eq!(&buf[..ok.len()], ok);

    Ok(())
}

#[tokio::main]
async fn main() {
   async_https_connect("www.example.com".to_owned()).await.unwrap();
}

An asynchronous TLS server:

async fn echo_server(cert: &str, key: &str) -> io::Result<()> {
    let config = TlsConfigBuilder::new()
        .keypair_file(cert, key, None)
        .build()?;

    let addr: SocketAddr = "[::1]:7".parse().unwrap();
    let mut listener = TcpListener::bind(&addr).await?;

    loop {
        let (tcp, _) = listener.accept().await?;
        let mut tls = AsyncTls::accept_stream(tcp, &config, None).await?;

        tokio::spawn(async move {
            loop {
                let mut buf = vec![0u8; 1024];
                if !tls.read(&mut buf).await.is_ok() || !tls.write_all(&buf).await.is_ok() {
                    break;
                }
            }
        });
    }
}

Copyright and license

Licensed under an OpenBSD-ISC-style license, see LICENSE for details.

Dependencies