use crate::msgs::enums::CipherSuite; use crate::msgs::enums::{AlertDescription, HandshakeType}; use crate::session::{Session, SessionCommon}; use crate::keylog::{KeyLog, NoKeyLog}; use crate::suites::{SupportedCipherSuite, ALL_CIPHERSUITES}; use crate::msgs::handshake::CertificatePayload; use crate::msgs::enums::SignatureScheme; use crate::msgs::enums::{ContentType, ProtocolVersion}; use crate::msgs::handshake::ClientExtension; use crate::msgs::message::Message; use crate::verify; use crate::anchors; use crate::sign; use crate::error::TLSError; use crate::key; use crate::vecbuf::WriteV; #[cfg(feature = "logging")] use crate::log::trace; use std::sync::Arc; use std::io; use std::fmt; use std::mem; use sct; use webpki; #[macro_use] mod hs; mod tls12; mod tls13; mod common; pub mod handy; /// A trait for the ability to store client session data. /// The keys and values are opaque. /// /// Both the keys and values should be treated as /// **highly sensitive data**, containing enough key material /// to break all security of the corresponding session. /// /// `put` is a mutating operation; 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 StoresClientSessions : Send + Sync { /// Stores a new `value` for `key`. Returns `true` /// if the value was stored. fn put(&self, key: Vec, value: Vec) -> bool; /// Returns the latest value for `key`. Returns `None` /// if there's no such value. fn get(&self, key: &[u8]) -> Option>; } /// A trait for the ability to choose a certificate chain and /// private key for the purposes of client authentication. pub trait ResolvesClientCert : Send + Sync { /// With the server-supplied acceptable issuers in `acceptable_issuers`, /// the server's supported signature schemes in `sigschemes`, /// return a certificate chain and signing key to authenticate. /// /// `acceptable_issuers` is undecoded and unverified by the rustls /// library, but it should be expected to contain a DER encodings /// of X501 NAMEs. /// /// Return None to continue the handshake without any client /// authentication. The server may reject the handshake later /// if it requires authentication. fn resolve(&self, acceptable_issuers: &[&[u8]], sigschemes: &[SignatureScheme]) -> Option; /// Return true if any certificates at all are available. fn has_certs(&self) -> bool; } /// Common configuration for (typically) all connections made by /// a program. /// /// Making one of these can be expensive, and should be /// once per process rather than once per connection. #[derive(Clone)] pub struct ClientConfig { /// List of ciphersuites, in preference order. pub ciphersuites: Vec<&'static SupportedCipherSuite>, /// Collection of root certificates. pub root_store: anchors::RootCertStore, /// Which ALPN protocols we include in our client hello. /// If empty, no ALPN extension is sent. pub alpn_protocols: Vec>, /// How we store session data or tickets. pub session_persistence: Arc, /// Our MTU. If None, we don't limit TLS message sizes. pub mtu: Option, /// How to decide what client auth certificate/keys to use. pub client_auth_cert_resolver: Arc, /// Whether to support RFC5077 tickets. You must provide a working /// `session_persistence` member for this to have any meaningful /// effect. /// /// The default is true. pub enable_tickets: bool, /// Supported versions, in no particular order. The default /// is all supported versions. pub versions: Vec, /// Collection of certificate transparency logs. /// If this collection is empty, then certificate transparency /// checking is disabled. pub ct_logs: Option<&'static [&'static sct::Log<'static>]>, /// Whether to send the Server Name Indication (SNI) extension /// during the client handshake. /// /// The default is true. pub enable_sni: bool, /// How to verify the server certificate chain. verifier: Arc, /// How to output key material for debugging. The default /// does nothing. pub key_log: Arc, /// Whether to send data on the first flight ("early data") in /// TLS 1.3 handshakes. /// /// The default is false. pub enable_early_data: bool, } impl Default for ClientConfig { fn default() -> Self { Self::new() } } impl ClientConfig { /// Make a `ClientConfig` with a default set of ciphersuites, /// no root certificates, no ALPN protocols, and no client auth. /// /// The default session persistence provider stores up to 32 /// items in memory. pub fn new() -> ClientConfig { ClientConfig { ciphersuites: ALL_CIPHERSUITES.to_vec(), root_store: anchors::RootCertStore::empty(), alpn_protocols: Vec::new(), session_persistence: handy::ClientSessionMemoryCache::new(32), mtu: None, client_auth_cert_resolver: Arc::new(handy::FailResolveClientCert {}), enable_tickets: true, versions: vec![ProtocolVersion::TLSv1_3, ProtocolVersion::TLSv1_2], ct_logs: None, enable_sni: true, verifier: Arc::new(verify::WebPKIVerifier::new()), key_log: Arc::new(NoKeyLog {}), enable_early_data: false, } } #[doc(hidden)] /// 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 fn supports_version(&self, v: ProtocolVersion) -> bool { self.versions.contains(&v) && self.ciphersuites.iter().any(|cs| cs.usable_for_version(v)) } #[doc(hidden)] pub fn get_verifier(&self) -> &dyn verify::ServerCertVerifier { self.verifier.as_ref() } /// Set the ALPN protocol list to the given protocol names. /// Overwrites any existing configured protocols. /// The first element in the `protocols` list is the most /// preferred, the last is the least preferred. pub fn set_protocols(&mut self, protocols: &[Vec]) { self.alpn_protocols.clear(); self.alpn_protocols.extend_from_slice(protocols); } /// Sets persistence layer to `persist`. pub fn set_persistence(&mut self, persist: Arc) { self.session_persistence = persist; } /// Sets MTU to `mtu`. If None, the default is used. /// If Some(x) then x must be greater than 5 bytes. pub fn set_mtu(&mut self, mtu: &Option) { // Internally our MTU relates to fragment size, and does // not include the TLS header overhead. // // Externally the MTU is the whole packet size. The difference // is PACKET_OVERHEAD. if let Some(x) = *mtu { use crate::msgs::fragmenter; debug_assert!(x > fragmenter::PACKET_OVERHEAD); self.mtu = Some(x - fragmenter::PACKET_OVERHEAD); } else { self.mtu = None; } } /// Sets a single client authentication certificate and private key. /// This is blindly used for all servers that ask for client auth. /// /// `cert_chain` is a vector of DER-encoded certificates, /// `key_der` is a DER-encoded RSA or ECDSA private key. pub fn set_single_client_cert(&mut self, cert_chain: Vec, key_der: key::PrivateKey) { let resolver = handy::AlwaysResolvesClientCert::new(cert_chain, &key_der); self.client_auth_cert_resolver = Arc::new(resolver); } /// Access configuration options whose use is dangerous and requires /// extra care. #[cfg(feature = "dangerous_configuration")] pub fn dangerous(&mut self) -> danger::DangerousClientConfig { danger::DangerousClientConfig { cfg: self } } } /// Container for unsafe APIs #[cfg(feature = "dangerous_configuration")] pub mod danger { use std::sync::Arc; use super::ClientConfig; use super::verify::ServerCertVerifier; /// Accessor for dangerous configuration options. pub struct DangerousClientConfig<'a> { /// The underlying ClientConfig pub cfg: &'a mut ClientConfig } impl<'a> DangerousClientConfig<'a> { /// Overrides the default `ServerCertVerifier` with something else. pub fn set_certificate_verifier(&mut self, verifier: Arc) { self.cfg.verifier = verifier; } } } #[derive(Debug, PartialEq)] enum EarlyDataState { Disabled, Ready, Accepted, AcceptedFinished, Rejected, } pub struct EarlyData { state: EarlyDataState, left: usize, } impl EarlyData { fn new() -> EarlyData { EarlyData { left: 0, state: EarlyDataState::Disabled, } } fn is_enabled(&self) -> bool { match self.state { EarlyDataState::Ready | EarlyDataState::Accepted => true, _ => false } } fn is_accepted(&self) -> bool { match self.state { EarlyDataState::Accepted | EarlyDataState::AcceptedFinished => true, _ => false } } fn enable(&mut self, max_data: usize) { assert_eq!(self.state, EarlyDataState::Disabled); self.state = EarlyDataState::Ready; self.left = max_data; } fn rejected(&mut self) { trace!("EarlyData rejected"); self.state = EarlyDataState::Rejected; } fn accepted(&mut self) { trace!("EarlyData accepted"); assert_eq!(self.state, EarlyDataState::Ready); self.state = EarlyDataState::Accepted; } fn finished(&mut self) { trace!("EarlyData finished"); self.state = match self.state { EarlyDataState::Accepted => EarlyDataState::AcceptedFinished, _ => panic!("bad EarlyData state"), } } fn check_write(&mut self, sz: usize) -> io::Result { match self.state { EarlyDataState::Disabled => unreachable!(), EarlyDataState::Ready | EarlyDataState::Accepted => { let take = if self.left < sz { mem::replace(&mut self.left, 0) } else { self.left -= sz; sz }; Ok(take) }, EarlyDataState::Rejected | EarlyDataState::AcceptedFinished => { Err(io::Error::from(io::ErrorKind::InvalidInput)) }, } } fn bytes_left(&self) -> usize { self.left } } /// Stub that implements io::Write and dispatches to `write_early_data`. pub struct WriteEarlyData<'a> { sess: &'a mut ClientSessionImpl, } impl<'a> WriteEarlyData<'a> { fn new(sess: &'a mut ClientSessionImpl) -> WriteEarlyData<'a> { WriteEarlyData { sess } } /// How many bytes you may send. Writes will become short /// once this reaches zero. pub fn bytes_left(&self) -> usize { self.sess.early_data.bytes_left() } } impl<'a> io::Write for WriteEarlyData<'a> { fn write(&mut self, buf: &[u8]) -> io::Result { self.sess.write_early_data(buf) } fn flush(&mut self) -> io::Result<()> { Ok(()) } } pub struct ClientSessionImpl { pub config: Arc, pub alpn_protocol: Option>, pub common: SessionCommon, pub error: Option, pub state: Option>, pub server_cert_chain: CertificatePayload, pub early_data: EarlyData, pub resumption_ciphersuite: Option<&'static SupportedCipherSuite>, } impl fmt::Debug for ClientSessionImpl { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_struct("ClientSessionImpl").finish() } } impl ClientSessionImpl { pub fn new(config: &Arc) -> ClientSessionImpl { ClientSessionImpl { config: config.clone(), alpn_protocol: None, common: SessionCommon::new(config.mtu, true), error: None, state: None, server_cert_chain: Vec::new(), early_data: EarlyData::new(), resumption_ciphersuite: None, } } pub fn start_handshake(&mut self, hostname: webpki::DNSName, extra_exts: Vec) { self.state = Some(hs::start_handshake(self, hostname, extra_exts)); } pub fn get_cipher_suites(&self) -> Vec { let mut ret = Vec::new(); for cs in &self.config.ciphersuites { ret.push(cs.suite); } // We don't do renegotation at all, in fact. ret.push(CipherSuite::TLS_EMPTY_RENEGOTIATION_INFO_SCSV); ret } pub fn find_cipher_suite(&self, suite: CipherSuite) -> Option<&'static SupportedCipherSuite> { for scs in &self.config.ciphersuites { if scs.suite == suite { return Some(scs); } } None } pub fn wants_read(&self) -> bool { // We want to read more data all the time, except when we // have unprocessed plaintext. This provides back-pressure // to the TCP buffers. // // This also covers the handshake case, because we don't have // readable plaintext before handshake has completed. !self.common.has_readable_plaintext() } pub fn wants_write(&self) -> bool { !self.common.sendable_tls.is_empty() } pub fn is_handshaking(&self) -> bool { !self.common.traffic } pub fn set_buffer_limit(&mut self, len: usize) { self.common.set_buffer_limit(len) } pub fn process_msg(&mut self, mut msg: Message) -> Result<(), TLSError> { // TLS1.3: drop CCS at any time during handshaking if self.common.is_tls13() && msg.is_content_type(ContentType::ChangeCipherSpec) && self.is_handshaking() { trace!("Dropping CCS"); return Ok(()); } // Decrypt if demanded by current state. if self.common.peer_encrypting { let dm = self.common.decrypt_incoming(msg)?; msg = dm; } // For handshake messages, we need to join them before parsing // and processing. if self.common.handshake_joiner.want_message(&msg) { self.common .handshake_joiner .take_message(msg) .ok_or_else(|| { self.common.send_fatal_alert(AlertDescription::DecodeError); TLSError::CorruptMessagePayload(ContentType::Handshake) })?; return self.process_new_handshake_messages(); } // Now we can fully parse the message payload. if !msg.decode_payload() { return Err(TLSError::CorruptMessagePayload(msg.typ)); } // For alerts, we have separate logic. if msg.is_content_type(ContentType::Alert) { return self.common.process_alert(msg); } self.process_main_protocol(msg) } pub fn process_new_handshake_messages(&mut self) -> Result<(), TLSError> { while let Some(msg) = self.common.handshake_joiner.frames.pop_front() { self.process_main_protocol(msg)?; } Ok(()) } fn queue_unexpected_alert(&mut self) { self.common.send_fatal_alert(AlertDescription::UnexpectedMessage); } fn reject_renegotiation_attempt(&mut self) -> Result<(), TLSError> { self.common.send_warning_alert(AlertDescription::NoRenegotiation); Ok(()) } /// Process `msg`. First, we get the current state. Then we ask what messages /// that state expects, enforced via a `Expectation`. Finally, we ask the handler /// to handle the message. fn process_main_protocol(&mut self, msg: Message) -> Result<(), TLSError> { // For TLS1.2, outside of the handshake, send rejection alerts for // renegotation requests. These can occur any time. if msg.is_handshake_type(HandshakeType::HelloRequest) && !self.common.is_tls13() && !self.is_handshaking() { return self.reject_renegotiation_attempt(); } let state = self.state.take().unwrap(); state .check_message(&msg) .map_err(|err| { self.queue_unexpected_alert(); err })?; self.state = Some(state.handle(self, msg)?); Ok(()) } pub fn process_new_packets(&mut self) -> Result<(), TLSError> { if let Some(ref err) = self.error { return Err(err.clone()); } if self.common.message_deframer.desynced { return Err(TLSError::CorruptMessage); } while let Some(msg) = self.common.message_deframer.frames.pop_front() { match self.process_msg(msg) { Ok(_) => {} Err(err) => { self.error = Some(err.clone()); return Err(err); } } } Ok(()) } pub fn get_peer_certificates(&self) -> Option> { if self.server_cert_chain.is_empty() { return None; } let mut r = Vec::new(); for cert in &self.server_cert_chain { r.push(cert.clone()); } Some(r) } pub fn get_alpn_protocol(&self) -> Option<&[u8]> { self.alpn_protocol.as_ref().map(AsRef::as_ref) } pub fn get_protocol_version(&self) -> Option { self.common.negotiated_version } pub fn get_negotiated_ciphersuite(&self) -> Option<&'static SupportedCipherSuite> { self.common.get_suite() } pub fn write_early_data(&mut self, data: &[u8]) -> io::Result { self.early_data.check_write(data.len()) .and_then(|sz| { self.common.send_early_plaintext(&data[..sz]) }) } } /// This represents a single TLS client session. #[derive(Debug)] pub struct ClientSession { // We use the pimpl idiom to hide unimportant details. pub(crate) imp: ClientSessionImpl, } impl ClientSession { /// Make a new ClientSession. `config` controls how /// we behave in the TLS protocol, `hostname` is the /// hostname of who we want to talk to. pub fn new(config: &Arc, hostname: webpki::DNSNameRef) -> ClientSession { let mut imp = ClientSessionImpl::new(config); imp.start_handshake(hostname.into(), vec![]); ClientSession { imp } } /// Returns an `io::Write` implementor you can write bytes to /// to send TLS1.3 early data (a.k.a. "0-RTT data") to the server. /// /// This returns None in many circumstances when the capability to /// send early data is not available, including but not limited to: /// /// - The server hasn't been talked to previously. /// - The server does not support resumption. /// - The server does not support early data. /// - The resumption data for the server has expired. /// /// The server specifies a maximum amount of early data. You can /// learn this limit through the returned object, and writes through /// it will process only this many bytes. /// /// The server can choose not to accept any sent early data -- /// in this case the data is lost but the connection continues. You /// can tell this happened using `is_early_data_accepted`. pub fn early_data(&mut self) -> Option { if self.imp.early_data.is_enabled() { Some(WriteEarlyData::new(&mut self.imp)) } else { None } } /// Returns True if the server signalled it will process early data. /// /// If you sent early data and this returns false at the end of the /// handshake then the server will not process the data. This /// is not an error, but you may wish to resend the data. pub fn is_early_data_accepted(&self) -> bool { self.imp.early_data.is_accepted() } } impl Session for ClientSession { fn read_tls(&mut self, rd: &mut dyn io::Read) -> io::Result { self.imp.common.read_tls(rd) } /// Writes TLS messages to `wr`. fn write_tls(&mut self, wr: &mut dyn io::Write) -> io::Result { self.imp.common.write_tls(wr) } fn writev_tls(&mut self, wr: &mut dyn WriteV) -> io::Result { self.imp.common.writev_tls(wr) } fn process_new_packets(&mut self) -> Result<(), TLSError> { self.imp.process_new_packets() } fn wants_read(&self) -> bool { self.imp.wants_read() } fn wants_write(&self) -> bool { self.imp.wants_write() } fn is_handshaking(&self) -> bool { self.imp.is_handshaking() } fn set_buffer_limit(&mut self, len: usize) { self.imp.set_buffer_limit(len) } fn send_close_notify(&mut self) { self.imp.common.send_close_notify() } fn get_peer_certificates(&self) -> Option> { self.imp.get_peer_certificates() } fn get_alpn_protocol(&self) -> Option<&[u8]> { self.imp.get_alpn_protocol() } fn get_protocol_version(&self) -> Option { self.imp.get_protocol_version() } fn export_keying_material(&self, output: &mut [u8], label: &[u8], context: Option<&[u8]>) -> Result<(), TLSError> { self.imp.common.export_keying_material(output, label, context) } fn get_negotiated_ciphersuite(&self) -> Option<&'static SupportedCipherSuite> { self.imp.get_negotiated_ciphersuite().or(self.imp.resumption_ciphersuite) } } impl io::Read for ClientSession { /// Obtain plaintext data received from the peer over /// this TLS connection. fn read(&mut self, buf: &mut [u8]) -> io::Result { self.imp.common.read(buf) } } impl io::Write for ClientSession { /// Send the plaintext `buf` to the peer, encrypting /// and authenticating it. Once this function succeeds /// you should call `write_tls` which will output the /// corresponding TLS records. /// /// This function buffers plaintext sent before the /// TLS handshake completes, and sends it as soon /// as it can. This buffer is of *unlimited size* so /// writing much data before it can be sent will /// cause excess memory usage. fn write(&mut self, buf: &[u8]) -> io::Result { self.imp.common.send_some_plaintext(buf) } fn flush(&mut self) -> io::Result<()> { self.imp.common.flush_plaintext(); Ok(()) } }