variant_ssl/ssl/
mod.rs

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