Skip to main content

tls_loopback/
tls_loopback.rs

1//! A complete TLS 1.3 handshake between a `purecrypto` client and server, run
2//! entirely in process (no sockets), then an application-data exchange.
3//!
4//! Run with: `cargo run --example tls_loopback`
5
6use purecrypto::rsa::{BoxedRsaPrivateKey, RsaPrivateKey};
7use purecrypto::tls::{Config, Connection, RootCertStore, SigningKey};
8use purecrypto::x509::{Certificate, DistinguishedName, Time, Validity};
9
10// A fixed RSA-2048 key, so the example needs no (slow) key generation.
11const SERVER_KEY_PEM: &str = include_str!("../testdata/rsa2048_test_a.pem");
12
13fn main() {
14    // --- Server setup: a self-signed certificate for "example.test". ---
15    let signing_key = RsaPrivateKey::<32>::from_pkcs1_pem(SERVER_KEY_PEM).unwrap();
16    let name = DistinguishedName::common_name("example.test");
17    let validity = Validity::new(
18        Time::utc(2024, 1, 1, 0, 0, 0),
19        Time::utc(2034, 1, 1, 0, 0, 0),
20    );
21    let cert = Certificate::self_signed(&signing_key, &name, &validity, 1, false).unwrap();
22    let cert_der = cert.to_der().to_vec();
23
24    let server_key = BoxedRsaPrivateKey::from_pkcs1_pem(SERVER_KEY_PEM).unwrap();
25    let server_cfg = Config::builder()
26        .tls_only()
27        .identity(vec![cert_der.clone()], SigningKey::Rsa(server_key))
28        .build();
29    let mut server = Connection::server(&server_cfg).expect("server config");
30
31    // --- Client setup: trust the server's certificate. ---
32    let mut roots = RootCertStore::new();
33    roots.add_der(cert_der).unwrap();
34    let client_cfg = Config::builder()
35        .tls_only()
36        .roots(roots)
37        .server_name("example.test")
38        .build();
39    let mut client = Connection::client(&client_cfg).expect("client config");
40
41    // --- Drive the handshake by shuttling records between the two ends. ---
42    for _ in 0..16 {
43        let to_server = client.pop().unwrap_or_default();
44        if !to_server.is_empty() {
45            server.feed(&to_server).unwrap();
46        }
47        let to_client = server.pop().unwrap_or_default();
48        if !to_client.is_empty() {
49            client.feed(&to_client).unwrap();
50        }
51        if to_server.is_empty() && to_client.is_empty() {
52            break;
53        }
54    }
55    assert!(client.is_handshake_complete() && server.is_handshake_complete());
56    println!("handshake complete");
57
58    // --- Application data: client -> server -> client. ---
59    client.send(b"GET / HTTP/1.0").unwrap();
60    let req = client.pop().unwrap_or_default();
61    server.feed(&req).unwrap();
62    println!(
63        "server received: {:?}",
64        String::from_utf8_lossy(&server.recv().unwrap_or_default())
65    );
66
67    server.send(b"HTTP/1.0 200 OK").unwrap();
68    let resp = server.pop().unwrap_or_default();
69    client.feed(&resp).unwrap();
70    println!(
71        "client received: {:?}",
72        String::from_utf8_lossy(&client.recv().unwrap_or_default())
73    );
74}