pki 0.2.2

Public key infrastructure tools for Rust
Documentation
use std::{
    io::{Read, Write},
    net::{Shutdown, TcpListener, TcpStream},
    sync::Arc,
};

use rustls::{
    ClientConfig, ClientConnection, RootCertStore, ServerConfig, ServerConnection, Stream,
};
use rustls_pki_types::{CertificateDer, PrivateKeyDer, PrivatePkcs1KeyDer};

const HOSTNAME: &str = "localhost";
const PORT: u16 = 8000;

fn accept(
    server: TcpListener,
    config: Arc<ServerConfig>,
) -> Result<(), Box<dyn std::error::Error>> {
    for stream in server.incoming() {
        let mut stream = stream?;
        let mut connection = ServerConnection::new(config.clone())?;
        let mut tls_stream = Stream::new(&mut connection, &mut stream);
        let mut buf = vec![0u8; 4];
        tls_stream.read_exact(&mut buf)?;
        println!("{}", String::from_utf8_lossy(&buf));
        tls_stream.sock.shutdown(Shutdown::Read)?;
        tls_stream.write_all(b"pong")?;
    }
    Ok(())
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let key_store = pki::util::create_easy_server_chain(HOSTNAME)?;

    let server_config = ServerConfig::builder()
        .with_no_client_auth()
        .with_single_cert(
            key_store
                .certs()
                .iter()
                .map(|s| CertificateDer::from(s.to_der().unwrap()))
                .collect(),
            PrivateKeyDer::Pkcs1(PrivatePkcs1KeyDer::from(key_store.private_key().to_der()?)),
        )?;

    let server = TcpListener::bind(format!("{}:{}", HOSTNAME, PORT))?;

    std::thread::spawn(move || {
        let _ = accept(server, Arc::new(server_config));
    });

    let mut cert_store = RootCertStore::empty();
    cert_store.add(CertificateDer::from(
        key_store.certs().last().unwrap().to_der()?,
    ))?;

    let client_config = ClientConfig::builder()
        .with_root_certificates(cert_store)
        .with_no_client_auth();

    let mut connection = ClientConnection::new(Arc::new(client_config), HOSTNAME.try_into()?)?;
    let mut client = TcpStream::connect(format!("{}:{}", HOSTNAME, PORT))?;

    let mut tls_stream = Stream::new(&mut connection, &mut client);
    tls_stream.write_all(b"ping")?;
    tls_stream.sock.shutdown(Shutdown::Write)?;

    let mut reply = vec![0u8; 4];
    tls_stream.read_exact(&mut reply)?;
    println!("{}", String::from_utf8_lossy(&reply));

    Ok(())
}