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            #[cfg_attr(not(feature = "fips-compat"), allow(clippy::unnecessary_cast))]
1616            {
1617                assert!(protocols.len() <= ProtosLen::MAX as usize);
1618            }
1619            let r = ffi::SSL_CTX_set_alpn_protos(
1620                self.as_ptr(),
1621                protocols.as_ptr(),
1622                protocols.len() as ProtosLen,
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#[cfg(not(feature = "fips-compat"))]
2405type ProtosLen = usize;
2406#[cfg(feature = "fips-compat")]
2407type ProtosLen = libc::c_uint;
2408
2409/// Information about the state of a cipher.
2410pub struct CipherBits {
2411    /// The number of secret bits used for the cipher.
2412    pub secret: i32,
2413
2414    /// The number of bits processed by the chosen algorithm.
2415    pub algorithm: i32,
2416}
2417
2418#[repr(transparent)]
2419pub struct ClientHello<'ssl>(&'ssl ffi::SSL_CLIENT_HELLO);
2420
2421impl ClientHello<'_> {
2422    /// Returns the data of a given extension, if present.
2423    #[corresponds(SSL_early_callback_ctx_extension_get)]
2424    #[must_use]
2425    pub fn get_extension(&self, ext_type: ExtensionType) -> Option<&[u8]> {
2426        unsafe {
2427            let mut ptr = ptr::null();
2428            let mut len = 0;
2429            let result =
2430                ffi::SSL_early_callback_ctx_extension_get(self.0, ext_type.0, &mut ptr, &mut len);
2431            if result == 0 {
2432                return None;
2433            }
2434            Some(slice::from_raw_parts(ptr, len))
2435        }
2436    }
2437
2438    pub fn ssl_mut(&mut self) -> &mut SslRef {
2439        unsafe { SslRef::from_ptr_mut(self.0.ssl) }
2440    }
2441
2442    #[must_use]
2443    pub fn ssl(&self) -> &SslRef {
2444        unsafe { SslRef::from_ptr(self.0.ssl) }
2445    }
2446
2447    /// Returns the servername sent by the client via Server Name Indication (SNI).
2448    #[must_use]
2449    pub fn servername(&self, type_: NameType) -> Option<&str> {
2450        self.ssl().servername(type_)
2451    }
2452
2453    /// Returns the version sent by the client in its Client Hello record.
2454    #[must_use]
2455    pub fn client_version(&self) -> SslVersion {
2456        SslVersion(self.0.version)
2457    }
2458
2459    /// Returns a string describing the protocol version of the connection.
2460    #[must_use]
2461    pub fn version_str(&self) -> &'static str {
2462        self.ssl().version_str()
2463    }
2464
2465    /// Returns the raw data of the client hello message
2466    #[must_use]
2467    pub fn as_bytes(&self) -> &[u8] {
2468        unsafe { slice::from_raw_parts(self.0.client_hello, self.0.client_hello_len) }
2469    }
2470
2471    /// Returns the client random data
2472    #[must_use]
2473    pub fn random(&self) -> &[u8] {
2474        unsafe { slice::from_raw_parts(self.0.random, self.0.random_len) }
2475    }
2476
2477    /// Returns the raw list of ciphers supported by the client in its Client Hello record.
2478    #[must_use]
2479    pub fn ciphers(&self) -> &[u8] {
2480        unsafe { slice::from_raw_parts(self.0.cipher_suites, self.0.cipher_suites_len) }
2481    }
2482}
2483
2484/// Information about a cipher.
2485pub struct SslCipher(*mut ffi::SSL_CIPHER);
2486
2487impl SslCipher {
2488    #[corresponds(SSL_get_cipher_by_value)]
2489    #[must_use]
2490    pub fn from_value(value: u16) -> Option<Self> {
2491        unsafe {
2492            let ptr = ffi::SSL_get_cipher_by_value(value);
2493            if ptr.is_null() {
2494                None
2495            } else {
2496                Some(Self::from_ptr(ptr as *mut ffi::SSL_CIPHER))
2497            }
2498        }
2499    }
2500}
2501
2502impl Stackable for SslCipher {
2503    type StackType = ffi::stack_st_SSL_CIPHER;
2504}
2505
2506unsafe impl ForeignType for SslCipher {
2507    type CType = ffi::SSL_CIPHER;
2508    type Ref = SslCipherRef;
2509
2510    #[inline]
2511    unsafe fn from_ptr(ptr: *mut ffi::SSL_CIPHER) -> SslCipher {
2512        SslCipher(ptr)
2513    }
2514
2515    #[inline]
2516    fn as_ptr(&self) -> *mut ffi::SSL_CIPHER {
2517        self.0
2518    }
2519}
2520
2521impl Deref for SslCipher {
2522    type Target = SslCipherRef;
2523
2524    fn deref(&self) -> &SslCipherRef {
2525        unsafe { SslCipherRef::from_ptr(self.0) }
2526    }
2527}
2528
2529impl DerefMut for SslCipher {
2530    fn deref_mut(&mut self) -> &mut SslCipherRef {
2531        unsafe { SslCipherRef::from_ptr_mut(self.0) }
2532    }
2533}
2534
2535/// Reference to an [`SslCipher`].
2536///
2537/// [`SslCipher`]: struct.SslCipher.html
2538pub struct SslCipherRef(Opaque);
2539
2540unsafe impl ForeignTypeRef for SslCipherRef {
2541    type CType = ffi::SSL_CIPHER;
2542}
2543
2544impl SslCipherRef {
2545    /// Returns the name of the cipher.
2546    #[corresponds(SSL_CIPHER_get_name)]
2547    #[must_use]
2548    pub fn name(&self) -> &'static str {
2549        unsafe {
2550            let ptr = ffi::SSL_CIPHER_get_name(self.as_ptr());
2551            CStr::from_ptr(ptr).to_str().unwrap()
2552        }
2553    }
2554
2555    /// Returns the RFC-standard name of the cipher, if one exists.
2556    #[corresponds(SSL_CIPHER_standard_name)]
2557    #[must_use]
2558    pub fn standard_name(&self) -> Option<&'static str> {
2559        unsafe {
2560            let ptr = ffi::SSL_CIPHER_standard_name(self.as_ptr());
2561            if ptr.is_null() {
2562                None
2563            } else {
2564                Some(CStr::from_ptr(ptr).to_str().unwrap())
2565            }
2566        }
2567    }
2568
2569    /// Returns the SSL/TLS protocol version that first defined the cipher.
2570    #[corresponds(SSL_CIPHER_get_version)]
2571    #[must_use]
2572    pub fn version(&self) -> &'static str {
2573        let version = unsafe {
2574            let ptr = ffi::SSL_CIPHER_get_version(self.as_ptr());
2575            CStr::from_ptr(ptr as *const _)
2576        };
2577
2578        version.to_str().unwrap()
2579    }
2580
2581    /// Returns the number of bits used for the cipher.
2582    #[corresponds(SSL_CIPHER_get_bits)]
2583    #[allow(clippy::useless_conversion)]
2584    #[must_use]
2585    pub fn bits(&self) -> CipherBits {
2586        unsafe {
2587            let mut algo_bits = 0;
2588            let secret_bits = ffi::SSL_CIPHER_get_bits(self.as_ptr(), &mut algo_bits);
2589            CipherBits {
2590                secret: secret_bits.into(),
2591                algorithm: algo_bits.into(),
2592            }
2593        }
2594    }
2595
2596    /// Returns a textual description of the cipher.
2597    #[corresponds(SSL_CIPHER_description)]
2598    #[must_use]
2599    pub fn description(&self) -> String {
2600        unsafe {
2601            // SSL_CIPHER_description requires a buffer of at least 128 bytes.
2602            let mut buf = [0; 128];
2603            let ptr = ffi::SSL_CIPHER_description(self.as_ptr(), buf.as_mut_ptr(), 128);
2604            CStr::from_ptr(ptr.cast()).to_string_lossy().into_owned()
2605        }
2606    }
2607
2608    /// Returns one if the cipher uses an AEAD cipher.
2609    #[corresponds(SSL_CIPHER_is_aead)]
2610    #[must_use]
2611    pub fn cipher_is_aead(&self) -> bool {
2612        unsafe { ffi::SSL_CIPHER_is_aead(self.as_ptr()) != 0 }
2613    }
2614
2615    /// Returns the NID corresponding to the cipher's authentication type.
2616    #[corresponds(SSL_CIPHER_get_auth_nid)]
2617    #[must_use]
2618    pub fn cipher_auth_nid(&self) -> Option<Nid> {
2619        let n = unsafe { ffi::SSL_CIPHER_get_auth_nid(self.as_ptr()) };
2620        if n == 0 {
2621            None
2622        } else {
2623            Some(Nid::from_raw(n))
2624        }
2625    }
2626
2627    /// Returns the NID corresponding to the cipher.
2628    #[corresponds(SSL_CIPHER_get_cipher_nid)]
2629    #[must_use]
2630    pub fn cipher_nid(&self) -> Option<Nid> {
2631        let n = unsafe { ffi::SSL_CIPHER_get_cipher_nid(self.as_ptr()) };
2632        if n == 0 {
2633            None
2634        } else {
2635            Some(Nid::from_raw(n))
2636        }
2637    }
2638}
2639
2640foreign_type_and_impl_send_sync! {
2641    type CType = ffi::SSL_SESSION;
2642    fn drop = ffi::SSL_SESSION_free;
2643
2644    /// An encoded SSL session.
2645    ///
2646    /// These can be cached to share sessions across connections.
2647    pub struct SslSession;
2648}
2649
2650impl Clone for SslSession {
2651    fn clone(&self) -> SslSession {
2652        SslSessionRef::to_owned(self)
2653    }
2654}
2655
2656impl SslSession {
2657    from_der! {
2658        /// Deserializes a DER-encoded session structure.
2659        #[corresponds(d2i_SSL_SESSION)]
2660        from_der,
2661        SslSession,
2662        ffi::d2i_SSL_SESSION,
2663        ::libc::c_long
2664    }
2665}
2666
2667impl ToOwned for SslSessionRef {
2668    type Owned = SslSession;
2669
2670    fn to_owned(&self) -> SslSession {
2671        unsafe {
2672            SSL_SESSION_up_ref(self.as_ptr());
2673            SslSession(NonNull::new_unchecked(self.as_ptr()))
2674        }
2675    }
2676}
2677
2678impl SslSessionRef {
2679    /// Returns the SSL session ID.
2680    #[corresponds(SSL_SESSION_get_id)]
2681    #[must_use]
2682    pub fn id(&self) -> &[u8] {
2683        unsafe {
2684            let mut len = 0;
2685            let p = ffi::SSL_SESSION_get_id(self.as_ptr(), &mut len);
2686            slice::from_raw_parts(p, len as usize)
2687        }
2688    }
2689
2690    /// Returns the length of the master key.
2691    #[corresponds(SSL_SESSION_get_master_key)]
2692    #[must_use]
2693    pub fn master_key_len(&self) -> usize {
2694        unsafe { SSL_SESSION_get_master_key(self.as_ptr(), ptr::null_mut(), 0) }
2695    }
2696
2697    /// Copies the master key into the provided buffer.
2698    ///
2699    /// Returns the number of bytes written, or the size of the master key if the buffer is empty.
2700    #[corresponds(SSL_SESSION_get_master_key)]
2701    pub fn master_key(&self, buf: &mut [u8]) -> usize {
2702        unsafe { SSL_SESSION_get_master_key(self.as_ptr(), buf.as_mut_ptr(), buf.len()) }
2703    }
2704
2705    /// Returns the time at which the session was established, in seconds since the Unix epoch.
2706    #[corresponds(SSL_SESSION_get_time)]
2707    #[allow(clippy::useless_conversion)]
2708    #[must_use]
2709    pub fn time(&self) -> u64 {
2710        unsafe { ffi::SSL_SESSION_get_time(self.as_ptr()) }
2711    }
2712
2713    /// Returns the sessions timeout, in seconds.
2714    ///
2715    /// A session older than this time should not be used for session resumption.
2716    #[corresponds(SSL_SESSION_get_timeout)]
2717    #[allow(clippy::useless_conversion)]
2718    #[must_use]
2719    pub fn timeout(&self) -> u32 {
2720        unsafe { ffi::SSL_SESSION_get_timeout(self.as_ptr()) }
2721    }
2722
2723    /// Returns the session's TLS protocol version.
2724    #[corresponds(SSL_SESSION_get_protocol_version)]
2725    #[must_use]
2726    pub fn protocol_version(&self) -> SslVersion {
2727        unsafe {
2728            let version = ffi::SSL_SESSION_get_protocol_version(self.as_ptr());
2729            SslVersion(version)
2730        }
2731    }
2732
2733    to_der! {
2734        /// Serializes the session into a DER-encoded structure.
2735        #[corresponds(i2d_SSL_SESSION)]
2736        to_der,
2737        ffi::i2d_SSL_SESSION
2738    }
2739}
2740
2741foreign_type_and_impl_send_sync! {
2742    type CType = ffi::SSL;
2743    fn drop = ffi::SSL_free;
2744
2745    /// The state of an SSL/TLS session.
2746    ///
2747    /// `Ssl` objects are created from an [`SslContext`], which provides configuration defaults.
2748    /// These defaults can be overridden on a per-`Ssl` basis, however.
2749    ///
2750    /// [`SslContext`]: struct.SslContext.html
2751    pub struct Ssl;
2752}
2753
2754impl fmt::Debug for Ssl {
2755    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
2756        fmt::Debug::fmt(&**self, fmt)
2757    }
2758}
2759
2760impl Ssl {
2761    /// Returns a new extra data index.
2762    ///
2763    /// Each invocation of this function is guaranteed to return a distinct index. These can be used
2764    /// to store data in the context that can be retrieved later by callbacks, for example.
2765    #[corresponds(SSL_get_ex_new_index)]
2766    pub fn new_ex_index<T>() -> Result<Index<Ssl, T>, ErrorStack>
2767    where
2768        T: 'static + Sync + Send,
2769    {
2770        unsafe {
2771            ffi::init();
2772            let idx = cvt_n(get_new_ssl_idx(Some(free_data_box::<T>)))?;
2773            Ok(Index::from_raw(idx))
2774        }
2775    }
2776
2777    // FIXME should return a result?
2778    fn cached_ex_index<T>() -> Index<Ssl, T>
2779    where
2780        T: 'static + Sync + Send,
2781    {
2782        unsafe {
2783            let idx = *SSL_INDEXES
2784                .lock()
2785                .unwrap_or_else(|e| e.into_inner())
2786                .entry(TypeId::of::<T>())
2787                .or_insert_with(|| Ssl::new_ex_index::<T>().unwrap().as_raw());
2788            Index::from_raw(idx)
2789        }
2790    }
2791
2792    /// Creates a new `Ssl`.
2793    ///
2794    // FIXME should take &SslContextRef
2795    #[corresponds(SSL_new)]
2796    pub fn new(ctx: &SslContext) -> Result<Ssl, ErrorStack> {
2797        unsafe {
2798            let ptr = cvt_p(ffi::SSL_new(ctx.as_ptr()))?;
2799            let mut ssl = Ssl::from_ptr(ptr);
2800            ssl.set_ex_data(*SESSION_CTX_INDEX, ctx.clone());
2801
2802            Ok(ssl)
2803        }
2804    }
2805
2806    /// Creates a new [`Ssl`].
2807    ///
2808    /// This function does the same as [`Self:new`] except that it takes &[SslContextRef].
2809    // Both functions exist for backward compatibility (no breaking API).
2810    #[corresponds(SSL_new)]
2811    pub fn new_from_ref(ctx: &SslContextRef) -> Result<Ssl, ErrorStack> {
2812        unsafe {
2813            let ptr = cvt_p(ffi::SSL_new(ctx.as_ptr()))?;
2814            let mut ssl = Ssl::from_ptr(ptr);
2815            SSL_CTX_up_ref(ctx.as_ptr());
2816            let ctx_owned = SslContext::from_ptr(ctx.as_ptr());
2817            ssl.set_ex_data(*SESSION_CTX_INDEX, ctx_owned);
2818
2819            Ok(ssl)
2820        }
2821    }
2822
2823    /// Initiates a client-side TLS handshake, returning a [`MidHandshakeSslStream`].
2824    ///
2825    /// This method is guaranteed to return without calling any callback defined
2826    /// in the internal [`Ssl`] or [`SslContext`].
2827    ///
2828    /// See [`SslStreamBuilder::setup_connect`] for more details.
2829    ///
2830    /// # Warning
2831    ///
2832    /// BoringSSL's default configuration is insecure. It is highly recommended to use
2833    /// [`SslConnector`] rather than [`Ssl`] directly, as it manages that configuration.
2834    pub fn setup_connect<S>(self, stream: S) -> MidHandshakeSslStream<S>
2835    where
2836        S: Read + Write,
2837    {
2838        SslStreamBuilder::new(self, stream).setup_connect()
2839    }
2840
2841    /// Attempts a client-side TLS handshake.
2842    ///
2843    /// This is a convenience method which combines [`Self::setup_connect`] and
2844    /// [`MidHandshakeSslStream::handshake`].
2845    ///
2846    /// # Warning
2847    ///
2848    /// OpenSSL's default configuration is insecure. It is highly recommended to use
2849    /// [`SslConnector`] rather than `Ssl` directly, as it manages that configuration.
2850    pub fn connect<S>(self, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
2851    where
2852        S: Read + Write,
2853    {
2854        self.setup_connect(stream).handshake()
2855    }
2856
2857    /// Initiates a server-side TLS handshake.
2858    ///
2859    /// This method is guaranteed to return without calling any callback defined
2860    /// in the internal [`Ssl`] or [`SslContext`].
2861    ///
2862    /// See [`SslStreamBuilder::setup_accept`] for more details.
2863    ///
2864    /// # Warning
2865    ///
2866    /// BoringSSL's default configuration is insecure. It is highly recommended to use
2867    /// [`SslAcceptor`] rather than [`Ssl`] directly, as it manages that configuration.
2868    pub fn setup_accept<S>(self, stream: S) -> MidHandshakeSslStream<S>
2869    where
2870        S: Read + Write,
2871    {
2872        #[cfg(feature = "rpk")]
2873        {
2874            let ctx = self.ssl_context();
2875
2876            if ctx.is_rpk() {
2877                unsafe {
2878                    ffi::SSL_CTX_set_custom_verify(
2879                        ctx.as_ptr(),
2880                        SslVerifyMode::PEER.bits(),
2881                        Some(rpk_verify_failure_callback),
2882                    );
2883                }
2884            }
2885        }
2886
2887        SslStreamBuilder::new(self, stream).setup_accept()
2888    }
2889
2890    /// Attempts a server-side TLS handshake.
2891    ///
2892    /// This is a convenience method which combines [`Self::setup_accept`] and
2893    /// [`MidHandshakeSslStream::handshake`].
2894    ///
2895    /// # Warning
2896    ///
2897    /// OpenSSL's default configuration is insecure. It is highly recommended to use
2898    /// `SslAcceptor` rather than `Ssl` directly, as it manages that configuration.
2899    ///
2900    /// [`SSL_accept`]: https://www.openssl.org/docs/manmaster/man3/SSL_accept.html
2901    pub fn accept<S>(self, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
2902    where
2903        S: Read + Write,
2904    {
2905        self.setup_accept(stream).handshake()
2906    }
2907}
2908
2909impl fmt::Debug for SslRef {
2910    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
2911        let mut builder = fmt.debug_struct("Ssl");
2912
2913        builder.field("state", &self.state_string_long());
2914
2915        #[cfg(feature = "rpk")]
2916        if !self.ssl_context().is_rpk() {
2917            builder.field("verify_result", &self.verify_result());
2918        }
2919
2920        #[cfg(not(feature = "rpk"))]
2921        builder.field("verify_result", &self.verify_result());
2922
2923        builder.finish()
2924    }
2925}
2926
2927impl SslRef {
2928    fn get_raw_rbio(&self) -> *mut ffi::BIO {
2929        unsafe { ffi::SSL_get_rbio(self.as_ptr()) }
2930    }
2931
2932    /// Sets the options used by the ongoing session, returning the old set.
2933    ///
2934    /// # Note
2935    ///
2936    /// This *enables* the specified options, but does not disable unspecified options. Use
2937    /// `clear_options` for that.
2938    #[corresponds(SSL_set_options)]
2939    pub fn set_options(&mut self, option: SslOptions) -> SslOptions {
2940        let bits = unsafe { ffi::SSL_set_options(self.as_ptr(), option.bits()) };
2941        SslOptions::from_bits_retain(bits)
2942    }
2943
2944    /// Clears the options used by the ongoing session, returning the old set.
2945    #[corresponds(SSL_clear_options)]
2946    pub fn clear_options(&mut self, option: SslOptions) -> SslOptions {
2947        let bits = unsafe { ffi::SSL_clear_options(self.as_ptr(), option.bits()) };
2948        SslOptions::from_bits_retain(bits)
2949    }
2950
2951    #[corresponds(SSL_set1_curves_list)]
2952    pub fn set_curves_list(&mut self, curves: &str) -> Result<(), ErrorStack> {
2953        let curves = CString::new(curves).map_err(ErrorStack::internal_error)?;
2954        unsafe {
2955            cvt_0i(ffi::SSL_set1_curves_list(
2956                self.as_ptr(),
2957                curves.as_ptr() as *const _,
2958            ))
2959            .map(|_| ())
2960        }
2961    }
2962
2963    /// Sets the ongoing session's supported groups by their named identifiers
2964    /// (formerly referred to as curves).
2965    #[corresponds(SSL_set1_groups)]
2966    #[deprecated(note = "SslCurveNid will be removed in the next release. Use set_curves_list")]
2967    #[allow(deprecated)]
2968    pub fn set_group_nids(&mut self, group_nids: &[SslCurveNid]) -> Result<(), ErrorStack> {
2969        unsafe {
2970            cvt_0i(ffi::SSL_set1_curves(
2971                self.as_ptr(),
2972                group_nids.as_ptr() as *const _,
2973                group_nids.len(),
2974            ))
2975            .map(|_| ())
2976        }
2977    }
2978
2979    #[cfg(feature = "kx-safe-default")]
2980    fn client_set_default_curves_list(&mut self) {
2981        let curves = if cfg!(feature = "kx-client-pq-preferred") {
2982            if cfg!(feature = "kx-client-nist-required") {
2983                "P256Kyber768Draft00:P-256:P-384:P-521"
2984            } else {
2985                "X25519MLKEM768:X25519Kyber768Draft00:X25519:P256Kyber768Draft00:P-256:P-384:P-521"
2986            }
2987        } else if cfg!(feature = "kx-client-pq-supported") {
2988            if cfg!(feature = "kx-client-nist-required") {
2989                "P-256:P-384:P-521:P256Kyber768Draft00"
2990            } else {
2991                "X25519:P-256:P-384:P-521:X25519MLKEM768:X25519Kyber768Draft00:P256Kyber768Draft00"
2992            }
2993        } else {
2994            if cfg!(feature = "kx-client-nist-required") {
2995                "P-256:P-384:P-521"
2996            } else {
2997                "X25519:P-256:P-384:P-521"
2998            }
2999        };
3000
3001        self.set_curves_list(curves)
3002            .expect("invalid default client curves list");
3003    }
3004
3005    #[cfg(feature = "kx-safe-default")]
3006    fn server_set_default_curves_list(&mut self) {
3007        self.set_curves_list(
3008            "X25519MLKEM768:X25519Kyber768Draft00:P256Kyber768Draft00:X25519:P-256:P-384",
3009        )
3010        .expect("invalid default server curves list");
3011    }
3012
3013    /// Returns the [`SslCurve`] used for this `SslRef`.
3014    #[corresponds(SSL_get_curve_id)]
3015    #[must_use]
3016    #[deprecated(note = "SslCurve will be removed in the next release")]
3017    #[allow(deprecated)]
3018    pub fn curve(&self) -> Option<SslCurve> {
3019        let curve_id = unsafe { ffi::SSL_get_curve_id(self.as_ptr()) };
3020        if curve_id == 0 {
3021            return None;
3022        }
3023        Some(SslCurve(curve_id.into()))
3024    }
3025
3026    /// Returns an `ErrorCode` value for the most recent operation on this `SslRef`.
3027    #[corresponds(SSL_get_error)]
3028    #[must_use]
3029    pub fn error_code(&self, ret: c_int) -> ErrorCode {
3030        unsafe { ErrorCode::from_raw(ffi::SSL_get_error(self.as_ptr(), ret)) }
3031    }
3032
3033    /// Like [`SslContextBuilder::set_verify`].
3034    ///
3035    /// [`SslContextBuilder::set_verify`]: struct.SslContextBuilder.html#method.set_verify
3036    #[corresponds(SSL_set_verify)]
3037    pub fn set_verify(&mut self, mode: SslVerifyMode) {
3038        #[cfg(feature = "rpk")]
3039        assert!(
3040            !self.ssl_context().is_rpk(),
3041            "This API is not supported for RPK"
3042        );
3043
3044        unsafe { ffi::SSL_set_verify(self.as_ptr(), mode.bits() as c_int, None) }
3045    }
3046
3047    /// Sets the certificate verification depth.
3048    ///
3049    /// If the peer's certificate chain is longer than this value, verification will fail.
3050    #[corresponds(SSL_set_verify_depth)]
3051    pub fn set_verify_depth(&mut self, depth: u32) {
3052        #[cfg(feature = "rpk")]
3053        assert!(
3054            !self.ssl_context().is_rpk(),
3055            "This API is not supported for RPK"
3056        );
3057
3058        unsafe {
3059            ffi::SSL_set_verify_depth(self.as_ptr(), depth as c_int);
3060        }
3061    }
3062
3063    /// Returns the verify mode that was set using `set_verify`.
3064    #[corresponds(SSL_get_verify_mode)]
3065    #[must_use]
3066    pub fn verify_mode(&self) -> SslVerifyMode {
3067        #[cfg(feature = "rpk")]
3068        assert!(
3069            !self.ssl_context().is_rpk(),
3070            "This API is not supported for RPK"
3071        );
3072
3073        let mode = unsafe { ffi::SSL_get_verify_mode(self.as_ptr()) };
3074        SslVerifyMode::from_bits(mode).expect("SSL_get_verify_mode returned invalid mode")
3075    }
3076
3077    /// Like [`SslContextBuilder::set_verify_callback`].
3078    ///
3079    /// *Warning*: This callback does not replace the default certificate verification
3080    /// process and is, instead, called multiple times in the course of that process.
3081    /// It is very difficult to implement this callback correctly, without inadvertently
3082    /// relying on implementation details or making incorrect assumptions about when the
3083    /// callback is called.
3084    ///
3085    /// Instead, use [`SslContextBuilder::set_custom_verify_callback`] to customize
3086    /// certificate verification. Those callbacks can inspect the peer-sent chain,
3087    /// call [`X509StoreContextRef::verify_cert`] and inspect the result, or perform
3088    /// other operations more straightforwardly.
3089    ///
3090    /// # Panics
3091    ///
3092    /// This method panics if this `Ssl` is associated with a RPK context.
3093    #[corresponds(SSL_set_verify)]
3094    pub fn set_verify_callback<F>(&mut self, mode: SslVerifyMode, callback: F)
3095    where
3096        F: Fn(bool, &mut X509StoreContextRef) -> bool + 'static + Sync + Send,
3097    {
3098        #[cfg(feature = "rpk")]
3099        assert!(
3100            !self.ssl_context().is_rpk(),
3101            "This API is not supported for RPK"
3102        );
3103
3104        unsafe {
3105            // this needs to be in an Arc since the callback can register a new callback!
3106            self.replace_ex_data(Ssl::cached_ex_index(), Arc::new(callback));
3107            ffi::SSL_set_verify(
3108                self.as_ptr(),
3109                mode.bits() as c_int,
3110                Some(ssl_raw_verify::<F>),
3111            );
3112        }
3113    }
3114
3115    /// Sets a custom certificate store for verifying peer certificates.
3116    #[corresponds(SSL_set0_verify_cert_store)]
3117    pub fn set_verify_cert_store(&mut self, cert_store: X509Store) -> Result<(), ErrorStack> {
3118        #[cfg(feature = "rpk")]
3119        assert!(
3120            !self.ssl_context().is_rpk(),
3121            "This API is not supported for RPK"
3122        );
3123
3124        unsafe {
3125            cvt(ffi::SSL_set0_verify_cert_store(self.as_ptr(), cert_store.into_ptr()) as c_int)?;
3126            Ok(())
3127        }
3128    }
3129
3130    /// Like [`SslContextBuilder::set_custom_verify_callback`].
3131    ///
3132    /// # Panics
3133    ///
3134    /// This method panics if this `Ssl` is associated with a RPK context.
3135    #[corresponds(SSL_set_custom_verify)]
3136    pub fn set_custom_verify_callback<F>(&mut self, mode: SslVerifyMode, callback: F)
3137    where
3138        F: Fn(&mut SslRef) -> Result<(), SslVerifyError> + 'static + Sync + Send,
3139    {
3140        #[cfg(feature = "rpk")]
3141        assert!(
3142            !self.ssl_context().is_rpk(),
3143            "This API is not supported for RPK"
3144        );
3145
3146        unsafe {
3147            // this needs to be in an Arc since the callback can register a new callback!
3148            self.replace_ex_data(Ssl::cached_ex_index(), Arc::new(callback));
3149            ffi::SSL_set_custom_verify(
3150                self.as_ptr(),
3151                mode.bits() as c_int,
3152                Some(ssl_raw_custom_verify::<F>),
3153            );
3154        }
3155    }
3156
3157    /// Like [`SslContextBuilder::set_tmp_dh`].
3158    ///
3159    /// [`SslContextBuilder::set_tmp_dh`]: struct.SslContextBuilder.html#method.set_tmp_dh
3160    #[corresponds(SSL_set_tmp_dh)]
3161    pub fn set_tmp_dh(&mut self, dh: &DhRef<Params>) -> Result<(), ErrorStack> {
3162        unsafe { cvt(ffi::SSL_set_tmp_dh(self.as_ptr(), dh.as_ptr()) as c_int).map(|_| ()) }
3163    }
3164
3165    /// Like [`SslContextBuilder::set_tmp_ecdh`].
3166    ///
3167    /// [`SslContextBuilder::set_tmp_ecdh`]: struct.SslContextBuilder.html#method.set_tmp_ecdh
3168    #[corresponds(SSL_set_tmp_ecdh)]
3169    pub fn set_tmp_ecdh(&mut self, key: &EcKeyRef<Params>) -> Result<(), ErrorStack> {
3170        unsafe { cvt(ffi::SSL_set_tmp_ecdh(self.as_ptr(), key.as_ptr()) as c_int).map(|_| ()) }
3171    }
3172
3173    /// Configures whether ClientHello extensions should be permuted.
3174    #[corresponds(SSL_set_permute_extensions)]
3175    ///
3176    /// Note: This is gated to non-fips because the fips feature builds with a separate
3177    /// version of BoringSSL which doesn't yet include these APIs.
3178    /// Once the submoduled fips commit is upgraded, these gates can be removed.
3179    #[cfg(not(feature = "fips-compat"))]
3180    pub fn set_permute_extensions(&mut self, enabled: bool) {
3181        unsafe { ffi::SSL_set_permute_extensions(self.as_ptr(), enabled as _) }
3182    }
3183
3184    /// Like [`SslContextBuilder::set_alpn_protos`].
3185    ///
3186    /// [`SslContextBuilder::set_alpn_protos`]: struct.SslContextBuilder.html#method.set_alpn_protos
3187    #[corresponds(SSL_set_alpn_protos)]
3188    pub fn set_alpn_protos(&mut self, protocols: &[u8]) -> Result<(), ErrorStack> {
3189        unsafe {
3190            #[cfg_attr(not(feature = "fips-compat"), allow(clippy::unnecessary_cast))]
3191            {
3192                assert!(protocols.len() <= ProtosLen::MAX as usize);
3193            }
3194            let r = ffi::SSL_set_alpn_protos(
3195                self.as_ptr(),
3196                protocols.as_ptr(),
3197                protocols.len() as ProtosLen,
3198            );
3199            // fun fact, SSL_set_alpn_protos has a reversed return code D:
3200            if r == 0 {
3201                Ok(())
3202            } else {
3203                Err(ErrorStack::get())
3204            }
3205        }
3206    }
3207
3208    /// Returns the stack of available SslCiphers for `SSL`, sorted by preference.
3209    #[corresponds(SSL_get_ciphers)]
3210    #[must_use]
3211    pub fn ciphers(&self) -> &StackRef<SslCipher> {
3212        unsafe {
3213            let cipher_list = ffi::SSL_get_ciphers(self.as_ptr());
3214            StackRef::from_ptr(cipher_list)
3215        }
3216    }
3217
3218    /// Returns the current cipher if the session is active.
3219    #[corresponds(SSL_get_current_cipher)]
3220    #[must_use]
3221    pub fn current_cipher(&self) -> Option<&SslCipherRef> {
3222        unsafe {
3223            let ptr = ffi::SSL_get_current_cipher(self.as_ptr());
3224
3225            if ptr.is_null() {
3226                None
3227            } else {
3228                Some(SslCipherRef::from_ptr(ptr as *mut _))
3229            }
3230        }
3231    }
3232
3233    /// Returns a short string describing the state of the session.
3234    ///
3235    /// Returns empty string if the state wasn't valid UTF-8.
3236    #[corresponds(SSL_state_string)]
3237    #[must_use]
3238    pub fn state_string(&self) -> &'static str {
3239        let state = unsafe {
3240            let ptr = ffi::SSL_state_string(self.as_ptr());
3241            CStr::from_ptr(ptr as *const _)
3242        };
3243
3244        state.to_str().unwrap_or_default()
3245    }
3246
3247    /// Returns a longer string describing the state of the session.
3248    ///
3249    /// Returns empty string if the state wasn't valid UTF-8.
3250    #[corresponds(SSL_state_string_long)]
3251    #[must_use]
3252    pub fn state_string_long(&self) -> &'static str {
3253        let state = unsafe {
3254            let ptr = ffi::SSL_state_string_long(self.as_ptr());
3255            CStr::from_ptr(ptr as *const _)
3256        };
3257
3258        state.to_str().unwrap_or_default()
3259    }
3260
3261    /// Sets the host name to be sent to the server for Server Name Indication (SNI).
3262    ///
3263    /// It has no effect for a server-side connection.
3264    #[corresponds(SSL_set_tlsext_host_name)]
3265    pub fn set_hostname(&mut self, hostname: &str) -> Result<(), ErrorStack> {
3266        let cstr = CString::new(hostname).map_err(ErrorStack::internal_error)?;
3267        unsafe {
3268            cvt(ffi::SSL_set_tlsext_host_name(self.as_ptr(), cstr.as_ptr() as *mut _) as c_int)
3269                .map(|_| ())
3270        }
3271    }
3272
3273    /// Returns the peer's certificate, if present.
3274    #[corresponds(SSL_get_peer_certificate)]
3275    #[must_use]
3276    pub fn peer_certificate(&self) -> Option<X509> {
3277        #[cfg(feature = "rpk")]
3278        assert!(
3279            !self.ssl_context().is_rpk(),
3280            "This API is not supported for RPK"
3281        );
3282
3283        unsafe {
3284            let ptr = ffi::SSL_get_peer_certificate(self.as_ptr());
3285            if ptr.is_null() {
3286                None
3287            } else {
3288                Some(X509::from_ptr(ptr))
3289            }
3290        }
3291    }
3292
3293    /// Returns the certificate chain of the peer, if present.
3294    ///
3295    /// On the client side, the chain includes the leaf certificate, but on the server side it does
3296    /// not. Fun!
3297    #[corresponds(SSL_get_peer_certificate)]
3298    #[must_use]
3299    pub fn peer_cert_chain(&self) -> Option<&StackRef<X509>> {
3300        #[cfg(feature = "rpk")]
3301        assert!(
3302            !self.ssl_context().is_rpk(),
3303            "This API is not supported for RPK"
3304        );
3305
3306        unsafe {
3307            let ptr = ffi::SSL_get_peer_cert_chain(self.as_ptr());
3308            if ptr.is_null() {
3309                None
3310            } else {
3311                Some(StackRef::from_ptr(ptr))
3312            }
3313        }
3314    }
3315
3316    /// Like [`SslContext::certificate`].
3317    #[corresponds(SSL_get_certificate)]
3318    #[must_use]
3319    pub fn certificate(&self) -> Option<&X509Ref> {
3320        #[cfg(feature = "rpk")]
3321        assert!(
3322            !self.ssl_context().is_rpk(),
3323            "This API is not supported for RPK"
3324        );
3325
3326        unsafe {
3327            let ptr = ffi::SSL_get_certificate(self.as_ptr());
3328            if ptr.is_null() {
3329                None
3330            } else {
3331                Some(X509Ref::from_ptr(ptr))
3332            }
3333        }
3334    }
3335
3336    /// Like [`SslContext::private_key`].
3337    #[corresponds(SSL_get_privatekey)]
3338    #[must_use]
3339    pub fn private_key(&self) -> Option<&PKeyRef<Private>> {
3340        unsafe {
3341            let ptr = ffi::SSL_get_privatekey(self.as_ptr());
3342            if ptr.is_null() {
3343                None
3344            } else {
3345                Some(PKeyRef::from_ptr(ptr))
3346            }
3347        }
3348    }
3349
3350    #[deprecated(since = "0.10.5", note = "renamed to `version_str`")]
3351    #[must_use]
3352    pub fn version(&self) -> &str {
3353        self.version_str()
3354    }
3355
3356    /// Returns the protocol version of the session.
3357    #[corresponds(SSL_version)]
3358    pub fn version2(&self) -> Option<SslVersion> {
3359        unsafe {
3360            let r = ffi::SSL_version(self.as_ptr());
3361            if r == 0 {
3362                None
3363            } else {
3364                r.try_into().ok().map(SslVersion)
3365            }
3366        }
3367    }
3368
3369    /// Returns a string describing the protocol version of the session.
3370    ///
3371    /// This may panic if the string isn't valid UTF-8 for some reason. Use [`Self::version2`] instead.
3372    #[corresponds(SSL_get_version)]
3373    #[must_use]
3374    pub fn version_str(&self) -> &'static str {
3375        let version = unsafe {
3376            let ptr = ffi::SSL_get_version(self.as_ptr());
3377            CStr::from_ptr(ptr as *const _)
3378        };
3379
3380        version.to_str().unwrap()
3381    }
3382
3383    /// Sets the minimum supported protocol version.
3384    ///
3385    /// If version is `None`, the default minimum version is used. For BoringSSL this defaults to
3386    /// TLS 1.0.
3387    #[corresponds(SSL_set_min_proto_version)]
3388    pub fn set_min_proto_version(&mut self, version: Option<SslVersion>) -> Result<(), ErrorStack> {
3389        unsafe {
3390            cvt(ffi::SSL_set_min_proto_version(
3391                self.as_ptr(),
3392                version.map_or(0, |v| v.0 as _),
3393            ))
3394            .map(|_| ())
3395        }
3396    }
3397
3398    /// Sets the maximum supported protocol version.
3399    ///
3400    /// If version is `None`, the default maximum version is used. For BoringSSL this is TLS 1.3.
3401    #[corresponds(SSL_set_max_proto_version)]
3402    pub fn set_max_proto_version(&mut self, version: Option<SslVersion>) -> Result<(), ErrorStack> {
3403        unsafe {
3404            cvt(ffi::SSL_set_max_proto_version(
3405                self.as_ptr(),
3406                version.map_or(0, |v| v.0 as _),
3407            ))
3408            .map(|_| ())
3409        }
3410    }
3411
3412    /// Gets the minimum supported protocol version.
3413    #[corresponds(SSL_get_min_proto_version)]
3414    pub fn min_proto_version(&mut self) -> Option<SslVersion> {
3415        unsafe {
3416            let r = ffi::SSL_get_min_proto_version(self.as_ptr());
3417            if r == 0 {
3418                None
3419            } else {
3420                Some(SslVersion(r))
3421            }
3422        }
3423    }
3424
3425    /// Gets the maximum supported protocol version.
3426    #[corresponds(SSL_get_max_proto_version)]
3427    #[must_use]
3428    pub fn max_proto_version(&self) -> Option<SslVersion> {
3429        let r = unsafe { ffi::SSL_get_max_proto_version(self.as_ptr()) };
3430        if r == 0 {
3431            None
3432        } else {
3433            Some(SslVersion(r))
3434        }
3435    }
3436
3437    /// Returns the protocol selected via Application Layer Protocol Negotiation (ALPN).
3438    ///
3439    /// The protocol's name is returned is an opaque sequence of bytes. It is up to the client
3440    /// to interpret it.
3441    #[corresponds(SSL_get0_alpn_selected)]
3442    #[must_use]
3443    pub fn selected_alpn_protocol(&self) -> Option<&[u8]> {
3444        unsafe {
3445            let mut data: *const c_uchar = ptr::null();
3446            let mut len: c_uint = 0;
3447            // Get the negotiated protocol from the SSL instance.
3448            // `data` will point at a `c_uchar` array; `len` will contain the length of this array.
3449            ffi::SSL_get0_alpn_selected(self.as_ptr(), &mut data, &mut len);
3450
3451            if data.is_null() {
3452                None
3453            } else {
3454                Some(slice::from_raw_parts(data, len as usize))
3455            }
3456        }
3457    }
3458
3459    /// Enables the DTLS extension "use_srtp" as defined in RFC5764.
3460    #[corresponds(SSL_set_tlsext_use_srtp)]
3461    pub fn set_tlsext_use_srtp(&mut self, protocols: &str) -> Result<(), ErrorStack> {
3462        unsafe {
3463            let cstr = CString::new(protocols).map_err(ErrorStack::internal_error)?;
3464
3465            let r = ffi::SSL_set_tlsext_use_srtp(self.as_ptr(), cstr.as_ptr());
3466            // fun fact, set_tlsext_use_srtp has a reversed return code D:
3467            if r == 0 {
3468                Ok(())
3469            } else {
3470                Err(ErrorStack::get())
3471            }
3472        }
3473    }
3474
3475    /// Gets all SRTP profiles that are enabled for handshake via set_tlsext_use_srtp
3476    ///
3477    /// DTLS extension "use_srtp" as defined in RFC5764 has to be enabled.
3478    #[corresponds(SSL_get_strp_profiles)]
3479    #[must_use]
3480    pub fn srtp_profiles(&self) -> Option<&StackRef<SrtpProtectionProfile>> {
3481        unsafe {
3482            let chain = ffi::SSL_get_srtp_profiles(self.as_ptr());
3483
3484            if chain.is_null() {
3485                None
3486            } else {
3487                Some(StackRef::from_ptr(chain as *mut _))
3488            }
3489        }
3490    }
3491
3492    /// Gets the SRTP profile selected by handshake.
3493    ///
3494    /// DTLS extension "use_srtp" as defined in RFC5764 has to be enabled.
3495    #[corresponds(SSL_get_selected_srtp_profile)]
3496    #[must_use]
3497    pub fn selected_srtp_profile(&self) -> Option<&SrtpProtectionProfileRef> {
3498        unsafe {
3499            let profile = ffi::SSL_get_selected_srtp_profile(self.as_ptr());
3500
3501            if profile.is_null() {
3502                None
3503            } else {
3504                Some(SrtpProtectionProfileRef::from_ptr(profile as *mut _))
3505            }
3506        }
3507    }
3508
3509    /// Returns the number of bytes remaining in the currently processed TLS record.
3510    ///
3511    /// If this is greater than 0, the next call to `read` will not call down to the underlying
3512    /// stream.
3513    #[corresponds(SSL_pending)]
3514    #[must_use]
3515    pub fn pending(&self) -> usize {
3516        unsafe { ffi::SSL_pending(self.as_ptr()) as usize }
3517    }
3518
3519    /// Returns the servername sent by the client via Server Name Indication (SNI).
3520    ///
3521    /// It is only useful on the server side.
3522    ///
3523    /// # Note
3524    ///
3525    /// While the SNI specification requires that servernames be valid domain names (and therefore
3526    /// ASCII), OpenSSL does not enforce this restriction. If the servername provided by the client
3527    /// is not valid UTF-8, this function will return `None`. The `servername_raw` method returns
3528    /// the raw bytes and does not have this restriction.
3529    ///
3530    // FIXME maybe rethink in 0.11?
3531    #[corresponds(SSL_get_servername)]
3532    #[must_use]
3533    pub fn servername(&self, type_: NameType) -> Option<&str> {
3534        self.servername_raw(type_)
3535            .and_then(|b| str::from_utf8(b).ok())
3536    }
3537
3538    /// Returns the servername sent by the client via Server Name Indication (SNI).
3539    ///
3540    /// It is only useful on the server side.
3541    ///
3542    /// # Note
3543    ///
3544    /// Unlike `servername`, this method does not require the name be valid UTF-8.
3545    #[corresponds(SSL_get_servername)]
3546    #[must_use]
3547    pub fn servername_raw(&self, type_: NameType) -> Option<&[u8]> {
3548        unsafe {
3549            let name = ffi::SSL_get_servername(self.as_ptr(), type_.0);
3550            if name.is_null() {
3551                None
3552            } else {
3553                Some(CStr::from_ptr(name as *const _).to_bytes())
3554            }
3555        }
3556    }
3557
3558    /// Changes the context corresponding to the current connection.
3559    ///
3560    /// It is most commonly used in the Server Name Indication (SNI) callback.
3561    #[corresponds(SSL_set_SSL_CTX)]
3562    pub fn set_ssl_context(&mut self, ctx: &SslContextRef) -> Result<(), ErrorStack> {
3563        unsafe { cvt_p(ffi::SSL_set_SSL_CTX(self.as_ptr(), ctx.as_ptr())).map(|_| ()) }
3564    }
3565
3566    /// Returns the context corresponding to the current connection.
3567    #[corresponds(SSL_get_SSL_CTX)]
3568    #[must_use]
3569    pub fn ssl_context(&self) -> &SslContextRef {
3570        unsafe {
3571            let ssl_ctx = ffi::SSL_get_SSL_CTX(self.as_ptr());
3572            SslContextRef::from_ptr(ssl_ctx)
3573        }
3574    }
3575
3576    /// Returns a mutable reference to the X509 verification configuration.
3577    #[corresponds(SSL_get0_param)]
3578    pub fn verify_param_mut(&mut self) -> &mut X509VerifyParamRef {
3579        #[cfg(feature = "rpk")]
3580        assert!(
3581            !self.ssl_context().is_rpk(),
3582            "This API is not supported for RPK"
3583        );
3584
3585        unsafe { X509VerifyParamRef::from_ptr_mut(ffi::SSL_get0_param(self.as_ptr())) }
3586    }
3587
3588    /// See [`Self::verify_param_mut`].
3589    pub fn param_mut(&mut self) -> &mut X509VerifyParamRef {
3590        self.verify_param_mut()
3591    }
3592
3593    /// Returns the certificate verification result.
3594    #[corresponds(SSL_get_verify_result)]
3595    pub fn verify_result(&self) -> X509VerifyResult {
3596        #[cfg(feature = "rpk")]
3597        assert!(
3598            !self.ssl_context().is_rpk(),
3599            "This API is not supported for RPK"
3600        );
3601
3602        unsafe { X509VerifyError::from_raw(ffi::SSL_get_verify_result(self.as_ptr()) as c_int) }
3603    }
3604
3605    /// Returns a shared reference to the SSL session.
3606    #[corresponds(SSL_get_session)]
3607    #[must_use]
3608    pub fn session(&self) -> Option<&SslSessionRef> {
3609        unsafe {
3610            let p = ffi::SSL_get_session(self.as_ptr());
3611            if p.is_null() {
3612                None
3613            } else {
3614                Some(SslSessionRef::from_ptr(p))
3615            }
3616        }
3617    }
3618
3619    /// Copies the client_random value sent by the client in the TLS handshake into a buffer.
3620    ///
3621    /// Returns the number of bytes copied, or if the buffer is empty, the size of the client_random
3622    /// value.
3623    #[corresponds(SSL_get_client_random)]
3624    pub fn client_random(&self, buf: &mut [u8]) -> usize {
3625        unsafe {
3626            ffi::SSL_get_client_random(self.as_ptr(), buf.as_mut_ptr() as *mut c_uchar, buf.len())
3627        }
3628    }
3629
3630    /// Copies the server_random value sent by the server in the TLS handshake into a buffer.
3631    ///
3632    /// Returns the number of bytes copied, or if the buffer is empty, the size of the server_random
3633    /// value.
3634    #[corresponds(SSL_get_server_random)]
3635    pub fn server_random(&self, buf: &mut [u8]) -> usize {
3636        unsafe {
3637            ffi::SSL_get_server_random(self.as_ptr(), buf.as_mut_ptr() as *mut c_uchar, buf.len())
3638        }
3639    }
3640
3641    /// Derives keying material for application use in accordance to RFC 5705.
3642    #[corresponds(SSL_export_keying_material)]
3643    pub fn export_keying_material(
3644        &self,
3645        out: &mut [u8],
3646        label: &str,
3647        context: Option<&[u8]>,
3648    ) -> Result<(), ErrorStack> {
3649        unsafe {
3650            let (context, contextlen, use_context) = match context {
3651                Some(context) => (context.as_ptr() as *const c_uchar, context.len(), 1),
3652                None => (ptr::null(), 0, 0),
3653            };
3654            cvt(ffi::SSL_export_keying_material(
3655                self.as_ptr(),
3656                out.as_mut_ptr() as *mut c_uchar,
3657                out.len(),
3658                label.as_ptr() as *const c_char,
3659                label.len(),
3660                context,
3661                contextlen,
3662                use_context,
3663            ))
3664            .map(|_| ())
3665        }
3666    }
3667
3668    /// Sets the session to be used.
3669    ///
3670    /// This should be called before the handshake to attempt to reuse a previously established
3671    /// session. If the server is not willing to reuse the session, a new one will be transparently
3672    /// negotiated.
3673    ///
3674    /// # Safety
3675    ///
3676    /// The caller of this method is responsible for ensuring that the session is associated
3677    /// with the same `SslContext` as this `Ssl`.
3678    #[corresponds(SSL_set_session)]
3679    pub unsafe fn set_session(&mut self, session: &SslSessionRef) -> Result<(), ErrorStack> {
3680        cvt(ffi::SSL_set_session(self.as_ptr(), session.as_ptr())).map(|_| ())
3681    }
3682
3683    /// Determines if the session provided to `set_session` was successfully reused.
3684    #[corresponds(SSL_session_reused)]
3685    #[must_use]
3686    pub fn session_reused(&self) -> bool {
3687        unsafe { ffi::SSL_session_reused(self.as_ptr()) != 0 }
3688    }
3689
3690    /// Sets the status response a client wishes the server to reply with.
3691    #[corresponds(SSL_set_tlsext_status_type)]
3692    pub fn set_status_type(&mut self, type_: StatusType) -> Result<(), ErrorStack> {
3693        unsafe {
3694            cvt(ffi::SSL_set_tlsext_status_type(self.as_ptr(), type_.as_raw()) as c_int).map(|_| ())
3695        }
3696    }
3697
3698    /// Returns the server's OCSP response, if present.
3699    #[corresponds(SSL_get_tlsext_status_ocsp_resp)]
3700    #[must_use]
3701    pub fn ocsp_status(&self) -> Option<&[u8]> {
3702        unsafe {
3703            let mut p = ptr::null();
3704            let len = ffi::SSL_get_tlsext_status_ocsp_resp(self.as_ptr(), &mut p);
3705
3706            if len == 0 {
3707                None
3708            } else {
3709                Some(slice::from_raw_parts(p, len))
3710            }
3711        }
3712    }
3713
3714    /// Sets the OCSP response to be returned to the client.
3715    #[corresponds(SSL_set_tlsext_status_ocsp_resp)]
3716    pub fn set_ocsp_status(&mut self, response: &[u8]) -> Result<(), ErrorStack> {
3717        unsafe {
3718            assert!(response.len() <= c_int::MAX as usize);
3719            let p = cvt_p(ffi::OPENSSL_malloc(response.len() as _))?;
3720            ptr::copy_nonoverlapping(response.as_ptr(), p as *mut u8, response.len());
3721            cvt(ffi::SSL_set_tlsext_status_ocsp_resp(
3722                self.as_ptr(),
3723                p as *mut c_uchar,
3724                response.len(),
3725            ) as c_int)
3726            .map(|_| ())
3727        }
3728    }
3729
3730    /// Determines if this `Ssl` is configured for server-side or client-side use.
3731    #[corresponds(SSL_is_server)]
3732    #[must_use]
3733    pub fn is_server(&self) -> bool {
3734        unsafe { SSL_is_server(self.as_ptr()) != 0 }
3735    }
3736
3737    /// Sets the extra data at the specified index.
3738    ///
3739    /// This can be used to provide data to callbacks registered with the context. Use the
3740    /// `Ssl::new_ex_index` method to create an `Index`.
3741    ///
3742    /// Note that if this method is called multiple times with the same index, any previous
3743    /// value stored in the `SslContextBuilder` will be leaked.
3744    #[corresponds(SSL_set_ex_data)]
3745    pub fn set_ex_data<T>(&mut self, index: Index<Ssl, T>, data: T) {
3746        if let Some(old) = self.ex_data_mut(index) {
3747            *old = data;
3748
3749            return;
3750        }
3751
3752        unsafe {
3753            let data = Box::new(data);
3754            ffi::SSL_set_ex_data(
3755                self.as_ptr(),
3756                index.as_raw(),
3757                Box::into_raw(data) as *mut c_void,
3758            );
3759        }
3760    }
3761
3762    /// Sets or overwrites the extra data at the specified index.
3763    ///
3764    /// This can be used to provide data to callbacks registered with the context. Use the
3765    /// `Ssl::new_ex_index` method to create an `Index`.
3766    ///
3767    /// The previous value, if any, will be returned.
3768    #[corresponds(SSL_set_ex_data)]
3769    pub fn replace_ex_data<T>(&mut self, index: Index<Ssl, T>, data: T) -> Option<T> {
3770        if let Some(old) = self.ex_data_mut(index) {
3771            return Some(mem::replace(old, data));
3772        }
3773
3774        self.set_ex_data(index, data);
3775
3776        None
3777    }
3778
3779    /// Returns a reference to the extra data at the specified index.
3780    #[corresponds(SSL_get_ex_data)]
3781    #[must_use]
3782    pub fn ex_data<T>(&self, index: Index<Ssl, T>) -> Option<&T> {
3783        unsafe {
3784            let data = ffi::SSL_get_ex_data(self.as_ptr(), index.as_raw());
3785            if data.is_null() {
3786                None
3787            } else {
3788                Some(&*(data as *const T))
3789            }
3790        }
3791    }
3792
3793    /// Returns a mutable reference to the extra data at the specified index.
3794    #[corresponds(SSL_get_ex_data)]
3795    pub fn ex_data_mut<T>(&mut self, index: Index<Ssl, T>) -> Option<&mut T> {
3796        unsafe {
3797            let data = ffi::SSL_get_ex_data(self.as_ptr(), index.as_raw());
3798            if data.is_null() {
3799                None
3800            } else {
3801                Some(&mut *(data as *mut T))
3802            }
3803        }
3804    }
3805
3806    /// Copies the contents of the last Finished message sent to the peer into the provided buffer.
3807    ///
3808    /// The total size of the message is returned, so this can be used to determine the size of the
3809    /// buffer required.
3810    #[corresponds(SSL_get_finished)]
3811    pub fn finished(&self, buf: &mut [u8]) -> usize {
3812        unsafe { ffi::SSL_get_finished(self.as_ptr(), buf.as_mut_ptr() as *mut c_void, buf.len()) }
3813    }
3814
3815    /// Copies the contents of the last Finished message received from the peer into the provided
3816    /// buffer.
3817    ///
3818    /// The total size of the message is returned, so this can be used to determine the size of the
3819    /// buffer required.
3820    #[corresponds(SSL_get_peer_finished)]
3821    pub fn peer_finished(&self, buf: &mut [u8]) -> usize {
3822        unsafe {
3823            ffi::SSL_get_peer_finished(self.as_ptr(), buf.as_mut_ptr() as *mut c_void, buf.len())
3824        }
3825    }
3826
3827    /// Determines if the initial handshake has been completed.
3828    #[corresponds(SSL_is_init_finished)]
3829    #[must_use]
3830    pub fn is_init_finished(&self) -> bool {
3831        unsafe { ffi::SSL_is_init_finished(self.as_ptr()) != 0 }
3832    }
3833
3834    /// Sets the MTU used for DTLS connections.
3835    #[corresponds(SSL_set_mtu)]
3836    pub fn set_mtu(&mut self, mtu: u32) -> Result<(), ErrorStack> {
3837        unsafe { cvt(ffi::SSL_set_mtu(self.as_ptr(), mtu as c_uint) as c_int).map(|_| ()) }
3838    }
3839
3840    /// Sets the certificate.
3841    #[corresponds(SSL_use_certificate)]
3842    pub fn set_certificate(&mut self, cert: &X509Ref) -> Result<(), ErrorStack> {
3843        unsafe {
3844            cvt(ffi::SSL_use_certificate(self.as_ptr(), cert.as_ptr()))?;
3845        }
3846
3847        Ok(())
3848    }
3849
3850    /// Sets the list of CA names sent to the client.
3851    ///
3852    /// The CA certificates must still be added to the trust root - they are not automatically set
3853    /// as trusted by this method.
3854    #[corresponds(SSL_set_client_CA_list)]
3855    pub fn set_client_ca_list(&mut self, list: Stack<X509Name>) {
3856        #[cfg(feature = "rpk")]
3857        assert!(
3858            !self.ssl_context().is_rpk(),
3859            "This API is not supported for RPK"
3860        );
3861
3862        unsafe { ffi::SSL_set_client_CA_list(self.as_ptr(), list.as_ptr()) }
3863        mem::forget(list);
3864    }
3865
3866    /// Sets the private key.
3867    #[corresponds(SSL_use_PrivateKey)]
3868    pub fn set_private_key<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack>
3869    where
3870        T: HasPrivate,
3871    {
3872        unsafe { cvt(ffi::SSL_use_PrivateKey(self.as_ptr(), key.as_ptr())).map(|_| ()) }
3873    }
3874
3875    /// Enables all modes set in `mode` in `SSL`. Returns a bitmask representing the resulting
3876    /// enabled modes.
3877    #[corresponds(SSL_set_mode)]
3878    pub fn set_mode(&mut self, mode: SslMode) -> SslMode {
3879        let bits = unsafe { ffi::SSL_set_mode(self.as_ptr(), mode.bits()) };
3880        SslMode::from_bits_retain(bits)
3881    }
3882
3883    /// Disables all modes set in `mode` in `SSL`. Returns a bitmask representing the resulting
3884    /// enabled modes.
3885    #[corresponds(SSL_clear_mode)]
3886    pub fn clear_mode(&mut self, mode: SslMode) -> SslMode {
3887        let bits = unsafe { ffi::SSL_clear_mode(self.as_ptr(), mode.bits()) };
3888        SslMode::from_bits_retain(bits)
3889    }
3890
3891    /// Appends `cert` to the chain associated with the current certificate of `SSL`.
3892    #[corresponds(SSL_add1_chain_cert)]
3893    pub fn add_chain_cert(&mut self, cert: &X509Ref) -> Result<(), ErrorStack> {
3894        unsafe { cvt(ffi::SSL_add1_chain_cert(self.as_ptr(), cert.as_ptr())).map(|_| ()) }
3895    }
3896
3897    /// Configures `ech_config_list` on `SSL` for offering ECH during handshakes. If the server
3898    /// cannot decrypt the encrypted ClientHello, `SSL` will instead handshake using
3899    /// the cleartext parameters of the ClientHelloOuter.
3900    ///
3901    /// Clients should use `get_ech_name_override` to verify the server certificate in case of ECH
3902    /// rejection, and follow up with `get_ech_retry_configs` to retry the connection with a fresh
3903    /// set of ECHConfigs. If the retry also fails, clients should report a connection failure.
3904    #[cfg(not(feature = "fips"))]
3905    #[corresponds(SSL_set1_ech_config_list)]
3906    pub fn set_ech_config_list(&mut self, ech_config_list: &[u8]) -> Result<(), ErrorStack> {
3907        unsafe {
3908            cvt_0i(ffi::SSL_set1_ech_config_list(
3909                self.as_ptr(),
3910                ech_config_list.as_ptr(),
3911                ech_config_list.len(),
3912            ))
3913            .map(|_| ())
3914        }
3915    }
3916
3917    /// This function returns a serialized `ECHConfigList` as provided by the
3918    /// server, if one exists.
3919    ///
3920    /// Clients should call this function when handling an `SSL_R_ECH_REJECTED` error code to
3921    /// recover from potential key mismatches. If the result is `Some`, the client should retry the
3922    /// connection using the returned `ECHConfigList`.
3923    #[cfg(not(feature = "fips"))]
3924    #[corresponds(SSL_get0_ech_retry_configs)]
3925    #[must_use]
3926    pub fn get_ech_retry_configs(&self) -> Option<&[u8]> {
3927        unsafe {
3928            let mut data = ptr::null();
3929            let mut len: usize = 0;
3930            ffi::SSL_get0_ech_retry_configs(self.as_ptr(), &mut data, &mut len);
3931
3932            if data.is_null() {
3933                None
3934            } else {
3935                Some(slice::from_raw_parts(data, len))
3936            }
3937        }
3938    }
3939
3940    /// If `SSL` is a client and the server rejects ECH, this function returns the public name
3941    /// associated with the ECHConfig that was used to attempt ECH.
3942    ///
3943    /// Clients should call this function during the certificate verification callback to
3944    /// ensure the server's certificate is valid for the public name, which is required to
3945    /// authenticate retry configs.
3946    #[cfg(not(feature = "fips"))]
3947    #[corresponds(SSL_get0_ech_name_override)]
3948    #[must_use]
3949    pub fn get_ech_name_override(&self) -> Option<&[u8]> {
3950        unsafe {
3951            let mut data: *const c_char = ptr::null();
3952            let mut len: usize = 0;
3953            ffi::SSL_get0_ech_name_override(self.as_ptr(), &mut data, &mut len);
3954
3955            if data.is_null() {
3956                None
3957            } else {
3958                Some(slice::from_raw_parts(data as *const u8, len))
3959            }
3960        }
3961    }
3962
3963    // Whether or not `SSL` negotiated ECH.
3964    #[cfg(not(feature = "fips"))]
3965    #[corresponds(SSL_ech_accepted)]
3966    #[must_use]
3967    pub fn ech_accepted(&self) -> bool {
3968        unsafe { ffi::SSL_ech_accepted(self.as_ptr()) != 0 }
3969    }
3970
3971    // Whether or not to enable ECH grease on `SSL`.
3972    #[cfg(not(feature = "fips"))]
3973    #[corresponds(SSL_set_enable_ech_grease)]
3974    pub fn set_enable_ech_grease(&self, enable: bool) {
3975        let enable = if enable { 1 } else { 0 };
3976
3977        unsafe {
3978            ffi::SSL_set_enable_ech_grease(self.as_ptr(), enable);
3979        }
3980    }
3981
3982    /// Sets the compliance policy on `SSL`.
3983    #[cfg(not(feature = "fips-compat"))]
3984    #[corresponds(SSL_set_compliance_policy)]
3985    pub fn set_compliance_policy(&mut self, policy: CompliancePolicy) -> Result<(), ErrorStack> {
3986        unsafe { cvt_0i(ffi::SSL_set_compliance_policy(self.as_ptr(), policy.0)).map(|_| ()) }
3987    }
3988}
3989
3990/// An SSL stream midway through the handshake process.
3991#[derive(Debug)]
3992pub struct MidHandshakeSslStream<S> {
3993    stream: SslStream<S>,
3994    error: Error,
3995}
3996
3997impl<S> MidHandshakeSslStream<S> {
3998    /// Returns a shared reference to the inner stream.
3999    #[must_use]
4000    pub fn get_ref(&self) -> &S {
4001        self.stream.get_ref()
4002    }
4003
4004    /// Returns a mutable reference to the inner stream.
4005    pub fn get_mut(&mut self) -> &mut S {
4006        self.stream.get_mut()
4007    }
4008
4009    /// Returns a shared reference to the `Ssl` of the stream.
4010    #[must_use]
4011    pub fn ssl(&self) -> &SslRef {
4012        self.stream.ssl()
4013    }
4014
4015    /// Returns a mutable reference to the `Ssl` of the stream.
4016    pub fn ssl_mut(&mut self) -> &mut SslRef {
4017        self.stream.ssl_mut()
4018    }
4019
4020    /// Returns the underlying error which interrupted this handshake.
4021    #[must_use]
4022    pub fn error(&self) -> &Error {
4023        &self.error
4024    }
4025
4026    /// Consumes `self`, returning its error.
4027    #[must_use]
4028    pub fn into_error(self) -> Error {
4029        self.error
4030    }
4031
4032    /// Returns the source data stream.
4033    #[must_use]
4034    pub fn into_source_stream(self) -> S {
4035        self.stream.into_inner()
4036    }
4037
4038    /// Returns both the error and the source data stream, consuming `self`.
4039    #[must_use]
4040    pub fn into_parts(self) -> (Error, S) {
4041        (self.error, self.stream.into_inner())
4042    }
4043
4044    /// Restarts the handshake process.
4045    #[corresponds(SSL_do_handshake)]
4046    pub fn handshake(mut self) -> Result<SslStream<S>, HandshakeError<S>> {
4047        let ret = unsafe { ffi::SSL_do_handshake(self.stream.ssl.as_ptr()) };
4048        if ret > 0 {
4049            Ok(self.stream)
4050        } else {
4051            self.error = self.stream.make_error(ret);
4052            Err(if self.error.would_block() {
4053                HandshakeError::WouldBlock(self)
4054            } else {
4055                HandshakeError::Failure(self)
4056            })
4057        }
4058    }
4059}
4060
4061/// A TLS session over a stream.
4062pub struct SslStream<S> {
4063    ssl: ManuallyDrop<Ssl>,
4064    method: ManuallyDrop<BioMethod>,
4065    _p: PhantomData<S>,
4066}
4067
4068impl<S> Drop for SslStream<S> {
4069    fn drop(&mut self) {
4070        // ssl holds a reference to method internally so it has to drop first
4071        unsafe {
4072            ManuallyDrop::drop(&mut self.ssl);
4073            ManuallyDrop::drop(&mut self.method);
4074        }
4075    }
4076}
4077
4078impl<S> fmt::Debug for SslStream<S>
4079where
4080    S: fmt::Debug,
4081{
4082    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
4083        fmt.debug_struct("SslStream")
4084            .field("stream", &self.get_ref())
4085            .field("ssl", &self.ssl())
4086            .finish()
4087    }
4088}
4089
4090impl<S: Read + Write> SslStream<S> {
4091    fn new_base(ssl: Ssl, stream: S) -> Self {
4092        unsafe {
4093            let (bio, method) = bio::new(stream).unwrap();
4094            ffi::SSL_set_bio(ssl.as_ptr(), bio, bio);
4095
4096            SslStream {
4097                ssl: ManuallyDrop::new(ssl),
4098                method: ManuallyDrop::new(method),
4099                _p: PhantomData,
4100            }
4101        }
4102    }
4103
4104    /// Creates a new `SslStream`.
4105    ///
4106    /// This function performs no IO; the stream will not have performed any part of the handshake
4107    /// with the peer. The `connect` and `accept` methods can be used to
4108    /// explicitly perform the handshake.
4109    pub fn new(ssl: Ssl, stream: S) -> Result<Self, ErrorStack> {
4110        Ok(Self::new_base(ssl, stream))
4111    }
4112
4113    /// Constructs an `SslStream` from a pointer to the underlying OpenSSL `SSL` struct.
4114    ///
4115    /// This is useful if the handshake has already been completed elsewhere.
4116    ///
4117    /// # Safety
4118    ///
4119    /// The caller must ensure the pointer is valid.
4120    pub unsafe fn from_raw_parts(ssl: *mut ffi::SSL, stream: S) -> Self {
4121        let ssl = Ssl::from_ptr(ssl);
4122        Self::new_base(ssl, stream)
4123    }
4124
4125    /// Like `read`, but takes a possibly-uninitialized slice.
4126    ///
4127    /// # Safety
4128    ///
4129    /// No portion of `buf` will be de-initialized by this method. If the method returns `Ok(n)`,
4130    /// then the first `n` bytes of `buf` are guaranteed to be initialized.
4131    pub fn read_uninit(&mut self, buf: &mut [MaybeUninit<u8>]) -> io::Result<usize> {
4132        loop {
4133            match self.ssl_read_uninit(buf) {
4134                Ok(n) => return Ok(n),
4135                Err(ref e) if e.code() == ErrorCode::ZERO_RETURN => return Ok(0),
4136                Err(ref e) if e.code() == ErrorCode::SYSCALL && e.io_error().is_none() => {
4137                    return Ok(0);
4138                }
4139                Err(ref e) if e.code() == ErrorCode::WANT_READ && e.io_error().is_none() => {}
4140                Err(e) => {
4141                    return Err(e.into_io_error().unwrap_or_else(io::Error::other));
4142                }
4143            }
4144        }
4145    }
4146
4147    /// Like `read`, but returns an `ssl::Error` rather than an `io::Error`.
4148    ///
4149    /// It is particularly useful with a nonblocking socket, where the error value will identify if
4150    /// OpenSSL is waiting on read or write readiness.
4151    #[corresponds(SSL_read)]
4152    pub fn ssl_read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
4153        // SAFETY: `ssl_read_uninit` does not de-initialize the buffer.
4154        unsafe {
4155            self.ssl_read_uninit(slice::from_raw_parts_mut(
4156                buf.as_mut_ptr().cast::<MaybeUninit<u8>>(),
4157                buf.len(),
4158            ))
4159        }
4160    }
4161
4162    /// Like `read_ssl`, but takes a possibly-uninitialized slice.
4163    ///
4164    /// # Safety
4165    ///
4166    /// No portion of `buf` will be de-initialized by this method. If the method returns `Ok(n)`,
4167    /// then the first `n` bytes of `buf` are guaranteed to be initialized.
4168    pub fn ssl_read_uninit(&mut self, buf: &mut [MaybeUninit<u8>]) -> Result<usize, Error> {
4169        if buf.is_empty() {
4170            return Ok(0);
4171        }
4172
4173        let len = usize::min(c_int::MAX as usize, buf.len()) as c_int;
4174        let ret = unsafe { ffi::SSL_read(self.ssl().as_ptr(), buf.as_mut_ptr().cast(), len) };
4175        if ret > 0 {
4176            Ok(ret as usize)
4177        } else {
4178            Err(self.make_error(ret))
4179        }
4180    }
4181
4182    /// Like `write`, but returns an `ssl::Error` rather than an `io::Error`.
4183    ///
4184    /// It is particularly useful with a nonblocking socket, where the error value will identify if
4185    /// OpenSSL is waiting on read or write readiness.
4186    #[corresponds(SSL_write)]
4187    pub fn ssl_write(&mut self, buf: &[u8]) -> Result<usize, Error> {
4188        if buf.is_empty() {
4189            return Ok(0);
4190        }
4191
4192        let len = usize::min(c_int::MAX as usize, buf.len()) as c_int;
4193        let ret = unsafe { ffi::SSL_write(self.ssl().as_ptr(), buf.as_ptr().cast(), len) };
4194        if ret > 0 {
4195            Ok(ret as usize)
4196        } else {
4197            Err(self.make_error(ret))
4198        }
4199    }
4200
4201    /// Shuts down the session.
4202    ///
4203    /// The shutdown process consists of two steps. The first step sends a close notify message to
4204    /// the peer, after which `ShutdownResult::Sent` is returned. The second step awaits the receipt
4205    /// of a close notify message from the peer, after which `ShutdownResult::Received` is returned.
4206    ///
4207    /// While the connection may be closed after the first step, it is recommended to fully shut the
4208    /// session down. In particular, it must be fully shut down if the connection is to be used for
4209    /// further communication in the future.
4210    #[corresponds(SSL_shutdown)]
4211    pub fn shutdown(&mut self) -> Result<ShutdownResult, Error> {
4212        match unsafe { ffi::SSL_shutdown(self.ssl.as_ptr()) } {
4213            0 => Ok(ShutdownResult::Sent),
4214            1 => Ok(ShutdownResult::Received),
4215            n => Err(self.make_error(n)),
4216        }
4217    }
4218
4219    /// Returns the session's shutdown state.
4220    #[corresponds(SSL_get_shutdown)]
4221    pub fn get_shutdown(&mut self) -> ShutdownState {
4222        unsafe {
4223            let bits = ffi::SSL_get_shutdown(self.ssl.as_ptr());
4224            ShutdownState::from_bits_retain(bits)
4225        }
4226    }
4227
4228    /// Sets the session's shutdown state.
4229    ///
4230    /// This can be used to tell OpenSSL that the session should be cached even if a full two-way
4231    /// shutdown was not completed.
4232    #[corresponds(SSL_set_shutdown)]
4233    pub fn set_shutdown(&mut self, state: ShutdownState) {
4234        unsafe { ffi::SSL_set_shutdown(self.ssl.as_ptr(), state.bits()) }
4235    }
4236
4237    /// Initiates a client-side TLS handshake.
4238    #[corresponds(SSL_connect)]
4239    pub fn connect(&mut self) -> Result<(), Error> {
4240        let ret = unsafe { ffi::SSL_connect(self.ssl.as_ptr()) };
4241        if ret > 0 {
4242            Ok(())
4243        } else {
4244            Err(self.make_error(ret))
4245        }
4246    }
4247
4248    /// Initiates a server-side TLS handshake.
4249    #[corresponds(SSL_accept)]
4250    pub fn accept(&mut self) -> Result<(), Error> {
4251        let ret = unsafe { ffi::SSL_accept(self.ssl.as_ptr()) };
4252        if ret > 0 {
4253            Ok(())
4254        } else {
4255            Err(self.make_error(ret))
4256        }
4257    }
4258
4259    /// Initiates the handshake.
4260    #[corresponds(SSL_do_handshake)]
4261    pub fn do_handshake(&mut self) -> Result<(), Error> {
4262        let ret = unsafe { ffi::SSL_do_handshake(self.ssl.as_ptr()) };
4263        if ret > 0 {
4264            Ok(())
4265        } else {
4266            Err(self.make_error(ret))
4267        }
4268    }
4269}
4270
4271impl<S> SslStream<S> {
4272    fn make_error(&mut self, ret: c_int) -> Error {
4273        self.check_panic();
4274
4275        let code = self.ssl.error_code(ret);
4276
4277        let cause = match code {
4278            ErrorCode::SSL => Some(InnerError::Ssl(ErrorStack::get())),
4279            ErrorCode::SYSCALL => {
4280                let errs = ErrorStack::get();
4281                if errs.errors().is_empty() {
4282                    self.get_bio_error().map(InnerError::Io)
4283                } else {
4284                    Some(InnerError::Ssl(errs))
4285                }
4286            }
4287            ErrorCode::ZERO_RETURN => None,
4288            ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => {
4289                self.get_bio_error().map(InnerError::Io)
4290            }
4291            _ => None,
4292        };
4293
4294        Error { code, cause }
4295    }
4296
4297    fn check_panic(&mut self) {
4298        if let Some(err) = unsafe { bio::take_panic::<S>(self.ssl.get_raw_rbio()) } {
4299            resume_unwind(err)
4300        }
4301    }
4302
4303    fn get_bio_error(&mut self) -> Option<io::Error> {
4304        unsafe { bio::take_error::<S>(self.ssl.get_raw_rbio()) }
4305    }
4306
4307    /// Converts the SslStream to the underlying data stream.
4308    #[must_use]
4309    pub fn into_inner(self) -> S {
4310        unsafe { bio::take_stream::<S>(self.ssl.get_raw_rbio()) }
4311    }
4312
4313    /// Returns a shared reference to the underlying stream.
4314    #[must_use]
4315    pub fn get_ref(&self) -> &S {
4316        unsafe {
4317            let bio = self.ssl.get_raw_rbio();
4318            bio::get_ref(bio)
4319        }
4320    }
4321
4322    /// Returns a mutable reference to the underlying stream.
4323    ///
4324    /// # Warning
4325    ///
4326    /// It is inadvisable to read from or write to the underlying stream as it
4327    /// will most likely corrupt the SSL session.
4328    pub fn get_mut(&mut self) -> &mut S {
4329        unsafe {
4330            let bio = self.ssl.get_raw_rbio();
4331            bio::get_mut(bio)
4332        }
4333    }
4334
4335    /// Returns a shared reference to the `Ssl` object associated with this stream.
4336    #[must_use]
4337    pub fn ssl(&self) -> &SslRef {
4338        &self.ssl
4339    }
4340
4341    /// Returns a mutable reference to the `Ssl` object associated with this stream.
4342    pub fn ssl_mut(&mut self) -> &mut SslRef {
4343        &mut self.ssl
4344    }
4345}
4346
4347impl<S: Read + Write> Read for SslStream<S> {
4348    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
4349        // SAFETY: `read_uninit` does not de-initialize the buffer
4350        unsafe {
4351            self.read_uninit(slice::from_raw_parts_mut(
4352                buf.as_mut_ptr().cast::<MaybeUninit<u8>>(),
4353                buf.len(),
4354            ))
4355        }
4356    }
4357}
4358
4359impl<S: Read + Write> Write for SslStream<S> {
4360    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
4361        loop {
4362            match self.ssl_write(buf) {
4363                Ok(n) => return Ok(n),
4364                Err(ref e) if e.code() == ErrorCode::WANT_READ && e.io_error().is_none() => {}
4365                Err(e) => {
4366                    return Err(e.into_io_error().unwrap_or_else(io::Error::other));
4367                }
4368            }
4369        }
4370    }
4371
4372    fn flush(&mut self) -> io::Result<()> {
4373        self.get_mut().flush()
4374    }
4375}
4376
4377/// A partially constructed `SslStream`, useful for unusual handshakes.
4378pub struct SslStreamBuilder<S> {
4379    inner: SslStream<S>,
4380}
4381
4382impl<S> SslStreamBuilder<S>
4383where
4384    S: Read + Write,
4385{
4386    /// Begin creating an `SslStream` atop `stream`
4387    pub fn new(ssl: Ssl, stream: S) -> Self {
4388        Self {
4389            inner: SslStream::new_base(ssl, stream),
4390        }
4391    }
4392
4393    /// Configure as an outgoing stream from a client.
4394    #[corresponds(SSL_set_connect_state)]
4395    pub fn set_connect_state(&mut self) {
4396        unsafe { ffi::SSL_set_connect_state(self.inner.ssl.as_ptr()) }
4397    }
4398
4399    /// Configure as an incoming stream to a server.
4400    #[corresponds(SSL_set_accept_state)]
4401    pub fn set_accept_state(&mut self) {
4402        unsafe { ffi::SSL_set_accept_state(self.inner.ssl.as_ptr()) }
4403    }
4404
4405    /// Initiates a client-side TLS handshake, returning a [`MidHandshakeSslStream`].
4406    ///
4407    /// This method calls [`Self::set_connect_state`] and returns without actually
4408    /// initiating the handshake. The caller is then free to call
4409    /// [`MidHandshakeSslStream`] and loop on [`HandshakeError::WouldBlock`].
4410    #[must_use]
4411    pub fn setup_connect(mut self) -> MidHandshakeSslStream<S> {
4412        self.set_connect_state();
4413
4414        #[cfg(feature = "kx-safe-default")]
4415        self.inner.ssl.client_set_default_curves_list();
4416
4417        MidHandshakeSslStream {
4418            stream: self.inner,
4419            error: Error {
4420                code: ErrorCode::WANT_WRITE,
4421                cause: Some(InnerError::Io(io::Error::new(
4422                    io::ErrorKind::WouldBlock,
4423                    "connect handshake has not started yet",
4424                ))),
4425            },
4426        }
4427    }
4428
4429    /// Attempts a client-side TLS handshake.
4430    ///
4431    /// This is a convenience method which combines [`Self::setup_connect`] and
4432    /// [`MidHandshakeSslStream::handshake`].
4433    pub fn connect(self) -> Result<SslStream<S>, HandshakeError<S>> {
4434        self.setup_connect().handshake()
4435    }
4436
4437    /// Initiates a server-side TLS handshake, returning a [`MidHandshakeSslStream`].
4438    ///
4439    /// This method calls [`Self::set_accept_state`] and returns without actually
4440    /// initiating the handshake. The caller is then free to call
4441    /// [`MidHandshakeSslStream`] and loop on [`HandshakeError::WouldBlock`].
4442    #[must_use]
4443    pub fn setup_accept(mut self) -> MidHandshakeSslStream<S> {
4444        self.set_accept_state();
4445
4446        #[cfg(feature = "kx-safe-default")]
4447        self.inner.ssl.server_set_default_curves_list();
4448
4449        MidHandshakeSslStream {
4450            stream: self.inner,
4451            error: Error {
4452                code: ErrorCode::WANT_READ,
4453                cause: Some(InnerError::Io(io::Error::new(
4454                    io::ErrorKind::WouldBlock,
4455                    "accept handshake has not started yet",
4456                ))),
4457            },
4458        }
4459    }
4460
4461    /// Attempts a server-side TLS handshake.
4462    ///
4463    /// This is a convenience method which combines [`Self::setup_accept`] and
4464    /// [`MidHandshakeSslStream::handshake`].
4465    pub fn accept(self) -> Result<SslStream<S>, HandshakeError<S>> {
4466        self.setup_accept().handshake()
4467    }
4468
4469    /// Initiates the handshake.
4470    ///
4471    /// This will fail if `set_accept_state` or `set_connect_state` was not called first.
4472    #[corresponds(SSL_do_handshake)]
4473    pub fn handshake(self) -> Result<SslStream<S>, HandshakeError<S>> {
4474        let mut stream = self.inner;
4475        let ret = unsafe { ffi::SSL_do_handshake(stream.ssl.as_ptr()) };
4476        if ret > 0 {
4477            Ok(stream)
4478        } else {
4479            let error = stream.make_error(ret);
4480            Err(if error.would_block() {
4481                HandshakeError::WouldBlock(MidHandshakeSslStream { stream, error })
4482            } else {
4483                HandshakeError::Failure(MidHandshakeSslStream { stream, error })
4484            })
4485        }
4486    }
4487}
4488
4489impl<S> SslStreamBuilder<S> {
4490    /// Returns a shared reference to the underlying stream.
4491    #[must_use]
4492    pub fn get_ref(&self) -> &S {
4493        unsafe {
4494            let bio = self.inner.ssl.get_raw_rbio();
4495            bio::get_ref(bio)
4496        }
4497    }
4498
4499    /// Returns a mutable reference to the underlying stream.
4500    ///
4501    /// # Warning
4502    ///
4503    /// It is inadvisable to read from or write to the underlying stream as it
4504    /// will most likely corrupt the SSL session.
4505    pub fn get_mut(&mut self) -> &mut S {
4506        unsafe {
4507            let bio = self.inner.ssl.get_raw_rbio();
4508            bio::get_mut(bio)
4509        }
4510    }
4511
4512    /// Returns a shared reference to the `Ssl` object associated with this builder.
4513    #[must_use]
4514    pub fn ssl(&self) -> &SslRef {
4515        &self.inner.ssl
4516    }
4517
4518    /// Returns a mutable reference to the `Ssl` object associated with this builder.
4519    pub fn ssl_mut(&mut self) -> &mut SslRef {
4520        &mut self.inner.ssl
4521    }
4522
4523    /// Set the DTLS MTU size.
4524    ///
4525    /// It will be ignored if the value is smaller than the minimum packet size
4526    /// the DTLS protocol requires.
4527    ///
4528    /// # Panics
4529    /// This function panics if the given mtu size can't be represented in a positive `c_long` range
4530    #[deprecated(note = "Use SslRef::set_mtu instead", since = "0.10.30")]
4531    pub fn set_dtls_mtu_size(&mut self, mtu_size: usize) {
4532        unsafe {
4533            let bio = self.inner.ssl.get_raw_rbio();
4534            bio::set_dtls_mtu_size::<S>(bio, mtu_size);
4535        }
4536    }
4537}
4538
4539/// The result of a shutdown request.
4540#[derive(Copy, Clone, Debug, PartialEq, Eq)]
4541pub enum ShutdownResult {
4542    /// A close notify message has been sent to the peer.
4543    Sent,
4544
4545    /// A close notify response message has been received from the peer.
4546    Received,
4547}
4548
4549bitflags! {
4550    /// The shutdown state of a session.
4551    #[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord, Hash)]
4552    pub struct ShutdownState: c_int {
4553        /// A close notify message has been sent to the peer.
4554        const SENT = ffi::SSL_SENT_SHUTDOWN;
4555        /// A close notify message has been received from the peer.
4556        const RECEIVED = ffi::SSL_RECEIVED_SHUTDOWN;
4557    }
4558}
4559
4560/// Describes private key hooks. This is used to off-load signing operations to
4561/// a custom, potentially asynchronous, backend. Metadata about the key such as
4562/// the type and size are parsed out of the certificate.
4563///
4564/// Corresponds to [`ssl_private_key_method_st`].
4565///
4566/// [`ssl_private_key_method_st`]: https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#ssl_private_key_method_st
4567pub trait PrivateKeyMethod: Send + Sync + 'static {
4568    /// Signs the message `input` using the specified signature algorithm.
4569    ///
4570    /// On success, it returns `Ok(written)` where `written` is the number of
4571    /// bytes written into `output`. On failure, it returns
4572    /// `Err(PrivateKeyMethodError::FAILURE)`. If the operation has not completed,
4573    /// it returns `Err(PrivateKeyMethodError::RETRY)`.
4574    ///
4575    /// The caller should arrange for the high-level operation on `ssl` to be
4576    /// retried when the operation is completed. This will result in a call to
4577    /// [`Self::complete`].
4578    fn sign(
4579        &self,
4580        ssl: &mut SslRef,
4581        input: &[u8],
4582        signature_algorithm: SslSignatureAlgorithm,
4583        output: &mut [u8],
4584    ) -> Result<usize, PrivateKeyMethodError>;
4585
4586    /// Decrypts `input`.
4587    ///
4588    /// On success, it returns `Ok(written)` where `written` is the number of
4589    /// bytes written into `output`. On failure, it returns
4590    /// `Err(PrivateKeyMethodError::FAILURE)`. If the operation has not completed,
4591    /// it returns `Err(PrivateKeyMethodError::RETRY)`.
4592    ///
4593    /// The caller should arrange for the high-level operation on `ssl` to be
4594    /// retried when the operation is completed. This will result in a call to
4595    /// [`Self::complete`].
4596    ///
4597    /// This method only works with RSA keys and should perform a raw RSA
4598    /// decryption operation with no padding.
4599    // NOTE(nox): What does it mean that it is an error?
4600    fn decrypt(
4601        &self,
4602        ssl: &mut SslRef,
4603        input: &[u8],
4604        output: &mut [u8],
4605    ) -> Result<usize, PrivateKeyMethodError>;
4606
4607    /// Completes a pending operation.
4608    ///
4609    /// On success, it returns `Ok(written)` where `written` is the number of
4610    /// bytes written into `output`. On failure, it returns
4611    /// `Err(PrivateKeyMethodError::FAILURE)`. If the operation has not completed,
4612    /// it returns `Err(PrivateKeyMethodError::RETRY)`.
4613    ///
4614    /// This method may be called arbitrarily many times before completion.
4615    fn complete(&self, ssl: &mut SslRef, output: &mut [u8])
4616        -> Result<usize, PrivateKeyMethodError>;
4617}
4618
4619/// An error returned from a private key method.
4620#[derive(Debug, Copy, Clone, PartialEq, Eq)]
4621pub struct PrivateKeyMethodError(ffi::ssl_private_key_result_t);
4622
4623impl PrivateKeyMethodError {
4624    /// A fatal error occurred and the handshake should be terminated.
4625    pub const FAILURE: Self = Self(ffi::ssl_private_key_result_t::ssl_private_key_failure);
4626
4627    /// The operation could not be completed and should be retried later.
4628    pub const RETRY: Self = Self(ffi::ssl_private_key_result_t::ssl_private_key_retry);
4629}
4630
4631/// Describes certificate compression algorithm. Implementation MUST implement transformation at least in one direction.
4632pub trait CertificateCompressor: Send + Sync + 'static {
4633    /// An IANA assigned identifier of compression algorithm
4634    const ALGORITHM: CertificateCompressionAlgorithm;
4635
4636    /// Indicates if compressor support compression
4637    const CAN_COMPRESS: bool;
4638
4639    /// Indicates if compressor support decompression
4640    const CAN_DECOMPRESS: bool;
4641
4642    /// Perform compression of `input` buffer and write compressed data to `output`.
4643    #[allow(unused_variables)]
4644    fn compress<W>(&self, input: &[u8], output: &mut W) -> std::io::Result<()>
4645    where
4646        W: std::io::Write,
4647    {
4648        Err(std::io::Error::other("not implemented"))
4649    }
4650
4651    /// Perform decompression of `input` buffer and write compressed data to `output`.
4652    #[allow(unused_variables)]
4653    fn decompress<W>(&self, input: &[u8], output: &mut W) -> std::io::Result<()>
4654    where
4655        W: std::io::Write,
4656    {
4657        Err(std::io::Error::other("not implemented"))
4658    }
4659}
4660
4661use crate::ffi::{SSL_CTX_up_ref, SSL_SESSION_get_master_key, SSL_SESSION_up_ref, SSL_is_server};
4662
4663use crate::ffi::{DTLS_method, TLS_client_method, TLS_method, TLS_server_method};
4664
4665use std::sync::Once;
4666
4667unsafe fn get_new_idx(f: ffi::CRYPTO_EX_free) -> c_int {
4668    // hack around https://rt.openssl.org/Ticket/Display.html?id=3710&user=guest&pass=guest
4669    static ONCE: Once = Once::new();
4670    ONCE.call_once(|| {
4671        ffi::SSL_CTX_get_ex_new_index(0, ptr::null_mut(), ptr::null_mut(), None, None);
4672    });
4673
4674    ffi::SSL_CTX_get_ex_new_index(0, ptr::null_mut(), ptr::null_mut(), None, f)
4675}
4676
4677unsafe fn get_new_ssl_idx(f: ffi::CRYPTO_EX_free) -> c_int {
4678    // hack around https://rt.openssl.org/Ticket/Display.html?id=3710&user=guest&pass=guest
4679    static ONCE: Once = Once::new();
4680    ONCE.call_once(|| {
4681        ffi::SSL_get_ex_new_index(0, ptr::null_mut(), ptr::null_mut(), None, None);
4682    });
4683
4684    ffi::SSL_get_ex_new_index(0, ptr::null_mut(), ptr::null_mut(), None, f)
4685}