boring/ssl/
mod.rs

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