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