native_tls/
lib.rs

1//! An abstraction over platform-specific TLS implementations.
2//!
3//! Many applications require TLS/SSL communication in one form or another as
4//! part of their implementation, but finding a library for this isn't always
5//! trivial! The purpose of this crate is to provide a seamless integration
6//! experience on all platforms with a cross-platform API that deals with all
7//! the underlying details for you.
8//!
9//! # How is this implemented?
10//!
11//! This crate uses SChannel on Windows (via the `schannel` crate), Secure
12//! Transport on OSX (via the `security-framework` crate), and OpenSSL (via the
13//! `openssl` crate) on all other platforms. Future features may also enable
14//! other TLS frameworks as well, but these initial libraries are likely to
15//! remain as the defaults.
16//!
17//! Note that this crate also strives to be secure-by-default. For example when
18//! using OpenSSL it will configure validation callbacks to ensure that
19//! hostnames match certificates, use strong ciphers, etc. This implies that
20//! this crate is *not* just a thin abstraction around the underlying libraries,
21//! but also an implementation that strives to strike reasonable defaults.
22//!
23//! # Supported features
24//!
25//! This crate supports the following features out of the box:
26//!
27//! * TLS/SSL client communication
28//! * TLS/SSL server communication
29//! * PKCS#12 encoded identities
30//! * X.509/PKCS#8 encoded identities
31//! * Secure-by-default for client and server
32//!     * Includes hostname verification for clients
33//! * Supports asynchronous I/O for both the server and the client
34//!
35//! # Cargo Features
36//!
37//! * `vendored` - If enabled, the crate will compile and statically link to a
38//!     vendored copy of OpenSSL. This feature has no effect on Windows and
39//!     macOS, where OpenSSL is not used.
40//!
41//! # Examples
42//!
43//! To connect as a client to a remote server:
44//!
45//! ```rust
46//! use native_tls::TlsConnector;
47//! use std::io::{Read, Write};
48//! use std::net::TcpStream;
49//!
50//! let connector = TlsConnector::new().unwrap();
51//!
52//! let stream = TcpStream::connect("google.com:443").unwrap();
53//! let mut stream = connector.connect("google.com", stream).unwrap();
54//!
55//! stream.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap();
56//! let mut res = vec![];
57//! stream.read_to_end(&mut res).unwrap();
58//! println!("{}", String::from_utf8_lossy(&res));
59//! ```
60//!
61//! To accept connections as a server from remote clients:
62//!
63//! ```rust,no_run
64//! use native_tls::{Identity, TlsAcceptor, TlsStream};
65//! use std::fs::File;
66//! use std::io::{Read};
67//! use std::net::{TcpListener, TcpStream};
68//! use std::sync::Arc;
69//! use std::thread;
70//!
71//! let mut file = File::open("identity.pfx").unwrap();
72//! let mut identity = vec![];
73//! file.read_to_end(&mut identity).unwrap();
74//! let identity = Identity::from_pkcs12(&identity, "hunter2").unwrap();
75//!
76//! let listener = TcpListener::bind("0.0.0.0:8443").unwrap();
77//! let acceptor = TlsAcceptor::new(identity).unwrap();
78//! let acceptor = Arc::new(acceptor);
79//!
80//! fn handle_client(stream: TlsStream<TcpStream>) {
81//!     // ...
82//! }
83//!
84//! for stream in listener.incoming() {
85//!     match stream {
86//!         Ok(stream) => {
87//!             let acceptor = acceptor.clone();
88//!             thread::spawn(move || {
89//!                 let stream = acceptor.accept(stream).unwrap();
90//!                 handle_client(stream);
91//!             });
92//!         }
93//!         Err(e) => { /* connection failed */ }
94//!     }
95//! }
96//! ```
97#![warn(missing_docs)]
98#![cfg_attr(docsrs, feature(doc_cfg))]
99
100use std::any::Any;
101use std::error;
102use std::fmt;
103use std::io;
104use std::result;
105
106#[cfg(not(any(target_os = "windows", target_vendor = "apple")))]
107#[macro_use]
108extern crate log;
109#[cfg(target_vendor = "apple")]
110#[path = "imp/security_framework.rs"]
111mod imp;
112#[cfg(target_os = "windows")]
113#[path = "imp/schannel.rs"]
114mod imp;
115#[cfg(not(any(target_vendor = "apple", target_os = "windows")))]
116#[path = "imp/openssl.rs"]
117mod imp;
118
119#[cfg(test)]
120mod test;
121
122/// A typedef of the result-type returned by many methods.
123pub type Result<T> = result::Result<T, Error>;
124
125/// An error returned from the TLS implementation.
126pub struct Error(imp::Error);
127
128impl error::Error for Error {
129    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
130        error::Error::source(&self.0)
131    }
132}
133
134impl fmt::Display for Error {
135    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
136        fmt::Display::fmt(&self.0, fmt)
137    }
138}
139
140impl fmt::Debug for Error {
141    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
142        fmt::Debug::fmt(&self.0, fmt)
143    }
144}
145
146impl From<imp::Error> for Error {
147    fn from(err: imp::Error) -> Error {
148        Error(err)
149    }
150}
151
152/// A cryptographic identity.
153///
154/// An identity is an X509 certificate along with its corresponding private key and chain of certificates to a trusted
155/// root.
156#[derive(Clone)]
157pub struct Identity(imp::Identity);
158
159impl Identity {
160    /// Parses a DER-formatted PKCS #12 archive, using the specified password to decrypt the key.
161    ///
162    /// The archive should contain a leaf certificate and its private key, as well any intermediate
163    /// certificates that should be sent to clients to allow them to build a chain to a trusted
164    /// root. The chain certificates should be in order from the leaf certificate towards the root.
165    ///
166    /// PKCS #12 archives typically have the file extension `.p12` or `.pfx`, and can be created
167    /// with the OpenSSL `pkcs12` tool:
168    ///
169    /// ```bash
170    /// openssl pkcs12 -export -out identity.pfx -inkey key.pem -in cert.pem -certfile chain_certs.pem
171    /// ```
172    pub fn from_pkcs12(der: &[u8], password: &str) -> Result<Identity> {
173        let identity = imp::Identity::from_pkcs12(der, password)?;
174        Ok(Identity(identity))
175    }
176
177    /// Parses a chain of PEM encoded X509 certificates, with the leaf certificate first.
178    /// `key` is a PEM encoded PKCS #8 formatted private key for the leaf certificate.
179    ///
180    /// The certificate chain should contain any intermediate cerficates that should be sent to
181    /// clients to allow them to build a chain to a trusted root.
182    ///
183    /// A certificate chain here means a series of PEM encoded certificates concatenated together.
184    pub fn from_pkcs8(pem: &[u8], key: &[u8]) -> Result<Identity> {
185        let identity = imp::Identity::from_pkcs8(pem, key)?;
186        Ok(Identity(identity))
187    }
188}
189
190/// An X509 certificate.
191#[derive(Clone)]
192pub struct Certificate(imp::Certificate);
193
194impl Certificate {
195    /// Parses a DER-formatted X509 certificate.
196    pub fn from_der(der: &[u8]) -> Result<Certificate> {
197        let cert = imp::Certificate::from_der(der)?;
198        Ok(Certificate(cert))
199    }
200
201    /// Parses a PEM-formatted X509 certificate.
202    pub fn from_pem(pem: &[u8]) -> Result<Certificate> {
203        let cert = imp::Certificate::from_pem(pem)?;
204        Ok(Certificate(cert))
205    }
206
207    /// Returns the DER-encoded representation of this certificate.
208    pub fn to_der(&self) -> Result<Vec<u8>> {
209        let der = self.0.to_der()?;
210        Ok(der)
211    }
212}
213
214/// A TLS stream which has been interrupted midway through the handshake process.
215pub struct MidHandshakeTlsStream<S>(imp::MidHandshakeTlsStream<S>);
216
217impl<S> fmt::Debug for MidHandshakeTlsStream<S>
218where
219    S: fmt::Debug,
220{
221    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
222        fmt::Debug::fmt(&self.0, fmt)
223    }
224}
225
226impl<S> MidHandshakeTlsStream<S> {
227    /// Returns a shared reference to the inner stream.
228    pub fn get_ref(&self) -> &S {
229        self.0.get_ref()
230    }
231
232    /// Returns a mutable reference to the inner stream.
233    pub fn get_mut(&mut self) -> &mut S {
234        self.0.get_mut()
235    }
236}
237
238impl<S> MidHandshakeTlsStream<S>
239where
240    S: io::Read + io::Write,
241{
242    /// Restarts the handshake process.
243    ///
244    /// If the handshake completes successfully then the negotiated stream is
245    /// returned. If there is a problem, however, then an error is returned.
246    /// Note that the error may not be fatal. For example if the underlying
247    /// stream is an asynchronous one then `HandshakeError::WouldBlock` may
248    /// just mean to wait for more I/O to happen later.
249    pub fn handshake(self) -> result::Result<TlsStream<S>, HandshakeError<S>> {
250        match self.0.handshake() {
251            Ok(s) => Ok(TlsStream(s)),
252            Err(e) => Err(e.into()),
253        }
254    }
255}
256
257/// An error returned from `ClientBuilder::handshake`.
258#[derive(Debug)]
259pub enum HandshakeError<S> {
260    /// A fatal error.
261    Failure(Error),
262
263    /// A stream interrupted midway through the handshake process due to a
264    /// `WouldBlock` error.
265    ///
266    /// Note that this is not a fatal error and it should be safe to call
267    /// `handshake` at a later time once the stream is ready to perform I/O
268    /// again.
269    WouldBlock(MidHandshakeTlsStream<S>),
270}
271
272impl<S> error::Error for HandshakeError<S>
273where
274    S: Any + fmt::Debug,
275{
276    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
277        match *self {
278            HandshakeError::Failure(ref e) => Some(e),
279            HandshakeError::WouldBlock(_) => None,
280        }
281    }
282}
283
284impl<S> fmt::Display for HandshakeError<S>
285where
286    S: Any + fmt::Debug,
287{
288    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
289        match *self {
290            HandshakeError::Failure(ref e) => fmt::Display::fmt(e, fmt),
291            HandshakeError::WouldBlock(_) => fmt.write_str("the handshake process was interrupted"),
292        }
293    }
294}
295
296impl<S> From<imp::HandshakeError<S>> for HandshakeError<S> {
297    fn from(e: imp::HandshakeError<S>) -> HandshakeError<S> {
298        match e {
299            imp::HandshakeError::Failure(e) => HandshakeError::Failure(Error(e)),
300            imp::HandshakeError::WouldBlock(s) => {
301                HandshakeError::WouldBlock(MidHandshakeTlsStream(s))
302            }
303        }
304    }
305}
306
307/// SSL/TLS protocol versions.
308#[derive(Debug, Copy, Clone)]
309#[non_exhaustive]
310pub enum Protocol {
311    /// The SSL 3.0 protocol.
312    ///
313    /// # Warning
314    ///
315    /// SSL 3.0 has severe security flaws, and should not be used unless absolutely necessary. If
316    /// you are not sure if you need to enable this protocol, you should not.
317    Sslv3,
318    /// The TLS 1.0 protocol.
319    Tlsv10,
320    /// The TLS 1.1 protocol.
321    Tlsv11,
322    /// The TLS 1.2 protocol.
323    Tlsv12,
324}
325
326/// A builder for `TlsConnector`s.
327///
328/// You can get one from [`TlsConnector::builder()`](TlsConnector::builder)
329pub struct TlsConnectorBuilder {
330    identity: Option<Identity>,
331    min_protocol: Option<Protocol>,
332    max_protocol: Option<Protocol>,
333    root_certificates: Vec<Certificate>,
334    accept_invalid_certs: bool,
335    accept_invalid_hostnames: bool,
336    use_sni: bool,
337    disable_built_in_roots: bool,
338    #[cfg(feature = "alpn")]
339    alpn: Vec<String>,
340}
341
342impl TlsConnectorBuilder {
343    /// Sets the identity to be used for client certificate authentication.
344    pub fn identity(&mut self, identity: Identity) -> &mut TlsConnectorBuilder {
345        self.identity = Some(identity);
346        self
347    }
348
349    /// Sets the minimum supported protocol version.
350    ///
351    /// A value of `None` enables support for the oldest protocols supported by the implementation.
352    ///
353    /// Defaults to `Some(Protocol::Tlsv10)`.
354    pub fn min_protocol_version(&mut self, protocol: Option<Protocol>) -> &mut TlsConnectorBuilder {
355        self.min_protocol = protocol;
356        self
357    }
358
359    /// Sets the maximum supported protocol version.
360    ///
361    /// A value of `None` enables support for the newest protocols supported by the implementation.
362    ///
363    /// Defaults to `None`.
364    pub fn max_protocol_version(&mut self, protocol: Option<Protocol>) -> &mut TlsConnectorBuilder {
365        self.max_protocol = protocol;
366        self
367    }
368
369    /// Adds a certificate to the set of roots that the connector will trust.
370    ///
371    /// The connector will use the system's trust root by default. This method can be used to add
372    /// to that set when communicating with servers not trusted by the system.
373    ///
374    /// Defaults to an empty set.
375    pub fn add_root_certificate(&mut self, cert: Certificate) -> &mut TlsConnectorBuilder {
376        self.root_certificates.push(cert);
377        self
378    }
379
380    /// Controls the use of built-in system certificates during certificate validation.
381    ///
382    /// Defaults to `false` -- built-in system certs will be used.
383    pub fn disable_built_in_roots(&mut self, disable: bool) -> &mut TlsConnectorBuilder {
384        self.disable_built_in_roots = disable;
385        self
386    }
387
388    /// Request specific protocols through ALPN (Application-Layer Protocol Negotiation).
389    ///
390    /// Defaults to no protocols.
391    #[cfg(feature = "alpn")]
392    #[cfg_attr(docsrs, doc(cfg(feature = "alpn")))]
393    pub fn request_alpns(&mut self, protocols: &[&str]) -> &mut TlsConnectorBuilder {
394        self.alpn = protocols.iter().map(|s| (*s).to_owned()).collect();
395        self
396    }
397
398    /// Controls the use of certificate validation.
399    ///
400    /// Defaults to `false`.
401    ///
402    /// # Warning
403    ///
404    /// You should think very carefully before using this method. If invalid certificates are trusted, *any*
405    /// certificate for *any* site will be trusted for use. This includes expired certificates. This introduces
406    /// significant vulnerabilities, and should only be used as a last resort.
407    pub fn danger_accept_invalid_certs(
408        &mut self,
409        accept_invalid_certs: bool,
410    ) -> &mut TlsConnectorBuilder {
411        self.accept_invalid_certs = accept_invalid_certs;
412        self
413    }
414
415    /// Controls the use of Server Name Indication (SNI).
416    ///
417    /// Defaults to `true`.
418    pub fn use_sni(&mut self, use_sni: bool) -> &mut TlsConnectorBuilder {
419        self.use_sni = use_sni;
420        self
421    }
422
423    /// Controls the use of hostname verification.
424    ///
425    /// Defaults to `false`.
426    ///
427    /// # Warning
428    ///
429    /// You should think very carefully before using this method. If invalid hostnames are trusted, *any* valid
430    /// certificate for *any* site will be trusted for use. This introduces significant vulnerabilities, and should
431    /// only be used as a last resort.
432    pub fn danger_accept_invalid_hostnames(
433        &mut self,
434        accept_invalid_hostnames: bool,
435    ) -> &mut TlsConnectorBuilder {
436        self.accept_invalid_hostnames = accept_invalid_hostnames;
437        self
438    }
439
440    /// Creates a new `TlsConnector`.
441    pub fn build(&self) -> Result<TlsConnector> {
442        let connector = imp::TlsConnector::new(self)?;
443        Ok(TlsConnector(connector))
444    }
445}
446
447/// A builder for client-side TLS connections.
448///
449/// # Examples
450///
451/// ```rust
452/// use native_tls::TlsConnector;
453/// use std::io::{Read, Write};
454/// use std::net::TcpStream;
455///
456/// let connector = TlsConnector::new().unwrap();
457///
458/// let stream = TcpStream::connect("google.com:443").unwrap();
459/// let mut stream = connector.connect("google.com", stream).unwrap();
460///
461/// stream.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap();
462/// let mut res = vec![];
463/// stream.read_to_end(&mut res).unwrap();
464/// println!("{}", String::from_utf8_lossy(&res));
465/// ```
466#[derive(Clone, Debug)]
467pub struct TlsConnector(imp::TlsConnector);
468
469impl TlsConnector {
470    /// Returns a new connector with default settings.
471    pub fn new() -> Result<TlsConnector> {
472        TlsConnector::builder().build()
473    }
474
475    /// Returns a new builder for a `TlsConnector`.
476    pub fn builder() -> TlsConnectorBuilder {
477        TlsConnectorBuilder {
478            identity: None,
479            min_protocol: Some(Protocol::Tlsv10),
480            max_protocol: None,
481            root_certificates: vec![],
482            use_sni: true,
483            accept_invalid_certs: false,
484            accept_invalid_hostnames: false,
485            disable_built_in_roots: false,
486            #[cfg(feature = "alpn")]
487            alpn: vec![],
488        }
489    }
490
491    /// Initiates a TLS handshake.
492    ///
493    /// The provided domain will be used for both SNI and certificate hostname
494    /// validation.
495    ///
496    /// If the socket is nonblocking and a `WouldBlock` error is returned during
497    /// the handshake, a `HandshakeError::WouldBlock` error will be returned
498    /// which can be used to restart the handshake when the socket is ready
499    /// again.
500    ///
501    /// The domain is ignored if both SNI and hostname verification are
502    /// disabled.
503    pub fn connect<S>(
504        &self,
505        domain: &str,
506        stream: S,
507    ) -> result::Result<TlsStream<S>, HandshakeError<S>>
508    where
509        S: io::Read + io::Write,
510    {
511        let s = self.0.connect(domain, stream)?;
512        Ok(TlsStream(s))
513    }
514}
515
516/// A builder for `TlsAcceptor`s.
517///
518/// You can get one from [`TlsAcceptor::builder()`](TlsAcceptor::builder)
519pub struct TlsAcceptorBuilder {
520    identity: Identity,
521    min_protocol: Option<Protocol>,
522    max_protocol: Option<Protocol>,
523}
524
525impl TlsAcceptorBuilder {
526    /// Sets the minimum supported protocol version.
527    ///
528    /// A value of `None` enables support for the oldest protocols supported by the implementation.
529    ///
530    /// Defaults to `Some(Protocol::Tlsv10)`.
531    pub fn min_protocol_version(&mut self, protocol: Option<Protocol>) -> &mut TlsAcceptorBuilder {
532        self.min_protocol = protocol;
533        self
534    }
535
536    /// Sets the maximum supported protocol version.
537    ///
538    /// A value of `None` enables support for the newest protocols supported by the implementation.
539    ///
540    /// Defaults to `None`.
541    pub fn max_protocol_version(&mut self, protocol: Option<Protocol>) -> &mut TlsAcceptorBuilder {
542        self.max_protocol = protocol;
543        self
544    }
545
546    /// Creates a new `TlsAcceptor`.
547    pub fn build(&self) -> Result<TlsAcceptor> {
548        let acceptor = imp::TlsAcceptor::new(self)?;
549        Ok(TlsAcceptor(acceptor))
550    }
551}
552
553/// A builder for server-side TLS connections.
554///
555/// # Examples
556///
557/// ```rust,no_run
558/// use native_tls::{Identity, TlsAcceptor, TlsStream};
559/// use std::fs::File;
560/// use std::io::{Read};
561/// use std::net::{TcpListener, TcpStream};
562/// use std::sync::Arc;
563/// use std::thread;
564///
565/// let mut file = File::open("identity.pfx").unwrap();
566/// let mut identity = vec![];
567/// file.read_to_end(&mut identity).unwrap();
568/// let identity = Identity::from_pkcs12(&identity, "hunter2").unwrap();
569///
570/// let listener = TcpListener::bind("0.0.0.0:8443").unwrap();
571/// let acceptor = TlsAcceptor::new(identity).unwrap();
572/// let acceptor = Arc::new(acceptor);
573///
574/// fn handle_client(stream: TlsStream<TcpStream>) {
575///     // ...
576/// }
577///
578/// for stream in listener.incoming() {
579///     match stream {
580///         Ok(stream) => {
581///             let acceptor = acceptor.clone();
582///             thread::spawn(move || {
583///                 let stream = acceptor.accept(stream).unwrap();
584///                 handle_client(stream);
585///             });
586///         }
587///         Err(e) => { /* connection failed */ }
588///     }
589/// }
590/// ```
591#[derive(Clone)]
592pub struct TlsAcceptor(imp::TlsAcceptor);
593
594impl TlsAcceptor {
595    /// Creates a acceptor with default settings.
596    ///
597    /// The identity acts as the server's private key/certificate chain.
598    pub fn new(identity: Identity) -> Result<TlsAcceptor> {
599        TlsAcceptor::builder(identity).build()
600    }
601
602    /// Returns a new builder for a `TlsAcceptor`.
603    ///
604    /// The identity acts as the server's private key/certificate chain.
605    pub fn builder(identity: Identity) -> TlsAcceptorBuilder {
606        TlsAcceptorBuilder {
607            identity,
608            min_protocol: Some(Protocol::Tlsv10),
609            max_protocol: None,
610        }
611    }
612
613    /// Initiates a TLS handshake.
614    ///
615    /// If the socket is nonblocking and a `WouldBlock` error is returned during
616    /// the handshake, a `HandshakeError::WouldBlock` error will be returned
617    /// which can be used to restart the handshake when the socket is ready
618    /// again.
619    pub fn accept<S>(&self, stream: S) -> result::Result<TlsStream<S>, HandshakeError<S>>
620    where
621        S: io::Read + io::Write,
622    {
623        match self.0.accept(stream) {
624            Ok(s) => Ok(TlsStream(s)),
625            Err(e) => Err(e.into()),
626        }
627    }
628}
629
630/// A stream managing a TLS session.
631pub struct TlsStream<S>(imp::TlsStream<S>);
632
633impl<S: fmt::Debug> fmt::Debug for TlsStream<S> {
634    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
635        fmt::Debug::fmt(&self.0, fmt)
636    }
637}
638
639impl<S> TlsStream<S> {
640    /// Returns a shared reference to the inner stream.
641    pub fn get_ref(&self) -> &S {
642        self.0.get_ref()
643    }
644
645    /// Returns a mutable reference to the inner stream.
646    pub fn get_mut(&mut self) -> &mut S {
647        self.0.get_mut()
648    }
649}
650
651impl<S: io::Read + io::Write> TlsStream<S> {
652    /// Returns the number of bytes that can be read without resulting in any
653    /// network calls.
654    pub fn buffered_read_size(&self) -> Result<usize> {
655        Ok(self.0.buffered_read_size()?)
656    }
657
658    /// Returns the peer's leaf certificate, if available.
659    pub fn peer_certificate(&self) -> Result<Option<Certificate>> {
660        Ok(self.0.peer_certificate()?.map(Certificate))
661    }
662
663    /// Returns the tls-server-end-point channel binding data as defined in [RFC 5929].
664    ///
665    /// [RFC 5929]: https://tools.ietf.org/html/rfc5929
666    pub fn tls_server_end_point(&self) -> Result<Option<Vec<u8>>> {
667        Ok(self.0.tls_server_end_point()?)
668    }
669
670    /// Returns the negotiated ALPN protocol.
671    #[cfg(feature = "alpn")]
672    #[cfg_attr(docsrs, doc(cfg(feature = "alpn")))]
673    pub fn negotiated_alpn(&self) -> Result<Option<Vec<u8>>> {
674        Ok(self.0.negotiated_alpn()?)
675    }
676
677    /// Shuts down the TLS session.
678    pub fn shutdown(&mut self) -> io::Result<()> {
679        self.0.shutdown()?;
680        Ok(())
681    }
682}
683
684impl<S: io::Read + io::Write> io::Read for TlsStream<S> {
685    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
686        self.0.read(buf)
687    }
688}
689
690impl<S: io::Read + io::Write> io::Write for TlsStream<S> {
691    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
692        self.0.write(buf)
693    }
694
695    fn flush(&mut self) -> io::Result<()> {
696        self.0.flush()
697    }
698}
699
700fn _check_kinds() {
701    use std::net::TcpStream;
702
703    fn is_sync<T: Sync>() {}
704    fn is_send<T: Send>() {}
705    is_sync::<Error>();
706    is_send::<Error>();
707    is_sync::<TlsConnectorBuilder>();
708    is_send::<TlsConnectorBuilder>();
709    is_sync::<TlsConnector>();
710    is_send::<TlsConnector>();
711    is_sync::<TlsAcceptorBuilder>();
712    is_send::<TlsAcceptorBuilder>();
713    is_sync::<TlsAcceptor>();
714    is_send::<TlsAcceptor>();
715    is_sync::<TlsStream<TcpStream>>();
716    is_send::<TlsStream<TcpStream>>();
717    is_sync::<MidHandshakeTlsStream<TcpStream>>();
718    is_send::<MidHandshakeTlsStream<TcpStream>>();
719}