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