giong_tls/lib.rs
1//! # giong-tls
2//!
3//! Server-side TLS for the [giong] thread-per-core runtime, built on
4//! [rustls] (TLS 1.2 and 1.3, `ring` for cryptography).
5//!
6//! ```no_run
7//! use giong::net::TcpListener;
8//! use giong_tls::TlsAcceptor;
9//!
10//! # fn main() -> std::io::Result<()> {
11//! let cert = std::fs::read("cert.pem")?;
12//! let key = std::fs::read("key.pem")?;
13//! let acceptor = TlsAcceptor::from_pem(&cert, &key)?;
14//!
15//! giong::block_on(async move {
16//! let listener = TcpListener::bind("0.0.0.0:8443")?;
17//! loop {
18//! let tcp = listener.accept().await?;
19//! let acceptor = acceptor.clone();
20//! giong::spawn(async move {
21//! let Ok(tls) = acceptor.accept(tcp).await else { return };
22//! while let Ok(data) = tls.recv().await {
23//! if data.is_empty() {
24//! break; // closed by the peer
25//! }
26//! if tls.write_all(data).await.0.is_err() {
27//! break;
28//! }
29//! }
30//! let _ = tls.shutdown().await;
31//! });
32//! }
33//! })
34//! # }
35//! ```
36//!
37//! The API mirrors [`giong::net::TcpStream`]: [`TlsStream::recv`] returns the
38//! next piece of decrypted data and [`TlsStream::write_all`] takes a buffer by
39//! value and hands it back.
40
41#![warn(missing_docs)]
42
43use std::cell::{Cell, RefCell};
44use std::future::poll_fn;
45use std::io::{self, Read, Write};
46use std::mem;
47use std::net::Shutdown;
48use std::sync::Arc;
49use std::task::{Poll, Waker};
50use std::time::Duration;
51
52use giong::net::TcpStream;
53use giong::time::timeout;
54use rustls::pki_types::pem::PemObject;
55use rustls::pki_types::{CertificateDer, PrivateKeyDer};
56use rustls::{ServerConfig, ServerConnection};
57
58pub use rustls;
59
60fn invalid(e: impl std::fmt::Display) -> io::Error {
61 io::Error::new(io::ErrorKind::InvalidData, e.to_string())
62}
63
64/// Turns accepted TCP connections into TLS connections.
65///
66/// Cheap to clone; share one between all workers.
67#[derive(Clone)]
68pub struct TlsAcceptor {
69 config: Arc<ServerConfig>,
70 handshake_timeout: Duration,
71}
72
73impl TlsAcceptor {
74 /// An acceptor using an existing rustls configuration.
75 pub fn new(config: Arc<ServerConfig>) -> Self {
76 Self {
77 config,
78 handshake_timeout: Duration::from_secs(10),
79 }
80 }
81
82 /// An acceptor for one certificate chain and its private key, both in PEM
83 /// format. TLS 1.2 and 1.3 with rustls' default cipher suites, no client
84 /// authentication, and `http/1.1` offered through ALPN.
85 pub fn from_pem(cert_chain: &[u8], private_key: &[u8]) -> io::Result<Self> {
86 let certs = CertificateDer::pem_slice_iter(cert_chain)
87 .collect::<Result<Vec<_>, _>>()
88 .map_err(invalid)?;
89 if certs.is_empty() {
90 return Err(invalid("no certificate found in the PEM data"));
91 }
92 let key = PrivateKeyDer::from_pem_slice(private_key).map_err(invalid)?;
93 let provider = Arc::new(rustls::crypto::ring::default_provider());
94 let mut config = ServerConfig::builder_with_provider(provider)
95 .with_safe_default_protocol_versions()
96 .map_err(invalid)?
97 .with_no_client_auth()
98 .with_single_cert(certs, key)
99 .map_err(invalid)?;
100 config.alpn_protocols = vec![b"http/1.1".to_vec()];
101 Ok(Self::new(Arc::new(config)))
102 }
103
104 /// How long a client may take to complete the TLS handshake (default:
105 /// 10 s).
106 pub fn handshake_timeout(mut self, timeout: Duration) -> Self {
107 self.handshake_timeout = timeout;
108 self
109 }
110
111 /// Performs the TLS handshake on an accepted connection.
112 pub async fn accept(&self, tcp: TcpStream) -> io::Result<TlsStream> {
113 let conn = ServerConnection::new(self.config.clone()).map_err(invalid)?;
114 let stream = TlsStream {
115 tcp,
116 conn: RefCell::new(conn),
117 plain: RefCell::new(Vec::new()),
118 wire: RefCell::new(Vec::new()),
119 eof: Cell::new(false),
120 sending: Cell::new(false),
121 broken: Cell::new(false),
122 failed: Cell::new(None),
123 waiters: RefCell::new(Vec::new()),
124 };
125 let handshake = async {
126 while stream.conn.borrow().is_handshaking() {
127 stream.flush_tls().await?;
128 if !stream.conn.borrow().is_handshaking() {
129 break;
130 }
131 if stream.eof.get() {
132 return Err(io::ErrorKind::UnexpectedEof.into());
133 }
134 stream.pump().await?;
135 }
136 stream.flush_tls().await
137 };
138 match timeout(self.handshake_timeout, handshake).await {
139 Ok(Ok(())) => Ok(stream),
140 Ok(Err(e)) => Err(e),
141 Err(_) => Err(io::Error::new(
142 io::ErrorKind::TimedOut,
143 "TLS handshake timed out",
144 )),
145 }
146 }
147}
148
149impl std::fmt::Debug for TlsAcceptor {
150 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
151 f.debug_struct("TlsAcceptor")
152 .field("handshake_timeout", &self.handshake_timeout)
153 .finish_non_exhaustive()
154 }
155}
156
157/// A TLS connection over a [`TcpStream`].
158pub struct TlsStream {
159 tcp: TcpStream,
160 conn: RefCell<ServerConnection>,
161 /// Decrypted data not handed out yet.
162 plain: RefCell<Vec<u8>>,
163 /// Scratch buffer for outgoing TLS records, reused between writes.
164 wire: RefCell<Vec<u8>>,
165 /// The peer closed the connection (with or without `close_notify`).
166 eof: Cell<bool>,
167 /// A task is writing TLS records to the socket. Records must not
168 /// interleave, so other tasks wait for it in `waiters`.
169 sending: Cell<bool>,
170 /// A write to the socket failed or was cancelled half way: the record
171 /// stream is cut in the middle and nothing more can be sent.
172 broken: Cell<bool>,
173 /// A receive error held back until the data before it has been handed out.
174 failed: Cell<Option<io::Error>>,
175 /// Tasks waiting for `sending` to clear.
176 waiters: RefCell<Vec<Waker>>,
177}
178
179/// Held while TLS records are being written to the socket.
180struct Sending<'a> {
181 stream: &'a TlsStream,
182 complete: bool,
183}
184
185impl Drop for Sending<'_> {
186 fn drop(&mut self) {
187 if !self.complete {
188 self.stream.broken.set(true);
189 }
190 self.stream.sending.set(false);
191 let waiters = mem::take(&mut *self.stream.waiters.borrow_mut());
192 for waker in waiters {
193 waker.wake();
194 }
195 }
196}
197
198impl TlsStream {
199 /// Sends every TLS record rustls has queued.
200 async fn flush_tls(&self) -> io::Result<()> {
201 loop {
202 if !self.conn.borrow().wants_write() {
203 return Ok(());
204 }
205 if self.broken.get() {
206 return Err(io::Error::new(
207 io::ErrorKind::BrokenPipe,
208 "a TLS write failed or was cancelled; nothing more can be sent",
209 ));
210 }
211 if self.sending.get() {
212 // Another task is sending. Wait for it, then send what is
213 // left (it may already have sent this task's records too).
214 poll_fn(|cx| {
215 if !self.sending.get() {
216 return Poll::Ready(());
217 }
218 self.waiters.borrow_mut().push(cx.waker().clone());
219 Poll::Pending
220 })
221 .await;
222 continue;
223 }
224 let mut wire = mem::take(&mut *self.wire.borrow_mut());
225 {
226 let mut conn = self.conn.borrow_mut();
227 while conn.wants_write() {
228 conn.write_tls(&mut wire)?;
229 }
230 }
231 self.sending.set(true);
232 let mut sending = Sending {
233 stream: self,
234 complete: false,
235 };
236 let (res, mut wire) = self.tcp.write_all(wire).await;
237 res?;
238 sending.complete = true;
239 drop(sending);
240 wire.clear();
241 *self.wire.borrow_mut() = wire;
242 }
243 }
244
245 /// Receives one chunk of TLS data, decrypts it into `plain`, and sends
246 /// whatever the protocol wants to send in response.
247 async fn pump(&self) -> io::Result<()> {
248 // Cancelling here loses nothing: `recv` is cancel safe.
249 let chunk = self.tcp.recv().await?;
250 if chunk.is_empty() {
251 self.eof.set(true);
252 return Ok(());
253 }
254 let result = {
255 let mut conn = self.conn.borrow_mut();
256 let mut plain = self.plain.borrow_mut();
257 let mut input = &chunk[..];
258 let mut result = Ok(());
259 while !input.is_empty() {
260 // rustls buffers a bounded amount of plaintext, so it has to
261 // be drained as the records are fed in.
262 match conn.read_tls(&mut input) {
263 Ok(0) => {
264 result = Err(invalid("rustls accepted no more TLS data"));
265 break;
266 }
267 Ok(_) => {}
268 Err(e) => {
269 result = Err(e);
270 break;
271 }
272 }
273 match conn.process_new_packets() {
274 Ok(state) => {
275 let n = state.plaintext_bytes_to_read();
276 if n > 0 {
277 let at = plain.len();
278 plain.resize(at + n, 0);
279 if let Err(e) = conn.reader().read_exact(&mut plain[at..]) {
280 plain.truncate(at);
281 result = Err(e);
282 break;
283 }
284 }
285 if state.peer_has_closed() {
286 self.eof.set(true);
287 break;
288 }
289 }
290 Err(e) => {
291 result = Err(invalid(e));
292 break;
293 }
294 }
295 }
296 result
297 };
298 drop(chunk);
299 // Handshake messages, key updates, or the alert describing `result`.
300 // Not being able to send them is no reason to withhold what was
301 // received, if sending has failed before.
302 if self.broken.get() {
303 return result;
304 }
305 let flushed = self.flush_tls().await;
306 result.and(flushed)
307 }
308
309 /// Receives decrypted data. An empty buffer means that the peer has closed
310 /// the connection, with a `close_notify` alert or by closing the socket.
311 ///
312 /// Cancel safe: dropping the future loses no data. (If it is dropped at
313 /// the rare moment a TLS protocol message is being sent, sending fails
314 /// from then on instead of continuing on a broken stream.)
315 ///
316 /// One task may receive while another one sends.
317 pub async fn recv(&self) -> io::Result<Vec<u8>> {
318 loop {
319 {
320 let mut plain = self.plain.borrow_mut();
321 if !plain.is_empty() {
322 return Ok(mem::take(&mut *plain));
323 }
324 }
325 if let Some(e) = self.failed.take() {
326 return Err(e);
327 }
328 if self.eof.get() {
329 return Ok(Vec::new());
330 }
331 if let Err(e) = self.pump().await {
332 // Data that arrived intact before the failure comes first.
333 if self.plain.borrow().is_empty() {
334 return Err(e);
335 }
336 self.failed.set(Some(e));
337 }
338 }
339 }
340
341 /// Encrypts and sends all of `buf`, then hands the buffer back.
342 ///
343 /// Not cancel safe: if the future is dropped, part of `buf` may have been
344 /// sent, and if that happened in the middle of a TLS record the
345 /// connection cannot send any more: later writes return an error, while
346 /// data the peer already sent can still be received.
347 pub async fn write_all(&self, buf: Vec<u8>) -> (io::Result<()>, Vec<u8>) {
348 let mut sent = 0;
349 while sent < buf.len() {
350 // rustls accepts a bounded amount per call; send as it fills up.
351 let accepted = self.conn.borrow_mut().writer().write(&buf[sent..]);
352 match accepted {
353 Ok(n) => sent += n,
354 Err(e) => return (Err(e), buf),
355 }
356 if let Err(e) = self.flush_tls().await {
357 return (Err(e), buf);
358 }
359 }
360 (Ok(()), buf)
361 }
362
363 /// Sends the TLS `close_notify` alert and closes the sending direction.
364 pub async fn shutdown(&self) -> io::Result<()> {
365 self.conn.borrow_mut().send_close_notify();
366 self.flush_tls().await?;
367 self.tcp.shutdown(Shutdown::Write)
368 }
369
370 /// The protocol agreed on through ALPN, if any (for example `http/1.1`).
371 pub fn alpn_protocol(&self) -> Option<Vec<u8>> {
372 self.conn.borrow().alpn_protocol().map(<[u8]>::to_vec)
373 }
374
375 /// The underlying TCP connection.
376 pub fn tcp(&self) -> &TcpStream {
377 &self.tcp
378 }
379}
380
381impl std::fmt::Debug for TlsStream {
382 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
383 f.debug_struct("TlsStream")
384 .field("tcp", &self.tcp)
385 .finish_non_exhaustive()
386 }
387}