Skip to main content

boring/ssl/
mod.rs

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