1 | use alloc::vec::Vec; |
2 | use core::marker::PhantomData; |
3 | use core::ops::{Deref, DerefMut}; |
4 | use core::{fmt, mem}; |
5 | |
6 | use pki_types::{ServerName, UnixTime}; |
7 | |
8 | use super::handy::NoClientSessionStorage; |
9 | use super::hs; |
10 | #[cfg (feature = "std" )] |
11 | use crate::WantsVerifier; |
12 | use crate::builder::ConfigBuilder; |
13 | use crate::client::{EchMode, EchStatus}; |
14 | use crate::common_state::{CommonState, Protocol, Side}; |
15 | use crate::conn::{ConnectionCore, UnbufferedConnectionCommon}; |
16 | use crate::crypto::{CryptoProvider, SupportedKxGroup}; |
17 | use crate::enums::{CipherSuite, ProtocolVersion, SignatureScheme}; |
18 | use crate::error::Error; |
19 | use crate::log::trace; |
20 | use crate::msgs::enums::NamedGroup; |
21 | use crate::msgs::handshake::ClientExtension; |
22 | use crate::msgs::persist; |
23 | use crate::suites::{ExtractedSecrets, SupportedCipherSuite}; |
24 | use crate::sync::Arc; |
25 | #[cfg (feature = "std" )] |
26 | use crate::time_provider::DefaultTimeProvider; |
27 | use crate::time_provider::TimeProvider; |
28 | use crate::unbuffered::{EncryptError, TransmitTlsData}; |
29 | #[cfg (doc)] |
30 | use crate::{DistinguishedName, crypto}; |
31 | use crate::{KeyLog, WantsVersions, compress, sign, verify, versions}; |
32 | |
33 | /// A trait for the ability to store client session data, so that sessions |
34 | /// can be resumed in future connections. |
35 | /// |
36 | /// Generally all data in this interface should be treated as |
37 | /// **highly sensitive**, containing enough key material to break all security |
38 | /// of the corresponding session. |
39 | /// |
40 | /// `set_`, `insert_`, `remove_` and `take_` operations are mutating; this isn't |
41 | /// expressed in the type system to allow implementations freedom in |
42 | /// how to achieve interior mutability. `Mutex` is a common choice. |
43 | pub trait ClientSessionStore: fmt::Debug + Send + Sync { |
44 | /// Remember what `NamedGroup` the given server chose. |
45 | fn set_kx_hint(&self, server_name: ServerName<'static>, group: NamedGroup); |
46 | |
47 | /// This should return the value most recently passed to `set_kx_hint` |
48 | /// for the given `server_name`. |
49 | /// |
50 | /// If `None` is returned, the caller chooses the first configured group, |
51 | /// and an extra round trip might happen if that choice is unsatisfactory |
52 | /// to the server. |
53 | fn kx_hint(&self, server_name: &ServerName<'_>) -> Option<NamedGroup>; |
54 | |
55 | /// Remember a TLS1.2 session. |
56 | /// |
57 | /// At most one of these can be remembered at a time, per `server_name`. |
58 | fn set_tls12_session( |
59 | &self, |
60 | server_name: ServerName<'static>, |
61 | value: persist::Tls12ClientSessionValue, |
62 | ); |
63 | |
64 | /// Get the most recently saved TLS1.2 session for `server_name` provided to `set_tls12_session`. |
65 | fn tls12_session( |
66 | &self, |
67 | server_name: &ServerName<'_>, |
68 | ) -> Option<persist::Tls12ClientSessionValue>; |
69 | |
70 | /// Remove and forget any saved TLS1.2 session for `server_name`. |
71 | fn remove_tls12_session(&self, server_name: &ServerName<'static>); |
72 | |
73 | /// Remember a TLS1.3 ticket that might be retrieved later from `take_tls13_ticket`, allowing |
74 | /// resumption of this session. |
75 | /// |
76 | /// This can be called multiple times for a given session, allowing multiple independent tickets |
77 | /// to be valid at once. The number of times this is called is controlled by the server, so |
78 | /// implementations of this trait should apply a reasonable bound of how many items are stored |
79 | /// simultaneously. |
80 | fn insert_tls13_ticket( |
81 | &self, |
82 | server_name: ServerName<'static>, |
83 | value: persist::Tls13ClientSessionValue, |
84 | ); |
85 | |
86 | /// Return a TLS1.3 ticket previously provided to `add_tls13_ticket`. |
87 | /// |
88 | /// Implementations of this trait must return each value provided to `add_tls13_ticket` _at most once_. |
89 | fn take_tls13_ticket( |
90 | &self, |
91 | server_name: &ServerName<'static>, |
92 | ) -> Option<persist::Tls13ClientSessionValue>; |
93 | } |
94 | |
95 | /// A trait for the ability to choose a certificate chain and |
96 | /// private key for the purposes of client authentication. |
97 | pub trait ResolvesClientCert: fmt::Debug + Send + Sync { |
98 | /// Resolve a client certificate chain/private key to use as the client's |
99 | /// identity. |
100 | /// |
101 | /// `root_hint_subjects` is an optional list of certificate authority |
102 | /// subject distinguished names that the client can use to help |
103 | /// decide on a client certificate the server is likely to accept. If |
104 | /// the list is empty, the client should send whatever certificate it |
105 | /// has. The hints are expected to be DER-encoded X.500 distinguished names, |
106 | /// per [RFC 5280 A.1]. See [`DistinguishedName`] for more information |
107 | /// on decoding with external crates like `x509-parser`. |
108 | /// |
109 | /// `sigschemes` is the list of the [`SignatureScheme`]s the server |
110 | /// supports. |
111 | /// |
112 | /// Return `None` to continue the handshake without any client |
113 | /// authentication. The server may reject the handshake later |
114 | /// if it requires authentication. |
115 | /// |
116 | /// [RFC 5280 A.1]: https://www.rfc-editor.org/rfc/rfc5280#appendix-A.1 |
117 | fn resolve( |
118 | &self, |
119 | root_hint_subjects: &[&[u8]], |
120 | sigschemes: &[SignatureScheme], |
121 | ) -> Option<Arc<sign::CertifiedKey>>; |
122 | |
123 | /// Return true if the client only supports raw public keys. |
124 | /// |
125 | /// See [RFC 7250](https://www.rfc-editor.org/rfc/rfc7250). |
126 | fn only_raw_public_keys(&self) -> bool { |
127 | false |
128 | } |
129 | |
130 | /// Return true if any certificates at all are available. |
131 | fn has_certs(&self) -> bool; |
132 | } |
133 | |
134 | /// Common configuration for (typically) all connections made by a program. |
135 | /// |
136 | /// Making one of these is cheap, though one of the inputs may be expensive: gathering trust roots |
137 | /// from the operating system to add to the [`RootCertStore`] passed to `with_root_certificates()` |
138 | /// (the rustls-native-certs crate is often used for this) may take on the order of a few hundred |
139 | /// milliseconds. |
140 | /// |
141 | /// These must be created via the [`ClientConfig::builder()`] or [`ClientConfig::builder_with_provider()`] |
142 | /// function. |
143 | /// |
144 | /// Note that using [`ConfigBuilder<ClientConfig, WantsVersions>::with_ech()`] will produce a common |
145 | /// configuration specific to the provided [`crate::client::EchConfig`] that may not be appropriate |
146 | /// for all connections made by the program. In this case the configuration should only be shared |
147 | /// by connections intended for domains that offer the provided [`crate::client::EchConfig`] in |
148 | /// their DNS zone. |
149 | /// |
150 | /// # Defaults |
151 | /// |
152 | /// * [`ClientConfig::max_fragment_size`]: the default is `None` (meaning 16kB). |
153 | /// * [`ClientConfig::resumption`]: supports resumption with up to 256 server names, using session |
154 | /// ids or tickets, with a max of eight tickets per server. |
155 | /// * [`ClientConfig::alpn_protocols`]: the default is empty -- no ALPN protocol is negotiated. |
156 | /// * [`ClientConfig::key_log`]: key material is not logged. |
157 | /// * [`ClientConfig::cert_decompressors`]: depends on the crate features, see [`compress::default_cert_decompressors()`]. |
158 | /// * [`ClientConfig::cert_compressors`]: depends on the crate features, see [`compress::default_cert_compressors()`]. |
159 | /// * [`ClientConfig::cert_compression_cache`]: caches the most recently used 4 compressions |
160 | /// |
161 | /// [`RootCertStore`]: crate::RootCertStore |
162 | #[derive (Clone, Debug)] |
163 | pub struct ClientConfig { |
164 | /// Which ALPN protocols we include in our client hello. |
165 | /// If empty, no ALPN extension is sent. |
166 | pub alpn_protocols: Vec<Vec<u8>>, |
167 | |
168 | /// How and when the client can resume a previous session. |
169 | /// |
170 | /// # Sharing `resumption` between `ClientConfig`s |
171 | /// In a program using many `ClientConfig`s it may improve resumption rates |
172 | /// (which has a significant impact on connection performance) if those |
173 | /// configs share a single `Resumption`. |
174 | /// |
175 | /// However, resumption is only allowed between two `ClientConfig`s if their |
176 | /// `client_auth_cert_resolver` (ie, potential client authentication credentials) |
177 | /// and `verifier` (ie, server certificate verification settings) are |
178 | /// the same (according to `Arc::ptr_eq`). |
179 | /// |
180 | /// To illustrate, imagine two `ClientConfig`s `A` and `B`. `A` fully validates |
181 | /// the server certificate, `B` does not. If `A` and `B` shared a resumption store, |
182 | /// it would be possible for a session originated by `B` to be inserted into the |
183 | /// store, and then resumed by `A`. This would give a false impression to the user |
184 | /// of `A` that the server certificate is fully validated. |
185 | pub resumption: Resumption, |
186 | |
187 | /// The maximum size of plaintext input to be emitted in a single TLS record. |
188 | /// A value of None is equivalent to the [TLS maximum] of 16 kB. |
189 | /// |
190 | /// rustls enforces an arbitrary minimum of 32 bytes for this field. |
191 | /// Out of range values are reported as errors from [ClientConnection::new]. |
192 | /// |
193 | /// Setting this value to a little less than the TCP MSS may improve latency |
194 | /// for stream-y workloads. |
195 | /// |
196 | /// [TLS maximum]: https://datatracker.ietf.org/doc/html/rfc8446#section-5.1 |
197 | /// [ClientConnection::new]: crate::client::ClientConnection::new |
198 | pub max_fragment_size: Option<usize>, |
199 | |
200 | /// How to decide what client auth certificate/keys to use. |
201 | pub client_auth_cert_resolver: Arc<dyn ResolvesClientCert>, |
202 | |
203 | /// Whether to send the Server Name Indication (SNI) extension |
204 | /// during the client handshake. |
205 | /// |
206 | /// The default is true. |
207 | pub enable_sni: bool, |
208 | |
209 | /// How to output key material for debugging. The default |
210 | /// does nothing. |
211 | pub key_log: Arc<dyn KeyLog>, |
212 | |
213 | /// Allows traffic secrets to be extracted after the handshake, |
214 | /// e.g. for kTLS setup. |
215 | pub enable_secret_extraction: bool, |
216 | |
217 | /// Whether to send data on the first flight ("early data") in |
218 | /// TLS 1.3 handshakes. |
219 | /// |
220 | /// The default is false. |
221 | pub enable_early_data: bool, |
222 | |
223 | /// If set to `true`, requires the server to support the extended |
224 | /// master secret extraction method defined in [RFC 7627]. |
225 | /// |
226 | /// The default is `true` if the `fips` crate feature is enabled, |
227 | /// `false` otherwise. |
228 | /// |
229 | /// It must be set to `true` to meet FIPS requirement mentioned in section |
230 | /// **D.Q Transition of the TLS 1.2 KDF to Support the Extended Master |
231 | /// Secret** from [FIPS 140-3 IG.pdf]. |
232 | /// |
233 | /// [RFC 7627]: https://datatracker.ietf.org/doc/html/rfc7627 |
234 | /// [FIPS 140-3 IG.pdf]: https://csrc.nist.gov/csrc/media/Projects/cryptographic-module-validation-program/documents/fips%20140-3/FIPS%20140-3%20IG.pdf |
235 | #[cfg (feature = "tls12" )] |
236 | pub require_ems: bool, |
237 | |
238 | /// Provides the current system time |
239 | pub time_provider: Arc<dyn TimeProvider>, |
240 | |
241 | /// Source of randomness and other crypto. |
242 | pub(super) provider: Arc<CryptoProvider>, |
243 | |
244 | /// Supported versions, in no particular order. The default |
245 | /// is all supported versions. |
246 | pub(super) versions: versions::EnabledVersions, |
247 | |
248 | /// How to verify the server certificate chain. |
249 | pub(super) verifier: Arc<dyn verify::ServerCertVerifier>, |
250 | |
251 | /// How to decompress the server's certificate chain. |
252 | /// |
253 | /// If this is non-empty, the [RFC8779] certificate compression |
254 | /// extension is offered, and any compressed certificates are |
255 | /// transparently decompressed during the handshake. |
256 | /// |
257 | /// This only applies to TLS1.3 connections. It is ignored for |
258 | /// TLS1.2 connections. |
259 | /// |
260 | /// [RFC8779]: https://datatracker.ietf.org/doc/rfc8879/ |
261 | pub cert_decompressors: Vec<&'static dyn compress::CertDecompressor>, |
262 | |
263 | /// How to compress the client's certificate chain. |
264 | /// |
265 | /// If a server supports this extension, and advertises support |
266 | /// for one of the compression algorithms included here, the |
267 | /// client certificate will be compressed according to [RFC8779]. |
268 | /// |
269 | /// This only applies to TLS1.3 connections. It is ignored for |
270 | /// TLS1.2 connections. |
271 | /// |
272 | /// [RFC8779]: https://datatracker.ietf.org/doc/rfc8879/ |
273 | pub cert_compressors: Vec<&'static dyn compress::CertCompressor>, |
274 | |
275 | /// Caching for compressed certificates. |
276 | /// |
277 | /// This is optional: [`compress::CompressionCache::Disabled`] gives |
278 | /// a cache that does no caching. |
279 | pub cert_compression_cache: Arc<compress::CompressionCache>, |
280 | |
281 | /// How to offer Encrypted Client Hello (ECH). The default is to not offer ECH. |
282 | pub(super) ech_mode: Option<EchMode>, |
283 | } |
284 | |
285 | impl ClientConfig { |
286 | /// Create a builder for a client configuration with |
287 | /// [the process-default `CryptoProvider`][CryptoProvider#using-the-per-process-default-cryptoprovider] |
288 | /// and safe protocol version defaults. |
289 | /// |
290 | /// For more information, see the [`ConfigBuilder`] documentation. |
291 | #[cfg (feature = "std" )] |
292 | pub fn builder() -> ConfigBuilder<Self, WantsVerifier> { |
293 | Self::builder_with_protocol_versions(versions::DEFAULT_VERSIONS) |
294 | } |
295 | |
296 | /// Create a builder for a client configuration with |
297 | /// [the process-default `CryptoProvider`][CryptoProvider#using-the-per-process-default-cryptoprovider] |
298 | /// and the provided protocol versions. |
299 | /// |
300 | /// Panics if |
301 | /// - the supported versions are not compatible with the provider (eg. |
302 | /// the combination of ciphersuites supported by the provider and supported |
303 | /// versions lead to zero cipher suites being usable), |
304 | /// - if a `CryptoProvider` cannot be resolved using a combination of |
305 | /// the crate features and process default. |
306 | /// |
307 | /// For more information, see the [`ConfigBuilder`] documentation. |
308 | #[cfg (feature = "std" )] |
309 | pub fn builder_with_protocol_versions( |
310 | versions: &[&'static versions::SupportedProtocolVersion], |
311 | ) -> ConfigBuilder<Self, WantsVerifier> { |
312 | // Safety assumptions: |
313 | // 1. that the provider has been installed (explicitly or implicitly) |
314 | // 2. that the process-level default provider is usable with the supplied protocol versions. |
315 | Self::builder_with_provider(Arc::clone( |
316 | CryptoProvider::get_default_or_install_from_crate_features(), |
317 | )) |
318 | .with_protocol_versions(versions) |
319 | .unwrap() |
320 | } |
321 | |
322 | /// Create a builder for a client configuration with a specific [`CryptoProvider`]. |
323 | /// |
324 | /// This will use the provider's configured ciphersuites. You must additionally choose |
325 | /// which protocol versions to enable, using `with_protocol_versions` or |
326 | /// `with_safe_default_protocol_versions` and handling the `Result` in case a protocol |
327 | /// version is not supported by the provider's ciphersuites. |
328 | /// |
329 | /// For more information, see the [`ConfigBuilder`] documentation. |
330 | #[cfg (feature = "std" )] |
331 | pub fn builder_with_provider( |
332 | provider: Arc<CryptoProvider>, |
333 | ) -> ConfigBuilder<Self, WantsVersions> { |
334 | ConfigBuilder { |
335 | state: WantsVersions {}, |
336 | provider, |
337 | time_provider: Arc::new(DefaultTimeProvider), |
338 | side: PhantomData, |
339 | } |
340 | } |
341 | /// Create a builder for a client configuration with no default implementation details. |
342 | /// |
343 | /// This API must be used by `no_std` users. |
344 | /// |
345 | /// You must provide a specific [`TimeProvider`]. |
346 | /// |
347 | /// You must provide a specific [`CryptoProvider`]. |
348 | /// |
349 | /// This will use the provider's configured ciphersuites. You must additionally choose |
350 | /// which protocol versions to enable, using `with_protocol_versions` or |
351 | /// `with_safe_default_protocol_versions` and handling the `Result` in case a protocol |
352 | /// version is not supported by the provider's ciphersuites. |
353 | /// |
354 | /// For more information, see the [`ConfigBuilder`] documentation. |
355 | pub fn builder_with_details( |
356 | provider: Arc<CryptoProvider>, |
357 | time_provider: Arc<dyn TimeProvider>, |
358 | ) -> ConfigBuilder<Self, WantsVersions> { |
359 | ConfigBuilder { |
360 | state: WantsVersions {}, |
361 | provider, |
362 | time_provider, |
363 | side: PhantomData, |
364 | } |
365 | } |
366 | |
367 | /// Return true if connections made with this `ClientConfig` will |
368 | /// operate in FIPS mode. |
369 | /// |
370 | /// This is different from [`CryptoProvider::fips()`]: [`CryptoProvider::fips()`] |
371 | /// is concerned only with cryptography, whereas this _also_ covers TLS-level |
372 | /// configuration that NIST recommends, as well as ECH HPKE suites if applicable. |
373 | pub fn fips(&self) -> bool { |
374 | let mut is_fips = self.provider.fips(); |
375 | |
376 | #[cfg (feature = "tls12" )] |
377 | { |
378 | is_fips = is_fips && self.require_ems |
379 | } |
380 | |
381 | if let Some(ech_mode) = &self.ech_mode { |
382 | is_fips = is_fips && ech_mode.fips(); |
383 | } |
384 | |
385 | is_fips |
386 | } |
387 | |
388 | /// Return the crypto provider used to construct this client configuration. |
389 | pub fn crypto_provider(&self) -> &Arc<CryptoProvider> { |
390 | &self.provider |
391 | } |
392 | |
393 | /// Access configuration options whose use is dangerous and requires |
394 | /// extra care. |
395 | pub fn dangerous(&mut self) -> danger::DangerousClientConfig<'_> { |
396 | danger::DangerousClientConfig { cfg: self } |
397 | } |
398 | |
399 | /// We support a given TLS version if it's quoted in the configured |
400 | /// versions *and* at least one ciphersuite for this version is |
401 | /// also configured. |
402 | pub(crate) fn supports_version(&self, v: ProtocolVersion) -> bool { |
403 | self.versions.contains(v) |
404 | && self |
405 | .provider |
406 | .cipher_suites |
407 | .iter() |
408 | .any(|cs| cs.version().version == v) |
409 | } |
410 | |
411 | #[cfg (feature = "std" )] |
412 | pub(crate) fn supports_protocol(&self, proto: Protocol) -> bool { |
413 | self.provider |
414 | .cipher_suites |
415 | .iter() |
416 | .any(|cs| cs.usable_for_protocol(proto)) |
417 | } |
418 | |
419 | pub(super) fn find_cipher_suite(&self, suite: CipherSuite) -> Option<SupportedCipherSuite> { |
420 | self.provider |
421 | .cipher_suites |
422 | .iter() |
423 | .copied() |
424 | .find(|&scs| scs.suite() == suite) |
425 | } |
426 | |
427 | pub(super) fn find_kx_group( |
428 | &self, |
429 | group: NamedGroup, |
430 | version: ProtocolVersion, |
431 | ) -> Option<&'static dyn SupportedKxGroup> { |
432 | self.provider |
433 | .kx_groups |
434 | .iter() |
435 | .copied() |
436 | .find(|skxg| skxg.usable_for_version(version) && skxg.name() == group) |
437 | } |
438 | |
439 | pub(super) fn current_time(&self) -> Result<UnixTime, Error> { |
440 | self.time_provider |
441 | .current_time() |
442 | .ok_or(Error::FailedToGetCurrentTime) |
443 | } |
444 | } |
445 | |
446 | /// Configuration for how/when a client is allowed to resume a previous session. |
447 | #[derive (Clone, Debug)] |
448 | pub struct Resumption { |
449 | /// How we store session data or tickets. The default is to use an in-memory |
450 | /// [super::handy::ClientSessionMemoryCache]. |
451 | pub(super) store: Arc<dyn ClientSessionStore>, |
452 | |
453 | /// What mechanism is used for resuming a TLS 1.2 session. |
454 | pub(super) tls12_resumption: Tls12Resumption, |
455 | } |
456 | |
457 | impl Resumption { |
458 | /// Create a new `Resumption` that stores data for the given number of sessions in memory. |
459 | /// |
460 | /// This is the default `Resumption` choice, and enables resuming a TLS 1.2 session with |
461 | /// a session id or RFC 5077 ticket. |
462 | #[cfg (feature = "std" )] |
463 | pub fn in_memory_sessions(num: usize) -> Self { |
464 | Self { |
465 | store: Arc::new(super::handy::ClientSessionMemoryCache::new(num)), |
466 | tls12_resumption: Tls12Resumption::SessionIdOrTickets, |
467 | } |
468 | } |
469 | |
470 | /// Use a custom [`ClientSessionStore`] implementation to store sessions. |
471 | /// |
472 | /// By default, enables resuming a TLS 1.2 session with a session id or RFC 5077 ticket. |
473 | pub fn store(store: Arc<dyn ClientSessionStore>) -> Self { |
474 | Self { |
475 | store, |
476 | tls12_resumption: Tls12Resumption::SessionIdOrTickets, |
477 | } |
478 | } |
479 | |
480 | /// Disable all use of session resumption. |
481 | pub fn disabled() -> Self { |
482 | Self { |
483 | store: Arc::new(NoClientSessionStorage), |
484 | tls12_resumption: Tls12Resumption::Disabled, |
485 | } |
486 | } |
487 | |
488 | /// Configure whether TLS 1.2 sessions may be resumed, and by what mechanism. |
489 | /// |
490 | /// This is meaningless if you've disabled resumption entirely, which is the case in `no-std` |
491 | /// contexts. |
492 | pub fn tls12_resumption(mut self, tls12: Tls12Resumption) -> Self { |
493 | self.tls12_resumption = tls12; |
494 | self |
495 | } |
496 | } |
497 | |
498 | impl Default for Resumption { |
499 | /// Create an in-memory session store resumption with up to 256 server names, allowing |
500 | /// a TLS 1.2 session to resume with a session id or RFC 5077 ticket. |
501 | fn default() -> Self { |
502 | #[cfg (feature = "std" )] |
503 | let ret: Resumption = Self::in_memory_sessions(num:256); |
504 | |
505 | #[cfg (not(feature = "std" ))] |
506 | let ret = Self::disabled(); |
507 | |
508 | ret |
509 | } |
510 | } |
511 | |
512 | /// What mechanisms to support for resuming a TLS 1.2 session. |
513 | #[derive (Clone, Copy, Debug, PartialEq)] |
514 | pub enum Tls12Resumption { |
515 | /// Disable 1.2 resumption. |
516 | Disabled, |
517 | /// Support 1.2 resumption using session ids only. |
518 | SessionIdOnly, |
519 | /// Support 1.2 resumption using session ids or RFC 5077 tickets. |
520 | /// |
521 | /// See[^1] for why you might like to disable RFC 5077 by instead choosing the `SessionIdOnly` |
522 | /// option. Note that TLS 1.3 tickets do not have those issues. |
523 | /// |
524 | /// [^1]: <https://words.filippo.io/we-need-to-talk-about-session-tickets/> |
525 | SessionIdOrTickets, |
526 | } |
527 | |
528 | /// Container for unsafe APIs |
529 | pub(super) mod danger { |
530 | use super::ClientConfig; |
531 | use super::verify::ServerCertVerifier; |
532 | use crate::sync::Arc; |
533 | |
534 | /// Accessor for dangerous configuration options. |
535 | #[derive (Debug)] |
536 | pub struct DangerousClientConfig<'a> { |
537 | /// The underlying ClientConfig |
538 | pub cfg: &'a mut ClientConfig, |
539 | } |
540 | |
541 | impl DangerousClientConfig<'_> { |
542 | /// Overrides the default `ServerCertVerifier` with something else. |
543 | pub fn set_certificate_verifier(&mut self, verifier: Arc<dyn ServerCertVerifier>) { |
544 | self.cfg.verifier = verifier; |
545 | } |
546 | } |
547 | } |
548 | |
549 | #[derive (Debug, PartialEq)] |
550 | enum EarlyDataState { |
551 | Disabled, |
552 | Ready, |
553 | Accepted, |
554 | AcceptedFinished, |
555 | Rejected, |
556 | } |
557 | |
558 | #[derive (Debug)] |
559 | pub(super) struct EarlyData { |
560 | state: EarlyDataState, |
561 | left: usize, |
562 | } |
563 | |
564 | impl EarlyData { |
565 | fn new() -> Self { |
566 | Self { |
567 | left: 0, |
568 | state: EarlyDataState::Disabled, |
569 | } |
570 | } |
571 | |
572 | pub(super) fn is_enabled(&self) -> bool { |
573 | matches!(self.state, EarlyDataState::Ready | EarlyDataState::Accepted) |
574 | } |
575 | |
576 | #[cfg (feature = "std" )] |
577 | fn is_accepted(&self) -> bool { |
578 | matches!( |
579 | self.state, |
580 | EarlyDataState::Accepted | EarlyDataState::AcceptedFinished |
581 | ) |
582 | } |
583 | |
584 | pub(super) fn enable(&mut self, max_data: usize) { |
585 | assert_eq!(self.state, EarlyDataState::Disabled); |
586 | self.state = EarlyDataState::Ready; |
587 | self.left = max_data; |
588 | } |
589 | |
590 | pub(super) fn rejected(&mut self) { |
591 | trace!("EarlyData rejected" ); |
592 | self.state = EarlyDataState::Rejected; |
593 | } |
594 | |
595 | pub(super) fn accepted(&mut self) { |
596 | trace!("EarlyData accepted" ); |
597 | assert_eq!(self.state, EarlyDataState::Ready); |
598 | self.state = EarlyDataState::Accepted; |
599 | } |
600 | |
601 | pub(super) fn finished(&mut self) { |
602 | trace!("EarlyData finished" ); |
603 | self.state = match self.state { |
604 | EarlyDataState::Accepted => EarlyDataState::AcceptedFinished, |
605 | _ => panic!("bad EarlyData state" ), |
606 | } |
607 | } |
608 | |
609 | fn check_write_opt(&mut self, sz: usize) -> Option<usize> { |
610 | match self.state { |
611 | EarlyDataState::Disabled => unreachable!(), |
612 | EarlyDataState::Ready | EarlyDataState::Accepted => { |
613 | let take = if self.left < sz { |
614 | mem::replace(&mut self.left, 0) |
615 | } else { |
616 | self.left -= sz; |
617 | sz |
618 | }; |
619 | |
620 | Some(take) |
621 | } |
622 | EarlyDataState::Rejected | EarlyDataState::AcceptedFinished => None, |
623 | } |
624 | } |
625 | } |
626 | |
627 | #[cfg (feature = "std" )] |
628 | mod connection { |
629 | use alloc::vec::Vec; |
630 | use core::fmt; |
631 | use core::ops::{Deref, DerefMut}; |
632 | use std::io; |
633 | |
634 | use pki_types::ServerName; |
635 | |
636 | use super::ClientConnectionData; |
637 | use crate::ClientConfig; |
638 | use crate::client::EchStatus; |
639 | use crate::common_state::Protocol; |
640 | use crate::conn::{ConnectionCommon, ConnectionCore}; |
641 | use crate::error::Error; |
642 | use crate::suites::ExtractedSecrets; |
643 | use crate::sync::Arc; |
644 | |
645 | /// Stub that implements io::Write and dispatches to `write_early_data`. |
646 | pub struct WriteEarlyData<'a> { |
647 | sess: &'a mut ClientConnection, |
648 | } |
649 | |
650 | impl<'a> WriteEarlyData<'a> { |
651 | fn new(sess: &'a mut ClientConnection) -> Self { |
652 | WriteEarlyData { sess } |
653 | } |
654 | |
655 | /// How many bytes you may send. Writes will become short |
656 | /// once this reaches zero. |
657 | pub fn bytes_left(&self) -> usize { |
658 | self.sess |
659 | .inner |
660 | .core |
661 | .data |
662 | .early_data |
663 | .bytes_left() |
664 | } |
665 | } |
666 | |
667 | impl io::Write for WriteEarlyData<'_> { |
668 | fn write(&mut self, buf: &[u8]) -> io::Result<usize> { |
669 | self.sess.write_early_data(buf) |
670 | } |
671 | |
672 | fn flush(&mut self) -> io::Result<()> { |
673 | Ok(()) |
674 | } |
675 | } |
676 | |
677 | impl super::EarlyData { |
678 | fn check_write(&mut self, sz: usize) -> io::Result<usize> { |
679 | self.check_write_opt(sz) |
680 | .ok_or_else(|| io::Error::from(io::ErrorKind::InvalidInput)) |
681 | } |
682 | |
683 | fn bytes_left(&self) -> usize { |
684 | self.left |
685 | } |
686 | } |
687 | |
688 | /// This represents a single TLS client connection. |
689 | pub struct ClientConnection { |
690 | inner: ConnectionCommon<ClientConnectionData>, |
691 | } |
692 | |
693 | impl fmt::Debug for ClientConnection { |
694 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
695 | f.debug_struct("ClientConnection" ) |
696 | .finish() |
697 | } |
698 | } |
699 | |
700 | impl ClientConnection { |
701 | /// Make a new ClientConnection. `config` controls how |
702 | /// we behave in the TLS protocol, `name` is the |
703 | /// name of the server we want to talk to. |
704 | pub fn new(config: Arc<ClientConfig>, name: ServerName<'static>) -> Result<Self, Error> { |
705 | Ok(Self { |
706 | inner: ConnectionCore::for_client(config, name, Vec::new(), Protocol::Tcp)?.into(), |
707 | }) |
708 | } |
709 | |
710 | /// Returns an `io::Write` implementer you can write bytes to |
711 | /// to send TLS1.3 early data (a.k.a. "0-RTT data") to the server. |
712 | /// |
713 | /// This returns None in many circumstances when the capability to |
714 | /// send early data is not available, including but not limited to: |
715 | /// |
716 | /// - The server hasn't been talked to previously. |
717 | /// - The server does not support resumption. |
718 | /// - The server does not support early data. |
719 | /// - The resumption data for the server has expired. |
720 | /// |
721 | /// The server specifies a maximum amount of early data. You can |
722 | /// learn this limit through the returned object, and writes through |
723 | /// it will process only this many bytes. |
724 | /// |
725 | /// The server can choose not to accept any sent early data -- |
726 | /// in this case the data is lost but the connection continues. You |
727 | /// can tell this happened using `is_early_data_accepted`. |
728 | pub fn early_data(&mut self) -> Option<WriteEarlyData<'_>> { |
729 | if self |
730 | .inner |
731 | .core |
732 | .data |
733 | .early_data |
734 | .is_enabled() |
735 | { |
736 | Some(WriteEarlyData::new(self)) |
737 | } else { |
738 | None |
739 | } |
740 | } |
741 | |
742 | /// Returns True if the server signalled it will process early data. |
743 | /// |
744 | /// If you sent early data and this returns false at the end of the |
745 | /// handshake then the server will not process the data. This |
746 | /// is not an error, but you may wish to resend the data. |
747 | pub fn is_early_data_accepted(&self) -> bool { |
748 | self.inner.core.is_early_data_accepted() |
749 | } |
750 | |
751 | /// Extract secrets, so they can be used when configuring kTLS, for example. |
752 | /// Should be used with care as it exposes secret key material. |
753 | pub fn dangerous_extract_secrets(self) -> Result<ExtractedSecrets, Error> { |
754 | self.inner.dangerous_extract_secrets() |
755 | } |
756 | |
757 | /// Return the connection's Encrypted Client Hello (ECH) status. |
758 | pub fn ech_status(&self) -> EchStatus { |
759 | self.inner.core.data.ech_status |
760 | } |
761 | |
762 | /// Return true if the connection was made with a `ClientConfig` that is FIPS compatible. |
763 | /// |
764 | /// This is different from [`crate::crypto::CryptoProvider::fips()`]: |
765 | /// it is concerned only with cryptography, whereas this _also_ covers TLS-level |
766 | /// configuration that NIST recommends, as well as ECH HPKE suites if applicable. |
767 | pub fn fips(&self) -> bool { |
768 | self.inner.core.common_state.fips |
769 | } |
770 | |
771 | fn write_early_data(&mut self, data: &[u8]) -> io::Result<usize> { |
772 | self.inner |
773 | .core |
774 | .data |
775 | .early_data |
776 | .check_write(data.len()) |
777 | .map(|sz| { |
778 | self.inner |
779 | .send_early_plaintext(&data[..sz]) |
780 | }) |
781 | } |
782 | } |
783 | |
784 | impl Deref for ClientConnection { |
785 | type Target = ConnectionCommon<ClientConnectionData>; |
786 | |
787 | fn deref(&self) -> &Self::Target { |
788 | &self.inner |
789 | } |
790 | } |
791 | |
792 | impl DerefMut for ClientConnection { |
793 | fn deref_mut(&mut self) -> &mut Self::Target { |
794 | &mut self.inner |
795 | } |
796 | } |
797 | |
798 | #[doc (hidden)] |
799 | impl<'a> TryFrom<&'a mut crate::Connection> for &'a mut ClientConnection { |
800 | type Error = (); |
801 | |
802 | fn try_from(value: &'a mut crate::Connection) -> Result<Self, Self::Error> { |
803 | use crate::Connection::*; |
804 | match value { |
805 | Client(conn) => Ok(conn), |
806 | Server(_) => Err(()), |
807 | } |
808 | } |
809 | } |
810 | |
811 | impl From<ClientConnection> for crate::Connection { |
812 | fn from(conn: ClientConnection) -> Self { |
813 | Self::Client(conn) |
814 | } |
815 | } |
816 | } |
817 | #[cfg (feature = "std" )] |
818 | pub use connection::{ClientConnection, WriteEarlyData}; |
819 | |
820 | impl ConnectionCore<ClientConnectionData> { |
821 | pub(crate) fn for_client( |
822 | config: Arc<ClientConfig>, |
823 | name: ServerName<'static>, |
824 | extra_exts: Vec<ClientExtension>, |
825 | proto: Protocol, |
826 | ) -> Result<Self, Error> { |
827 | let mut common_state = CommonState::new(Side::Client); |
828 | common_state.set_max_fragment_size(config.max_fragment_size)?; |
829 | common_state.protocol = proto; |
830 | common_state.enable_secret_extraction = config.enable_secret_extraction; |
831 | common_state.fips = config.fips(); |
832 | let mut data = ClientConnectionData::new(); |
833 | |
834 | let mut cx = hs::ClientContext { |
835 | common: &mut common_state, |
836 | data: &mut data, |
837 | // `start_handshake` won't produce plaintext |
838 | sendable_plaintext: None, |
839 | }; |
840 | |
841 | let state = hs::start_handshake(name, extra_exts, config, &mut cx)?; |
842 | Ok(Self::new(state, data, common_state)) |
843 | } |
844 | |
845 | #[cfg (feature = "std" )] |
846 | pub(crate) fn is_early_data_accepted(&self) -> bool { |
847 | self.data.early_data.is_accepted() |
848 | } |
849 | } |
850 | |
851 | /// Unbuffered version of `ClientConnection` |
852 | /// |
853 | /// See the [`crate::unbuffered`] module docs for more details |
854 | pub struct UnbufferedClientConnection { |
855 | inner: UnbufferedConnectionCommon<ClientConnectionData>, |
856 | } |
857 | |
858 | impl UnbufferedClientConnection { |
859 | /// Make a new ClientConnection. `config` controls how we behave in the TLS protocol, `name` is |
860 | /// the name of the server we want to talk to. |
861 | pub fn new(config: Arc<ClientConfig>, name: ServerName<'static>) -> Result<Self, Error> { |
862 | Ok(Self { |
863 | inner: ConnectionCore::for_client(config, name, extra_exts:Vec::new(), proto:Protocol::Tcp)?.into(), |
864 | }) |
865 | } |
866 | |
867 | /// Extract secrets, so they can be used when configuring kTLS, for example. |
868 | /// Should be used with care as it exposes secret key material. |
869 | pub fn dangerous_extract_secrets(self) -> Result<ExtractedSecrets, Error> { |
870 | self.inner.dangerous_extract_secrets() |
871 | } |
872 | } |
873 | |
874 | impl Deref for UnbufferedClientConnection { |
875 | type Target = UnbufferedConnectionCommon<ClientConnectionData>; |
876 | |
877 | fn deref(&self) -> &Self::Target { |
878 | &self.inner |
879 | } |
880 | } |
881 | |
882 | impl DerefMut for UnbufferedClientConnection { |
883 | fn deref_mut(&mut self) -> &mut Self::Target { |
884 | &mut self.inner |
885 | } |
886 | } |
887 | |
888 | impl TransmitTlsData<'_, ClientConnectionData> { |
889 | /// returns an adapter that allows encrypting early (RTT-0) data before transmitting the |
890 | /// already encoded TLS data |
891 | /// |
892 | /// IF allowed by the protocol |
893 | pub fn may_encrypt_early_data(&mut self) -> Option<MayEncryptEarlyData<'_>> { |
894 | if self |
895 | .conn |
896 | .core |
897 | .data |
898 | .early_data |
899 | .is_enabled() |
900 | { |
901 | Some(MayEncryptEarlyData { conn: self.conn }) |
902 | } else { |
903 | None |
904 | } |
905 | } |
906 | } |
907 | |
908 | /// Allows encrypting early (RTT-0) data |
909 | pub struct MayEncryptEarlyData<'c> { |
910 | conn: &'c mut UnbufferedConnectionCommon<ClientConnectionData>, |
911 | } |
912 | |
913 | impl MayEncryptEarlyData<'_> { |
914 | /// Encrypts `application_data` into the `outgoing_tls` buffer |
915 | /// |
916 | /// returns the number of bytes that were written into `outgoing_tls`, or an error if |
917 | /// the provided buffer was too small. In the error case, `outgoing_tls` is not modified |
918 | pub fn encrypt( |
919 | &mut self, |
920 | early_data: &[u8], |
921 | outgoing_tls: &mut [u8], |
922 | ) -> Result<usize, EarlyDataError> { |
923 | let Some(allowed) = self |
924 | .conn |
925 | .core |
926 | .data |
927 | .early_data |
928 | .check_write_opt(early_data.len()) |
929 | else { |
930 | return Err(EarlyDataError::ExceededAllowedEarlyData); |
931 | }; |
932 | |
933 | self.conn |
934 | .core |
935 | .common_state |
936 | .write_plaintext(early_data[..allowed].into(), outgoing_tls) |
937 | .map_err(|e| e.into()) |
938 | } |
939 | } |
940 | |
941 | /// Errors that may arise when encrypting early (RTT-0) data |
942 | #[derive (Debug)] |
943 | pub enum EarlyDataError { |
944 | /// Cannot encrypt more early data due to imposed limits |
945 | ExceededAllowedEarlyData, |
946 | /// Encryption error |
947 | Encrypt(EncryptError), |
948 | } |
949 | |
950 | impl From<EncryptError> for EarlyDataError { |
951 | fn from(v: EncryptError) -> Self { |
952 | Self::Encrypt(v) |
953 | } |
954 | } |
955 | |
956 | impl fmt::Display for EarlyDataError { |
957 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
958 | match self { |
959 | Self::ExceededAllowedEarlyData => f.write_str(data:"cannot send any more early data" ), |
960 | Self::Encrypt(e: &EncryptError) => fmt::Display::fmt(self:e, f), |
961 | } |
962 | } |
963 | } |
964 | |
965 | #[cfg (feature = "std" )] |
966 | impl std::error::Error for EarlyDataError {} |
967 | |
968 | /// State associated with a client connection. |
969 | #[derive (Debug)] |
970 | pub struct ClientConnectionData { |
971 | pub(super) early_data: EarlyData, |
972 | pub(super) resumption_ciphersuite: Option<SupportedCipherSuite>, |
973 | pub(super) ech_status: EchStatus, |
974 | } |
975 | |
976 | impl ClientConnectionData { |
977 | fn new() -> Self { |
978 | Self { |
979 | early_data: EarlyData::new(), |
980 | resumption_ciphersuite: None, |
981 | ech_status: EchStatus::NotOffered, |
982 | } |
983 | } |
984 | } |
985 | |
986 | impl crate::conn::SideData for ClientConnectionData {} |
987 | |