|  | 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<u8>, value: Vec<u8>) -> bool; | 
|  |  | 
|  | /// Returns the latest value for `key`.  Returns `None` | 
|  | /// if there's no such value. | 
|  | fn get(&self, key: &[u8]) -> Option<Vec<u8>>; | 
|  | } | 
|  |  | 
|  | /// 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<sign::CertifiedKey>; | 
|  |  | 
|  | /// 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<Vec<u8>>, | 
|  |  | 
|  | /// How we store session data or tickets. | 
|  | pub session_persistence: Arc<dyn StoresClientSessions>, | 
|  |  | 
|  | /// Our MTU.  If None, we don't limit TLS message sizes. | 
|  | pub mtu: Option<usize>, | 
|  |  | 
|  | /// How to decide what client auth certificate/keys to use. | 
|  | pub client_auth_cert_resolver: Arc<dyn ResolvesClientCert>, | 
|  |  | 
|  | /// 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<ProtocolVersion>, | 
|  |  | 
|  | /// 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<dyn verify::ServerCertVerifier>, | 
|  |  | 
|  | /// How to output key material for debugging.  The default | 
|  | /// does nothing. | 
|  | pub key_log: Arc<dyn KeyLog>, | 
|  |  | 
|  | /// 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<u8>]) { | 
|  | self.alpn_protocols.clear(); | 
|  | self.alpn_protocols.extend_from_slice(protocols); | 
|  | } | 
|  |  | 
|  | /// Sets persistence layer to `persist`. | 
|  | pub fn set_persistence(&mut self, persist: Arc<dyn StoresClientSessions>) { | 
|  | 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<usize>) { | 
|  | // 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::Certificate>, | 
|  | key_der: key::PrivateKey) -> Result<(), TLSError> { | 
|  | let resolver = handy::AlwaysResolvesClientCert::new(cert_chain, &key_der)?; | 
|  | self.client_auth_cert_resolver = Arc::new(resolver); | 
|  | Ok(()) | 
|  | } | 
|  |  | 
|  | /// 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<dyn ServerCertVerifier>) { | 
|  | 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<usize> { | 
|  | 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<usize> { | 
|  | self.sess.write_early_data(buf) | 
|  | } | 
|  |  | 
|  | fn flush(&mut self) -> io::Result<()> { | 
|  | Ok(()) | 
|  | } | 
|  | } | 
|  |  | 
|  | pub struct ClientSessionImpl { | 
|  | pub config: Arc<ClientConfig>, | 
|  | pub alpn_protocol: Option<Vec<u8>>, | 
|  | pub common: SessionCommon, | 
|  | pub error: Option<TLSError>, | 
|  | pub state: Option<Box<dyn hs::State + Send + Sync>>, | 
|  | 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<ClientConfig>) -> 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<ClientExtension>) { | 
|  | self.state = Some(hs::start_handshake(self, hostname, extra_exts)); | 
|  | } | 
|  |  | 
|  | pub fn get_cipher_suites(&self) -> Vec<CipherSuite> { | 
|  | 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.record_layer.is_decrypting() { | 
|  | 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 `check_message`.  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<Vec<key::Certificate>> { | 
|  | 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<ProtocolVersion> { | 
|  | 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<usize> { | 
|  | self.early_data.check_write(data.len()) | 
|  | .and_then(|sz| { | 
|  | self.common.send_early_plaintext(&data[..sz]) | 
|  | }) | 
|  | } | 
|  |  | 
|  | fn export_keying_material(&self, | 
|  | output: &mut [u8], | 
|  | label: &[u8], | 
|  | context: Option<&[u8]>) -> Result<(), TLSError> { | 
|  | self.state | 
|  | .as_ref() | 
|  | .ok_or_else(|| TLSError::HandshakeNotComplete) | 
|  | .and_then(|st| st.export_keying_material(output, label, context)) | 
|  | } | 
|  |  | 
|  | fn send_some_plaintext(&mut self, buf: &[u8]) -> io::Result<usize> { | 
|  | let mut st = self.state.take(); | 
|  | st.as_mut() | 
|  | .map(|st| st.perhaps_write_key_update(self)); | 
|  | self.state = st; | 
|  |  | 
|  | self.common.send_some_plaintext(buf) | 
|  | } | 
|  | } | 
|  |  | 
|  | /// 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<ClientConfig>, 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<WriteEarlyData> { | 
|  | 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<usize> { | 
|  | self.imp.common.read_tls(rd) | 
|  | } | 
|  |  | 
|  | /// Writes TLS messages to `wr`. | 
|  | fn write_tls(&mut self, wr: &mut dyn io::Write) -> io::Result<usize> { | 
|  | self.imp.common.write_tls(wr) | 
|  | } | 
|  |  | 
|  | fn writev_tls(&mut self, wr: &mut dyn WriteV) -> io::Result<usize> { | 
|  | 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<Vec<key::Certificate>> { | 
|  | self.imp.get_peer_certificates() | 
|  | } | 
|  |  | 
|  | fn get_alpn_protocol(&self) -> Option<&[u8]> { | 
|  | self.imp.get_alpn_protocol() | 
|  | } | 
|  |  | 
|  | fn get_protocol_version(&self) -> Option<ProtocolVersion> { | 
|  | self.imp.get_protocol_version() | 
|  | } | 
|  |  | 
|  | fn export_keying_material(&self, | 
|  | output: &mut [u8], | 
|  | label: &[u8], | 
|  | context: Option<&[u8]>) -> Result<(), TLSError> { | 
|  | self.imp.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<usize> { | 
|  | 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<usize> { | 
|  | self.imp.send_some_plaintext(buf) | 
|  | } | 
|  |  | 
|  | fn flush(&mut self) -> io::Result<()> { | 
|  | self.imp.common.flush_plaintext(); | 
|  | Ok(()) | 
|  | } | 
|  | } |