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