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