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