diff options
Diffstat (limited to 'vendor/rustls/src/server/server_conn.rs')
| -rw-r--r-- | vendor/rustls/src/server/server_conn.rs | 1288 |
1 files changed, 1288 insertions, 0 deletions
diff --git a/vendor/rustls/src/server/server_conn.rs b/vendor/rustls/src/server/server_conn.rs new file mode 100644 index 00000000..d1024b14 --- /dev/null +++ b/vendor/rustls/src/server/server_conn.rs @@ -0,0 +1,1288 @@ +use alloc::boxed::Box; +use alloc::vec::Vec; +use core::fmt; +use core::fmt::{Debug, Formatter}; +use core::marker::PhantomData; +use core::ops::{Deref, DerefMut}; +#[cfg(feature = "std")] +use std::io; + +use pki_types::{DnsName, UnixTime}; + +use super::hs; +#[cfg(feature = "std")] +use crate::WantsVerifier; +use crate::builder::ConfigBuilder; +use crate::common_state::{CommonState, Side}; +#[cfg(feature = "std")] +use crate::common_state::{Protocol, State}; +use crate::conn::{ConnectionCommon, ConnectionCore, UnbufferedConnectionCommon}; +#[cfg(doc)] +use crate::crypto; +use crate::crypto::CryptoProvider; +use crate::enums::{CertificateType, CipherSuite, ProtocolVersion, SignatureScheme}; +use crate::error::Error; +use crate::kernel::KernelConnection; +use crate::log::trace; +use crate::msgs::base::Payload; +use crate::msgs::handshake::{ClientHelloPayload, ProtocolName, ServerExtensionsInput}; +use crate::msgs::message::Message; +use crate::suites::ExtractedSecrets; +use crate::sync::Arc; +#[cfg(feature = "std")] +use crate::time_provider::DefaultTimeProvider; +use crate::time_provider::TimeProvider; +use crate::vecbuf::ChunkVecBuffer; +use crate::{ + DistinguishedName, KeyLog, NamedGroup, WantsVersions, compress, sign, verify, versions, +}; + +/// A trait for the ability to store server session data. +/// +/// The keys and values are opaque. +/// +/// Inserted keys are randomly chosen by the library and have +/// no internal structure (in other words, you may rely on all +/// bits being uniformly random). Queried keys are untrusted data. +/// +/// Both the keys and values should be treated as +/// **highly sensitive data**, containing enough key material +/// to break all security of the corresponding sessions. +/// +/// Implementations can be lossy (in other words, forgetting +/// key/value pairs) without any negative security consequences. +/// +/// However, note that `take` **must** reliably delete a returned +/// value. If it does not, there may be security consequences. +/// +/// `put` and `take` are mutating operations; this isn't expressed +/// in the type system to allow implementations freedom in +/// how to achieve interior mutability. `Mutex` is a common +/// choice. +pub trait StoresServerSessions: Debug + Send + Sync { + /// Store session secrets encoded in `value` against `key`, + /// overwrites any existing value against `key`. Returns `true` + /// if the value was stored. + fn put(&self, key: Vec<u8>, value: Vec<u8>) -> bool; + + /// Find a value with the given `key`. Return it, or None + /// if it doesn't exist. + fn get(&self, key: &[u8]) -> Option<Vec<u8>>; + + /// Find a value with the given `key`. Return it and delete it; + /// or None if it doesn't exist. + fn take(&self, key: &[u8]) -> Option<Vec<u8>>; + + /// Whether the store can cache another session. This is used to indicate to clients + /// whether their session can be resumed; the implementation is not required to remember + /// a session even if it returns `true` here. + fn can_cache(&self) -> bool; +} + +/// A trait for the ability to encrypt and decrypt tickets. +pub trait ProducesTickets: Debug + Send + Sync { + /// Returns true if this implementation will encrypt/decrypt + /// tickets. Should return false if this is a dummy + /// implementation: the server will not send the SessionTicket + /// extension and will not call the other functions. + fn enabled(&self) -> bool; + + /// Returns the lifetime in seconds of tickets produced now. + /// The lifetime is provided as a hint to clients that the + /// ticket will not be useful after the given time. + /// + /// This lifetime must be implemented by key rolling and + /// erasure, *not* by storing a lifetime in the ticket. + /// + /// The objective is to limit damage to forward secrecy caused + /// by tickets, not just limiting their lifetime. + fn lifetime(&self) -> u32; + + /// Encrypt and authenticate `plain`, returning the resulting + /// ticket. Return None if `plain` cannot be encrypted for + /// some reason: an empty ticket will be sent and the connection + /// will continue. + fn encrypt(&self, plain: &[u8]) -> Option<Vec<u8>>; + + /// Decrypt `cipher`, validating its authenticity protection + /// and recovering the plaintext. `cipher` is fully attacker + /// controlled, so this decryption must be side-channel free, + /// panic-proof, and otherwise bullet-proof. If the decryption + /// fails, return None. + fn decrypt(&self, cipher: &[u8]) -> Option<Vec<u8>>; +} + +/// How to choose a certificate chain and signing key for use +/// in server authentication. +/// +/// This is suitable when selecting a certificate does not require +/// I/O or when the application is using blocking I/O anyhow. +/// +/// For applications that use async I/O and need to do I/O to choose +/// a certificate (for instance, fetching a certificate from a data store), +/// the [`Acceptor`] interface is more suitable. +pub trait ResolvesServerCert: Debug + Send + Sync { + /// Choose a certificate chain and matching key given simplified + /// ClientHello information. + /// + /// Return `None` to abort the handshake. + fn resolve(&self, client_hello: ClientHello<'_>) -> Option<Arc<sign::CertifiedKey>>; + + /// Return true when the server only supports raw public keys. + fn only_raw_public_keys(&self) -> bool { + false + } +} + +/// A struct representing the received Client Hello +#[derive(Debug)] +pub struct ClientHello<'a> { + pub(super) server_name: &'a Option<DnsName<'a>>, + pub(super) signature_schemes: &'a [SignatureScheme], + pub(super) alpn: Option<&'a Vec<ProtocolName>>, + pub(super) server_cert_types: Option<&'a [CertificateType]>, + pub(super) client_cert_types: Option<&'a [CertificateType]>, + pub(super) cipher_suites: &'a [CipherSuite], + /// The [certificate_authorities] extension, if it was sent by the client. + /// + /// [certificate_authorities]: https://datatracker.ietf.org/doc/html/rfc8446#section-4.2.4 + pub(super) certificate_authorities: Option<&'a [DistinguishedName]>, + pub(super) named_groups: Option<&'a [NamedGroup]>, +} + +impl<'a> ClientHello<'a> { + /// Get the server name indicator. + /// + /// Returns `None` if the client did not supply a SNI. + pub fn server_name(&self) -> Option<&str> { + self.server_name + .as_ref() + .map(<DnsName<'_> as AsRef<str>>::as_ref) + } + + /// Get the compatible signature schemes. + /// + /// Returns standard-specified default if the client omitted this extension. + pub fn signature_schemes(&self) -> &[SignatureScheme] { + self.signature_schemes + } + + /// Get the ALPN protocol identifiers submitted by the client. + /// + /// Returns `None` if the client did not include an ALPN extension. + /// + /// Application Layer Protocol Negotiation (ALPN) is a TLS extension that lets a client + /// submit a set of identifiers that each a represent an application-layer protocol. + /// The server will then pick its preferred protocol from the set submitted by the client. + /// Each identifier is represented as a byte array, although common values are often ASCII-encoded. + /// See the official RFC-7301 specifications at <https://datatracker.ietf.org/doc/html/rfc7301> + /// for more information on ALPN. + /// + /// For example, a HTTP client might specify "http/1.1" and/or "h2". Other well-known values + /// are listed in the at IANA registry at + /// <https://www.iana.org/assignments/tls-extensiontype-values/tls-extensiontype-values.xhtml#alpn-protocol-ids>. + /// + /// The server can specify supported ALPN protocols by setting [`ServerConfig::alpn_protocols`]. + /// During the handshake, the server will select the first protocol configured that the client supports. + pub fn alpn(&self) -> Option<impl Iterator<Item = &'a [u8]>> { + self.alpn.map(|protocols| { + protocols + .iter() + .map(|proto| proto.as_ref()) + }) + } + + /// Get cipher suites. + pub fn cipher_suites(&self) -> &[CipherSuite] { + self.cipher_suites + } + + /// Get the server certificate types offered in the ClientHello. + /// + /// Returns `None` if the client did not include a certificate type extension. + pub fn server_cert_types(&self) -> Option<&'a [CertificateType]> { + self.server_cert_types + } + + /// Get the client certificate types offered in the ClientHello. + /// + /// Returns `None` if the client did not include a certificate type extension. + pub fn client_cert_types(&self) -> Option<&'a [CertificateType]> { + self.client_cert_types + } + + /// Get the [certificate_authorities] extension sent by the client. + /// + /// Returns `None` if the client did not send this extension. + /// + /// [certificate_authorities]: https://datatracker.ietf.org/doc/html/rfc8446#section-4.2.4 + pub fn certificate_authorities(&self) -> Option<&'a [DistinguishedName]> { + self.certificate_authorities + } + + /// Get the [`named_groups`] extension sent by the client. + /// + /// This means different things in different versions of TLS: + /// + /// Originally it was introduced as the "[`elliptic_curves`]" extension for TLS1.2. + /// It described the elliptic curves supported by a client for all purposes: key + /// exchange, signature verification (for server authentication), and signing (for + /// client auth). Later [RFC7919] extended this to include FFDHE "named groups", + /// but FFDHE groups in this context only relate to key exchange. + /// + /// In TLS1.3 it was renamed to "[`named_groups`]" and now describes all types + /// of key exchange mechanisms, and does not relate at all to elliptic curves + /// used for signatures. + /// + /// [`elliptic_curves`]: https://datatracker.ietf.org/doc/html/rfc4492#section-5.1.1 + /// [RFC7919]: https://datatracker.ietf.org/doc/html/rfc7919#section-2 + /// [`named_groups`]:https://datatracker.ietf.org/doc/html/rfc8446#section-4.2.7 + pub fn named_groups(&self) -> Option<&'a [NamedGroup]> { + self.named_groups + } +} + +/// Common configuration for a set of server sessions. +/// +/// Making one of these is cheap, though one of the inputs may be expensive: gathering trust roots +/// from the operating system to add to the [`RootCertStore`] passed to a `ClientCertVerifier` +/// builder may take on the order of a few hundred milliseconds. +/// +/// These must be created via the [`ServerConfig::builder()`] or [`ServerConfig::builder_with_provider()`] +/// function. +/// +/// # Defaults +/// +/// * [`ServerConfig::max_fragment_size`]: the default is `None` (meaning 16kB). +/// * [`ServerConfig::session_storage`]: if the `std` feature is enabled, the default stores 256 +/// sessions in memory. If the `std` feature is not enabled, the default is to not store any +/// sessions. In a no-std context, by enabling the `hashbrown` feature you may provide your +/// own `session_storage` using [`ServerSessionMemoryCache`] and a `crate::lock::MakeMutex` +/// implementation. +/// * [`ServerConfig::alpn_protocols`]: the default is empty -- no ALPN protocol is negotiated. +/// * [`ServerConfig::key_log`]: key material is not logged. +/// * [`ServerConfig::send_tls13_tickets`]: 2 tickets are sent. +/// * [`ServerConfig::cert_compressors`]: depends on the crate features, see [`compress::default_cert_compressors()`]. +/// * [`ServerConfig::cert_compression_cache`]: caches the most recently used 4 compressions +/// * [`ServerConfig::cert_decompressors`]: depends on the crate features, see [`compress::default_cert_decompressors()`]. +/// +/// # Sharing resumption storage between `ServerConfig`s +/// +/// In a program using many `ServerConfig`s it may improve resumption rates +/// (which has a significant impact on connection performance) if those +/// configs share [`ServerConfig::session_storage`] or [`ServerConfig::ticketer`]. +/// +/// However, caution is needed: other fields influence the security of a session +/// and resumption between them can be surprising. If sharing +/// [`ServerConfig::session_storage`] or [`ServerConfig::ticketer`] between two +/// `ServerConfig`s, you should also evaluate the following fields and ensure +/// they are equivalent: +/// +/// * `ServerConfig::verifier` -- client authentication requirements, +/// * [`ServerConfig::cert_resolver`] -- server identities. +/// +/// To illustrate, imagine two `ServerConfig`s `A` and `B`. `A` requires +/// client authentication, `B` does not. If `A` and `B` shared a resumption store, +/// it would be possible for a session originated by `B` (that is, an unauthenticated client) +/// to be inserted into the store, and then resumed by `A`. This would give a false +/// impression to the user of `A` that the client was authenticated. This is possible +/// whether the resumption is performed statefully (via [`ServerConfig::session_storage`]) +/// or statelessly (via [`ServerConfig::ticketer`]). +/// +/// _Unlike_ `ClientConfig`, rustls does not enforce any policy here. +/// +/// [`RootCertStore`]: crate::RootCertStore +/// [`ServerSessionMemoryCache`]: crate::server::handy::ServerSessionMemoryCache +#[derive(Clone, Debug)] +pub struct ServerConfig { + /// Source of randomness and other crypto. + pub(super) provider: Arc<CryptoProvider>, + + /// Ignore the client's ciphersuite order. Instead, + /// choose the top ciphersuite in the server list + /// which is supported by the client. + pub ignore_client_order: bool, + + /// The maximum size of plaintext input to be emitted in a single TLS record. + /// A value of None is equivalent to the [TLS maximum] of 16 kB. + /// + /// rustls enforces an arbitrary minimum of 32 bytes for this field. + /// Out of range values are reported as errors from [ServerConnection::new]. + /// + /// Setting this value to a little less than the TCP MSS may improve latency + /// for stream-y workloads. + /// + /// [TLS maximum]: https://datatracker.ietf.org/doc/html/rfc8446#section-5.1 + /// [ServerConnection::new]: crate::server::ServerConnection::new + pub max_fragment_size: Option<usize>, + + /// How to store client sessions. + /// + /// See [ServerConfig#sharing-resumption-storage-between-serverconfigs] + /// for a warning related to this field. + pub session_storage: Arc<dyn StoresServerSessions>, + + /// How to produce tickets. + /// + /// See [ServerConfig#sharing-resumption-storage-between-serverconfigs] + /// for a warning related to this field. + pub ticketer: Arc<dyn ProducesTickets>, + + /// How to choose a server cert and key. This is usually set by + /// [ConfigBuilder::with_single_cert] or [ConfigBuilder::with_cert_resolver]. + /// For async applications, see also [Acceptor]. + pub cert_resolver: Arc<dyn ResolvesServerCert>, + + /// Protocol names we support, most preferred first. + /// If empty we don't do ALPN at all. + pub alpn_protocols: Vec<Vec<u8>>, + + /// Supported protocol versions, in no particular order. + /// The default is all supported versions. + pub(super) versions: versions::EnabledVersions, + + /// How to verify client certificates. + pub(super) verifier: Arc<dyn verify::ClientCertVerifier>, + + /// How to output key material for debugging. The default + /// does nothing. + pub key_log: Arc<dyn KeyLog>, + + /// Allows traffic secrets to be extracted after the handshake, + /// e.g. for kTLS setup. + pub enable_secret_extraction: bool, + + /// Amount of early data to accept for sessions created by + /// this config. Specify 0 to disable early data. The + /// default is 0. + /// + /// Read the early data via [`ServerConnection::early_data`]. + /// + /// The units for this are _both_ plaintext bytes, _and_ ciphertext + /// bytes, depending on whether the server accepts a client's early_data + /// or not. It is therefore recommended to include some slop in + /// this value to account for the unknown amount of ciphertext + /// expansion in the latter case. + pub max_early_data_size: u32, + + /// Whether the server should send "0.5RTT" data. This means the server + /// sends data after its first flight of handshake messages, without + /// waiting for the client to complete the handshake. + /// + /// This can improve TTFB latency for either server-speaks-first protocols, + /// or client-speaks-first protocols when paired with "0RTT" data. This + /// comes at the cost of a subtle weakening of the normal handshake + /// integrity guarantees that TLS provides. Note that the initial + /// `ClientHello` is indirectly authenticated because it is included + /// in the transcript used to derive the keys used to encrypt the data. + /// + /// This only applies to TLS1.3 connections. TLS1.2 connections cannot + /// do this optimisation and this setting is ignored for them. It is + /// also ignored for TLS1.3 connections that even attempt client + /// authentication. + /// + /// This defaults to false. This means the first application data + /// sent by the server comes after receiving and validating the client's + /// handshake up to the `Finished` message. This is the safest option. + pub send_half_rtt_data: bool, + + /// How many TLS1.3 tickets to send immediately after a successful + /// handshake. + /// + /// Because TLS1.3 tickets are single-use, this allows + /// a client to perform multiple resumptions. + /// + /// The default is 2. + /// + /// If this is 0, no tickets are sent and clients will not be able to + /// do any resumption. + pub send_tls13_tickets: usize, + + /// If set to `true`, requires the client to support the extended + /// master secret extraction method defined in [RFC 7627]. + /// + /// The default is `true` if the "fips" crate feature is enabled, + /// `false` otherwise. + /// + /// It must be set to `true` to meet FIPS requirement mentioned in section + /// **D.Q Transition of the TLS 1.2 KDF to Support the Extended Master + /// Secret** from [FIPS 140-3 IG.pdf]. + /// + /// [RFC 7627]: https://datatracker.ietf.org/doc/html/rfc7627 + /// [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 + #[cfg(feature = "tls12")] + pub require_ems: bool, + + /// Provides the current system time + pub time_provider: Arc<dyn TimeProvider>, + + /// How to compress the server's certificate chain. + /// + /// If a client supports this extension, and advertises support + /// for one of the compression algorithms included here, the + /// server certificate will be compressed according to [RFC8779]. + /// + /// This only applies to TLS1.3 connections. It is ignored for + /// TLS1.2 connections. + /// + /// [RFC8779]: https://datatracker.ietf.org/doc/rfc8879/ + pub cert_compressors: Vec<&'static dyn compress::CertCompressor>, + + /// Caching for compressed certificates. + /// + /// This is optional: [`compress::CompressionCache::Disabled`] gives + /// a cache that does no caching. + pub cert_compression_cache: Arc<compress::CompressionCache>, + + /// How to decompress the clients's certificate chain. + /// + /// If this is non-empty, the [RFC8779] certificate compression + /// extension is offered when requesting client authentication, + /// and any compressed certificates are transparently decompressed + /// during the handshake. + /// + /// This only applies to TLS1.3 connections. It is ignored for + /// TLS1.2 connections. + /// + /// [RFC8779]: https://datatracker.ietf.org/doc/rfc8879/ + pub cert_decompressors: Vec<&'static dyn compress::CertDecompressor>, +} + +impl ServerConfig { + /// Create a builder for a server configuration with + /// [the process-default `CryptoProvider`][CryptoProvider#using-the-per-process-default-cryptoprovider] + /// and safe protocol version defaults. + /// + /// For more information, see the [`ConfigBuilder`] documentation. + #[cfg(feature = "std")] + pub fn builder() -> ConfigBuilder<Self, WantsVerifier> { + Self::builder_with_protocol_versions(versions::DEFAULT_VERSIONS) + } + + /// Create a builder for a server configuration with + /// [the process-default `CryptoProvider`][CryptoProvider#using-the-per-process-default-cryptoprovider] + /// and the provided protocol versions. + /// + /// Panics if + /// - the supported versions are not compatible with the provider (eg. + /// the combination of ciphersuites supported by the provider and supported + /// versions lead to zero cipher suites being usable), + /// - if a `CryptoProvider` cannot be resolved using a combination of + /// the crate features and process default. + /// + /// For more information, see the [`ConfigBuilder`] documentation. + #[cfg(feature = "std")] + pub fn builder_with_protocol_versions( + versions: &[&'static versions::SupportedProtocolVersion], + ) -> ConfigBuilder<Self, WantsVerifier> { + // Safety assumptions: + // 1. that the provider has been installed (explicitly or implicitly) + // 2. that the process-level default provider is usable with the supplied protocol versions. + Self::builder_with_provider( + CryptoProvider::get_default_or_install_from_crate_features().clone(), + ) + .with_protocol_versions(versions) + .unwrap() + } + + /// Create a builder for a server configuration with a specific [`CryptoProvider`]. + /// + /// This will use the provider's configured ciphersuites. You must additionally choose + /// which protocol versions to enable, using `with_protocol_versions` or + /// `with_safe_default_protocol_versions` and handling the `Result` in case a protocol + /// version is not supported by the provider's ciphersuites. + /// + /// For more information, see the [`ConfigBuilder`] documentation. + #[cfg(feature = "std")] + pub fn builder_with_provider( + provider: Arc<CryptoProvider>, + ) -> ConfigBuilder<Self, WantsVersions> { + ConfigBuilder { + state: WantsVersions {}, + provider, + time_provider: Arc::new(DefaultTimeProvider), + side: PhantomData, + } + } + + /// Create a builder for a server configuration with no default implementation details. + /// + /// This API must be used by `no_std` users. + /// + /// You must provide a specific [`TimeProvider`]. + /// + /// You must provide a specific [`CryptoProvider`]. + /// + /// This will use the provider's configured ciphersuites. You must additionally choose + /// which protocol versions to enable, using `with_protocol_versions` or + /// `with_safe_default_protocol_versions` and handling the `Result` in case a protocol + /// version is not supported by the provider's ciphersuites. + /// + /// For more information, see the [`ConfigBuilder`] documentation. + pub fn builder_with_details( + provider: Arc<CryptoProvider>, + time_provider: Arc<dyn TimeProvider>, + ) -> ConfigBuilder<Self, WantsVersions> { + ConfigBuilder { + state: WantsVersions {}, + provider, + time_provider, + side: PhantomData, + } + } + + /// Return `true` if connections made with this `ServerConfig` will + /// operate in FIPS mode. + /// + /// This is different from [`CryptoProvider::fips()`]: [`CryptoProvider::fips()`] + /// is concerned only with cryptography, whereas this _also_ covers TLS-level + /// configuration that NIST recommends. + pub fn fips(&self) -> bool { + #[cfg(feature = "tls12")] + { + self.provider.fips() && self.require_ems + } + + #[cfg(not(feature = "tls12"))] + { + self.provider.fips() + } + } + + /// Return the crypto provider used to construct this client configuration. + pub fn crypto_provider(&self) -> &Arc<CryptoProvider> { + &self.provider + } + + /// We support a given TLS version if it's quoted in the configured + /// versions *and* at least one ciphersuite for this version is + /// also configured. + pub(crate) fn supports_version(&self, v: ProtocolVersion) -> bool { + self.versions.contains(v) + && self + .provider + .cipher_suites + .iter() + .any(|cs| cs.version().version == v) + } + + #[cfg(feature = "std")] + pub(crate) fn supports_protocol(&self, proto: Protocol) -> bool { + self.provider + .cipher_suites + .iter() + .any(|cs| cs.usable_for_protocol(proto)) + } + + pub(super) fn current_time(&self) -> Result<UnixTime, Error> { + self.time_provider + .current_time() + .ok_or(Error::FailedToGetCurrentTime) + } +} + +#[cfg(feature = "std")] +mod connection { + use alloc::boxed::Box; + use core::fmt; + use core::fmt::{Debug, Formatter}; + use core::ops::{Deref, DerefMut}; + use std::io; + + use super::{ + Accepted, Accepting, EarlyDataState, ServerConfig, ServerConnectionData, + ServerExtensionsInput, + }; + use crate::common_state::{CommonState, Context, Side}; + use crate::conn::{ConnectionCommon, ConnectionCore}; + use crate::error::Error; + use crate::server::hs; + use crate::suites::ExtractedSecrets; + use crate::sync::Arc; + use crate::vecbuf::ChunkVecBuffer; + + /// Allows reading of early data in resumed TLS1.3 connections. + /// + /// "Early data" is also known as "0-RTT data". + /// + /// This structure implements [`std::io::Read`]. + pub struct ReadEarlyData<'a> { + early_data: &'a mut EarlyDataState, + } + + impl<'a> ReadEarlyData<'a> { + fn new(early_data: &'a mut EarlyDataState) -> Self { + ReadEarlyData { early_data } + } + } + + impl io::Read for ReadEarlyData<'_> { + fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { + self.early_data.read(buf) + } + + #[cfg(read_buf)] + fn read_buf(&mut self, cursor: core::io::BorrowedCursor<'_>) -> io::Result<()> { + self.early_data.read_buf(cursor) + } + } + + /// This represents a single TLS server connection. + /// + /// Send TLS-protected data to the peer using the `io::Write` trait implementation. + /// Read data from the peer using the `io::Read` trait implementation. + pub struct ServerConnection { + pub(super) inner: ConnectionCommon<ServerConnectionData>, + } + + impl ServerConnection { + /// Make a new ServerConnection. `config` controls how + /// we behave in the TLS protocol. + pub fn new(config: Arc<ServerConfig>) -> Result<Self, Error> { + Ok(Self { + inner: ConnectionCommon::from(ConnectionCore::for_server( + config, + ServerExtensionsInput::default(), + )?), + }) + } + + /// Retrieves the server name, if any, used to select the certificate and + /// private key. + /// + /// This returns `None` until some time after the client's server name indication + /// (SNI) extension value is processed during the handshake. It will never be + /// `None` when the connection is ready to send or process application data, + /// unless the client does not support SNI. + /// + /// This is useful for application protocols that need to enforce that the + /// server name matches an application layer protocol hostname. For + /// example, HTTP/1.1 servers commonly expect the `Host:` header field of + /// every request on a connection to match the hostname in the SNI extension + /// when the client provides the SNI extension. + /// + /// The server name is also used to match sessions during session resumption. + pub fn server_name(&self) -> Option<&str> { + self.inner.core.get_sni_str() + } + + /// Application-controlled portion of the resumption ticket supplied by the client, if any. + /// + /// Recovered from the prior session's `set_resumption_data`. Integrity is guaranteed by rustls. + /// + /// Returns `Some` if and only if a valid resumption ticket has been received from the client. + pub fn received_resumption_data(&self) -> Option<&[u8]> { + self.inner + .core + .data + .received_resumption_data + .as_ref() + .map(|x| &x[..]) + } + + /// Set the resumption data to embed in future resumption tickets supplied to the client. + /// + /// Defaults to the empty byte string. Must be less than 2^15 bytes to allow room for other + /// data. Should be called while `is_handshaking` returns true to ensure all transmitted + /// resumption tickets are affected. + /// + /// Integrity will be assured by rustls, but the data will be visible to the client. If secrecy + /// from the client is desired, encrypt the data separately. + pub fn set_resumption_data(&mut self, data: &[u8]) { + assert!(data.len() < 2usize.pow(15)); + self.inner.core.data.resumption_data = data.into(); + } + + /// Explicitly discard early data, notifying the client + /// + /// Useful if invariants encoded in `received_resumption_data()` cannot be respected. + /// + /// Must be called while `is_handshaking` is true. + pub fn reject_early_data(&mut self) { + self.inner.core.reject_early_data() + } + + /// Returns an `io::Read` implementer you can read bytes from that are + /// received from a client as TLS1.3 0RTT/"early" data, during the handshake. + /// + /// This returns `None` in many circumstances, such as : + /// + /// - Early data is disabled if [`ServerConfig::max_early_data_size`] is zero (the default). + /// - The session negotiated with the client is not TLS1.3. + /// - The client just doesn't support early data. + /// - The connection doesn't resume an existing session. + /// - The client hasn't sent a full ClientHello yet. + pub fn early_data(&mut self) -> Option<ReadEarlyData<'_>> { + let data = &mut self.inner.core.data; + if data.early_data.was_accepted() { + Some(ReadEarlyData::new(&mut data.early_data)) + } else { + None + } + } + + /// Return true if the connection was made with a `ServerConfig` that is FIPS compatible. + /// + /// This is different from [`crate::crypto::CryptoProvider::fips()`]: + /// it is concerned only with cryptography, whereas this _also_ covers TLS-level + /// configuration that NIST recommends, as well as ECH HPKE suites if applicable. + pub fn fips(&self) -> bool { + self.inner.core.common_state.fips + } + + /// Extract secrets, so they can be used when configuring kTLS, for example. + /// Should be used with care as it exposes secret key material. + pub fn dangerous_extract_secrets(self) -> Result<ExtractedSecrets, Error> { + self.inner.dangerous_extract_secrets() + } + } + + impl Debug for ServerConnection { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("ServerConnection") + .finish() + } + } + + impl Deref for ServerConnection { + type Target = ConnectionCommon<ServerConnectionData>; + + fn deref(&self) -> &Self::Target { + &self.inner + } + } + + impl DerefMut for ServerConnection { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner + } + } + + impl From<ServerConnection> for crate::Connection { + fn from(conn: ServerConnection) -> Self { + Self::Server(conn) + } + } + + /// Handle a server-side connection before configuration is available. + /// + /// `Acceptor` allows the caller to choose a [`ServerConfig`] after reading + /// the [`super::ClientHello`] of an incoming connection. This is useful for servers + /// that choose different certificates or cipher suites based on the + /// characteristics of the `ClientHello`. In particular it is useful for + /// servers that need to do some I/O to load a certificate and its private key + /// and don't want to use the blocking interface provided by + /// [`super::ResolvesServerCert`]. + /// + /// Create an Acceptor with [`Acceptor::default()`]. + /// + /// # Example + /// + /// ```no_run + /// # #[cfg(feature = "aws_lc_rs")] { + /// # fn choose_server_config( + /// # _: rustls::server::ClientHello, + /// # ) -> std::sync::Arc<rustls::ServerConfig> { + /// # unimplemented!(); + /// # } + /// # #[allow(unused_variables)] + /// # fn main() { + /// use rustls::server::{Acceptor, ServerConfig}; + /// let listener = std::net::TcpListener::bind("127.0.0.1:0").unwrap(); + /// for stream in listener.incoming() { + /// let mut stream = stream.unwrap(); + /// let mut acceptor = Acceptor::default(); + /// let accepted = loop { + /// acceptor.read_tls(&mut stream).unwrap(); + /// if let Some(accepted) = acceptor.accept().unwrap() { + /// break accepted; + /// } + /// }; + /// + /// // For some user-defined choose_server_config: + /// let config = choose_server_config(accepted.client_hello()); + /// let conn = accepted + /// .into_connection(config) + /// .unwrap(); + /// + /// // Proceed with handling the ServerConnection. + /// } + /// # } + /// # } + /// ``` + pub struct Acceptor { + inner: Option<ConnectionCommon<ServerConnectionData>>, + } + + impl Default for Acceptor { + /// Return an empty Acceptor, ready to receive bytes from a new client connection. + fn default() -> Self { + Self { + inner: Some( + ConnectionCore::new( + Box::new(Accepting), + ServerConnectionData::default(), + CommonState::new(Side::Server), + ) + .into(), + ), + } + } + } + + impl Acceptor { + /// Read TLS content from `rd`. + /// + /// Returns an error if this `Acceptor` has already yielded an [`Accepted`]. For more details, + /// refer to [`Connection::read_tls()`]. + /// + /// [`Connection::read_tls()`]: crate::Connection::read_tls + pub fn read_tls(&mut self, rd: &mut dyn io::Read) -> Result<usize, io::Error> { + match &mut self.inner { + Some(conn) => conn.read_tls(rd), + None => Err(io::Error::new( + io::ErrorKind::Other, + "acceptor cannot read after successful acceptance", + )), + } + } + + /// Check if a `ClientHello` message has been received. + /// + /// Returns `Ok(None)` if the complete `ClientHello` has not yet been received. + /// Do more I/O and then call this function again. + /// + /// Returns `Ok(Some(accepted))` if the connection has been accepted. Call + /// `accepted.into_connection()` to continue. Do not call this function again. + /// + /// Returns `Err((err, alert))` if an error occurred. If an alert is returned, the + /// application should call `alert.write()` to send the alert to the client. It should + /// not call `accept()` again. + pub fn accept(&mut self) -> Result<Option<Accepted>, (Error, AcceptedAlert)> { + let Some(mut connection) = self.inner.take() else { + return Err(( + Error::General("Acceptor polled after completion".into()), + AcceptedAlert::empty(), + )); + }; + + let message = match connection.first_handshake_message() { + Ok(Some(msg)) => msg, + Ok(None) => { + self.inner = Some(connection); + return Ok(None); + } + Err(err) => return Err((err, AcceptedAlert::from(connection))), + }; + + let mut cx = Context::from(&mut connection); + let sig_schemes = match hs::process_client_hello(&message, false, &mut cx) { + Ok((_, sig_schemes)) => sig_schemes, + Err(err) => { + return Err((err, AcceptedAlert::from(connection))); + } + }; + + Ok(Some(Accepted { + connection, + message, + sig_schemes, + })) + } + } + + /// Represents a TLS alert resulting from handling the client's `ClientHello` message. + /// + /// When [`Acceptor::accept()`] returns an error, it yields an `AcceptedAlert` such that the + /// application can communicate failure to the client via [`AcceptedAlert::write()`]. + pub struct AcceptedAlert(ChunkVecBuffer); + + impl AcceptedAlert { + pub(super) fn empty() -> Self { + Self(ChunkVecBuffer::new(None)) + } + + /// Send the alert to the client. + /// + /// To account for short writes this function should be called repeatedly until it + /// returns `Ok(0)` or an error. + pub fn write(&mut self, wr: &mut dyn io::Write) -> Result<usize, io::Error> { + self.0.write_to(wr) + } + + /// Send the alert to the client. + /// + /// This function will invoke the writer until the buffer is empty. + pub fn write_all(&mut self, wr: &mut dyn io::Write) -> Result<(), io::Error> { + while self.write(wr)? != 0 {} + Ok(()) + } + } + + impl From<ConnectionCommon<ServerConnectionData>> for AcceptedAlert { + fn from(conn: ConnectionCommon<ServerConnectionData>) -> Self { + Self(conn.core.common_state.sendable_tls) + } + } + + impl Debug for AcceptedAlert { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("AcceptedAlert").finish() + } + } +} + +#[cfg(feature = "std")] +pub use connection::{AcceptedAlert, Acceptor, ReadEarlyData, ServerConnection}; + +/// Unbuffered version of `ServerConnection` +/// +/// See the [`crate::unbuffered`] module docs for more details +pub struct UnbufferedServerConnection { + inner: UnbufferedConnectionCommon<ServerConnectionData>, +} + +impl UnbufferedServerConnection { + /// Make a new ServerConnection. `config` controls how we behave in the TLS protocol. + pub fn new(config: Arc<ServerConfig>) -> Result<Self, Error> { + Ok(Self { + inner: UnbufferedConnectionCommon::from(ConnectionCore::for_server( + config, + ServerExtensionsInput::default(), + )?), + }) + } + + /// Extract secrets, so they can be used when configuring kTLS, for example. + /// Should be used with care as it exposes secret key material. + #[deprecated = "dangerous_extract_secrets() does not support session tickets or \ + key updates, use dangerous_into_kernel_connection() instead"] + pub fn dangerous_extract_secrets(self) -> Result<ExtractedSecrets, Error> { + self.inner.dangerous_extract_secrets() + } + + /// Extract secrets and an [`KernelConnection`] object. + /// + /// This allows you use rustls to manage keys and then manage encryption and + /// decryption yourself (e.g. for kTLS). + /// + /// Should be used with care as it exposes secret key material. + /// + /// See the [`crate::kernel`] documentations for details on prerequisites + /// for calling this method. + pub fn dangerous_into_kernel_connection( + self, + ) -> Result<(ExtractedSecrets, KernelConnection<ServerConnectionData>), Error> { + self.inner + .core + .dangerous_into_kernel_connection() + } +} + +impl Deref for UnbufferedServerConnection { + type Target = UnbufferedConnectionCommon<ServerConnectionData>; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +impl DerefMut for UnbufferedServerConnection { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.inner + } +} + +impl UnbufferedConnectionCommon<ServerConnectionData> { + pub(crate) fn pop_early_data(&mut self) -> Option<Vec<u8>> { + self.core.data.early_data.pop() + } + + pub(crate) fn peek_early_data(&self) -> Option<&[u8]> { + self.core.data.early_data.peek() + } +} + +/// Represents a `ClientHello` message received through the [`Acceptor`]. +/// +/// Contains the state required to resume the connection through [`Accepted::into_connection()`]. +pub struct Accepted { + connection: ConnectionCommon<ServerConnectionData>, + message: Message<'static>, + sig_schemes: Vec<SignatureScheme>, +} + +impl Accepted { + /// Get the [`ClientHello`] for this connection. + pub fn client_hello(&self) -> ClientHello<'_> { + let payload = Self::client_hello_payload(&self.message); + let ch = ClientHello { + server_name: &self.connection.core.data.sni, + signature_schemes: &self.sig_schemes, + alpn: payload.protocols.as_ref(), + server_cert_types: payload + .server_certificate_types + .as_deref(), + client_cert_types: payload + .client_certificate_types + .as_deref(), + cipher_suites: &payload.cipher_suites, + certificate_authorities: payload + .certificate_authority_names + .as_deref(), + named_groups: payload.named_groups.as_deref(), + }; + + trace!("Accepted::client_hello(): {ch:#?}"); + ch + } + + /// Convert the [`Accepted`] into a [`ServerConnection`]. + /// + /// Takes the state returned from [`Acceptor::accept()`] as well as the [`ServerConfig`] and + /// [`sign::CertifiedKey`] that should be used for the session. Returns an error if + /// configuration-dependent validation of the received `ClientHello` message fails. + #[cfg(feature = "std")] + pub fn into_connection( + mut self, + config: Arc<ServerConfig>, + ) -> Result<ServerConnection, (Error, AcceptedAlert)> { + if let Err(err) = self + .connection + .set_max_fragment_size(config.max_fragment_size) + { + // We have a connection here, but it won't contain an alert since the error + // is with the fragment size configured in the `ServerConfig`. + return Err((err, AcceptedAlert::empty())); + } + + self.connection.enable_secret_extraction = config.enable_secret_extraction; + + let state = hs::ExpectClientHello::new(config, ServerExtensionsInput::default()); + let mut cx = hs::ServerContext::from(&mut self.connection); + + let ch = Self::client_hello_payload(&self.message); + let new = match state.with_certified_key(self.sig_schemes, ch, &self.message, &mut cx) { + Ok(new) => new, + Err(err) => return Err((err, AcceptedAlert::from(self.connection))), + }; + + self.connection.replace_state(new); + Ok(ServerConnection { + inner: self.connection, + }) + } + + fn client_hello_payload<'a>(message: &'a Message<'_>) -> &'a ClientHelloPayload { + match &message.payload { + crate::msgs::message::MessagePayload::Handshake { parsed, .. } => match &parsed.0 { + crate::msgs::handshake::HandshakePayload::ClientHello(ch) => ch, + _ => unreachable!(), + }, + _ => unreachable!(), + } + } +} + +impl Debug for Accepted { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + f.debug_struct("Accepted").finish() + } +} + +#[cfg(feature = "std")] +struct Accepting; + +#[cfg(feature = "std")] +impl State<ServerConnectionData> for Accepting { + fn handle<'m>( + self: Box<Self>, + _cx: &mut hs::ServerContext<'_>, + _m: Message<'m>, + ) -> Result<Box<dyn State<ServerConnectionData> + 'm>, Error> + where + Self: 'm, + { + Err(Error::General("unreachable state".into())) + } + + fn into_owned(self: Box<Self>) -> hs::NextState<'static> { + self + } +} + +pub(super) enum EarlyDataState { + New, + Accepted { + received: ChunkVecBuffer, + left: usize, + }, + Rejected, +} + +impl Default for EarlyDataState { + fn default() -> Self { + Self::New + } +} + +impl EarlyDataState { + pub(super) fn reject(&mut self) { + *self = Self::Rejected; + } + + pub(super) fn accept(&mut self, max_size: usize) { + *self = Self::Accepted { + received: ChunkVecBuffer::new(Some(max_size)), + left: max_size, + }; + } + + #[cfg(feature = "std")] + fn was_accepted(&self) -> bool { + matches!(self, Self::Accepted { .. }) + } + + pub(super) fn was_rejected(&self) -> bool { + matches!(self, Self::Rejected) + } + + fn peek(&self) -> Option<&[u8]> { + match self { + Self::Accepted { received, .. } => received.peek(), + _ => None, + } + } + + fn pop(&mut self) -> Option<Vec<u8>> { + match self { + Self::Accepted { received, .. } => received.pop(), + _ => None, + } + } + + #[cfg(feature = "std")] + fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { + match self { + Self::Accepted { received, .. } => received.read(buf), + _ => Err(io::Error::from(io::ErrorKind::BrokenPipe)), + } + } + + #[cfg(read_buf)] + fn read_buf(&mut self, cursor: core::io::BorrowedCursor<'_>) -> io::Result<()> { + match self { + Self::Accepted { received, .. } => received.read_buf(cursor), + _ => Err(io::Error::from(io::ErrorKind::BrokenPipe)), + } + } + + pub(super) fn take_received_plaintext(&mut self, bytes: Payload<'_>) -> bool { + let available = bytes.bytes().len(); + let Self::Accepted { received, left } = self else { + return false; + }; + + if received.apply_limit(available) != available || available > *left { + return false; + } + + received.append(bytes.into_vec()); + *left -= available; + true + } +} + +impl Debug for EarlyDataState { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + Self::New => write!(f, "EarlyDataState::New"), + Self::Accepted { received, left } => write!( + f, + "EarlyDataState::Accepted {{ received: {}, left: {} }}", + received.len(), + left + ), + Self::Rejected => write!(f, "EarlyDataState::Rejected"), + } + } +} + +impl ConnectionCore<ServerConnectionData> { + pub(crate) fn for_server( + config: Arc<ServerConfig>, + extra_exts: ServerExtensionsInput<'static>, + ) -> Result<Self, Error> { + let mut common = CommonState::new(Side::Server); + common.set_max_fragment_size(config.max_fragment_size)?; + common.enable_secret_extraction = config.enable_secret_extraction; + common.fips = config.fips(); + Ok(Self::new( + Box::new(hs::ExpectClientHello::new(config, extra_exts)), + ServerConnectionData::default(), + common, + )) + } + + #[cfg(feature = "std")] + pub(crate) fn reject_early_data(&mut self) { + assert!( + self.common_state.is_handshaking(), + "cannot retroactively reject early data" + ); + self.data.early_data.reject(); + } + + #[cfg(feature = "std")] + pub(crate) fn get_sni_str(&self) -> Option<&str> { + self.data.get_sni_str() + } +} + +/// State associated with a server connection. +#[derive(Default, Debug)] +pub struct ServerConnectionData { + pub(super) sni: Option<DnsName<'static>>, + pub(super) received_resumption_data: Option<Vec<u8>>, + pub(super) resumption_data: Vec<u8>, + pub(super) early_data: EarlyDataState, +} + +impl ServerConnectionData { + #[cfg(feature = "std")] + pub(super) fn get_sni_str(&self) -> Option<&str> { + self.sni.as_ref().map(AsRef::as_ref) + } +} + +impl crate::conn::SideData for ServerConnectionData {} + +#[cfg(feature = "std")] +#[cfg(test)] +mod tests { + use std::format; + + use super::*; + + // these branches not reachable externally, unless something else goes wrong. + #[test] + fn test_read_in_new_state() { + assert_eq!( + format!("{:?}", EarlyDataState::default().read(&mut [0u8; 5])), + "Err(Kind(BrokenPipe))" + ); + } + + #[cfg(read_buf)] + #[test] + fn test_read_buf_in_new_state() { + use core::io::BorrowedBuf; + + let mut buf = [0u8; 5]; + let mut buf: BorrowedBuf<'_> = buf.as_mut_slice().into(); + assert_eq!( + format!("{:?}", EarlyDataState::default().read_buf(buf.unfilled())), + "Err(Kind(BrokenPipe))" + ); + } +} |
