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