tongsuo/ssl/
mod.rs

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