Skip to main content

boring/ssl/
mod.rs

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