dope-tls 0.1.0

TCP TLS streams for dope runtime, shin-backed
Documentation

use ring::rand::{SecureRandom, SystemRandom};

use dope_session::CodecLayer;
use dope_tls::{TlsCodec, TlsConnState, TlsState};
use shin::client::Config as ClientConfig;
use shin::server::Config as ServerConfig;
use shin::sig::SigningKey;

fn signing_key() -> SigningKey {
    let mut seed = [0u8; 32];
    SystemRandom::new().fill(&mut seed).unwrap();
    SigningKey::from_seed(&seed).unwrap()
}

#[test]
fn server_config_install_seeds_default_state() {
    let signing = signing_key();
    TlsCodec::install_server_config(ServerConfig { source: shin::server::CertSource::RawPublicKey { signing_key: signing }, transport_params: Vec::new(), alpn_protocols: Vec::new(), ticket_secret: None, accept_early_data: false });
    let state = TlsConnState::default();
    assert!(state.tls.is_some(), "session present after install");
    assert!(!state.bufs.close);
}

#[test]
fn missing_install_marks_state_dead_on_arrival() {
    install_clear();
    let state = TlsConnState::default();
    assert!(state.tls.is_none());
    assert!(state.bufs.close);
}

fn install_clear() {
}

#[test]
fn handshake_drives_through_codec_to_active() {
    let signing = signing_key();
    let server_pubkey = *signing.pubkey();
    TlsCodec::install_server_config(ServerConfig { source: shin::server::CertSource::RawPublicKey { signing_key: signing }, transport_params: Vec::new(), alpn_protocols: Vec::new(), ticket_secret: None, accept_early_data: false });
    let mut server = TlsConnState::default();
    let mut client = TlsState::new_client(ClientConfig { verifier: shin::client::Verifier::RawPublicKey { expected_pubkey: server_pubkey }, transport_params: Vec::new(), alpn_protocols: Vec::new(), resumption: None, enable_early_data: false })
    .unwrap();

    for _ in 0..6 {
        let from_client = client.pull_send();
        if !from_client.is_empty() {
            TlsCodec::process_inbound(&mut server, &from_client);
        }
        let server_wire: Vec<u8> = TlsCodec::wire_slice(&server).to_vec();
        if !server_wire.is_empty() {
            let _ = TlsCodec::take_inflight(&mut server);
            assert!(TlsCodec::has_inflight(&server));
            let n = server_wire.len();
            let _ = TlsCodec::consume_inflight(&mut server, n);
            client.read_tcp(&server_wire).expect("client read");
        }
    }

    assert!(client.is_established());
    assert!(TlsCodec::is_active(&server));
}

#[test]
fn application_data_routes_through_codec() {
    let signing = signing_key();
    let server_pubkey = *signing.pubkey();
    TlsCodec::install_server_config(ServerConfig { source: shin::server::CertSource::RawPublicKey { signing_key: signing }, transport_params: Vec::new(), alpn_protocols: Vec::new(), ticket_secret: None, accept_early_data: false });
    let mut server = TlsConnState::default();
    let mut client = TlsState::new_client(ClientConfig { verifier: shin::client::Verifier::RawPublicKey { expected_pubkey: server_pubkey }, transport_params: Vec::new(), alpn_protocols: Vec::new(), resumption: None, enable_early_data: false })
    .unwrap();

    for _ in 0..6 {
        let from_client = client.pull_send();
        if !from_client.is_empty() {
            TlsCodec::process_inbound(&mut server, &from_client);
        }
        let server_wire: Vec<u8> = TlsCodec::wire_slice(&server).to_vec();
        if !server_wire.is_empty() {
            let _ = TlsCodec::take_inflight(&mut server);
            let n = server_wire.len();
            let _ = TlsCodec::consume_inflight(&mut server, n);
            client.read_tcp(&server_wire).unwrap();
        }
    }
    assert!(TlsCodec::is_active(&server));

    client.write_app(b"hello server").unwrap();
    let from_client = client.pull_send();
    TlsCodec::process_inbound(&mut server, &from_client);
    let plain = TlsCodec::take_plaintext(&mut server);
    assert_eq!(&plain, b"hello server");
    TlsCodec::install_plaintext(&mut server, plain);

    TlsCodec::process_outbound(&mut server, b"hi back");
    let to_client: Vec<u8> = TlsCodec::wire_slice(&server).to_vec();
    let _ = TlsCodec::take_inflight(&mut server);
    let _ = TlsCodec::consume_inflight(&mut server, to_client.len());
    client.read_tcp(&to_client).unwrap();
    let recv = client.pull_app().expect("client got reply");
    assert_eq!(&recv, b"hi back");
}

#[test]
fn partial_inflight_consume_keeps_remainder() {
    let signing = signing_key();
    TlsCodec::install_server_config(ServerConfig { source: shin::server::CertSource::RawPublicKey { signing_key: signing }, transport_params: Vec::new(), alpn_protocols: Vec::new(), ticket_secret: None, accept_early_data: false });
    let mut server = TlsConnState::default();
    server.bufs.wire.extend_from_slice(b"hello");
    let _ = TlsCodec::take_inflight(&mut server);
    assert!(TlsCodec::has_inflight(&server));
    let still_more = TlsCodec::consume_inflight(&mut server, 2);
    assert!(still_more);
    assert_eq!(TlsCodec::wire_slice(&server), b"llo");
    assert!(!TlsCodec::has_inflight(&server));
}