Safe I/O-free implementation of the opportunistic TLS extension, based on stream-flows and inspired by @duesee's blog post.
This Rust library allows you to upgrade any plain stream to an encrypted one. Actually only IMAP is supported, but other protocols will be supported in the future. PRs are welcomed!
This library does not perform any I/O. Instead, it exposes I/O-free, composable and iterable state machines so called flows.
A flow emits I/O requests, which should be processed by I/O handlers. A flow is considered terminated when it does not emit I/O requests anymore.
STARTTLS flows emit stream I/O requests defined by the stream-flows crate, so any I/O stream handler should work.
use std::{net::TcpStream, sync::Arc};
use rustls::{ClientConfig, ClientConnection, StreamOwned};
use rustls_platform_verifier::ConfigVerifierExt;
use starttls_flows::imap::UpgradeTls;
use stream_lib::handlers::std::Handler;
// first connect to IMAP stream using plain TCP
let mut tcp = TcpStream::connect(("posteo.de", 143)).unwrap();
// create a new STARTTLS flow
let mut starttls = UpgradeTls::new().with_discard_greeting(true);
while let Err(io) = starttls.next() {
// handle I/O requests synchronously
Handler::handle(&mut tcp, &mut starttls, io).unwrap();
}
// now the TCP stream is ready to be upgraded to TLS using rustls
let config = ClientConfig::with_platform_verifier();
let server_name = "posteo.de".to_string().try_into().unwrap();
let conn = ClientConnection::new(Arc::new(config), server_name).unwrap();
let mut tls = StreamOwned::new(conn, tcp);
See complete example at ./examples/imap.rs.
cargo run --example imap
Special thanks to the NLnet foundation and the European Commission that helped the project to receive financial support from various programs:
- NGI Assure in 2022
- NGI Zero Entrust in 2023
- NGI Zero Core in 2024 (still ongoing)
If you appreciate the project, feel free to donate using one of the following providers: