Skip to main content

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