Skip to main content

openssl/ssl/
mod.rs

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