use native_ossl::bio::Bio;
use native_ossl::pkey::KeygenCtx;
use native_ossl::ssl::{SslCtx, SslIoError, SslVerifyMode, TlsVersion};
use native_ossl::x509::{X509Builder, X509NameOwned};
fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut kgen = KeygenCtx::new(c"ED25519")?;
let priv_key = kgen.generate()?;
let pub_key = native_ossl::pkey::Pkey::<native_ossl::pkey::Public>::from(priv_key.clone());
let mut name = X509NameOwned::new()?;
name.add_entry_by_txt(c"CN", b"localhost")?;
let cert = X509Builder::new()?
.set_version(2)?
.set_serial_number(1)?
.set_not_before_offset(0)?
.set_not_after_offset(86400)?
.set_subject_name(&name)?
.set_issuer_name(&name)?
.set_public_key(&pub_key)?
.sign(&priv_key, None)?
.build();
let server_ctx = SslCtx::new_server()?;
server_ctx.set_min_proto_version(TlsVersion::Tls13)?;
server_ctx.use_certificate(&cert)?;
server_ctx.use_private_key(&priv_key)?;
server_ctx.check_private_key()?;
let client_ctx = SslCtx::new_client()?;
client_ctx.set_min_proto_version(TlsVersion::Tls13)?;
client_ctx.set_verify(SslVerifyMode::NONE);
let mut client = client_ctx.new_ssl()?;
let mut server = server_ctx.new_ssl()?;
client.set_connect_state();
client.set_hostname(c"localhost")?;
server.set_accept_state();
let (client_bio, server_bio) = Bio::new_pair()?;
client.set_bio_duplex(client_bio);
server.set_bio_duplex(server_bio);
let mut client_done = false;
let mut server_done = false;
for step in 0..20 {
if !client_done {
match client.connect() {
Ok(()) => {
client_done = true;
println!("Client handshake done at step {step}");
}
Err(SslIoError::WantRead | SslIoError::WantWrite) => {}
Err(e) => return Err(format!("client error: {e}").into()),
}
}
if !server_done {
match server.accept() {
Ok(()) => {
server_done = true;
println!("Server handshake done at step {step}");
}
Err(SslIoError::WantRead | SslIoError::WantWrite) => {}
Err(e) => return Err(format!("server error: {e}").into()),
}
}
if client_done && server_done {
break;
}
}
assert!(client_done && server_done, "handshake did not complete");
if let Some(peer_cert) = client.peer_certificate() {
if let Some(subject) = peer_cert.subject_name().to_string() {
println!("Server cert subject: {subject}");
}
}
let request = b"GET / HTTP/1.0\r\n\r\n";
let response = b"HTTP/1.0 200 OK\r\n\r\nHello, TLS!";
let written = client.write(request)?;
assert_eq!(written, request.len());
let mut rbuf = [0u8; 64];
let n = server.read(&mut rbuf)?;
assert_eq!(&rbuf[..n], request);
println!("Server received: {:?}", std::str::from_utf8(&rbuf[..n])?);
let written = server.write(response)?;
assert_eq!(written, response.len());
let n = client.read(&mut rbuf)?;
assert_eq!(&rbuf[..n], response);
println!("Client received: {:?}", std::str::from_utf8(&rbuf[..n])?);
println!("In-process TLS 1.3 round-trip: OK");
Ok(())
}