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