]> git.proxmox.com Git - cargo.git/blob - vendor/openssl-0.9.19/src/ssl/mod.rs
New upstream version 0.23.0
[cargo.git] / vendor / openssl-0.9.19 / src / ssl / mod.rs
1 //! SSL/TLS support.
2 //!
3 //! `SslConnector` and `SslAcceptor` should be used in most cases - they handle
4 //! configuration of the OpenSSL primitives for you.
5 //!
6 //! # Examples
7 //!
8 //! To connect as a client to a remote server:
9 //!
10 //! ```
11 //! use openssl::ssl::{SslMethod, SslConnectorBuilder};
12 //! use std::io::{Read, Write};
13 //! use std::net::TcpStream;
14 //!
15 //! let connector = SslConnectorBuilder::new(SslMethod::tls()).unwrap().build();
16 //!
17 //! let stream = TcpStream::connect("google.com:443").unwrap();
18 //! let mut stream = connector.connect("google.com", stream).unwrap();
19 //!
20 //! stream.write_all(b"GET / HTTP/1.0\r\n\r\n").unwrap();
21 //! let mut res = vec![];
22 //! stream.read_to_end(&mut res).unwrap();
23 //! println!("{}", String::from_utf8_lossy(&res));
24 //! ```
25 //!
26 //! To accept connections as a server from remote clients:
27 //!
28 //! ```no_run
29 //! use openssl::pkcs12::Pkcs12;
30 //! use openssl::ssl::{SslMethod, SslAcceptorBuilder, SslStream};
31 //! use std::fs::File;
32 //! use std::io::{Read, Write};
33 //! use std::net::{TcpListener, TcpStream};
34 //! use std::sync::Arc;
35 //! use std::thread;
36 //!
37 //! // In this example we retrieve our keypair and certificate chain from a PKCS #12 archive,
38 //! // but but they can also be retrieved from, for example, individual PEM- or DER-formatted
39 //! // files. See the documentation for the `PKey` and `X509` types for more details.
40 //! let mut file = File::open("identity.pfx").unwrap();
41 //! let mut pkcs12 = vec![];
42 //! file.read_to_end(&mut pkcs12).unwrap();
43 //! let pkcs12 = Pkcs12::from_der(&pkcs12).unwrap();
44 //! let identity = pkcs12.parse("password123").unwrap();
45 //!
46 //! let acceptor = SslAcceptorBuilder::mozilla_intermediate(SslMethod::tls(),
47 //! &identity.pkey,
48 //! &identity.cert,
49 //! &identity.chain)
50 //! .unwrap()
51 //! .build();
52 //! let acceptor = Arc::new(acceptor);
53 //!
54 //! let listener = TcpListener::bind("0.0.0.0:8443").unwrap();
55 //!
56 //! fn handle_client(stream: SslStream<TcpStream>) {
57 //! // ...
58 //! }
59 //!
60 //! for stream in listener.incoming() {
61 //! match stream {
62 //! Ok(stream) => {
63 //! let acceptor = acceptor.clone();
64 //! thread::spawn(move || {
65 //! let stream = acceptor.accept(stream).unwrap();
66 //! handle_client(stream);
67 //! });
68 //! }
69 //! Err(e) => { /* connection failed */ }
70 //! }
71 //! }
72 //! ```
73 use ffi;
74 use foreign_types::{ForeignType, ForeignTypeRef, Opaque};
75 use libc::{c_int, c_void, c_long, c_ulong};
76 use libc::{c_uchar, c_uint};
77 use std::any::Any;
78 use std::any::TypeId;
79 use std::borrow::Borrow;
80 use std::cmp;
81 use std::collections::HashMap;
82 use std::ffi::{CStr, CString};
83 use std::fmt;
84 use std::io;
85 use std::io::prelude::*;
86 use std::marker::PhantomData;
87 use std::mem;
88 use std::ops::{Deref, DerefMut};
89 use std::panic::resume_unwind;
90 use std::path::Path;
91 use std::ptr;
92 use std::slice;
93 use std::str;
94 use std::sync::Mutex;
95
96 use {init, cvt, cvt_p, cvt_n};
97 use dh::{Dh, DhRef};
98 use ec::EcKeyRef;
99 #[cfg(any(all(feature = "v101", ossl101), all(feature = "v102", ossl102)))]
100 use ec::EcKey;
101 use x509::{X509StoreContextRef, X509FileType, X509, X509Ref, X509VerifyError, X509Name};
102 use x509::store::{X509StoreBuilderRef, X509StoreRef};
103 #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))]
104 use x509::store::X509Store;
105 #[cfg(any(ossl102, ossl110))]
106 use verify::X509VerifyParamRef;
107 use pkey::PKeyRef;
108 use error::ErrorStack;
109 use ex_data::Index;
110 use stack::{Stack, StackRef};
111 use ssl::bio::BioMethod;
112 use ssl::callbacks::*;
113
114 pub use ssl::connector::{SslConnectorBuilder, SslConnector, SslAcceptorBuilder, SslAcceptor,
115 ConnectConfiguration};
116 pub use ssl::error::{Error, HandshakeError};
117
118 mod error;
119 mod callbacks;
120 mod connector;
121 mod bio;
122 #[cfg(test)]
123 mod tests;
124
125 // FIXME drop SSL_ prefix
126 // FIXME remvove flags not used in OpenSSL 1.1
127 bitflags! {
128 pub struct SslOption: c_ulong {
129 const SSL_OP_MICROSOFT_SESS_ID_BUG = ffi::SSL_OP_MICROSOFT_SESS_ID_BUG;
130 const SSL_OP_NETSCAPE_CHALLENGE_BUG = ffi::SSL_OP_NETSCAPE_CHALLENGE_BUG;
131 const SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG =
132 ffi::SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG;
133 const SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER = ffi::SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER;
134 const SSL_OP_SSLEAY_080_CLIENT_DH_BUG = ffi::SSL_OP_SSLEAY_080_CLIENT_DH_BUG;
135 const SSL_OP_TLS_D5_BUG = ffi::SSL_OP_TLS_D5_BUG;
136 const SSL_OP_TLS_BLOCK_PADDING_BUG = ffi::SSL_OP_TLS_BLOCK_PADDING_BUG;
137 const SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS = ffi::SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
138 const SSL_OP_ALL = ffi::SSL_OP_ALL;
139 const SSL_OP_NO_QUERY_MTU = ffi::SSL_OP_NO_QUERY_MTU;
140 const SSL_OP_COOKIE_EXCHANGE = ffi::SSL_OP_COOKIE_EXCHANGE;
141 const SSL_OP_NO_TICKET = ffi::SSL_OP_NO_TICKET;
142 const SSL_OP_CISCO_ANYCONNECT = ffi::SSL_OP_CISCO_ANYCONNECT;
143 const SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION =
144 ffi::SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION;
145 const SSL_OP_NO_COMPRESSION = ffi::SSL_OP_NO_COMPRESSION;
146 const SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION =
147 ffi::SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION;
148 const SSL_OP_SINGLE_ECDH_USE = ffi::SSL_OP_SINGLE_ECDH_USE;
149 const SSL_OP_SINGLE_DH_USE = ffi::SSL_OP_SINGLE_DH_USE;
150 const SSL_OP_CIPHER_SERVER_PREFERENCE = ffi::SSL_OP_CIPHER_SERVER_PREFERENCE;
151 const SSL_OP_TLS_ROLLBACK_BUG = ffi::SSL_OP_TLS_ROLLBACK_BUG;
152 const SSL_OP_NO_SSLV2 = ffi::SSL_OP_NO_SSLv2;
153 const SSL_OP_NO_SSLV3 = ffi::SSL_OP_NO_SSLv3;
154 const SSL_OP_NO_TLSV1 = ffi::SSL_OP_NO_TLSv1;
155 const SSL_OP_NO_TLSV1_2 = ffi::SSL_OP_NO_TLSv1_2;
156 const SSL_OP_NO_TLSV1_1 = ffi::SSL_OP_NO_TLSv1_1;
157 /// Requires the `v102` or `v110` features and OpenSSL 1.0.2 or OpenSSL 1.1.0.
158 #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))]
159 const SSL_OP_NO_DTLSV1 = ffi::SSL_OP_NO_DTLSv1;
160 /// Requires the `v102` or `v110` features and OpenSSL 1.0.2 or OpenSSL 1.1.0.
161 #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))]
162 const SSL_OP_NO_DTLSV1_2 = ffi::SSL_OP_NO_DTLSv1_2;
163 /// Requires the `v102` or `v110` features and OpenSSL 1.0.2 or OpenSSL 1.1.0.
164 #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))]
165 const SSL_OP_NO_SSL_MASK = ffi::SSL_OP_NO_SSL_MASK;
166 }
167 }
168
169 bitflags! {
170 pub struct SslMode: c_long {
171 const SSL_MODE_ENABLE_PARTIAL_WRITE = ffi::SSL_MODE_ENABLE_PARTIAL_WRITE;
172 const SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER = ffi::SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER;
173 const SSL_MODE_AUTO_RETRY = ffi::SSL_MODE_AUTO_RETRY;
174 const SSL_MODE_NO_AUTO_CHAIN = ffi::SSL_MODE_NO_AUTO_CHAIN;
175 const SSL_MODE_RELEASE_BUFFERS = ffi::SSL_MODE_RELEASE_BUFFERS;
176 #[cfg(not(libressl))]
177 const SSL_MODE_SEND_CLIENTHELLO_TIME = ffi::SSL_MODE_SEND_CLIENTHELLO_TIME;
178 #[cfg(not(libressl))]
179 const SSL_MODE_SEND_SERVERHELLO_TIME = ffi::SSL_MODE_SEND_SERVERHELLO_TIME;
180 #[cfg(not(libressl))]
181 const SSL_MODE_SEND_FALLBACK_SCSV = ffi::SSL_MODE_SEND_FALLBACK_SCSV;
182 }
183 }
184
185 #[derive(Copy, Clone)]
186 pub struct SslMethod(*const ffi::SSL_METHOD);
187
188 impl SslMethod {
189 /// Support all versions of the TLS protocol.
190 ///
191 /// This corresponds to `TLS_method` on OpenSSL 1.1.0 and `SSLv23_method`
192 /// on OpenSSL 1.0.x.
193 pub fn tls() -> SslMethod {
194 SslMethod(compat::tls_method())
195 }
196
197 /// Support all versions of the DTLS protocol.
198 ///
199 /// This corresponds to `DTLS_method` on OpenSSL 1.1.0 and `DTLSv1_method`
200 /// on OpenSSL 1.0.x.
201 pub fn dtls() -> SslMethod {
202 SslMethod(compat::dtls_method())
203 }
204
205 pub unsafe fn from_ptr(ptr: *const ffi::SSL_METHOD) -> SslMethod {
206 SslMethod(ptr)
207 }
208
209 pub fn as_ptr(&self) -> *const ffi::SSL_METHOD {
210 self.0
211 }
212 }
213
214 /// Determines the type of certificate verification used
215 bitflags! {
216 pub struct SslVerifyMode: i32 {
217 /// Verify that the server's certificate is trusted
218 const SSL_VERIFY_PEER = ::ffi::SSL_VERIFY_PEER;
219 /// Do not verify the server's certificate
220 const SSL_VERIFY_NONE = ::ffi::SSL_VERIFY_NONE;
221 /// Terminate handshake if client did not return a certificate.
222 /// Use together with SSL_VERIFY_PEER.
223 const SSL_VERIFY_FAIL_IF_NO_PEER_CERT = ::ffi::SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
224 }
225 }
226
227 #[derive(Copy, Clone)]
228 pub struct StatusType(c_int);
229
230 impl StatusType {
231 pub fn from_raw(raw: c_int) -> StatusType {
232 StatusType(raw)
233 }
234
235 pub fn as_raw(&self) -> c_int {
236 self.0
237 }
238 }
239
240 /// An OSCP status.
241 pub const STATUS_TYPE_OCSP: StatusType = StatusType(ffi::TLSEXT_STATUSTYPE_ocsp);
242
243 lazy_static! {
244 static ref INDEXES: Mutex<HashMap<TypeId, c_int>> = Mutex::new(HashMap::new());
245 static ref SSL_INDEXES: Mutex<HashMap<TypeId, c_int>> = Mutex::new(HashMap::new());
246 }
247
248 // Creates a static index for user data of type T
249 // Registers a destructor for the data which will be called
250 // when context is freed
251 fn get_callback_idx<T: Any + 'static>() -> c_int {
252 *INDEXES
253 .lock()
254 .unwrap()
255 .entry(TypeId::of::<T>())
256 .or_insert_with(|| get_new_idx::<T>())
257 }
258
259 fn get_ssl_callback_idx<T: Any + 'static>() -> c_int {
260 *SSL_INDEXES
261 .lock()
262 .unwrap()
263 .entry(TypeId::of::<T>())
264 .or_insert_with(|| get_new_ssl_idx::<T>())
265 }
266
267 lazy_static! {
268 static ref NPN_PROTOS_IDX: c_int = get_new_idx::<Vec<u8>>();
269 }
270
271 #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))]
272 lazy_static! {
273 static ref ALPN_PROTOS_IDX: c_int = get_new_idx::<Vec<u8>>();
274 }
275
276 unsafe extern "C" fn free_data_box<T>(
277 _parent: *mut c_void,
278 ptr: *mut c_void,
279 _ad: *mut ffi::CRYPTO_EX_DATA,
280 _idx: c_int,
281 _argl: c_long,
282 _argp: *mut c_void,
283 ) {
284 if !ptr.is_null() {
285 Box::<T>::from_raw(ptr as *mut T);
286 }
287 }
288
289 /// Determine a new index to use for SSL CTX ex data.
290 /// Registers a destruct for the data which will be called by openssl when the context is freed.
291 fn get_new_idx<T>() -> c_int {
292 unsafe {
293 let idx = compat::get_new_idx(free_data_box::<T>);
294 assert!(idx >= 0);
295 idx
296 }
297 }
298
299 fn get_new_ssl_idx<T>() -> c_int {
300 unsafe {
301 let idx = compat::get_new_ssl_idx(free_data_box::<T>);
302 assert!(idx >= 0);
303 idx
304 }
305 }
306
307 /// Convert a set of byte slices into a series of byte strings encoded for SSL. Encoding is a byte
308 /// containing the length followed by the string.
309 fn ssl_encode_byte_strings(strings: &[&[u8]]) -> Vec<u8> {
310 let mut enc = Vec::new();
311 for string in strings {
312 let len = string.len() as u8;
313 if len as usize != string.len() {
314 // If the item does not fit, discard it
315 continue;
316 }
317 enc.push(len);
318 enc.extend(string[..len as usize].to_vec());
319 }
320 enc
321 }
322
323 /// An error returned from an SNI callback.
324 pub enum SniError {
325 Fatal(c_int),
326 Warning(c_int),
327 NoAck,
328 }
329
330 /// A builder for `SslContext`s.
331 pub struct SslContextBuilder(*mut ffi::SSL_CTX);
332
333 unsafe impl Sync for SslContextBuilder {}
334 unsafe impl Send for SslContextBuilder {}
335
336 impl Drop for SslContextBuilder {
337 fn drop(&mut self) {
338 unsafe { ffi::SSL_CTX_free(self.as_ptr()) }
339 }
340 }
341
342 impl SslContextBuilder {
343 pub fn new(method: SslMethod) -> Result<SslContextBuilder, ErrorStack> {
344 unsafe {
345 init();
346 let ctx = try!(cvt_p(ffi::SSL_CTX_new(method.as_ptr())));
347
348 Ok(SslContextBuilder::from_ptr(ctx))
349 }
350 }
351
352 pub unsafe fn from_ptr(ctx: *mut ffi::SSL_CTX) -> SslContextBuilder {
353 SslContextBuilder(ctx)
354 }
355
356 pub fn as_ptr(&self) -> *mut ffi::SSL_CTX {
357 self.0
358 }
359
360 /// Configures the certificate verification method for new connections.
361 pub fn set_verify(&mut self, mode: SslVerifyMode) {
362 unsafe {
363 ffi::SSL_CTX_set_verify(self.as_ptr(), mode.bits as c_int, None);
364 }
365 }
366
367 /// Configures the certificate verification method for new connections and
368 /// registers a verification callback.
369 pub fn set_verify_callback<F>(&mut self, mode: SslVerifyMode, verify: F)
370 where
371 F: Fn(bool, &X509StoreContextRef) -> bool + Any + 'static + Sync + Send,
372 {
373 unsafe {
374 let verify = Box::new(verify);
375 ffi::SSL_CTX_set_ex_data(
376 self.as_ptr(),
377 get_callback_idx::<F>(),
378 mem::transmute(verify),
379 );
380 ffi::SSL_CTX_set_verify(self.as_ptr(), mode.bits as c_int, Some(raw_verify::<F>));
381 }
382 }
383
384 /// Configures the server name indication (SNI) callback for new connections
385 ///
386 /// Obtain the server name with `servername` then set the corresponding context
387 /// with `set_ssl_context`
388 pub fn set_servername_callback<F>(&mut self, callback: F)
389 where
390 F: Fn(&mut SslRef) -> Result<(), SniError> + Any + 'static + Sync + Send,
391 {
392 unsafe {
393 let callback = Box::new(callback);
394 ffi::SSL_CTX_set_ex_data(
395 self.as_ptr(),
396 get_callback_idx::<F>(),
397 mem::transmute(callback),
398 );
399 let f: extern "C" fn(_, _, _) -> _ = raw_sni::<F>;
400 let f: extern "C" fn() = mem::transmute(f);
401 ffi::SSL_CTX_set_tlsext_servername_callback(self.as_ptr(), Some(f));
402 }
403 }
404
405 /// Sets verification depth
406 pub fn set_verify_depth(&mut self, depth: u32) {
407 unsafe {
408 ffi::SSL_CTX_set_verify_depth(self.as_ptr(), depth as c_int);
409 }
410 }
411
412 /// Sets a custom X509Store for verifying peer certificates.
413 ///
414 /// Requires the `v102` feature and OpenSSL 1.0.2, or the `v110` feature and OpenSSL 1.1.0.
415 #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))]
416 pub fn set_verify_cert_store(&mut self, cert_store: X509Store) -> Result<(), ErrorStack> {
417 unsafe {
418 let ptr = cert_store.as_ptr();
419 try!(cvt(
420 ffi::SSL_CTX_set0_verify_cert_store(self.as_ptr(), ptr) as
421 c_int,
422 ));
423 mem::forget(cert_store);
424
425 Ok(())
426 }
427 }
428
429 pub fn set_read_ahead(&mut self, read_ahead: bool) {
430 unsafe {
431 ffi::SSL_CTX_set_read_ahead(self.as_ptr(), read_ahead as c_long);
432 }
433 }
434
435 pub fn set_mode(&mut self, mode: SslMode) -> SslMode {
436 unsafe {
437 let mode = ffi::SSL_CTX_set_mode(self.as_ptr(), mode.bits());
438 SslMode::from_bits(mode).unwrap()
439 }
440 }
441
442 pub fn set_tmp_dh(&mut self, dh: &DhRef) -> Result<(), ErrorStack> {
443 unsafe { cvt(ffi::SSL_CTX_set_tmp_dh(self.as_ptr(), dh.as_ptr()) as c_int).map(|_| ()) }
444 }
445
446 pub fn set_tmp_dh_callback<F>(&mut self, callback: F)
447 where
448 F: Fn(&mut SslRef, bool, u32) -> Result<Dh, ErrorStack> + Any + 'static + Sync + Send,
449 {
450 unsafe {
451 let callback = Box::new(callback);
452 ffi::SSL_CTX_set_ex_data(
453 self.as_ptr(),
454 get_callback_idx::<F>(),
455 Box::into_raw(callback) as *mut c_void,
456 );
457 let f: unsafe extern "C" fn(_, _, _) -> _ = raw_tmp_dh::<F>;
458 ffi::SSL_CTX_set_tmp_dh_callback(self.as_ptr(), f);
459 }
460 }
461
462 pub fn set_tmp_ecdh(&mut self, key: &EcKeyRef) -> Result<(), ErrorStack> {
463 unsafe {
464 cvt(ffi::SSL_CTX_set_tmp_ecdh(self.as_ptr(), key.as_ptr()) as
465 c_int).map(|_| ())
466 }
467 }
468
469 /// Requires the `v101` feature and OpenSSL 1.0.1, or the `v102` feature and OpenSSL 1.0.2.
470 #[cfg(any(all(feature = "v101", ossl101), all(feature = "v102", ossl102)))]
471 pub fn set_tmp_ecdh_callback<F>(&mut self, callback: F)
472 where
473 F: Fn(&mut SslRef, bool, u32) -> Result<EcKey, ErrorStack> + Any + 'static + Sync + Send,
474 {
475 unsafe {
476 let callback = Box::new(callback);
477 ffi::SSL_CTX_set_ex_data(
478 self.as_ptr(),
479 get_callback_idx::<F>(),
480 Box::into_raw(callback) as *mut c_void,
481 );
482 let f: unsafe extern "C" fn(_, _, _) -> _ = raw_tmp_ecdh::<F>;
483 ffi::SSL_CTX_set_tmp_ecdh_callback(self.as_ptr(), f);
484 }
485 }
486
487 /// Use the default locations of trusted certificates for verification.
488 ///
489 /// These locations are read from the `SSL_CERT_FILE` and `SSL_CERT_DIR`
490 /// environment variables if present, or defaults specified at OpenSSL
491 /// build time otherwise.
492 pub fn set_default_verify_paths(&mut self) -> Result<(), ErrorStack> {
493 unsafe { cvt(ffi::SSL_CTX_set_default_verify_paths(self.as_ptr())).map(|_| ()) }
494 }
495
496 /// Specifies the file that contains trusted CA certificates.
497 pub fn set_ca_file<P: AsRef<Path>>(&mut self, file: P) -> Result<(), ErrorStack> {
498 let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap();
499 unsafe {
500 cvt(ffi::SSL_CTX_load_verify_locations(
501 self.as_ptr(),
502 file.as_ptr() as *const _,
503 ptr::null(),
504 )).map(|_| ())
505 }
506 }
507
508 /// Sets the list of CAs sent to the client.
509 ///
510 /// The CA certificates must still be added to the trust root.
511 pub fn set_client_ca_list(&mut self, list: Stack<X509Name>) {
512 unsafe {
513 ffi::SSL_CTX_set_client_CA_list(self.as_ptr(), list.as_ptr());
514 mem::forget(list);
515 }
516 }
517
518 /// Set the context identifier for sessions
519 ///
520 /// This value identifies the server's session cache to clients, telling them when they're
521 /// able to reuse sessions. Should be set to a unique value per server, unless multiple servers
522 /// share a session cache.
523 ///
524 /// This value should be set when using client certificates, or each request will fail
525 /// handshake and need to be restarted.
526 pub fn set_session_id_context(&mut self, sid_ctx: &[u8]) -> Result<(), ErrorStack> {
527 unsafe {
528 assert!(sid_ctx.len() <= c_uint::max_value() as usize);
529 cvt(ffi::SSL_CTX_set_session_id_context(
530 self.as_ptr(),
531 sid_ctx.as_ptr(),
532 sid_ctx.len() as c_uint,
533 )).map(|_| ())
534 }
535 }
536
537 /// Loads a certificate from a file.
538 pub fn set_certificate_file<P: AsRef<Path>>(
539 &mut self,
540 file: P,
541 file_type: X509FileType,
542 ) -> Result<(), ErrorStack> {
543 let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap();
544 unsafe {
545 cvt(ffi::SSL_CTX_use_certificate_file(
546 self.as_ptr(),
547 file.as_ptr() as *const _,
548 file_type.as_raw(),
549 )).map(|_| ())
550 }
551 }
552
553 /// Loads a certificate chain from a file.
554 ///
555 /// The file should contain a sequence of PEM-formatted certificates, the first being the leaf
556 /// certificate, and the remainder forming the chain of certificates up to and including the
557 /// trusted root certificate.
558 pub fn set_certificate_chain_file<P: AsRef<Path>>(
559 &mut self,
560 file: P,
561 ) -> Result<(), ErrorStack> {
562 let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap();
563 unsafe {
564 cvt(ffi::SSL_CTX_use_certificate_chain_file(
565 self.as_ptr(),
566 file.as_ptr() as *const _,
567 )).map(|_| ())
568 }
569 }
570
571 /// Sets the certificate.
572 pub fn set_certificate(&mut self, cert: &X509Ref) -> Result<(), ErrorStack> {
573 unsafe { cvt(ffi::SSL_CTX_use_certificate(self.as_ptr(), cert.as_ptr())).map(|_| ()) }
574 }
575
576 /// Appends a certificate to the certificate chain.
577 ///
578 /// This chain should contain all certificates necessary to go from the certificate specified by
579 /// `set_certificate` to a trusted root.
580 pub fn add_extra_chain_cert(&mut self, cert: X509) -> Result<(), ErrorStack> {
581 unsafe {
582 try!(cvt(ffi::SSL_CTX_add_extra_chain_cert(
583 self.as_ptr(),
584 cert.as_ptr(),
585 ) as c_int));
586 mem::forget(cert);
587 Ok(())
588 }
589 }
590
591 /// Loads the private key from a file.
592 pub fn set_private_key_file<P: AsRef<Path>>(
593 &mut self,
594 file: P,
595 file_type: X509FileType,
596 ) -> Result<(), ErrorStack> {
597 let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap();
598 unsafe {
599 cvt(ffi::SSL_CTX_use_PrivateKey_file(
600 self.as_ptr(),
601 file.as_ptr() as *const _,
602 file_type.as_raw(),
603 )).map(|_| ())
604 }
605 }
606
607 /// Sets the private key.
608 pub fn set_private_key(&mut self, key: &PKeyRef) -> Result<(), ErrorStack> {
609 unsafe { cvt(ffi::SSL_CTX_use_PrivateKey(self.as_ptr(), key.as_ptr())).map(|_| ()) }
610 }
611
612 /// Sets the cipher configuration.
613 ///
614 /// See `man 1 ciphers` for details on the format.
615 pub fn set_cipher_list(&mut self, cipher_list: &str) -> Result<(), ErrorStack> {
616 let cipher_list = CString::new(cipher_list).unwrap();
617 unsafe {
618 cvt(ffi::SSL_CTX_set_cipher_list(
619 self.as_ptr(),
620 cipher_list.as_ptr() as *const _,
621 )).map(|_| ())
622 }
623 }
624
625 /// Enables ECDHE key exchange with an automatically chosen curve list.
626 ///
627 /// Requires the `v102` feature and OpenSSL 1.0.2.
628 #[cfg(all(feature = "v102", any(ossl102, libressl)))]
629 pub fn set_ecdh_auto(&mut self, onoff: bool) -> Result<(), ErrorStack> {
630 self._set_ecdh_auto(onoff)
631 }
632
633 #[cfg(any(ossl102, libressl))]
634 fn _set_ecdh_auto(&mut self, onoff: bool) -> Result<(), ErrorStack> {
635 unsafe { cvt(ffi::SSL_CTX_set_ecdh_auto(self.as_ptr(), onoff as c_int)).map(|_| ()) }
636 }
637
638 pub fn set_options(&mut self, option: SslOption) -> SslOption {
639 let ret = unsafe { compat::SSL_CTX_set_options(self.as_ptr(), option.bits()) };
640 SslOption::from_bits(ret).unwrap()
641 }
642
643 pub fn options(&self) -> SslOption {
644 let ret = unsafe { compat::SSL_CTX_get_options(self.as_ptr()) };
645 SslOption::from_bits(ret).unwrap()
646 }
647
648 pub fn clear_options(&mut self, option: SslOption) -> SslOption {
649 let ret = unsafe { compat::SSL_CTX_clear_options(self.as_ptr(), option.bits()) };
650 SslOption::from_bits(ret).unwrap()
651 }
652
653 /// Set the protocols to be used during Next Protocol Negotiation (the protocols
654 /// supported by the application).
655 #[cfg(not(libressl261))]
656 pub fn set_npn_protocols(&mut self, protocols: &[&[u8]]) -> Result<(), ErrorStack> {
657 // Firstly, convert the list of protocols to a byte-array that can be passed to OpenSSL
658 // APIs -- a list of length-prefixed strings.
659 let protocols: Box<Vec<u8>> = Box::new(ssl_encode_byte_strings(protocols));
660
661 unsafe {
662 // Attach the protocol list to the OpenSSL context structure,
663 // so that we can refer to it within the callback.
664 try!(cvt(ffi::SSL_CTX_set_ex_data(
665 self.as_ptr(),
666 *NPN_PROTOS_IDX,
667 Box::into_raw(protocols) as *mut c_void,
668 )));
669 // Now register the callback that performs the default protocol
670 // matching based on the client-supported list of protocols that
671 // has been saved.
672 ffi::SSL_CTX_set_next_proto_select_cb(
673 self.as_ptr(),
674 raw_next_proto_select_cb,
675 ptr::null_mut(),
676 );
677 // Also register the callback to advertise these protocols, if a server socket is
678 // created with the context.
679 ffi::SSL_CTX_set_next_protos_advertised_cb(
680 self.as_ptr(),
681 raw_next_protos_advertise_cb,
682 ptr::null_mut(),
683 );
684 Ok(())
685 }
686 }
687
688 /// Set the protocols to be used during ALPN (application layer protocol negotiation).
689 /// If this is a server, these are the protocols we report to the client.
690 /// If this is a client, these are the protocols we try to match with those reported by the
691 /// server.
692 ///
693 /// Note that ordering of the protocols controls the priority with which they are chosen.
694 ///
695 /// Requires the `v102` or `v110` features and OpenSSL 1.0.2 or OpenSSL 1.1.0.
696 #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))]
697 pub fn set_alpn_protocols(&mut self, protocols: &[&[u8]]) -> Result<(), ErrorStack> {
698 let protocols: Box<Vec<u8>> = Box::new(ssl_encode_byte_strings(protocols));
699 unsafe {
700 // Set the context's internal protocol list for use if we are a server
701 let r = ffi::SSL_CTX_set_alpn_protos(
702 self.as_ptr(),
703 protocols.as_ptr(),
704 protocols.len() as c_uint,
705 );
706 // fun fact, SSL_CTX_set_alpn_protos has a reversed return code D:
707 if r != 0 {
708 return Err(ErrorStack::get());
709 }
710
711 // Rather than use the argument to the callback to contain our data, store it in the
712 // ssl ctx's ex_data so that we can configure a function to free it later. In the
713 // future, it might make sense to pull this into our internal struct Ssl instead of
714 // leaning on openssl and using function pointers.
715 try!(cvt(ffi::SSL_CTX_set_ex_data(
716 self.as_ptr(),
717 *ALPN_PROTOS_IDX,
718 Box::into_raw(protocols) as *mut c_void,
719 )));
720
721 // Now register the callback that performs the default protocol
722 // matching based on the client-supported list of protocols that
723 // has been saved.
724 ffi::SSL_CTX_set_alpn_select_cb(self.as_ptr(), raw_alpn_select_cb, ptr::null_mut());
725
726 Ok(())
727 }
728 }
729
730 /// Checks consistency between the private key and certificate.
731 pub fn check_private_key(&self) -> Result<(), ErrorStack> {
732 unsafe { cvt(ffi::SSL_CTX_check_private_key(self.as_ptr())).map(|_| ()) }
733 }
734
735 /// Returns a shared reference to the context's certificate store.
736 pub fn cert_store(&self) -> &X509StoreBuilderRef {
737 unsafe { X509StoreBuilderRef::from_ptr(ffi::SSL_CTX_get_cert_store(self.as_ptr())) }
738 }
739
740 /// Returns a mutable reference to the context's certificate store.
741 pub fn cert_store_mut(&mut self) -> &mut X509StoreBuilderRef {
742 unsafe { X509StoreBuilderRef::from_ptr_mut(ffi::SSL_CTX_get_cert_store(self.as_ptr())) }
743 }
744
745 /// Sets the callback dealing with OCSP stapling.
746 ///
747 /// On the client side, this callback is responsible for validating the OCSP status response
748 /// returned by the server. The status may be retrieved with the `SslRef::ocsp_status` method.
749 /// A response of `Ok(true)` indicates that the OCSP status is valid, and a response of
750 /// `Ok(false)` indicates that the OCSP status is invalid and the handshake should be
751 /// terminated.
752 ///
753 /// On the server side, this callback is resopnsible for setting the OCSP status response to be
754 /// returned to clients. The status may be set with the `SslRef::set_ocsp_status` method. A
755 /// response of `Ok(true)` indicates that the OCSP status should be returned to the client, and
756 /// `Ok(false)` indicates that the status should not be returned to the client.
757 pub fn set_status_callback<F>(&mut self, callback: F) -> Result<(), ErrorStack>
758 where
759 F: Fn(&mut SslRef) -> Result<bool, ErrorStack> + Any + 'static + Sync + Send,
760 {
761 unsafe {
762 let callback = Box::new(callback);
763 ffi::SSL_CTX_set_ex_data(
764 self.as_ptr(),
765 get_callback_idx::<F>(),
766 Box::into_raw(callback) as *mut c_void,
767 );
768 let f: unsafe extern "C" fn(_, _) -> _ = raw_tlsext_status::<F>;
769 cvt(ffi::SSL_CTX_set_tlsext_status_cb(
770 self.as_ptr(),
771 Some(f),
772 ) as c_int).map(|_| ())
773 }
774 }
775
776 /// Sets the callback for providing an identity and pre-shared key for a TLS-PSK client.
777 ///
778 /// The callback will be called with the SSL context, an identity hint if one was provided
779 /// by the server, a mut slice for each of the identity and pre-shared key bytes. The identity
780 /// must be written as a null-terminated C string.
781 #[cfg(not(osslconf = "OPENSSL_NO_PSK"))]
782 pub fn set_psk_callback<F>(&mut self, callback: F)
783 where
784 F: Fn(&mut SslRef, Option<&[u8]>, &mut [u8], &mut [u8]) -> Result<usize, ErrorStack>
785 + Any
786 + 'static
787 + Sync
788 + Send,
789 {
790 unsafe {
791 let callback = Box::new(callback);
792 ffi::SSL_CTX_set_ex_data(
793 self.as_ptr(),
794 get_callback_idx::<F>(),
795 mem::transmute(callback),
796 );
797 ffi::SSL_CTX_set_psk_client_callback(self.as_ptr(), Some(raw_psk::<F>))
798 }
799 }
800
801 /// Sets the extra data at the specified index.
802 pub fn set_ex_data<T>(&mut self, index: Index<SslContext, T>, data: T) {
803 unsafe {
804 let data = Box::new(data);
805 ffi::SSL_CTX_set_ex_data(
806 self.as_ptr(),
807 index.as_raw(),
808 Box::into_raw(data) as *mut c_void,
809 );
810 }
811 }
812
813 pub fn build(self) -> SslContext {
814 let ctx = SslContext(self.0);
815 mem::forget(self);
816 ctx
817 }
818 }
819
820 foreign_type! {
821 type CType = ffi::SSL_CTX;
822 fn drop = ffi::SSL_CTX_free;
823
824 pub struct SslContext;
825 pub struct SslContextRef;
826 }
827
828 unsafe impl Send for SslContext {}
829 unsafe impl Sync for SslContext {}
830
831 impl Clone for SslContext {
832 fn clone(&self) -> Self {
833 unsafe {
834 compat::SSL_CTX_up_ref(self.as_ptr());
835 SslContext::from_ptr(self.as_ptr())
836 }
837 }
838 }
839
840 // TODO: add useful info here
841 impl fmt::Debug for SslContext {
842 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
843 write!(fmt, "SslContext")
844 }
845 }
846
847 impl SslContext {
848 pub fn builder(method: SslMethod) -> Result<SslContextBuilder, ErrorStack> {
849 SslContextBuilder::new(method)
850 }
851
852 /// Returns a new extra data index.
853 ///
854 /// Each invocation of this function is guaranteed to return a distinct
855 /// index.
856 pub fn new_ex_index<T>() -> Result<Index<SslContext, T>, ErrorStack>
857 where
858 T: 'static + Sync + Send,
859 {
860 unsafe {
861 ffi::init();
862 let idx = try!(cvt_n(compat::get_new_idx(free_data_box::<T>)));
863 Ok(Index::from_raw(idx))
864 }
865 }
866 }
867
868 impl SslContextRef {
869 /// Returns the certificate associated with this `SslContext`, if present.
870 ///
871 /// Requires the `v102` or `v110` features and OpenSSL 1.0.2 or OpenSSL 1.1.0.
872 #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))]
873 pub fn certificate(&self) -> Option<&X509Ref> {
874 unsafe {
875 let ptr = ffi::SSL_CTX_get0_certificate(self.as_ptr());
876 if ptr.is_null() {
877 None
878 } else {
879 Some(X509Ref::from_ptr(ptr))
880 }
881 }
882 }
883
884 /// Returns the private key associated with this `SslContext`, if present.
885 ///
886 /// Requires the `v102` or `v110` features and OpenSSL 1.0.2 or OpenSSL 1.1.0.
887 #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))]
888 pub fn private_key(&self) -> Option<&PKeyRef> {
889 unsafe {
890 let ptr = ffi::SSL_CTX_get0_privatekey(self.as_ptr());
891 if ptr.is_null() {
892 None
893 } else {
894 Some(PKeyRef::from_ptr(ptr))
895 }
896 }
897 }
898
899 /// Returns the certificate store used for verification.
900 pub fn cert_store(&self) -> &X509StoreRef {
901 unsafe { X509StoreRef::from_ptr(ffi::SSL_CTX_get_cert_store(self.as_ptr())) }
902 }
903
904 pub fn extra_chain_certs(&self) -> &StackRef<X509> {
905 unsafe {
906 let mut chain = ptr::null_mut();
907 ffi::SSL_CTX_get_extra_chain_certs(self.as_ptr(), &mut chain);
908 assert!(!chain.is_null());
909 StackRef::from_ptr(chain)
910 }
911 }
912
913 /// Returns a reference to the extra data at the specified index.
914 pub fn ex_data<T>(&self, index: Index<SslContext, T>) -> Option<&T> {
915 unsafe {
916 let data = ffi::SSL_CTX_get_ex_data(self.as_ptr(), index.as_raw());
917 if data.is_null() {
918 None
919 } else {
920 Some(&*(data as *const T))
921 }
922 }
923 }
924 }
925
926 pub struct CipherBits {
927 /// The number of secret bits used for the cipher.
928 pub secret: i32,
929
930 /// The number of bits processed by the chosen algorithm.
931 pub algorithm: i32,
932 }
933
934 pub struct SslCipher(*mut ffi::SSL_CIPHER);
935
936 impl ForeignType for SslCipher {
937 type CType = ffi::SSL_CIPHER;
938 type Ref = SslCipherRef;
939
940 #[inline]
941 unsafe fn from_ptr(ptr: *mut ffi::SSL_CIPHER) -> SslCipher {
942 SslCipher(ptr)
943 }
944
945 #[inline]
946 fn as_ptr(&self) -> *mut ffi::SSL_CIPHER {
947 self.0
948 }
949 }
950
951 impl Deref for SslCipher {
952 type Target = SslCipherRef;
953
954 fn deref(&self) -> &SslCipherRef {
955 unsafe { SslCipherRef::from_ptr(self.0) }
956 }
957 }
958
959 impl DerefMut for SslCipher {
960 fn deref_mut(&mut self) -> &mut SslCipherRef {
961 unsafe { SslCipherRef::from_ptr_mut(self.0) }
962 }
963 }
964
965 pub struct SslCipherRef(Opaque);
966
967 impl ForeignTypeRef for SslCipherRef {
968 type CType = ffi::SSL_CIPHER;
969 }
970
971 impl SslCipherRef {
972 /// Returns the name of cipher.
973 pub fn name(&self) -> &str {
974 let name = unsafe {
975 let ptr = ffi::SSL_CIPHER_get_name(self.as_ptr());
976 CStr::from_ptr(ptr as *const _)
977 };
978
979 str::from_utf8(name.to_bytes()).unwrap()
980 }
981
982 /// Returns the SSL/TLS protocol version that first defined the cipher.
983 pub fn version(&self) -> &str {
984 let version = unsafe {
985 let ptr = ffi::SSL_CIPHER_get_version(self.as_ptr());
986 CStr::from_ptr(ptr as *const _)
987 };
988
989 str::from_utf8(version.to_bytes()).unwrap()
990 }
991
992 /// Returns the number of bits used for the cipher.
993 pub fn bits(&self) -> CipherBits {
994 unsafe {
995 let mut algo_bits = 0;
996 let secret_bits = ffi::SSL_CIPHER_get_bits(self.as_ptr(), &mut algo_bits);
997 CipherBits {
998 secret: secret_bits.into(),
999 algorithm: algo_bits.into(),
1000 }
1001 }
1002 }
1003
1004 /// Returns a textual description of the cipher used
1005 pub fn description(&self) -> String {
1006 unsafe {
1007 // SSL_CIPHER_description requires a buffer of at least 128 bytes.
1008 let mut buf = [0; 128];
1009 let ptr = ffi::SSL_CIPHER_description(self.as_ptr(), buf.as_mut_ptr(), 128);
1010 String::from_utf8(CStr::from_ptr(ptr as *const _).to_bytes().to_vec()).unwrap()
1011 }
1012 }
1013 }
1014
1015 foreign_type! {
1016 type CType = ffi::SSL_SESSION;
1017 fn drop = ffi::SSL_SESSION_free;
1018
1019 pub struct SslSession;
1020 pub struct SslSessionRef;
1021 }
1022
1023 unsafe impl Sync for SslSession {}
1024 unsafe impl Send for SslSession {}
1025
1026 impl Clone for SslSession {
1027 fn clone(&self) -> SslSession {
1028 self.to_owned()
1029 }
1030 }
1031
1032 impl Borrow<SslSessionRef> for SslSession {
1033 fn borrow(&self) -> &SslSessionRef {
1034 &self
1035 }
1036 }
1037
1038 impl ToOwned for SslSessionRef {
1039 type Owned = SslSession;
1040
1041 fn to_owned(&self) -> SslSession {
1042 unsafe {
1043 compat::SSL_SESSION_up_ref(self.as_ptr());
1044 SslSession(self.as_ptr())
1045 }
1046 }
1047 }
1048
1049 impl SslSessionRef {
1050 /// Returns the SSL session ID.
1051 pub fn id(&self) -> &[u8] {
1052 unsafe {
1053 let mut len = 0;
1054 let p = ffi::SSL_SESSION_get_id(self.as_ptr(), &mut len);
1055 slice::from_raw_parts(p as *const u8, len as usize)
1056 }
1057 }
1058
1059 /// Returns the length of the master key.
1060 pub fn master_key_len(&self) -> usize {
1061 unsafe { compat::SSL_SESSION_get_master_key(self.as_ptr(), ptr::null_mut(), 0) }
1062 }
1063
1064 /// Copies the master key into the provided buffer.
1065 ///
1066 /// Returns the number of bytes written.
1067 pub fn master_key(&self, buf: &mut [u8]) -> usize {
1068 unsafe { compat::SSL_SESSION_get_master_key(self.as_ptr(), buf.as_mut_ptr(), buf.len()) }
1069 }
1070 }
1071
1072 foreign_type! {
1073 type CType = ffi::SSL;
1074 fn drop = ffi::SSL_free;
1075
1076 pub struct Ssl;
1077 pub struct SslRef;
1078 }
1079
1080 impl Ssl {
1081 /// Returns a new extra data index.
1082 ///
1083 /// Each invocation of this function is guaranteed to return a distinct
1084 /// index.
1085 pub fn new_ex_index<T>() -> Result<Index<Ssl, T>, ErrorStack>
1086 where
1087 T: 'static + Sync + Send,
1088 {
1089 unsafe {
1090 ffi::init();
1091 let idx = try!(cvt_n(compat::get_new_ssl_idx(free_data_box::<T>)));
1092 Ok(Index::from_raw(idx))
1093 }
1094 }
1095 }
1096
1097 impl fmt::Debug for SslRef {
1098 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1099 let mut builder = fmt.debug_struct("Ssl");
1100 builder.field("state", &self.state_string_long());
1101 if let Some(err) = self.verify_result() {
1102 builder.field("verify_result", &err);
1103 }
1104 builder.finish()
1105 }
1106 }
1107
1108 impl SslRef {
1109 fn get_raw_rbio(&self) -> *mut ffi::BIO {
1110 unsafe { ffi::SSL_get_rbio(self.as_ptr()) }
1111 }
1112
1113 fn read(&mut self, buf: &mut [u8]) -> c_int {
1114 let len = cmp::min(c_int::max_value() as usize, buf.len()) as c_int;
1115 unsafe { ffi::SSL_read(self.as_ptr(), buf.as_ptr() as *mut c_void, len) }
1116 }
1117
1118 fn write(&mut self, buf: &[u8]) -> c_int {
1119 let len = cmp::min(c_int::max_value() as usize, buf.len()) as c_int;
1120 unsafe { ffi::SSL_write(self.as_ptr(), buf.as_ptr() as *const c_void, len) }
1121 }
1122
1123 fn get_error(&self, ret: c_int) -> c_int {
1124 unsafe { ffi::SSL_get_error(self.as_ptr(), ret) }
1125 }
1126
1127 /// Sets the verification mode to be used during the handshake process.
1128 ///
1129 /// Use `set_verify_callback` to additionally add a callback.
1130 pub fn set_verify(&mut self, mode: SslVerifyMode) {
1131 unsafe { ffi::SSL_set_verify(self.as_ptr(), mode.bits as c_int, None) }
1132 }
1133
1134 /// Sets the certificate verification callback to be used during the
1135 /// handshake process.
1136 ///
1137 /// The callback is provided with a boolean indicating if the
1138 /// preveification process was successful, and an object providing access
1139 /// to the certificate chain. It should return `true` if the certificate
1140 /// chain is valid and `false` otherwise.
1141 pub fn set_verify_callback<F>(&mut self, mode: SslVerifyMode, verify: F)
1142 where
1143 F: Fn(bool, &X509StoreContextRef) -> bool + Any + 'static + Sync + Send,
1144 {
1145 unsafe {
1146 let verify = Box::new(verify);
1147 ffi::SSL_set_ex_data(
1148 self.as_ptr(),
1149 get_ssl_callback_idx::<F>(),
1150 mem::transmute(verify),
1151 );
1152 ffi::SSL_set_verify(self.as_ptr(), mode.bits as c_int, Some(ssl_raw_verify::<F>));
1153 }
1154 }
1155
1156 pub fn set_tmp_dh(&mut self, dh: &DhRef) -> Result<(), ErrorStack> {
1157 unsafe { cvt(ffi::SSL_set_tmp_dh(self.as_ptr(), dh.as_ptr()) as c_int).map(|_| ()) }
1158 }
1159
1160 pub fn set_tmp_dh_callback<F>(&mut self, callback: F)
1161 where
1162 F: Fn(&mut SslRef, bool, u32) -> Result<Dh, ErrorStack> + Any + 'static + Sync + Send,
1163 {
1164 unsafe {
1165 let callback = Box::new(callback);
1166 ffi::SSL_set_ex_data(
1167 self.as_ptr(),
1168 get_ssl_callback_idx::<F>(),
1169 Box::into_raw(callback) as *mut c_void,
1170 );
1171 let f: unsafe extern "C" fn(_, _, _) -> _ = raw_tmp_dh_ssl::<F>;
1172 ffi::SSL_set_tmp_dh_callback(self.as_ptr(), f);
1173 }
1174 }
1175
1176 pub fn set_tmp_ecdh(&mut self, key: &EcKeyRef) -> Result<(), ErrorStack> {
1177 unsafe { cvt(ffi::SSL_set_tmp_ecdh(self.as_ptr(), key.as_ptr()) as c_int).map(|_| ()) }
1178 }
1179
1180 /// Requires the `v101` feature and OpenSSL 1.0.1, or the `v102` feature and OpenSSL 1.0.2.
1181 #[cfg(any(all(feature = "v101", ossl101), all(feature = "v102", ossl102)))]
1182 pub fn set_tmp_ecdh_callback<F>(&mut self, callback: F)
1183 where
1184 F: Fn(&mut SslRef, bool, u32) -> Result<EcKey, ErrorStack> + Any + 'static + Sync + Send,
1185 {
1186 unsafe {
1187 let callback = Box::new(callback);
1188 ffi::SSL_set_ex_data(
1189 self.as_ptr(),
1190 get_ssl_callback_idx::<F>(),
1191 Box::into_raw(callback) as *mut c_void,
1192 );
1193 let f: unsafe extern "C" fn(_, _, _) -> _ = raw_tmp_ecdh_ssl::<F>;
1194 ffi::SSL_set_tmp_ecdh_callback(self.as_ptr(), f);
1195 }
1196 }
1197
1198 /// If `onoff` is set to `true`, enable ECDHE for key exchange with
1199 /// compatible clients, and automatically select an appropriate elliptic
1200 /// curve.
1201 ///
1202 /// Requires the `v102` feature and OpenSSL 1.0.2.
1203 #[cfg(all(feature = "v102", ossl102))]
1204 pub fn set_ecdh_auto(&mut self, onoff: bool) -> Result<(), ErrorStack> {
1205 unsafe { cvt(ffi::SSL_set_ecdh_auto(self.as_ptr(), onoff as c_int)).map(|_| ()) }
1206 }
1207
1208 pub fn current_cipher(&self) -> Option<&SslCipherRef> {
1209 unsafe {
1210 let ptr = ffi::SSL_get_current_cipher(self.as_ptr());
1211
1212 if ptr.is_null() {
1213 None
1214 } else {
1215 Some(SslCipherRef::from_ptr(ptr as *mut _))
1216 }
1217 }
1218 }
1219
1220 pub fn state_string(&self) -> &'static str {
1221 let state = unsafe {
1222 let ptr = ffi::SSL_state_string(self.as_ptr());
1223 CStr::from_ptr(ptr as *const _)
1224 };
1225
1226 str::from_utf8(state.to_bytes()).unwrap()
1227 }
1228
1229 pub fn state_string_long(&self) -> &'static str {
1230 let state = unsafe {
1231 let ptr = ffi::SSL_state_string_long(self.as_ptr());
1232 CStr::from_ptr(ptr as *const _)
1233 };
1234
1235 str::from_utf8(state.to_bytes()).unwrap()
1236 }
1237
1238 /// Sets the host name to be used with SNI (Server Name Indication).
1239 pub fn set_hostname(&mut self, hostname: &str) -> Result<(), ErrorStack> {
1240 let cstr = CString::new(hostname).unwrap();
1241 unsafe {
1242 cvt(ffi::SSL_set_tlsext_host_name(
1243 self.as_ptr(),
1244 cstr.as_ptr() as *mut _,
1245 ) as c_int).map(|_| ())
1246 }
1247 }
1248
1249 /// Returns the certificate of the peer, if present.
1250 pub fn peer_certificate(&self) -> Option<X509> {
1251 unsafe {
1252 let ptr = ffi::SSL_get_peer_certificate(self.as_ptr());
1253 if ptr.is_null() {
1254 None
1255 } else {
1256 Some(X509::from_ptr(ptr))
1257 }
1258 }
1259 }
1260
1261 /// Returns the certificate chain of the peer, if present.
1262 ///
1263 /// On the client side, the chain includes the leaf certificate, but on the server side it does
1264 /// not. Fun!
1265 pub fn peer_cert_chain(&self) -> Option<&StackRef<X509>> {
1266 unsafe {
1267 let ptr = ffi::SSL_get_peer_cert_chain(self.as_ptr());
1268 if ptr.is_null() {
1269 None
1270 } else {
1271 Some(StackRef::from_ptr(ptr))
1272 }
1273 }
1274 }
1275
1276 /// Returns the certificate associated with this `Ssl`, if present.
1277 pub fn certificate(&self) -> Option<&X509Ref> {
1278 unsafe {
1279 let ptr = ffi::SSL_get_certificate(self.as_ptr());
1280 if ptr.is_null() {
1281 None
1282 } else {
1283 Some(X509Ref::from_ptr(ptr))
1284 }
1285 }
1286 }
1287
1288 /// Returns the private key associated with this `Ssl`, if present.
1289 pub fn private_key(&self) -> Option<&PKeyRef> {
1290 unsafe {
1291 let ptr = ffi::SSL_get_privatekey(self.as_ptr());
1292 if ptr.is_null() {
1293 None
1294 } else {
1295 Some(PKeyRef::from_ptr(ptr))
1296 }
1297 }
1298 }
1299
1300 /// Returns the name of the protocol used for the connection, e.g. "TLSv1.2", "SSLv3", etc.
1301 pub fn version(&self) -> &'static str {
1302 let version = unsafe {
1303 let ptr = ffi::SSL_get_version(self.as_ptr());
1304 CStr::from_ptr(ptr as *const _)
1305 };
1306
1307 str::from_utf8(version.to_bytes()).unwrap()
1308 }
1309
1310 /// Returns the protocol selected by performing Next Protocol Negotiation, if any.
1311 ///
1312 /// The protocol's name is returned is an opaque sequence of bytes. It is up to the client
1313 /// to interpret it.
1314 #[cfg(not(libressl261))]
1315 pub fn selected_npn_protocol(&self) -> Option<&[u8]> {
1316 unsafe {
1317 let mut data: *const c_uchar = ptr::null();
1318 let mut len: c_uint = 0;
1319 // Get the negotiated protocol from the SSL instance.
1320 // `data` will point at a `c_uchar` array; `len` will contain the length of this array.
1321 ffi::SSL_get0_next_proto_negotiated(self.as_ptr(), &mut data, &mut len);
1322
1323 if data.is_null() {
1324 None
1325 } else {
1326 Some(slice::from_raw_parts(data, len as usize))
1327 }
1328 }
1329 }
1330
1331 /// Returns the protocol selected by performing ALPN, if any.
1332 ///
1333 /// The protocol's name is returned is an opaque sequence of bytes. It is up to the client
1334 /// to interpret it.
1335 ///
1336 /// Requires the `v102` or `v110` features and OpenSSL 1.0.2 or OpenSSL 1.1.0.
1337 #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))]
1338 pub fn selected_alpn_protocol(&self) -> Option<&[u8]> {
1339 unsafe {
1340 let mut data: *const c_uchar = ptr::null();
1341 let mut len: c_uint = 0;
1342 // Get the negotiated protocol from the SSL instance.
1343 // `data` will point at a `c_uchar` array; `len` will contain the length of this array.
1344 ffi::SSL_get0_alpn_selected(self.as_ptr(), &mut data, &mut len);
1345
1346 if data.is_null() {
1347 None
1348 } else {
1349 Some(slice::from_raw_parts(data, len as usize))
1350 }
1351 }
1352 }
1353
1354 /// Returns the number of bytes remaining in the currently processed TLS
1355 /// record.
1356 pub fn pending(&self) -> usize {
1357 unsafe { ffi::SSL_pending(self.as_ptr()) as usize }
1358 }
1359
1360 /// Returns the compression currently in use.
1361 ///
1362 /// The result will be either None, indicating no compression is in use, or
1363 /// a string with the compression name.
1364 pub fn compression(&self) -> Option<&str> {
1365 self._compression()
1366 }
1367
1368 #[cfg(not(osslconf = "OPENSSL_NO_COMP"))]
1369 fn _compression(&self) -> Option<&str> {
1370 unsafe {
1371 let ptr = ffi::SSL_get_current_compression(self.as_ptr());
1372 if ptr == ptr::null() {
1373 return None;
1374 }
1375 let meth = ffi::SSL_COMP_get_name(ptr);
1376 Some(
1377 str::from_utf8(CStr::from_ptr(meth as *const _).to_bytes()).unwrap(),
1378 )
1379 }
1380 }
1381
1382 #[cfg(osslconf = "OPENSSL_NO_COMP")]
1383 fn _compression(&self) -> Option<&str> {
1384 None
1385 }
1386
1387 /// Returns the server's name for the current connection
1388 pub fn servername(&self) -> Option<&str> {
1389 unsafe {
1390 let name = ffi::SSL_get_servername(self.as_ptr(), ffi::TLSEXT_NAMETYPE_host_name);
1391 if name == ptr::null() {
1392 return None;
1393 }
1394
1395 Some(
1396 str::from_utf8(CStr::from_ptr(name as *const _).to_bytes()).unwrap(),
1397 )
1398 }
1399 }
1400
1401 /// Changes the context corresponding to the current connection.
1402 pub fn set_ssl_context(&mut self, ctx: &SslContextRef) -> Result<(), ErrorStack> {
1403 unsafe { cvt_p(ffi::SSL_set_SSL_CTX(self.as_ptr(), ctx.as_ptr())).map(|_| ()) }
1404 }
1405
1406 /// Returns the context corresponding to the current connection
1407 pub fn ssl_context(&self) -> &SslContextRef {
1408 unsafe {
1409 let ssl_ctx = ffi::SSL_get_SSL_CTX(self.as_ptr());
1410 SslContextRef::from_ptr(ssl_ctx)
1411 }
1412 }
1413
1414 /// Returns the X509 verification configuration.
1415 ///
1416 /// Requires the `v102` or `v110` features and OpenSSL 1.0.2 or 1.1.0.
1417 #[cfg(any(all(feature = "v102", ossl102), all(feature = "v110", ossl110)))]
1418 pub fn param_mut(&mut self) -> &mut X509VerifyParamRef {
1419 self._param_mut()
1420 }
1421
1422 #[cfg(any(ossl102, ossl110))]
1423 fn _param_mut(&mut self) -> &mut X509VerifyParamRef {
1424 unsafe { X509VerifyParamRef::from_ptr_mut(ffi::SSL_get0_param(self.as_ptr())) }
1425 }
1426
1427 /// Returns the result of X509 certificate verification.
1428 pub fn verify_result(&self) -> Option<X509VerifyError> {
1429 unsafe { X509VerifyError::from_raw(ffi::SSL_get_verify_result(self.as_ptr())) }
1430 }
1431
1432 /// Returns the SSL session.
1433 pub fn session(&self) -> Option<&SslSessionRef> {
1434 unsafe {
1435 let p = ffi::SSL_get_session(self.as_ptr());
1436 if p.is_null() {
1437 None
1438 } else {
1439 Some(SslSessionRef::from_ptr(p))
1440 }
1441 }
1442 }
1443
1444 /// Sets the session to be used.
1445 ///
1446 /// # Safety
1447 ///
1448 /// The caller of this method is responsible for ensuring that the session is associated
1449 /// with the same `SslContext` as this `Ssl`.
1450 pub unsafe fn set_session(&mut self, session: &SslSessionRef) -> Result<(), ErrorStack> {
1451 cvt(ffi::SSL_set_session(self.as_ptr(), session.as_ptr())).map(|_| ())
1452 }
1453
1454 /// Determines if the session provided to `set_session` was successfully reused.
1455 pub fn session_reused(&self) -> bool {
1456 unsafe { ffi::SSL_session_reused(self.as_ptr()) != 0 }
1457 }
1458
1459 /// Sets the status response a client wishes the server to reply with.
1460 pub fn set_status_type(&mut self, type_: StatusType) -> Result<(), ErrorStack> {
1461 unsafe {
1462 cvt(ffi::SSL_set_tlsext_status_type(
1463 self.as_ptr(),
1464 type_.as_raw(),
1465 ) as c_int).map(|_| ())
1466 }
1467 }
1468
1469 /// Returns the server's OCSP response, if present.
1470 pub fn ocsp_status(&self) -> Option<&[u8]> {
1471 unsafe {
1472 let mut p = ptr::null_mut();
1473 let len = ffi::SSL_get_tlsext_status_ocsp_resp(self.as_ptr(), &mut p);
1474
1475 if len < 0 {
1476 None
1477 } else {
1478 Some(slice::from_raw_parts(p as *const u8, len as usize))
1479 }
1480 }
1481 }
1482
1483 /// Sets the OCSP response to be returned to the client.
1484 pub fn set_ocsp_status(&mut self, response: &[u8]) -> Result<(), ErrorStack> {
1485 unsafe {
1486 assert!(response.len() <= c_int::max_value() as usize);
1487 let p = try!(cvt_p(ffi::CRYPTO_malloc(
1488 response.len() as _,
1489 concat!(file!(), "\0").as_ptr() as *const _,
1490 line!() as c_int,
1491 )));
1492 ptr::copy_nonoverlapping(response.as_ptr(), p as *mut u8, response.len());
1493 cvt(ffi::SSL_set_tlsext_status_ocsp_resp(
1494 self.as_ptr(),
1495 p as *mut c_uchar,
1496 response.len() as c_long,
1497 ) as c_int).map(|_| ())
1498 }
1499 }
1500
1501 /// Determines if this `Ssl` is configured for server-side or client-side use.
1502 pub fn is_server(&self) -> bool {
1503 unsafe { compat::SSL_is_server(self.as_ptr()) != 0 }
1504 }
1505
1506 /// Sets the extra data at the specified index.
1507 pub fn set_ex_data<T>(&mut self, index: Index<Ssl, T>, data: T) {
1508 unsafe {
1509 let data = Box::new(data);
1510 ffi::SSL_set_ex_data(
1511 self.as_ptr(),
1512 index.as_raw(),
1513 Box::into_raw(data) as *mut c_void,
1514 );
1515 }
1516 }
1517
1518 /// Returns a reference to the extra data at the specified index.
1519 pub fn ex_data<T>(&self, index: Index<Ssl, T>) -> Option<&T> {
1520 unsafe {
1521 let data = ffi::SSL_get_ex_data(self.as_ptr(), index.as_raw());
1522 if data.is_null() {
1523 None
1524 } else {
1525 Some(&*(data as *const T))
1526 }
1527 }
1528 }
1529 }
1530
1531 unsafe impl Sync for Ssl {}
1532 unsafe impl Send for Ssl {}
1533
1534 impl fmt::Debug for Ssl {
1535 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1536 fmt::Debug::fmt(&**self, fmt)
1537 }
1538 }
1539
1540 impl Ssl {
1541 pub fn new(ctx: &SslContext) -> Result<Ssl, ErrorStack> {
1542 unsafe {
1543 let ssl = try!(cvt_p(ffi::SSL_new(ctx.as_ptr())));
1544 Ok(Ssl::from_ptr(ssl))
1545 }
1546 }
1547
1548 /// Creates an SSL/TLS client operating over the provided stream.
1549 ///
1550 /// # Warning
1551 ///
1552 /// OpenSSL's default configuration is insecure. It is highly recommended to use
1553 /// `SslConnector` rather than `Ssl` directly, as it manages that configuration.
1554 pub fn connect<S>(self, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
1555 where
1556 S: Read + Write,
1557 {
1558 let mut stream = SslStream::new_base(self, stream);
1559 let ret = unsafe { ffi::SSL_connect(stream.ssl.as_ptr()) };
1560 if ret > 0 {
1561 Ok(stream)
1562 } else {
1563 match stream.make_error(ret) {
1564 e @ Error::WantWrite(_) |
1565 e @ Error::WantRead(_) => {
1566 Err(HandshakeError::Interrupted(MidHandshakeSslStream {
1567 stream: stream,
1568 error: e,
1569 }))
1570 }
1571 err => {
1572 Err(HandshakeError::Failure(MidHandshakeSslStream {
1573 stream: stream,
1574 error: err,
1575 }))
1576 }
1577 }
1578 }
1579 }
1580
1581 /// Creates an SSL/TLS server operating over the provided stream.
1582 ///
1583 /// # Warning
1584 ///
1585 /// OpenSSL's default configuration is insecure. It is highly recommended to use
1586 /// `SslAcceptor` rather than `Ssl` directly, as it manages that configuration.
1587 pub fn accept<S>(self, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
1588 where
1589 S: Read + Write,
1590 {
1591 let mut stream = SslStream::new_base(self, stream);
1592 let ret = unsafe { ffi::SSL_accept(stream.ssl.as_ptr()) };
1593 if ret > 0 {
1594 Ok(stream)
1595 } else {
1596 match stream.make_error(ret) {
1597 e @ Error::WantWrite(_) |
1598 e @ Error::WantRead(_) => {
1599 Err(HandshakeError::Interrupted(MidHandshakeSslStream {
1600 stream: stream,
1601 error: e,
1602 }))
1603 }
1604 err => {
1605 Err(HandshakeError::Failure(MidHandshakeSslStream {
1606 stream: stream,
1607 error: err,
1608 }))
1609 }
1610 }
1611 }
1612 }
1613 }
1614
1615 /// An SSL stream midway through the handshake process.
1616 #[derive(Debug)]
1617 pub struct MidHandshakeSslStream<S> {
1618 stream: SslStream<S>,
1619 error: Error,
1620 }
1621
1622 impl<S> MidHandshakeSslStream<S> {
1623 /// Returns a shared reference to the inner stream.
1624 pub fn get_ref(&self) -> &S {
1625 self.stream.get_ref()
1626 }
1627
1628 /// Returns a mutable reference to the inner stream.
1629 pub fn get_mut(&mut self) -> &mut S {
1630 self.stream.get_mut()
1631 }
1632
1633 /// Returns a shared reference to the `Ssl` of the stream.
1634 pub fn ssl(&self) -> &SslRef {
1635 self.stream.ssl()
1636 }
1637
1638 /// Returns the underlying error which interrupted this handshake.
1639 pub fn error(&self) -> &Error {
1640 &self.error
1641 }
1642
1643 /// Consumes `self`, returning its error.
1644 pub fn into_error(self) -> Error {
1645 self.error
1646 }
1647
1648 /// Restarts the handshake process.
1649 pub fn handshake(mut self) -> Result<SslStream<S>, HandshakeError<S>> {
1650 let ret = unsafe { ffi::SSL_do_handshake(self.stream.ssl.as_ptr()) };
1651 if ret > 0 {
1652 Ok(self.stream)
1653 } else {
1654 match self.stream.make_error(ret) {
1655 e @ Error::WantWrite(_) |
1656 e @ Error::WantRead(_) => {
1657 self.error = e;
1658 Err(HandshakeError::Interrupted(self))
1659 }
1660 err => {
1661 self.error = err;
1662 Err(HandshakeError::Failure(self))
1663 }
1664 }
1665 }
1666 }
1667 }
1668
1669 /// A stream wrapper which handles SSL encryption for an underlying stream.
1670 pub struct SslStream<S> {
1671 ssl: Ssl,
1672 _method: BioMethod, // NOTE: this *must* be after the Ssl field so things drop right
1673 _p: PhantomData<S>,
1674 }
1675
1676 impl<S> fmt::Debug for SslStream<S>
1677 where
1678 S: fmt::Debug,
1679 {
1680 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
1681 fmt.debug_struct("SslStream")
1682 .field("stream", &self.get_ref())
1683 .field("ssl", &self.ssl())
1684 .finish()
1685 }
1686 }
1687
1688 impl<S: Read + Write> SslStream<S> {
1689 fn new_base(ssl: Ssl, stream: S) -> Self {
1690 unsafe {
1691 let (bio, method) = bio::new(stream).unwrap();
1692 ffi::SSL_set_bio(ssl.as_ptr(), bio, bio);
1693
1694 SslStream {
1695 ssl: ssl,
1696 _method: method,
1697 _p: PhantomData,
1698 }
1699 }
1700 }
1701
1702 /// Like `read`, but returns an `ssl::Error` rather than an `io::Error`.
1703 ///
1704 /// This is particularly useful with a nonblocking socket, where the error
1705 /// value will identify if OpenSSL is waiting on read or write readiness.
1706 pub fn ssl_read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
1707 // The intepretation of the return code here is a little odd with a
1708 // zero-length write. OpenSSL will likely correctly report back to us
1709 // that it read zero bytes, but zero is also the sentinel for "error".
1710 // To avoid that confusion short-circuit that logic and return quickly
1711 // if `buf` has a length of zero.
1712 if buf.len() == 0 {
1713 return Ok(0);
1714 }
1715
1716 let ret = self.ssl.read(buf);
1717 if ret > 0 {
1718 Ok(ret as usize)
1719 } else {
1720 match self.make_error(ret) {
1721 // Don't treat unexpected EOFs as errors when reading
1722 Error::Stream(ref e) if e.kind() == io::ErrorKind::ConnectionAborted => Ok(0),
1723 e => Err(e),
1724 }
1725 }
1726 }
1727
1728 /// Like `write`, but returns an `ssl::Error` rather than an `io::Error`.
1729 ///
1730 /// This is particularly useful with a nonblocking socket, where the error
1731 /// value will identify if OpenSSL is waiting on read or write readiness.
1732 pub fn ssl_write(&mut self, buf: &[u8]) -> Result<usize, Error> {
1733 // See above for why we short-circuit on zero-length buffers
1734 if buf.len() == 0 {
1735 return Ok(0);
1736 }
1737
1738 let ret = self.ssl.write(buf);
1739 if ret > 0 {
1740 Ok(ret as usize)
1741 } else {
1742 Err(self.make_error(ret))
1743 }
1744 }
1745
1746 /// Shuts down the session.
1747 ///
1748 /// The shutdown process consists of two steps. The first step sends a
1749 /// close notify message to the peer, after which `ShutdownResult::Sent`
1750 /// is returned. The second step awaits the receipt of a close notify
1751 /// message from the peer, after which `ShutdownResult::Received` is
1752 /// returned.
1753 ///
1754 /// While the connection may be closed after the first step, it is
1755 /// recommended to fully shut the session down. In particular, it must
1756 /// be fully shut down if the connection is to be used for further
1757 /// communication in the future.
1758 pub fn shutdown(&mut self) -> Result<ShutdownResult, Error> {
1759 match unsafe { ffi::SSL_shutdown(self.ssl.as_ptr()) } {
1760 0 => Ok(ShutdownResult::Sent),
1761 1 => Ok(ShutdownResult::Received),
1762 n => Err(self.make_error(n)),
1763 }
1764 }
1765 }
1766
1767 impl<S> SslStream<S> {
1768 fn make_error(&mut self, ret: c_int) -> Error {
1769 self.check_panic();
1770
1771 match self.ssl.get_error(ret) {
1772 ffi::SSL_ERROR_SSL => Error::Ssl(ErrorStack::get()),
1773 ffi::SSL_ERROR_SYSCALL => {
1774 let errs = ErrorStack::get();
1775 if errs.errors().is_empty() {
1776 match self.get_bio_error() {
1777 Some(err) => Error::Stream(err),
1778 None => {
1779 Error::Stream(io::Error::new(
1780 io::ErrorKind::ConnectionAborted,
1781 "unexpected EOF observed",
1782 ))
1783 }
1784 }
1785 } else {
1786 Error::Ssl(errs)
1787 }
1788 }
1789 ffi::SSL_ERROR_ZERO_RETURN => Error::ZeroReturn,
1790 ffi::SSL_ERROR_WANT_WRITE => {
1791 let err = match self.get_bio_error() {
1792 Some(err) => err,
1793 None => {
1794 io::Error::new(
1795 io::ErrorKind::Other,
1796 "BUG: got an SSL_ERROR_WANT_WRITE with no error in the BIO",
1797 )
1798 }
1799 };
1800 Error::WantWrite(err)
1801 }
1802 ffi::SSL_ERROR_WANT_READ => {
1803 let err = match self.get_bio_error() {
1804 Some(err) => err,
1805 None => {
1806 io::Error::new(
1807 io::ErrorKind::Other,
1808 "BUG: got an SSL_ERROR_WANT_WRITE with no error in the BIO",
1809 )
1810 }
1811 };
1812 Error::WantRead(err)
1813 }
1814 err => {
1815 Error::Stream(io::Error::new(
1816 io::ErrorKind::InvalidData,
1817 format!("unexpected error {}", err),
1818 ))
1819 }
1820 }
1821 }
1822
1823 fn check_panic(&mut self) {
1824 if let Some(err) = unsafe { bio::take_panic::<S>(self.ssl.get_raw_rbio()) } {
1825 resume_unwind(err)
1826 }
1827 }
1828
1829 fn get_bio_error(&mut self) -> Option<io::Error> {
1830 unsafe { bio::take_error::<S>(self.ssl.get_raw_rbio()) }
1831 }
1832
1833 /// Returns a reference to the underlying stream.
1834 pub fn get_ref(&self) -> &S {
1835 unsafe {
1836 let bio = self.ssl.get_raw_rbio();
1837 bio::get_ref(bio)
1838 }
1839 }
1840
1841 /// Returns a mutable reference to the underlying stream.
1842 ///
1843 /// ## Warning
1844 ///
1845 /// It is inadvisable to read from or write to the underlying stream as it
1846 /// will most likely corrupt the SSL session.
1847 pub fn get_mut(&mut self) -> &mut S {
1848 unsafe {
1849 let bio = self.ssl.get_raw_rbio();
1850 bio::get_mut(bio)
1851 }
1852 }
1853
1854 /// Returns the OpenSSL `Ssl` object associated with this stream.
1855 pub fn ssl(&self) -> &SslRef {
1856 &self.ssl
1857 }
1858 }
1859
1860 impl<S: Read + Write> Read for SslStream<S> {
1861 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
1862 match self.ssl_read(buf) {
1863 Ok(n) => Ok(n),
1864 Err(Error::ZeroReturn) => Ok(0),
1865 Err(Error::Stream(e)) => Err(e),
1866 Err(Error::WantRead(e)) => Err(e),
1867 Err(Error::WantWrite(e)) => Err(e),
1868 Err(e) => Err(io::Error::new(io::ErrorKind::Other, e)),
1869 }
1870 }
1871 }
1872
1873 impl<S: Read + Write> Write for SslStream<S> {
1874 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
1875 self.ssl_write(buf).map_err(|e| match e {
1876 Error::Stream(e) => e,
1877 Error::WantRead(e) => e,
1878 Error::WantWrite(e) => e,
1879 e => io::Error::new(io::ErrorKind::Other, e),
1880 })
1881 }
1882
1883 fn flush(&mut self) -> io::Result<()> {
1884 self.get_mut().flush()
1885 }
1886 }
1887
1888 /// The result of a shutdown request.
1889 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
1890 pub enum ShutdownResult {
1891 /// A close notify message has been sent to the peer.
1892 Sent,
1893
1894 /// A close notify response message has been received from the peer.
1895 Received,
1896 }
1897
1898 #[cfg(ossl110)]
1899 mod compat {
1900 use std::ptr;
1901
1902 use ffi;
1903 use libc::c_int;
1904
1905 pub use ffi::{SSL_CTX_get_options, SSL_CTX_set_options, SSL_CTX_clear_options, SSL_CTX_up_ref,
1906 SSL_SESSION_get_master_key, SSL_is_server, SSL_SESSION_up_ref};
1907
1908 pub unsafe fn get_new_idx(f: ffi::CRYPTO_EX_free) -> c_int {
1909 ffi::CRYPTO_get_ex_new_index(
1910 ffi::CRYPTO_EX_INDEX_SSL_CTX,
1911 0,
1912 ptr::null_mut(),
1913 None,
1914 None,
1915 Some(f),
1916 )
1917 }
1918
1919 pub unsafe fn get_new_ssl_idx(f: ffi::CRYPTO_EX_free) -> c_int {
1920 ffi::CRYPTO_get_ex_new_index(
1921 ffi::CRYPTO_EX_INDEX_SSL,
1922 0,
1923 ptr::null_mut(),
1924 None,
1925 None,
1926 Some(f),
1927 )
1928 }
1929
1930 pub fn tls_method() -> *const ffi::SSL_METHOD {
1931 unsafe { ffi::TLS_method() }
1932 }
1933
1934 pub fn dtls_method() -> *const ffi::SSL_METHOD {
1935 unsafe { ffi::DTLS_method() }
1936 }
1937 }
1938
1939 #[cfg(ossl10x)]
1940 #[allow(bad_style)]
1941 mod compat {
1942 use std::ptr;
1943
1944 use ffi;
1945 use libc::{self, c_long, c_ulong, c_int, size_t, c_uchar};
1946
1947 pub unsafe fn SSL_CTX_get_options(ctx: *const ffi::SSL_CTX) -> c_ulong {
1948 ffi::SSL_CTX_ctrl(ctx as *mut _, ffi::SSL_CTRL_OPTIONS, 0, ptr::null_mut()) as c_ulong
1949 }
1950
1951 pub unsafe fn SSL_CTX_set_options(ctx: *const ffi::SSL_CTX, op: c_ulong) -> c_ulong {
1952 ffi::SSL_CTX_ctrl(
1953 ctx as *mut _,
1954 ffi::SSL_CTRL_OPTIONS,
1955 op as c_long,
1956 ptr::null_mut(),
1957 ) as c_ulong
1958 }
1959
1960 pub unsafe fn SSL_CTX_clear_options(ctx: *const ffi::SSL_CTX, op: c_ulong) -> c_ulong {
1961 ffi::SSL_CTX_ctrl(
1962 ctx as *mut _,
1963 ffi::SSL_CTRL_CLEAR_OPTIONS,
1964 op as c_long,
1965 ptr::null_mut(),
1966 ) as c_ulong
1967 }
1968
1969 pub unsafe fn get_new_idx(f: ffi::CRYPTO_EX_free) -> c_int {
1970 ffi::SSL_CTX_get_ex_new_index(0, ptr::null_mut(), None, None, Some(f))
1971 }
1972
1973 pub unsafe fn get_new_ssl_idx(f: ffi::CRYPTO_EX_free) -> c_int {
1974 ffi::SSL_get_ex_new_index(0, ptr::null_mut(), None, None, Some(f))
1975 }
1976
1977 pub unsafe fn SSL_CTX_up_ref(ssl: *mut ffi::SSL_CTX) -> libc::c_int {
1978 ffi::CRYPTO_add_lock(
1979 &mut (*ssl).references,
1980 1,
1981 ffi::CRYPTO_LOCK_SSL_CTX,
1982 "mod.rs\0".as_ptr() as *const _,
1983 line!() as libc::c_int,
1984 );
1985 0
1986 }
1987
1988 pub unsafe fn SSL_SESSION_get_master_key(
1989 session: *const ffi::SSL_SESSION,
1990 out: *mut c_uchar,
1991 mut outlen: size_t,
1992 ) -> size_t {
1993 if outlen == 0 {
1994 return (*session).master_key_length as size_t;
1995 }
1996 if outlen > (*session).master_key_length as size_t {
1997 outlen = (*session).master_key_length as size_t;
1998 }
1999 ptr::copy_nonoverlapping((*session).master_key.as_ptr(), out, outlen);
2000 outlen
2001 }
2002
2003 pub fn tls_method() -> *const ffi::SSL_METHOD {
2004 unsafe { ffi::SSLv23_method() }
2005 }
2006
2007 pub fn dtls_method() -> *const ffi::SSL_METHOD {
2008 unsafe { ffi::DTLSv1_method() }
2009 }
2010
2011 pub unsafe fn SSL_is_server(s: *mut ffi::SSL) -> c_int {
2012 (*s).server
2013 }
2014
2015 pub unsafe fn SSL_SESSION_up_ref(ses: *mut ffi::SSL_SESSION) -> c_int {
2016 ffi::CRYPTO_add_lock(
2017 &mut (*ses).references,
2018 1,
2019 ffi::CRYPTO_LOCK_SSL_CTX,
2020 "mod.rs\0".as_ptr() as *const _,
2021 line!() as libc::c_int,
2022 );
2023 0
2024 }
2025 }