• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 //! ```no_run
11 //! use openssl::ssl::{SslMethod, SslConnector};
12 //! use std::io::{Read, Write};
13 //! use std::net::TcpStream;
14 //!
15 //! let connector = SslConnector::builder(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::ssl::{SslMethod, SslAcceptor, SslStream, SslFiletype};
30 //! use std::net::{TcpListener, TcpStream};
31 //! use std::sync::Arc;
32 //! use std::thread;
33 //!
34 //!
35 //! let mut acceptor = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap();
36 //! acceptor.set_private_key_file("key.pem", SslFiletype::PEM).unwrap();
37 //! acceptor.set_certificate_chain_file("certs.pem").unwrap();
38 //! acceptor.check_private_key().unwrap();
39 //! let acceptor = Arc::new(acceptor.build());
40 //!
41 //! let listener = TcpListener::bind("0.0.0.0:8443").unwrap();
42 //!
43 //! fn handle_client(stream: SslStream<TcpStream>) {
44 //!     // ...
45 //! }
46 //!
47 //! for stream in listener.incoming() {
48 //!     match stream {
49 //!         Ok(stream) => {
50 //!             let acceptor = acceptor.clone();
51 //!             thread::spawn(move || {
52 //!                 let stream = acceptor.accept(stream).unwrap();
53 //!                 handle_client(stream);
54 //!             });
55 //!         }
56 //!         Err(e) => { /* connection failed */ }
57 //!     }
58 //! }
59 //! ```
60 use crate::dh::{Dh, DhRef};
61 #[cfg(all(ossl101, not(ossl110)))]
62 use crate::ec::EcKey;
63 use crate::ec::EcKeyRef;
64 use crate::error::ErrorStack;
65 use crate::ex_data::Index;
66 #[cfg(ossl111)]
67 use crate::hash::MessageDigest;
68 #[cfg(any(ossl110, libressl270))]
69 use crate::nid::Nid;
70 use crate::pkey::{HasPrivate, PKeyRef, Params, Private};
71 use crate::srtp::{SrtpProtectionProfile, SrtpProtectionProfileRef};
72 use crate::ssl::bio::BioMethod;
73 use crate::ssl::callbacks::*;
74 use crate::ssl::error::InnerError;
75 use crate::stack::{Stack, StackRef};
76 use crate::util::{ForeignTypeExt, ForeignTypeRefExt};
77 use crate::x509::store::{X509Store, X509StoreBuilderRef, X509StoreRef};
78 #[cfg(any(ossl102, libressl261))]
79 use crate::x509::verify::X509VerifyParamRef;
80 use crate::x509::{X509Name, X509Ref, X509StoreContextRef, X509VerifyResult, X509};
81 use crate::{cvt, cvt_n, cvt_p, init};
82 use bitflags::bitflags;
83 use cfg_if::cfg_if;
84 use foreign_types::{ForeignType, ForeignTypeRef, Opaque};
85 use libc::{c_char, c_int, c_long, c_uchar, c_uint, c_void};
86 use once_cell::sync::{Lazy, OnceCell};
87 use openssl_macros::corresponds;
88 use std::any::TypeId;
89 use std::cmp;
90 use std::collections::HashMap;
91 use std::ffi::{CStr, CString};
92 use std::fmt;
93 use std::io;
94 use std::io::prelude::*;
95 use std::marker::PhantomData;
96 use std::mem::{self, ManuallyDrop};
97 use std::ops::{Deref, DerefMut};
98 use std::panic::resume_unwind;
99 use std::path::Path;
100 use std::ptr;
101 use std::slice;
102 use std::str;
103 use std::sync::{Arc, Mutex};
104 
105 pub use crate::ssl::connector::{
106     ConnectConfiguration, SslAcceptor, SslAcceptorBuilder, SslConnector, SslConnectorBuilder,
107 };
108 pub use crate::ssl::error::{Error, ErrorCode, HandshakeError};
109 
110 mod bio;
111 mod callbacks;
112 mod connector;
113 mod error;
114 #[cfg(test)]
115 mod test;
116 
117 /// Returns the OpenSSL name of a cipher corresponding to an RFC-standard cipher name.
118 ///
119 /// If the cipher has no corresponding OpenSSL name, the string `(NONE)` is returned.
120 ///
121 /// Requires OpenSSL 1.1.1 or newer.
122 #[corresponds(OPENSSL_cipher_name)]
123 #[cfg(ossl111)]
cipher_name(std_name: &str) -> &'static str124 pub fn cipher_name(std_name: &str) -> &'static str {
125     unsafe {
126         ffi::init();
127 
128         let s = CString::new(std_name).unwrap();
129         let ptr = ffi::OPENSSL_cipher_name(s.as_ptr());
130         CStr::from_ptr(ptr).to_str().unwrap()
131     }
132 }
133 
134 cfg_if! {
135     if #[cfg(ossl300)] {
136         type SslOptionsRepr = u64;
137     } else if #[cfg(boringssl)] {
138         type SslOptionsRepr = u32;
139     } else {
140         type SslOptionsRepr = libc::c_ulong;
141     }
142 }
143 
144 bitflags! {
145     /// Options controlling the behavior of an `SslContext`.
146     pub struct SslOptions: SslOptionsRepr {
147         /// Disables a countermeasure against an SSLv3/TLSv1.0 vulnerability affecting CBC ciphers.
148         const DONT_INSERT_EMPTY_FRAGMENTS = ffi::SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS as SslOptionsRepr;
149 
150         /// A "reasonable default" set of options which enables compatibility flags.
151         #[cfg(not(boringssl))]
152         const ALL = ffi::SSL_OP_ALL as SslOptionsRepr;
153 
154         /// Do not query the MTU.
155         ///
156         /// Only affects DTLS connections.
157         const NO_QUERY_MTU = ffi::SSL_OP_NO_QUERY_MTU as SslOptionsRepr;
158 
159         /// Enables Cookie Exchange as described in [RFC 4347 Section 4.2.1].
160         ///
161         /// Only affects DTLS connections.
162         ///
163         /// [RFC 4347 Section 4.2.1]: https://tools.ietf.org/html/rfc4347#section-4.2.1
164         #[cfg(not(boringssl))]
165         const COOKIE_EXCHANGE = ffi::SSL_OP_COOKIE_EXCHANGE as SslOptionsRepr;
166 
167         /// Disables the use of session tickets for session resumption.
168         const NO_TICKET = ffi::SSL_OP_NO_TICKET as SslOptionsRepr;
169 
170         /// Always start a new session when performing a renegotiation on the server side.
171         #[cfg(not(boringssl))]
172         const NO_SESSION_RESUMPTION_ON_RENEGOTIATION =
173             ffi::SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION as SslOptionsRepr;
174 
175         /// Disables the use of TLS compression.
176         #[cfg(not(boringssl))]
177         const NO_COMPRESSION = ffi::SSL_OP_NO_COMPRESSION as SslOptionsRepr;
178 
179         /// Allow legacy insecure renegotiation with servers or clients that do not support secure
180         /// renegotiation.
181         const ALLOW_UNSAFE_LEGACY_RENEGOTIATION =
182             ffi::SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION as SslOptionsRepr;
183 
184         /// Creates a new key for each session when using ECDHE.
185         ///
186         /// This is always enabled in OpenSSL 1.1.0.
187         const SINGLE_ECDH_USE = ffi::SSL_OP_SINGLE_ECDH_USE as SslOptionsRepr;
188 
189         /// Creates a new key for each session when using DHE.
190         ///
191         /// This is always enabled in OpenSSL 1.1.0.
192         const SINGLE_DH_USE = ffi::SSL_OP_SINGLE_DH_USE as SslOptionsRepr;
193 
194         /// Use the server's preferences rather than the client's when selecting a cipher.
195         ///
196         /// This has no effect on the client side.
197         const CIPHER_SERVER_PREFERENCE = ffi::SSL_OP_CIPHER_SERVER_PREFERENCE as SslOptionsRepr;
198 
199         /// Disables version rollback attach detection.
200         const TLS_ROLLBACK_BUG = ffi::SSL_OP_TLS_ROLLBACK_BUG as SslOptionsRepr;
201 
202         /// Disables the use of SSLv2.
203         const NO_SSLV2 = ffi::SSL_OP_NO_SSLv2 as SslOptionsRepr;
204 
205         /// Disables the use of SSLv3.
206         const NO_SSLV3 = ffi::SSL_OP_NO_SSLv3 as SslOptionsRepr;
207 
208         /// Disables the use of TLSv1.0.
209         const NO_TLSV1 = ffi::SSL_OP_NO_TLSv1 as SslOptionsRepr;
210 
211         /// Disables the use of TLSv1.1.
212         const NO_TLSV1_1 = ffi::SSL_OP_NO_TLSv1_1 as SslOptionsRepr;
213 
214         /// Disables the use of TLSv1.2.
215         const NO_TLSV1_2 = ffi::SSL_OP_NO_TLSv1_2 as SslOptionsRepr;
216 
217         /// Disables the use of TLSv1.3.
218         ///
219         /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer.
220         #[cfg(any(boringssl, ossl111, libressl340))]
221         const NO_TLSV1_3 = ffi::SSL_OP_NO_TLSv1_3 as SslOptionsRepr;
222 
223         /// Disables the use of DTLSv1.0
224         ///
225         /// Requires OpenSSL 1.0.2 or LibreSSL 3.3.2 or newer.
226         #[cfg(any(boringssl, ossl102, ossl110, libressl332))]
227         const NO_DTLSV1 = ffi::SSL_OP_NO_DTLSv1 as SslOptionsRepr;
228 
229         /// Disables the use of DTLSv1.2.
230         ///
231         /// Requires OpenSSL 1.0.2 or LibreSSL 3.3.2 or newer.
232         #[cfg(any(boringssl, ossl102, ossl110, libressl332))]
233         const NO_DTLSV1_2 = ffi::SSL_OP_NO_DTLSv1_2 as SslOptionsRepr;
234 
235         /// Disables the use of all (D)TLS protocol versions.
236         ///
237         /// This can be used as a mask when whitelisting protocol versions.
238         ///
239         /// Requires OpenSSL 1.0.2 or newer.
240         ///
241         /// # Examples
242         ///
243         /// Only support TLSv1.2:
244         ///
245         /// ```rust
246         /// use openssl::ssl::SslOptions;
247         ///
248         /// let options = SslOptions::NO_SSL_MASK & !SslOptions::NO_TLSV1_2;
249         /// ```
250         #[cfg(any(ossl102, ossl110))]
251         const NO_SSL_MASK = ffi::SSL_OP_NO_SSL_MASK as SslOptionsRepr;
252 
253         /// Disallow all renegotiation in TLSv1.2 and earlier.
254         ///
255         /// Requires OpenSSL 1.1.0h or newer.
256         #[cfg(any(boringssl, ossl110h))]
257         const NO_RENEGOTIATION = ffi::SSL_OP_NO_RENEGOTIATION as SslOptionsRepr;
258 
259         /// Enable TLSv1.3 Compatibility mode.
260         ///
261         /// Requires OpenSSL 1.1.1 or newer. This is on by default in 1.1.1, but a future version
262         /// may have this disabled by default.
263         #[cfg(ossl111)]
264         const ENABLE_MIDDLEBOX_COMPAT = ffi::SSL_OP_ENABLE_MIDDLEBOX_COMPAT as SslOptionsRepr;
265 
266         /// Prioritize ChaCha ciphers when preferred by clients.
267         ///
268         /// Temporarily reprioritize ChaCha20-Poly1305 ciphers to the top of the server cipher list
269         /// if a ChaCha20-Poly1305 cipher is at the top of the client cipher list. This helps those
270         /// clients (e.g. mobile) use ChaCha20-Poly1305 if that cipher is anywhere in the server
271         /// cipher list; but still allows other clients to use AES and other ciphers.
272         ///
273         /// Requires enable [`SslOptions::CIPHER_SERVER_PREFERENCE`].
274         /// Requires OpenSSL 1.1.1 or newer.
275         ///
276         /// [`SslOptions::CIPHER_SERVER_PREFERENCE`]: struct.SslOptions.html#associatedconstant.CIPHER_SERVER_PREFERENCE
277         #[cfg(ossl111)]
278         const PRIORITIZE_CHACHA = ffi::SSL_OP_PRIORITIZE_CHACHA as SslOptionsRepr;
279     }
280 }
281 
282 bitflags! {
283     /// Options controlling the behavior of an `SslContext`.
284     pub struct SslMode: SslBitType {
285         /// Enables "short writes".
286         ///
287         /// Normally, a write in OpenSSL will always write out all of the requested data, even if it
288         /// requires more than one TLS record or write to the underlying stream. This option will
289         /// cause a write to return after writing a single TLS record instead.
290         const ENABLE_PARTIAL_WRITE = ffi::SSL_MODE_ENABLE_PARTIAL_WRITE;
291 
292         /// Disables a check that the data buffer has not moved between calls when operating in a
293         /// non-blocking context.
294         const ACCEPT_MOVING_WRITE_BUFFER = ffi::SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER;
295 
296         /// Enables automatic retries after TLS session events such as renegotiations or heartbeats.
297         ///
298         /// By default, OpenSSL will return a `WantRead` error after a renegotiation or heartbeat.
299         /// This option will cause OpenSSL to automatically continue processing the requested
300         /// operation instead.
301         ///
302         /// Note that `SslStream::read` and `SslStream::write` will automatically retry regardless
303         /// of the state of this option. It only affects `SslStream::ssl_read` and
304         /// `SslStream::ssl_write`.
305         const AUTO_RETRY = ffi::SSL_MODE_AUTO_RETRY;
306 
307         /// Disables automatic chain building when verifying a peer's certificate.
308         ///
309         /// TLS peers are responsible for sending the entire certificate chain from the leaf to a
310         /// trusted root, but some will incorrectly not do so. OpenSSL will try to build the chain
311         /// out of certificates it knows of, and this option will disable that behavior.
312         const NO_AUTO_CHAIN = ffi::SSL_MODE_NO_AUTO_CHAIN;
313 
314         /// Release memory buffers when the session does not need them.
315         ///
316         /// This saves ~34 KiB of memory for idle streams.
317         const RELEASE_BUFFERS = ffi::SSL_MODE_RELEASE_BUFFERS;
318 
319         /// Sends the fake `TLS_FALLBACK_SCSV` cipher suite in the ClientHello message of a
320         /// handshake.
321         ///
322         /// This should only be enabled if a client has failed to connect to a server which
323         /// attempted to downgrade the protocol version of the session.
324         ///
325         /// Do not use this unless you know what you're doing!
326         #[cfg(not(libressl))]
327         const SEND_FALLBACK_SCSV = ffi::SSL_MODE_SEND_FALLBACK_SCSV;
328     }
329 }
330 
331 /// A type specifying the kind of protocol an `SslContext` will speak.
332 #[derive(Copy, Clone)]
333 pub struct SslMethod(*const ffi::SSL_METHOD);
334 
335 impl SslMethod {
336     /// Support all versions of the TLS protocol.
337     #[corresponds(TLS_method)]
tls() -> SslMethod338     pub fn tls() -> SslMethod {
339         unsafe { SslMethod(TLS_method()) }
340     }
341 
342     /// Support all versions of the DTLS protocol.
343     #[corresponds(DTLS_method)]
dtls() -> SslMethod344     pub fn dtls() -> SslMethod {
345         unsafe { SslMethod(DTLS_method()) }
346     }
347 
348     /// Support all versions of the TLS protocol, explicitly as a client.
349     #[corresponds(TLS_client_method)]
tls_client() -> SslMethod350     pub fn tls_client() -> SslMethod {
351         unsafe { SslMethod(TLS_client_method()) }
352     }
353 
354     /// Support all versions of the TLS protocol, explicitly as a server.
355     #[corresponds(TLS_server_method)]
tls_server() -> SslMethod356     pub fn tls_server() -> SslMethod {
357         unsafe { SslMethod(TLS_server_method()) }
358     }
359 
360     /// Constructs an `SslMethod` from a pointer to the underlying OpenSSL value.
361     ///
362     /// # Safety
363     ///
364     /// The caller must ensure the pointer is valid.
from_ptr(ptr: *const ffi::SSL_METHOD) -> SslMethod365     pub unsafe fn from_ptr(ptr: *const ffi::SSL_METHOD) -> SslMethod {
366         SslMethod(ptr)
367     }
368 
369     /// Returns a pointer to the underlying OpenSSL value.
370     #[allow(clippy::trivially_copy_pass_by_ref)]
as_ptr(&self) -> *const ffi::SSL_METHOD371     pub fn as_ptr(&self) -> *const ffi::SSL_METHOD {
372         self.0
373     }
374 }
375 
376 unsafe impl Sync for SslMethod {}
377 unsafe impl Send for SslMethod {}
378 
379 bitflags! {
380     /// Options controlling the behavior of certificate verification.
381     pub struct SslVerifyMode: i32 {
382         /// Verifies that the peer's certificate is trusted.
383         ///
384         /// On the server side, this will cause OpenSSL to request a certificate from the client.
385         const PEER = ffi::SSL_VERIFY_PEER;
386 
387         /// Disables verification of the peer's certificate.
388         ///
389         /// On the server side, this will cause OpenSSL to not request a certificate from the
390         /// client. On the client side, the certificate will be checked for validity, but the
391         /// negotiation will continue regardless of the result of that check.
392         const NONE = ffi::SSL_VERIFY_NONE;
393 
394         /// On the server side, abort the handshake if the client did not send a certificate.
395         ///
396         /// This should be paired with `SSL_VERIFY_PEER`. It has no effect on the client side.
397         const FAIL_IF_NO_PEER_CERT = ffi::SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
398     }
399 }
400 
401 #[cfg(boringssl)]
402 type SslBitType = c_int;
403 #[cfg(not(boringssl))]
404 type SslBitType = c_long;
405 
406 #[cfg(boringssl)]
407 type SslTimeTy = u64;
408 #[cfg(not(boringssl))]
409 type SslTimeTy = c_long;
410 
411 bitflags! {
412     /// Options controlling the behavior of session caching.
413     pub struct SslSessionCacheMode: SslBitType {
414         /// No session caching for the client or server takes place.
415         const OFF = ffi::SSL_SESS_CACHE_OFF;
416 
417         /// Enable session caching on the client side.
418         ///
419         /// OpenSSL has no way of identifying the proper session to reuse automatically, so the
420         /// application is responsible for setting it explicitly via [`SslRef::set_session`].
421         ///
422         /// [`SslRef::set_session`]: struct.SslRef.html#method.set_session
423         const CLIENT = ffi::SSL_SESS_CACHE_CLIENT;
424 
425         /// Enable session caching on the server side.
426         ///
427         /// This is the default mode.
428         const SERVER = ffi::SSL_SESS_CACHE_SERVER;
429 
430         /// Enable session caching on both the client and server side.
431         const BOTH = ffi::SSL_SESS_CACHE_BOTH;
432 
433         /// Disable automatic removal of expired sessions from the session cache.
434         const NO_AUTO_CLEAR = ffi::SSL_SESS_CACHE_NO_AUTO_CLEAR;
435 
436         /// Disable use of the internal session cache for session lookups.
437         const NO_INTERNAL_LOOKUP = ffi::SSL_SESS_CACHE_NO_INTERNAL_LOOKUP;
438 
439         /// Disable use of the internal session cache for session storage.
440         const NO_INTERNAL_STORE = ffi::SSL_SESS_CACHE_NO_INTERNAL_STORE;
441 
442         /// Disable use of the internal session cache for storage and lookup.
443         const NO_INTERNAL = ffi::SSL_SESS_CACHE_NO_INTERNAL;
444     }
445 }
446 
447 #[cfg(ossl111)]
448 bitflags! {
449     /// Which messages and under which conditions an extension should be added or expected.
450     pub struct ExtensionContext: c_uint {
451         /// This extension is only allowed in TLS
452         const TLS_ONLY = ffi::SSL_EXT_TLS_ONLY;
453         /// This extension is only allowed in DTLS
454         const DTLS_ONLY = ffi::SSL_EXT_DTLS_ONLY;
455         /// Some extensions may be allowed in DTLS but we don't implement them for it
456         const TLS_IMPLEMENTATION_ONLY = ffi::SSL_EXT_TLS_IMPLEMENTATION_ONLY;
457         /// Most extensions are not defined for SSLv3 but EXT_TYPE_renegotiate is
458         const SSL3_ALLOWED = ffi::SSL_EXT_SSL3_ALLOWED;
459         /// Extension is only defined for TLS1.2 and below
460         const TLS1_2_AND_BELOW_ONLY = ffi::SSL_EXT_TLS1_2_AND_BELOW_ONLY;
461         /// Extension is only defined for TLS1.3 and above
462         const TLS1_3_ONLY = ffi::SSL_EXT_TLS1_3_ONLY;
463         /// Ignore this extension during parsing if we are resuming
464         const IGNORE_ON_RESUMPTION = ffi::SSL_EXT_IGNORE_ON_RESUMPTION;
465         const CLIENT_HELLO = ffi::SSL_EXT_CLIENT_HELLO;
466         /// Really means TLS1.2 or below
467         const TLS1_2_SERVER_HELLO = ffi::SSL_EXT_TLS1_2_SERVER_HELLO;
468         const TLS1_3_SERVER_HELLO = ffi::SSL_EXT_TLS1_3_SERVER_HELLO;
469         const TLS1_3_ENCRYPTED_EXTENSIONS = ffi::SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS;
470         const TLS1_3_HELLO_RETRY_REQUEST = ffi::SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST;
471         const TLS1_3_CERTIFICATE = ffi::SSL_EXT_TLS1_3_CERTIFICATE;
472         const TLS1_3_NEW_SESSION_TICKET = ffi::SSL_EXT_TLS1_3_NEW_SESSION_TICKET;
473         const TLS1_3_CERTIFICATE_REQUEST = ffi::SSL_EXT_TLS1_3_CERTIFICATE_REQUEST;
474     }
475 }
476 
477 /// An identifier of the format of a certificate or key file.
478 #[derive(Copy, Clone)]
479 pub struct SslFiletype(c_int);
480 
481 impl SslFiletype {
482     /// The PEM format.
483     ///
484     /// This corresponds to `SSL_FILETYPE_PEM`.
485     pub const PEM: SslFiletype = SslFiletype(ffi::SSL_FILETYPE_PEM);
486 
487     /// The ASN1 format.
488     ///
489     /// This corresponds to `SSL_FILETYPE_ASN1`.
490     pub const ASN1: SslFiletype = SslFiletype(ffi::SSL_FILETYPE_ASN1);
491 
492     /// Constructs an `SslFiletype` from a raw OpenSSL value.
from_raw(raw: c_int) -> SslFiletype493     pub fn from_raw(raw: c_int) -> SslFiletype {
494         SslFiletype(raw)
495     }
496 
497     /// Returns the raw OpenSSL value represented by this type.
498     #[allow(clippy::trivially_copy_pass_by_ref)]
as_raw(&self) -> c_int499     pub fn as_raw(&self) -> c_int {
500         self.0
501     }
502 }
503 
504 /// An identifier of a certificate status type.
505 #[derive(Copy, Clone)]
506 pub struct StatusType(c_int);
507 
508 impl StatusType {
509     /// An OSCP status.
510     pub const OCSP: StatusType = StatusType(ffi::TLSEXT_STATUSTYPE_ocsp);
511 
512     /// Constructs a `StatusType` from a raw OpenSSL value.
from_raw(raw: c_int) -> StatusType513     pub fn from_raw(raw: c_int) -> StatusType {
514         StatusType(raw)
515     }
516 
517     /// Returns the raw OpenSSL value represented by this type.
518     #[allow(clippy::trivially_copy_pass_by_ref)]
as_raw(&self) -> c_int519     pub fn as_raw(&self) -> c_int {
520         self.0
521     }
522 }
523 
524 /// An identifier of a session name type.
525 #[derive(Copy, Clone)]
526 pub struct NameType(c_int);
527 
528 impl NameType {
529     /// A host name.
530     pub const HOST_NAME: NameType = NameType(ffi::TLSEXT_NAMETYPE_host_name);
531 
532     /// Constructs a `StatusType` from a raw OpenSSL value.
from_raw(raw: c_int) -> StatusType533     pub fn from_raw(raw: c_int) -> StatusType {
534         StatusType(raw)
535     }
536 
537     /// Returns the raw OpenSSL value represented by this type.
538     #[allow(clippy::trivially_copy_pass_by_ref)]
as_raw(&self) -> c_int539     pub fn as_raw(&self) -> c_int {
540         self.0
541     }
542 }
543 
544 static INDEXES: Lazy<Mutex<HashMap<TypeId, c_int>>> = Lazy::new(|| Mutex::new(HashMap::new()));
545 static SSL_INDEXES: Lazy<Mutex<HashMap<TypeId, c_int>>> = Lazy::new(|| Mutex::new(HashMap::new()));
546 static SESSION_CTX_INDEX: OnceCell<Index<Ssl, SslContext>> = OnceCell::new();
547 
try_get_session_ctx_index() -> Result<&'static Index<Ssl, SslContext>, ErrorStack>548 fn try_get_session_ctx_index() -> Result<&'static Index<Ssl, SslContext>, ErrorStack> {
549     SESSION_CTX_INDEX.get_or_try_init(Ssl::new_ex_index)
550 }
551 
free_data_box<T>( _parent: *mut c_void, ptr: *mut c_void, _ad: *mut ffi::CRYPTO_EX_DATA, _idx: c_int, _argl: c_long, _argp: *mut c_void, )552 unsafe extern "C" fn free_data_box<T>(
553     _parent: *mut c_void,
554     ptr: *mut c_void,
555     _ad: *mut ffi::CRYPTO_EX_DATA,
556     _idx: c_int,
557     _argl: c_long,
558     _argp: *mut c_void,
559 ) {
560     if !ptr.is_null() {
561         let _ = Box::<T>::from_raw(ptr as *mut T);
562     }
563 }
564 
565 /// An error returned from the SNI callback.
566 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
567 pub struct SniError(c_int);
568 
569 impl SniError {
570     /// Abort the handshake with a fatal alert.
571     pub const ALERT_FATAL: SniError = SniError(ffi::SSL_TLSEXT_ERR_ALERT_FATAL);
572 
573     /// Send a warning alert to the client and continue the handshake.
574     pub const ALERT_WARNING: SniError = SniError(ffi::SSL_TLSEXT_ERR_ALERT_WARNING);
575 
576     pub const NOACK: SniError = SniError(ffi::SSL_TLSEXT_ERR_NOACK);
577 }
578 
579 /// An SSL/TLS alert.
580 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
581 pub struct SslAlert(c_int);
582 
583 impl SslAlert {
584     /// Alert 112 - `unrecognized_name`.
585     pub const UNRECOGNIZED_NAME: SslAlert = SslAlert(ffi::SSL_AD_UNRECOGNIZED_NAME);
586     pub const ILLEGAL_PARAMETER: SslAlert = SslAlert(ffi::SSL_AD_ILLEGAL_PARAMETER);
587     pub const DECODE_ERROR: SslAlert = SslAlert(ffi::SSL_AD_DECODE_ERROR);
588 }
589 
590 /// An error returned from an ALPN selection callback.
591 ///
592 /// Requires OpenSSL 1.0.2 or LibreSSL 2.6.1 or newer.
593 #[cfg(any(ossl102, libressl261))]
594 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
595 pub struct AlpnError(c_int);
596 
597 #[cfg(any(ossl102, libressl261))]
598 impl AlpnError {
599     /// Terminate the handshake with a fatal alert.
600     ///
601     /// Requires OpenSSL 1.1.0 or newer.
602     #[cfg(any(ossl110))]
603     pub const ALERT_FATAL: AlpnError = AlpnError(ffi::SSL_TLSEXT_ERR_ALERT_FATAL);
604 
605     /// Do not select a protocol, but continue the handshake.
606     pub const NOACK: AlpnError = AlpnError(ffi::SSL_TLSEXT_ERR_NOACK);
607 }
608 
609 /// The result of a client hello callback.
610 ///
611 /// Requires OpenSSL 1.1.1 or newer.
612 #[cfg(ossl111)]
613 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
614 pub struct ClientHelloResponse(c_int);
615 
616 #[cfg(ossl111)]
617 impl ClientHelloResponse {
618     /// Continue the handshake.
619     pub const SUCCESS: ClientHelloResponse = ClientHelloResponse(ffi::SSL_CLIENT_HELLO_SUCCESS);
620 
621     /// Return from the handshake with an `ErrorCode::WANT_CLIENT_HELLO_CB` error.
622     pub const RETRY: ClientHelloResponse = ClientHelloResponse(ffi::SSL_CLIENT_HELLO_RETRY);
623 }
624 
625 /// An SSL/TLS protocol version.
626 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
627 pub struct SslVersion(c_int);
628 
629 impl SslVersion {
630     /// SSLv3
631     pub const SSL3: SslVersion = SslVersion(ffi::SSL3_VERSION);
632 
633     /// TLSv1.0
634     pub const TLS1: SslVersion = SslVersion(ffi::TLS1_VERSION);
635 
636     /// TLSv1.1
637     pub const TLS1_1: SslVersion = SslVersion(ffi::TLS1_1_VERSION);
638 
639     /// TLSv1.2
640     pub const TLS1_2: SslVersion = SslVersion(ffi::TLS1_2_VERSION);
641 
642     /// TLSv1.3
643     ///
644     /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer.
645     #[cfg(any(ossl111, libressl340))]
646     pub const TLS1_3: SslVersion = SslVersion(ffi::TLS1_3_VERSION);
647 }
648 
649 cfg_if! {
650     if #[cfg(boringssl)] {
651         type SslCacheTy = i64;
652         type SslCacheSize = libc::c_ulong;
653         type MtuTy = u32;
654         type SizeTy = usize;
655     } else {
656         type SslCacheTy = i64;
657         type SslCacheSize = c_long;
658         type MtuTy = c_long;
659         type SizeTy = u32;
660     }
661 }
662 
663 /// A standard implementation of protocol selection for Application Layer Protocol Negotiation
664 /// (ALPN).
665 ///
666 /// `server` should contain the server's list of supported protocols and `client` the client's. They
667 /// must both be in the ALPN wire format. See the documentation for
668 /// [`SslContextBuilder::set_alpn_protos`] for details.
669 ///
670 /// It will select the first protocol supported by the server which is also supported by the client.
671 ///
672 /// [`SslContextBuilder::set_alpn_protos`]: struct.SslContextBuilder.html#method.set_alpn_protos
673 #[corresponds(SSL_select_next_proto)]
select_next_proto<'a>(server: &[u8], client: &'a [u8]) -> Option<&'a [u8]>674 pub fn select_next_proto<'a>(server: &[u8], client: &'a [u8]) -> Option<&'a [u8]> {
675     unsafe {
676         let mut out = ptr::null_mut();
677         let mut outlen = 0;
678         let r = ffi::SSL_select_next_proto(
679             &mut out,
680             &mut outlen,
681             server.as_ptr(),
682             server.len() as c_uint,
683             client.as_ptr(),
684             client.len() as c_uint,
685         );
686         if r == ffi::OPENSSL_NPN_NEGOTIATED {
687             Some(slice::from_raw_parts(out as *const u8, outlen as usize))
688         } else {
689             None
690         }
691     }
692 }
693 
694 /// A builder for `SslContext`s.
695 pub struct SslContextBuilder(SslContext);
696 
697 impl SslContextBuilder {
698     /// Creates a new `SslContextBuilder`.
699     #[corresponds(SSL_CTX_new)]
new(method: SslMethod) -> Result<SslContextBuilder, ErrorStack>700     pub fn new(method: SslMethod) -> Result<SslContextBuilder, ErrorStack> {
701         unsafe {
702             init();
703             let ctx = cvt_p(ffi::SSL_CTX_new(method.as_ptr()))?;
704 
705             Ok(SslContextBuilder::from_ptr(ctx))
706         }
707     }
708 
709     /// Creates an `SslContextBuilder` from a pointer to a raw OpenSSL value.
710     ///
711     /// # Safety
712     ///
713     /// The caller must ensure that the pointer is valid and uniquely owned by the builder.
from_ptr(ctx: *mut ffi::SSL_CTX) -> SslContextBuilder714     pub unsafe fn from_ptr(ctx: *mut ffi::SSL_CTX) -> SslContextBuilder {
715         SslContextBuilder(SslContext::from_ptr(ctx))
716     }
717 
718     /// Returns a pointer to the raw OpenSSL value.
as_ptr(&self) -> *mut ffi::SSL_CTX719     pub fn as_ptr(&self) -> *mut ffi::SSL_CTX {
720         self.0.as_ptr()
721     }
722 
723     /// Configures the certificate verification method for new connections.
724     #[corresponds(SSL_CTX_set_verify)]
set_verify(&mut self, mode: SslVerifyMode)725     pub fn set_verify(&mut self, mode: SslVerifyMode) {
726         unsafe {
727             ffi::SSL_CTX_set_verify(self.as_ptr(), mode.bits as c_int, None);
728         }
729     }
730 
731     /// Configures the certificate verification method for new connections and
732     /// registers a verification callback.
733     ///
734     /// The callback is passed a boolean indicating if OpenSSL's internal verification succeeded as
735     /// well as a reference to the `X509StoreContext` which can be used to examine the certificate
736     /// chain. It should return a boolean indicating if verification succeeded.
737     #[corresponds(SSL_CTX_set_verify)]
set_verify_callback<F>(&mut self, mode: SslVerifyMode, verify: F) where F: Fn(bool, &mut X509StoreContextRef) -> bool + 'static + Sync + Send,738     pub fn set_verify_callback<F>(&mut self, mode: SslVerifyMode, verify: F)
739     where
740         F: Fn(bool, &mut X509StoreContextRef) -> bool + 'static + Sync + Send,
741     {
742         unsafe {
743             self.set_ex_data(SslContext::cached_ex_index::<F>(), verify);
744             ffi::SSL_CTX_set_verify(self.as_ptr(), mode.bits as c_int, Some(raw_verify::<F>));
745         }
746     }
747 
748     /// Configures the server name indication (SNI) callback for new connections.
749     ///
750     /// SNI is used to allow a single server to handle requests for multiple domains, each of which
751     /// has its own certificate chain and configuration.
752     ///
753     /// Obtain the server name with the `servername` method and then set the corresponding context
754     /// with `set_ssl_context`
755     #[corresponds(SSL_CTX_set_tlsext_servername_callback)]
756     // FIXME tlsext prefix?
set_servername_callback<F>(&mut self, callback: F) where F: Fn(&mut SslRef, &mut SslAlert) -> Result<(), SniError> + 'static + Sync + Send,757     pub fn set_servername_callback<F>(&mut self, callback: F)
758     where
759         F: Fn(&mut SslRef, &mut SslAlert) -> Result<(), SniError> + 'static + Sync + Send,
760     {
761         unsafe {
762             // The SNI callback is somewhat unique in that the callback associated with the original
763             // context associated with an SSL can be used even if the SSL's context has been swapped
764             // out. When that happens, we wouldn't be able to look up the callback's state in the
765             // context's ex data. Instead, pass the pointer directly as the servername arg. It's
766             // still stored in ex data to manage the lifetime.
767             let arg = self.set_ex_data_inner(SslContext::cached_ex_index::<F>(), callback);
768             ffi::SSL_CTX_set_tlsext_servername_arg(self.as_ptr(), arg);
769             #[cfg(boringssl)]
770             ffi::SSL_CTX_set_tlsext_servername_callback(self.as_ptr(), Some(raw_sni::<F>));
771             #[cfg(not(boringssl))]
772             ffi::SSL_CTX_set_tlsext_servername_callback__fixed_rust(
773                 self.as_ptr(),
774                 Some(raw_sni::<F>),
775             );
776         }
777     }
778 
779     /// Sets the certificate verification depth.
780     ///
781     /// If the peer's certificate chain is longer than this value, verification will fail.
782     #[corresponds(SSL_CTX_set_verify_depth)]
set_verify_depth(&mut self, depth: u32)783     pub fn set_verify_depth(&mut self, depth: u32) {
784         unsafe {
785             ffi::SSL_CTX_set_verify_depth(self.as_ptr(), depth as c_int);
786         }
787     }
788 
789     /// Sets a custom certificate store for verifying peer certificates.
790     ///
791     /// Requires OpenSSL 1.0.2 or newer.
792     #[corresponds(SSL_CTX_set0_verify_cert_store)]
793     #[cfg(ossl102)]
set_verify_cert_store(&mut self, cert_store: X509Store) -> Result<(), ErrorStack>794     pub fn set_verify_cert_store(&mut self, cert_store: X509Store) -> Result<(), ErrorStack> {
795         unsafe {
796             let ptr = cert_store.as_ptr();
797             cvt(ffi::SSL_CTX_set0_verify_cert_store(self.as_ptr(), ptr) as c_int)?;
798             mem::forget(cert_store);
799 
800             Ok(())
801         }
802     }
803 
804     /// Replaces the context's certificate store.
805     #[corresponds(SSL_CTX_set_cert_store)]
set_cert_store(&mut self, cert_store: X509Store)806     pub fn set_cert_store(&mut self, cert_store: X509Store) {
807         unsafe {
808             ffi::SSL_CTX_set_cert_store(self.as_ptr(), cert_store.as_ptr());
809             mem::forget(cert_store);
810         }
811     }
812 
813     /// Controls read ahead behavior.
814     ///
815     /// If enabled, OpenSSL will read as much data as is available from the underlying stream,
816     /// instead of a single record at a time.
817     ///
818     /// It has no effect when used with DTLS.
819     #[corresponds(SSL_CTX_set_read_ahead)]
set_read_ahead(&mut self, read_ahead: bool)820     pub fn set_read_ahead(&mut self, read_ahead: bool) {
821         unsafe {
822             ffi::SSL_CTX_set_read_ahead(self.as_ptr(), read_ahead as SslBitType);
823         }
824     }
825 
826     /// Sets the mode used by the context, returning the previous mode.
827     #[corresponds(SSL_CTX_set_mode)]
set_mode(&mut self, mode: SslMode) -> SslMode828     pub fn set_mode(&mut self, mode: SslMode) -> SslMode {
829         unsafe {
830             let bits = ffi::SSL_CTX_set_mode(self.as_ptr(), mode.bits() as MtuTy) as SslBitType;
831             SslMode { bits }
832         }
833     }
834 
835     /// Sets the parameters to be used during ephemeral Diffie-Hellman key exchange.
836     #[corresponds(SSL_CTX_set_tmp_dh)]
set_tmp_dh(&mut self, dh: &DhRef<Params>) -> Result<(), ErrorStack>837     pub fn set_tmp_dh(&mut self, dh: &DhRef<Params>) -> Result<(), ErrorStack> {
838         unsafe { cvt(ffi::SSL_CTX_set_tmp_dh(self.as_ptr(), dh.as_ptr()) as c_int).map(|_| ()) }
839     }
840 
841     /// Sets the callback which will generate parameters to be used during ephemeral Diffie-Hellman
842     /// key exchange.
843     ///
844     /// The callback is provided with a reference to the `Ssl` for the session, as well as a boolean
845     /// indicating if the selected cipher is export-grade, and the key length. The export and key
846     /// length options are archaic and should be ignored in almost all cases.
847     #[corresponds(SSL_CTX_set_tmp_dh_callback)]
set_tmp_dh_callback<F>(&mut self, callback: F) where F: Fn(&mut SslRef, bool, u32) -> Result<Dh<Params>, ErrorStack> + 'static + Sync + Send,848     pub fn set_tmp_dh_callback<F>(&mut self, callback: F)
849     where
850         F: Fn(&mut SslRef, bool, u32) -> Result<Dh<Params>, ErrorStack> + 'static + Sync + Send,
851     {
852         unsafe {
853             self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
854 
855             #[cfg(not(boringssl))]
856             ffi::SSL_CTX_set_tmp_dh_callback__fixed_rust(self.as_ptr(), Some(raw_tmp_dh::<F>));
857             #[cfg(boringssl)]
858             ffi::SSL_CTX_set_tmp_dh_callback(self.as_ptr(), Some(raw_tmp_dh::<F>));
859         }
860     }
861 
862     /// Sets the parameters to be used during ephemeral elliptic curve Diffie-Hellman key exchange.
863     #[corresponds(SSL_CTX_set_tmp_ecdh)]
set_tmp_ecdh(&mut self, key: &EcKeyRef<Params>) -> Result<(), ErrorStack>864     pub fn set_tmp_ecdh(&mut self, key: &EcKeyRef<Params>) -> Result<(), ErrorStack> {
865         unsafe { cvt(ffi::SSL_CTX_set_tmp_ecdh(self.as_ptr(), key.as_ptr()) as c_int).map(|_| ()) }
866     }
867 
868     /// Sets the callback which will generate parameters to be used during ephemeral elliptic curve
869     /// Diffie-Hellman key exchange.
870     ///
871     /// The callback is provided with a reference to the `Ssl` for the session, as well as a boolean
872     /// indicating if the selected cipher is export-grade, and the key length. The export and key
873     /// length options are archaic and should be ignored in almost all cases.
874     ///
875     /// Requires OpenSSL 1.0.1 or 1.0.2.
876     #[corresponds(SSL_CTX_set_tmp_ecdh_callback)]
877     #[cfg(all(ossl101, not(ossl110)))]
878     #[deprecated(note = "this function leaks memory and does not exist on newer OpenSSL versions")]
set_tmp_ecdh_callback<F>(&mut self, callback: F) where F: Fn(&mut SslRef, bool, u32) -> Result<EcKey<Params>, ErrorStack> + 'static + Sync + Send,879     pub fn set_tmp_ecdh_callback<F>(&mut self, callback: F)
880     where
881         F: Fn(&mut SslRef, bool, u32) -> Result<EcKey<Params>, ErrorStack> + 'static + Sync + Send,
882     {
883         unsafe {
884             self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
885             ffi::SSL_CTX_set_tmp_ecdh_callback__fixed_rust(self.as_ptr(), Some(raw_tmp_ecdh::<F>));
886         }
887     }
888 
889     /// Use the default locations of trusted certificates for verification.
890     ///
891     /// These locations are read from the `SSL_CERT_FILE` and `SSL_CERT_DIR` environment variables
892     /// if present, or defaults specified at OpenSSL build time otherwise.
893     #[corresponds(SSL_CTX_set_default_verify_paths)]
set_default_verify_paths(&mut self) -> Result<(), ErrorStack>894     pub fn set_default_verify_paths(&mut self) -> Result<(), ErrorStack> {
895         unsafe { cvt(ffi::SSL_CTX_set_default_verify_paths(self.as_ptr())).map(|_| ()) }
896     }
897 
898     /// Loads trusted root certificates from a file.
899     ///
900     /// The file should contain a sequence of PEM-formatted CA certificates.
901     #[corresponds(SSL_CTX_load_verify_locations)]
set_ca_file<P: AsRef<Path>>(&mut self, file: P) -> Result<(), ErrorStack>902     pub fn set_ca_file<P: AsRef<Path>>(&mut self, file: P) -> Result<(), ErrorStack> {
903         let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap();
904         unsafe {
905             cvt(ffi::SSL_CTX_load_verify_locations(
906                 self.as_ptr(),
907                 file.as_ptr() as *const _,
908                 ptr::null(),
909             ))
910             .map(|_| ())
911         }
912     }
913 
914     /// Sets the list of CA names sent to the client.
915     ///
916     /// The CA certificates must still be added to the trust root - they are not automatically set
917     /// as trusted by this method.
918     #[corresponds(SSL_CTX_set_client_CA_list)]
set_client_ca_list(&mut self, list: Stack<X509Name>)919     pub fn set_client_ca_list(&mut self, list: Stack<X509Name>) {
920         unsafe {
921             ffi::SSL_CTX_set_client_CA_list(self.as_ptr(), list.as_ptr());
922             mem::forget(list);
923         }
924     }
925 
926     /// Add the provided CA certificate to the list sent by the server to the client when
927     /// requesting client-side TLS authentication.
928     #[corresponds(SSL_CTX_add_client_CA)]
add_client_ca(&mut self, cacert: &X509Ref) -> Result<(), ErrorStack>929     pub fn add_client_ca(&mut self, cacert: &X509Ref) -> Result<(), ErrorStack> {
930         unsafe { cvt(ffi::SSL_CTX_add_client_CA(self.as_ptr(), cacert.as_ptr())).map(|_| ()) }
931     }
932 
933     /// Set the context identifier for sessions.
934     ///
935     /// This value identifies the server's session cache to clients, telling them when they're
936     /// able to reuse sessions. It should be set to a unique value per server, unless multiple
937     /// servers share a session cache.
938     ///
939     /// This value should be set when using client certificates, or each request will fail its
940     /// handshake and need to be restarted.
941     #[corresponds(SSL_CTX_set_session_id_context)]
set_session_id_context(&mut self, sid_ctx: &[u8]) -> Result<(), ErrorStack>942     pub fn set_session_id_context(&mut self, sid_ctx: &[u8]) -> Result<(), ErrorStack> {
943         unsafe {
944             assert!(sid_ctx.len() <= c_uint::max_value() as usize);
945             cvt(ffi::SSL_CTX_set_session_id_context(
946                 self.as_ptr(),
947                 sid_ctx.as_ptr(),
948                 sid_ctx.len() as SizeTy,
949             ))
950             .map(|_| ())
951         }
952     }
953 
954     /// Loads a leaf certificate from a file.
955     ///
956     /// Only a single certificate will be loaded - use `add_extra_chain_cert` to add the remainder
957     /// of the certificate chain, or `set_certificate_chain_file` to load the entire chain from a
958     /// single file.
959     #[corresponds(SSL_CTX_use_certificate_file)]
set_certificate_file<P: AsRef<Path>>( &mut self, file: P, file_type: SslFiletype, ) -> Result<(), ErrorStack>960     pub fn set_certificate_file<P: AsRef<Path>>(
961         &mut self,
962         file: P,
963         file_type: SslFiletype,
964     ) -> Result<(), ErrorStack> {
965         let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap();
966         unsafe {
967             cvt(ffi::SSL_CTX_use_certificate_file(
968                 self.as_ptr(),
969                 file.as_ptr() as *const _,
970                 file_type.as_raw(),
971             ))
972             .map(|_| ())
973         }
974     }
975 
976     /// Loads a certificate chain from a file.
977     ///
978     /// The file should contain a sequence of PEM-formatted certificates, the first being the leaf
979     /// certificate, and the remainder forming the chain of certificates up to and including the
980     /// trusted root certificate.
981     #[corresponds(SSL_CTX_use_certificate_chain_file)]
set_certificate_chain_file<P: AsRef<Path>>( &mut self, file: P, ) -> Result<(), ErrorStack>982     pub fn set_certificate_chain_file<P: AsRef<Path>>(
983         &mut self,
984         file: P,
985     ) -> Result<(), ErrorStack> {
986         let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap();
987         unsafe {
988             cvt(ffi::SSL_CTX_use_certificate_chain_file(
989                 self.as_ptr(),
990                 file.as_ptr() as *const _,
991             ))
992             .map(|_| ())
993         }
994     }
995 
996     /// Sets the leaf certificate.
997     ///
998     /// Use `add_extra_chain_cert` to add the remainder of the certificate chain.
999     #[corresponds(SSL_CTX_use_certificate)]
set_certificate(&mut self, cert: &X509Ref) -> Result<(), ErrorStack>1000     pub fn set_certificate(&mut self, cert: &X509Ref) -> Result<(), ErrorStack> {
1001         unsafe { cvt(ffi::SSL_CTX_use_certificate(self.as_ptr(), cert.as_ptr())).map(|_| ()) }
1002     }
1003 
1004     /// Appends a certificate to the certificate chain.
1005     ///
1006     /// This chain should contain all certificates necessary to go from the certificate specified by
1007     /// `set_certificate` to a trusted root.
1008     #[corresponds(SSL_CTX_add_extra_chain_cert)]
add_extra_chain_cert(&mut self, cert: X509) -> Result<(), ErrorStack>1009     pub fn add_extra_chain_cert(&mut self, cert: X509) -> Result<(), ErrorStack> {
1010         unsafe {
1011             cvt(ffi::SSL_CTX_add_extra_chain_cert(self.as_ptr(), cert.as_ptr()) as c_int)?;
1012             mem::forget(cert);
1013             Ok(())
1014         }
1015     }
1016 
1017     /// Loads the private key from a file.
1018     #[corresponds(SSL_CTX_use_PrivateKey_file)]
set_private_key_file<P: AsRef<Path>>( &mut self, file: P, file_type: SslFiletype, ) -> Result<(), ErrorStack>1019     pub fn set_private_key_file<P: AsRef<Path>>(
1020         &mut self,
1021         file: P,
1022         file_type: SslFiletype,
1023     ) -> Result<(), ErrorStack> {
1024         let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap();
1025         unsafe {
1026             cvt(ffi::SSL_CTX_use_PrivateKey_file(
1027                 self.as_ptr(),
1028                 file.as_ptr() as *const _,
1029                 file_type.as_raw(),
1030             ))
1031             .map(|_| ())
1032         }
1033     }
1034 
1035     /// Sets the private key.
1036     #[corresponds(SSL_CTX_use_PrivateKey)]
set_private_key<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack> where T: HasPrivate,1037     pub fn set_private_key<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack>
1038     where
1039         T: HasPrivate,
1040     {
1041         unsafe { cvt(ffi::SSL_CTX_use_PrivateKey(self.as_ptr(), key.as_ptr())).map(|_| ()) }
1042     }
1043 
1044     /// Sets the list of supported ciphers for protocols before TLSv1.3.
1045     ///
1046     /// The `set_ciphersuites` method controls the cipher suites for TLSv1.3.
1047     ///
1048     /// See [`ciphers`] for details on the format.
1049     ///
1050     /// [`ciphers`]: https://www.openssl.org/docs/manmaster/apps/ciphers.html
1051     #[corresponds(SSL_CTX_set_cipher_list)]
set_cipher_list(&mut self, cipher_list: &str) -> Result<(), ErrorStack>1052     pub fn set_cipher_list(&mut self, cipher_list: &str) -> Result<(), ErrorStack> {
1053         let cipher_list = CString::new(cipher_list).unwrap();
1054         unsafe {
1055             cvt(ffi::SSL_CTX_set_cipher_list(
1056                 self.as_ptr(),
1057                 cipher_list.as_ptr() as *const _,
1058             ))
1059             .map(|_| ())
1060         }
1061     }
1062 
1063     /// Sets the list of supported ciphers for the TLSv1.3 protocol.
1064     ///
1065     /// The `set_cipher_list` method controls the cipher suites for protocols before TLSv1.3.
1066     ///
1067     /// The format consists of TLSv1.3 cipher suite names separated by `:` characters in order of
1068     /// preference.
1069     ///
1070     /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer.
1071     #[corresponds(SSL_CTX_set_ciphersuites)]
1072     #[cfg(any(ossl111, libressl340))]
set_ciphersuites(&mut self, cipher_list: &str) -> Result<(), ErrorStack>1073     pub fn set_ciphersuites(&mut self, cipher_list: &str) -> Result<(), ErrorStack> {
1074         let cipher_list = CString::new(cipher_list).unwrap();
1075         unsafe {
1076             cvt(ffi::SSL_CTX_set_ciphersuites(
1077                 self.as_ptr(),
1078                 cipher_list.as_ptr() as *const _,
1079             ))
1080             .map(|_| ())
1081         }
1082     }
1083 
1084     /// Enables ECDHE key exchange with an automatically chosen curve list.
1085     ///
1086     /// Requires OpenSSL 1.0.2.
1087     #[corresponds(SSL_CTX_set_ecdh_auto)]
1088     #[cfg(any(libressl, all(ossl102, not(ossl110))))]
set_ecdh_auto(&mut self, onoff: bool) -> Result<(), ErrorStack>1089     pub fn set_ecdh_auto(&mut self, onoff: bool) -> Result<(), ErrorStack> {
1090         unsafe { cvt(ffi::SSL_CTX_set_ecdh_auto(self.as_ptr(), onoff as c_int)).map(|_| ()) }
1091     }
1092 
1093     /// Sets the options used by the context, returning the old set.
1094     ///
1095     /// # Note
1096     ///
1097     /// This *enables* the specified options, but does not disable unspecified options. Use
1098     /// `clear_options` for that.
1099     #[corresponds(SSL_CTX_set_options)]
set_options(&mut self, option: SslOptions) -> SslOptions1100     pub fn set_options(&mut self, option: SslOptions) -> SslOptions {
1101         let bits =
1102             unsafe { ffi::SSL_CTX_set_options(self.as_ptr(), option.bits()) } as SslOptionsRepr;
1103         SslOptions { bits }
1104     }
1105 
1106     /// Returns the options used by the context.
1107     #[corresponds(SSL_CTX_get_options)]
options(&self) -> SslOptions1108     pub fn options(&self) -> SslOptions {
1109         let bits = unsafe { ffi::SSL_CTX_get_options(self.as_ptr()) } as SslOptionsRepr;
1110         SslOptions { bits }
1111     }
1112 
1113     /// Clears the options used by the context, returning the old set.
1114     #[corresponds(SSL_CTX_clear_options)]
clear_options(&mut self, option: SslOptions) -> SslOptions1115     pub fn clear_options(&mut self, option: SslOptions) -> SslOptions {
1116         let bits =
1117             unsafe { ffi::SSL_CTX_clear_options(self.as_ptr(), option.bits()) } as SslOptionsRepr;
1118         SslOptions { bits }
1119     }
1120 
1121     /// Sets the minimum supported protocol version.
1122     ///
1123     /// A value of `None` will enable protocol versions down the the lowest version supported by
1124     /// OpenSSL.
1125     ///
1126     /// Requires OpenSSL 1.1.0 or LibreSSL 2.6.1 or newer.
1127     #[corresponds(SSL_CTX_set_min_proto_version)]
1128     #[cfg(any(ossl110, libressl261))]
set_min_proto_version(&mut self, version: Option<SslVersion>) -> Result<(), ErrorStack>1129     pub fn set_min_proto_version(&mut self, version: Option<SslVersion>) -> Result<(), ErrorStack> {
1130         unsafe {
1131             cvt(ffi::SSL_CTX_set_min_proto_version(
1132                 self.as_ptr(),
1133                 version.map_or(0, |v| v.0 as _),
1134             ))
1135             .map(|_| ())
1136         }
1137     }
1138 
1139     /// Sets the maximum supported protocol version.
1140     ///
1141     /// A value of `None` will enable protocol versions down the the highest version supported by
1142     /// OpenSSL.
1143     ///
1144     /// Requires OpenSSL 1.1.0 or or LibreSSL 2.6.1 or newer.
1145     #[corresponds(SSL_CTX_set_max_proto_version)]
1146     #[cfg(any(ossl110, libressl261))]
set_max_proto_version(&mut self, version: Option<SslVersion>) -> Result<(), ErrorStack>1147     pub fn set_max_proto_version(&mut self, version: Option<SslVersion>) -> Result<(), ErrorStack> {
1148         unsafe {
1149             cvt(ffi::SSL_CTX_set_max_proto_version(
1150                 self.as_ptr(),
1151                 version.map_or(0, |v| v.0 as _),
1152             ))
1153             .map(|_| ())
1154         }
1155     }
1156 
1157     /// Gets the minimum supported protocol version.
1158     ///
1159     /// A value of `None` indicates that all versions down the the lowest version supported by
1160     /// OpenSSL are enabled.
1161     ///
1162     /// Requires OpenSSL 1.1.0g or LibreSSL 2.7.0 or newer.
1163     #[corresponds(SSL_CTX_get_min_proto_version)]
1164     #[cfg(any(ossl110g, libressl270))]
min_proto_version(&mut self) -> Option<SslVersion>1165     pub fn min_proto_version(&mut self) -> Option<SslVersion> {
1166         unsafe {
1167             let r = ffi::SSL_CTX_get_min_proto_version(self.as_ptr());
1168             if r == 0 {
1169                 None
1170             } else {
1171                 Some(SslVersion(r))
1172             }
1173         }
1174     }
1175 
1176     /// Gets the maximum supported protocol version.
1177     ///
1178     /// A value of `None` indicates that all versions down the the highest version supported by
1179     /// OpenSSL are enabled.
1180     ///
1181     /// Requires OpenSSL 1.1.0g or LibreSSL 2.7.0 or newer.
1182     #[corresponds(SSL_CTX_get_max_proto_version)]
1183     #[cfg(any(ossl110g, libressl270))]
max_proto_version(&mut self) -> Option<SslVersion>1184     pub fn max_proto_version(&mut self) -> Option<SslVersion> {
1185         unsafe {
1186             let r = ffi::SSL_CTX_get_max_proto_version(self.as_ptr());
1187             if r == 0 {
1188                 None
1189             } else {
1190                 Some(SslVersion(r))
1191             }
1192         }
1193     }
1194 
1195     /// Sets the protocols to sent to the server for Application Layer Protocol Negotiation (ALPN).
1196     ///
1197     /// The input must be in ALPN "wire format". It consists of a sequence of supported protocol
1198     /// names prefixed by their byte length. For example, the protocol list consisting of `spdy/1`
1199     /// and `http/1.1` is encoded as `b"\x06spdy/1\x08http/1.1"`. The protocols are ordered by
1200     /// preference.
1201     ///
1202     /// Requires OpenSSL 1.0.2 or LibreSSL 2.6.1 or newer.
1203     #[corresponds(SSL_CTX_set_alpn_protos)]
1204     #[cfg(any(ossl102, libressl261))]
set_alpn_protos(&mut self, protocols: &[u8]) -> Result<(), ErrorStack>1205     pub fn set_alpn_protos(&mut self, protocols: &[u8]) -> Result<(), ErrorStack> {
1206         unsafe {
1207             assert!(protocols.len() <= c_uint::max_value() as usize);
1208             let r = ffi::SSL_CTX_set_alpn_protos(
1209                 self.as_ptr(),
1210                 protocols.as_ptr(),
1211                 protocols.len() as c_uint,
1212             );
1213             // fun fact, SSL_CTX_set_alpn_protos has a reversed return code D:
1214             if r == 0 {
1215                 Ok(())
1216             } else {
1217                 Err(ErrorStack::get())
1218             }
1219         }
1220     }
1221 
1222     /// Enables the DTLS extension "use_srtp" as defined in RFC5764.
1223     #[corresponds(SSL_CTX_set_tlsext_use_srtp)]
set_tlsext_use_srtp(&mut self, protocols: &str) -> Result<(), ErrorStack>1224     pub fn set_tlsext_use_srtp(&mut self, protocols: &str) -> Result<(), ErrorStack> {
1225         unsafe {
1226             let cstr = CString::new(protocols).unwrap();
1227 
1228             let r = ffi::SSL_CTX_set_tlsext_use_srtp(self.as_ptr(), cstr.as_ptr());
1229             // fun fact, set_tlsext_use_srtp has a reversed return code D:
1230             if r == 0 {
1231                 Ok(())
1232             } else {
1233                 Err(ErrorStack::get())
1234             }
1235         }
1236     }
1237 
1238     /// Sets the callback used by a server to select a protocol for Application Layer Protocol
1239     /// Negotiation (ALPN).
1240     ///
1241     /// The callback is provided with the client's protocol list in ALPN wire format. See the
1242     /// documentation for [`SslContextBuilder::set_alpn_protos`] for details. It should return one
1243     /// of those protocols on success. The [`select_next_proto`] function implements the standard
1244     /// protocol selection algorithm.
1245     ///
1246     /// Requires OpenSSL 1.0.2 or LibreSSL 2.6.1 or newer.
1247     ///
1248     /// [`SslContextBuilder::set_alpn_protos`]: struct.SslContextBuilder.html#method.set_alpn_protos
1249     /// [`select_next_proto`]: fn.select_next_proto.html
1250     #[corresponds(SSL_CTX_set_alpn_select_cb)]
1251     #[cfg(any(ossl102, libressl261))]
set_alpn_select_callback<F>(&mut self, callback: F) where F: for<'a> Fn(&mut SslRef, &'a [u8]) -> Result<&'a [u8], AlpnError> + 'static + Sync + Send,1252     pub fn set_alpn_select_callback<F>(&mut self, callback: F)
1253     where
1254         F: for<'a> Fn(&mut SslRef, &'a [u8]) -> Result<&'a [u8], AlpnError> + 'static + Sync + Send,
1255     {
1256         unsafe {
1257             self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
1258             ffi::SSL_CTX_set_alpn_select_cb__fixed_rust(
1259                 self.as_ptr(),
1260                 Some(callbacks::raw_alpn_select::<F>),
1261                 ptr::null_mut(),
1262             );
1263         }
1264     }
1265 
1266     /// Checks for consistency between the private key and certificate.
1267     #[corresponds(SSL_CTX_check_private_key)]
check_private_key(&self) -> Result<(), ErrorStack>1268     pub fn check_private_key(&self) -> Result<(), ErrorStack> {
1269         unsafe { cvt(ffi::SSL_CTX_check_private_key(self.as_ptr())).map(|_| ()) }
1270     }
1271 
1272     /// Returns a shared reference to the context's certificate store.
1273     #[corresponds(SSL_CTX_get_cert_store)]
cert_store(&self) -> &X509StoreBuilderRef1274     pub fn cert_store(&self) -> &X509StoreBuilderRef {
1275         unsafe { X509StoreBuilderRef::from_ptr(ffi::SSL_CTX_get_cert_store(self.as_ptr())) }
1276     }
1277 
1278     /// Returns a mutable reference to the context's certificate store.
1279     #[corresponds(SSL_CTX_get_cert_store)]
cert_store_mut(&mut self) -> &mut X509StoreBuilderRef1280     pub fn cert_store_mut(&mut self) -> &mut X509StoreBuilderRef {
1281         unsafe { X509StoreBuilderRef::from_ptr_mut(ffi::SSL_CTX_get_cert_store(self.as_ptr())) }
1282     }
1283 
1284     /// Returns a reference to the X509 verification configuration.
1285     ///
1286     /// Requires OpenSSL 1.0.2 or newer.
1287     #[corresponds(SSL_CTX_get0_param)]
1288     #[cfg(any(ossl102, libressl261))]
verify_param(&self) -> &X509VerifyParamRef1289     pub fn verify_param(&self) -> &X509VerifyParamRef {
1290         unsafe { X509VerifyParamRef::from_ptr(ffi::SSL_CTX_get0_param(self.as_ptr())) }
1291     }
1292 
1293     /// Returns a mutable reference to the X509 verification configuration.
1294     ///
1295     /// Requires OpenSSL 1.0.2 or newer.
1296     #[corresponds(SSL_CTX_get0_param)]
1297     #[cfg(any(ossl102, libressl261))]
verify_param_mut(&mut self) -> &mut X509VerifyParamRef1298     pub fn verify_param_mut(&mut self) -> &mut X509VerifyParamRef {
1299         unsafe { X509VerifyParamRef::from_ptr_mut(ffi::SSL_CTX_get0_param(self.as_ptr())) }
1300     }
1301 
1302     /// Sets the callback dealing with OCSP stapling.
1303     ///
1304     /// On the client side, this callback is responsible for validating the OCSP status response
1305     /// returned by the server. The status may be retrieved with the `SslRef::ocsp_status` method.
1306     /// A response of `Ok(true)` indicates that the OCSP status is valid, and a response of
1307     /// `Ok(false)` indicates that the OCSP status is invalid and the handshake should be
1308     /// terminated.
1309     ///
1310     /// On the server side, this callback is responsible for setting the OCSP status response to be
1311     /// returned to clients. The status may be set with the `SslRef::set_ocsp_status` method. A
1312     /// response of `Ok(true)` indicates that the OCSP status should be returned to the client, and
1313     /// `Ok(false)` indicates that the status should not be returned to the client.
1314     #[corresponds(SSL_CTX_set_tlsext_status_cb)]
set_status_callback<F>(&mut self, callback: F) -> Result<(), ErrorStack> where F: Fn(&mut SslRef) -> Result<bool, ErrorStack> + 'static + Sync + Send,1315     pub fn set_status_callback<F>(&mut self, callback: F) -> Result<(), ErrorStack>
1316     where
1317         F: Fn(&mut SslRef) -> Result<bool, ErrorStack> + 'static + Sync + Send,
1318     {
1319         unsafe {
1320             self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
1321             cvt(
1322                 ffi::SSL_CTX_set_tlsext_status_cb(self.as_ptr(), Some(raw_tlsext_status::<F>))
1323                     as c_int,
1324             )
1325             .map(|_| ())
1326         }
1327     }
1328 
1329     /// Sets the callback for providing an identity and pre-shared key for a TLS-PSK client.
1330     ///
1331     /// The callback will be called with the SSL context, an identity hint if one was provided
1332     /// by the server, a mutable slice for each of the identity and pre-shared key bytes. The
1333     /// identity must be written as a null-terminated C string.
1334     #[corresponds(SSL_CTX_set_psk_client_callback)]
1335     #[cfg(not(osslconf = "OPENSSL_NO_PSK"))]
set_psk_client_callback<F>(&mut self, callback: F) where F: Fn(&mut SslRef, Option<&[u8]>, &mut [u8], &mut [u8]) -> Result<usize, ErrorStack> + 'static + Sync + Send,1336     pub fn set_psk_client_callback<F>(&mut self, callback: F)
1337     where
1338         F: Fn(&mut SslRef, Option<&[u8]>, &mut [u8], &mut [u8]) -> Result<usize, ErrorStack>
1339             + 'static
1340             + Sync
1341             + Send,
1342     {
1343         unsafe {
1344             self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
1345             ffi::SSL_CTX_set_psk_client_callback(self.as_ptr(), Some(raw_client_psk::<F>));
1346         }
1347     }
1348 
1349     #[deprecated(since = "0.10.10", note = "renamed to `set_psk_client_callback`")]
1350     #[cfg(not(osslconf = "OPENSSL_NO_PSK"))]
set_psk_callback<F>(&mut self, callback: F) where F: Fn(&mut SslRef, Option<&[u8]>, &mut [u8], &mut [u8]) -> Result<usize, ErrorStack> + 'static + Sync + Send,1351     pub fn set_psk_callback<F>(&mut self, callback: F)
1352     where
1353         F: Fn(&mut SslRef, Option<&[u8]>, &mut [u8], &mut [u8]) -> Result<usize, ErrorStack>
1354             + 'static
1355             + Sync
1356             + Send,
1357     {
1358         self.set_psk_client_callback(callback)
1359     }
1360 
1361     /// Sets the callback for providing an identity and pre-shared key for a TLS-PSK server.
1362     ///
1363     /// The callback will be called with the SSL context, an identity provided by the client,
1364     /// and, a mutable slice for the pre-shared key bytes. The callback returns the number of
1365     /// bytes in the pre-shared key.
1366     #[corresponds(SSL_CTX_set_psk_server_callback)]
1367     #[cfg(not(osslconf = "OPENSSL_NO_PSK"))]
set_psk_server_callback<F>(&mut self, callback: F) where F: Fn(&mut SslRef, Option<&[u8]>, &mut [u8]) -> Result<usize, ErrorStack> + 'static + Sync + Send,1368     pub fn set_psk_server_callback<F>(&mut self, callback: F)
1369     where
1370         F: Fn(&mut SslRef, Option<&[u8]>, &mut [u8]) -> Result<usize, ErrorStack>
1371             + 'static
1372             + Sync
1373             + Send,
1374     {
1375         unsafe {
1376             self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
1377             ffi::SSL_CTX_set_psk_server_callback(self.as_ptr(), Some(raw_server_psk::<F>));
1378         }
1379     }
1380 
1381     /// Sets the callback which is called when new sessions are negotiated.
1382     ///
1383     /// This can be used by clients to implement session caching. While in TLSv1.2 the session is
1384     /// available to access via [`SslRef::session`] immediately after the handshake completes, this
1385     /// is not the case for TLSv1.3. There, a session is not generally available immediately, and
1386     /// the server may provide multiple session tokens to the client over a single session. The new
1387     /// session callback is a portable way to deal with both cases.
1388     ///
1389     /// Note that session caching must be enabled for the callback to be invoked, and it defaults
1390     /// off for clients. [`set_session_cache_mode`] controls that behavior.
1391     ///
1392     /// [`SslRef::session`]: struct.SslRef.html#method.session
1393     /// [`set_session_cache_mode`]: #method.set_session_cache_mode
1394     #[corresponds(SSL_CTX_sess_set_new_cb)]
set_new_session_callback<F>(&mut self, callback: F) where F: Fn(&mut SslRef, SslSession) + 'static + Sync + Send,1395     pub fn set_new_session_callback<F>(&mut self, callback: F)
1396     where
1397         F: Fn(&mut SslRef, SslSession) + 'static + Sync + Send,
1398     {
1399         unsafe {
1400             self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
1401             ffi::SSL_CTX_sess_set_new_cb(self.as_ptr(), Some(callbacks::raw_new_session::<F>));
1402         }
1403     }
1404 
1405     /// Sets the callback which is called when sessions are removed from the context.
1406     ///
1407     /// Sessions can be removed because they have timed out or because they are considered faulty.
1408     #[corresponds(SSL_CTX_sess_set_remove_cb)]
set_remove_session_callback<F>(&mut self, callback: F) where F: Fn(&SslContextRef, &SslSessionRef) + 'static + Sync + Send,1409     pub fn set_remove_session_callback<F>(&mut self, callback: F)
1410     where
1411         F: Fn(&SslContextRef, &SslSessionRef) + 'static + Sync + Send,
1412     {
1413         unsafe {
1414             self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
1415             ffi::SSL_CTX_sess_set_remove_cb(
1416                 self.as_ptr(),
1417                 Some(callbacks::raw_remove_session::<F>),
1418             );
1419         }
1420     }
1421 
1422     /// Sets the callback which is called when a client proposed to resume a session but it was not
1423     /// found in the internal cache.
1424     ///
1425     /// The callback is passed a reference to the session ID provided by the client. It should
1426     /// return the session corresponding to that ID if available. This is only used for servers, not
1427     /// clients.
1428     ///
1429     /// # Safety
1430     ///
1431     /// The returned `SslSession` must not be associated with a different `SslContext`.
1432     #[corresponds(SSL_CTX_sess_set_get_cb)]
set_get_session_callback<F>(&mut self, callback: F) where F: Fn(&mut SslRef, &[u8]) -> Option<SslSession> + 'static + Sync + Send,1433     pub unsafe fn set_get_session_callback<F>(&mut self, callback: F)
1434     where
1435         F: Fn(&mut SslRef, &[u8]) -> Option<SslSession> + 'static + Sync + Send,
1436     {
1437         self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
1438         ffi::SSL_CTX_sess_set_get_cb(self.as_ptr(), Some(callbacks::raw_get_session::<F>));
1439     }
1440 
1441     /// Sets the TLS key logging callback.
1442     ///
1443     /// The callback is invoked whenever TLS key material is generated, and is passed a line of NSS
1444     /// SSLKEYLOGFILE-formatted text. This can be used by tools like Wireshark to decrypt message
1445     /// traffic. The line does not contain a trailing newline.
1446     ///
1447     /// Requires OpenSSL 1.1.1 or newer.
1448     #[corresponds(SSL_CTX_set_keylog_callback)]
1449     #[cfg(ossl111)]
set_keylog_callback<F>(&mut self, callback: F) where F: Fn(&SslRef, &str) + 'static + Sync + Send,1450     pub fn set_keylog_callback<F>(&mut self, callback: F)
1451     where
1452         F: Fn(&SslRef, &str) + 'static + Sync + Send,
1453     {
1454         unsafe {
1455             self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
1456             ffi::SSL_CTX_set_keylog_callback(self.as_ptr(), Some(callbacks::raw_keylog::<F>));
1457         }
1458     }
1459 
1460     /// Sets the session caching mode use for connections made with the context.
1461     ///
1462     /// Returns the previous session caching mode.
1463     #[corresponds(SSL_CTX_set_session_cache_mode)]
set_session_cache_mode(&mut self, mode: SslSessionCacheMode) -> SslSessionCacheMode1464     pub fn set_session_cache_mode(&mut self, mode: SslSessionCacheMode) -> SslSessionCacheMode {
1465         unsafe {
1466             let bits = ffi::SSL_CTX_set_session_cache_mode(self.as_ptr(), mode.bits());
1467             SslSessionCacheMode { bits }
1468         }
1469     }
1470 
1471     /// Sets the callback for generating an application cookie for TLS1.3
1472     /// stateless handshakes.
1473     ///
1474     /// The callback will be called with the SSL context and a slice into which the cookie
1475     /// should be written. The callback should return the number of bytes written.
1476     #[corresponds(SSL_CTX_set_stateless_cookie_generate_cb)]
1477     #[cfg(ossl111)]
set_stateless_cookie_generate_cb<F>(&mut self, callback: F) where F: Fn(&mut SslRef, &mut [u8]) -> Result<usize, ErrorStack> + 'static + Sync + Send,1478     pub fn set_stateless_cookie_generate_cb<F>(&mut self, callback: F)
1479     where
1480         F: Fn(&mut SslRef, &mut [u8]) -> Result<usize, ErrorStack> + 'static + Sync + Send,
1481     {
1482         unsafe {
1483             self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
1484             ffi::SSL_CTX_set_stateless_cookie_generate_cb(
1485                 self.as_ptr(),
1486                 Some(raw_stateless_cookie_generate::<F>),
1487             );
1488         }
1489     }
1490 
1491     /// Sets the callback for verifying an application cookie for TLS1.3
1492     /// stateless handshakes.
1493     ///
1494     /// The callback will be called with the SSL context and the cookie supplied by the
1495     /// client. It should return true if and only if the cookie is valid.
1496     ///
1497     /// Note that the OpenSSL implementation independently verifies the integrity of
1498     /// application cookies using an HMAC before invoking the supplied callback.
1499     #[corresponds(SSL_CTX_set_stateless_cookie_verify_cb)]
1500     #[cfg(ossl111)]
set_stateless_cookie_verify_cb<F>(&mut self, callback: F) where F: Fn(&mut SslRef, &[u8]) -> bool + 'static + Sync + Send,1501     pub fn set_stateless_cookie_verify_cb<F>(&mut self, callback: F)
1502     where
1503         F: Fn(&mut SslRef, &[u8]) -> bool + 'static + Sync + Send,
1504     {
1505         unsafe {
1506             self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
1507             ffi::SSL_CTX_set_stateless_cookie_verify_cb(
1508                 self.as_ptr(),
1509                 Some(raw_stateless_cookie_verify::<F>),
1510             )
1511         }
1512     }
1513 
1514     /// Sets the callback for generating a DTLSv1 cookie
1515     ///
1516     /// The callback will be called with the SSL context and a slice into which the cookie
1517     /// should be written. The callback should return the number of bytes written.
1518     #[corresponds(SSL_CTX_set_cookie_generate_cb)]
1519     #[cfg(not(boringssl))]
set_cookie_generate_cb<F>(&mut self, callback: F) where F: Fn(&mut SslRef, &mut [u8]) -> Result<usize, ErrorStack> + 'static + Sync + Send,1520     pub fn set_cookie_generate_cb<F>(&mut self, callback: F)
1521     where
1522         F: Fn(&mut SslRef, &mut [u8]) -> Result<usize, ErrorStack> + 'static + Sync + Send,
1523     {
1524         unsafe {
1525             self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
1526             ffi::SSL_CTX_set_cookie_generate_cb(self.as_ptr(), Some(raw_cookie_generate::<F>));
1527         }
1528     }
1529 
1530     /// Sets the callback for verifying a DTLSv1 cookie
1531     ///
1532     /// The callback will be called with the SSL context and the cookie supplied by the
1533     /// client. It should return true if and only if the cookie is valid.
1534     #[corresponds(SSL_CTX_set_cookie_verify_cb)]
1535     #[cfg(not(boringssl))]
set_cookie_verify_cb<F>(&mut self, callback: F) where F: Fn(&mut SslRef, &[u8]) -> bool + 'static + Sync + Send,1536     pub fn set_cookie_verify_cb<F>(&mut self, callback: F)
1537     where
1538         F: Fn(&mut SslRef, &[u8]) -> bool + 'static + Sync + Send,
1539     {
1540         unsafe {
1541             self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
1542             ffi::SSL_CTX_set_cookie_verify_cb(self.as_ptr(), Some(raw_cookie_verify::<F>));
1543         }
1544     }
1545 
1546     /// Sets the extra data at the specified index.
1547     ///
1548     /// This can be used to provide data to callbacks registered with the context. Use the
1549     /// `SslContext::new_ex_index` method to create an `Index`.
1550     #[corresponds(SSL_CTX_set_ex_data)]
set_ex_data<T>(&mut self, index: Index<SslContext, T>, data: T)1551     pub fn set_ex_data<T>(&mut self, index: Index<SslContext, T>, data: T) {
1552         self.set_ex_data_inner(index, data);
1553     }
1554 
set_ex_data_inner<T>(&mut self, index: Index<SslContext, T>, data: T) -> *mut c_void1555     fn set_ex_data_inner<T>(&mut self, index: Index<SslContext, T>, data: T) -> *mut c_void {
1556         unsafe {
1557             let data = Box::into_raw(Box::new(data)) as *mut c_void;
1558             ffi::SSL_CTX_set_ex_data(self.as_ptr(), index.as_raw(), data);
1559             data
1560         }
1561     }
1562 
1563     /// Adds a custom extension for a TLS/DTLS client or server for all supported protocol versions.
1564     ///
1565     /// Requires OpenSSL 1.1.1 or newer.
1566     #[corresponds(SSL_CTX_add_custom_ext)]
1567     #[cfg(ossl111)]
add_custom_ext<AddFn, ParseFn, T>( &mut self, ext_type: u16, context: ExtensionContext, add_cb: AddFn, parse_cb: ParseFn, ) -> Result<(), ErrorStack> where AddFn: Fn( &mut SslRef, ExtensionContext, Option<(usize, &X509Ref)>, ) -> Result<Option<T>, SslAlert> + 'static + Sync + Send, T: AsRef<[u8]> + 'static + Sync + Send, ParseFn: Fn( &mut SslRef, ExtensionContext, &[u8], Option<(usize, &X509Ref)>, ) -> Result<(), SslAlert> + 'static + Sync + Send,1568     pub fn add_custom_ext<AddFn, ParseFn, T>(
1569         &mut self,
1570         ext_type: u16,
1571         context: ExtensionContext,
1572         add_cb: AddFn,
1573         parse_cb: ParseFn,
1574     ) -> Result<(), ErrorStack>
1575     where
1576         AddFn: Fn(
1577                 &mut SslRef,
1578                 ExtensionContext,
1579                 Option<(usize, &X509Ref)>,
1580             ) -> Result<Option<T>, SslAlert>
1581             + 'static
1582             + Sync
1583             + Send,
1584         T: AsRef<[u8]> + 'static + Sync + Send,
1585         ParseFn: Fn(
1586                 &mut SslRef,
1587                 ExtensionContext,
1588                 &[u8],
1589                 Option<(usize, &X509Ref)>,
1590             ) -> Result<(), SslAlert>
1591             + 'static
1592             + Sync
1593             + Send,
1594     {
1595         let ret = unsafe {
1596             self.set_ex_data(SslContext::cached_ex_index::<AddFn>(), add_cb);
1597             self.set_ex_data(SslContext::cached_ex_index::<ParseFn>(), parse_cb);
1598 
1599             ffi::SSL_CTX_add_custom_ext(
1600                 self.as_ptr(),
1601                 ext_type as c_uint,
1602                 context.bits(),
1603                 Some(raw_custom_ext_add::<AddFn, T>),
1604                 Some(raw_custom_ext_free::<T>),
1605                 ptr::null_mut(),
1606                 Some(raw_custom_ext_parse::<ParseFn>),
1607                 ptr::null_mut(),
1608             )
1609         };
1610         if ret == 1 {
1611             Ok(())
1612         } else {
1613             Err(ErrorStack::get())
1614         }
1615     }
1616 
1617     /// Sets the maximum amount of early data that will be accepted on incoming connections.
1618     ///
1619     /// Defaults to 0.
1620     ///
1621     /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer.
1622     #[corresponds(SSL_CTX_set_max_early_data)]
1623     #[cfg(any(ossl111, libressl340))]
set_max_early_data(&mut self, bytes: u32) -> Result<(), ErrorStack>1624     pub fn set_max_early_data(&mut self, bytes: u32) -> Result<(), ErrorStack> {
1625         if unsafe { ffi::SSL_CTX_set_max_early_data(self.as_ptr(), bytes) } == 1 {
1626             Ok(())
1627         } else {
1628             Err(ErrorStack::get())
1629         }
1630     }
1631 
1632     /// Sets a callback which will be invoked just after the client's hello message is received.
1633     ///
1634     /// Requires OpenSSL 1.1.1 or newer.
1635     #[corresponds(SSL_CTX_set_client_hello_cb)]
1636     #[cfg(ossl111)]
set_client_hello_callback<F>(&mut self, callback: F) where F: Fn(&mut SslRef, &mut SslAlert) -> Result<ClientHelloResponse, ErrorStack> + 'static + Sync + Send,1637     pub fn set_client_hello_callback<F>(&mut self, callback: F)
1638     where
1639         F: Fn(&mut SslRef, &mut SslAlert) -> Result<ClientHelloResponse, ErrorStack>
1640             + 'static
1641             + Sync
1642             + Send,
1643     {
1644         unsafe {
1645             let ptr = self.set_ex_data_inner(SslContext::cached_ex_index::<F>(), callback);
1646             ffi::SSL_CTX_set_client_hello_cb(
1647                 self.as_ptr(),
1648                 Some(callbacks::raw_client_hello::<F>),
1649                 ptr,
1650             );
1651         }
1652     }
1653 
1654     /// Sets the context's session cache size limit, returning the previous limit.
1655     ///
1656     /// A value of 0 means that the cache size is unbounded.
1657     #[corresponds(SSL_CTX_sess_set_cache_size)]
1658     #[allow(clippy::useless_conversion)]
set_session_cache_size(&mut self, size: i32) -> i641659     pub fn set_session_cache_size(&mut self, size: i32) -> i64 {
1660         unsafe {
1661             ffi::SSL_CTX_sess_set_cache_size(self.as_ptr(), size as SslCacheSize) as SslCacheTy
1662         }
1663     }
1664 
1665     /// Sets the context's supported signature algorithms.
1666     ///
1667     /// Requires OpenSSL 1.0.2 or newer.
1668     #[corresponds(SSL_CTX_set1_sigalgs_list)]
1669     #[cfg(ossl102)]
set_sigalgs_list(&mut self, sigalgs: &str) -> Result<(), ErrorStack>1670     pub fn set_sigalgs_list(&mut self, sigalgs: &str) -> Result<(), ErrorStack> {
1671         let sigalgs = CString::new(sigalgs).unwrap();
1672         unsafe {
1673             cvt(ffi::SSL_CTX_set1_sigalgs_list(self.as_ptr(), sigalgs.as_ptr()) as c_int)
1674                 .map(|_| ())
1675         }
1676     }
1677 
1678     /// Sets the context's supported elliptic curve groups.
1679     ///
1680     /// Requires OpenSSL 1.1.1 or LibreSSL 2.5.1 or newer.
1681     #[corresponds(SSL_CTX_set1_groups_list)]
1682     #[cfg(any(ossl111, libressl251))]
set_groups_list(&mut self, groups: &str) -> Result<(), ErrorStack>1683     pub fn set_groups_list(&mut self, groups: &str) -> Result<(), ErrorStack> {
1684         let groups = CString::new(groups).unwrap();
1685         unsafe {
1686             cvt(ffi::SSL_CTX_set1_groups_list(self.as_ptr(), groups.as_ptr()) as c_int).map(|_| ())
1687         }
1688     }
1689 
1690     /// Sets the number of TLS 1.3 session tickets that will be sent to a client after a full
1691     /// handshake.
1692     ///
1693     /// Requires OpenSSL 1.1.1 or newer.
1694     #[corresponds(SSL_CTX_set_num_tickets)]
1695     #[cfg(ossl111)]
set_num_tickets(&mut self, num_tickets: usize) -> Result<(), ErrorStack>1696     pub fn set_num_tickets(&mut self, num_tickets: usize) -> Result<(), ErrorStack> {
1697         unsafe { cvt(ffi::SSL_CTX_set_num_tickets(self.as_ptr(), num_tickets)).map(|_| ()) }
1698     }
1699 
1700     /// Consumes the builder, returning a new `SslContext`.
build(self) -> SslContext1701     pub fn build(self) -> SslContext {
1702         self.0
1703     }
1704 }
1705 
1706 foreign_type_and_impl_send_sync! {
1707     type CType = ffi::SSL_CTX;
1708     fn drop = ffi::SSL_CTX_free;
1709 
1710     /// A context object for TLS streams.
1711     ///
1712     /// Applications commonly configure a single `SslContext` that is shared by all of its
1713     /// `SslStreams`.
1714     pub struct SslContext;
1715 
1716     /// Reference to [`SslContext`]
1717     ///
1718     /// [`SslContext`]: struct.SslContext.html
1719     pub struct SslContextRef;
1720 }
1721 
1722 impl Clone for SslContext {
clone(&self) -> Self1723     fn clone(&self) -> Self {
1724         (**self).to_owned()
1725     }
1726 }
1727 
1728 impl ToOwned for SslContextRef {
1729     type Owned = SslContext;
1730 
to_owned(&self) -> Self::Owned1731     fn to_owned(&self) -> Self::Owned {
1732         unsafe {
1733             SSL_CTX_up_ref(self.as_ptr());
1734             SslContext::from_ptr(self.as_ptr())
1735         }
1736     }
1737 }
1738 
1739 // TODO: add useful info here
1740 impl fmt::Debug for SslContext {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result1741     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
1742         write!(fmt, "SslContext")
1743     }
1744 }
1745 
1746 impl SslContext {
1747     /// Creates a new builder object for an `SslContext`.
builder(method: SslMethod) -> Result<SslContextBuilder, ErrorStack>1748     pub fn builder(method: SslMethod) -> Result<SslContextBuilder, ErrorStack> {
1749         SslContextBuilder::new(method)
1750     }
1751 
1752     /// Returns a new extra data index.
1753     ///
1754     /// Each invocation of this function is guaranteed to return a distinct index. These can be used
1755     /// to store data in the context that can be retrieved later by callbacks, for example.
1756     #[corresponds(SSL_CTX_get_ex_new_index)]
new_ex_index<T>() -> Result<Index<SslContext, T>, ErrorStack> where T: 'static + Sync + Send,1757     pub fn new_ex_index<T>() -> Result<Index<SslContext, T>, ErrorStack>
1758     where
1759         T: 'static + Sync + Send,
1760     {
1761         unsafe {
1762             ffi::init();
1763             #[cfg(boringssl)]
1764             let idx = cvt_n(get_new_idx(Some(free_data_box::<T>)))?;
1765             #[cfg(not(boringssl))]
1766             let idx = cvt_n(get_new_idx(free_data_box::<T>))?;
1767             Ok(Index::from_raw(idx))
1768         }
1769     }
1770 
1771     // FIXME should return a result?
cached_ex_index<T>() -> Index<SslContext, T> where T: 'static + Sync + Send,1772     fn cached_ex_index<T>() -> Index<SslContext, T>
1773     where
1774         T: 'static + Sync + Send,
1775     {
1776         unsafe {
1777             let idx = *INDEXES
1778                 .lock()
1779                 .unwrap_or_else(|e| e.into_inner())
1780                 .entry(TypeId::of::<T>())
1781                 .or_insert_with(|| SslContext::new_ex_index::<T>().unwrap().as_raw());
1782             Index::from_raw(idx)
1783         }
1784     }
1785 }
1786 
1787 impl SslContextRef {
1788     /// Returns the certificate associated with this `SslContext`, if present.
1789     ///
1790     /// Requires OpenSSL 1.0.2 or LibreSSL 2.7.0 or newer.
1791     #[corresponds(SSL_CTX_get0_certificate)]
1792     #[cfg(any(ossl102, libressl270))]
certificate(&self) -> Option<&X509Ref>1793     pub fn certificate(&self) -> Option<&X509Ref> {
1794         unsafe {
1795             let ptr = ffi::SSL_CTX_get0_certificate(self.as_ptr());
1796             X509Ref::from_const_ptr_opt(ptr)
1797         }
1798     }
1799 
1800     /// Returns the private key associated with this `SslContext`, if present.
1801     ///
1802     /// Requires OpenSSL 1.0.2 or LibreSSL 3.4.0 or newer.
1803     #[corresponds(SSL_CTX_get0_privatekey)]
1804     #[cfg(any(ossl102, libressl340))]
private_key(&self) -> Option<&PKeyRef<Private>>1805     pub fn private_key(&self) -> Option<&PKeyRef<Private>> {
1806         unsafe {
1807             let ptr = ffi::SSL_CTX_get0_privatekey(self.as_ptr());
1808             PKeyRef::from_const_ptr_opt(ptr)
1809         }
1810     }
1811 
1812     /// Returns a shared reference to the certificate store used for verification.
1813     #[corresponds(SSL_CTX_get_cert_store)]
cert_store(&self) -> &X509StoreRef1814     pub fn cert_store(&self) -> &X509StoreRef {
1815         unsafe { X509StoreRef::from_ptr(ffi::SSL_CTX_get_cert_store(self.as_ptr())) }
1816     }
1817 
1818     /// Returns a shared reference to the stack of certificates making up the chain from the leaf.
1819     #[corresponds(SSL_CTX_get_extra_chain_certs)]
extra_chain_certs(&self) -> &StackRef<X509>1820     pub fn extra_chain_certs(&self) -> &StackRef<X509> {
1821         unsafe {
1822             let mut chain = ptr::null_mut();
1823             ffi::SSL_CTX_get_extra_chain_certs(self.as_ptr(), &mut chain);
1824             StackRef::from_const_ptr_opt(chain).expect("extra chain certs must not be null")
1825         }
1826     }
1827 
1828     /// Returns a reference to the extra data at the specified index.
1829     #[corresponds(SSL_CTX_get_ex_data)]
ex_data<T>(&self, index: Index<SslContext, T>) -> Option<&T>1830     pub fn ex_data<T>(&self, index: Index<SslContext, T>) -> Option<&T> {
1831         unsafe {
1832             let data = ffi::SSL_CTX_get_ex_data(self.as_ptr(), index.as_raw());
1833             if data.is_null() {
1834                 None
1835             } else {
1836                 Some(&*(data as *const T))
1837             }
1838         }
1839     }
1840 
1841     /// Gets the maximum amount of early data that will be accepted on incoming connections.
1842     ///
1843     /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer.
1844     #[corresponds(SSL_CTX_get_max_early_data)]
1845     #[cfg(any(ossl111, libressl340))]
max_early_data(&self) -> u321846     pub fn max_early_data(&self) -> u32 {
1847         unsafe { ffi::SSL_CTX_get_max_early_data(self.as_ptr()) }
1848     }
1849 
1850     /// Adds a session to the context's cache.
1851     ///
1852     /// Returns `true` if the session was successfully added to the cache, and `false` if it was already present.
1853     ///
1854     /// # Safety
1855     ///
1856     /// The caller of this method is responsible for ensuring that the session has never been used with another
1857     /// `SslContext` than this one.
1858     #[corresponds(SSL_CTX_add_session)]
add_session(&self, session: &SslSessionRef) -> bool1859     pub unsafe fn add_session(&self, session: &SslSessionRef) -> bool {
1860         ffi::SSL_CTX_add_session(self.as_ptr(), session.as_ptr()) != 0
1861     }
1862 
1863     /// Removes a session from the context's cache and marks it as non-resumable.
1864     ///
1865     /// Returns `true` if the session was successfully found and removed, and `false` otherwise.
1866     ///
1867     /// # Safety
1868     ///
1869     /// The caller of this method is responsible for ensuring that the session has never been used with another
1870     /// `SslContext` than this one.
1871     #[corresponds(SSL_CTX_remove_session)]
remove_session(&self, session: &SslSessionRef) -> bool1872     pub unsafe fn remove_session(&self, session: &SslSessionRef) -> bool {
1873         ffi::SSL_CTX_remove_session(self.as_ptr(), session.as_ptr()) != 0
1874     }
1875 
1876     /// Returns the context's session cache size limit.
1877     ///
1878     /// A value of 0 means that the cache size is unbounded.
1879     #[corresponds(SSL_CTX_sess_get_cache_size)]
1880     #[allow(clippy::unnecessary_cast)]
session_cache_size(&self) -> i641881     pub fn session_cache_size(&self) -> i64 {
1882         unsafe { ffi::SSL_CTX_sess_get_cache_size(self.as_ptr()) as i64 }
1883     }
1884 
1885     /// Returns the verify mode that was set on this context from [`SslContextBuilder::set_verify`].
1886     ///
1887     /// [`SslContextBuilder::set_verify`]: struct.SslContextBuilder.html#method.set_verify
1888     #[corresponds(SSL_CTX_get_verify_mode)]
verify_mode(&self) -> SslVerifyMode1889     pub fn verify_mode(&self) -> SslVerifyMode {
1890         let mode = unsafe { ffi::SSL_CTX_get_verify_mode(self.as_ptr()) };
1891         SslVerifyMode::from_bits(mode).expect("SSL_CTX_get_verify_mode returned invalid mode")
1892     }
1893 
1894     /// Gets the number of TLS 1.3 session tickets that will be sent to a client after a full
1895     /// handshake.
1896     ///
1897     /// Requires OpenSSL 1.1.1 or newer.
1898     #[corresponds(SSL_CTX_get_num_tickets)]
1899     #[cfg(ossl111)]
num_tickets(&self) -> usize1900     pub fn num_tickets(&self) -> usize {
1901         unsafe { ffi::SSL_CTX_get_num_tickets(self.as_ptr()) }
1902     }
1903 }
1904 
1905 /// Information about the state of a cipher.
1906 pub struct CipherBits {
1907     /// The number of secret bits used for the cipher.
1908     pub secret: i32,
1909 
1910     /// The number of bits processed by the chosen algorithm.
1911     pub algorithm: i32,
1912 }
1913 
1914 /// Information about a cipher.
1915 pub struct SslCipher(*mut ffi::SSL_CIPHER);
1916 
1917 impl ForeignType for SslCipher {
1918     type CType = ffi::SSL_CIPHER;
1919     type Ref = SslCipherRef;
1920 
1921     #[inline]
from_ptr(ptr: *mut ffi::SSL_CIPHER) -> SslCipher1922     unsafe fn from_ptr(ptr: *mut ffi::SSL_CIPHER) -> SslCipher {
1923         SslCipher(ptr)
1924     }
1925 
1926     #[inline]
as_ptr(&self) -> *mut ffi::SSL_CIPHER1927     fn as_ptr(&self) -> *mut ffi::SSL_CIPHER {
1928         self.0
1929     }
1930 }
1931 
1932 impl Deref for SslCipher {
1933     type Target = SslCipherRef;
1934 
deref(&self) -> &SslCipherRef1935     fn deref(&self) -> &SslCipherRef {
1936         unsafe { SslCipherRef::from_ptr(self.0) }
1937     }
1938 }
1939 
1940 impl DerefMut for SslCipher {
deref_mut(&mut self) -> &mut SslCipherRef1941     fn deref_mut(&mut self) -> &mut SslCipherRef {
1942         unsafe { SslCipherRef::from_ptr_mut(self.0) }
1943     }
1944 }
1945 
1946 /// Reference to an [`SslCipher`].
1947 ///
1948 /// [`SslCipher`]: struct.SslCipher.html
1949 pub struct SslCipherRef(Opaque);
1950 
1951 impl ForeignTypeRef for SslCipherRef {
1952     type CType = ffi::SSL_CIPHER;
1953 }
1954 
1955 impl SslCipherRef {
1956     /// Returns the name of the cipher.
1957     #[corresponds(SSL_CIPHER_get_name)]
name(&self) -> &'static str1958     pub fn name(&self) -> &'static str {
1959         unsafe {
1960             let ptr = ffi::SSL_CIPHER_get_name(self.as_ptr());
1961             CStr::from_ptr(ptr).to_str().unwrap()
1962         }
1963     }
1964 
1965     /// Returns the RFC-standard name of the cipher, if one exists.
1966     ///
1967     /// Requires OpenSSL 1.1.1 or newer.
1968     #[corresponds(SSL_CIPHER_standard_name)]
1969     #[cfg(ossl111)]
standard_name(&self) -> Option<&'static str>1970     pub fn standard_name(&self) -> Option<&'static str> {
1971         unsafe {
1972             let ptr = ffi::SSL_CIPHER_standard_name(self.as_ptr());
1973             if ptr.is_null() {
1974                 None
1975             } else {
1976                 Some(CStr::from_ptr(ptr).to_str().unwrap())
1977             }
1978         }
1979     }
1980 
1981     /// Returns the SSL/TLS protocol version that first defined the cipher.
1982     #[corresponds(SSL_CIPHER_get_version)]
version(&self) -> &'static str1983     pub fn version(&self) -> &'static str {
1984         let version = unsafe {
1985             let ptr = ffi::SSL_CIPHER_get_version(self.as_ptr());
1986             CStr::from_ptr(ptr as *const _)
1987         };
1988 
1989         str::from_utf8(version.to_bytes()).unwrap()
1990     }
1991 
1992     /// Returns the number of bits used for the cipher.
1993     #[corresponds(SSL_CIPHER_get_bits)]
1994     #[allow(clippy::useless_conversion)]
bits(&self) -> CipherBits1995     pub fn bits(&self) -> CipherBits {
1996         unsafe {
1997             let mut algo_bits = 0;
1998             let secret_bits = ffi::SSL_CIPHER_get_bits(self.as_ptr(), &mut algo_bits);
1999             CipherBits {
2000                 secret: secret_bits.into(),
2001                 algorithm: algo_bits.into(),
2002             }
2003         }
2004     }
2005 
2006     /// Returns a textual description of the cipher.
2007     #[corresponds(SSL_CIPHER_description)]
description(&self) -> String2008     pub fn description(&self) -> String {
2009         unsafe {
2010             // SSL_CIPHER_description requires a buffer of at least 128 bytes.
2011             let mut buf = [0; 128];
2012             let ptr = ffi::SSL_CIPHER_description(self.as_ptr(), buf.as_mut_ptr(), 128);
2013             String::from_utf8(CStr::from_ptr(ptr as *const _).to_bytes().to_vec()).unwrap()
2014         }
2015     }
2016 
2017     /// Returns the handshake digest of the cipher.
2018     ///
2019     /// Requires OpenSSL 1.1.1 or newer.
2020     #[corresponds(SSL_CIPHER_get_handshake_digest)]
2021     #[cfg(ossl111)]
handshake_digest(&self) -> Option<MessageDigest>2022     pub fn handshake_digest(&self) -> Option<MessageDigest> {
2023         unsafe {
2024             let ptr = ffi::SSL_CIPHER_get_handshake_digest(self.as_ptr());
2025             if ptr.is_null() {
2026                 None
2027             } else {
2028                 Some(MessageDigest::from_ptr(ptr))
2029             }
2030         }
2031     }
2032 
2033     /// Returns the NID corresponding to the cipher.
2034     ///
2035     /// Requires OpenSSL 1.1.0 or LibreSSL 2.7.0 or newer.
2036     #[corresponds(SSL_CIPHER_get_cipher_nid)]
2037     #[cfg(any(ossl110, libressl270))]
cipher_nid(&self) -> Option<Nid>2038     pub fn cipher_nid(&self) -> Option<Nid> {
2039         let n = unsafe { ffi::SSL_CIPHER_get_cipher_nid(self.as_ptr()) };
2040         if n == 0 {
2041             None
2042         } else {
2043             Some(Nid::from_raw(n))
2044         }
2045     }
2046 }
2047 
2048 foreign_type_and_impl_send_sync! {
2049     type CType = ffi::SSL_SESSION;
2050     fn drop = ffi::SSL_SESSION_free;
2051 
2052     /// An encoded SSL session.
2053     ///
2054     /// These can be cached to share sessions across connections.
2055     pub struct SslSession;
2056 
2057     /// Reference to [`SslSession`].
2058     ///
2059     /// [`SslSession`]: struct.SslSession.html
2060     pub struct SslSessionRef;
2061 }
2062 
2063 impl Clone for SslSession {
clone(&self) -> SslSession2064     fn clone(&self) -> SslSession {
2065         SslSessionRef::to_owned(self)
2066     }
2067 }
2068 
2069 impl SslSession {
2070     from_der! {
2071         /// Deserializes a DER-encoded session structure.
2072         #[corresponds(d2i_SSL_SESSION)]
2073         from_der,
2074         SslSession,
2075         ffi::d2i_SSL_SESSION
2076     }
2077 }
2078 
2079 impl ToOwned for SslSessionRef {
2080     type Owned = SslSession;
2081 
to_owned(&self) -> SslSession2082     fn to_owned(&self) -> SslSession {
2083         unsafe {
2084             SSL_SESSION_up_ref(self.as_ptr());
2085             SslSession(self.as_ptr())
2086         }
2087     }
2088 }
2089 
2090 impl SslSessionRef {
2091     /// Returns the SSL session ID.
2092     #[corresponds(SSL_SESSION_get_id)]
id(&self) -> &[u8]2093     pub fn id(&self) -> &[u8] {
2094         unsafe {
2095             let mut len = 0;
2096             let p = ffi::SSL_SESSION_get_id(self.as_ptr(), &mut len);
2097             slice::from_raw_parts(p as *const u8, len as usize)
2098         }
2099     }
2100 
2101     /// Returns the length of the master key.
2102     #[corresponds(SSL_SESSION_get_master_key)]
master_key_len(&self) -> usize2103     pub fn master_key_len(&self) -> usize {
2104         unsafe { SSL_SESSION_get_master_key(self.as_ptr(), ptr::null_mut(), 0) }
2105     }
2106 
2107     /// Copies the master key into the provided buffer.
2108     ///
2109     /// Returns the number of bytes written, or the size of the master key if the buffer is empty.
2110     #[corresponds(SSL_SESSION_get_master_key)]
master_key(&self, buf: &mut [u8]) -> usize2111     pub fn master_key(&self, buf: &mut [u8]) -> usize {
2112         unsafe { SSL_SESSION_get_master_key(self.as_ptr(), buf.as_mut_ptr(), buf.len()) }
2113     }
2114 
2115     /// Gets the maximum amount of early data that can be sent on this session.
2116     ///
2117     /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer.
2118     #[corresponds(SSL_SESSION_get_max_early_data)]
2119     #[cfg(any(ossl111, libressl340))]
max_early_data(&self) -> u322120     pub fn max_early_data(&self) -> u32 {
2121         unsafe { ffi::SSL_SESSION_get_max_early_data(self.as_ptr()) }
2122     }
2123 
2124     /// Returns the time at which the session was established, in seconds since the Unix epoch.
2125     #[corresponds(SSL_SESSION_get_time)]
2126     #[allow(clippy::useless_conversion)]
time(&self) -> SslTimeTy2127     pub fn time(&self) -> SslTimeTy {
2128         unsafe { ffi::SSL_SESSION_get_time(self.as_ptr()) }
2129     }
2130 
2131     /// Returns the sessions timeout, in seconds.
2132     ///
2133     /// A session older than this time should not be used for session resumption.
2134     #[corresponds(SSL_SESSION_get_timeout)]
2135     #[allow(clippy::useless_conversion)]
timeout(&self) -> i642136     pub fn timeout(&self) -> i64 {
2137         unsafe { ffi::SSL_SESSION_get_timeout(self.as_ptr()).into() }
2138     }
2139 
2140     /// Returns the session's TLS protocol version.
2141     ///
2142     /// Requires OpenSSL 1.1.0 or LibreSSL 2.7.0 or newer.
2143     #[corresponds(SSL_SESSION_get_protocol_version)]
2144     #[cfg(any(ossl110, libressl270))]
protocol_version(&self) -> SslVersion2145     pub fn protocol_version(&self) -> SslVersion {
2146         unsafe {
2147             let version = ffi::SSL_SESSION_get_protocol_version(self.as_ptr());
2148             SslVersion(version)
2149         }
2150     }
2151 
2152     to_der! {
2153         /// Serializes the session into a DER-encoded structure.
2154         #[corresponds(i2d_SSL_SESSION)]
2155         to_der,
2156         ffi::i2d_SSL_SESSION
2157     }
2158 }
2159 
2160 foreign_type_and_impl_send_sync! {
2161     type CType = ffi::SSL;
2162     fn drop = ffi::SSL_free;
2163 
2164     /// The state of an SSL/TLS session.
2165     ///
2166     /// `Ssl` objects are created from an [`SslContext`], which provides configuration defaults.
2167     /// These defaults can be overridden on a per-`Ssl` basis, however.
2168     ///
2169     /// [`SslContext`]: struct.SslContext.html
2170     pub struct Ssl;
2171 
2172     /// Reference to an [`Ssl`].
2173     ///
2174     /// [`Ssl`]: struct.Ssl.html
2175     pub struct SslRef;
2176 }
2177 
2178 impl fmt::Debug for Ssl {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result2179     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
2180         fmt::Debug::fmt(&**self, fmt)
2181     }
2182 }
2183 
2184 impl Ssl {
2185     /// Returns a new extra data index.
2186     ///
2187     /// Each invocation of this function is guaranteed to return a distinct index. These can be used
2188     /// to store data in the context that can be retrieved later by callbacks, for example.
2189     #[corresponds(SSL_get_ex_new_index)]
new_ex_index<T>() -> Result<Index<Ssl, T>, ErrorStack> where T: 'static + Sync + Send,2190     pub fn new_ex_index<T>() -> Result<Index<Ssl, T>, ErrorStack>
2191     where
2192         T: 'static + Sync + Send,
2193     {
2194         unsafe {
2195             ffi::init();
2196             #[cfg(boringssl)]
2197             let idx = cvt_n(get_new_ssl_idx(Some(free_data_box::<T>)))?;
2198             #[cfg(not(boringssl))]
2199             let idx = cvt_n(get_new_ssl_idx(free_data_box::<T>))?;
2200             Ok(Index::from_raw(idx))
2201         }
2202     }
2203 
2204     // FIXME should return a result?
cached_ex_index<T>() -> Index<Ssl, T> where T: 'static + Sync + Send,2205     fn cached_ex_index<T>() -> Index<Ssl, T>
2206     where
2207         T: 'static + Sync + Send,
2208     {
2209         unsafe {
2210             let idx = *SSL_INDEXES
2211                 .lock()
2212                 .unwrap_or_else(|e| e.into_inner())
2213                 .entry(TypeId::of::<T>())
2214                 .or_insert_with(|| Ssl::new_ex_index::<T>().unwrap().as_raw());
2215             Index::from_raw(idx)
2216         }
2217     }
2218 
2219     /// Creates a new `Ssl`.
2220     ///
2221     /// This corresponds to [`SSL_new`].
2222     ///
2223     /// [`SSL_new`]: https://www.openssl.org/docs/manmaster/ssl/SSL_new.html
2224     #[corresponds(SSL_new)]
new(ctx: &SslContextRef) -> Result<Ssl, ErrorStack>2225     pub fn new(ctx: &SslContextRef) -> Result<Ssl, ErrorStack> {
2226         let session_ctx_index = try_get_session_ctx_index()?;
2227         unsafe {
2228             let ptr = cvt_p(ffi::SSL_new(ctx.as_ptr()))?;
2229             let mut ssl = Ssl::from_ptr(ptr);
2230             ssl.set_ex_data(*session_ctx_index, ctx.to_owned());
2231 
2232             Ok(ssl)
2233         }
2234     }
2235 
2236     /// Initiates a client-side TLS handshake.
2237     ///
2238     /// This corresponds to [`SSL_connect`].
2239     ///
2240     /// # Warning
2241     ///
2242     /// OpenSSL's default configuration is insecure. It is highly recommended to use
2243     /// `SslConnector` rather than `Ssl` directly, as it manages that configuration.
2244     ///
2245     /// [`SSL_connect`]: https://www.openssl.org/docs/manmaster/man3/SSL_connect.html
2246     #[corresponds(SSL_connect)]
2247     #[allow(deprecated)]
connect<S>(self, stream: S) -> Result<SslStream<S>, HandshakeError<S>> where S: Read + Write,2248     pub fn connect<S>(self, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
2249     where
2250         S: Read + Write,
2251     {
2252         SslStreamBuilder::new(self, stream).connect()
2253     }
2254 
2255     /// Initiates a server-side TLS handshake.
2256     ///
2257     /// This corresponds to [`SSL_accept`].
2258     ///
2259     /// # Warning
2260     ///
2261     /// OpenSSL's default configuration is insecure. It is highly recommended to use
2262     /// `SslAcceptor` rather than `Ssl` directly, as it manages that configuration.
2263     ///
2264     /// [`SSL_accept`]: https://www.openssl.org/docs/manmaster/man3/SSL_accept.html
2265     #[corresponds(SSL_accept)]
2266     #[allow(deprecated)]
accept<S>(self, stream: S) -> Result<SslStream<S>, HandshakeError<S>> where S: Read + Write,2267     pub fn accept<S>(self, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
2268     where
2269         S: Read + Write,
2270     {
2271         SslStreamBuilder::new(self, stream).accept()
2272     }
2273 }
2274 
2275 impl fmt::Debug for SslRef {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result2276     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
2277         fmt.debug_struct("Ssl")
2278             .field("state", &self.state_string_long())
2279             .field("verify_result", &self.verify_result())
2280             .finish()
2281     }
2282 }
2283 
2284 impl SslRef {
get_raw_rbio(&self) -> *mut ffi::BIO2285     fn get_raw_rbio(&self) -> *mut ffi::BIO {
2286         unsafe { ffi::SSL_get_rbio(self.as_ptr()) }
2287     }
2288 
read(&mut self, buf: &mut [u8]) -> c_int2289     fn read(&mut self, buf: &mut [u8]) -> c_int {
2290         let len = cmp::min(c_int::max_value() as usize, buf.len()) as c_int;
2291         unsafe { ffi::SSL_read(self.as_ptr(), buf.as_ptr() as *mut c_void, len) }
2292     }
2293 
peek(&mut self, buf: &mut [u8]) -> c_int2294     fn peek(&mut self, buf: &mut [u8]) -> c_int {
2295         let len = cmp::min(c_int::max_value() as usize, buf.len()) as c_int;
2296         unsafe { ffi::SSL_peek(self.as_ptr(), buf.as_ptr() as *mut c_void, len) }
2297     }
2298 
write(&mut self, buf: &[u8]) -> c_int2299     fn write(&mut self, buf: &[u8]) -> c_int {
2300         let len = cmp::min(c_int::max_value() as usize, buf.len()) as c_int;
2301         unsafe { ffi::SSL_write(self.as_ptr(), buf.as_ptr() as *const c_void, len) }
2302     }
2303 
get_error(&self, ret: c_int) -> ErrorCode2304     fn get_error(&self, ret: c_int) -> ErrorCode {
2305         unsafe { ErrorCode::from_raw(ffi::SSL_get_error(self.as_ptr(), ret)) }
2306     }
2307 
2308     /// Configure as an outgoing stream from a client.
2309     #[corresponds(SSL_set_connect_state)]
set_connect_state(&mut self)2310     pub fn set_connect_state(&mut self) {
2311         unsafe { ffi::SSL_set_connect_state(self.as_ptr()) }
2312     }
2313 
2314     /// Configure as an incoming stream to a server.
2315     #[corresponds(SSL_set_accept_state)]
set_accept_state(&mut self)2316     pub fn set_accept_state(&mut self) {
2317         unsafe { ffi::SSL_set_accept_state(self.as_ptr()) }
2318     }
2319 
2320     /// Like [`SslContextBuilder::set_verify`].
2321     ///
2322     /// [`SslContextBuilder::set_verify`]: struct.SslContextBuilder.html#method.set_verify
2323     #[corresponds(SSL_set_verify)]
set_verify(&mut self, mode: SslVerifyMode)2324     pub fn set_verify(&mut self, mode: SslVerifyMode) {
2325         unsafe { ffi::SSL_set_verify(self.as_ptr(), mode.bits as c_int, None) }
2326     }
2327 
2328     /// Returns the verify mode that was set using `set_verify`.
2329     #[corresponds(SSL_set_verify_mode)]
verify_mode(&self) -> SslVerifyMode2330     pub fn verify_mode(&self) -> SslVerifyMode {
2331         let mode = unsafe { ffi::SSL_get_verify_mode(self.as_ptr()) };
2332         SslVerifyMode::from_bits(mode).expect("SSL_get_verify_mode returned invalid mode")
2333     }
2334 
2335     /// Like [`SslContextBuilder::set_verify_callback`].
2336     ///
2337     /// [`SslContextBuilder::set_verify_callback`]: struct.SslContextBuilder.html#method.set_verify_callback
2338     #[corresponds(SSL_set_verify)]
set_verify_callback<F>(&mut self, mode: SslVerifyMode, verify: F) where F: Fn(bool, &mut X509StoreContextRef) -> bool + 'static + Sync + Send,2339     pub fn set_verify_callback<F>(&mut self, mode: SslVerifyMode, verify: F)
2340     where
2341         F: Fn(bool, &mut X509StoreContextRef) -> bool + 'static + Sync + Send,
2342     {
2343         unsafe {
2344             // this needs to be in an Arc since the callback can register a new callback!
2345             self.set_ex_data(Ssl::cached_ex_index(), Arc::new(verify));
2346             ffi::SSL_set_verify(self.as_ptr(), mode.bits as c_int, Some(ssl_raw_verify::<F>));
2347         }
2348     }
2349 
2350     /// Like [`SslContextBuilder::set_tmp_dh`].
2351     ///
2352     /// [`SslContextBuilder::set_tmp_dh`]: struct.SslContextBuilder.html#method.set_tmp_dh
2353     #[corresponds(SSL_set_tmp_dh)]
set_tmp_dh(&mut self, dh: &DhRef<Params>) -> Result<(), ErrorStack>2354     pub fn set_tmp_dh(&mut self, dh: &DhRef<Params>) -> Result<(), ErrorStack> {
2355         unsafe { cvt(ffi::SSL_set_tmp_dh(self.as_ptr(), dh.as_ptr()) as c_int).map(|_| ()) }
2356     }
2357 
2358     /// Like [`SslContextBuilder::set_tmp_dh_callback`].
2359     ///
2360     /// [`SslContextBuilder::set_tmp_dh_callback`]: struct.SslContextBuilder.html#method.set_tmp_dh_callback
2361     #[corresponds(SSL_set_tmp_dh_callback)]
set_tmp_dh_callback<F>(&mut self, callback: F) where F: Fn(&mut SslRef, bool, u32) -> Result<Dh<Params>, ErrorStack> + 'static + Sync + Send,2362     pub fn set_tmp_dh_callback<F>(&mut self, callback: F)
2363     where
2364         F: Fn(&mut SslRef, bool, u32) -> Result<Dh<Params>, ErrorStack> + 'static + Sync + Send,
2365     {
2366         unsafe {
2367             // this needs to be in an Arc since the callback can register a new callback!
2368             self.set_ex_data(Ssl::cached_ex_index(), Arc::new(callback));
2369             #[cfg(boringssl)]
2370             ffi::SSL_set_tmp_dh_callback(self.as_ptr(), Some(raw_tmp_dh_ssl::<F>));
2371             #[cfg(not(boringssl))]
2372             ffi::SSL_set_tmp_dh_callback__fixed_rust(self.as_ptr(), Some(raw_tmp_dh_ssl::<F>));
2373         }
2374     }
2375 
2376     /// Like [`SslContextBuilder::set_tmp_ecdh`].
2377     ///
2378     /// [`SslContextBuilder::set_tmp_ecdh`]: struct.SslContextBuilder.html#method.set_tmp_ecdh
2379     #[corresponds(SSL_set_tmp_ecdh)]
set_tmp_ecdh(&mut self, key: &EcKeyRef<Params>) -> Result<(), ErrorStack>2380     pub fn set_tmp_ecdh(&mut self, key: &EcKeyRef<Params>) -> Result<(), ErrorStack> {
2381         unsafe { cvt(ffi::SSL_set_tmp_ecdh(self.as_ptr(), key.as_ptr()) as c_int).map(|_| ()) }
2382     }
2383 
2384     /// Like [`SslContextBuilder::set_tmp_ecdh_callback`].
2385     ///
2386     /// Requires OpenSSL 1.0.1 or 1.0.2.
2387     #[corresponds(SSL_set_tmp_ecdh_callback)]
2388     #[cfg(any(all(ossl101, not(ossl110))))]
2389     #[deprecated(note = "this function leaks memory and does not exist on newer OpenSSL versions")]
set_tmp_ecdh_callback<F>(&mut self, callback: F) where F: Fn(&mut SslRef, bool, u32) -> Result<EcKey<Params>, ErrorStack> + 'static + Sync + Send,2390     pub fn set_tmp_ecdh_callback<F>(&mut self, callback: F)
2391     where
2392         F: Fn(&mut SslRef, bool, u32) -> Result<EcKey<Params>, ErrorStack> + 'static + Sync + Send,
2393     {
2394         unsafe {
2395             // this needs to be in an Arc since the callback can register a new callback!
2396             self.set_ex_data(Ssl::cached_ex_index(), Arc::new(callback));
2397             ffi::SSL_set_tmp_ecdh_callback__fixed_rust(self.as_ptr(), Some(raw_tmp_ecdh_ssl::<F>));
2398         }
2399     }
2400 
2401     /// Like [`SslContextBuilder::set_ecdh_auto`].
2402     ///
2403     /// Requires OpenSSL 1.0.2 or LibreSSL.
2404     ///
2405     /// [`SslContextBuilder::set_tmp_ecdh`]: struct.SslContextBuilder.html#method.set_tmp_ecdh
2406     #[corresponds(SSL_set_ecdh_auto)]
2407     #[cfg(any(all(ossl102, not(ossl110)), libressl))]
set_ecdh_auto(&mut self, onoff: bool) -> Result<(), ErrorStack>2408     pub fn set_ecdh_auto(&mut self, onoff: bool) -> Result<(), ErrorStack> {
2409         unsafe { cvt(ffi::SSL_set_ecdh_auto(self.as_ptr(), onoff as c_int)).map(|_| ()) }
2410     }
2411 
2412     /// Like [`SslContextBuilder::set_alpn_protos`].
2413     ///
2414     /// Requires OpenSSL 1.0.2 or LibreSSL 2.6.1 or newer.
2415     ///
2416     /// [`SslContextBuilder::set_alpn_protos`]: struct.SslContextBuilder.html#method.set_alpn_protos
2417     #[corresponds(SSL_set_alpn_protos)]
2418     #[cfg(any(ossl102, libressl261))]
set_alpn_protos(&mut self, protocols: &[u8]) -> Result<(), ErrorStack>2419     pub fn set_alpn_protos(&mut self, protocols: &[u8]) -> Result<(), ErrorStack> {
2420         unsafe {
2421             assert!(protocols.len() <= c_uint::max_value() as usize);
2422             let r = ffi::SSL_set_alpn_protos(
2423                 self.as_ptr(),
2424                 protocols.as_ptr(),
2425                 protocols.len() as c_uint,
2426             );
2427             // fun fact, SSL_set_alpn_protos has a reversed return code D:
2428             if r == 0 {
2429                 Ok(())
2430             } else {
2431                 Err(ErrorStack::get())
2432             }
2433         }
2434     }
2435 
2436     /// Returns the current cipher if the session is active.
2437     #[corresponds(SSL_get_current_cipher)]
current_cipher(&self) -> Option<&SslCipherRef>2438     pub fn current_cipher(&self) -> Option<&SslCipherRef> {
2439         unsafe {
2440             let ptr = ffi::SSL_get_current_cipher(self.as_ptr());
2441 
2442             SslCipherRef::from_const_ptr_opt(ptr)
2443         }
2444     }
2445 
2446     /// Returns a short string describing the state of the session.
2447     #[corresponds(SSL_state_string)]
state_string(&self) -> &'static str2448     pub fn state_string(&self) -> &'static str {
2449         let state = unsafe {
2450             let ptr = ffi::SSL_state_string(self.as_ptr());
2451             CStr::from_ptr(ptr as *const _)
2452         };
2453 
2454         str::from_utf8(state.to_bytes()).unwrap()
2455     }
2456 
2457     /// Returns a longer string describing the state of the session.
2458     #[corresponds(SSL_state_string_long)]
state_string_long(&self) -> &'static str2459     pub fn state_string_long(&self) -> &'static str {
2460         let state = unsafe {
2461             let ptr = ffi::SSL_state_string_long(self.as_ptr());
2462             CStr::from_ptr(ptr as *const _)
2463         };
2464 
2465         str::from_utf8(state.to_bytes()).unwrap()
2466     }
2467 
2468     /// Sets the host name to be sent to the server for Server Name Indication (SNI).
2469     ///
2470     /// It has no effect for a server-side connection.
2471     #[corresponds(SSL_set_tlsext_host_name)]
set_hostname(&mut self, hostname: &str) -> Result<(), ErrorStack>2472     pub fn set_hostname(&mut self, hostname: &str) -> Result<(), ErrorStack> {
2473         let cstr = CString::new(hostname).unwrap();
2474         unsafe {
2475             cvt(ffi::SSL_set_tlsext_host_name(self.as_ptr(), cstr.as_ptr() as *mut _) as c_int)
2476                 .map(|_| ())
2477         }
2478     }
2479 
2480     /// Returns the peer's certificate, if present.
2481     #[corresponds(SSL_get_peer_certificate)]
peer_certificate(&self) -> Option<X509>2482     pub fn peer_certificate(&self) -> Option<X509> {
2483         unsafe {
2484             let ptr = SSL_get1_peer_certificate(self.as_ptr());
2485             X509::from_ptr_opt(ptr)
2486         }
2487     }
2488 
2489     /// Returns the certificate chain of the peer, if present.
2490     ///
2491     /// On the client side, the chain includes the leaf certificate, but on the server side it does
2492     /// not. Fun!
2493     #[corresponds(SSL_get_peer_cert_chain)]
peer_cert_chain(&self) -> Option<&StackRef<X509>>2494     pub fn peer_cert_chain(&self) -> Option<&StackRef<X509>> {
2495         unsafe {
2496             let ptr = ffi::SSL_get_peer_cert_chain(self.as_ptr());
2497             StackRef::from_const_ptr_opt(ptr)
2498         }
2499     }
2500 
2501     /// Returns the verified certificate chain of the peer, including the leaf certificate.
2502     ///
2503     /// If verification was not successful (i.e. [`verify_result`] does not return
2504     /// [`X509VerifyResult::OK`]), this chain may be incomplete or invalid.
2505     ///
2506     /// Requires OpenSSL 1.1.0 or newer.
2507     ///
2508     /// [`verify_result`]: #method.verify_result
2509     /// [`X509VerifyResult::OK`]: ../x509/struct.X509VerifyResult.html#associatedconstant.OK
2510     #[corresponds(SSL_get0_verified_chain)]
2511     #[cfg(ossl110)]
verified_chain(&self) -> Option<&StackRef<X509>>2512     pub fn verified_chain(&self) -> Option<&StackRef<X509>> {
2513         unsafe {
2514             let ptr = ffi::SSL_get0_verified_chain(self.as_ptr());
2515             StackRef::from_const_ptr_opt(ptr)
2516         }
2517     }
2518 
2519     /// Like [`SslContext::certificate`].
2520     #[corresponds(SSL_get_certificate)]
certificate(&self) -> Option<&X509Ref>2521     pub fn certificate(&self) -> Option<&X509Ref> {
2522         unsafe {
2523             let ptr = ffi::SSL_get_certificate(self.as_ptr());
2524             X509Ref::from_const_ptr_opt(ptr)
2525         }
2526     }
2527 
2528     /// Like [`SslContext::private_key`].
2529     ///
2530     /// [`SslContext::private_key`]: struct.SslContext.html#method.private_key
2531     #[corresponds(SSL_get_privatekey)]
private_key(&self) -> Option<&PKeyRef<Private>>2532     pub fn private_key(&self) -> Option<&PKeyRef<Private>> {
2533         unsafe {
2534             let ptr = ffi::SSL_get_privatekey(self.as_ptr());
2535             PKeyRef::from_const_ptr_opt(ptr)
2536         }
2537     }
2538 
2539     #[deprecated(since = "0.10.5", note = "renamed to `version_str`")]
version(&self) -> &str2540     pub fn version(&self) -> &str {
2541         self.version_str()
2542     }
2543 
2544     /// Returns the protocol version of the session.
2545     #[corresponds(SSL_version)]
version2(&self) -> Option<SslVersion>2546     pub fn version2(&self) -> Option<SslVersion> {
2547         unsafe {
2548             let r = ffi::SSL_version(self.as_ptr());
2549             if r == 0 {
2550                 None
2551             } else {
2552                 Some(SslVersion(r))
2553             }
2554         }
2555     }
2556 
2557     /// Returns a string describing the protocol version of the session.
2558     #[corresponds(SSL_get_version)]
version_str(&self) -> &'static str2559     pub fn version_str(&self) -> &'static str {
2560         let version = unsafe {
2561             let ptr = ffi::SSL_get_version(self.as_ptr());
2562             CStr::from_ptr(ptr as *const _)
2563         };
2564 
2565         str::from_utf8(version.to_bytes()).unwrap()
2566     }
2567 
2568     /// Returns the protocol selected via Application Layer Protocol Negotiation (ALPN).
2569     ///
2570     /// The protocol's name is returned is an opaque sequence of bytes. It is up to the client
2571     /// to interpret it.
2572     ///
2573     /// Requires OpenSSL 1.0.2 or LibreSSL 2.6.1 or newer.
2574     #[corresponds(SSL_get0_alpn_selected)]
2575     #[cfg(any(ossl102, libressl261))]
selected_alpn_protocol(&self) -> Option<&[u8]>2576     pub fn selected_alpn_protocol(&self) -> Option<&[u8]> {
2577         unsafe {
2578             let mut data: *const c_uchar = ptr::null();
2579             let mut len: c_uint = 0;
2580             // Get the negotiated protocol from the SSL instance.
2581             // `data` will point at a `c_uchar` array; `len` will contain the length of this array.
2582             ffi::SSL_get0_alpn_selected(self.as_ptr(), &mut data, &mut len);
2583 
2584             if data.is_null() {
2585                 None
2586             } else {
2587                 Some(slice::from_raw_parts(data, len as usize))
2588             }
2589         }
2590     }
2591 
2592     /// Enables the DTLS extension "use_srtp" as defined in RFC5764.
2593     ///
2594     /// This corresponds to [`SSL_set_tlsext_use_srtp`].
2595     ///
2596     /// [`SSL_set_tlsext_use_srtp`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_tlsext_use_srtp.html
2597     #[corresponds(SSL_set_tlsext_use_srtp)]
set_tlsext_use_srtp(&mut self, protocols: &str) -> Result<(), ErrorStack>2598     pub fn set_tlsext_use_srtp(&mut self, protocols: &str) -> Result<(), ErrorStack> {
2599         unsafe {
2600             let cstr = CString::new(protocols).unwrap();
2601 
2602             let r = ffi::SSL_set_tlsext_use_srtp(self.as_ptr(), cstr.as_ptr());
2603             // fun fact, set_tlsext_use_srtp has a reversed return code D:
2604             if r == 0 {
2605                 Ok(())
2606             } else {
2607                 Err(ErrorStack::get())
2608             }
2609         }
2610     }
2611 
2612     /// Gets all SRTP profiles that are enabled for handshake via set_tlsext_use_srtp
2613     ///
2614     /// DTLS extension "use_srtp" as defined in RFC5764 has to be enabled.
2615     ///
2616     /// This corresponds to [`SSL_get_srtp_profiles`].
2617     ///
2618     /// [`SSL_get_srtp_profiles`]: https://www.openssl.org/docs/man1.1.1/man3/SSL_CTX_set_tlsext_use_srtp.html
2619     #[corresponds(SSL_get_srtp_profiles)]
srtp_profiles(&self) -> Option<&StackRef<SrtpProtectionProfile>>2620     pub fn srtp_profiles(&self) -> Option<&StackRef<SrtpProtectionProfile>> {
2621         unsafe {
2622             let chain = ffi::SSL_get_srtp_profiles(self.as_ptr());
2623 
2624             StackRef::from_const_ptr_opt(chain)
2625         }
2626     }
2627 
2628     /// Gets the SRTP profile selected by handshake.
2629     ///
2630     /// DTLS extension "use_srtp" as defined in RFC5764 has to be enabled.
2631     #[corresponds(SSL_get_selected_srtp_profile)]
selected_srtp_profile(&self) -> Option<&SrtpProtectionProfileRef>2632     pub fn selected_srtp_profile(&self) -> Option<&SrtpProtectionProfileRef> {
2633         unsafe {
2634             let profile = ffi::SSL_get_selected_srtp_profile(self.as_ptr());
2635 
2636             SrtpProtectionProfileRef::from_const_ptr_opt(profile)
2637         }
2638     }
2639 
2640     /// Returns the number of bytes remaining in the currently processed TLS record.
2641     ///
2642     /// If this is greater than 0, the next call to `read` will not call down to the underlying
2643     /// stream.
2644     #[corresponds(SSL_pending)]
pending(&self) -> usize2645     pub fn pending(&self) -> usize {
2646         unsafe { ffi::SSL_pending(self.as_ptr()) as usize }
2647     }
2648 
2649     /// Returns the servername sent by the client via Server Name Indication (SNI).
2650     ///
2651     /// It is only useful on the server side.
2652     ///
2653     /// # Note
2654     ///
2655     /// While the SNI specification requires that servernames be valid domain names (and therefore
2656     /// ASCII), OpenSSL does not enforce this restriction. If the servername provided by the client
2657     /// is not valid UTF-8, this function will return `None`. The `servername_raw` method returns
2658     /// the raw bytes and does not have this restriction.
2659     ///
2660     /// [`SSL_get_servername`]: https://www.openssl.org/docs/manmaster/man3/SSL_get_servername.html
2661     #[corresponds(SSL_get_servername)]
2662     // FIXME maybe rethink in 0.11?
servername(&self, type_: NameType) -> Option<&str>2663     pub fn servername(&self, type_: NameType) -> Option<&str> {
2664         self.servername_raw(type_)
2665             .and_then(|b| str::from_utf8(b).ok())
2666     }
2667 
2668     /// Returns the servername sent by the client via Server Name Indication (SNI).
2669     ///
2670     /// It is only useful on the server side.
2671     ///
2672     /// # Note
2673     ///
2674     /// Unlike `servername`, this method does not require the name be valid UTF-8.
2675     #[corresponds(SSL_get_servername)]
servername_raw(&self, type_: NameType) -> Option<&[u8]>2676     pub fn servername_raw(&self, type_: NameType) -> Option<&[u8]> {
2677         unsafe {
2678             let name = ffi::SSL_get_servername(self.as_ptr(), type_.0);
2679             if name.is_null() {
2680                 None
2681             } else {
2682                 Some(CStr::from_ptr(name as *const _).to_bytes())
2683             }
2684         }
2685     }
2686 
2687     /// Changes the context corresponding to the current connection.
2688     ///
2689     /// It is most commonly used in the Server Name Indication (SNI) callback.
2690     #[corresponds(SSL_set_SSL_CTX)]
set_ssl_context(&mut self, ctx: &SslContextRef) -> Result<(), ErrorStack>2691     pub fn set_ssl_context(&mut self, ctx: &SslContextRef) -> Result<(), ErrorStack> {
2692         unsafe { cvt_p(ffi::SSL_set_SSL_CTX(self.as_ptr(), ctx.as_ptr())).map(|_| ()) }
2693     }
2694 
2695     /// Returns the context corresponding to the current connection.
2696     #[corresponds(SSL_get_SSL_CTX)]
ssl_context(&self) -> &SslContextRef2697     pub fn ssl_context(&self) -> &SslContextRef {
2698         unsafe {
2699             let ssl_ctx = ffi::SSL_get_SSL_CTX(self.as_ptr());
2700             SslContextRef::from_ptr(ssl_ctx)
2701         }
2702     }
2703 
2704     /// Returns a mutable reference to the X509 verification configuration.
2705     ///
2706     /// Requires OpenSSL 1.0.2 or newer.
2707     #[corresponds(SSL_get0_param)]
2708     #[cfg(any(ossl102, libressl261))]
param_mut(&mut self) -> &mut X509VerifyParamRef2709     pub fn param_mut(&mut self) -> &mut X509VerifyParamRef {
2710         unsafe { X509VerifyParamRef::from_ptr_mut(ffi::SSL_get0_param(self.as_ptr())) }
2711     }
2712 
2713     /// Returns the certificate verification result.
2714     #[corresponds(SSL_get_verify_result)]
verify_result(&self) -> X509VerifyResult2715     pub fn verify_result(&self) -> X509VerifyResult {
2716         unsafe { X509VerifyResult::from_raw(ffi::SSL_get_verify_result(self.as_ptr()) as c_int) }
2717     }
2718 
2719     /// Returns a shared reference to the SSL session.
2720     #[corresponds(SSL_get_session)]
session(&self) -> Option<&SslSessionRef>2721     pub fn session(&self) -> Option<&SslSessionRef> {
2722         unsafe {
2723             let p = ffi::SSL_get_session(self.as_ptr());
2724             SslSessionRef::from_const_ptr_opt(p)
2725         }
2726     }
2727 
2728     /// Copies the `client_random` value sent by the client in the TLS handshake into a buffer.
2729     ///
2730     /// Returns the number of bytes copied, or if the buffer is empty, the size of the `client_random`
2731     /// value.
2732     ///
2733     /// Requires OpenSSL 1.1.0 or LibreSSL 2.7.0 or newer.
2734     #[corresponds(SSL_get_client_random)]
2735     #[cfg(any(ossl110, libressl270))]
client_random(&self, buf: &mut [u8]) -> usize2736     pub fn client_random(&self, buf: &mut [u8]) -> usize {
2737         unsafe {
2738             ffi::SSL_get_client_random(self.as_ptr(), buf.as_mut_ptr() as *mut c_uchar, buf.len())
2739         }
2740     }
2741 
2742     /// Copies the `server_random` value sent by the server in the TLS handshake into a buffer.
2743     ///
2744     /// Returns the number of bytes copied, or if the buffer is empty, the size of the `server_random`
2745     /// value.
2746     ///
2747     /// Requires OpenSSL 1.1.0 or LibreSSL 2.7.0 or newer.
2748     #[corresponds(SSL_get_server_random)]
2749     #[cfg(any(ossl110, libressl270))]
server_random(&self, buf: &mut [u8]) -> usize2750     pub fn server_random(&self, buf: &mut [u8]) -> usize {
2751         unsafe {
2752             ffi::SSL_get_server_random(self.as_ptr(), buf.as_mut_ptr() as *mut c_uchar, buf.len())
2753         }
2754     }
2755 
2756     /// Derives keying material for application use in accordance to RFC 5705.
2757     #[corresponds(SSL_export_keying_material)]
export_keying_material( &self, out: &mut [u8], label: &str, context: Option<&[u8]>, ) -> Result<(), ErrorStack>2758     pub fn export_keying_material(
2759         &self,
2760         out: &mut [u8],
2761         label: &str,
2762         context: Option<&[u8]>,
2763     ) -> Result<(), ErrorStack> {
2764         unsafe {
2765             let (context, contextlen, use_context) = match context {
2766                 Some(context) => (context.as_ptr() as *const c_uchar, context.len(), 1),
2767                 None => (ptr::null(), 0, 0),
2768             };
2769             cvt(ffi::SSL_export_keying_material(
2770                 self.as_ptr(),
2771                 out.as_mut_ptr() as *mut c_uchar,
2772                 out.len(),
2773                 label.as_ptr() as *const c_char,
2774                 label.len(),
2775                 context,
2776                 contextlen,
2777                 use_context,
2778             ))
2779             .map(|_| ())
2780         }
2781     }
2782 
2783     /// Derives keying material for application use in accordance to RFC 5705.
2784     ///
2785     /// This function is only usable with TLSv1.3, wherein there is no distinction between an empty context and no
2786     /// context. Therefore, unlike `export_keying_material`, `context` must always be supplied.
2787     ///
2788     /// Requires OpenSSL 1.1.1 or newer.
2789     #[corresponds(SSL_export_keying_material_early)]
2790     #[cfg(ossl111)]
export_keying_material_early( &self, out: &mut [u8], label: &str, context: &[u8], ) -> Result<(), ErrorStack>2791     pub fn export_keying_material_early(
2792         &self,
2793         out: &mut [u8],
2794         label: &str,
2795         context: &[u8],
2796     ) -> Result<(), ErrorStack> {
2797         unsafe {
2798             cvt(ffi::SSL_export_keying_material_early(
2799                 self.as_ptr(),
2800                 out.as_mut_ptr() as *mut c_uchar,
2801                 out.len(),
2802                 label.as_ptr() as *const c_char,
2803                 label.len(),
2804                 context.as_ptr() as *const c_uchar,
2805                 context.len(),
2806             ))
2807             .map(|_| ())
2808         }
2809     }
2810 
2811     /// Sets the session to be used.
2812     ///
2813     /// This should be called before the handshake to attempt to reuse a previously established
2814     /// session. If the server is not willing to reuse the session, a new one will be transparently
2815     /// negotiated.
2816     ///
2817     /// # Safety
2818     ///
2819     /// The caller of this method is responsible for ensuring that the session is associated
2820     /// with the same `SslContext` as this `Ssl`.
2821     #[corresponds(SSL_set_session)]
set_session(&mut self, session: &SslSessionRef) -> Result<(), ErrorStack>2822     pub unsafe fn set_session(&mut self, session: &SslSessionRef) -> Result<(), ErrorStack> {
2823         cvt(ffi::SSL_set_session(self.as_ptr(), session.as_ptr())).map(|_| ())
2824     }
2825 
2826     /// Determines if the session provided to `set_session` was successfully reused.
2827     #[corresponds(SSL_session_reused)]
session_reused(&self) -> bool2828     pub fn session_reused(&self) -> bool {
2829         unsafe { ffi::SSL_session_reused(self.as_ptr()) != 0 }
2830     }
2831 
2832     /// Sets the status response a client wishes the server to reply with.
2833     #[corresponds(SSL_set_tlsext_status_type)]
set_status_type(&mut self, type_: StatusType) -> Result<(), ErrorStack>2834     pub fn set_status_type(&mut self, type_: StatusType) -> Result<(), ErrorStack> {
2835         unsafe {
2836             cvt(ffi::SSL_set_tlsext_status_type(self.as_ptr(), type_.as_raw()) as c_int).map(|_| ())
2837         }
2838     }
2839 
2840     /// Determines if current session used Extended Master Secret
2841     ///
2842     /// Returns `None` if the handshake is still in-progress.
2843     #[corresponds(SSL_get_extms_support)]
2844     #[cfg(ossl110)]
extms_support(&self) -> Option<bool>2845     pub fn extms_support(&self) -> Option<bool> {
2846         unsafe {
2847             match ffi::SSL_get_extms_support(self.as_ptr()) {
2848                 -1 => None,
2849                 ret => Some(ret != 0),
2850             }
2851         }
2852     }
2853 
2854     /// Returns the server's OCSP response, if present.
2855     #[corresponds(SSL_get_tlsext_status_ocsp_resp)]
2856     #[cfg(not(boringssl))]
ocsp_status(&self) -> Option<&[u8]>2857     pub fn ocsp_status(&self) -> Option<&[u8]> {
2858         unsafe {
2859             let mut p = ptr::null_mut();
2860             let len = ffi::SSL_get_tlsext_status_ocsp_resp(self.as_ptr(), &mut p);
2861 
2862             if len < 0 {
2863                 None
2864             } else {
2865                 Some(slice::from_raw_parts(p as *const u8, len as usize))
2866             }
2867         }
2868     }
2869 
2870     /// Sets the OCSP response to be returned to the client.
2871     #[corresponds(SSL_set_tlsext_status_oscp_resp)]
2872     #[cfg(not(boringssl))]
set_ocsp_status(&mut self, response: &[u8]) -> Result<(), ErrorStack>2873     pub fn set_ocsp_status(&mut self, response: &[u8]) -> Result<(), ErrorStack> {
2874         unsafe {
2875             assert!(response.len() <= c_int::max_value() as usize);
2876             let p = cvt_p(ffi::OPENSSL_malloc(response.len() as _))?;
2877             ptr::copy_nonoverlapping(response.as_ptr(), p as *mut u8, response.len());
2878             cvt(ffi::SSL_set_tlsext_status_ocsp_resp(
2879                 self.as_ptr(),
2880                 p as *mut c_uchar,
2881                 response.len() as c_long,
2882             ) as c_int)
2883             .map(|_| ())
2884             .map_err(|e| {
2885                 ffi::OPENSSL_free(p);
2886                 e
2887             })
2888         }
2889     }
2890 
2891     /// Determines if this `Ssl` is configured for server-side or client-side use.
2892     #[corresponds(SSL_is_server)]
is_server(&self) -> bool2893     pub fn is_server(&self) -> bool {
2894         unsafe { SSL_is_server(self.as_ptr()) != 0 }
2895     }
2896 
2897     /// Sets the extra data at the specified index.
2898     ///
2899     /// This can be used to provide data to callbacks registered with the context. Use the
2900     /// `Ssl::new_ex_index` method to create an `Index`.
2901     #[corresponds(SSL_set_ex_data)]
set_ex_data<T>(&mut self, index: Index<Ssl, T>, data: T)2902     pub fn set_ex_data<T>(&mut self, index: Index<Ssl, T>, data: T) {
2903         unsafe {
2904             let data = Box::new(data);
2905             ffi::SSL_set_ex_data(
2906                 self.as_ptr(),
2907                 index.as_raw(),
2908                 Box::into_raw(data) as *mut c_void,
2909             );
2910         }
2911     }
2912 
2913     /// Returns a reference to the extra data at the specified index.
2914     #[corresponds(SSL_get_ex_data)]
ex_data<T>(&self, index: Index<Ssl, T>) -> Option<&T>2915     pub fn ex_data<T>(&self, index: Index<Ssl, T>) -> Option<&T> {
2916         unsafe {
2917             let data = ffi::SSL_get_ex_data(self.as_ptr(), index.as_raw());
2918             if data.is_null() {
2919                 None
2920             } else {
2921                 Some(&*(data as *const T))
2922             }
2923         }
2924     }
2925 
2926     /// Returns a mutable reference to the extra data at the specified index.
2927     #[corresponds(SSL_get_ex_data)]
ex_data_mut<T>(&mut self, index: Index<Ssl, T>) -> Option<&mut T>2928     pub fn ex_data_mut<T>(&mut self, index: Index<Ssl, T>) -> Option<&mut T> {
2929         unsafe {
2930             let data = ffi::SSL_get_ex_data(self.as_ptr(), index.as_raw());
2931             if data.is_null() {
2932                 None
2933             } else {
2934                 Some(&mut *(data as *mut T))
2935             }
2936         }
2937     }
2938 
2939     /// Sets the maximum amount of early data that will be accepted on this connection.
2940     ///
2941     /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer.
2942     #[corresponds(SSL_set_max_early_data)]
2943     #[cfg(any(ossl111, libressl340))]
set_max_early_data(&mut self, bytes: u32) -> Result<(), ErrorStack>2944     pub fn set_max_early_data(&mut self, bytes: u32) -> Result<(), ErrorStack> {
2945         if unsafe { ffi::SSL_set_max_early_data(self.as_ptr(), bytes) } == 1 {
2946             Ok(())
2947         } else {
2948             Err(ErrorStack::get())
2949         }
2950     }
2951 
2952     /// Gets the maximum amount of early data that can be sent on this connection.
2953     ///
2954     /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer.
2955     #[corresponds(SSL_get_max_early_data)]
2956     #[cfg(any(ossl111, libressl340))]
max_early_data(&self) -> u322957     pub fn max_early_data(&self) -> u32 {
2958         unsafe { ffi::SSL_get_max_early_data(self.as_ptr()) }
2959     }
2960 
2961     /// Copies the contents of the last Finished message sent to the peer into the provided buffer.
2962     ///
2963     /// The total size of the message is returned, so this can be used to determine the size of the
2964     /// buffer required.
2965     #[corresponds(SSL_get_finished)]
finished(&self, buf: &mut [u8]) -> usize2966     pub fn finished(&self, buf: &mut [u8]) -> usize {
2967         unsafe { ffi::SSL_get_finished(self.as_ptr(), buf.as_mut_ptr() as *mut c_void, buf.len()) }
2968     }
2969 
2970     /// Copies the contents of the last Finished message received from the peer into the provided
2971     /// buffer.
2972     ///
2973     /// The total size of the message is returned, so this can be used to determine the size of the
2974     /// buffer required.
2975     #[corresponds(SSL_get_peer_finished)]
peer_finished(&self, buf: &mut [u8]) -> usize2976     pub fn peer_finished(&self, buf: &mut [u8]) -> usize {
2977         unsafe {
2978             ffi::SSL_get_peer_finished(self.as_ptr(), buf.as_mut_ptr() as *mut c_void, buf.len())
2979         }
2980     }
2981 
2982     /// Determines if the initial handshake has been completed.
2983     #[corresponds(SSL_is_init_finished)]
2984     #[cfg(ossl110)]
is_init_finished(&self) -> bool2985     pub fn is_init_finished(&self) -> bool {
2986         unsafe { ffi::SSL_is_init_finished(self.as_ptr()) != 0 }
2987     }
2988 
2989     /// Determines if the client's hello message is in the SSLv2 format.
2990     ///
2991     /// This can only be used inside of the client hello callback. Otherwise, `false` is returned.
2992     ///
2993     /// Requires OpenSSL 1.1.1 or newer.
2994     #[corresponds(SSL_client_hello_isv2)]
2995     #[cfg(ossl111)]
client_hello_isv2(&self) -> bool2996     pub fn client_hello_isv2(&self) -> bool {
2997         unsafe { ffi::SSL_client_hello_isv2(self.as_ptr()) != 0 }
2998     }
2999 
3000     /// Returns the legacy version field of the client's hello message.
3001     ///
3002     /// This can only be used inside of the client hello callback. Otherwise, `None` is returned.
3003     ///
3004     /// Requires OpenSSL 1.1.1 or newer.
3005     #[corresponds(SSL_client_hello_get0_legacy_version)]
3006     #[cfg(ossl111)]
client_hello_legacy_version(&self) -> Option<SslVersion>3007     pub fn client_hello_legacy_version(&self) -> Option<SslVersion> {
3008         unsafe {
3009             let version = ffi::SSL_client_hello_get0_legacy_version(self.as_ptr());
3010             if version == 0 {
3011                 None
3012             } else {
3013                 Some(SslVersion(version as c_int))
3014             }
3015         }
3016     }
3017 
3018     /// Returns the random field of the client's hello message.
3019     ///
3020     /// This can only be used inside of the client hello callback. Otherwise, `None` is returned.
3021     ///
3022     /// Requires OpenSSL 1.1.1 or newer.
3023     #[corresponds(SSL_client_hello_get0_random)]
3024     #[cfg(ossl111)]
client_hello_random(&self) -> Option<&[u8]>3025     pub fn client_hello_random(&self) -> Option<&[u8]> {
3026         unsafe {
3027             let mut ptr = ptr::null();
3028             let len = ffi::SSL_client_hello_get0_random(self.as_ptr(), &mut ptr);
3029             if len == 0 {
3030                 None
3031             } else {
3032                 Some(slice::from_raw_parts(ptr, len))
3033             }
3034         }
3035     }
3036 
3037     /// Returns the session ID field of the client's hello message.
3038     ///
3039     /// This can only be used inside of the client hello callback. Otherwise, `None` is returned.
3040     ///
3041     /// Requires OpenSSL 1.1.1 or newer.
3042     #[corresponds(SSL_client_hello_get0_session_id)]
3043     #[cfg(ossl111)]
client_hello_session_id(&self) -> Option<&[u8]>3044     pub fn client_hello_session_id(&self) -> Option<&[u8]> {
3045         unsafe {
3046             let mut ptr = ptr::null();
3047             let len = ffi::SSL_client_hello_get0_session_id(self.as_ptr(), &mut ptr);
3048             if len == 0 {
3049                 None
3050             } else {
3051                 Some(slice::from_raw_parts(ptr, len))
3052             }
3053         }
3054     }
3055 
3056     /// Returns the ciphers field of the client's hello message.
3057     ///
3058     /// This can only be used inside of the client hello callback. Otherwise, `None` is returned.
3059     ///
3060     /// Requires OpenSSL 1.1.1 or newer.
3061     #[corresponds(SSL_client_hello_get0_ciphers)]
3062     #[cfg(ossl111)]
client_hello_ciphers(&self) -> Option<&[u8]>3063     pub fn client_hello_ciphers(&self) -> Option<&[u8]> {
3064         unsafe {
3065             let mut ptr = ptr::null();
3066             let len = ffi::SSL_client_hello_get0_ciphers(self.as_ptr(), &mut ptr);
3067             if len == 0 {
3068                 None
3069             } else {
3070                 Some(slice::from_raw_parts(ptr, len))
3071             }
3072         }
3073     }
3074 
3075     /// Returns the compression methods field of the client's hello message.
3076     ///
3077     /// This can only be used inside of the client hello callback. Otherwise, `None` is returned.
3078     ///
3079     /// Requires OpenSSL 1.1.1 or newer.
3080     #[corresponds(SSL_client_hello_get0_compression_methods)]
3081     #[cfg(ossl111)]
client_hello_compression_methods(&self) -> Option<&[u8]>3082     pub fn client_hello_compression_methods(&self) -> Option<&[u8]> {
3083         unsafe {
3084             let mut ptr = ptr::null();
3085             let len = ffi::SSL_client_hello_get0_compression_methods(self.as_ptr(), &mut ptr);
3086             if len == 0 {
3087                 None
3088             } else {
3089                 Some(slice::from_raw_parts(ptr, len))
3090             }
3091         }
3092     }
3093 
3094     /// Sets the MTU used for DTLS connections.
3095     #[corresponds(SSL_set_mtu)]
set_mtu(&mut self, mtu: u32) -> Result<(), ErrorStack>3096     pub fn set_mtu(&mut self, mtu: u32) -> Result<(), ErrorStack> {
3097         unsafe { cvt(ffi::SSL_set_mtu(self.as_ptr(), mtu as MtuTy) as c_int).map(|_| ()) }
3098     }
3099 
3100     /// Returns the PSK identity hint used during connection setup.
3101     ///
3102     /// May return `None` if no PSK identity hint was used during the connection setup.
3103     #[corresponds(SSL_get_psk_identity_hint)]
3104     #[cfg(not(osslconf = "OPENSSL_NO_PSK"))]
psk_identity_hint(&self) -> Option<&[u8]>3105     pub fn psk_identity_hint(&self) -> Option<&[u8]> {
3106         unsafe {
3107             let ptr = ffi::SSL_get_psk_identity_hint(self.as_ptr());
3108             if ptr.is_null() {
3109                 None
3110             } else {
3111                 Some(CStr::from_ptr(ptr).to_bytes())
3112             }
3113         }
3114     }
3115 
3116     /// Returns the PSK identity used during connection setup.
3117     #[corresponds(SSL_get_psk_identity)]
3118     #[cfg(not(osslconf = "OPENSSL_NO_PSK"))]
psk_identity(&self) -> Option<&[u8]>3119     pub fn psk_identity(&self) -> Option<&[u8]> {
3120         unsafe {
3121             let ptr = ffi::SSL_get_psk_identity(self.as_ptr());
3122             if ptr.is_null() {
3123                 None
3124             } else {
3125                 Some(CStr::from_ptr(ptr).to_bytes())
3126             }
3127         }
3128     }
3129 
3130     #[corresponds(SSL_add0_chain_cert)]
3131     #[cfg(ossl102)]
add_chain_cert(&mut self, chain: X509) -> Result<(), ErrorStack>3132     pub fn add_chain_cert(&mut self, chain: X509) -> Result<(), ErrorStack> {
3133         unsafe {
3134             cvt(ffi::SSL_add0_chain_cert(self.as_ptr(), chain.as_ptr()) as c_int).map(|_| ())?;
3135             mem::forget(chain);
3136         }
3137         Ok(())
3138     }
3139 
3140     /// Sets a new default TLS/SSL method for SSL objects
3141     #[cfg(not(boringssl))]
set_method(&mut self, method: SslMethod) -> Result<(), ErrorStack>3142     pub fn set_method(&mut self, method: SslMethod) -> Result<(), ErrorStack> {
3143         unsafe {
3144             cvt(ffi::SSL_set_ssl_method(self.as_ptr(), method.as_ptr()))?;
3145         };
3146         Ok(())
3147     }
3148 
3149     /// Loads the private key from a file.
3150     #[corresponds(SSL_use_Private_Key_file)]
set_private_key_file<P: AsRef<Path>>( &mut self, path: P, ssl_file_type: SslFiletype, ) -> Result<(), ErrorStack>3151     pub fn set_private_key_file<P: AsRef<Path>>(
3152         &mut self,
3153         path: P,
3154         ssl_file_type: SslFiletype,
3155     ) -> Result<(), ErrorStack> {
3156         let p = path.as_ref().as_os_str().to_str().unwrap();
3157         let key_file = CString::new(p).unwrap();
3158         unsafe {
3159             cvt(ffi::SSL_use_PrivateKey_file(
3160                 self.as_ptr(),
3161                 key_file.as_ptr(),
3162                 ssl_file_type.as_raw(),
3163             ))?;
3164         };
3165         Ok(())
3166     }
3167 
3168     /// Sets the private key.
3169     #[corresponds(SSL_use_PrivateKey)]
set_private_key(&mut self, pkey: &PKeyRef<Private>) -> Result<(), ErrorStack>3170     pub fn set_private_key(&mut self, pkey: &PKeyRef<Private>) -> Result<(), ErrorStack> {
3171         unsafe {
3172             cvt(ffi::SSL_use_PrivateKey(self.as_ptr(), pkey.as_ptr()))?;
3173         };
3174         Ok(())
3175     }
3176 
3177     /// Sets the certificate
3178     #[corresponds(SSL_use_certificate)]
set_certificate(&mut self, cert: &X509Ref) -> Result<(), ErrorStack>3179     pub fn set_certificate(&mut self, cert: &X509Ref) -> Result<(), ErrorStack> {
3180         unsafe {
3181             cvt(ffi::SSL_use_certificate(self.as_ptr(), cert.as_ptr()))?;
3182         };
3183         Ok(())
3184     }
3185 
3186     /// Loads a certificate chain from a file.
3187     ///
3188     /// The file should contain a sequence of PEM-formatted certificates, the first being the leaf
3189     /// certificate, and the remainder forming the chain of certificates up to and including the
3190     /// trusted root certificate.
3191     #[corresponds(SSL_use_certificate_chain_file)]
3192     #[cfg(any(ossl110, libressl332))]
set_certificate_chain_file<P: AsRef<Path>>( &mut self, path: P, ) -> Result<(), ErrorStack>3193     pub fn set_certificate_chain_file<P: AsRef<Path>>(
3194         &mut self,
3195         path: P,
3196     ) -> Result<(), ErrorStack> {
3197         let p = path.as_ref().as_os_str().to_str().unwrap();
3198         let cert_file = CString::new(p).unwrap();
3199         unsafe {
3200             cvt(ffi::SSL_use_certificate_chain_file(
3201                 self.as_ptr(),
3202                 cert_file.as_ptr(),
3203             ))?;
3204         };
3205         Ok(())
3206     }
3207 
3208     /// Sets ca certificate that client trusted
3209     #[corresponds(SSL_add_client_CA)]
add_client_ca(&mut self, cacert: &X509Ref) -> Result<(), ErrorStack>3210     pub fn add_client_ca(&mut self, cacert: &X509Ref) -> Result<(), ErrorStack> {
3211         unsafe {
3212             cvt(ffi::SSL_add_client_CA(self.as_ptr(), cacert.as_ptr()))?;
3213         };
3214         Ok(())
3215     }
3216 
3217     // Sets the list of CAs sent to the client when requesting a client certificate for the chosen ssl
3218     #[corresponds(SSL_set_client_CA_list)]
set_client_ca_list(&mut self, list: Stack<X509Name>)3219     pub fn set_client_ca_list(&mut self, list: Stack<X509Name>) {
3220         unsafe { ffi::SSL_set_client_CA_list(self.as_ptr(), list.as_ptr()) }
3221         mem::forget(list);
3222     }
3223 
3224     /// Sets the minimum supported protocol version.
3225     ///
3226     /// A value of `None` will enable protocol versions down the the lowest version supported by
3227     /// OpenSSL.
3228     ///
3229     /// Requires OpenSSL 1.1.0 or LibreSSL 2.6.1 or newer.
3230     #[corresponds(SSL_set_min_proto_version)]
3231     #[cfg(any(ossl110, libressl261))]
set_min_proto_version(&mut self, version: Option<SslVersion>) -> Result<(), ErrorStack>3232     pub fn set_min_proto_version(&mut self, version: Option<SslVersion>) -> Result<(), ErrorStack> {
3233         unsafe {
3234             cvt(ffi::SSL_set_min_proto_version(
3235                 self.as_ptr(),
3236                 version.map_or(0, |v| v.0 as _),
3237             ))
3238             .map(|_| ())
3239         }
3240     }
3241 
3242     /// Sets the maximum supported protocol version.
3243     ///
3244     /// A value of `None` will enable protocol versions down the the highest version supported by
3245     /// OpenSSL.
3246     ///
3247     /// Requires OpenSSL 1.1.0 or or LibreSSL 2.6.1 or newer.
3248     #[corresponds(SSL_set_max_proto_version)]
3249     #[cfg(any(ossl110, libressl261))]
set_max_proto_version(&mut self, version: Option<SslVersion>) -> Result<(), ErrorStack>3250     pub fn set_max_proto_version(&mut self, version: Option<SslVersion>) -> Result<(), ErrorStack> {
3251         unsafe {
3252             cvt(ffi::SSL_set_max_proto_version(
3253                 self.as_ptr(),
3254                 version.map_or(0, |v| v.0 as _),
3255             ))
3256             .map(|_| ())
3257         }
3258     }
3259 
3260     /// Sets the list of supported ciphers for the TLSv1.3 protocol.
3261     ///
3262     /// The `set_cipher_list` method controls the cipher suites for protocols before TLSv1.3.
3263     ///
3264     /// The format consists of TLSv1.3 cipher suite names separated by `:` characters in order of
3265     /// preference.
3266     ///
3267     /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer.
3268     #[corresponds(SSL_set_ciphersuites)]
3269     #[cfg(any(ossl111, libressl340))]
set_ciphersuites(&mut self, cipher_list: &str) -> Result<(), ErrorStack>3270     pub fn set_ciphersuites(&mut self, cipher_list: &str) -> Result<(), ErrorStack> {
3271         let cipher_list = CString::new(cipher_list).unwrap();
3272         unsafe {
3273             cvt(ffi::SSL_set_ciphersuites(
3274                 self.as_ptr(),
3275                 cipher_list.as_ptr() as *const _,
3276             ))
3277             .map(|_| ())
3278         }
3279     }
3280 
3281     /// Sets the list of supported ciphers for protocols before TLSv1.3.
3282     ///
3283     /// The `set_ciphersuites` method controls the cipher suites for TLSv1.3.
3284     ///
3285     /// See [`ciphers`] for details on the format.
3286     ///
3287     /// [`ciphers`]: https://www.openssl.org/docs/manmaster/apps/ciphers.html
3288     #[corresponds(SSL_set_cipher_list)]
set_cipher_list(&mut self, cipher_list: &str) -> Result<(), ErrorStack>3289     pub fn set_cipher_list(&mut self, cipher_list: &str) -> Result<(), ErrorStack> {
3290         let cipher_list = CString::new(cipher_list).unwrap();
3291         unsafe {
3292             cvt(ffi::SSL_set_cipher_list(
3293                 self.as_ptr(),
3294                 cipher_list.as_ptr() as *const _,
3295             ))
3296             .map(|_| ())
3297         }
3298     }
3299 
3300     /// Set the certificate store used for certificate verification
3301     #[corresponds(SSL_set_cert_store)]
3302     #[cfg(ossl102)]
set_verify_cert_store(&mut self, cert_store: X509Store) -> Result<(), ErrorStack>3303     pub fn set_verify_cert_store(&mut self, cert_store: X509Store) -> Result<(), ErrorStack> {
3304         unsafe {
3305             cvt(ffi::SSL_set0_verify_cert_store(self.as_ptr(), cert_store.as_ptr()) as c_int)?;
3306             mem::forget(cert_store);
3307             Ok(())
3308         }
3309     }
3310 
3311     /// Sets the number of TLS 1.3 session tickets that will be sent to a client after a full
3312     /// handshake.
3313     ///
3314     /// Requires OpenSSL 1.1.1 or newer.
3315     #[corresponds(SSL_set_num_tickets)]
3316     #[cfg(ossl111)]
set_num_tickets(&mut self, num_tickets: usize) -> Result<(), ErrorStack>3317     pub fn set_num_tickets(&mut self, num_tickets: usize) -> Result<(), ErrorStack> {
3318         unsafe { cvt(ffi::SSL_set_num_tickets(self.as_ptr(), num_tickets)).map(|_| ()) }
3319     }
3320 
3321     /// Gets the number of TLS 1.3 session tickets that will be sent to a client after a full
3322     /// handshake.
3323     ///
3324     /// Requires OpenSSL 1.1.1 or newer.
3325     #[corresponds(SSL_get_num_tickets)]
3326     #[cfg(ossl111)]
num_tickets(&self) -> usize3327     pub fn num_tickets(&self) -> usize {
3328         unsafe { ffi::SSL_get_num_tickets(self.as_ptr()) }
3329     }
3330 }
3331 
3332 /// An SSL stream midway through the handshake process.
3333 #[derive(Debug)]
3334 pub struct MidHandshakeSslStream<S> {
3335     stream: SslStream<S>,
3336     error: Error,
3337 }
3338 
3339 impl<S> MidHandshakeSslStream<S> {
3340     /// Returns a shared reference to the inner stream.
get_ref(&self) -> &S3341     pub fn get_ref(&self) -> &S {
3342         self.stream.get_ref()
3343     }
3344 
3345     /// Returns a mutable reference to the inner stream.
get_mut(&mut self) -> &mut S3346     pub fn get_mut(&mut self) -> &mut S {
3347         self.stream.get_mut()
3348     }
3349 
3350     /// Returns a shared reference to the `Ssl` of the stream.
ssl(&self) -> &SslRef3351     pub fn ssl(&self) -> &SslRef {
3352         self.stream.ssl()
3353     }
3354 
3355     /// Returns the underlying error which interrupted this handshake.
error(&self) -> &Error3356     pub fn error(&self) -> &Error {
3357         &self.error
3358     }
3359 
3360     /// Consumes `self`, returning its error.
into_error(self) -> Error3361     pub fn into_error(self) -> Error {
3362         self.error
3363     }
3364 }
3365 
3366 impl<S> MidHandshakeSslStream<S>
3367 where
3368     S: Read + Write,
3369 {
3370     /// Restarts the handshake process.
3371     ///
3372     /// This corresponds to [`SSL_do_handshake`].
3373     ///
3374     /// [`SSL_do_handshake`]: https://www.openssl.org/docs/manmaster/man3/SSL_do_handshake.html
handshake(mut self) -> Result<SslStream<S>, HandshakeError<S>>3375     pub fn handshake(mut self) -> Result<SslStream<S>, HandshakeError<S>> {
3376         match self.stream.do_handshake() {
3377             Ok(()) => Ok(self.stream),
3378             Err(error) => {
3379                 self.error = error;
3380                 match self.error.code() {
3381                     ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => {
3382                         Err(HandshakeError::WouldBlock(self))
3383                     }
3384                     _ => Err(HandshakeError::Failure(self)),
3385                 }
3386             }
3387         }
3388     }
3389 }
3390 
3391 /// A TLS session over a stream.
3392 pub struct SslStream<S> {
3393     ssl: ManuallyDrop<Ssl>,
3394     method: ManuallyDrop<BioMethod>,
3395     _p: PhantomData<S>,
3396 }
3397 
3398 impl<S> Drop for SslStream<S> {
drop(&mut self)3399     fn drop(&mut self) {
3400         // ssl holds a reference to method internally so it has to drop first
3401         unsafe {
3402             ManuallyDrop::drop(&mut self.ssl);
3403             ManuallyDrop::drop(&mut self.method);
3404         }
3405     }
3406 }
3407 
3408 impl<S> fmt::Debug for SslStream<S>
3409 where
3410     S: fmt::Debug,
3411 {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result3412     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
3413         fmt.debug_struct("SslStream")
3414             .field("stream", &self.get_ref())
3415             .field("ssl", &self.ssl())
3416             .finish()
3417     }
3418 }
3419 
3420 impl<S: Read + Write> SslStream<S> {
3421     /// Creates a new `SslStream`.
3422     ///
3423     /// This function performs no IO; the stream will not have performed any part of the handshake
3424     /// with the peer. If the `Ssl` was configured with [`SslRef::set_connect_state`] or
3425     /// [`SslRef::set_accept_state`], the handshake can be performed automatically during the first
3426     /// call to read or write. Otherwise the `connect` and `accept` methods can be used to
3427     /// explicitly perform the handshake.
3428     #[corresponds(SSL_set_bio)]
new(ssl: Ssl, stream: S) -> Result<Self, ErrorStack>3429     pub fn new(ssl: Ssl, stream: S) -> Result<Self, ErrorStack> {
3430         let (bio, method) = bio::new(stream)?;
3431         unsafe {
3432             ffi::SSL_set_bio(ssl.as_ptr(), bio, bio);
3433         }
3434 
3435         Ok(SslStream {
3436             ssl: ManuallyDrop::new(ssl),
3437             method: ManuallyDrop::new(method),
3438             _p: PhantomData,
3439         })
3440     }
3441 
3442     /// Constructs an `SslStream` from a pointer to the underlying OpenSSL `SSL` struct.
3443     ///
3444     /// This is useful if the handshake has already been completed elsewhere.
3445     ///
3446     /// # Safety
3447     ///
3448     /// The caller must ensure the pointer is valid.
3449     #[deprecated(
3450         since = "0.10.32",
3451         note = "use Ssl::from_ptr and SslStream::new instead"
3452     )]
from_raw_parts(ssl: *mut ffi::SSL, stream: S) -> Self3453     pub unsafe fn from_raw_parts(ssl: *mut ffi::SSL, stream: S) -> Self {
3454         let ssl = Ssl::from_ptr(ssl);
3455         Self::new(ssl, stream).unwrap()
3456     }
3457 
3458     /// Read application data transmitted by a client before handshake completion.
3459     ///
3460     /// Useful for reducing latency, but vulnerable to replay attacks. Call
3461     /// [`SslRef::set_accept_state`] first.
3462     ///
3463     /// Returns `Ok(0)` if all early data has been read.
3464     ///
3465     /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer.
3466     #[corresponds(SSL_read_early_data)]
3467     #[cfg(any(ossl111, libressl340))]
read_early_data(&mut self, buf: &mut [u8]) -> Result<usize, Error>3468     pub fn read_early_data(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
3469         let mut read = 0;
3470         let ret = unsafe {
3471             ffi::SSL_read_early_data(
3472                 self.ssl.as_ptr(),
3473                 buf.as_ptr() as *mut c_void,
3474                 buf.len(),
3475                 &mut read,
3476             )
3477         };
3478         match ret {
3479             ffi::SSL_READ_EARLY_DATA_ERROR => Err(self.make_error(ret)),
3480             ffi::SSL_READ_EARLY_DATA_SUCCESS => Ok(read),
3481             ffi::SSL_READ_EARLY_DATA_FINISH => Ok(0),
3482             _ => unreachable!(),
3483         }
3484     }
3485 
3486     /// Send data to the server without blocking on handshake completion.
3487     ///
3488     /// Useful for reducing latency, but vulnerable to replay attacks. Call
3489     /// [`SslRef::set_connect_state`] first.
3490     ///
3491     /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer.
3492     #[corresponds(SSL_write_early_data)]
3493     #[cfg(any(ossl111, libressl340))]
write_early_data(&mut self, buf: &[u8]) -> Result<usize, Error>3494     pub fn write_early_data(&mut self, buf: &[u8]) -> Result<usize, Error> {
3495         let mut written = 0;
3496         let ret = unsafe {
3497             ffi::SSL_write_early_data(
3498                 self.ssl.as_ptr(),
3499                 buf.as_ptr() as *const c_void,
3500                 buf.len(),
3501                 &mut written,
3502             )
3503         };
3504         if ret > 0 {
3505             Ok(written)
3506         } else {
3507             Err(self.make_error(ret))
3508         }
3509     }
3510 
3511     /// Initiates a client-side TLS handshake.
3512     ///
3513     /// # Warning
3514     ///
3515     /// OpenSSL's default configuration is insecure. It is highly recommended to use
3516     /// `SslConnector` rather than `Ssl` directly, as it manages that configuration.
3517     #[corresponds(SSL_connect)]
connect(&mut self) -> Result<(), Error>3518     pub fn connect(&mut self) -> Result<(), Error> {
3519         let ret = unsafe { ffi::SSL_connect(self.ssl.as_ptr()) };
3520         if ret > 0 {
3521             Ok(())
3522         } else {
3523             Err(self.make_error(ret))
3524         }
3525     }
3526 
3527     /// Initiates a server-side TLS handshake.
3528     ///
3529     /// # Warning
3530     ///
3531     /// OpenSSL's default configuration is insecure. It is highly recommended to use
3532     /// `SslAcceptor` rather than `Ssl` directly, as it manages that configuration.
3533     #[corresponds(SSL_accept)]
accept(&mut self) -> Result<(), Error>3534     pub fn accept(&mut self) -> Result<(), Error> {
3535         let ret = unsafe { ffi::SSL_accept(self.ssl.as_ptr()) };
3536         if ret > 0 {
3537             Ok(())
3538         } else {
3539             Err(self.make_error(ret))
3540         }
3541     }
3542 
3543     /// Initiates the handshake.
3544     ///
3545     /// This will fail if `set_accept_state` or `set_connect_state` was not called first.
3546     #[corresponds(SSL_do_handshake)]
do_handshake(&mut self) -> Result<(), Error>3547     pub fn do_handshake(&mut self) -> Result<(), Error> {
3548         let ret = unsafe { ffi::SSL_do_handshake(self.ssl.as_ptr()) };
3549         if ret > 0 {
3550             Ok(())
3551         } else {
3552             Err(self.make_error(ret))
3553         }
3554     }
3555 
3556     /// Perform a stateless server-side handshake.
3557     ///
3558     /// Requires that cookie generation and verification callbacks were
3559     /// set on the SSL context.
3560     ///
3561     /// Returns `Ok(true)` if a complete ClientHello containing a valid cookie
3562     /// was read, in which case the handshake should be continued via
3563     /// `accept`. If a HelloRetryRequest containing a fresh cookie was
3564     /// transmitted, `Ok(false)` is returned instead. If the handshake cannot
3565     /// proceed at all, `Err` is returned.
3566     #[corresponds(SSL_stateless)]
3567     #[cfg(ossl111)]
stateless(&mut self) -> Result<bool, ErrorStack>3568     pub fn stateless(&mut self) -> Result<bool, ErrorStack> {
3569         match unsafe { ffi::SSL_stateless(self.ssl.as_ptr()) } {
3570             1 => Ok(true),
3571             0 => Ok(false),
3572             -1 => Err(ErrorStack::get()),
3573             _ => unreachable!(),
3574         }
3575     }
3576 
3577     /// Like `read`, but returns an `ssl::Error` rather than an `io::Error`.
3578     ///
3579     /// It is particularly useful with a non-blocking socket, where the error value will identify if
3580     /// OpenSSL is waiting on read or write readiness.
3581     #[corresponds(SSL_read)]
ssl_read(&mut self, buf: &mut [u8]) -> Result<usize, Error>3582     pub fn ssl_read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
3583         // The interpretation of the return code here is a little odd with a
3584         // zero-length write. OpenSSL will likely correctly report back to us
3585         // that it read zero bytes, but zero is also the sentinel for "error".
3586         // To avoid that confusion short-circuit that logic and return quickly
3587         // if `buf` has a length of zero.
3588         if buf.is_empty() {
3589             return Ok(0);
3590         }
3591 
3592         let ret = self.ssl.read(buf);
3593         if ret > 0 {
3594             Ok(ret as usize)
3595         } else {
3596             Err(self.make_error(ret))
3597         }
3598     }
3599 
3600     /// Like `write`, but returns an `ssl::Error` rather than an `io::Error`.
3601     ///
3602     /// It is particularly useful with a non-blocking socket, where the error value will identify if
3603     /// OpenSSL is waiting on read or write readiness.
3604     #[corresponds(SSL_write)]
ssl_write(&mut self, buf: &[u8]) -> Result<usize, Error>3605     pub fn ssl_write(&mut self, buf: &[u8]) -> Result<usize, Error> {
3606         // See above for why we short-circuit on zero-length buffers
3607         if buf.is_empty() {
3608             return Ok(0);
3609         }
3610 
3611         let ret = self.ssl.write(buf);
3612         if ret > 0 {
3613             Ok(ret as usize)
3614         } else {
3615             Err(self.make_error(ret))
3616         }
3617     }
3618 
3619     /// Reads data from the stream, without removing it from the queue.
3620     #[corresponds(SSL_peek)]
ssl_peek(&mut self, buf: &mut [u8]) -> Result<usize, Error>3621     pub fn ssl_peek(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
3622         // See above for why we short-circuit on zero-length buffers
3623         if buf.is_empty() {
3624             return Ok(0);
3625         }
3626 
3627         let ret = self.ssl.peek(buf);
3628         if ret > 0 {
3629             Ok(ret as usize)
3630         } else {
3631             Err(self.make_error(ret))
3632         }
3633     }
3634 
3635     /// Shuts down the session.
3636     ///
3637     /// The shutdown process consists of two steps. The first step sends a close notify message to
3638     /// the peer, after which `ShutdownResult::Sent` is returned. The second step awaits the receipt
3639     /// of a close notify message from the peer, after which `ShutdownResult::Received` is returned.
3640     ///
3641     /// While the connection may be closed after the first step, it is recommended to fully shut the
3642     /// session down. In particular, it must be fully shut down if the connection is to be used for
3643     /// further communication in the future.
3644     #[corresponds(SSL_shutdown)]
shutdown(&mut self) -> Result<ShutdownResult, Error>3645     pub fn shutdown(&mut self) -> Result<ShutdownResult, Error> {
3646         match unsafe { ffi::SSL_shutdown(self.ssl.as_ptr()) } {
3647             0 => Ok(ShutdownResult::Sent),
3648             1 => Ok(ShutdownResult::Received),
3649             n => Err(self.make_error(n)),
3650         }
3651     }
3652 
3653     /// Returns the session's shutdown state.
3654     #[corresponds(SSL_get_shutdown)]
get_shutdown(&mut self) -> ShutdownState3655     pub fn get_shutdown(&mut self) -> ShutdownState {
3656         unsafe {
3657             let bits = ffi::SSL_get_shutdown(self.ssl.as_ptr());
3658             ShutdownState { bits }
3659         }
3660     }
3661 
3662     /// Sets the session's shutdown state.
3663     ///
3664     /// This can be used to tell OpenSSL that the session should be cached even if a full two-way
3665     /// shutdown was not completed.
3666     #[corresponds(SSL_set_shutdown)]
set_shutdown(&mut self, state: ShutdownState)3667     pub fn set_shutdown(&mut self, state: ShutdownState) {
3668         unsafe { ffi::SSL_set_shutdown(self.ssl.as_ptr(), state.bits()) }
3669     }
3670 }
3671 
3672 impl<S> SslStream<S> {
make_error(&mut self, ret: c_int) -> Error3673     fn make_error(&mut self, ret: c_int) -> Error {
3674         self.check_panic();
3675 
3676         let code = self.ssl.get_error(ret);
3677 
3678         let cause = match code {
3679             ErrorCode::SSL => Some(InnerError::Ssl(ErrorStack::get())),
3680             ErrorCode::SYSCALL => {
3681                 let errs = ErrorStack::get();
3682                 if errs.errors().is_empty() {
3683                     self.get_bio_error().map(InnerError::Io)
3684                 } else {
3685                     Some(InnerError::Ssl(errs))
3686                 }
3687             }
3688             ErrorCode::ZERO_RETURN => None,
3689             ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => {
3690                 self.get_bio_error().map(InnerError::Io)
3691             }
3692             _ => None,
3693         };
3694 
3695         Error { code, cause }
3696     }
3697 
check_panic(&mut self)3698     fn check_panic(&mut self) {
3699         if let Some(err) = unsafe { bio::take_panic::<S>(self.ssl.get_raw_rbio()) } {
3700             resume_unwind(err)
3701         }
3702     }
3703 
get_bio_error(&mut self) -> Option<io::Error>3704     fn get_bio_error(&mut self) -> Option<io::Error> {
3705         unsafe { bio::take_error::<S>(self.ssl.get_raw_rbio()) }
3706     }
3707 
3708     /// Returns a shared reference to the underlying stream.
get_ref(&self) -> &S3709     pub fn get_ref(&self) -> &S {
3710         unsafe {
3711             let bio = self.ssl.get_raw_rbio();
3712             bio::get_ref(bio)
3713         }
3714     }
3715 
3716     /// Returns a mutable reference to the underlying stream.
3717     ///
3718     /// # Warning
3719     ///
3720     /// It is inadvisable to read from or write to the underlying stream as it
3721     /// will most likely corrupt the SSL session.
get_mut(&mut self) -> &mut S3722     pub fn get_mut(&mut self) -> &mut S {
3723         unsafe {
3724             let bio = self.ssl.get_raw_rbio();
3725             bio::get_mut(bio)
3726         }
3727     }
3728 
3729     /// Returns a shared reference to the `Ssl` object associated with this stream.
ssl(&self) -> &SslRef3730     pub fn ssl(&self) -> &SslRef {
3731         &self.ssl
3732     }
3733 }
3734 
3735 impl<S: Read + Write> Read for SslStream<S> {
read(&mut self, buf: &mut [u8]) -> io::Result<usize>3736     fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
3737         loop {
3738             match self.ssl_read(buf) {
3739                 Ok(n) => return Ok(n),
3740                 Err(ref e) if e.code() == ErrorCode::ZERO_RETURN => return Ok(0),
3741                 Err(ref e) if e.code() == ErrorCode::SYSCALL && e.io_error().is_none() => {
3742                     return Ok(0);
3743                 }
3744                 Err(ref e) if e.code() == ErrorCode::WANT_READ && e.io_error().is_none() => {}
3745                 Err(e) => {
3746                     return Err(e
3747                         .into_io_error()
3748                         .unwrap_or_else(|e| io::Error::new(io::ErrorKind::Other, e)));
3749                 }
3750             }
3751         }
3752     }
3753 }
3754 
3755 impl<S: Read + Write> Write for SslStream<S> {
write(&mut self, buf: &[u8]) -> io::Result<usize>3756     fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
3757         loop {
3758             match self.ssl_write(buf) {
3759                 Ok(n) => return Ok(n),
3760                 Err(ref e) if e.code() == ErrorCode::WANT_READ && e.io_error().is_none() => {}
3761                 Err(e) => {
3762                     return Err(e
3763                         .into_io_error()
3764                         .unwrap_or_else(|e| io::Error::new(io::ErrorKind::Other, e)));
3765                 }
3766             }
3767         }
3768     }
3769 
flush(&mut self) -> io::Result<()>3770     fn flush(&mut self) -> io::Result<()> {
3771         self.get_mut().flush()
3772     }
3773 }
3774 
3775 /// A partially constructed `SslStream`, useful for unusual handshakes.
3776 #[deprecated(
3777     since = "0.10.32",
3778     note = "use the methods directly on Ssl/SslStream instead"
3779 )]
3780 pub struct SslStreamBuilder<S> {
3781     inner: SslStream<S>,
3782 }
3783 
3784 #[allow(deprecated)]
3785 impl<S> SslStreamBuilder<S>
3786 where
3787     S: Read + Write,
3788 {
3789     /// Begin creating an `SslStream` atop `stream`
new(ssl: Ssl, stream: S) -> Self3790     pub fn new(ssl: Ssl, stream: S) -> Self {
3791         Self {
3792             inner: SslStream::new(ssl, stream).unwrap(),
3793         }
3794     }
3795 
3796     /// Perform a stateless server-side handshake
3797     ///
3798     /// Requires that cookie generation and verification callbacks were
3799     /// set on the SSL context.
3800     ///
3801     /// Returns `Ok(true)` if a complete ClientHello containing a valid cookie
3802     /// was read, in which case the handshake should be continued via
3803     /// `accept`. If a HelloRetryRequest containing a fresh cookie was
3804     /// transmitted, `Ok(false)` is returned instead. If the handshake cannot
3805     /// proceed at all, `Err` is returned.
3806     ///
3807     /// This corresponds to [`SSL_stateless`]
3808     ///
3809     /// [`SSL_stateless`]: https://www.openssl.org/docs/manmaster/man3/SSL_stateless.html
3810     #[cfg(ossl111)]
stateless(&mut self) -> Result<bool, ErrorStack>3811     pub fn stateless(&mut self) -> Result<bool, ErrorStack> {
3812         match unsafe { ffi::SSL_stateless(self.inner.ssl.as_ptr()) } {
3813             1 => Ok(true),
3814             0 => Ok(false),
3815             -1 => Err(ErrorStack::get()),
3816             _ => unreachable!(),
3817         }
3818     }
3819 
3820     /// Configure as an outgoing stream from a client.
3821     ///
3822     /// This corresponds to [`SSL_set_connect_state`].
3823     ///
3824     /// [`SSL_set_connect_state`]: https://www.openssl.org/docs/manmaster/man3/SSL_set_connect_state.html
set_connect_state(&mut self)3825     pub fn set_connect_state(&mut self) {
3826         unsafe { ffi::SSL_set_connect_state(self.inner.ssl.as_ptr()) }
3827     }
3828 
3829     /// Configure as an incoming stream to a server.
3830     ///
3831     /// This corresponds to [`SSL_set_accept_state`].
3832     ///
3833     /// [`SSL_set_accept_state`]: https://www.openssl.org/docs/manmaster/man3/SSL_set_accept_state.html
set_accept_state(&mut self)3834     pub fn set_accept_state(&mut self) {
3835         unsafe { ffi::SSL_set_accept_state(self.inner.ssl.as_ptr()) }
3836     }
3837 
3838     /// See `Ssl::connect`
connect(mut self) -> Result<SslStream<S>, HandshakeError<S>>3839     pub fn connect(mut self) -> Result<SslStream<S>, HandshakeError<S>> {
3840         match self.inner.connect() {
3841             Ok(()) => Ok(self.inner),
3842             Err(error) => match error.code() {
3843                 ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => {
3844                     Err(HandshakeError::WouldBlock(MidHandshakeSslStream {
3845                         stream: self.inner,
3846                         error,
3847                     }))
3848                 }
3849                 _ => Err(HandshakeError::Failure(MidHandshakeSslStream {
3850                     stream: self.inner,
3851                     error,
3852                 })),
3853             },
3854         }
3855     }
3856 
3857     /// See `Ssl::accept`
accept(mut self) -> Result<SslStream<S>, HandshakeError<S>>3858     pub fn accept(mut self) -> Result<SslStream<S>, HandshakeError<S>> {
3859         match self.inner.accept() {
3860             Ok(()) => Ok(self.inner),
3861             Err(error) => match error.code() {
3862                 ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => {
3863                     Err(HandshakeError::WouldBlock(MidHandshakeSslStream {
3864                         stream: self.inner,
3865                         error,
3866                     }))
3867                 }
3868                 _ => Err(HandshakeError::Failure(MidHandshakeSslStream {
3869                     stream: self.inner,
3870                     error,
3871                 })),
3872             },
3873         }
3874     }
3875 
3876     /// Initiates the handshake.
3877     ///
3878     /// This will fail if `set_accept_state` or `set_connect_state` was not called first.
3879     ///
3880     /// This corresponds to [`SSL_do_handshake`].
3881     ///
3882     /// [`SSL_do_handshake`]: https://www.openssl.org/docs/manmaster/man3/SSL_do_handshake.html
handshake(mut self) -> Result<SslStream<S>, HandshakeError<S>>3883     pub fn handshake(mut self) -> Result<SslStream<S>, HandshakeError<S>> {
3884         match self.inner.do_handshake() {
3885             Ok(()) => Ok(self.inner),
3886             Err(error) => match error.code() {
3887                 ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => {
3888                     Err(HandshakeError::WouldBlock(MidHandshakeSslStream {
3889                         stream: self.inner,
3890                         error,
3891                     }))
3892                 }
3893                 _ => Err(HandshakeError::Failure(MidHandshakeSslStream {
3894                     stream: self.inner,
3895                     error,
3896                 })),
3897             },
3898         }
3899     }
3900 
3901     /// Read application data transmitted by a client before handshake
3902     /// completion.
3903     ///
3904     /// Useful for reducing latency, but vulnerable to replay attacks. Call
3905     /// `set_accept_state` first.
3906     ///
3907     /// Returns `Ok(0)` if all early data has been read.
3908     ///
3909     /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer.
3910     ///
3911     /// This corresponds to [`SSL_read_early_data`].
3912     ///
3913     /// [`SSL_read_early_data`]: https://www.openssl.org/docs/manmaster/man3/SSL_read_early_data.html
3914     #[cfg(any(ossl111, libressl340))]
read_early_data(&mut self, buf: &mut [u8]) -> Result<usize, Error>3915     pub fn read_early_data(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
3916         self.inner.read_early_data(buf)
3917     }
3918 
3919     /// Send data to the server without blocking on handshake completion.
3920     ///
3921     /// Useful for reducing latency, but vulnerable to replay attacks. Call
3922     /// `set_connect_state` first.
3923     ///
3924     /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer.
3925     ///
3926     /// This corresponds to [`SSL_write_early_data`].
3927     ///
3928     /// [`SSL_write_early_data`]: https://www.openssl.org/docs/manmaster/man3/SSL_write_early_data.html
3929     #[cfg(any(ossl111, libressl340))]
write_early_data(&mut self, buf: &[u8]) -> Result<usize, Error>3930     pub fn write_early_data(&mut self, buf: &[u8]) -> Result<usize, Error> {
3931         self.inner.write_early_data(buf)
3932     }
3933 }
3934 
3935 #[allow(deprecated)]
3936 impl<S> SslStreamBuilder<S> {
3937     /// Returns a shared reference to the underlying stream.
get_ref(&self) -> &S3938     pub fn get_ref(&self) -> &S {
3939         unsafe {
3940             let bio = self.inner.ssl.get_raw_rbio();
3941             bio::get_ref(bio)
3942         }
3943     }
3944 
3945     /// Returns a mutable reference to the underlying stream.
3946     ///
3947     /// # Warning
3948     ///
3949     /// It is inadvisable to read from or write to the underlying stream as it
3950     /// will most likely corrupt the SSL session.
get_mut(&mut self) -> &mut S3951     pub fn get_mut(&mut self) -> &mut S {
3952         unsafe {
3953             let bio = self.inner.ssl.get_raw_rbio();
3954             bio::get_mut(bio)
3955         }
3956     }
3957 
3958     /// Returns a shared reference to the `Ssl` object associated with this builder.
ssl(&self) -> &SslRef3959     pub fn ssl(&self) -> &SslRef {
3960         &self.inner.ssl
3961     }
3962 
3963     /// Set the DTLS MTU size.
3964     ///
3965     /// It will be ignored if the value is smaller than the minimum packet size
3966     /// the DTLS protocol requires.
3967     ///
3968     /// # Panics
3969     /// This function panics if the given mtu size can't be represented in a positive `c_long` range
3970     #[deprecated(note = "Use SslRef::set_mtu instead", since = "0.10.30")]
set_dtls_mtu_size(&mut self, mtu_size: usize)3971     pub fn set_dtls_mtu_size(&mut self, mtu_size: usize) {
3972         unsafe {
3973             let bio = self.inner.ssl.get_raw_rbio();
3974             bio::set_dtls_mtu_size::<S>(bio, mtu_size);
3975         }
3976     }
3977 }
3978 
3979 /// The result of a shutdown request.
3980 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
3981 pub enum ShutdownResult {
3982     /// A close notify message has been sent to the peer.
3983     Sent,
3984 
3985     /// A close notify response message has been received from the peer.
3986     Received,
3987 }
3988 
3989 bitflags! {
3990     /// The shutdown state of a session.
3991     pub struct ShutdownState: c_int {
3992         /// A close notify message has been sent to the peer.
3993         const SENT = ffi::SSL_SENT_SHUTDOWN;
3994         /// A close notify message has been received from the peer.
3995         const RECEIVED = ffi::SSL_RECEIVED_SHUTDOWN;
3996     }
3997 }
3998 
3999 cfg_if! {
4000     if #[cfg(any(boringssl, ossl110, libressl273))] {
4001         use ffi::{SSL_CTX_up_ref, SSL_SESSION_get_master_key, SSL_SESSION_up_ref, SSL_is_server};
4002     } else {
4003         #[allow(bad_style)]
4004         pub unsafe fn SSL_CTX_up_ref(ssl: *mut ffi::SSL_CTX) -> c_int {
4005             ffi::CRYPTO_add_lock(
4006                 &mut (*ssl).references,
4007                 1,
4008                 ffi::CRYPTO_LOCK_SSL_CTX,
4009                 "mod.rs\0".as_ptr() as *const _,
4010                 line!() as c_int,
4011             );
4012             0
4013         }
4014 
4015         #[allow(bad_style)]
4016         pub unsafe fn SSL_SESSION_get_master_key(
4017             session: *const ffi::SSL_SESSION,
4018             out: *mut c_uchar,
4019             mut outlen: usize,
4020         ) -> usize {
4021             if outlen == 0 {
4022                 return (*session).master_key_length as usize;
4023             }
4024             if outlen > (*session).master_key_length as usize {
4025                 outlen = (*session).master_key_length as usize;
4026             }
4027             ptr::copy_nonoverlapping((*session).master_key.as_ptr(), out, outlen);
4028             outlen
4029         }
4030 
4031         #[allow(bad_style)]
4032         pub unsafe fn SSL_is_server(s: *mut ffi::SSL) -> c_int {
4033             (*s).server
4034         }
4035 
4036         #[allow(bad_style)]
4037         pub unsafe fn SSL_SESSION_up_ref(ses: *mut ffi::SSL_SESSION) -> c_int {
4038             ffi::CRYPTO_add_lock(
4039                 &mut (*ses).references,
4040                 1,
4041                 ffi::CRYPTO_LOCK_SSL_CTX,
4042                 "mod.rs\0".as_ptr() as *const _,
4043                 line!() as c_int,
4044             );
4045             0
4046         }
4047     }
4048 }
4049 
4050 cfg_if! {
4051     if #[cfg(ossl300)] {
4052         use ffi::SSL_get1_peer_certificate;
4053     } else {
4054         use ffi::SSL_get_peer_certificate as SSL_get1_peer_certificate;
4055     }
4056 }
4057 cfg_if! {
4058     if #[cfg(any(boringssl, ossl110, libressl291))] {
4059         use ffi::{TLS_method, DTLS_method, TLS_client_method, TLS_server_method};
4060     } else {
4061         use ffi::{
4062             SSLv23_method as TLS_method, DTLSv1_method as DTLS_method, SSLv23_client_method as TLS_client_method,
4063             SSLv23_server_method as TLS_server_method,
4064         };
4065     }
4066 }
4067 cfg_if! {
4068     if #[cfg(ossl110)] {
4069         unsafe fn get_new_idx(f: ffi::CRYPTO_EX_free) -> c_int {
4070             ffi::CRYPTO_get_ex_new_index(
4071                 ffi::CRYPTO_EX_INDEX_SSL_CTX,
4072                 0,
4073                 ptr::null_mut(),
4074                 None,
4075                 None,
4076                 Some(f),
4077             )
4078         }
4079 
4080         unsafe fn get_new_ssl_idx(f: ffi::CRYPTO_EX_free) -> c_int {
4081             ffi::CRYPTO_get_ex_new_index(
4082                 ffi::CRYPTO_EX_INDEX_SSL,
4083                 0,
4084                 ptr::null_mut(),
4085                 None,
4086                 None,
4087                 Some(f),
4088             )
4089         }
4090     } else {
4091         use std::sync::Once;
4092 
4093         unsafe fn get_new_idx(f: ffi::CRYPTO_EX_free) -> c_int {
4094             // hack around https://rt.openssl.org/Ticket/Display.html?id=3710&user=guest&pass=guest
4095             static ONCE: Once = Once::new();
4096             ONCE.call_once(|| {
4097                 cfg_if! {
4098                     if #[cfg(not(boringssl))] {
4099                         ffi::SSL_CTX_get_ex_new_index(0, ptr::null_mut(), None, None, None);
4100                     } else {
4101                         ffi::SSL_CTX_get_ex_new_index(0, ptr::null_mut(), ptr::null_mut(), None, None);
4102                     }
4103                 }
4104             });
4105 
4106             cfg_if! {
4107                 if #[cfg(not(boringssl))] {
4108                     ffi::SSL_CTX_get_ex_new_index(0, ptr::null_mut(), None, None, Some(f))
4109                 } else {
4110                     ffi::SSL_CTX_get_ex_new_index(0, ptr::null_mut(), ptr::null_mut(), None, f)
4111                 }
4112             }
4113         }
4114 
4115         unsafe fn get_new_ssl_idx(f: ffi::CRYPTO_EX_free) -> c_int {
4116             // hack around https://rt.openssl.org/Ticket/Display.html?id=3710&user=guest&pass=guest
4117             static ONCE: Once = Once::new();
4118             ONCE.call_once(|| {
4119                 #[cfg(not(boringssl))]
4120                 ffi::SSL_get_ex_new_index(0, ptr::null_mut(), None, None, None);
4121                 #[cfg(boringssl)]
4122                 ffi::SSL_get_ex_new_index(0, ptr::null_mut(), ptr::null_mut(), None, None);
4123             });
4124 
4125             #[cfg(not(boringssl))]
4126             return ffi::SSL_get_ex_new_index(0, ptr::null_mut(), None, None, Some(f));
4127             #[cfg(boringssl)]
4128             return ffi::SSL_get_ex_new_index(0, ptr::null_mut(), ptr::null_mut(), None, f);
4129         }
4130     }
4131 }
4132