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 | |
100 | use std::any::Any; |
101 | use std::error; |
102 | use std::fmt; |
103 | use std::io; |
104 | use std::result; |
105 | |
106 | #[cfg (not(any(target_os = "windows" , target_vendor = "apple" )))] |
107 | #[macro_use ] |
108 | extern crate log; |
109 | #[cfg (target_vendor = "apple" )] |
110 | #[path = "imp/security_framework.rs" ] |
111 | mod imp; |
112 | #[cfg (target_os = "windows" )] |
113 | #[path = "imp/schannel.rs" ] |
114 | mod imp; |
115 | #[cfg (not(any(target_vendor = "apple" , target_os = "windows" )))] |
116 | #[path = "imp/openssl.rs" ] |
117 | mod imp; |
118 | |
119 | #[cfg (test)] |
120 | mod test; |
121 | |
122 | /// A typedef of the result-type returned by many methods. |
123 | pub type Result<T> = result::Result<T, Error>; |
124 | |
125 | /// An error returned from the TLS implementation. |
126 | pub struct Error(imp::Error); |
127 | |
128 | impl error::Error for Error { |
129 | fn source(&self) -> Option<&(dyn error::Error + 'static)> { |
130 | error::Error::source(&self.0) |
131 | } |
132 | } |
133 | |
134 | impl fmt::Display for Error { |
135 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { |
136 | fmt::Display::fmt(&self.0, f:fmt) |
137 | } |
138 | } |
139 | |
140 | impl fmt::Debug for Error { |
141 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { |
142 | fmt::Debug::fmt(&self.0, f:fmt) |
143 | } |
144 | } |
145 | |
146 | impl 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)] |
157 | pub struct Identity(imp::Identity); |
158 | |
159 | impl 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)] |
192 | pub struct Certificate(imp::Certificate); |
193 | |
194 | impl Certificate { |
195 | /// Parses a DER-formatted X509 certificate. |
196 | pub fn from_der(der: &[u8]) -> Result<Certificate> { |
197 | let cert: Certificate = imp::Certificate::from_der(buf: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: Certificate = imp::Certificate::from_pem(buf: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: Vec = self.0.to_der()?; |
210 | Ok(der) |
211 | } |
212 | } |
213 | |
214 | /// A TLS stream which has been interrupted midway through the handshake process. |
215 | pub struct MidHandshakeTlsStream<S>(imp::MidHandshakeTlsStream<S>); |
216 | |
217 | impl<S> fmt::Debug for MidHandshakeTlsStream<S> |
218 | where |
219 | S: fmt::Debug, |
220 | { |
221 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { |
222 | fmt::Debug::fmt(&self.0, f:fmt) |
223 | } |
224 | } |
225 | |
226 | impl<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 | |
238 | impl<S> MidHandshakeTlsStream<S> |
239 | where |
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: TlsStream) => Ok(TlsStream(s)), |
252 | Err(e: HandshakeError) => Err(e.into()), |
253 | } |
254 | } |
255 | } |
256 | |
257 | /// An error returned from `ClientBuilder::handshake`. |
258 | #[derive (Debug)] |
259 | pub 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 | |
272 | impl<S> error::Error for HandshakeError<S> |
273 | where |
274 | S: Any + fmt::Debug, |
275 | { |
276 | fn source(&self) -> Option<&(dyn error::Error + 'static)> { |
277 | match *self { |
278 | HandshakeError::Failure(ref e: &Error) => Some(e), |
279 | HandshakeError::WouldBlock(_) => None, |
280 | } |
281 | } |
282 | } |
283 | |
284 | impl<S> fmt::Display for HandshakeError<S> |
285 | where |
286 | S: Any + fmt::Debug, |
287 | { |
288 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { |
289 | match *self { |
290 | HandshakeError::Failure(ref e: &Error) => fmt::Display::fmt(self:e, f:fmt), |
291 | HandshakeError::WouldBlock(_) => fmt.write_str(data:"the handshake process was interrupted" ), |
292 | } |
293 | } |
294 | } |
295 | |
296 | impl<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: Error) => HandshakeError::Failure(Error(e)), |
300 | imp::HandshakeError::WouldBlock(s: MidHandshakeTlsStream) => { |
301 | HandshakeError::WouldBlock(MidHandshakeTlsStream(s)) |
302 | } |
303 | } |
304 | } |
305 | } |
306 | |
307 | /// SSL/TLS protocol versions. |
308 | #[derive (Debug, Copy, Clone)] |
309 | #[non_exhaustive ] |
310 | pub 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) |
329 | pub 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 | |
342 | impl 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)] |
467 | pub struct TlsConnector(imp::TlsConnector); |
468 | |
469 | impl 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) |
519 | pub struct TlsAcceptorBuilder { |
520 | identity: Identity, |
521 | min_protocol: Option<Protocol>, |
522 | max_protocol: Option<Protocol>, |
523 | } |
524 | |
525 | impl 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)] |
592 | pub struct TlsAcceptor(imp::TlsAcceptor); |
593 | |
594 | impl 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. |
631 | pub struct TlsStream<S>(imp::TlsStream<S>); |
632 | |
633 | impl<S: fmt::Debug> fmt::Debug for TlsStream<S> { |
634 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { |
635 | fmt::Debug::fmt(&self.0, f:fmt) |
636 | } |
637 | } |
638 | |
639 | impl<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 | |
651 | impl<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 | |
684 | impl<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 | |
690 | impl<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 | |
700 | fn _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 | } |
720 | |