| 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 | |