Skip to main content

rama_boring/ssl/
mod.rs

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