Skip to main content

ssl/
ssl.rs

1//! TLS example — in-process TLS 1.3 handshake using paired memory BIOs.
2//!
3//! Creates a self-signed Ed25519 certificate, configures client and server
4//! `SslCtx` objects, and drives a full TLS 1.3 handshake in a single thread
5//! using `BIO_new_bio_pair` (via `Bio::new_pair`).
6//!
7//! Run with: cargo run --example ssl -p native-ossl
8
9use native_ossl::bio::Bio;
10use native_ossl::pkey::KeygenCtx;
11use native_ossl::ssl::{SslCtx, SslIoError, SslVerifyMode, TlsVersion};
12use native_ossl::x509::{X509Builder, X509NameOwned};
13
14fn main() -> Result<(), Box<dyn std::error::Error>> {
15    // ── Key pair and self-signed certificate ───────────────────────────────────
16
17    let mut kgen = KeygenCtx::new(c"ED25519")?;
18    let priv_key = kgen.generate()?;
19    let pub_key = native_ossl::pkey::Pkey::<native_ossl::pkey::Public>::from(priv_key.clone());
20
21    let mut name = X509NameOwned::new()?;
22    name.add_entry_by_txt(c"CN", b"localhost")?;
23
24    let cert = X509Builder::new()?
25        .set_version(2)?
26        .set_serial_number(1)?
27        .set_not_before_offset(0)?
28        .set_not_after_offset(86400)?
29        .set_subject_name(&name)?
30        .set_issuer_name(&name)?
31        .set_public_key(&pub_key)?
32        .sign(&priv_key, None)?
33        .build();
34
35    // ── Server context ─────────────────────────────────────────────────────────
36
37    let server_ctx = SslCtx::new_server()?;
38    server_ctx.set_min_proto_version(TlsVersion::Tls13)?;
39    server_ctx.use_certificate(&cert)?;
40    server_ctx.use_private_key(&priv_key)?;
41    server_ctx.check_private_key()?;
42
43    // ── Client context ─────────────────────────────────────────────────────────
44
45    let client_ctx = SslCtx::new_client()?;
46    client_ctx.set_min_proto_version(TlsVersion::Tls13)?;
47    // Skip certificate verification for this self-signed example.
48    client_ctx.set_verify(SslVerifyMode::NONE);
49
50    // ── SSL objects ────────────────────────────────────────────────────────────
51
52    let mut client = client_ctx.new_ssl()?;
53    let mut server = server_ctx.new_ssl()?;
54
55    client.set_connect_state();
56    client.set_hostname(c"localhost")?;
57    server.set_accept_state();
58
59    // ── In-process BIO pair ────────────────────────────────────────────────────
60    // Data written to client_bio is readable from server_bio and vice-versa.
61
62    let (client_bio, server_bio) = Bio::new_pair()?;
63    client.set_bio_duplex(client_bio);
64    server.set_bio_duplex(server_bio);
65
66    // ── Drive the handshake ────────────────────────────────────────────────────
67    // Alternate between client and server until both report success.
68
69    let mut client_done = false;
70    let mut server_done = false;
71
72    for step in 0..20 {
73        if !client_done {
74            match client.connect() {
75                Ok(()) => {
76                    client_done = true;
77                    println!("Client handshake done at step {step}");
78                }
79                Err(SslIoError::WantRead | SslIoError::WantWrite) => {}
80                Err(e) => return Err(format!("client error: {e}").into()),
81            }
82        }
83        if !server_done {
84            match server.accept() {
85                Ok(()) => {
86                    server_done = true;
87                    println!("Server handshake done at step {step}");
88                }
89                Err(SslIoError::WantRead | SslIoError::WantWrite) => {}
90                Err(e) => return Err(format!("server error: {e}").into()),
91            }
92        }
93        if client_done && server_done {
94            break;
95        }
96    }
97    assert!(client_done && server_done, "handshake did not complete");
98
99    // ── Inspect the peer certificate on the client ─────────────────────────────
100
101    if let Some(peer_cert) = client.peer_certificate() {
102        if let Some(subject) = peer_cert.subject_name().to_string() {
103            println!("Server cert subject: {subject}");
104        }
105    }
106
107    // ── Application data exchange ──────────────────────────────────────────────
108
109    let request = b"GET / HTTP/1.0\r\n\r\n";
110    let response = b"HTTP/1.0 200 OK\r\n\r\nHello, TLS!";
111
112    let written = client.write(request)?;
113    assert_eq!(written, request.len());
114
115    let mut rbuf = [0u8; 64];
116    let n = server.read(&mut rbuf)?;
117    assert_eq!(&rbuf[..n], request);
118    println!("Server received: {:?}", std::str::from_utf8(&rbuf[..n])?);
119
120    let written = server.write(response)?;
121    assert_eq!(written, response.len());
122
123    let n = client.read(&mut rbuf)?;
124    assert_eq!(&rbuf[..n], response);
125    println!("Client received: {:?}", std::str::from_utf8(&rbuf[..n])?);
126
127    println!("In-process TLS 1.3 round-trip: OK");
128
129    Ok(())
130}