1 | use crate::common_state::{CommonState, Context, IoState, State}; |
---|---|
2 | use crate::enums::{AlertDescription, ContentType}; |
3 | use crate::error::{Error, PeerMisbehaved}; |
4 | #[cfg(feature = "logging")] |
5 | use crate::log::trace; |
6 | use crate::msgs::deframer::{Deframed, DeframerSliceBuffer, DeframerVecBuffer, MessageDeframer}; |
7 | use crate::msgs::handshake::Random; |
8 | use crate::msgs::message::{Message, MessagePayload, PlainMessage}; |
9 | use crate::suites::{ExtractedSecrets, PartiallyExtractedSecrets}; |
10 | use crate::vecbuf::ChunkVecBuffer; |
11 | |
12 | use alloc::boxed::Box; |
13 | use core::fmt::Debug; |
14 | use core::mem; |
15 | use core::ops::{Deref, DerefMut}; |
16 | use std::io; |
17 | |
18 | /// A client or server connection. |
19 | #[derive(Debug)] |
20 | pub enum Connection { |
21 | /// A client connection |
22 | Client(crate::client::ClientConnection), |
23 | /// A server connection |
24 | Server(crate::server::ServerConnection), |
25 | } |
26 | |
27 | impl Connection { |
28 | /// Read TLS content from `rd`. |
29 | /// |
30 | /// See [`ConnectionCommon::read_tls()`] for more information. |
31 | pub fn read_tls(&mut self, rd: &mut dyn io::Read) -> Result<usize, io::Error> { |
32 | match self { |
33 | Self::Client(conn) => conn.read_tls(rd), |
34 | Self::Server(conn) => conn.read_tls(rd), |
35 | } |
36 | } |
37 | |
38 | /// Writes TLS messages to `wr`. |
39 | /// |
40 | /// See [`ConnectionCommon::write_tls()`] for more information. |
41 | pub fn write_tls(&mut self, wr: &mut dyn io::Write) -> Result<usize, io::Error> { |
42 | self.sendable_tls.write_to(wr) |
43 | } |
44 | |
45 | /// Returns an object that allows reading plaintext. |
46 | pub fn reader(&mut self) -> Reader { |
47 | match self { |
48 | Self::Client(conn) => conn.reader(), |
49 | Self::Server(conn) => conn.reader(), |
50 | } |
51 | } |
52 | |
53 | /// Returns an object that allows writing plaintext. |
54 | pub fn writer(&mut self) -> Writer { |
55 | match self { |
56 | Self::Client(conn) => Writer::new(&mut **conn), |
57 | Self::Server(conn) => Writer::new(&mut **conn), |
58 | } |
59 | } |
60 | |
61 | /// Processes any new packets read by a previous call to [`Connection::read_tls`]. |
62 | /// |
63 | /// See [`ConnectionCommon::process_new_packets()`] for more information. |
64 | pub fn process_new_packets(&mut self) -> Result<IoState, Error> { |
65 | match self { |
66 | Self::Client(conn) => conn.process_new_packets(), |
67 | Self::Server(conn) => conn.process_new_packets(), |
68 | } |
69 | } |
70 | |
71 | /// Derives key material from the agreed connection secrets. |
72 | /// |
73 | /// See [`ConnectionCommon::export_keying_material()`] for more information. |
74 | pub fn export_keying_material<T: AsMut<[u8]>>( |
75 | &self, |
76 | output: T, |
77 | label: &[u8], |
78 | context: Option<&[u8]>, |
79 | ) -> Result<T, Error> { |
80 | match self { |
81 | Self::Client(conn) => conn.export_keying_material(output, label, context), |
82 | Self::Server(conn) => conn.export_keying_material(output, label, context), |
83 | } |
84 | } |
85 | |
86 | /// This function uses `io` to complete any outstanding IO for this connection. |
87 | /// |
88 | /// See [`ConnectionCommon::complete_io()`] for more information. |
89 | pub fn complete_io<T>(&mut self, io: &mut T) -> Result<(usize, usize), io::Error> |
90 | where |
91 | Self: Sized, |
92 | T: io::Read + io::Write, |
93 | { |
94 | match self { |
95 | Self::Client(conn) => conn.complete_io(io), |
96 | Self::Server(conn) => conn.complete_io(io), |
97 | } |
98 | } |
99 | |
100 | /// Extract secrets, so they can be used when configuring kTLS, for example. |
101 | /// Should be used with care as it exposes secret key material. |
102 | pub fn dangerous_extract_secrets(self) -> Result<ExtractedSecrets, Error> { |
103 | match self { |
104 | Self::Client(client) => client.dangerous_extract_secrets(), |
105 | Self::Server(server) => server.dangerous_extract_secrets(), |
106 | } |
107 | } |
108 | } |
109 | |
110 | impl Deref for Connection { |
111 | type Target = CommonState; |
112 | |
113 | fn deref(&self) -> &Self::Target { |
114 | match self { |
115 | Self::Client(conn: &ClientConnection) => &conn.core.common_state, |
116 | Self::Server(conn: &ServerConnection) => &conn.core.common_state, |
117 | } |
118 | } |
119 | } |
120 | |
121 | impl DerefMut for Connection { |
122 | fn deref_mut(&mut self) -> &mut Self::Target { |
123 | match self { |
124 | Self::Client(conn: &mut ClientConnection) => &mut conn.core.common_state, |
125 | Self::Server(conn: &mut ServerConnection) => &mut conn.core.common_state, |
126 | } |
127 | } |
128 | } |
129 | |
130 | /// A structure that implements [`std::io::Read`] for reading plaintext. |
131 | pub struct Reader<'a> { |
132 | received_plaintext: &'a mut ChunkVecBuffer, |
133 | peer_cleanly_closed: bool, |
134 | has_seen_eof: bool, |
135 | } |
136 | |
137 | impl<'a> io::Read for Reader<'a> { |
138 | /// Obtain plaintext data received from the peer over this TLS connection. |
139 | /// |
140 | /// If the peer closes the TLS session cleanly, this returns `Ok(0)` once all |
141 | /// the pending data has been read. No further data can be received on that |
142 | /// connection, so the underlying TCP connection should be half-closed too. |
143 | /// |
144 | /// If the peer closes the TLS session uncleanly (a TCP EOF without sending a |
145 | /// `close_notify` alert) this function returns a `std::io::Error` of type |
146 | /// `ErrorKind::UnexpectedEof` once any pending data has been read. |
147 | /// |
148 | /// Note that support for `close_notify` varies in peer TLS libraries: many do not |
149 | /// support it and uncleanly close the TCP connection (this might be |
150 | /// vulnerable to truncation attacks depending on the application protocol). |
151 | /// This means applications using rustls must both handle EOF |
152 | /// from this function, *and* unexpected EOF of the underlying TCP connection. |
153 | /// |
154 | /// If there are no bytes to read, this returns `Err(ErrorKind::WouldBlock.into())`. |
155 | /// |
156 | /// You may learn the number of bytes available at any time by inspecting |
157 | /// the return of [`Connection::process_new_packets`]. |
158 | fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { |
159 | let len = self.received_plaintext.read(buf)?; |
160 | |
161 | if len == 0 && !buf.is_empty() { |
162 | // No bytes available: |
163 | match (self.peer_cleanly_closed, self.has_seen_eof) { |
164 | // cleanly closed; don't care about TCP EOF: express this as Ok(0) |
165 | (true, _) => {} |
166 | // unclean closure |
167 | (false, true) => { |
168 | return Err(io::Error::new( |
169 | io::ErrorKind::UnexpectedEof, |
170 | UNEXPECTED_EOF_MESSAGE, |
171 | )) |
172 | } |
173 | // connection still going, but needs more data: signal `WouldBlock` so that |
174 | // the caller knows this |
175 | (false, false) => return Err(io::ErrorKind::WouldBlock.into()), |
176 | } |
177 | } |
178 | |
179 | Ok(len) |
180 | } |
181 | |
182 | /// Obtain plaintext data received from the peer over this TLS connection. |
183 | /// |
184 | /// If the peer closes the TLS session, this returns `Ok(())` without filling |
185 | /// any more of the buffer once all the pending data has been read. No further |
186 | /// data can be received on that connection, so the underlying TCP connection |
187 | /// should be half-closed too. |
188 | /// |
189 | /// If the peer closes the TLS session uncleanly (a TCP EOF without sending a |
190 | /// `close_notify` alert) this function returns a `std::io::Error` of type |
191 | /// `ErrorKind::UnexpectedEof` once any pending data has been read. |
192 | /// |
193 | /// Note that support for `close_notify` varies in peer TLS libraries: many do not |
194 | /// support it and uncleanly close the TCP connection (this might be |
195 | /// vulnerable to truncation attacks depending on the application protocol). |
196 | /// This means applications using rustls must both handle EOF |
197 | /// from this function, *and* unexpected EOF of the underlying TCP connection. |
198 | /// |
199 | /// If there are no bytes to read, this returns `Err(ErrorKind::WouldBlock.into())`. |
200 | /// |
201 | /// You may learn the number of bytes available at any time by inspecting |
202 | /// the return of [`Connection::process_new_packets`]. |
203 | #[cfg(read_buf)] |
204 | fn read_buf(&mut self, mut cursor: core::io::BorrowedCursor<'_>) -> io::Result<()> { |
205 | let before = cursor.written(); |
206 | self.received_plaintext |
207 | .read_buf(cursor.reborrow())?; |
208 | let len = cursor.written() - before; |
209 | |
210 | if len == 0 && cursor.capacity() > 0 { |
211 | // No bytes available: |
212 | match (self.peer_cleanly_closed, self.has_seen_eof) { |
213 | // cleanly closed; don't care about TCP EOF: express this as Ok(0) |
214 | (true, _) => {} |
215 | // unclean closure |
216 | (false, true) => { |
217 | return Err(io::Error::new( |
218 | io::ErrorKind::UnexpectedEof, |
219 | UNEXPECTED_EOF_MESSAGE, |
220 | )); |
221 | } |
222 | // connection still going, but need more data: signal `WouldBlock` so that |
223 | // the caller knows this |
224 | (false, false) => return Err(io::ErrorKind::WouldBlock.into()), |
225 | } |
226 | } |
227 | |
228 | Ok(()) |
229 | } |
230 | } |
231 | |
232 | /// Internal trait implemented by the [`ServerConnection`]/[`ClientConnection`] |
233 | /// allowing them to be the subject of a [`Writer`]. |
234 | /// |
235 | /// [`ServerConnection`]: crate::ServerConnection |
236 | /// [`ClientConnection`]: crate::ClientConnection |
237 | pub(crate) trait PlaintextSink { |
238 | fn write(&mut self, buf: &[u8]) -> io::Result<usize>; |
239 | fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize>; |
240 | fn flush(&mut self) -> io::Result<()>; |
241 | } |
242 | |
243 | impl<T> PlaintextSink for ConnectionCommon<T> { |
244 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> { |
245 | Ok(self.send_some_plaintext(data:buf)) |
246 | } |
247 | |
248 | fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> { |
249 | let mut sz: usize = 0; |
250 | for buf: &IoSlice<'_> in bufs { |
251 | sz += self.send_some_plaintext(data:buf); |
252 | } |
253 | Ok(sz) |
254 | } |
255 | |
256 | fn flush(&mut self) -> io::Result<()> { |
257 | Ok(()) |
258 | } |
259 | } |
260 | |
261 | /// A structure that implements [`std::io::Write`] for writing plaintext. |
262 | pub struct Writer<'a> { |
263 | sink: &'a mut dyn PlaintextSink, |
264 | } |
265 | |
266 | impl<'a> Writer<'a> { |
267 | /// Create a new Writer. |
268 | /// |
269 | /// This is not an external interface. Get one of these objects |
270 | /// from [`Connection::writer`]. |
271 | pub(crate) fn new(sink: &'a mut dyn PlaintextSink) -> Writer<'a> { |
272 | Writer { sink } |
273 | } |
274 | } |
275 | |
276 | impl<'a> io::Write for Writer<'a> { |
277 | /// Send the plaintext `buf` to the peer, encrypting |
278 | /// and authenticating it. Once this function succeeds |
279 | /// you should call [`Connection::write_tls`] which will output the |
280 | /// corresponding TLS records. |
281 | /// |
282 | /// This function buffers plaintext sent before the |
283 | /// TLS handshake completes, and sends it as soon |
284 | /// as it can. See [`CommonState::set_buffer_limit`] to control |
285 | /// the size of this buffer. |
286 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> { |
287 | self.sink.write(buf) |
288 | } |
289 | |
290 | fn write_vectored(&mut self, bufs: &[io::IoSlice<'_>]) -> io::Result<usize> { |
291 | self.sink.write_vectored(bufs) |
292 | } |
293 | |
294 | fn flush(&mut self) -> io::Result<()> { |
295 | self.sink.flush() |
296 | } |
297 | } |
298 | |
299 | #[derive(Debug)] |
300 | pub(crate) struct ConnectionRandoms { |
301 | pub(crate) client: [u8; 32], |
302 | pub(crate) server: [u8; 32], |
303 | } |
304 | |
305 | /// How many ChangeCipherSpec messages we accept and drop in TLS1.3 handshakes. |
306 | /// The spec says 1, but implementations (namely the boringssl test suite) get |
307 | /// this wrong. BoringSSL itself accepts up to 32. |
308 | static TLS13_MAX_DROPPED_CCS: u8 = 2u8; |
309 | |
310 | impl ConnectionRandoms { |
311 | pub(crate) fn new(client: Random, server: Random) -> Self { |
312 | Self { |
313 | client: client.0, |
314 | server: server.0, |
315 | } |
316 | } |
317 | } |
318 | |
319 | // --- Common (to client and server) connection functions --- |
320 | |
321 | fn is_valid_ccs(msg: &PlainMessage) -> bool { |
322 | // We passthrough ChangeCipherSpec messages in the deframer without decrypting them. |
323 | // Note: this is prior to the record layer, so is unencrypted. See |
324 | // third paragraph of section 5 in RFC8446. |
325 | msg.typ == ContentType::ChangeCipherSpec && msg.payload.0 == [0x01] |
326 | } |
327 | |
328 | /// Interface shared by client and server connections. |
329 | pub struct ConnectionCommon<Data> { |
330 | pub(crate) core: ConnectionCore<Data>, |
331 | deframer_buffer: DeframerVecBuffer, |
332 | } |
333 | |
334 | impl<Data> ConnectionCommon<Data> { |
335 | /// Returns an object that allows reading plaintext. |
336 | pub fn reader(&mut self) -> Reader { |
337 | let common = &mut self.core.common_state; |
338 | Reader { |
339 | received_plaintext: &mut common.received_plaintext, |
340 | // Are we done? i.e., have we processed all received messages, and received a |
341 | // close_notify to indicate that no new messages will arrive? |
342 | peer_cleanly_closed: common.has_received_close_notify |
343 | && !self.deframer_buffer.has_pending(), |
344 | has_seen_eof: common.has_seen_eof, |
345 | } |
346 | } |
347 | |
348 | /// Returns an object that allows writing plaintext. |
349 | pub fn writer(&mut self) -> Writer { |
350 | Writer::new(self) |
351 | } |
352 | |
353 | /// This function uses `io` to complete any outstanding IO for |
354 | /// this connection. |
355 | /// |
356 | /// This is a convenience function which solely uses other parts |
357 | /// of the public API. |
358 | /// |
359 | /// What this means depends on the connection state: |
360 | /// |
361 | /// - If the connection [`is_handshaking`], then IO is performed until |
362 | /// the handshake is complete. |
363 | /// - Otherwise, if [`wants_write`] is true, [`write_tls`] is invoked |
364 | /// until it is all written. |
365 | /// - Otherwise, if [`wants_read`] is true, [`read_tls`] is invoked |
366 | /// once. |
367 | /// |
368 | /// The return value is the number of bytes read from and written |
369 | /// to `io`, respectively. |
370 | /// |
371 | /// This function will block if `io` blocks. |
372 | /// |
373 | /// Errors from TLS record handling (i.e., from [`process_new_packets`]) |
374 | /// are wrapped in an `io::ErrorKind::InvalidData`-kind error. |
375 | /// |
376 | /// [`is_handshaking`]: CommonState::is_handshaking |
377 | /// [`wants_read`]: CommonState::wants_read |
378 | /// [`wants_write`]: CommonState::wants_write |
379 | /// [`write_tls`]: ConnectionCommon::write_tls |
380 | /// [`read_tls`]: ConnectionCommon::read_tls |
381 | /// [`process_new_packets`]: ConnectionCommon::process_new_packets |
382 | pub fn complete_io<T>(&mut self, io: &mut T) -> Result<(usize, usize), io::Error> |
383 | where |
384 | Self: Sized, |
385 | T: io::Read + io::Write, |
386 | { |
387 | let mut eof = false; |
388 | let mut wrlen = 0; |
389 | let mut rdlen = 0; |
390 | |
391 | loop { |
392 | let until_handshaked = self.is_handshaking(); |
393 | |
394 | while self.wants_write() { |
395 | wrlen += self.write_tls(io)?; |
396 | } |
397 | io.flush()?; |
398 | |
399 | if !until_handshaked && wrlen > 0 { |
400 | return Ok((rdlen, wrlen)); |
401 | } |
402 | |
403 | while !eof && self.wants_read() { |
404 | let read_size = match self.read_tls(io) { |
405 | Ok(0) => { |
406 | eof = true; |
407 | Some(0) |
408 | } |
409 | Ok(n) => { |
410 | rdlen += n; |
411 | Some(n) |
412 | } |
413 | Err(ref err) if err.kind() == io::ErrorKind::Interrupted => None, // nothing to do |
414 | Err(err) => return Err(err), |
415 | }; |
416 | if read_size.is_some() { |
417 | break; |
418 | } |
419 | } |
420 | |
421 | match self.process_new_packets() { |
422 | Ok(_) => {} |
423 | Err(e) => { |
424 | // In case we have an alert to send describing this error, |
425 | // try a last-gasp write -- but don't predate the primary |
426 | // error. |
427 | let _ignored = self.write_tls(io); |
428 | let _ignored = io.flush(); |
429 | |
430 | return Err(io::Error::new(io::ErrorKind::InvalidData, e)); |
431 | } |
432 | }; |
433 | |
434 | // if we're doing IO until handshaked, and we believe we've finished handshaking, |
435 | // but process_new_packets() has queued TLS data to send, loop around again to write |
436 | // the queued messages. |
437 | if until_handshaked && !self.is_handshaking() && self.wants_write() { |
438 | continue; |
439 | } |
440 | |
441 | match (eof, until_handshaked, self.is_handshaking()) { |
442 | (_, true, false) => return Ok((rdlen, wrlen)), |
443 | (_, false, _) => return Ok((rdlen, wrlen)), |
444 | (true, true, true) => return Err(io::Error::from(io::ErrorKind::UnexpectedEof)), |
445 | (..) => {} |
446 | } |
447 | } |
448 | } |
449 | |
450 | /// Extract the first handshake message. |
451 | /// |
452 | /// This is a shortcut to the `process_new_packets()` -> `process_msg()` -> |
453 | /// `process_handshake_messages()` path, specialized for the first handshake message. |
454 | pub(crate) fn first_handshake_message(&mut self) -> Result<Option<Message>, Error> { |
455 | let mut deframer_buffer = self.deframer_buffer.borrow(); |
456 | let res = self |
457 | .core |
458 | .deframe(None, &mut deframer_buffer); |
459 | let discard = deframer_buffer.pending_discard(); |
460 | self.deframer_buffer.discard(discard); |
461 | |
462 | match res?.map(Message::try_from) { |
463 | Some(Ok(msg)) => Ok(Some(msg)), |
464 | Some(Err(err)) => Err(self.send_fatal_alert(AlertDescription::DecodeError, err)), |
465 | None => Ok(None), |
466 | } |
467 | } |
468 | |
469 | pub(crate) fn replace_state(&mut self, new: Box<dyn State<Data>>) { |
470 | self.core.state = Ok(new); |
471 | } |
472 | |
473 | /// Processes any new packets read by a previous call to |
474 | /// [`Connection::read_tls`]. |
475 | /// |
476 | /// Errors from this function relate to TLS protocol errors, and |
477 | /// are fatal to the connection. Future calls after an error will do |
478 | /// no new work and will return the same error. After an error is |
479 | /// received from [`process_new_packets`], you should not call [`read_tls`] |
480 | /// any more (it will fill up buffers to no purpose). However, you |
481 | /// may call the other methods on the connection, including `write`, |
482 | /// `send_close_notify`, and `write_tls`. Most likely you will want to |
483 | /// call `write_tls` to send any alerts queued by the error and then |
484 | /// close the underlying connection. |
485 | /// |
486 | /// Success from this function comes with some sundry state data |
487 | /// about the connection. |
488 | /// |
489 | /// [`read_tls`]: Connection::read_tls |
490 | /// [`process_new_packets`]: Connection::process_new_packets |
491 | #[inline] |
492 | pub fn process_new_packets(&mut self) -> Result<IoState, Error> { |
493 | self.core |
494 | .process_new_packets(&mut self.deframer_buffer) |
495 | } |
496 | |
497 | /// Read TLS content from `rd` into the internal buffer. |
498 | /// |
499 | /// Due to the internal buffering, `rd` can supply TLS messages in arbitrary-sized chunks (like |
500 | /// a socket or pipe might). |
501 | /// |
502 | /// You should call [`process_new_packets()`] each time a call to this function succeeds in order |
503 | /// to empty the incoming TLS data buffer. |
504 | /// |
505 | /// This function returns `Ok(0)` when the underlying `rd` does so. This typically happens when |
506 | /// a socket is cleanly closed, or a file is at EOF. Errors may result from the IO done through |
507 | /// `rd`; additionally, errors of `ErrorKind::Other` are emitted to signal backpressure: |
508 | /// |
509 | /// * In order to empty the incoming TLS data buffer, you should call [`process_new_packets()`] |
510 | /// each time a call to this function succeeds. |
511 | /// * In order to empty the incoming plaintext data buffer, you should empty it through |
512 | /// the [`reader()`] after the call to [`process_new_packets()`]. |
513 | /// |
514 | /// [`process_new_packets()`]: ConnectionCommon::process_new_packets |
515 | /// [`reader()`]: ConnectionCommon::reader |
516 | pub fn read_tls(&mut self, rd: &mut dyn io::Read) -> Result<usize, io::Error> { |
517 | if self.received_plaintext.is_full() { |
518 | return Err(io::Error::new( |
519 | io::ErrorKind::Other, |
520 | "received plaintext buffer full", |
521 | )); |
522 | } |
523 | |
524 | let res = self |
525 | .core |
526 | .message_deframer |
527 | .read(rd, &mut self.deframer_buffer); |
528 | if let Ok(0) = res { |
529 | self.has_seen_eof = true; |
530 | } |
531 | res |
532 | } |
533 | |
534 | /// Writes TLS messages to `wr`. |
535 | /// |
536 | /// On success, this function returns `Ok(n)` where `n` is a number of bytes written to `wr` |
537 | /// (after encoding and encryption). |
538 | /// |
539 | /// After this function returns, the connection buffer may not yet be fully flushed. The |
540 | /// [`CommonState::wants_write`] function can be used to check if the output buffer is empty. |
541 | pub fn write_tls(&mut self, wr: &mut dyn io::Write) -> Result<usize, io::Error> { |
542 | self.sendable_tls.write_to(wr) |
543 | } |
544 | |
545 | /// Derives key material from the agreed connection secrets. |
546 | /// |
547 | /// This function fills in `output` with `output.len()` bytes of key |
548 | /// material derived from the master session secret using `label` |
549 | /// and `context` for diversification. Ownership of the buffer is taken |
550 | /// by the function and returned via the Ok result to ensure no key |
551 | /// material leaks if the function fails. |
552 | /// |
553 | /// See RFC5705 for more details on what this does and is for. |
554 | /// |
555 | /// For TLS1.3 connections, this function does not use the |
556 | /// "early" exporter at any point. |
557 | /// |
558 | /// This function fails if called prior to the handshake completing; |
559 | /// check with [`CommonState::is_handshaking`] first. |
560 | /// |
561 | /// This function fails if `output.len()` is zero. |
562 | #[inline] |
563 | pub fn export_keying_material<T: AsMut<[u8]>>( |
564 | &self, |
565 | output: T, |
566 | label: &[u8], |
567 | context: Option<&[u8]>, |
568 | ) -> Result<T, Error> { |
569 | self.core |
570 | .export_keying_material(output, label, context) |
571 | } |
572 | |
573 | /// Extract secrets, so they can be used when configuring kTLS, for example. |
574 | /// Should be used with care as it exposes secret key material. |
575 | pub fn dangerous_extract_secrets(self) -> Result<ExtractedSecrets, Error> { |
576 | if !self.enable_secret_extraction { |
577 | return Err(Error::General("Secret extraction is disabled".into())); |
578 | } |
579 | |
580 | let st = self.core.state?; |
581 | |
582 | let record_layer = self.core.common_state.record_layer; |
583 | let PartiallyExtractedSecrets { tx, rx } = st.extract_secrets()?; |
584 | Ok(ExtractedSecrets { |
585 | tx: (record_layer.write_seq(), tx), |
586 | rx: (record_layer.read_seq(), rx), |
587 | }) |
588 | } |
589 | } |
590 | |
591 | impl<'a, Data> From<&'a mut ConnectionCommon<Data>> for Context<'a, Data> { |
592 | fn from(conn: &'a mut ConnectionCommon<Data>) -> Self { |
593 | Self { |
594 | common: &mut conn.core.common_state, |
595 | data: &mut conn.core.data, |
596 | } |
597 | } |
598 | } |
599 | |
600 | impl<T> Deref for ConnectionCommon<T> { |
601 | type Target = CommonState; |
602 | |
603 | fn deref(&self) -> &Self::Target { |
604 | &self.core.common_state |
605 | } |
606 | } |
607 | |
608 | impl<T> DerefMut for ConnectionCommon<T> { |
609 | fn deref_mut(&mut self) -> &mut Self::Target { |
610 | &mut self.core.common_state |
611 | } |
612 | } |
613 | |
614 | impl<Data> From<ConnectionCore<Data>> for ConnectionCommon<Data> { |
615 | fn from(core: ConnectionCore<Data>) -> Self { |
616 | Self { |
617 | core, |
618 | deframer_buffer: DeframerVecBuffer::default(), |
619 | } |
620 | } |
621 | } |
622 | |
623 | pub(crate) struct ConnectionCore<Data> { |
624 | pub(crate) state: Result<Box<dyn State<Data>>, Error>, |
625 | pub(crate) data: Data, |
626 | pub(crate) common_state: CommonState, |
627 | pub(crate) message_deframer: MessageDeframer, |
628 | } |
629 | |
630 | impl<Data> ConnectionCore<Data> { |
631 | pub(crate) fn new(state: Box<dyn State<Data>>, data: Data, common_state: CommonState) -> Self { |
632 | Self { |
633 | state: Ok(state), |
634 | data, |
635 | common_state, |
636 | message_deframer: MessageDeframer::default(), |
637 | } |
638 | } |
639 | |
640 | pub(crate) fn process_new_packets( |
641 | &mut self, |
642 | deframer_buffer: &mut DeframerVecBuffer, |
643 | ) -> Result<IoState, Error> { |
644 | let mut state = match mem::replace(&mut self.state, Err(Error::HandshakeNotComplete)) { |
645 | Ok(state) => state, |
646 | Err(e) => { |
647 | self.state = Err(e.clone()); |
648 | return Err(e); |
649 | } |
650 | }; |
651 | |
652 | let mut borrowed_buffer = deframer_buffer.borrow(); |
653 | while let Some(msg) = self.deframe(Some(&*state), &mut borrowed_buffer)? { |
654 | match self.process_msg(msg, state) { |
655 | Ok(new) => state = new, |
656 | Err(e) => { |
657 | self.state = Err(e.clone()); |
658 | let discard = borrowed_buffer.pending_discard(); |
659 | deframer_buffer.discard(discard); |
660 | return Err(e); |
661 | } |
662 | } |
663 | } |
664 | |
665 | let discard = borrowed_buffer.pending_discard(); |
666 | deframer_buffer.discard(discard); |
667 | self.state = Ok(state); |
668 | Ok(self.common_state.current_io_state()) |
669 | } |
670 | |
671 | /// Pull a message out of the deframer and send any messages that need to be sent as a result. |
672 | fn deframe( |
673 | &mut self, |
674 | state: Option<&dyn State<Data>>, |
675 | deframer_buffer: &mut DeframerSliceBuffer, |
676 | ) -> Result<Option<PlainMessage>, Error> { |
677 | match self.message_deframer.pop( |
678 | &mut self.common_state.record_layer, |
679 | self.common_state.negotiated_version, |
680 | deframer_buffer, |
681 | ) { |
682 | Ok(Some(Deframed { |
683 | want_close_before_decrypt, |
684 | aligned, |
685 | trial_decryption_finished, |
686 | message, |
687 | })) => { |
688 | if want_close_before_decrypt { |
689 | self.common_state.send_close_notify(); |
690 | } |
691 | |
692 | if trial_decryption_finished { |
693 | self.common_state |
694 | .record_layer |
695 | .finish_trial_decryption(); |
696 | } |
697 | |
698 | self.common_state.aligned_handshake = aligned; |
699 | Ok(Some(message)) |
700 | } |
701 | Ok(None) => Ok(None), |
702 | Err(err @ Error::InvalidMessage(_)) => { |
703 | if self.common_state.is_quic() { |
704 | self.common_state.quic.alert = Some(AlertDescription::DecodeError); |
705 | } |
706 | |
707 | Err(if !self.common_state.is_quic() { |
708 | self.common_state |
709 | .send_fatal_alert(AlertDescription::DecodeError, err) |
710 | } else { |
711 | err |
712 | }) |
713 | } |
714 | Err(err @ Error::PeerSentOversizedRecord) => Err(self |
715 | .common_state |
716 | .send_fatal_alert(AlertDescription::RecordOverflow, err)), |
717 | Err(err @ Error::DecryptError) => { |
718 | if let Some(state) = state { |
719 | state.handle_decrypt_error(); |
720 | } |
721 | Err(self |
722 | .common_state |
723 | .send_fatal_alert(AlertDescription::BadRecordMac, err)) |
724 | } |
725 | Err(e) => Err(e), |
726 | } |
727 | } |
728 | |
729 | fn process_msg( |
730 | &mut self, |
731 | msg: PlainMessage, |
732 | state: Box<dyn State<Data>>, |
733 | ) -> Result<Box<dyn State<Data>>, Error> { |
734 | // Drop CCS messages during handshake in TLS1.3 |
735 | if msg.typ == ContentType::ChangeCipherSpec |
736 | && !self |
737 | .common_state |
738 | .may_receive_application_data |
739 | && self.common_state.is_tls13() |
740 | { |
741 | if !is_valid_ccs(&msg) |
742 | || self.common_state.received_middlebox_ccs > TLS13_MAX_DROPPED_CCS |
743 | { |
744 | // "An implementation which receives any other change_cipher_spec value or |
745 | // which receives a protected change_cipher_spec record MUST abort the |
746 | // handshake with an "unexpected_message" alert." |
747 | return Err(self.common_state.send_fatal_alert( |
748 | AlertDescription::UnexpectedMessage, |
749 | PeerMisbehaved::IllegalMiddleboxChangeCipherSpec, |
750 | )); |
751 | } else { |
752 | self.common_state.received_middlebox_ccs += 1; |
753 | trace!("Dropping CCS"); |
754 | return Ok(state); |
755 | } |
756 | } |
757 | |
758 | // Now we can fully parse the message payload. |
759 | let msg = match Message::try_from(msg) { |
760 | Ok(msg) => msg, |
761 | Err(err) => { |
762 | return Err(self |
763 | .common_state |
764 | .send_fatal_alert(AlertDescription::DecodeError, err)); |
765 | } |
766 | }; |
767 | |
768 | // For alerts, we have separate logic. |
769 | if let MessagePayload::Alert(alert) = &msg.payload { |
770 | self.common_state.process_alert(alert)?; |
771 | return Ok(state); |
772 | } |
773 | |
774 | self.common_state |
775 | .process_main_protocol(msg, state, &mut self.data) |
776 | } |
777 | |
778 | pub(crate) fn export_keying_material<T: AsMut<[u8]>>( |
779 | &self, |
780 | mut output: T, |
781 | label: &[u8], |
782 | context: Option<&[u8]>, |
783 | ) -> Result<T, Error> { |
784 | if output.as_mut().is_empty() { |
785 | return Err(Error::General( |
786 | "export_keying_material with zero-length output".into(), |
787 | )); |
788 | } |
789 | |
790 | match self.state.as_ref() { |
791 | Ok(st) => st |
792 | .export_keying_material(output.as_mut(), label, context) |
793 | .map(|_| output), |
794 | Err(e) => Err(e.clone()), |
795 | } |
796 | } |
797 | } |
798 | |
799 | /// Data specific to the peer's side (client or server). |
800 | pub trait SideData: Debug {} |
801 | |
802 | const UNEXPECTED_EOF_MESSAGE: &str = "peer closed connection without sending TLS close_notify: \ |
803 | https://docs.rs/rustls/latest/rustls/manual/_03_howto/index.html#unexpected-eof"; |
804 |
Definitions
- Connection
- Client
- Server
- read_tls
- write_tls
- reader
- writer
- process_new_packets
- export_keying_material
- complete_io
- dangerous_extract_secrets
- Target
- deref
- deref_mut
- Reader
- received_plaintext
- peer_cleanly_closed
- has_seen_eof
- read
- PlaintextSink
- write
- write_vectored
- flush
- write
- write_vectored
- flush
- Writer
- sink
- new
- write
- write_vectored
- flush
- ConnectionRandoms
- client
- server
- new
- is_valid_ccs
- ConnectionCommon
- core
- deframer_buffer
- reader
- writer
- complete_io
- first_handshake_message
- replace_state
- process_new_packets
- read_tls
- write_tls
- export_keying_material
- dangerous_extract_secrets
- tx
- rx
- from
- Target
- deref
- deref_mut
- from
- ConnectionCore
- state
- data
- common_state
- message_deframer
- new
- process_new_packets
- deframe
- want_close_before_decrypt
- aligned
- trial_decryption_finished
- message
- process_msg
- export_keying_material
Learn Rust with the experts
Find out more