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" ))] |
103 | extern crate lazy_static; |
104 | |
105 | use std::any::Any; |
106 | use std::error; |
107 | use std::fmt; |
108 | use std::io; |
109 | use std::result; |
110 | |
111 | #[cfg (not(any(target_os = "macos" , target_os = "windows" , target_os = "ios" )))] |
112 | #[macro_use ] |
113 | extern crate log; |
114 | #[cfg (any(target_os = "macos" , target_os = "ios" ))] |
115 | #[path = "imp/security_framework.rs" ] |
116 | mod imp; |
117 | #[cfg (target_os = "windows" )] |
118 | #[path = "imp/schannel.rs" ] |
119 | mod imp; |
120 | #[cfg (not(any(target_os = "macos" , target_os = "windows" , target_os = "ios" )))] |
121 | #[path = "imp/openssl.rs" ] |
122 | mod imp; |
123 | |
124 | #[cfg (test)] |
125 | mod test; |
126 | |
127 | /// A typedef of the result-type returned by many methods. |
128 | pub type Result<T> = result::Result<T, Error>; |
129 | |
130 | /// An error returned from the TLS implementation. |
131 | pub struct Error(imp::Error); |
132 | |
133 | impl error::Error for Error { |
134 | fn source(&self) -> Option<&(dyn error::Error + 'static)> { |
135 | error::Error::source(&self.0) |
136 | } |
137 | } |
138 | |
139 | impl 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 | |
145 | impl 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 | |
151 | impl 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)] |
162 | pub struct Identity(imp::Identity); |
163 | |
164 | impl 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)] |
197 | pub struct Certificate(imp::Certificate); |
198 | |
199 | impl 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. |
220 | pub struct MidHandshakeTlsStream<S>(imp::MidHandshakeTlsStream<S>); |
221 | |
222 | impl<S> fmt::Debug for MidHandshakeTlsStream<S> |
223 | where |
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 | |
231 | impl<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 | |
243 | impl<S> MidHandshakeTlsStream<S> |
244 | where |
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)] |
264 | pub 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 | |
277 | impl<S> error::Error for HandshakeError<S> |
278 | where |
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 | |
289 | impl<S> fmt::Display for HandshakeError<S> |
290 | where |
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 | |
301 | impl<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)] |
314 | pub 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. |
333 | pub 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 | |
346 | impl 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)] |
471 | pub struct TlsConnector(imp::TlsConnector); |
472 | |
473 | impl 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. |
521 | pub struct TlsAcceptorBuilder { |
522 | identity: Identity, |
523 | min_protocol: Option<Protocol>, |
524 | max_protocol: Option<Protocol>, |
525 | } |
526 | |
527 | impl 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)] |
594 | pub struct TlsAcceptor(imp::TlsAcceptor); |
595 | |
596 | impl 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. |
633 | pub struct TlsStream<S>(imp::TlsStream<S>); |
634 | |
635 | impl<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 | |
641 | impl<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 | |
653 | impl<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 | |
686 | impl<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 | |
692 | impl<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 | |
702 | fn _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 | |