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