1 | use crate::builder::ConfigBuilder; |
2 | use crate::common_state::{CommonState, Protocol, Side}; |
3 | use crate::conn::{ConnectionCommon, ConnectionCore}; |
4 | use crate::crypto::{CryptoProvider, SupportedKxGroup}; |
5 | use crate::enums::{CipherSuite, ProtocolVersion, SignatureScheme}; |
6 | use crate::error::Error; |
7 | #[cfg (feature = "logging" )] |
8 | use crate::log::trace; |
9 | use crate::msgs::enums::NamedGroup; |
10 | use crate::msgs::handshake::ClientExtension; |
11 | use crate::msgs::persist; |
12 | use crate::sign; |
13 | use crate::suites::{ExtractedSecrets, SupportedCipherSuite}; |
14 | use crate::versions; |
15 | use crate::KeyLog; |
16 | #[cfg (feature = "ring" )] |
17 | use crate::WantsVerifier; |
18 | use crate::{verify, WantsVersions}; |
19 | |
20 | use super::handy::{ClientSessionMemoryCache, NoClientSessionStorage}; |
21 | use super::hs; |
22 | |
23 | use pki_types::ServerName; |
24 | |
25 | use alloc::sync::Arc; |
26 | use alloc::vec::Vec; |
27 | use core::fmt; |
28 | use core::marker::PhantomData; |
29 | use core::mem; |
30 | use core::ops::{Deref, DerefMut}; |
31 | use std::io; |
32 | |
33 | #[cfg (doc)] |
34 | use crate::{crypto, DistinguishedName}; |
35 | |
36 | /// A trait for the ability to store client session data, so that sessions |
37 | /// can be resumed in future connections. |
38 | /// |
39 | /// Generally all data in this interface should be treated as |
40 | /// **highly sensitive**, containing enough key material to break all security |
41 | /// of the corresponding session. |
42 | /// |
43 | /// `set_`, `insert_`, `remove_` and `take_` operations are mutating; this isn't |
44 | /// expressed in the type system to allow implementations freedom in |
45 | /// how to achieve interior mutability. `Mutex` is a common choice. |
46 | pub trait ClientSessionStore: fmt::Debug + Send + Sync { |
47 | /// Remember what `NamedGroup` the given server chose. |
48 | fn set_kx_hint(&self, server_name: ServerName<'static>, group: NamedGroup); |
49 | |
50 | /// This should return the value most recently passed to `set_kx_hint` |
51 | /// for the given `server_name`. |
52 | /// |
53 | /// If `None` is returned, the caller chooses the first configured group, |
54 | /// and an extra round trip might happen if that choice is unsatisfactory |
55 | /// to the server. |
56 | fn kx_hint(&self, server_name: &ServerName<'_>) -> Option<NamedGroup>; |
57 | |
58 | /// Remember a TLS1.2 session. |
59 | /// |
60 | /// At most one of these can be remembered at a time, per `server_name`. |
61 | fn set_tls12_session( |
62 | &self, |
63 | server_name: ServerName<'static>, |
64 | value: persist::Tls12ClientSessionValue, |
65 | ); |
66 | |
67 | /// Get the most recently saved TLS1.2 session for `server_name` provided to `set_tls12_session`. |
68 | fn tls12_session( |
69 | &self, |
70 | server_name: &ServerName<'_>, |
71 | ) -> Option<persist::Tls12ClientSessionValue>; |
72 | |
73 | /// Remove and forget any saved TLS1.2 session for `server_name`. |
74 | fn remove_tls12_session(&self, server_name: &ServerName<'static>); |
75 | |
76 | /// Remember a TLS1.3 ticket that might be retrieved later from `take_tls13_ticket`, allowing |
77 | /// resumption of this session. |
78 | /// |
79 | /// This can be called multiple times for a given session, allowing multiple independent tickets |
80 | /// to be valid at once. The number of times this is called is controlled by the server, so |
81 | /// implementations of this trait should apply a reasonable bound of how many items are stored |
82 | /// simultaneously. |
83 | fn insert_tls13_ticket( |
84 | &self, |
85 | server_name: ServerName<'static>, |
86 | value: persist::Tls13ClientSessionValue, |
87 | ); |
88 | |
89 | /// Return a TLS1.3 ticket previously provided to `add_tls13_ticket`. |
90 | /// |
91 | /// Implementations of this trait must return each value provided to `add_tls13_ticket` _at most once_. |
92 | fn take_tls13_ticket( |
93 | &self, |
94 | server_name: &ServerName<'static>, |
95 | ) -> Option<persist::Tls13ClientSessionValue>; |
96 | } |
97 | |
98 | /// A trait for the ability to choose a certificate chain and |
99 | /// private key for the purposes of client authentication. |
100 | pub trait ResolvesClientCert: fmt::Debug + Send + Sync { |
101 | /// Resolve a client certificate chain/private key to use as the client's |
102 | /// identity. |
103 | /// |
104 | /// `root_hint_subjects` is an optional list of certificate authority |
105 | /// subject distinguished names that the client can use to help |
106 | /// decide on a client certificate the server is likely to accept. If |
107 | /// the list is empty, the client should send whatever certificate it |
108 | /// has. The hints are expected to be DER-encoded X.500 distinguished names, |
109 | /// per [RFC 5280 A.1]. See [`DistinguishedName`] for more information |
110 | /// on decoding with external crates like `x509-parser`. |
111 | /// |
112 | /// `sigschemes` is the list of the [`SignatureScheme`]s the server |
113 | /// supports. |
114 | /// |
115 | /// Return `None` to continue the handshake without any client |
116 | /// authentication. The server may reject the handshake later |
117 | /// if it requires authentication. |
118 | /// |
119 | /// [RFC 5280 A.1]: https://www.rfc-editor.org/rfc/rfc5280#appendix-A.1 |
120 | fn resolve( |
121 | &self, |
122 | root_hint_subjects: &[&[u8]], |
123 | sigschemes: &[SignatureScheme], |
124 | ) -> Option<Arc<sign::CertifiedKey>>; |
125 | |
126 | /// Return true if any certificates at all are available. |
127 | fn has_certs(&self) -> bool; |
128 | } |
129 | |
130 | /// Common configuration for (typically) all connections made by a program. |
131 | /// |
132 | /// Making one of these is cheap, though one of the inputs may be expensive: gathering trust roots |
133 | /// from the operating system to add to the [`RootCertStore`] passed to `with_root_certificates()` |
134 | /// (the rustls-native-certs crate is often used for this) may take on the order of a few hundred |
135 | /// milliseconds. |
136 | /// |
137 | /// These must be created via the [`ClientConfig::builder()`] or [`ClientConfig::builder_with_provider()`] |
138 | /// function. |
139 | /// |
140 | /// # Defaults |
141 | /// |
142 | /// * [`ClientConfig::max_fragment_size`]: the default is `None` (meaning 16kB). |
143 | /// * [`ClientConfig::resumption`]: supports resumption with up to 256 server names, using session |
144 | /// ids or tickets, with a max of eight tickets per server. |
145 | /// * [`ClientConfig::alpn_protocols`]: the default is empty -- no ALPN protocol is negotiated. |
146 | /// * [`ClientConfig::key_log`]: key material is not logged. |
147 | /// |
148 | /// [`RootCertStore`]: crate::RootCertStore |
149 | #[derive (Debug)] |
150 | pub struct ClientConfig { |
151 | /// Source of randomness and other crypto. |
152 | pub(super) provider: Arc<CryptoProvider>, |
153 | |
154 | /// Which ALPN protocols we include in our client hello. |
155 | /// If empty, no ALPN extension is sent. |
156 | pub alpn_protocols: Vec<Vec<u8>>, |
157 | |
158 | /// How and when the client can resume a previous session. |
159 | pub resumption: Resumption, |
160 | |
161 | /// The maximum size of plaintext input to be emitted in a single TLS record. |
162 | /// A value of None is equivalent to the [TLS maximum] of 16 kB. |
163 | /// |
164 | /// rustls enforces an arbitrary minimum of 32 bytes for this field. |
165 | /// Out of range values are reported as errors from [ClientConnection::new]. |
166 | /// |
167 | /// Setting this value to a little less than the TCP MSS may improve latency |
168 | /// for stream-y workloads. |
169 | /// |
170 | /// [TLS maximum]: https://datatracker.ietf.org/doc/html/rfc8446#section-5.1 |
171 | /// [ClientConnection::new]: crate::client::ClientConnection::new |
172 | pub max_fragment_size: Option<usize>, |
173 | |
174 | /// How to decide what client auth certificate/keys to use. |
175 | pub client_auth_cert_resolver: Arc<dyn ResolvesClientCert>, |
176 | |
177 | /// Supported versions, in no particular order. The default |
178 | /// is all supported versions. |
179 | pub(super) versions: versions::EnabledVersions, |
180 | |
181 | /// Whether to send the Server Name Indication (SNI) extension |
182 | /// during the client handshake. |
183 | /// |
184 | /// The default is true. |
185 | pub enable_sni: bool, |
186 | |
187 | /// How to verify the server certificate chain. |
188 | pub(super) verifier: Arc<dyn verify::ServerCertVerifier>, |
189 | |
190 | /// How to output key material for debugging. The default |
191 | /// does nothing. |
192 | pub key_log: Arc<dyn KeyLog>, |
193 | |
194 | /// Allows traffic secrets to be extracted after the handshake, |
195 | /// e.g. for kTLS setup. |
196 | pub enable_secret_extraction: bool, |
197 | |
198 | /// Whether to send data on the first flight ("early data") in |
199 | /// TLS 1.3 handshakes. |
200 | /// |
201 | /// The default is false. |
202 | pub enable_early_data: bool, |
203 | } |
204 | |
205 | /// What mechanisms to support for resuming a TLS 1.2 session. |
206 | #[derive (Clone, Copy, Debug, PartialEq)] |
207 | pub enum Tls12Resumption { |
208 | /// Disable 1.2 resumption. |
209 | Disabled, |
210 | /// Support 1.2 resumption using session ids only. |
211 | SessionIdOnly, |
212 | /// Support 1.2 resumption using session ids or RFC 5077 tickets. |
213 | /// |
214 | /// See[^1] for why you might like to disable RFC 5077 by instead choosing the `SessionIdOnly` |
215 | /// option. Note that TLS 1.3 tickets do not have those issues. |
216 | /// |
217 | /// [^1]: <https://words.filippo.io/we-need-to-talk-about-session-tickets/> |
218 | SessionIdOrTickets, |
219 | } |
220 | |
221 | impl Clone for ClientConfig { |
222 | fn clone(&self) -> Self { |
223 | Self { |
224 | provider: Arc::<CryptoProvider>::clone(&self.provider), |
225 | resumption: self.resumption.clone(), |
226 | alpn_protocols: self.alpn_protocols.clone(), |
227 | max_fragment_size: self.max_fragment_size, |
228 | client_auth_cert_resolver: Arc::clone(&self.client_auth_cert_resolver), |
229 | versions: self.versions, |
230 | enable_sni: self.enable_sni, |
231 | verifier: Arc::clone(&self.verifier), |
232 | key_log: Arc::clone(&self.key_log), |
233 | enable_secret_extraction: self.enable_secret_extraction, |
234 | enable_early_data: self.enable_early_data, |
235 | } |
236 | } |
237 | } |
238 | |
239 | impl ClientConfig { |
240 | /// Create a builder for a client configuration with the default |
241 | /// [`CryptoProvider`]: [`crypto::ring::default_provider`] and safe ciphersuite and |
242 | /// protocol defaults. |
243 | /// |
244 | /// For more information, see the [`ConfigBuilder`] documentation. |
245 | #[cfg (feature = "ring" )] |
246 | pub fn builder() -> ConfigBuilder<Self, WantsVerifier> { |
247 | // Safety: we know the *ring* provider's ciphersuites are compatible with the safe default protocol versions. |
248 | Self::builder_with_provider(crate::crypto::ring::default_provider().into()) |
249 | .with_safe_default_protocol_versions() |
250 | .unwrap() |
251 | } |
252 | |
253 | /// Create a builder for a client configuration with the default |
254 | /// [`CryptoProvider`]: [`crypto::ring::default_provider`], safe ciphersuite defaults and |
255 | /// the provided protocol versions. |
256 | /// |
257 | /// Panics if provided an empty slice of supported versions. |
258 | /// |
259 | /// For more information, see the [`ConfigBuilder`] documentation. |
260 | #[cfg (feature = "ring" )] |
261 | pub fn builder_with_protocol_versions( |
262 | versions: &[&'static versions::SupportedProtocolVersion], |
263 | ) -> ConfigBuilder<Self, WantsVerifier> { |
264 | // Safety: we know the *ring* provider's ciphersuites are compatible with all protocol version choices. |
265 | Self::builder_with_provider(crate::crypto::ring::default_provider().into()) |
266 | .with_protocol_versions(versions) |
267 | .unwrap() |
268 | } |
269 | |
270 | /// Create a builder for a client configuration with a specific [`CryptoProvider`]. |
271 | /// |
272 | /// This will use the provider's configured ciphersuites. You must additionally choose |
273 | /// which protocol versions to enable, using `with_protocol_versions` or |
274 | /// `with_safe_default_protocol_versions` and handling the `Result` in case a protocol |
275 | /// version is not supported by the provider's ciphersuites. |
276 | /// |
277 | /// For more information, see the [`ConfigBuilder`] documentation. |
278 | pub fn builder_with_provider( |
279 | provider: Arc<CryptoProvider>, |
280 | ) -> ConfigBuilder<Self, WantsVersions> { |
281 | ConfigBuilder { |
282 | state: WantsVersions { provider }, |
283 | side: PhantomData, |
284 | } |
285 | } |
286 | |
287 | /// We support a given TLS version if it's quoted in the configured |
288 | /// versions *and* at least one ciphersuite for this version is |
289 | /// also configured. |
290 | pub(crate) fn supports_version(&self, v: ProtocolVersion) -> bool { |
291 | self.versions.contains(v) |
292 | && self |
293 | .provider |
294 | .cipher_suites |
295 | .iter() |
296 | .any(|cs| cs.version().version == v) |
297 | } |
298 | |
299 | pub(crate) fn supports_protocol(&self, proto: Protocol) -> bool { |
300 | self.provider |
301 | .cipher_suites |
302 | .iter() |
303 | .any(|cs| cs.usable_for_protocol(proto)) |
304 | } |
305 | |
306 | /// Access configuration options whose use is dangerous and requires |
307 | /// extra care. |
308 | pub fn dangerous(&mut self) -> danger::DangerousClientConfig<'_> { |
309 | danger::DangerousClientConfig { cfg: self } |
310 | } |
311 | |
312 | pub(super) fn find_cipher_suite(&self, suite: CipherSuite) -> Option<SupportedCipherSuite> { |
313 | self.provider |
314 | .cipher_suites |
315 | .iter() |
316 | .copied() |
317 | .find(|&scs| scs.suite() == suite) |
318 | } |
319 | |
320 | pub(super) fn find_kx_group(&self, group: NamedGroup) -> Option<&'static dyn SupportedKxGroup> { |
321 | self.provider |
322 | .kx_groups |
323 | .iter() |
324 | .copied() |
325 | .find(|skxg| skxg.name() == group) |
326 | } |
327 | } |
328 | |
329 | /// Configuration for how/when a client is allowed to resume a previous session. |
330 | #[derive (Clone, Debug)] |
331 | pub struct Resumption { |
332 | /// How we store session data or tickets. The default is to use an in-memory |
333 | /// [ClientSessionMemoryCache]. |
334 | pub(super) store: Arc<dyn ClientSessionStore>, |
335 | |
336 | /// What mechanism is used for resuming a TLS 1.2 session. |
337 | pub(super) tls12_resumption: Tls12Resumption, |
338 | } |
339 | |
340 | impl Resumption { |
341 | /// Create a new `Resumption` that stores data for the given number of sessions in memory. |
342 | /// |
343 | /// This is the default `Resumption` choice, and enables resuming a TLS 1.2 session with |
344 | /// a session id or RFC 5077 ticket. |
345 | pub fn in_memory_sessions(num: usize) -> Self { |
346 | Self { |
347 | store: Arc::new(ClientSessionMemoryCache::new(num)), |
348 | tls12_resumption: Tls12Resumption::SessionIdOrTickets, |
349 | } |
350 | } |
351 | |
352 | /// Use a custom [`ClientSessionStore`] implementation to store sessions. |
353 | /// |
354 | /// By default, enables resuming a TLS 1.2 session with a session id or RFC 5077 ticket. |
355 | pub fn store(store: Arc<dyn ClientSessionStore>) -> Self { |
356 | Self { |
357 | store, |
358 | tls12_resumption: Tls12Resumption::SessionIdOrTickets, |
359 | } |
360 | } |
361 | |
362 | /// Disable all use of session resumption. |
363 | pub fn disabled() -> Self { |
364 | Self { |
365 | store: Arc::new(NoClientSessionStorage), |
366 | tls12_resumption: Tls12Resumption::Disabled, |
367 | } |
368 | } |
369 | |
370 | /// Configure whether TLS 1.2 sessions may be resumed, and by what mechanism. |
371 | /// |
372 | /// This is meaningless if you've disabled resumption entirely. |
373 | pub fn tls12_resumption(mut self, tls12: Tls12Resumption) -> Self { |
374 | self.tls12_resumption = tls12; |
375 | self |
376 | } |
377 | } |
378 | |
379 | impl Default for Resumption { |
380 | /// Create an in-memory session store resumption with up to 256 server names, allowing |
381 | /// a TLS 1.2 session to resume with a session id or RFC 5077 ticket. |
382 | fn default() -> Self { |
383 | Self::in_memory_sessions(num:256) |
384 | } |
385 | } |
386 | |
387 | /// Container for unsafe APIs |
388 | pub(super) mod danger { |
389 | use alloc::sync::Arc; |
390 | |
391 | use super::verify::ServerCertVerifier; |
392 | use super::ClientConfig; |
393 | |
394 | /// Accessor for dangerous configuration options. |
395 | #[derive (Debug)] |
396 | pub struct DangerousClientConfig<'a> { |
397 | /// The underlying ClientConfig |
398 | pub cfg: &'a mut ClientConfig, |
399 | } |
400 | |
401 | impl<'a> DangerousClientConfig<'a> { |
402 | /// Overrides the default `ServerCertVerifier` with something else. |
403 | pub fn set_certificate_verifier(&mut self, verifier: Arc<dyn ServerCertVerifier>) { |
404 | self.cfg.verifier = verifier; |
405 | } |
406 | } |
407 | } |
408 | |
409 | #[derive (Debug, PartialEq)] |
410 | enum EarlyDataState { |
411 | Disabled, |
412 | Ready, |
413 | Accepted, |
414 | AcceptedFinished, |
415 | Rejected, |
416 | } |
417 | |
418 | #[derive (Debug)] |
419 | pub(super) struct EarlyData { |
420 | state: EarlyDataState, |
421 | left: usize, |
422 | } |
423 | |
424 | impl EarlyData { |
425 | fn new() -> Self { |
426 | Self { |
427 | left: 0, |
428 | state: EarlyDataState::Disabled, |
429 | } |
430 | } |
431 | |
432 | pub(super) fn is_enabled(&self) -> bool { |
433 | matches!(self.state, EarlyDataState::Ready | EarlyDataState::Accepted) |
434 | } |
435 | |
436 | fn is_accepted(&self) -> bool { |
437 | matches!( |
438 | self.state, |
439 | EarlyDataState::Accepted | EarlyDataState::AcceptedFinished |
440 | ) |
441 | } |
442 | |
443 | pub(super) fn enable(&mut self, max_data: usize) { |
444 | assert_eq!(self.state, EarlyDataState::Disabled); |
445 | self.state = EarlyDataState::Ready; |
446 | self.left = max_data; |
447 | } |
448 | |
449 | pub(super) fn rejected(&mut self) { |
450 | trace!("EarlyData rejected" ); |
451 | self.state = EarlyDataState::Rejected; |
452 | } |
453 | |
454 | pub(super) fn accepted(&mut self) { |
455 | trace!("EarlyData accepted" ); |
456 | assert_eq!(self.state, EarlyDataState::Ready); |
457 | self.state = EarlyDataState::Accepted; |
458 | } |
459 | |
460 | pub(super) fn finished(&mut self) { |
461 | trace!("EarlyData finished" ); |
462 | self.state = match self.state { |
463 | EarlyDataState::Accepted => EarlyDataState::AcceptedFinished, |
464 | _ => panic!("bad EarlyData state" ), |
465 | } |
466 | } |
467 | |
468 | fn check_write(&mut self, sz: usize) -> io::Result<usize> { |
469 | match self.state { |
470 | EarlyDataState::Disabled => unreachable!(), |
471 | EarlyDataState::Ready | EarlyDataState::Accepted => { |
472 | let take = if self.left < sz { |
473 | mem::replace(&mut self.left, 0) |
474 | } else { |
475 | self.left -= sz; |
476 | sz |
477 | }; |
478 | |
479 | Ok(take) |
480 | } |
481 | EarlyDataState::Rejected | EarlyDataState::AcceptedFinished => { |
482 | Err(io::Error::from(io::ErrorKind::InvalidInput)) |
483 | } |
484 | } |
485 | } |
486 | |
487 | fn bytes_left(&self) -> usize { |
488 | self.left |
489 | } |
490 | } |
491 | |
492 | /// Stub that implements io::Write and dispatches to `write_early_data`. |
493 | pub struct WriteEarlyData<'a> { |
494 | sess: &'a mut ClientConnection, |
495 | } |
496 | |
497 | impl<'a> WriteEarlyData<'a> { |
498 | fn new(sess: &'a mut ClientConnection) -> WriteEarlyData<'a> { |
499 | WriteEarlyData { sess } |
500 | } |
501 | |
502 | /// How many bytes you may send. Writes will become short |
503 | /// once this reaches zero. |
504 | pub fn bytes_left(&self) -> usize { |
505 | self.sess |
506 | .inner |
507 | .core |
508 | .data |
509 | .early_data |
510 | .bytes_left() |
511 | } |
512 | } |
513 | |
514 | impl<'a> io::Write for WriteEarlyData<'a> { |
515 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> { |
516 | self.sess.write_early_data(buf) |
517 | } |
518 | |
519 | fn flush(&mut self) -> io::Result<()> { |
520 | Ok(()) |
521 | } |
522 | } |
523 | |
524 | /// This represents a single TLS client connection. |
525 | pub struct ClientConnection { |
526 | inner: ConnectionCommon<ClientConnectionData>, |
527 | } |
528 | |
529 | impl fmt::Debug for ClientConnection { |
530 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
531 | fDebugStruct<'_, '_>.debug_struct(name:"ClientConnection" ) |
532 | .finish() |
533 | } |
534 | } |
535 | |
536 | impl ClientConnection { |
537 | /// Make a new ClientConnection. `config` controls how |
538 | /// we behave in the TLS protocol, `name` is the |
539 | /// name of the server we want to talk to. |
540 | pub fn new(config: Arc<ClientConfig>, name: ServerName<'static>) -> Result<Self, Error> { |
541 | Ok(Self { |
542 | inner: ConnectionCore::for_client(config, name, Vec::new(), Protocol::Tcp)?.into(), |
543 | }) |
544 | } |
545 | |
546 | /// Returns an `io::Write` implementer you can write bytes to |
547 | /// to send TLS1.3 early data (a.k.a. "0-RTT data") to the server. |
548 | /// |
549 | /// This returns None in many circumstances when the capability to |
550 | /// send early data is not available, including but not limited to: |
551 | /// |
552 | /// - The server hasn't been talked to previously. |
553 | /// - The server does not support resumption. |
554 | /// - The server does not support early data. |
555 | /// - The resumption data for the server has expired. |
556 | /// |
557 | /// The server specifies a maximum amount of early data. You can |
558 | /// learn this limit through the returned object, and writes through |
559 | /// it will process only this many bytes. |
560 | /// |
561 | /// The server can choose not to accept any sent early data -- |
562 | /// in this case the data is lost but the connection continues. You |
563 | /// can tell this happened using `is_early_data_accepted`. |
564 | pub fn early_data(&mut self) -> Option<WriteEarlyData> { |
565 | if self |
566 | .inner |
567 | .core |
568 | .data |
569 | .early_data |
570 | .is_enabled() |
571 | { |
572 | Some(WriteEarlyData::new(self)) |
573 | } else { |
574 | None |
575 | } |
576 | } |
577 | |
578 | /// Returns True if the server signalled it will process early data. |
579 | /// |
580 | /// If you sent early data and this returns false at the end of the |
581 | /// handshake then the server will not process the data. This |
582 | /// is not an error, but you may wish to resend the data. |
583 | pub fn is_early_data_accepted(&self) -> bool { |
584 | self.inner.core.is_early_data_accepted() |
585 | } |
586 | |
587 | /// Extract secrets, so they can be used when configuring kTLS, for example. |
588 | /// Should be used with care as it exposes secret key material. |
589 | pub fn dangerous_extract_secrets(self) -> Result<ExtractedSecrets, Error> { |
590 | self.inner.dangerous_extract_secrets() |
591 | } |
592 | |
593 | fn write_early_data(&mut self, data: &[u8]) -> io::Result<usize> { |
594 | self.inner |
595 | .core |
596 | .data |
597 | .early_data |
598 | .check_write(data.len()) |
599 | .map(|sz| { |
600 | self.inner |
601 | .send_early_plaintext(&data[..sz]) |
602 | }) |
603 | } |
604 | } |
605 | |
606 | impl Deref for ClientConnection { |
607 | type Target = ConnectionCommon<ClientConnectionData>; |
608 | |
609 | fn deref(&self) -> &Self::Target { |
610 | &self.inner |
611 | } |
612 | } |
613 | |
614 | impl DerefMut for ClientConnection { |
615 | fn deref_mut(&mut self) -> &mut Self::Target { |
616 | &mut self.inner |
617 | } |
618 | } |
619 | |
620 | #[doc (hidden)] |
621 | impl<'a> TryFrom<&'a mut crate::Connection> for &'a mut ClientConnection { |
622 | type Error = (); |
623 | |
624 | fn try_from(value: &'a mut crate::Connection) -> Result<Self, Self::Error> { |
625 | use crate::Connection::*; |
626 | match value { |
627 | Client(conn: &mut ClientConnection) => Ok(conn), |
628 | Server(_) => Err(()), |
629 | } |
630 | } |
631 | } |
632 | |
633 | impl From<ClientConnection> for crate::Connection { |
634 | fn from(conn: ClientConnection) -> Self { |
635 | Self::Client(conn) |
636 | } |
637 | } |
638 | |
639 | impl ConnectionCore<ClientConnectionData> { |
640 | pub(crate) fn for_client( |
641 | config: Arc<ClientConfig>, |
642 | name: ServerName<'static>, |
643 | extra_exts: Vec<ClientExtension>, |
644 | proto: Protocol, |
645 | ) -> Result<Self, Error> { |
646 | let mut common_state = CommonState::new(Side::Client); |
647 | common_state.set_max_fragment_size(config.max_fragment_size)?; |
648 | common_state.protocol = proto; |
649 | common_state.enable_secret_extraction = config.enable_secret_extraction; |
650 | let mut data = ClientConnectionData::new(); |
651 | |
652 | let mut cx = hs::ClientContext { |
653 | common: &mut common_state, |
654 | data: &mut data, |
655 | }; |
656 | |
657 | let state = hs::start_handshake(name, extra_exts, config, &mut cx)?; |
658 | Ok(Self::new(state, data, common_state)) |
659 | } |
660 | |
661 | pub(crate) fn is_early_data_accepted(&self) -> bool { |
662 | self.data.early_data.is_accepted() |
663 | } |
664 | } |
665 | |
666 | /// State associated with a client connection. |
667 | #[derive (Debug)] |
668 | pub struct ClientConnectionData { |
669 | pub(super) early_data: EarlyData, |
670 | pub(super) resumption_ciphersuite: Option<SupportedCipherSuite>, |
671 | } |
672 | |
673 | impl ClientConnectionData { |
674 | fn new() -> Self { |
675 | Self { |
676 | early_data: EarlyData::new(), |
677 | resumption_ciphersuite: None, |
678 | } |
679 | } |
680 | } |
681 | |
682 | impl crate::conn::SideData for ClientConnectionData {} |
683 | |