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("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 raw list of ciphers, regardless if they are supported or not.
1556    ///
1557    /// Use [`set_cipher_list`] if you want to play safe instead and do not control the exact cipher list.
1558    #[corresponds(RAMA_SSL_CTX_set_raw_cipher_list)]
1559    pub fn set_raw_cipher_list(&mut self, cipher_list: &[u16]) -> Result<(), ErrorStack> {
1560        unsafe {
1561            cvt(ffi::RAMA_SSL_CTX_set_raw_cipher_list(
1562                self.as_ptr(),
1563                cipher_list.as_ptr() as *const _,
1564                cipher_list.len() as i32,
1565            ))
1566        }
1567    }
1568
1569    /// Gets the list of supported ciphers for protocols before TLSv1.3.
1570    ///
1571    /// See [`ciphers`] for details on the format
1572    ///
1573    /// [`ciphers`]: https://www.openssl.org/docs/manmaster/man1/ciphers.html
1574    #[corresponds(SSL_CTX_get_ciphers)]
1575    #[must_use]
1576    pub fn ciphers(&self) -> Option<&StackRef<SslCipher>> {
1577        self.ctx.ciphers()
1578    }
1579
1580    /// Sets the options used by the context, returning the old set.
1581    ///
1582    /// # Note
1583    ///
1584    /// This *enables* the specified options, but does not disable unspecified options. Use
1585    /// `clear_options` for that.
1586    #[corresponds(SSL_CTX_set_options)]
1587    pub fn set_options(&mut self, option: SslOptions) -> SslOptions {
1588        let bits = unsafe { ffi::SSL_CTX_set_options(self.as_ptr(), option.bits()) };
1589        SslOptions::from_bits_retain(bits)
1590    }
1591
1592    /// Returns the options used by the context.
1593    #[corresponds(SSL_CTX_get_options)]
1594    #[must_use]
1595    pub fn options(&self) -> SslOptions {
1596        let bits = unsafe { ffi::SSL_CTX_get_options(self.as_ptr()) };
1597        SslOptions::from_bits_retain(bits)
1598    }
1599
1600    /// Clears the options used by the context, returning the old set.
1601    #[corresponds(SSL_CTX_clear_options)]
1602    pub fn clear_options(&mut self, option: SslOptions) -> SslOptions {
1603        let bits = unsafe { ffi::SSL_CTX_clear_options(self.as_ptr(), option.bits()) };
1604        SslOptions::from_bits_retain(bits)
1605    }
1606
1607    /// Sets the minimum supported protocol version.
1608    ///
1609    /// If version is `None`, the default minimum version is used. For BoringSSL this defaults to
1610    /// TLS 1.0.
1611    #[corresponds(SSL_CTX_set_min_proto_version)]
1612    pub fn set_min_proto_version(&mut self, version: Option<SslVersion>) -> Result<(), ErrorStack> {
1613        unsafe {
1614            cvt(ffi::SSL_CTX_set_min_proto_version(
1615                self.as_ptr(),
1616                version.map_or(0, |v| v.0 as _),
1617            ))
1618        }
1619    }
1620
1621    /// Sets the maximum supported protocol version.
1622    ///
1623    /// If version is `None`, the default maximum version is used. For BoringSSL this is TLS 1.3.
1624    #[corresponds(SSL_CTX_set_max_proto_version)]
1625    pub fn set_max_proto_version(&mut self, version: Option<SslVersion>) -> Result<(), ErrorStack> {
1626        unsafe {
1627            cvt(ffi::SSL_CTX_set_max_proto_version(
1628                self.as_ptr(),
1629                version.map_or(0, |v| v.0 as _),
1630            ))
1631            .map(|_| ())
1632        }
1633    }
1634
1635    /// Gets the minimum supported protocol version.
1636    #[corresponds(SSL_CTX_get_min_proto_version)]
1637    pub fn min_proto_version(&mut self) -> Option<SslVersion> {
1638        unsafe {
1639            let r = ffi::SSL_CTX_get_min_proto_version(self.as_ptr());
1640            if r == 0 {
1641                None
1642            } else {
1643                Some(SslVersion(r))
1644            }
1645        }
1646    }
1647
1648    /// Gets the maximum supported protocol version.
1649    #[corresponds(SSL_CTX_get_max_proto_version)]
1650    pub fn max_proto_version(&mut self) -> Option<SslVersion> {
1651        unsafe {
1652            let r = ffi::SSL_CTX_get_max_proto_version(self.as_ptr());
1653            if r == 0 {
1654                None
1655            } else {
1656                Some(SslVersion(r))
1657            }
1658        }
1659    }
1660
1661    /// Sets the protocols to sent to the server for Application Layer Protocol Negotiation (ALPN).
1662    ///
1663    /// The input must be in ALPN "wire format". It consists of a sequence of supported protocol
1664    /// names prefixed by their byte length. For example, the protocol list consisting of `spdy/1`
1665    /// and `http/1.1` is encoded as `b"\x06spdy/1\x08http/1.1"`. The protocols are ordered by
1666    /// preference.
1667    #[corresponds(SSL_CTX_set_alpn_protos)]
1668    pub fn set_alpn_protos(&mut self, protocols: &[u8]) -> Result<(), ErrorStack> {
1669        unsafe {
1670            let r = ffi::SSL_CTX_set_alpn_protos(
1671                self.as_ptr(),
1672                protocols.as_ptr(),
1673                try_int(protocols.len())?,
1674            );
1675            // fun fact, SSL_CTX_set_alpn_protos has a reversed return code D:
1676            if r == 0 {
1677                Ok(())
1678            } else {
1679                Err(ErrorStack::get())
1680            }
1681        }
1682    }
1683
1684    /// Enables the DTLS extension "use_srtp" as defined in RFC5764.
1685    #[corresponds(SSL_CTX_set_tlsext_use_srtp)]
1686    pub fn set_tlsext_use_srtp(&mut self, protocols: &str) -> Result<(), ErrorStack> {
1687        unsafe {
1688            let cstr = CString::new(protocols).map_err(ErrorStack::internal_error)?;
1689
1690            let r = ffi::SSL_CTX_set_tlsext_use_srtp(self.as_ptr(), cstr.as_ptr());
1691            // fun fact, set_tlsext_use_srtp has a reversed return code D:
1692            if r == 0 {
1693                Ok(())
1694            } else {
1695                Err(ErrorStack::get())
1696            }
1697        }
1698    }
1699
1700    /// Sets the callback used by a server to select a protocol for Application Layer Protocol
1701    /// Negotiation (ALPN).
1702    ///
1703    /// The callback is provided with the client's protocol list in ALPN wire format. See the
1704    /// documentation for [`SslContextBuilder::set_alpn_protos`] for details. It should return one
1705    /// of those protocols on success. The [`select_next_proto`] function implements the standard
1706    /// protocol selection algorithm.
1707    ///
1708    /// [`SslContextBuilder::set_alpn_protos`]: struct.SslContextBuilder.html#method.set_alpn_protos
1709    /// [`select_next_proto`]: fn.select_next_proto.html
1710    #[corresponds(SSL_CTX_set_alpn_select_cb)]
1711    pub fn set_alpn_select_callback<F>(&mut self, callback: F)
1712    where
1713        F: for<'a> Fn(&mut SslRef, &'a [u8]) -> Result<&'a [u8], AlpnError> + 'static + Sync + Send,
1714    {
1715        unsafe {
1716            self.replace_ex_data(SslContext::cached_ex_index::<F>(), callback);
1717            ffi::SSL_CTX_set_alpn_select_cb(
1718                self.as_ptr(),
1719                Some(callbacks::raw_alpn_select::<F>),
1720                ptr::null_mut(),
1721            );
1722        }
1723    }
1724
1725    /// Sets a callback that is called before most ClientHello processing and before the decision whether
1726    /// to resume a session is made. The callback may inspect the ClientHello and configure the
1727    /// connection.
1728    #[corresponds(SSL_CTX_set_select_certificate_cb)]
1729    pub fn set_select_certificate_callback<F>(&mut self, callback: F)
1730    where
1731        F: Fn(ClientHello<'_>) -> Result<(), SelectCertError> + Sync + Send + 'static,
1732    {
1733        unsafe {
1734            self.replace_ex_data(SslContext::cached_ex_index::<F>(), callback);
1735            ffi::SSL_CTX_set_select_certificate_cb(
1736                self.as_ptr(),
1737                Some(callbacks::raw_select_cert::<F>),
1738            );
1739        }
1740    }
1741
1742    /// Registers a certificate compression algorithm.
1743    ///
1744    /// [`SSL_CTX_add_cert_compression_alg`]: https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#SSL_CTX_add_cert_compression_alg
1745    #[corresponds(SSL_CTX_add_cert_compression_alg)]
1746    pub fn add_certificate_compression_algorithm<C>(
1747        &mut self,
1748        compressor: C,
1749    ) -> Result<(), ErrorStack>
1750    where
1751        C: CertificateCompressor,
1752    {
1753        const {
1754            assert!(C::CAN_COMPRESS || C::CAN_DECOMPRESS, "Either compression or decompression must be supported for algorithm to be registered");
1755        };
1756        let success = unsafe {
1757            ffi::SSL_CTX_add_cert_compression_alg(
1758                self.as_ptr(),
1759                C::ALGORITHM.0,
1760                const {
1761                    if C::CAN_COMPRESS {
1762                        Some(callbacks::raw_ssl_cert_compress::<C>)
1763                    } else {
1764                        None
1765                    }
1766                },
1767                const {
1768                    if C::CAN_DECOMPRESS {
1769                        Some(callbacks::raw_ssl_cert_decompress::<C>)
1770                    } else {
1771                        None
1772                    }
1773                },
1774            ) == 1
1775        };
1776        if !success {
1777            return Err(ErrorStack::get());
1778        }
1779        self.replace_ex_data(SslContext::cached_ex_index::<C>(), compressor);
1780        Ok(())
1781    }
1782
1783    /// Configures a custom private key method on the context.
1784    ///
1785    /// See [`PrivateKeyMethod`] for more details.
1786    #[corresponds(SSL_CTX_set_private_key_method)]
1787    pub fn set_private_key_method<M>(&mut self, method: M)
1788    where
1789        M: PrivateKeyMethod,
1790    {
1791        unsafe {
1792            self.replace_ex_data(SslContext::cached_ex_index::<M>(), method);
1793
1794            ffi::SSL_CTX_set_private_key_method(
1795                self.as_ptr(),
1796                &ffi::SSL_PRIVATE_KEY_METHOD {
1797                    sign: Some(callbacks::raw_sign::<M>),
1798                    decrypt: Some(callbacks::raw_decrypt::<M>),
1799                    complete: Some(callbacks::raw_complete::<M>),
1800                },
1801            );
1802        }
1803    }
1804
1805    /// Checks for consistency between the private key and certificate.
1806    #[corresponds(SSL_CTX_check_private_key)]
1807    pub fn check_private_key(&self) -> Result<(), ErrorStack> {
1808        unsafe { cvt(ffi::SSL_CTX_check_private_key(self.as_ptr())) }
1809    }
1810
1811    /// Returns a shared reference to the context's certificate store.
1812    #[corresponds(SSL_CTX_get_cert_store)]
1813    #[must_use]
1814    pub fn cert_store(&self) -> &X509StoreBuilderRef {
1815        self.ctx.check_x509();
1816        unsafe { X509StoreBuilderRef::from_ptr(ffi::SSL_CTX_get_cert_store(self.as_ptr())) }
1817    }
1818
1819    /// Returns a mutable reference to the context's certificate store.
1820    ///
1821    /// Newly-created `SslContextBuilder` will have its own default mutable store.
1822    ///
1823    /// ## Panics
1824    ///
1825    /// If a shared store has been set via [`Self::set_cert_store_ref`].
1826    #[corresponds(SSL_CTX_get_cert_store)]
1827    pub fn cert_store_mut(&mut self) -> &mut X509StoreBuilderRef {
1828        self.ctx.check_x509();
1829        assert!(
1830            !self.has_shared_cert_store,
1831            "Shared X509Store can't be mutated. Use set_cert_store_builder() instead of set_cert_store()
1832                            or completely finish building the cert store setting it."
1833        );
1834        // OTOH, it's not safe to return a shared &X509Store when the builder owns it exclusively
1835
1836        unsafe { X509StoreBuilderRef::from_ptr_mut(ffi::SSL_CTX_get_cert_store(self.as_ptr())) }
1837    }
1838
1839    /// Sets the callback dealing with OCSP stapling.
1840    ///
1841    /// On the client side, this callback is responsible for validating the OCSP status response
1842    /// returned by the server. The status may be retrieved with the `SslRef::ocsp_status` method.
1843    /// A response of `Ok(true)` indicates that the OCSP status is valid, and a response of
1844    /// `Ok(false)` indicates that the OCSP status is invalid and the handshake should be
1845    /// terminated.
1846    ///
1847    /// On the server side, this callback is resopnsible for setting the OCSP status response to be
1848    /// returned to clients. The status may be set with the `SslRef::set_ocsp_status` method. A
1849    /// response of `Ok(true)` indicates that the OCSP status should be returned to the client, and
1850    /// `Ok(false)` indicates that the status should not be returned to the client.
1851    #[corresponds(SSL_CTX_set_tlsext_status_cb)]
1852    pub fn set_status_callback<F>(&mut self, callback: F) -> Result<(), ErrorStack>
1853    where
1854        F: Fn(&mut SslRef) -> Result<bool, ErrorStack> + 'static + Sync + Send,
1855    {
1856        unsafe {
1857            self.replace_ex_data(SslContext::cached_ex_index::<F>(), callback);
1858            cvt(ffi::SSL_CTX_set_tlsext_status_cb(
1859                self.as_ptr(),
1860                Some(raw_tlsext_status::<F>),
1861            ))
1862        }
1863    }
1864
1865    /// Sets the callback for providing an identity and pre-shared key for a TLS-PSK client.
1866    ///
1867    /// The callback will be called with the SSL context, an identity hint if one was provided
1868    /// by the server, a mutable slice for each of the identity and pre-shared key bytes. The
1869    /// identity must be written as a null-terminated C string.
1870    #[corresponds(SSL_CTX_set_psk_client_callback)]
1871    pub fn set_psk_client_callback<F>(&mut self, callback: F)
1872    where
1873        F: Fn(&mut SslRef, Option<&[u8]>, &mut [u8], &mut [u8]) -> Result<usize, ErrorStack>
1874            + 'static
1875            + Sync
1876            + Send,
1877    {
1878        unsafe {
1879            self.replace_ex_data(SslContext::cached_ex_index::<F>(), callback);
1880            ffi::SSL_CTX_set_psk_client_callback(self.as_ptr(), Some(raw_client_psk::<F>));
1881        }
1882    }
1883
1884    #[deprecated(since = "0.10.10", note = "renamed to `set_psk_client_callback`")]
1885    pub fn set_psk_callback<F>(&mut self, callback: F)
1886    where
1887        F: Fn(&mut SslRef, Option<&[u8]>, &mut [u8], &mut [u8]) -> Result<usize, ErrorStack>
1888            + 'static
1889            + Sync
1890            + Send,
1891    {
1892        self.set_psk_client_callback(callback);
1893    }
1894
1895    /// Sets the callback for providing an identity and pre-shared key for a TLS-PSK server.
1896    ///
1897    /// The callback will be called with the SSL context, an identity provided by the client,
1898    /// and, a mutable slice for the pre-shared key bytes. The callback returns the number of
1899    /// bytes in the pre-shared key.
1900    #[corresponds(SSL_CTX_set_psk_server_callback)]
1901    pub fn set_psk_server_callback<F>(&mut self, callback: F)
1902    where
1903        F: Fn(&mut SslRef, Option<&[u8]>, &mut [u8]) -> Result<usize, ErrorStack>
1904            + 'static
1905            + Sync
1906            + Send,
1907    {
1908        unsafe {
1909            self.replace_ex_data(SslContext::cached_ex_index::<F>(), callback);
1910            ffi::SSL_CTX_set_psk_server_callback(self.as_ptr(), Some(raw_server_psk::<F>));
1911        }
1912    }
1913
1914    /// Sets the callback which is called when new sessions are negotiated.
1915    ///
1916    /// This can be used by clients to implement session caching. While in TLSv1.2 the session is
1917    /// available to access via [`SslRef::session`] immediately after the handshake completes, this
1918    /// is not the case for TLSv1.3. There, a session is not generally available immediately, and
1919    /// the server may provide multiple session tokens to the client over a single session. The new
1920    /// session callback is a portable way to deal with both cases.
1921    ///
1922    /// Note that session caching must be enabled for the callback to be invoked, and it defaults
1923    /// off for clients. [`set_session_cache_mode`] controls that behavior.
1924    ///
1925    /// [`SslRef::session`]: struct.SslRef.html#method.session
1926    /// [`set_session_cache_mode`]: #method.set_session_cache_mode
1927    #[corresponds(SSL_CTX_sess_set_new_cb)]
1928    pub fn set_new_session_callback<F>(&mut self, callback: F)
1929    where
1930        F: Fn(&mut SslRef, SslSession) + 'static + Sync + Send,
1931    {
1932        unsafe {
1933            self.replace_ex_data(SslContext::cached_ex_index::<F>(), callback);
1934            ffi::SSL_CTX_sess_set_new_cb(self.as_ptr(), Some(callbacks::raw_new_session::<F>));
1935        }
1936    }
1937
1938    /// Sets the callback which is called when sessions are removed from the context.
1939    ///
1940    /// Sessions can be removed because they have timed out or because they are considered faulty.
1941    #[corresponds(SSL_CTX_sess_set_remove_cb)]
1942    pub fn set_remove_session_callback<F>(&mut self, callback: F)
1943    where
1944        F: Fn(&SslContextRef, &SslSessionRef) + 'static + Sync + Send,
1945    {
1946        unsafe {
1947            self.replace_ex_data(SslContext::cached_ex_index::<F>(), callback);
1948            ffi::SSL_CTX_sess_set_remove_cb(
1949                self.as_ptr(),
1950                Some(callbacks::raw_remove_session::<F>),
1951            );
1952        }
1953    }
1954
1955    /// Sets the callback which is called when a client proposed to resume a session but it was not
1956    /// found in the internal cache.
1957    ///
1958    /// The callback is passed a reference to the session ID provided by the client. It should
1959    /// return the session corresponding to that ID if available. This is only used for servers, not
1960    /// clients.
1961    ///
1962    /// # Safety
1963    ///
1964    /// The returned [`SslSession`] must not be associated with a different [`SslContext`].
1965    #[corresponds(SSL_CTX_sess_set_get_cb)]
1966    pub unsafe fn set_get_session_callback<F>(&mut self, callback: F)
1967    where
1968        F: Fn(&mut SslRef, &[u8]) -> Result<Option<SslSession>, GetSessionPendingError>
1969            + 'static
1970            + Sync
1971            + Send,
1972    {
1973        self.replace_ex_data(SslContext::cached_ex_index::<F>(), callback);
1974        ffi::SSL_CTX_sess_set_get_cb(self.as_ptr(), Some(callbacks::raw_get_session::<F>));
1975    }
1976
1977    /// Sets the TLS key logging callback.
1978    ///
1979    /// The callback is invoked whenever TLS key material is generated, and is passed a line of NSS
1980    /// SSLKEYLOGFILE-formatted text. This can be used by tools like Wireshark to decrypt message
1981    /// traffic. The line does not contain a trailing newline.
1982    #[corresponds(SSL_CTX_set_keylog_callback)]
1983    pub fn set_keylog_callback<F>(&mut self, callback: F)
1984    where
1985        F: Fn(&SslRef, &str) + 'static + Sync + Send,
1986    {
1987        unsafe {
1988            self.replace_ex_data(SslContext::cached_ex_index::<F>(), callback);
1989            ffi::SSL_CTX_set_keylog_callback(self.as_ptr(), Some(callbacks::raw_keylog::<F>));
1990        }
1991    }
1992
1993    /// Sets the session caching mode use for connections made with the context.
1994    ///
1995    /// Returns the previous session caching mode.
1996    #[corresponds(SSL_CTX_set_session_cache_mode)]
1997    pub fn set_session_cache_mode(&mut self, mode: SslSessionCacheMode) -> SslSessionCacheMode {
1998        unsafe {
1999            let bits = ffi::SSL_CTX_set_session_cache_mode(self.as_ptr(), mode.bits());
2000            SslSessionCacheMode::from_bits_retain(bits)
2001        }
2002    }
2003
2004    /// Sets the extra data at the specified index.
2005    ///
2006    /// This can be used to provide data to callbacks registered with the context. Use the
2007    /// `SslContext::new_ex_index` method to create an `Index`.
2008    #[corresponds(SSL_CTX_set_ex_data)]
2009    pub fn set_ex_data<T>(&mut self, index: Index<SslContext, T>, data: T) {
2010        unsafe {
2011            self.ctx.replace_ex_data(index, data);
2012        }
2013    }
2014
2015    /// Sets or overwrites the extra data at the specified index.
2016    ///
2017    /// This can be used to provide data to callbacks registered with the context. Use the
2018    /// `SslContext::new_ex_index` method to create an `Index`.
2019    ///
2020    /// Any previous value will be returned and replaced by the new one.
2021    #[corresponds(SSL_CTX_set_ex_data)]
2022    pub fn replace_ex_data<T>(&mut self, index: Index<SslContext, T>, data: T) -> Option<T> {
2023        unsafe { self.ctx.replace_ex_data(index, data) }
2024    }
2025
2026    /// Sets the context's session cache size limit, returning the previous limit.
2027    ///
2028    /// A value of 0 means that the cache size is unbounded.
2029    #[corresponds(SSL_CTX_sess_set_cache_size)]
2030    #[allow(clippy::useless_conversion)]
2031    pub fn set_session_cache_size(&mut self, size: u32) -> u64 {
2032        unsafe { ffi::SSL_CTX_sess_set_cache_size(self.as_ptr(), size.into()).into() }
2033    }
2034
2035    /// Sets the context's supported signature algorithms.
2036    #[corresponds(SSL_CTX_set1_sigalgs_list)]
2037    pub fn set_sigalgs_list(&mut self, sigalgs: &str) -> Result<(), ErrorStack> {
2038        let sigalgs = CString::new(sigalgs).map_err(ErrorStack::internal_error)?;
2039        unsafe {
2040            cvt(ffi::SSL_CTX_set1_sigalgs_list(
2041                self.as_ptr(),
2042                sigalgs.as_ptr(),
2043            ))
2044        }
2045    }
2046
2047    /// Set's whether the context should enable GREASE.
2048    #[corresponds(SSL_CTX_set_grease_enabled)]
2049    pub fn set_grease_enabled(&mut self, enabled: bool) {
2050        unsafe { ffi::SSL_CTX_set_grease_enabled(self.as_ptr(), enabled as _) }
2051    }
2052
2053    /// Configures whether ClientHello extensions should be permuted.
2054    #[corresponds(SSL_CTX_set_permute_extensions)]
2055    pub fn set_permute_extensions(&mut self, enabled: bool) {
2056        unsafe { ffi::SSL_CTX_set_permute_extensions(self.as_ptr(), enabled as _) }
2057    }
2058
2059    /// Configures whether ClientHello extensions should be in the provided order.
2060    #[corresponds(RAMA_SSL_CTX_set_extension_order)]
2061    pub fn set_extension_order(&mut self, ids: &[u16]) -> Result<(), ErrorStack> {
2062        unsafe {
2063            cvt(ffi::RAMA_SSL_CTX_set_extension_order(
2064                self.as_ptr(),
2065                ids.as_ptr() as *const _,
2066                ids.len() as i32,
2067            ))
2068            .map(|_| ())
2069        }
2070    }
2071
2072    /// Sets the context's supported signature verification algorithms.
2073    #[corresponds(SSL_CTX_set_verify_algorithm_prefs)]
2074    pub fn set_verify_algorithm_prefs(
2075        &mut self,
2076        prefs: &[SslSignatureAlgorithm],
2077    ) -> Result<(), ErrorStack> {
2078        unsafe {
2079            cvt_0i(ffi::SSL_CTX_set_verify_algorithm_prefs(
2080                self.as_ptr(),
2081                prefs.as_ptr().cast(),
2082                prefs.len(),
2083            ))
2084            .map(|_| ())
2085        }
2086    }
2087
2088    /// Enables SCT requests on all client SSL handshakes.
2089    #[corresponds(SSL_CTX_enable_signed_cert_timestamps)]
2090    pub fn enable_signed_cert_timestamps(&mut self) {
2091        unsafe { ffi::SSL_CTX_enable_signed_cert_timestamps(self.as_ptr()) }
2092    }
2093
2094    /// Enables OCSP stapling on all client SSL handshakes.
2095    #[corresponds(SSL_CTX_enable_ocsp_stapling)]
2096    pub fn enable_ocsp_stapling(&mut self) {
2097        unsafe { ffi::SSL_CTX_enable_ocsp_stapling(self.as_ptr()) }
2098    }
2099
2100    /// Sets the context's supported curves.
2101    //
2102    // If the "kx-*" flags are used to set key exchange preference, then don't allow the user to
2103    // set them here. This ensures we don't override the user's preference without telling them:
2104    // when the flags are used, the preferences are set just before connecting or accepting.
2105    #[corresponds(SSL_CTX_set1_curves_list)]
2106    pub fn set_curves_list(&mut self, curves: &str) -> Result<(), ErrorStack> {
2107        let curves = CString::new(curves).unwrap();
2108        unsafe {
2109            cvt_0i(ffi::SSL_CTX_set1_curves_list(
2110                self.as_ptr(),
2111                curves.as_ptr(),
2112            ))
2113            .map(|_| ())
2114        }
2115    }
2116
2117    /// Sets the context's supported curves.
2118    //
2119    // If the "kx-*" flags are used to set key exchange preference, then don't allow the user to
2120    // set them here. This ensures we don't override the user's preference without telling them:
2121    // when the flags are used, the preferences are set just before connecting or accepting.
2122    #[corresponds(SSL_CTX_set1_curves)]
2123    pub fn set_curves(&mut self, curves: &[SslCurve]) -> Result<(), ErrorStack> {
2124        let curves: Vec<i32> = curves.iter().filter_map(|curve| curve.nid()).collect();
2125
2126        unsafe {
2127            cvt_0i(ffi::SSL_CTX_set1_curves(
2128                self.as_ptr(),
2129                curves.as_ptr() as *const _,
2130                curves.len(),
2131            ))
2132            .map(|_| ())
2133        }
2134    }
2135
2136    /// Sets the context's compliance policy.
2137    ///
2138    /// This feature isn't available in the certified version of BoringSSL.
2139    #[corresponds(SSL_CTX_set_compliance_policy)]
2140    pub fn set_compliance_policy(&mut self, policy: CompliancePolicy) -> Result<(), ErrorStack> {
2141        unsafe { cvt_0i(ffi::SSL_CTX_set_compliance_policy(self.as_ptr(), policy.0)).map(|_| ()) }
2142    }
2143
2144    /// Sets the context's info callback.
2145    #[corresponds(SSL_CTX_set_info_callback)]
2146    pub fn set_info_callback<F>(&mut self, callback: F)
2147    where
2148        F: Fn(&SslRef, SslInfoCallbackMode, SslInfoCallbackValue) + Send + Sync + 'static,
2149    {
2150        unsafe {
2151            self.replace_ex_data(SslContext::cached_ex_index::<F>(), callback);
2152            ffi::SSL_CTX_set_info_callback(self.as_ptr(), Some(callbacks::raw_info_callback::<F>));
2153        }
2154    }
2155
2156    /// Registers a list of ECH keys on the context. This list should contain new and old
2157    /// ECHConfigs to allow stale DNS caches to update. Unlike most `SSL_CTX` APIs, this function
2158    /// is safe to call even after the `SSL_CTX` has been associated with connections on various
2159    /// threads.
2160    #[corresponds(SSL_CTX_set1_ech_keys)]
2161    pub fn set_ech_keys(&self, keys: &SslEchKeys) -> Result<(), ErrorStack> {
2162        unsafe { cvt(ffi::SSL_CTX_set1_ech_keys(self.as_ptr(), keys.as_ptr())) }
2163    }
2164
2165    /// Adds a credential.
2166    #[corresponds(SSL_CTX_add1_credential)]
2167    pub fn add_credential(&mut self, credential: &SslCredentialRef) -> Result<(), ErrorStack> {
2168        unsafe {
2169            cvt_0i(ffi::SSL_CTX_add1_credential(
2170                self.as_ptr(),
2171                credential.as_ptr(),
2172            ))
2173            .map(|_| ())
2174        }
2175    }
2176
2177    /// Consumes the builder, returning a new `SslContext`.
2178    #[must_use]
2179    pub fn build(self) -> SslContext {
2180        self.ctx
2181    }
2182}
2183
2184foreign_type_and_impl_send_sync! {
2185    type CType = ffi::SSL_CTX;
2186    fn drop = ffi::SSL_CTX_free;
2187
2188    /// A context object for TLS streams.
2189    ///
2190    /// Applications commonly configure a single `SslContext` that is shared by all of its
2191    /// `SslStreams`.
2192    pub struct SslContext;
2193}
2194
2195impl Clone for SslContext {
2196    fn clone(&self) -> Self {
2197        (**self).to_owned()
2198    }
2199}
2200
2201impl ToOwned for SslContextRef {
2202    type Owned = SslContext;
2203
2204    fn to_owned(&self) -> Self::Owned {
2205        unsafe {
2206            SSL_CTX_up_ref(self.as_ptr());
2207            SslContext::from_ptr(self.as_ptr())
2208        }
2209    }
2210}
2211
2212// TODO: add useful info here
2213impl fmt::Debug for SslContext {
2214    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
2215        write!(fmt, "SslContext")
2216    }
2217}
2218
2219impl SslContext {
2220    /// Creates a new builder object for an `SslContext`.
2221    pub fn builder(method: SslMethod) -> Result<SslContextBuilder, ErrorStack> {
2222        SslContextBuilder::new(method)
2223    }
2224
2225    /// Returns a new extra data index.
2226    ///
2227    /// Each invocation of this function is guaranteed to return a distinct index. These can be used
2228    /// to store data in the context that can be retrieved later by callbacks, for example.
2229    #[corresponds(SSL_CTX_get_ex_new_index)]
2230    pub fn new_ex_index<T>() -> Result<Index<SslContext, T>, ErrorStack>
2231    where
2232        T: 'static + Sync + Send,
2233    {
2234        unsafe {
2235            ffi::init();
2236            let idx = cvt_n(get_new_idx(Some(free_data_box::<T>)))?;
2237            Ok(Index::from_raw(idx))
2238        }
2239    }
2240
2241    // FIXME should return a result?
2242    fn cached_ex_index<T>() -> Index<SslContext, T>
2243    where
2244        T: 'static + Sync + Send,
2245    {
2246        unsafe {
2247            let idx = *INDEXES
2248                .lock()
2249                .unwrap_or_else(|e| e.into_inner())
2250                .entry(TypeId::of::<T>())
2251                .or_insert_with(|| SslContext::new_ex_index::<T>().unwrap().as_raw());
2252            Index::from_raw(idx)
2253        }
2254    }
2255
2256    /// Gets the list of supported ciphers for protocols before TLSv1.3.
2257    ///
2258    /// See [`ciphers`] for details on the format
2259    ///
2260    /// [`ciphers`]: https://www.openssl.org/docs/manmaster/man1/ciphers.html
2261    #[corresponds(SSL_CTX_get_ciphers)]
2262    #[must_use]
2263    pub fn ciphers(&self) -> Option<&StackRef<SslCipher>> {
2264        unsafe {
2265            let ciphers = ffi::SSL_CTX_get_ciphers(self.as_ptr());
2266            if ciphers.is_null() {
2267                None
2268            } else {
2269                Some(StackRef::from_ptr(ciphers))
2270            }
2271        }
2272    }
2273}
2274
2275impl SslContextRef {
2276    /// Returns the certificate associated with this `SslContext`, if present.
2277    #[corresponds(SSL_CTX_get0_certificate)]
2278    #[must_use]
2279    pub fn certificate(&self) -> Option<&X509Ref> {
2280        self.check_x509();
2281        unsafe {
2282            let ptr = ffi::SSL_CTX_get0_certificate(self.as_ptr());
2283            if ptr.is_null() {
2284                None
2285            } else {
2286                Some(X509Ref::from_ptr(ptr))
2287            }
2288        }
2289    }
2290
2291    /// Returns the private key associated with this `SslContext`, if present.
2292    #[corresponds(SSL_CTX_get0_privatekey)]
2293    #[must_use]
2294    pub fn private_key(&self) -> Option<&PKeyRef<Private>> {
2295        unsafe {
2296            let ptr = ffi::SSL_CTX_get0_privatekey(self.as_ptr());
2297            if ptr.is_null() {
2298                None
2299            } else {
2300                Some(PKeyRef::from_ptr(ptr))
2301            }
2302        }
2303    }
2304
2305    /// Returns a shared reference to the certificate store used for verification.
2306    #[corresponds(SSL_CTX_get_cert_store)]
2307    #[must_use]
2308    pub fn cert_store(&self) -> &X509StoreRef {
2309        self.check_x509();
2310        unsafe { X509StoreRef::from_ptr(ffi::SSL_CTX_get_cert_store(self.as_ptr())) }
2311    }
2312
2313    /// Returns a shared reference to the stack of certificates making up the chain from the leaf.
2314    #[corresponds(SSL_CTX_get_extra_chain_certs)]
2315    #[must_use]
2316    pub fn extra_chain_certs(&self) -> &StackRef<X509> {
2317        unsafe {
2318            let mut chain = ptr::null_mut();
2319            ffi::SSL_CTX_get_extra_chain_certs(self.as_ptr(), &mut chain);
2320            assert!(!chain.is_null());
2321            StackRef::from_ptr(chain)
2322        }
2323    }
2324
2325    /// Returns a reference to the extra data at the specified index.
2326    #[corresponds(SSL_CTX_get_ex_data)]
2327    #[must_use]
2328    pub fn ex_data<T>(&self, index: Index<SslContext, T>) -> Option<&T> {
2329        unsafe {
2330            let data = ffi::SSL_CTX_get_ex_data(self.as_ptr(), index.as_raw());
2331            if data.is_null() {
2332                None
2333            } else {
2334                Some(&*(data as *const T))
2335            }
2336        }
2337    }
2338
2339    // Unsafe because SSL contexts are not guaranteed to be unique, we call
2340    // this only from SslContextBuilder.
2341    #[corresponds(SSL_CTX_get_ex_data)]
2342    unsafe fn ex_data_mut<T>(&mut self, index: Index<SslContext, T>) -> Option<&mut T> {
2343        ffi::SSL_CTX_get_ex_data(self.as_ptr(), index.as_raw())
2344            .cast::<T>()
2345            .as_mut()
2346    }
2347
2348    // Unsafe because SSL contexts are not guaranteed to be unique, we call
2349    // this only from SslContextBuilder.
2350    #[corresponds(SSL_CTX_set_ex_data)]
2351    unsafe fn set_ex_data<T>(&mut self, index: Index<SslContext, T>, data: T) {
2352        unsafe {
2353            let data = Box::into_raw(Box::new(data));
2354            ffi::SSL_CTX_set_ex_data(self.as_ptr(), index.as_raw(), data.cast());
2355        }
2356    }
2357
2358    // Unsafe because SSL contexts are not guaranteed to be unique, we call
2359    // this only from SslContextBuilder.
2360    #[corresponds(SSL_CTX_set_ex_data)]
2361    unsafe fn replace_ex_data<T>(&mut self, index: Index<SslContext, T>, data: T) -> Option<T> {
2362        if let Some(old) = self.ex_data_mut(index) {
2363            return Some(mem::replace(old, data));
2364        }
2365
2366        self.set_ex_data(index, data);
2367
2368        None
2369    }
2370
2371    /// Adds a session to the context's cache.
2372    ///
2373    /// Returns `true` if the session was successfully added to the cache, and `false` if it was already present.
2374    ///
2375    /// # Safety
2376    ///
2377    /// The caller of this method is responsible for ensuring that the session has never been used with another
2378    /// `SslContext` than this one.
2379    #[corresponds(SSL_CTX_add_session)]
2380    #[must_use]
2381    pub unsafe fn add_session(&self, session: &SslSessionRef) -> bool {
2382        ffi::SSL_CTX_add_session(self.as_ptr(), session.as_ptr()) != 0
2383    }
2384
2385    /// Removes a session from the context's cache and marks it as non-resumable.
2386    ///
2387    /// Returns `true` if the session was successfully found and removed, and `false` otherwise.
2388    ///
2389    /// # Safety
2390    ///
2391    /// The caller of this method is responsible for ensuring that the session has never been used with another
2392    /// `SslContext` than this one.
2393    #[corresponds(SSL_CTX_remove_session)]
2394    #[must_use]
2395    pub unsafe fn remove_session(&self, session: &SslSessionRef) -> bool {
2396        ffi::SSL_CTX_remove_session(self.as_ptr(), session.as_ptr()) != 0
2397    }
2398
2399    /// Returns the context's session cache size limit.
2400    ///
2401    /// A value of 0 means that the cache size is unbounded.
2402    #[corresponds(SSL_CTX_sess_get_cache_size)]
2403    #[allow(clippy::useless_conversion)]
2404    #[must_use]
2405    pub fn session_cache_size(&self) -> u64 {
2406        unsafe { ffi::SSL_CTX_sess_get_cache_size(self.as_ptr()).into() }
2407    }
2408
2409    /// Returns the verify mode that was set on this context from [`SslContextBuilder::set_verify`].
2410    ///
2411    /// [`SslContextBuilder::set_verify`]: struct.SslContextBuilder.html#method.set_verify
2412    #[corresponds(SSL_CTX_get_verify_mode)]
2413    #[must_use]
2414    pub fn verify_mode(&self) -> SslVerifyMode {
2415        self.check_x509();
2416        let mode = unsafe { ffi::SSL_CTX_get_verify_mode(self.as_ptr()) };
2417        SslVerifyMode::from_bits(mode).expect("SSL_CTX_get_verify_mode returned invalid mode")
2418    }
2419
2420    /// Assumes that this `SslContext` is configured for X.509 certificates.
2421    ///
2422    /// # Safety
2423    ///
2424    /// BoringSSL will crash if the user calls a function that involves
2425    /// X.509 certificates with an object configured with this method.
2426    /// You most probably don't need it.
2427    pub unsafe fn assume_x509(&mut self) {
2428        self.replace_ex_data(*X509_FLAG_INDEX, true);
2429    }
2430
2431    /// Returns `true` if context is configured for X.509 certificates.
2432    #[must_use]
2433    pub fn has_x509_support(&self) -> bool {
2434        self.ex_data(*X509_FLAG_INDEX).copied().unwrap_or_default()
2435    }
2436
2437    #[track_caller]
2438    fn check_x509(&self) {
2439        assert!(
2440            self.has_x509_support(),
2441            "This context is not configured for X.509 certificates"
2442        );
2443    }
2444
2445    /// Registers a list of ECH keys on the context. This list should contain new and old
2446    /// ECHConfigs to allow stale DNS caches to update. Unlike most `SSL_CTX` APIs, this function
2447    /// is safe to call even after the `SSL_CTX` has been associated with connections on various
2448    /// threads.
2449    #[corresponds(SSL_CTX_set1_ech_keys)]
2450    pub fn set_ech_keys(&self, keys: &SslEchKeys) -> Result<(), ErrorStack> {
2451        unsafe { cvt(ffi::SSL_CTX_set1_ech_keys(self.as_ptr(), keys.as_ptr())) }
2452    }
2453}
2454
2455/// Error returned by the callback to get a session when operation
2456/// could not complete and should be retried later.
2457///
2458/// See [`SslContextBuilder::set_get_session_callback`].
2459#[derive(Debug)]
2460pub struct GetSessionPendingError;
2461
2462/// Information about the state of a cipher.
2463pub struct CipherBits {
2464    /// The number of secret bits used for the cipher.
2465    pub secret: i32,
2466
2467    /// The number of bits processed by the chosen algorithm.
2468    pub algorithm: i32,
2469}
2470
2471#[repr(transparent)]
2472pub struct ClientHello<'ssl>(&'ssl ffi::SSL_CLIENT_HELLO);
2473
2474impl ClientHello<'_> {
2475    /// Returns the data of a given extension, if present.
2476    #[corresponds(SSL_early_callback_ctx_extension_get)]
2477    #[must_use]
2478    pub fn get_extension(&self, ext_type: ExtensionType) -> Option<&[u8]> {
2479        unsafe {
2480            let mut ptr = ptr::null();
2481            let mut len = 0;
2482            let result =
2483                ffi::SSL_early_callback_ctx_extension_get(self.0, ext_type.0, &mut ptr, &mut len);
2484            if result == 0 {
2485                return None;
2486            }
2487            Some(slice::from_raw_parts(ptr, len))
2488        }
2489    }
2490
2491    #[must_use]
2492    pub fn ssl_mut(&mut self) -> &mut SslRef {
2493        unsafe { SslRef::from_ptr_mut(self.0.ssl) }
2494    }
2495
2496    #[must_use]
2497    pub fn ssl(&self) -> &SslRef {
2498        unsafe { SslRef::from_ptr(self.0.ssl) }
2499    }
2500
2501    /// Returns the servername sent by the client via Server Name Indication (SNI).
2502    pub fn servername(&self, type_: NameType) -> Option<&str> {
2503        self.ssl().servername(type_)
2504    }
2505
2506    /// Returns the version sent by the client in its Client Hello record.
2507    #[must_use]
2508    pub fn client_version(&self) -> SslVersion {
2509        SslVersion(self.0.version)
2510    }
2511
2512    /// Returns a string describing the protocol version of the connection.
2513    #[must_use]
2514    pub fn version_str(&self) -> &'static str {
2515        self.ssl().version_str()
2516    }
2517
2518    /// Returns the raw data of the client hello message
2519    pub fn as_bytes(&self) -> &[u8] {
2520        unsafe { slice::from_raw_parts(self.0.client_hello, self.0.client_hello_len) }
2521    }
2522
2523    /// Returns the client random data
2524    #[must_use]
2525    pub fn random(&self) -> &[u8] {
2526        unsafe { slice::from_raw_parts(self.0.random, self.0.random_len) }
2527    }
2528
2529    /// Returns the raw list of ciphers supported by the client in its Client Hello record.
2530    #[must_use]
2531    pub fn ciphers(&self) -> &[u8] {
2532        unsafe { slice::from_raw_parts(self.0.cipher_suites, self.0.cipher_suites_len) }
2533    }
2534}
2535
2536/// Information about a cipher.
2537#[derive(Clone, Copy)]
2538pub struct SslCipher(&'static SslCipherRef);
2539
2540impl SslCipher {
2541    #[corresponds(SSL_get_cipher_by_value)]
2542    #[must_use]
2543    pub fn from_value(value: u16) -> Option<Self> {
2544        unsafe {
2545            let ptr = ffi::SSL_get_cipher_by_value(value);
2546            if ptr.is_null() {
2547                None
2548            } else {
2549                Some(Self::from_ptr(ptr.cast_mut()))
2550            }
2551        }
2552    }
2553}
2554
2555impl Stackable for SslCipher {
2556    type StackType = ffi::stack_st_SSL_CIPHER;
2557}
2558
2559unsafe impl ForeignType for SslCipher {
2560    type CType = ffi::SSL_CIPHER;
2561    type Ref = SslCipherRef;
2562
2563    #[inline]
2564    unsafe fn from_ptr(ptr: *mut ffi::SSL_CIPHER) -> SslCipher {
2565        SslCipher(SslCipherRef::from_ptr(ptr))
2566    }
2567
2568    #[inline]
2569    fn as_ptr(&self) -> *mut ffi::SSL_CIPHER {
2570        self.0.as_ptr()
2571    }
2572}
2573
2574impl Deref for SslCipher {
2575    type Target = SslCipherRef;
2576
2577    fn deref(&self) -> &SslCipherRef {
2578        self.0
2579    }
2580}
2581
2582/// Reference to an [`SslCipher`].
2583///
2584/// [`SslCipher`]: struct.SslCipher.html
2585pub struct SslCipherRef(Opaque);
2586
2587unsafe impl Send for SslCipherRef {}
2588unsafe impl Sync for SslCipherRef {}
2589
2590unsafe impl ForeignTypeRef for SslCipherRef {
2591    type CType = ffi::SSL_CIPHER;
2592}
2593
2594impl SslCipherRef {
2595    /// Returns the IANA number of the cipher.
2596    #[corresponds(SSL_CIPHER_get_protocol_id)]
2597    #[must_use]
2598    pub fn protocol_id(&self) -> u16 {
2599        unsafe { ffi::SSL_CIPHER_get_protocol_id(self.as_ptr()) }
2600    }
2601
2602    /// Returns the name of the cipher.
2603    #[corresponds(SSL_CIPHER_get_name)]
2604    #[must_use]
2605    pub fn name(&self) -> &'static str {
2606        unsafe {
2607            let ptr = ffi::SSL_CIPHER_get_name(self.as_ptr());
2608            CStr::from_ptr(ptr).to_str().unwrap()
2609        }
2610    }
2611
2612    /// Returns the RFC-standard name of the cipher, if one exists.
2613    #[corresponds(SSL_CIPHER_standard_name)]
2614    #[must_use]
2615    pub fn standard_name(&self) -> Option<&'static str> {
2616        unsafe {
2617            let ptr = ffi::SSL_CIPHER_standard_name(self.as_ptr());
2618            if ptr.is_null() {
2619                None
2620            } else {
2621                Some(CStr::from_ptr(ptr).to_str().unwrap())
2622            }
2623        }
2624    }
2625
2626    /// Returns the SSL/TLS protocol version that first defined the cipher.
2627    #[corresponds(SSL_CIPHER_get_version)]
2628    #[must_use]
2629    pub fn version(&self) -> &'static str {
2630        let version = unsafe {
2631            let ptr = ffi::SSL_CIPHER_get_version(self.as_ptr());
2632            CStr::from_ptr(ptr)
2633        };
2634
2635        str::from_utf8(version.to_bytes()).unwrap()
2636    }
2637
2638    /// Returns the number of bits used for the cipher.
2639    #[corresponds(SSL_CIPHER_get_bits)]
2640    #[allow(clippy::useless_conversion)]
2641    #[must_use]
2642    pub fn bits(&self) -> CipherBits {
2643        unsafe {
2644            let mut algo_bits = 0;
2645            let secret_bits = ffi::SSL_CIPHER_get_bits(self.as_ptr(), &mut algo_bits);
2646            CipherBits {
2647                secret: secret_bits.into(),
2648                algorithm: algo_bits.into(),
2649            }
2650        }
2651    }
2652
2653    /// Returns a textual description of the cipher.
2654    #[corresponds(SSL_CIPHER_description)]
2655    #[must_use]
2656    pub fn description(&self) -> String {
2657        unsafe {
2658            // SSL_CIPHER_description requires a buffer of at least 128 bytes.
2659            let mut buf = [0; 128];
2660            let ptr = ffi::SSL_CIPHER_description(self.as_ptr(), buf.as_mut_ptr(), 128);
2661            CStr::from_ptr(ptr).to_string_lossy().into_owned()
2662        }
2663    }
2664
2665    /// Returns one if the cipher uses an AEAD cipher.
2666    #[corresponds(SSL_CIPHER_is_aead)]
2667    #[must_use]
2668    pub fn cipher_is_aead(&self) -> bool {
2669        unsafe { ffi::SSL_CIPHER_is_aead(self.as_ptr()) != 0 }
2670    }
2671
2672    /// Returns the NID corresponding to the cipher's authentication type.
2673    #[corresponds(SSL_CIPHER_get_auth_nid)]
2674    #[must_use]
2675    pub fn cipher_auth_nid(&self) -> Option<Nid> {
2676        let n = unsafe { ffi::SSL_CIPHER_get_auth_nid(self.as_ptr()) };
2677        if n == 0 {
2678            None
2679        } else {
2680            Some(Nid::from_raw(n))
2681        }
2682    }
2683
2684    /// Returns the NID corresponding to the cipher.
2685    #[corresponds(SSL_CIPHER_get_cipher_nid)]
2686    #[must_use]
2687    pub fn cipher_nid(&self) -> Option<Nid> {
2688        let n = unsafe { ffi::SSL_CIPHER_get_cipher_nid(self.as_ptr()) };
2689        if n == 0 {
2690            None
2691        } else {
2692            Some(Nid::from_raw(n))
2693        }
2694    }
2695}
2696
2697foreign_type_and_impl_send_sync! {
2698    type CType = ffi::SSL_SESSION;
2699    fn drop = ffi::SSL_SESSION_free;
2700
2701    /// An encoded SSL session.
2702    ///
2703    /// These can be cached to share sessions across connections.
2704    pub struct SslSession;
2705}
2706
2707impl Clone for SslSession {
2708    fn clone(&self) -> SslSession {
2709        SslSessionRef::to_owned(self)
2710    }
2711}
2712
2713impl SslSession {
2714    from_der! {
2715        /// Deserializes a DER-encoded session structure.
2716        #[corresponds(d2i_SSL_SESSION)]
2717        from_der,
2718        SslSession,
2719        ffi::d2i_SSL_SESSION,
2720        crate::libc_types::c_long
2721    }
2722}
2723
2724impl ToOwned for SslSessionRef {
2725    type Owned = SslSession;
2726
2727    fn to_owned(&self) -> SslSession {
2728        unsafe {
2729            SSL_SESSION_up_ref(self.as_ptr());
2730            SslSession(NonNull::new_unchecked(self.as_ptr()))
2731        }
2732    }
2733}
2734
2735impl SslSessionRef {
2736    /// Returns the SSL session ID.
2737    #[corresponds(SSL_SESSION_get_id)]
2738    #[must_use]
2739    pub fn id(&self) -> &[u8] {
2740        unsafe {
2741            let mut len = 0;
2742            let p = ffi::SSL_SESSION_get_id(self.as_ptr(), &mut len);
2743            slice::from_raw_parts(p, len as usize)
2744        }
2745    }
2746
2747    /// Returns the length of the master key.
2748    #[corresponds(SSL_SESSION_get_master_key)]
2749    #[must_use]
2750    pub fn master_key_len(&self) -> usize {
2751        unsafe { SSL_SESSION_get_master_key(self.as_ptr(), ptr::null_mut(), 0) }
2752    }
2753
2754    /// Copies the master key into the provided buffer.
2755    ///
2756    /// Returns the number of bytes written, or the size of the master key if the buffer is empty.
2757    #[corresponds(SSL_SESSION_get_master_key)]
2758    #[must_use]
2759    pub fn master_key(&self, buf: &mut [u8]) -> usize {
2760        unsafe { SSL_SESSION_get_master_key(self.as_ptr(), buf.as_mut_ptr(), buf.len()) }
2761    }
2762
2763    /// Returns the time at which the session was established, in seconds since the Unix epoch.
2764    #[corresponds(SSL_SESSION_get_time)]
2765    #[allow(clippy::useless_conversion)]
2766    #[must_use]
2767    pub fn time(&self) -> u64 {
2768        unsafe { ffi::SSL_SESSION_get_time(self.as_ptr()) }
2769    }
2770
2771    /// Returns the sessions timeout, in seconds.
2772    ///
2773    /// A session older than this time should not be used for session resumption.
2774    #[corresponds(SSL_SESSION_get_timeout)]
2775    #[allow(clippy::useless_conversion)]
2776    #[must_use]
2777    pub fn timeout(&self) -> u32 {
2778        unsafe { ffi::SSL_SESSION_get_timeout(self.as_ptr()) }
2779    }
2780
2781    /// Returns the session's TLS protocol version.
2782    #[corresponds(SSL_SESSION_get_protocol_version)]
2783    #[must_use]
2784    pub fn protocol_version(&self) -> SslVersion {
2785        unsafe {
2786            let version = ffi::SSL_SESSION_get_protocol_version(self.as_ptr());
2787            SslVersion(version)
2788        }
2789    }
2790
2791    to_der! {
2792        /// Serializes the session into a DER-encoded structure.
2793        #[corresponds(i2d_SSL_SESSION)]
2794        to_der,
2795        ffi::i2d_SSL_SESSION
2796    }
2797}
2798
2799foreign_type_and_impl_send_sync! {
2800    type CType = ffi::SSL;
2801    fn drop = ffi::SSL_free;
2802
2803    /// The state of an SSL/TLS session.
2804    ///
2805    /// `Ssl` objects are created from an [`SslContext`], which provides configuration defaults.
2806    /// These defaults can be overridden on a per-`Ssl` basis, however.
2807    ///
2808    /// [`SslContext`]: struct.SslContext.html
2809    pub struct Ssl;
2810}
2811
2812impl fmt::Debug for Ssl {
2813    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
2814        fmt::Debug::fmt(&**self, fmt)
2815    }
2816}
2817
2818impl Ssl {
2819    /// Returns a new extra data index.
2820    ///
2821    /// Each invocation of this function is guaranteed to return a distinct index. These can be used
2822    /// to store data in the context that can be retrieved later by callbacks, for example.
2823    #[corresponds(SSL_get_ex_new_index)]
2824    pub fn new_ex_index<T>() -> Result<Index<Ssl, T>, ErrorStack>
2825    where
2826        T: 'static + Sync + Send,
2827    {
2828        unsafe {
2829            ffi::init();
2830            let idx = cvt_n(get_new_ssl_idx(Some(free_data_box::<T>)))?;
2831            Ok(Index::from_raw(idx))
2832        }
2833    }
2834
2835    // FIXME should return a result?
2836    fn cached_ex_index<T>() -> Index<Ssl, T>
2837    where
2838        T: 'static + Sync + Send,
2839    {
2840        unsafe {
2841            let idx = *SSL_INDEXES
2842                .lock()
2843                .unwrap_or_else(|e| e.into_inner())
2844                .entry(TypeId::of::<T>())
2845                .or_insert_with(|| Ssl::new_ex_index::<T>().unwrap().as_raw());
2846            Index::from_raw(idx)
2847        }
2848    }
2849
2850    /// Creates a new [`Ssl`].
2851    #[corresponds(SSL_new)]
2852    pub fn new(ctx: &SslContextRef) -> Result<Ssl, ErrorStack> {
2853        unsafe {
2854            let ptr = cvt_p(ffi::SSL_new(ctx.as_ptr()))?;
2855            let mut ssl = Ssl::from_ptr(ptr);
2856            SSL_CTX_up_ref(ctx.as_ptr());
2857            let ctx_owned = SslContext::from_ptr(ctx.as_ptr());
2858            ssl.set_ex_data(*SESSION_CTX_INDEX, ctx_owned);
2859
2860            Ok(ssl)
2861        }
2862    }
2863
2864    /// Initiates a client-side TLS handshake, returning a [`MidHandshakeSslStream`].
2865    ///
2866    /// This method is guaranteed to return without calling any callback defined
2867    /// in the internal [`Ssl`] or [`SslContext`].
2868    ///
2869    /// See [`SslStreamBuilder::setup_connect`] for more details.
2870    ///
2871    /// # Warning
2872    ///
2873    /// BoringSSL's default configuration is insecure. It is highly recommended to use
2874    /// [`SslConnector`] rather than [`Ssl`] directly, as it manages that configuration.
2875    pub fn setup_connect<S>(self, stream: S) -> MidHandshakeSslStream<S>
2876    where
2877        S: Read + Write,
2878    {
2879        SslStreamBuilder::new(self, stream).setup_connect()
2880    }
2881
2882    /// Attempts a client-side TLS handshake.
2883    ///
2884    /// This is a convenience method which combines [`Self::setup_connect`] and
2885    /// [`MidHandshakeSslStream::handshake`].
2886    ///
2887    /// # Warning
2888    ///
2889    /// OpenSSL's default configuration is insecure. It is highly recommended to use
2890    /// [`SslConnector`] rather than `Ssl` directly, as it manages that configuration.
2891    pub fn connect<S>(self, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
2892    where
2893        S: Read + Write,
2894    {
2895        self.setup_connect(stream).handshake()
2896    }
2897
2898    /// Initiates a server-side TLS handshake.
2899    ///
2900    /// This method is guaranteed to return without calling any callback defined
2901    /// in the internal [`Ssl`] or [`SslContext`].
2902    ///
2903    /// See [`SslStreamBuilder::setup_accept`] for more details.
2904    ///
2905    /// # Warning
2906    ///
2907    /// BoringSSL's default configuration is insecure. It is highly recommended to use
2908    /// [`SslAcceptor`] rather than [`Ssl`] directly, as it manages that configuration.
2909    pub fn setup_accept<S>(self, stream: S) -> MidHandshakeSslStream<S>
2910    where
2911        S: Read + Write,
2912    {
2913        SslStreamBuilder::new(self, stream).setup_accept()
2914    }
2915
2916    /// Attempts a server-side TLS handshake.
2917    ///
2918    /// This is a convenience method which combines [`Self::setup_accept`] and
2919    /// [`MidHandshakeSslStream::handshake`].
2920    ///
2921    /// # Warning
2922    ///
2923    /// OpenSSL's default configuration is insecure. It is highly recommended to use
2924    /// `SslAcceptor` rather than `Ssl` directly, as it manages that configuration.
2925    ///
2926    /// [`SSL_accept`]: https://www.openssl.org/docs/manmaster/man3/SSL_accept.html
2927    pub fn accept<S>(self, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
2928    where
2929        S: Read + Write,
2930    {
2931        self.setup_accept(stream).handshake()
2932    }
2933}
2934
2935impl fmt::Debug for SslRef {
2936    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
2937        let mut builder = fmt.debug_struct("Ssl");
2938        builder.field("state", &self.state_string_long());
2939        if self.ssl_context().has_x509_support() {
2940            builder.field("verify_result", &self.verify_result());
2941        }
2942        builder.finish()
2943    }
2944}
2945
2946impl SslRef {
2947    fn get_raw_rbio(&self) -> *mut ffi::BIO {
2948        unsafe { ffi::SSL_get_rbio(self.as_ptr()) }
2949    }
2950
2951    /// Sets the options used by the ongoing session, returning the old set.
2952    ///
2953    /// # Note
2954    ///
2955    /// This *enables* the specified options, but does not disable unspecified options. Use
2956    /// `clear_options` for that.
2957    #[corresponds(SSL_set_options)]
2958    pub fn set_options(&mut self, option: SslOptions) -> SslOptions {
2959        let bits = unsafe { ffi::SSL_set_options(self.as_ptr(), option.bits()) };
2960        SslOptions::from_bits_retain(bits)
2961    }
2962
2963    /// Clears the options used by the ongoing session, returning the old set.
2964    #[corresponds(SSL_clear_options)]
2965    pub fn clear_options(&mut self, option: SslOptions) -> SslOptions {
2966        let bits = unsafe { ffi::SSL_clear_options(self.as_ptr(), option.bits()) };
2967        SslOptions::from_bits_retain(bits)
2968    }
2969
2970    #[corresponds(SSL_set1_curves_list)]
2971    pub fn set_curves_list(&mut self, curves: &str) -> Result<(), ErrorStack> {
2972        let curves = CString::new(curves).map_err(ErrorStack::internal_error)?;
2973        unsafe {
2974            cvt_0i(ffi::SSL_set1_curves_list(
2975                self.as_ptr(),
2976                curves.as_ptr() as *const _,
2977            ))
2978            .map(|_| ())
2979        }
2980    }
2981
2982    /// Returns the [`SslCurve`] used for this `SslRef`.
2983    #[corresponds(SSL_get_curve_id)]
2984    pub fn curve(&self) -> Option<SslCurve> {
2985        let curve_id = unsafe { ffi::SSL_get_curve_id(self.as_ptr()) };
2986        if curve_id == 0 {
2987            return None;
2988        }
2989        Some(SslCurve(curve_id.into()))
2990    }
2991
2992    /// Returns the curve name used for this `SslRef`.
2993    #[corresponds(SSL_get_curve_name)]
2994    #[must_use]
2995    pub fn curve_name(&self) -> Option<&'static str> {
2996        let curve_id = self.curve()?.0;
2997
2998        unsafe {
2999            let ptr = ffi::SSL_get_curve_name(curve_id as u16);
3000            if ptr.is_null() {
3001                return None;
3002            }
3003
3004            CStr::from_ptr(ptr).to_str().ok()
3005        }
3006    }
3007
3008    /// Returns an `ErrorCode` value for the most recent operation on this `SslRef`.
3009    #[corresponds(SSL_get_error)]
3010    #[must_use]
3011    pub fn error_code(&self, ret: c_int) -> ErrorCode {
3012        unsafe { ErrorCode::from_raw(ffi::SSL_get_error(self.as_ptr(), ret)) }
3013    }
3014
3015    /// Like [`SslContextBuilder::set_verify`].
3016    ///
3017    /// [`SslContextBuilder::set_verify`]: struct.SslContextBuilder.html#method.set_verify
3018    #[corresponds(SSL_set_verify)]
3019    pub fn set_verify(&mut self, mode: SslVerifyMode) {
3020        self.ssl_context().check_x509();
3021        unsafe { ffi::SSL_set_verify(self.as_ptr(), c_int::from(mode.bits()), None) }
3022    }
3023
3024    /// Sets the certificate verification depth.
3025    ///
3026    /// If the peer's certificate chain is longer than this value, verification will fail.
3027    #[corresponds(SSL_set_verify_depth)]
3028    pub fn set_verify_depth(&mut self, depth: u32) {
3029        self.ssl_context().check_x509();
3030        unsafe {
3031            ffi::SSL_set_verify_depth(self.as_ptr(), depth as c_int);
3032        }
3033    }
3034
3035    /// Returns the verify mode that was set using `set_verify`.
3036    #[corresponds(SSL_get_verify_mode)]
3037    #[must_use]
3038    pub fn verify_mode(&self) -> SslVerifyMode {
3039        let mode = unsafe { ffi::SSL_get_verify_mode(self.as_ptr()) };
3040        SslVerifyMode::from_bits(mode).expect("SSL_get_verify_mode returned invalid mode")
3041    }
3042
3043    /// Like [`SslContextBuilder::set_verify_callback`].
3044    ///
3045    /// *Warning*: This callback does not replace the default certificate verification
3046    /// process and is, instead, called multiple times in the course of that process.
3047    /// It is very difficult to implement this callback correctly, without inadvertently
3048    /// relying on implementation details or making incorrect assumptions about when the
3049    /// callback is called.
3050    ///
3051    /// Instead, use [`SslContextBuilder::set_custom_verify_callback`] to customize
3052    /// certificate verification. Those callbacks can inspect the peer-sent chain,
3053    /// call [`X509StoreContextRef::verify_cert`] and inspect the result, or perform
3054    /// other operations more straightforwardly.
3055    ///
3056    /// # Panics
3057    ///
3058    /// This method panics if this `Ssl` is associated with a RPK context.
3059    #[corresponds(SSL_set_verify)]
3060    pub fn set_verify_callback<F>(&mut self, mode: SslVerifyMode, callback: F)
3061    where
3062        F: Fn(bool, &mut X509StoreContextRef) -> bool + 'static + Sync + Send,
3063    {
3064        self.ssl_context().check_x509();
3065        unsafe {
3066            // this needs to be in an Arc since the callback can register a new callback!
3067            self.replace_ex_data(Ssl::cached_ex_index(), Arc::new(callback));
3068            ffi::SSL_set_verify(
3069                self.as_ptr(),
3070                c_int::from(mode.bits()),
3071                Some(ssl_raw_verify::<F>),
3072            );
3073        }
3074    }
3075
3076    /// Sets a custom certificate store for verifying peer certificates.
3077    #[corresponds(SSL_set0_verify_cert_store)]
3078    pub fn set_verify_cert_store(&mut self, cert_store: X509Store) -> Result<(), ErrorStack> {
3079        self.ssl_context().check_x509();
3080        unsafe {
3081            cvt(ffi::SSL_set0_verify_cert_store(
3082                self.as_ptr(),
3083                cert_store.into_ptr(),
3084            ))
3085        }
3086    }
3087
3088    /// Like [`SslContextBuilder::set_custom_verify_callback`].
3089    ///
3090    /// # Panics
3091    ///
3092    /// This method panics if this `Ssl` is associated with a RPK context.
3093    #[corresponds(SSL_set_custom_verify)]
3094    pub fn set_custom_verify_callback<F>(&mut self, mode: SslVerifyMode, callback: F)
3095    where
3096        F: Fn(&mut SslRef) -> Result<(), SslVerifyError> + 'static + Sync + Send,
3097    {
3098        self.ssl_context().check_x509();
3099        unsafe {
3100            // this needs to be in an Arc since the callback can register a new callback!
3101            self.replace_ex_data(Ssl::cached_ex_index(), Arc::new(callback));
3102            ffi::SSL_set_custom_verify(
3103                self.as_ptr(),
3104                c_int::from(mode.bits()),
3105                Some(ssl_raw_custom_verify::<F>),
3106            );
3107        }
3108    }
3109
3110    /// Like [`SslContextBuilder::set_tmp_dh`].
3111    ///
3112    /// [`SslContextBuilder::set_tmp_dh`]: struct.SslContextBuilder.html#method.set_tmp_dh
3113    #[corresponds(SSL_set_tmp_dh)]
3114    pub fn set_tmp_dh(&mut self, dh: &DhRef<Params>) -> Result<(), ErrorStack> {
3115        unsafe { cvt(ffi::SSL_set_tmp_dh(self.as_ptr(), dh.as_ptr())) }
3116    }
3117
3118    /// Like [`SslContextBuilder::set_tmp_ecdh`].
3119    ///
3120    /// [`SslContextBuilder::set_tmp_ecdh`]: struct.SslContextBuilder.html#method.set_tmp_ecdh
3121    #[corresponds(SSL_set_tmp_ecdh)]
3122    pub fn set_tmp_ecdh(&mut self, key: &EcKeyRef<Params>) -> Result<(), ErrorStack> {
3123        unsafe { cvt(ffi::SSL_set_tmp_ecdh(self.as_ptr(), key.as_ptr())) }
3124    }
3125
3126    /// Configures whether ClientHello extensions should be permuted.
3127    #[corresponds(SSL_set_permute_extensions)]
3128    pub fn set_permute_extensions(&mut self, enabled: bool) {
3129        unsafe { ffi::SSL_set_permute_extensions(self.as_ptr(), enabled as _) }
3130    }
3131
3132    /// Like [`SslContextBuilder::set_alpn_protos`].
3133    ///
3134    /// [`SslContextBuilder::set_alpn_protos`]: struct.SslContextBuilder.html#method.set_alpn_protos
3135    #[corresponds(SSL_set_alpn_protos)]
3136    pub fn set_alpn_protos(&mut self, protocols: &[u8]) -> Result<(), ErrorStack> {
3137        unsafe {
3138            let r = ffi::SSL_set_alpn_protos(
3139                self.as_ptr(),
3140                protocols.as_ptr(),
3141                try_int(protocols.len())?,
3142            );
3143            // fun fact, SSL_set_alpn_protos has a reversed return code D:
3144            if r == 0 {
3145                Ok(())
3146            } else {
3147                Err(ErrorStack::get())
3148            }
3149        }
3150    }
3151
3152    #[corresponds(SSL_set_record_size_limit)]
3153    pub fn set_record_size_limit(&mut self, value: u16) -> Result<(), ErrorStack> {
3154        unsafe { cvt(ffi::SSL_set_record_size_limit(self.as_ptr(), value) as c_int).map(|_| ()) }
3155    }
3156
3157    #[corresponds(SSL_set_delegated_credential_schemes)]
3158    pub fn set_delegated_credential_schemes(
3159        &mut self,
3160        schemes: &[SslSignatureAlgorithm],
3161    ) -> Result<(), ErrorStack> {
3162        unsafe {
3163            cvt_0i(ffi::SSL_set_delegated_credential_schemes(
3164                self.as_ptr(),
3165                schemes.as_ptr() as *const _,
3166                schemes.len(),
3167            ))
3168            .map(|_| ())
3169        }
3170    }
3171
3172    /// Returns the stack of available SslCiphers for `SSL`, sorted by preference.
3173    #[corresponds(SSL_get_ciphers)]
3174    #[must_use]
3175    pub fn ciphers(&self) -> &StackRef<SslCipher> {
3176        unsafe {
3177            let cipher_list = ffi::SSL_get_ciphers(self.as_ptr());
3178            StackRef::from_ptr(cipher_list)
3179        }
3180    }
3181
3182    /// Returns the current cipher if the session is active.
3183    #[corresponds(SSL_get_current_cipher)]
3184    #[must_use]
3185    pub fn current_cipher(&self) -> Option<&SslCipherRef> {
3186        unsafe {
3187            let ptr = ffi::SSL_get_current_cipher(self.as_ptr());
3188
3189            if ptr.is_null() {
3190                None
3191            } else {
3192                Some(SslCipherRef::from_ptr(ptr.cast_mut()))
3193            }
3194        }
3195    }
3196
3197    /// Returns a short string describing the state of the session.
3198    #[corresponds(SSL_state_string)]
3199    #[must_use]
3200    pub fn state_string(&self) -> &'static str {
3201        let state = unsafe {
3202            let ptr = ffi::SSL_state_string(self.as_ptr());
3203            CStr::from_ptr(ptr)
3204        };
3205
3206        state.to_str().unwrap_or_default()
3207    }
3208
3209    /// Returns a longer string describing the state of the session.
3210    ///
3211    /// Returns empty string if the state wasn't valid UTF-8.
3212    #[corresponds(SSL_state_string_long)]
3213    #[must_use]
3214    pub fn state_string_long(&self) -> &'static str {
3215        let state = unsafe {
3216            let ptr = ffi::SSL_state_string_long(self.as_ptr());
3217            CStr::from_ptr(ptr)
3218        };
3219
3220        state.to_str().unwrap_or_default()
3221    }
3222
3223    /// Sets the host name to be sent to the server for Server Name Indication (SNI).
3224    ///
3225    /// It has no effect for a server-side connection.
3226    #[corresponds(SSL_set_tlsext_host_name)]
3227    pub fn set_hostname(&mut self, hostname: &str) -> Result<(), ErrorStack> {
3228        let cstr = CString::new(hostname).map_err(ErrorStack::internal_error)?;
3229        unsafe { cvt(ffi::SSL_set_tlsext_host_name(self.as_ptr(), cstr.as_ptr())) }
3230    }
3231
3232    /// Returns the peer's certificate, if present.
3233    #[corresponds(SSL_get_peer_certificate)]
3234    #[must_use]
3235    pub fn peer_certificate(&self) -> Option<X509> {
3236        self.ssl_context().check_x509();
3237        unsafe {
3238            let ptr = ffi::SSL_get_peer_certificate(self.as_ptr());
3239            if ptr.is_null() {
3240                None
3241            } else {
3242                Some(X509::from_ptr(ptr))
3243            }
3244        }
3245    }
3246
3247    /// Returns the certificate chain of the peer, if present.
3248    ///
3249    /// On the client side, the chain includes the leaf certificate, but on the server side it does
3250    /// not. Fun!
3251    #[corresponds(SSL_get_peer_certificate)]
3252    #[must_use]
3253    pub fn peer_cert_chain(&self) -> Option<&StackRef<X509>> {
3254        unsafe {
3255            let ptr = ffi::SSL_get_peer_cert_chain(self.as_ptr());
3256            if ptr.is_null() {
3257                None
3258            } else {
3259                Some(StackRef::from_ptr(ptr))
3260            }
3261        }
3262    }
3263
3264    /// Like [`SslContext::certificate`].
3265    #[corresponds(SSL_get_certificate)]
3266    #[must_use]
3267    pub fn certificate(&self) -> Option<&X509Ref> {
3268        self.ssl_context().check_x509();
3269        unsafe {
3270            let ptr = ffi::SSL_get_certificate(self.as_ptr());
3271            if ptr.is_null() {
3272                None
3273            } else {
3274                Some(X509Ref::from_ptr(ptr))
3275            }
3276        }
3277    }
3278
3279    /// Like [`SslContext::private_key`].
3280    #[corresponds(SSL_get_privatekey)]
3281    #[must_use]
3282    pub fn private_key(&self) -> Option<&PKeyRef<Private>> {
3283        unsafe {
3284            let ptr = ffi::SSL_get_privatekey(self.as_ptr());
3285            if ptr.is_null() {
3286                None
3287            } else {
3288                Some(PKeyRef::from_ptr(ptr))
3289            }
3290        }
3291    }
3292
3293    /// Returns the protocol version of the session.
3294    #[corresponds(SSL_version)]
3295    #[must_use]
3296    pub fn version(&self) -> Option<SslVersion> {
3297        unsafe {
3298            let r = ffi::SSL_version(self.as_ptr());
3299            if r == 0 {
3300                None
3301            } else {
3302                r.try_into().ok().map(SslVersion)
3303            }
3304        }
3305    }
3306
3307    /// Returns a string describing the protocol version of the session.
3308    ///
3309    /// This may panic if the string isn't valid UTF-8 for some reason. Use [`Self::version2`] instead.
3310    #[corresponds(SSL_get_version)]
3311    #[must_use]
3312    pub fn version_str(&self) -> &'static str {
3313        let version = unsafe {
3314            let ptr = ffi::SSL_get_version(self.as_ptr());
3315            CStr::from_ptr(ptr)
3316        };
3317
3318        version.to_str().unwrap()
3319    }
3320
3321    /// Sets the minimum supported protocol version.
3322    ///
3323    /// If version is `None`, the default minimum version is used. For BoringSSL this defaults to
3324    /// TLS 1.0.
3325    #[corresponds(SSL_set_min_proto_version)]
3326    pub fn set_min_proto_version(&mut self, version: Option<SslVersion>) -> Result<(), ErrorStack> {
3327        unsafe {
3328            cvt(ffi::SSL_set_min_proto_version(
3329                self.as_ptr(),
3330                version.map_or(0, |v| v.0 as _),
3331            ))
3332        }
3333    }
3334
3335    /// Sets the maximum supported protocol version.
3336    ///
3337    /// If version is `None`, the default maximum version is used. For BoringSSL this is TLS 1.3.
3338    #[corresponds(SSL_set_max_proto_version)]
3339    pub fn set_max_proto_version(&mut self, version: Option<SslVersion>) -> Result<(), ErrorStack> {
3340        unsafe {
3341            cvt(ffi::SSL_set_max_proto_version(
3342                self.as_ptr(),
3343                version.map_or(0, |v| v.0 as _),
3344            ))
3345        }
3346    }
3347
3348    /// Gets the minimum supported protocol version.
3349    #[corresponds(SSL_get_min_proto_version)]
3350    pub fn min_proto_version(&mut self) -> Option<SslVersion> {
3351        unsafe {
3352            let r = ffi::SSL_get_min_proto_version(self.as_ptr());
3353            if r == 0 {
3354                None
3355            } else {
3356                Some(SslVersion(r))
3357            }
3358        }
3359    }
3360
3361    /// Gets the maximum supported protocol version.
3362    #[corresponds(SSL_get_max_proto_version)]
3363    #[must_use]
3364    pub fn max_proto_version(&self) -> Option<SslVersion> {
3365        let r = unsafe { ffi::SSL_get_max_proto_version(self.as_ptr()) };
3366        if r == 0 {
3367            None
3368        } else {
3369            Some(SslVersion(r))
3370        }
3371    }
3372
3373    /// Returns the protocol selected via Application Layer Protocol Negotiation (ALPN).
3374    ///
3375    /// The protocol's name is returned is an opaque sequence of bytes. It is up to the client
3376    /// to interpret it.
3377    #[corresponds(SSL_get0_alpn_selected)]
3378    #[must_use]
3379    pub fn selected_alpn_protocol(&self) -> Option<&[u8]> {
3380        unsafe {
3381            let mut data: *const c_uchar = ptr::null();
3382            let mut len: c_uint = 0;
3383            // Get the negotiated protocol from the SSL instance.
3384            // `data` will point at a `c_uchar` array; `len` will contain the length of this array.
3385            ffi::SSL_get0_alpn_selected(self.as_ptr(), &mut data, &mut len);
3386
3387            if data.is_null() {
3388                None
3389            } else {
3390                Some(slice::from_raw_parts(data, len as usize))
3391            }
3392        }
3393    }
3394
3395    /// Enables the DTLS extension "use_srtp" as defined in RFC5764.
3396    #[corresponds(SSL_set_tlsext_use_srtp)]
3397    pub fn set_tlsext_use_srtp(&mut self, protocols: &str) -> Result<(), ErrorStack> {
3398        unsafe {
3399            let cstr = CString::new(protocols).map_err(ErrorStack::internal_error)?;
3400
3401            let r = ffi::SSL_set_tlsext_use_srtp(self.as_ptr(), cstr.as_ptr());
3402            // fun fact, set_tlsext_use_srtp has a reversed return code D:
3403            if r == 0 {
3404                Ok(())
3405            } else {
3406                Err(ErrorStack::get())
3407            }
3408        }
3409    }
3410
3411    /// Gets all SRTP profiles that are enabled for handshake via set_tlsext_use_srtp
3412    ///
3413    /// DTLS extension "use_srtp" as defined in RFC5764 has to be enabled.
3414    #[corresponds(SSL_get_strp_profiles)]
3415    #[must_use]
3416    pub fn srtp_profiles(&self) -> Option<&StackRef<SrtpProtectionProfile>> {
3417        unsafe {
3418            let chain = ffi::SSL_get_srtp_profiles(self.as_ptr());
3419
3420            if chain.is_null() {
3421                None
3422            } else {
3423                Some(StackRef::from_ptr(chain.cast_mut()))
3424            }
3425        }
3426    }
3427
3428    /// Gets the SRTP profile selected by handshake.
3429    ///
3430    /// DTLS extension "use_srtp" as defined in RFC5764 has to be enabled.
3431    #[corresponds(SSL_get_selected_srtp_profile)]
3432    #[must_use]
3433    pub fn selected_srtp_profile(&self) -> Option<&SrtpProtectionProfileRef> {
3434        unsafe {
3435            let profile = ffi::SSL_get_selected_srtp_profile(self.as_ptr());
3436
3437            if profile.is_null() {
3438                None
3439            } else {
3440                Some(SrtpProtectionProfileRef::from_ptr(profile.cast_mut()))
3441            }
3442        }
3443    }
3444
3445    /// Returns the number of bytes remaining in the currently processed TLS record.
3446    ///
3447    /// If this is greater than 0, the next call to `read` will not call down to the underlying
3448    /// stream.
3449    #[corresponds(SSL_pending)]
3450    #[must_use]
3451    pub fn pending(&self) -> usize {
3452        unsafe { ffi::SSL_pending(self.as_ptr()) as usize }
3453    }
3454
3455    /// Returns the servername sent by the client via Server Name Indication (SNI).
3456    ///
3457    /// It is only useful on the server side.
3458    ///
3459    /// # Note
3460    ///
3461    /// While the SNI specification requires that servernames be valid domain names (and therefore
3462    /// ASCII), OpenSSL does not enforce this restriction. If the servername provided by the client
3463    /// is not valid UTF-8, this function will return `None`. The `servername_raw` method returns
3464    /// the raw bytes and does not have this restriction.
3465    ///
3466    // FIXME maybe rethink in 0.11?
3467    #[corresponds(SSL_get_servername)]
3468    #[must_use]
3469    pub fn servername(&self, type_: NameType) -> Option<&str> {
3470        self.servername_raw(type_)
3471            .and_then(|b| str::from_utf8(b).ok())
3472    }
3473
3474    /// Returns the servername sent by the client via Server Name Indication (SNI).
3475    ///
3476    /// It is only useful on the server side.
3477    ///
3478    /// # Note
3479    ///
3480    /// Unlike `servername`, this method does not require the name be valid UTF-8.
3481    #[corresponds(SSL_get_servername)]
3482    #[must_use]
3483    pub fn servername_raw(&self, type_: NameType) -> Option<&[u8]> {
3484        unsafe {
3485            let name = ffi::SSL_get_servername(self.as_ptr(), type_.0);
3486            if name.is_null() {
3487                None
3488            } else {
3489                Some(CStr::from_ptr(name).to_bytes())
3490            }
3491        }
3492    }
3493
3494    /// Changes the context corresponding to the current connection.
3495    ///
3496    /// It is most commonly used in the Server Name Indication (SNI) callback.
3497    #[corresponds(SSL_set_SSL_CTX)]
3498    pub fn set_ssl_context(&mut self, ctx: &SslContextRef) -> Result<(), ErrorStack> {
3499        assert_eq!(
3500            self.ssl_context().has_x509_support(),
3501            ctx.has_x509_support(),
3502            "X.509 certificate support in old and new contexts doesn't match",
3503        );
3504        unsafe { cvt_p(ffi::SSL_set_SSL_CTX(self.as_ptr(), ctx.as_ptr())).map(|_| ()) }
3505    }
3506
3507    /// Returns the context corresponding to the current connection.
3508    #[corresponds(SSL_get_SSL_CTX)]
3509    #[must_use]
3510    pub fn ssl_context(&self) -> &SslContextRef {
3511        unsafe {
3512            let ssl_ctx = ffi::SSL_get_SSL_CTX(self.as_ptr());
3513            SslContextRef::from_ptr(ssl_ctx)
3514        }
3515    }
3516
3517    /// Returns a mutable reference to the X509 verification configuration.
3518    #[corresponds(SSL_get0_param)]
3519    pub fn verify_param_mut(&mut self) -> &mut X509VerifyParamRef {
3520        self.ssl_context().check_x509();
3521        unsafe { X509VerifyParamRef::from_ptr_mut(ffi::SSL_get0_param(self.as_ptr())) }
3522    }
3523
3524    /// See [`Self::verify_param_mut`].
3525    pub fn param_mut(&mut self) -> &mut X509VerifyParamRef {
3526        self.verify_param_mut()
3527    }
3528
3529    /// Returns the certificate verification result.
3530    #[corresponds(SSL_get_verify_result)]
3531    pub fn verify_result(&self) -> X509VerifyResult {
3532        self.ssl_context().check_x509();
3533        unsafe { X509VerifyError::from_raw(ffi::SSL_get_verify_result(self.as_ptr()) as c_int) }
3534    }
3535
3536    /// Returns a shared reference to the SSL session.
3537    #[corresponds(SSL_get_session)]
3538    #[must_use]
3539    pub fn session(&self) -> Option<&SslSessionRef> {
3540        unsafe {
3541            let p = ffi::SSL_get_session(self.as_ptr());
3542            if p.is_null() {
3543                None
3544            } else {
3545                Some(SslSessionRef::from_ptr(p))
3546            }
3547        }
3548    }
3549
3550    /// Copies the client_random value sent by the client in the TLS handshake into a buffer.
3551    ///
3552    /// Returns the number of bytes copied, or if the buffer is empty, the size of the client_random
3553    /// value.
3554    #[corresponds(SSL_get_client_random)]
3555    pub fn client_random(&self, buf: &mut [u8]) -> usize {
3556        unsafe { ffi::SSL_get_client_random(self.as_ptr(), buf.as_mut_ptr(), buf.len()) }
3557    }
3558
3559    /// Copies the server_random value sent by the server 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 server_random
3562    /// value.
3563    #[corresponds(SSL_get_server_random)]
3564    pub fn server_random(&self, buf: &mut [u8]) -> usize {
3565        unsafe { ffi::SSL_get_server_random(self.as_ptr(), buf.as_mut_ptr(), buf.len()) }
3566    }
3567
3568    /// Derives keying material for application use in accordance to RFC 5705.
3569    #[corresponds(SSL_export_keying_material)]
3570    pub fn export_keying_material(
3571        &self,
3572        out: &mut [u8],
3573        label: &str,
3574        context: Option<&[u8]>,
3575    ) -> Result<(), ErrorStack> {
3576        unsafe {
3577            let (context, contextlen, use_context) = match context {
3578                Some(context) => (context.as_ptr(), context.len(), 1),
3579                None => (ptr::null(), 0, 0),
3580            };
3581            cvt(ffi::SSL_export_keying_material(
3582                self.as_ptr(),
3583                out.as_mut_ptr(),
3584                out.len(),
3585                label.as_ptr().cast::<c_char>(),
3586                label.len(),
3587                context,
3588                contextlen,
3589                use_context,
3590            ))
3591            .map(|_| ())
3592        }
3593    }
3594
3595    /// Sets the session to be used.
3596    ///
3597    /// This should be called before the handshake to attempt to reuse a previously established
3598    /// session. If the server is not willing to reuse the session, a new one will be transparently
3599    /// negotiated.
3600    ///
3601    /// # Safety
3602    ///
3603    /// The caller of this method is responsible for ensuring that the session is associated
3604    /// with the same `SslContext` as this `Ssl`.
3605    #[corresponds(SSL_set_session)]
3606    pub unsafe fn set_session(&mut self, session: &SslSessionRef) -> Result<(), ErrorStack> {
3607        cvt(ffi::SSL_set_session(self.as_ptr(), session.as_ptr()))
3608    }
3609
3610    /// Determines if the session provided to `set_session` was successfully reused.
3611    #[corresponds(SSL_session_reused)]
3612    #[must_use]
3613    pub fn session_reused(&self) -> bool {
3614        unsafe { ffi::SSL_session_reused(self.as_ptr()) != 0 }
3615    }
3616
3617    /// Sets the status response a client wishes the server to reply with.
3618    #[corresponds(SSL_set_tlsext_status_type)]
3619    pub fn set_status_type(&mut self, type_: StatusType) -> Result<(), ErrorStack> {
3620        unsafe {
3621            cvt(ffi::SSL_set_tlsext_status_type(
3622                self.as_ptr(),
3623                type_.as_raw(),
3624            ))
3625        }
3626    }
3627
3628    /// Returns the server's OCSP response, if present.
3629    #[corresponds(SSL_get_tlsext_status_ocsp_resp)]
3630    #[must_use]
3631    pub fn ocsp_status(&self) -> Option<&[u8]> {
3632        unsafe {
3633            let mut p = ptr::null();
3634            let len = ffi::SSL_get_tlsext_status_ocsp_resp(self.as_ptr(), &mut p);
3635
3636            if len == 0 {
3637                None
3638            } else {
3639                Some(slice::from_raw_parts(p, len))
3640            }
3641        }
3642    }
3643
3644    /// Sets the OCSP response to be returned to the client.
3645    #[corresponds(SSL_set_ocsp_response)]
3646    pub fn set_ocsp_status(&mut self, response: &[u8]) -> Result<(), ErrorStack> {
3647        unsafe {
3648            assert!(response.len() <= c_int::MAX as usize);
3649            cvt(ffi::SSL_set_ocsp_response(
3650                self.as_ptr(),
3651                response.as_ptr(),
3652                response.len(),
3653            ))
3654        }
3655    }
3656
3657    /// Determines if this `Ssl` is configured for server-side or client-side use.
3658    #[corresponds(SSL_is_server)]
3659    #[must_use]
3660    pub fn is_server(&self) -> bool {
3661        unsafe { SSL_is_server(self.as_ptr()) != 0 }
3662    }
3663
3664    /// Sets the extra data at the specified index.
3665    ///
3666    /// This can be used to provide data to callbacks registered with the context. Use the
3667    /// `Ssl::new_ex_index` method to create an `Index`.
3668    ///
3669    /// Note that if this method is called multiple times with the same index, any previous
3670    /// value stored in the `SslContextBuilder` will be leaked.
3671    #[corresponds(SSL_set_ex_data)]
3672    pub fn set_ex_data<T>(&mut self, index: Index<Ssl, T>, data: T) {
3673        if let Some(old) = self.ex_data_mut(index) {
3674            *old = data;
3675            return;
3676        }
3677
3678        unsafe {
3679            let data = Box::into_raw(Box::new(data));
3680            ffi::SSL_set_ex_data(self.as_ptr(), index.as_raw(), data.cast());
3681        }
3682    }
3683
3684    /// Sets or overwrites the extra data at the specified index.
3685    ///
3686    /// This can be used to provide data to callbacks registered with the context. Use the
3687    /// `Ssl::new_ex_index` method to create an `Index`.
3688    ///
3689    /// The previous value, if any, will be returned.
3690    #[corresponds(SSL_set_ex_data)]
3691    pub fn replace_ex_data<T>(&mut self, index: Index<Ssl, T>, data: T) -> Option<T> {
3692        if let Some(old) = self.ex_data_mut(index) {
3693            return Some(mem::replace(old, data));
3694        }
3695
3696        self.set_ex_data(index, data);
3697
3698        None
3699    }
3700
3701    /// Returns a reference to the extra data at the specified index.
3702    #[corresponds(SSL_get_ex_data)]
3703    #[must_use]
3704    pub fn ex_data<T>(&self, index: Index<Ssl, T>) -> Option<&T> {
3705        unsafe {
3706            let data = ffi::SSL_get_ex_data(self.as_ptr(), index.as_raw());
3707            if data.is_null() {
3708                None
3709            } else {
3710                Some(&*(data as *const T))
3711            }
3712        }
3713    }
3714
3715    /// Returns a mutable reference to the extra data at the specified index.
3716    #[corresponds(SSL_get_ex_data)]
3717    pub fn ex_data_mut<T>(&mut self, index: Index<Ssl, T>) -> Option<&mut T> {
3718        unsafe {
3719            ffi::SSL_get_ex_data(self.as_ptr(), index.as_raw())
3720                .cast::<T>()
3721                .as_mut()
3722        }
3723    }
3724
3725    /// Copies the contents of the last Finished message sent to the peer into the provided buffer.
3726    ///
3727    /// The total size of the message is returned, so this can be used to determine the size of the
3728    /// buffer required.
3729    #[corresponds(SSL_get_finished)]
3730    pub fn finished(&self, buf: &mut [u8]) -> usize {
3731        unsafe { ffi::SSL_get_finished(self.as_ptr(), buf.as_mut_ptr().cast(), buf.len()) }
3732    }
3733
3734    /// Copies the contents of the last Finished message received from the peer into the provided
3735    /// buffer.
3736    ///
3737    /// The total size of the message is returned, so this can be used to determine the size of the
3738    /// buffer required.
3739    #[corresponds(SSL_get_peer_finished)]
3740    pub fn peer_finished(&self, buf: &mut [u8]) -> usize {
3741        unsafe { ffi::SSL_get_peer_finished(self.as_ptr(), buf.as_mut_ptr().cast(), buf.len()) }
3742    }
3743
3744    /// Determines if the initial handshake has been completed.
3745    #[corresponds(SSL_is_init_finished)]
3746    #[must_use]
3747    pub fn is_init_finished(&self) -> bool {
3748        unsafe { ffi::SSL_is_init_finished(self.as_ptr()) != 0 }
3749    }
3750
3751    /// Sets the MTU used for DTLS connections.
3752    #[corresponds(SSL_set_mtu)]
3753    pub fn set_mtu(&mut self, mtu: u32) -> Result<(), ErrorStack> {
3754        unsafe { cvt(ffi::SSL_set_mtu(self.as_ptr(), mtu as c_uint)) }
3755    }
3756
3757    /// Sets the certificate.
3758    #[corresponds(SSL_use_certificate)]
3759    pub fn set_certificate(&mut self, cert: &X509Ref) -> Result<(), ErrorStack> {
3760        unsafe {
3761            cvt(ffi::SSL_use_certificate(self.as_ptr(), cert.as_ptr()))?;
3762        }
3763
3764        Ok(())
3765    }
3766
3767    /// Sets the list of CA names sent to the client.
3768    ///
3769    /// The CA certificates must still be added to the trust root - they are not automatically set
3770    /// as trusted by this method.
3771    #[corresponds(SSL_set_client_CA_list)]
3772    pub fn set_client_ca_list(&mut self, list: Stack<X509Name>) {
3773        self.ssl_context().check_x509();
3774        unsafe { ffi::SSL_set_client_CA_list(self.as_ptr(), list.as_ptr()) }
3775        mem::forget(list);
3776    }
3777
3778    /// Sets the private key.
3779    #[corresponds(SSL_use_PrivateKey)]
3780    pub fn set_private_key<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack>
3781    where
3782        T: HasPrivate,
3783    {
3784        unsafe { cvt(ffi::SSL_use_PrivateKey(self.as_ptr(), key.as_ptr())) }
3785    }
3786
3787    /// Enables all modes set in `mode` in `SSL`. Returns a bitmask representing the resulting
3788    /// enabled modes.
3789    #[corresponds(SSL_set_mode)]
3790    pub fn set_mode(&mut self, mode: SslMode) -> SslMode {
3791        let bits = unsafe { ffi::SSL_set_mode(self.as_ptr(), mode.bits()) };
3792        SslMode::from_bits_retain(bits)
3793    }
3794
3795    /// Disables all modes set in `mode` in `SSL`. Returns a bitmask representing the resulting
3796    /// enabled modes.
3797    #[corresponds(SSL_clear_mode)]
3798    pub fn clear_mode(&mut self, mode: SslMode) -> SslMode {
3799        let bits = unsafe { ffi::SSL_clear_mode(self.as_ptr(), mode.bits()) };
3800        SslMode::from_bits_retain(bits)
3801    }
3802
3803    /// Appends `cert` to the chain associated with the current certificate of `SSL`.
3804    #[corresponds(SSL_add1_chain_cert)]
3805    pub fn add_chain_cert(&mut self, cert: &X509Ref) -> Result<(), ErrorStack> {
3806        unsafe { cvt(ffi::SSL_add1_chain_cert(self.as_ptr(), cert.as_ptr())) }
3807    }
3808
3809    /// Configures `ech_config_list` on `SSL` for offering ECH during handshakes. If the server
3810    /// cannot decrypt the encrypted ClientHello, `SSL` will instead handshake using
3811    /// the cleartext parameters of the ClientHelloOuter.
3812    ///
3813    /// Clients should use `get_ech_name_override` to verify the server certificate in case of ECH
3814    /// rejection, and follow up with `get_ech_retry_configs` to retry the connection with a fresh
3815    /// set of ECHConfigs. If the retry also fails, clients should report a connection failure.
3816    #[corresponds(SSL_set1_ech_config_list)]
3817    pub fn set_ech_config_list(&mut self, ech_config_list: &[u8]) -> Result<(), ErrorStack> {
3818        unsafe {
3819            cvt_0i(ffi::SSL_set1_ech_config_list(
3820                self.as_ptr(),
3821                ech_config_list.as_ptr(),
3822                ech_config_list.len(),
3823            ))
3824            .map(|_| ())
3825        }
3826    }
3827
3828    /// This function returns a serialized `ECHConfigList` as provided by the
3829    /// server, if one exists.
3830    ///
3831    /// Clients should call this function when handling an `SSL_R_ECH_REJECTED` error code to
3832    /// recover from potential key mismatches. If the result is `Some`, the client should retry the
3833    /// connection using the returned `ECHConfigList`.
3834    #[corresponds(SSL_get0_ech_retry_configs)]
3835    #[must_use]
3836    pub fn get_ech_retry_configs(&self) -> Option<&[u8]> {
3837        unsafe {
3838            let mut data = ptr::null();
3839            let mut len: usize = 0;
3840            ffi::SSL_get0_ech_retry_configs(self.as_ptr(), &mut data, &mut len);
3841
3842            if data.is_null() {
3843                None
3844            } else {
3845                Some(slice::from_raw_parts(data, len))
3846            }
3847        }
3848    }
3849
3850    /// If `SSL` is a client and the server rejects ECH, this function returns the public name
3851    /// associated with the ECHConfig that was used to attempt ECH.
3852    ///
3853    /// Clients should call this function during the certificate verification callback to
3854    /// ensure the server's certificate is valid for the public name, which is required to
3855    /// authenticate retry configs.
3856    #[corresponds(SSL_get0_ech_name_override)]
3857    #[must_use]
3858    pub fn get_ech_name_override(&self) -> Option<&[u8]> {
3859        unsafe {
3860            let mut data: *const c_char = ptr::null();
3861            let mut len: usize = 0;
3862            ffi::SSL_get0_ech_name_override(self.as_ptr(), &mut data, &mut len);
3863
3864            if data.is_null() {
3865                None
3866            } else {
3867                Some(slice::from_raw_parts(data.cast::<u8>(), len))
3868            }
3869        }
3870    }
3871
3872    // Whether or not `SSL` negotiated ECH.
3873    #[corresponds(SSL_ech_accepted)]
3874    pub fn ech_accepted(&self) -> bool {
3875        unsafe { ffi::SSL_ech_accepted(self.as_ptr()) != 0 }
3876    }
3877
3878    // Whether or not to enable ECH grease on `SSL`.
3879    #[corresponds(SSL_set_enable_ech_grease)]
3880    pub fn set_enable_ech_grease(&self, enable: bool) {
3881        let enable = if enable { 1 } else { 0 };
3882
3883        unsafe {
3884            ffi::SSL_set_enable_ech_grease(self.as_ptr(), enable);
3885        }
3886    }
3887
3888    /// Sets the compliance policy on `SSL`.
3889    #[corresponds(SSL_set_compliance_policy)]
3890    pub fn set_compliance_policy(&mut self, policy: CompliancePolicy) -> Result<(), ErrorStack> {
3891        unsafe { cvt_0i(ffi::SSL_set_compliance_policy(self.as_ptr(), policy.0)).map(|_| ()) }
3892    }
3893
3894    /// Adds a credential.
3895    #[corresponds(SSL_add1_credential)]
3896    pub fn add_credential(&mut self, credential: &SslCredentialRef) -> Result<(), ErrorStack> {
3897        unsafe { cvt_0i(ffi::SSL_add1_credential(self.as_ptr(), credential.as_ptr())).map(|_| ()) }
3898    }
3899
3900    /// Sets whether to use the new ALPS codepoint for `SSL`.
3901    #[corresponds(SSL_set_alps_use_new_codepoint)]
3902    pub fn set_alps_use_new_codepoint(&mut self, use_new_codepoint: bool) {
3903        let use_new_codepoint = if use_new_codepoint { 1 } else { 0 };
3904        unsafe {
3905            ffi::SSL_set_alps_use_new_codepoint(self.as_ptr(), use_new_codepoint);
3906        }
3907    }
3908
3909    /// Adds application settings for the given protocol to be sent via ALPS.
3910    #[corresponds(SSL_add_application_settings)]
3911    pub fn add_application_settings(&mut self, alps: &[u8]) -> Result<(), ErrorStack> {
3912        unsafe {
3913            cvt_0i(ffi::SSL_add_application_settings(
3914                self.as_ptr(),
3915                alps.as_ptr(),
3916                alps.len(),
3917                ptr::null(),
3918                0,
3919            ))
3920            .map(|_| ())
3921        }
3922    }
3923}
3924
3925/// An SSL stream midway through the handshake process.
3926#[derive(Debug)]
3927pub struct MidHandshakeSslStream<S> {
3928    stream: SslStream<S>,
3929    error: Error,
3930}
3931
3932impl<S> MidHandshakeSslStream<S> {
3933    /// Returns a shared reference to the inner stream.
3934    #[must_use]
3935    pub fn get_ref(&self) -> &S {
3936        self.stream.get_ref()
3937    }
3938
3939    /// Returns a mutable reference to the inner stream.
3940    pub fn get_mut(&mut self) -> &mut S {
3941        self.stream.get_mut()
3942    }
3943
3944    /// Returns a shared reference to the `Ssl` of the stream.
3945    #[must_use]
3946    pub fn ssl(&self) -> &SslRef {
3947        self.stream.ssl()
3948    }
3949
3950    /// Returns a mutable reference to the `Ssl` of the stream.
3951    pub fn ssl_mut(&mut self) -> &mut SslRef {
3952        self.stream.ssl_mut()
3953    }
3954
3955    /// Returns the underlying error which interrupted this handshake.
3956    #[must_use]
3957    pub fn error(&self) -> &Error {
3958        &self.error
3959    }
3960
3961    /// Consumes `self`, returning its error.
3962    #[must_use]
3963    pub fn into_error(self) -> Error {
3964        self.error
3965    }
3966
3967    /// Returns the source data stream.
3968    #[must_use]
3969    pub fn into_source_stream(self) -> S {
3970        self.stream.into_inner()
3971    }
3972
3973    /// Returns both the error and the source data stream, consuming `self`.
3974    pub fn into_parts(self) -> (Error, S) {
3975        (self.error, self.stream.into_inner())
3976    }
3977
3978    /// Restarts the handshake process.
3979    #[corresponds(SSL_do_handshake)]
3980    pub fn handshake(mut self) -> Result<SslStream<S>, HandshakeError<S>> {
3981        let ret = unsafe { ffi::SSL_do_handshake(self.stream.ssl.as_ptr()) };
3982        if ret > 0 {
3983            Ok(self.stream)
3984        } else {
3985            self.error = self.stream.make_error(ret);
3986            Err(if self.error.would_block() {
3987                HandshakeError::WouldBlock(self)
3988            } else {
3989                HandshakeError::Failure(self)
3990            })
3991        }
3992    }
3993}
3994
3995/// A TLS session over a stream.
3996pub struct SslStream<S> {
3997    ssl: ManuallyDrop<Ssl>,
3998    method: ManuallyDrop<BioMethod>,
3999    _p: PhantomData<S>,
4000}
4001
4002impl<S> Drop for SslStream<S> {
4003    fn drop(&mut self) {
4004        // ssl holds a reference to method internally so it has to drop first
4005        unsafe {
4006            ManuallyDrop::drop(&mut self.ssl);
4007            ManuallyDrop::drop(&mut self.method);
4008        }
4009    }
4010}
4011
4012impl<S> fmt::Debug for SslStream<S>
4013where
4014    S: fmt::Debug,
4015{
4016    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
4017        fmt.debug_struct("SslStream")
4018            .field("stream", &self.get_ref())
4019            .field("ssl", &self.ssl())
4020            .finish()
4021    }
4022}
4023
4024impl<S: Read + Write> SslStream<S> {
4025    /// Creates a new `SslStream`.
4026    ///
4027    /// This function performs no IO; the stream will not have performed any part of the handshake
4028    /// with the peer. The `connect` and `accept` methods can be used to
4029    /// explicitly perform the handshake.
4030    pub fn new(ssl: Ssl, stream: S) -> Result<Self, ErrorStack> {
4031        let (bio, method) = bio::new(stream)?;
4032
4033        unsafe {
4034            ffi::SSL_set_bio(ssl.as_ptr(), bio, bio);
4035        }
4036
4037        Ok(SslStream {
4038            ssl: ManuallyDrop::new(ssl),
4039            method: ManuallyDrop::new(method),
4040            _p: PhantomData,
4041        })
4042    }
4043
4044    /// Constructs an `SslStream` from a pointer to the underlying OpenSSL `SSL` struct.
4045    ///
4046    /// This is useful if the handshake has already been completed elsewhere.
4047    ///
4048    /// # Safety
4049    ///
4050    /// The caller must ensure the pointer is valid.
4051    pub unsafe fn from_raw_parts(ssl: *mut ffi::SSL, stream: S) -> Self {
4052        let ssl = Ssl::from_ptr(ssl);
4053        Self::new(ssl, stream).unwrap()
4054    }
4055
4056    /// Like `read`, but takes a possibly-uninitialized slice.
4057    ///
4058    /// # Safety
4059    ///
4060    /// No portion of `buf` will be de-initialized by this method. If the method returns `Ok(n)`,
4061    /// then the first `n` bytes of `buf` are guaranteed to be initialized.
4062    pub fn read_uninit(&mut self, buf: &mut [MaybeUninit<u8>]) -> io::Result<usize> {
4063        loop {
4064            match self.ssl_read_uninit(buf) {
4065                Ok(n) => return Ok(n),
4066                Err(ref e) if e.code() == ErrorCode::ZERO_RETURN => return Ok(0),
4067                Err(ref e) if e.code() == ErrorCode::SYSCALL && e.io_error().is_none() => {
4068                    return Ok(0);
4069                }
4070                Err(ref e) if e.code() == ErrorCode::WANT_READ && e.io_error().is_none() => {}
4071                Err(e) => {
4072                    return Err(e.into_io_error().unwrap_or_else(io::Error::other));
4073                }
4074            }
4075        }
4076    }
4077
4078    /// Like `read`, but returns an `ssl::Error` rather than an `io::Error`.
4079    ///
4080    /// It is particularly useful with a nonblocking socket, where the error value will identify if
4081    /// OpenSSL is waiting on read or write readiness.
4082    #[corresponds(SSL_read)]
4083    pub fn ssl_read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
4084        // SAFETY: `ssl_read_uninit` does not de-initialize the buffer.
4085        unsafe {
4086            self.ssl_read_uninit(slice::from_raw_parts_mut(
4087                buf.as_mut_ptr().cast::<MaybeUninit<u8>>(),
4088                buf.len(),
4089            ))
4090        }
4091    }
4092
4093    /// Like `read_ssl`, but takes a possibly-uninitialized slice.
4094    ///
4095    /// # Safety
4096    ///
4097    /// No portion of `buf` will be de-initialized by this method. If the method returns `Ok(n)`,
4098    /// then the first `n` bytes of `buf` are guaranteed to be initialized.
4099    pub fn ssl_read_uninit(&mut self, buf: &mut [MaybeUninit<u8>]) -> Result<usize, Error> {
4100        if buf.is_empty() {
4101            return Ok(0);
4102        }
4103
4104        let len = usize::min(c_int::MAX as usize, buf.len()) as c_int;
4105        let ret = unsafe { ffi::SSL_read(self.ssl().as_ptr(), buf.as_mut_ptr().cast(), len) };
4106        if ret > 0 {
4107            Ok(ret as usize)
4108        } else {
4109            Err(self.make_error(ret))
4110        }
4111    }
4112
4113    /// Like `write`, but returns an `ssl::Error` rather than an `io::Error`.
4114    ///
4115    /// It is particularly useful with a nonblocking socket, where the error value will identify if
4116    /// OpenSSL is waiting on read or write readiness.
4117    #[corresponds(SSL_write)]
4118    pub fn ssl_write(&mut self, buf: &[u8]) -> Result<usize, Error> {
4119        if buf.is_empty() {
4120            return Ok(0);
4121        }
4122
4123        let len = usize::min(c_int::MAX as usize, buf.len()) as c_int;
4124        let ret = unsafe { ffi::SSL_write(self.ssl().as_ptr(), buf.as_ptr().cast(), len) };
4125        if ret > 0 {
4126            Ok(ret as usize)
4127        } else {
4128            Err(self.make_error(ret))
4129        }
4130    }
4131
4132    /// Shuts down the session.
4133    ///
4134    /// The shutdown process consists of two steps. The first step sends a close notify message to
4135    /// the peer, after which `ShutdownResult::Sent` is returned. The second step awaits the receipt
4136    /// of a close notify message from the peer, after which `ShutdownResult::Received` is returned.
4137    ///
4138    /// While the connection may be closed after the first step, it is recommended to fully shut the
4139    /// session down. In particular, it must be fully shut down if the connection is to be used for
4140    /// further communication in the future.
4141    #[corresponds(SSL_shutdown)]
4142    pub fn shutdown(&mut self) -> Result<ShutdownResult, Error> {
4143        match unsafe { ffi::SSL_shutdown(self.ssl.as_ptr()) } {
4144            0 => Ok(ShutdownResult::Sent),
4145            1 => Ok(ShutdownResult::Received),
4146            n => Err(self.make_error(n)),
4147        }
4148    }
4149
4150    /// Returns the session's shutdown state.
4151    #[corresponds(SSL_get_shutdown)]
4152    pub fn get_shutdown(&mut self) -> ShutdownState {
4153        unsafe {
4154            let bits = ffi::SSL_get_shutdown(self.ssl.as_ptr());
4155            ShutdownState::from_bits_retain(bits)
4156        }
4157    }
4158
4159    /// Sets the session's shutdown state.
4160    ///
4161    /// This can be used to tell OpenSSL that the session should be cached even if a full two-way
4162    /// shutdown was not completed.
4163    #[corresponds(SSL_set_shutdown)]
4164    pub fn set_shutdown(&mut self, state: ShutdownState) {
4165        unsafe { ffi::SSL_set_shutdown(self.ssl.as_ptr(), state.bits()) }
4166    }
4167
4168    /// Initiates a client-side TLS handshake.
4169    #[corresponds(SSL_connect)]
4170    pub fn connect(&mut self) -> Result<(), Error> {
4171        let ret = unsafe { ffi::SSL_connect(self.ssl.as_ptr()) };
4172        if ret > 0 {
4173            Ok(())
4174        } else {
4175            Err(self.make_error(ret))
4176        }
4177    }
4178
4179    /// Initiates a server-side TLS handshake.
4180    #[corresponds(SSL_accept)]
4181    pub fn accept(&mut self) -> Result<(), Error> {
4182        let ret = unsafe { ffi::SSL_accept(self.ssl.as_ptr()) };
4183        if ret > 0 {
4184            Ok(())
4185        } else {
4186            Err(self.make_error(ret))
4187        }
4188    }
4189
4190    /// Initiates the handshake.
4191    #[corresponds(SSL_do_handshake)]
4192    pub fn do_handshake(&mut self) -> Result<(), Error> {
4193        let ret = unsafe { ffi::SSL_do_handshake(self.ssl.as_ptr()) };
4194        if ret > 0 {
4195            Ok(())
4196        } else {
4197            Err(self.make_error(ret))
4198        }
4199    }
4200}
4201
4202impl<S> SslStream<S> {
4203    fn make_error(&mut self, ret: c_int) -> Error {
4204        self.check_panic();
4205
4206        let code = self.ssl.error_code(ret);
4207
4208        let cause = match code {
4209            ErrorCode::SSL => Some(InnerError::Ssl(ErrorStack::get())),
4210            ErrorCode::SYSCALL => {
4211                let errs = ErrorStack::get();
4212                if errs.errors().is_empty() {
4213                    self.get_bio_error().map(InnerError::Io)
4214                } else {
4215                    Some(InnerError::Ssl(errs))
4216                }
4217            }
4218            ErrorCode::ZERO_RETURN => None,
4219            ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => {
4220                self.get_bio_error().map(InnerError::Io)
4221            }
4222            _ => None,
4223        };
4224
4225        Error { code, cause }
4226    }
4227
4228    fn check_panic(&mut self) {
4229        if let Some(err) = unsafe { bio::take_panic::<S>(self.ssl.get_raw_rbio()) } {
4230            resume_unwind(err)
4231        }
4232    }
4233
4234    fn get_bio_error(&mut self) -> Option<io::Error> {
4235        unsafe { bio::take_error::<S>(self.ssl.get_raw_rbio()) }
4236    }
4237
4238    /// Converts the SslStream to the underlying data stream.
4239    #[must_use]
4240    pub fn into_inner(self) -> S {
4241        unsafe { bio::take_stream::<S>(self.ssl.get_raw_rbio()) }
4242    }
4243
4244    /// Returns a shared reference to the underlying stream.
4245    #[must_use]
4246    pub fn get_ref(&self) -> &S {
4247        unsafe {
4248            let bio = self.ssl.get_raw_rbio();
4249            bio::get_ref(bio)
4250        }
4251    }
4252
4253    /// Returns a mutable reference to the underlying stream.
4254    ///
4255    /// # Warning
4256    ///
4257    /// It is inadvisable to read from or write to the underlying stream as it
4258    /// will most likely corrupt the SSL session.
4259    pub fn get_mut(&mut self) -> &mut S {
4260        unsafe {
4261            let bio = self.ssl.get_raw_rbio();
4262            bio::get_mut(bio)
4263        }
4264    }
4265
4266    /// Returns a shared reference to the `Ssl` object associated with this stream.
4267    #[must_use]
4268    pub fn ssl(&self) -> &SslRef {
4269        &self.ssl
4270    }
4271
4272    /// Returns a mutable reference to the `Ssl` object associated with this stream.
4273    pub fn ssl_mut(&mut self) -> &mut SslRef {
4274        &mut self.ssl
4275    }
4276}
4277
4278impl<S: Read + Write> Read for SslStream<S> {
4279    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
4280        // SAFETY: `read_uninit` does not de-initialize the buffer
4281        unsafe {
4282            self.read_uninit(slice::from_raw_parts_mut(
4283                buf.as_mut_ptr().cast::<MaybeUninit<u8>>(),
4284                buf.len(),
4285            ))
4286        }
4287    }
4288}
4289
4290impl<S: Read + Write> Write for SslStream<S> {
4291    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
4292        loop {
4293            match self.ssl_write(buf) {
4294                Ok(n) => return Ok(n),
4295                Err(ref e) if e.code() == ErrorCode::WANT_READ && e.io_error().is_none() => {}
4296                Err(e) => {
4297                    return Err(e.into_io_error().unwrap_or_else(io::Error::other));
4298                }
4299            }
4300        }
4301    }
4302
4303    fn flush(&mut self) -> io::Result<()> {
4304        self.get_mut().flush()
4305    }
4306}
4307
4308/// A partially constructed `SslStream`, useful for unusual handshakes.
4309pub struct SslStreamBuilder<S> {
4310    inner: SslStream<S>,
4311}
4312
4313impl<S> SslStreamBuilder<S>
4314where
4315    S: Read + Write,
4316{
4317    /// Begin creating an `SslStream` atop `stream`
4318    pub fn new(ssl: Ssl, stream: S) -> Self {
4319        Self {
4320            inner: SslStream::new(ssl, stream).unwrap(),
4321        }
4322    }
4323
4324    /// Configure as an outgoing stream from a client.
4325    #[corresponds(SSL_set_connect_state)]
4326    pub fn set_connect_state(&mut self) {
4327        unsafe { ffi::SSL_set_connect_state(self.inner.ssl.as_ptr()) }
4328    }
4329
4330    /// Configure as an incoming stream to a server.
4331    #[corresponds(SSL_set_accept_state)]
4332    pub fn set_accept_state(&mut self) {
4333        unsafe { ffi::SSL_set_accept_state(self.inner.ssl.as_ptr()) }
4334    }
4335
4336    /// Initiates a client-side TLS handshake, returning a [`MidHandshakeSslStream`].
4337    ///
4338    /// This method calls [`Self::set_connect_state`] and returns without actually
4339    /// initiating the handshake. The caller is then free to call
4340    /// [`MidHandshakeSslStream`] and loop on [`HandshakeError::WouldBlock`].
4341    #[must_use]
4342    pub fn setup_connect(mut self) -> MidHandshakeSslStream<S> {
4343        self.set_connect_state();
4344
4345        MidHandshakeSslStream {
4346            stream: self.inner,
4347            error: Error {
4348                code: ErrorCode::WANT_WRITE,
4349                cause: Some(InnerError::Io(io::Error::new(
4350                    io::ErrorKind::WouldBlock,
4351                    "connect handshake has not started yet",
4352                ))),
4353            },
4354        }
4355    }
4356
4357    /// Attempts a client-side TLS handshake.
4358    ///
4359    /// This is a convenience method which combines [`Self::setup_connect`] and
4360    /// [`MidHandshakeSslStream::handshake`].
4361    pub fn connect(self) -> Result<SslStream<S>, HandshakeError<S>> {
4362        self.setup_connect().handshake()
4363    }
4364
4365    /// Initiates a server-side TLS handshake, returning a [`MidHandshakeSslStream`].
4366    ///
4367    /// This method calls [`Self::set_accept_state`] and returns without actually
4368    /// initiating the handshake. The caller is then free to call
4369    /// [`MidHandshakeSslStream`] and loop on [`HandshakeError::WouldBlock`].
4370    #[must_use]
4371    pub fn setup_accept(mut self) -> MidHandshakeSslStream<S> {
4372        self.set_accept_state();
4373
4374        MidHandshakeSslStream {
4375            stream: self.inner,
4376            error: Error {
4377                code: ErrorCode::WANT_READ,
4378                cause: Some(InnerError::Io(io::Error::new(
4379                    io::ErrorKind::WouldBlock,
4380                    "accept handshake has not started yet",
4381                ))),
4382            },
4383        }
4384    }
4385
4386    /// Attempts a server-side TLS handshake.
4387    ///
4388    /// This is a convenience method which combines [`Self::setup_accept`] and
4389    /// [`MidHandshakeSslStream::handshake`].
4390    pub fn accept(self) -> Result<SslStream<S>, HandshakeError<S>> {
4391        self.setup_accept().handshake()
4392    }
4393
4394    /// Initiates the handshake.
4395    ///
4396    /// This will fail if `set_accept_state` or `set_connect_state` was not called first.
4397    #[corresponds(SSL_do_handshake)]
4398    pub fn handshake(self) -> Result<SslStream<S>, HandshakeError<S>> {
4399        let mut stream = self.inner;
4400        let ret = unsafe { ffi::SSL_do_handshake(stream.ssl.as_ptr()) };
4401        if ret > 0 {
4402            Ok(stream)
4403        } else {
4404            let error = stream.make_error(ret);
4405            Err(if error.would_block() {
4406                HandshakeError::WouldBlock(MidHandshakeSslStream { stream, error })
4407            } else {
4408                HandshakeError::Failure(MidHandshakeSslStream { stream, error })
4409            })
4410        }
4411    }
4412}
4413
4414impl<S> SslStreamBuilder<S> {
4415    /// Returns a shared reference to the underlying stream.
4416    #[must_use]
4417    pub fn get_ref(&self) -> &S {
4418        unsafe {
4419            let bio = self.inner.ssl.get_raw_rbio();
4420            bio::get_ref(bio)
4421        }
4422    }
4423
4424    /// Returns a mutable reference to the underlying stream.
4425    ///
4426    /// # Warning
4427    ///
4428    /// It is inadvisable to read from or write to the underlying stream as it
4429    /// will most likely corrupt the SSL session.
4430    pub fn get_mut(&mut self) -> &mut S {
4431        unsafe {
4432            let bio = self.inner.ssl.get_raw_rbio();
4433            bio::get_mut(bio)
4434        }
4435    }
4436
4437    /// Returns a shared reference to the `Ssl` object associated with this builder.
4438    #[must_use]
4439    pub fn ssl(&self) -> &SslRef {
4440        &self.inner.ssl
4441    }
4442
4443    /// Returns a mutable reference to the `Ssl` object associated with this builder.
4444    pub fn ssl_mut(&mut self) -> &mut SslRef {
4445        &mut self.inner.ssl
4446    }
4447
4448    /// Set the DTLS MTU size.
4449    ///
4450    /// It will be ignored if the value is smaller than the minimum packet size
4451    /// the DTLS protocol requires.
4452    ///
4453    /// # Panics
4454    /// This function panics if the given mtu size can't be represented in a positive `c_long` range
4455    #[deprecated(note = "Use SslRef::set_mtu instead", since = "0.10.30")]
4456    pub fn set_dtls_mtu_size(&mut self, mtu_size: usize) {
4457        unsafe {
4458            let bio = self.inner.ssl.get_raw_rbio();
4459            bio::set_dtls_mtu_size::<S>(bio, mtu_size);
4460        }
4461    }
4462}
4463
4464/// The result of a shutdown request.
4465#[derive(Copy, Clone, Debug, PartialEq, Eq)]
4466pub enum ShutdownResult {
4467    /// A close notify message has been sent to the peer.
4468    Sent,
4469
4470    /// A close notify response message has been received from the peer.
4471    Received,
4472}
4473
4474bitflags! {
4475    /// The shutdown state of a session.
4476    #[derive(Debug, PartialEq, Eq, Clone, Copy, PartialOrd, Ord, Hash)]
4477    pub struct ShutdownState: c_int {
4478        /// A close notify message has been sent to the peer.
4479        const SENT = ffi::SSL_SENT_SHUTDOWN;
4480        /// A close notify message has been received from the peer.
4481        const RECEIVED = ffi::SSL_RECEIVED_SHUTDOWN;
4482    }
4483}
4484
4485/// Describes private key hooks. This is used to off-load signing operations to
4486/// a custom, potentially asynchronous, backend. Metadata about the key such as
4487/// the type and size are parsed out of the certificate.
4488///
4489/// Corresponds to [`ssl_private_key_method_st`].
4490///
4491/// [`ssl_private_key_method_st`]: https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#ssl_private_key_method_st
4492pub trait PrivateKeyMethod: Send + Sync + 'static {
4493    /// Signs the message `input` using the specified signature algorithm.
4494    ///
4495    /// On success, it returns `Ok(written)` where `written` is the number of
4496    /// bytes written into `output`. On failure, it returns
4497    /// `Err(PrivateKeyMethodError::FAILURE)`. If the operation has not completed,
4498    /// it returns `Err(PrivateKeyMethodError::RETRY)`.
4499    ///
4500    /// The caller should arrange for the high-level operation on `ssl` to be
4501    /// retried when the operation is completed. This will result in a call to
4502    /// [`Self::complete`].
4503    fn sign(
4504        &self,
4505        ssl: &mut SslRef,
4506        input: &[u8],
4507        signature_algorithm: SslSignatureAlgorithm,
4508        output: &mut [u8],
4509    ) -> Result<usize, PrivateKeyMethodError>;
4510
4511    /// Decrypts `input`.
4512    ///
4513    /// On success, it returns `Ok(written)` where `written` is the number of
4514    /// bytes written into `output`. On failure, it returns
4515    /// `Err(PrivateKeyMethodError::FAILURE)`. If the operation has not completed,
4516    /// it returns `Err(PrivateKeyMethodError::RETRY)`.
4517    ///
4518    /// The caller should arrange for the high-level operation on `ssl` to be
4519    /// retried when the operation is completed. This will result in a call to
4520    /// [`Self::complete`].
4521    ///
4522    /// This method only works with RSA keys and should perform a raw RSA
4523    /// decryption operation with no padding.
4524    // NOTE(nox): What does it mean that it is an error?
4525    fn decrypt(
4526        &self,
4527        ssl: &mut SslRef,
4528        input: &[u8],
4529        output: &mut [u8],
4530    ) -> Result<usize, PrivateKeyMethodError>;
4531
4532    /// Completes a pending operation.
4533    ///
4534    /// On success, it returns `Ok(written)` where `written` is the number of
4535    /// bytes written into `output`. On failure, it returns
4536    /// `Err(PrivateKeyMethodError::FAILURE)`. If the operation has not completed,
4537    /// it returns `Err(PrivateKeyMethodError::RETRY)`.
4538    ///
4539    /// This method may be called arbitrarily many times before completion.
4540    fn complete(&self, ssl: &mut SslRef, output: &mut [u8])
4541        -> Result<usize, PrivateKeyMethodError>;
4542}
4543
4544/// An error returned from a private key method.
4545#[derive(Debug, Copy, Clone, PartialEq, Eq)]
4546pub struct PrivateKeyMethodError(ffi::ssl_private_key_result_t);
4547
4548impl PrivateKeyMethodError {
4549    /// A fatal error occurred and the handshake should be terminated.
4550    pub const FAILURE: Self = Self(ffi::ssl_private_key_result_t::ssl_private_key_failure);
4551
4552    /// The operation could not be completed and should be retried later.
4553    pub const RETRY: Self = Self(ffi::ssl_private_key_result_t::ssl_private_key_retry);
4554}
4555
4556/// Describes certificate compression algorithm. Implementation MUST implement transformation at least in one direction.
4557pub trait CertificateCompressor: Send + Sync + 'static {
4558    /// An IANA assigned identifier of compression algorithm
4559    const ALGORITHM: CertificateCompressionAlgorithm;
4560
4561    /// Indicates if compressor support compression
4562    const CAN_COMPRESS: bool;
4563
4564    /// Indicates if compressor support decompression
4565    const CAN_DECOMPRESS: bool;
4566
4567    /// Perform compression of `input` buffer and write compressed data to `output`.
4568    #[allow(unused_variables)]
4569    fn compress<W>(&self, input: &[u8], output: &mut W) -> std::io::Result<()>
4570    where
4571        W: std::io::Write,
4572    {
4573        Err(std::io::Error::other("not implemented"))
4574    }
4575
4576    /// Perform decompression of `input` buffer and write compressed data to `output`.
4577    #[allow(unused_variables)]
4578    fn decompress<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
4586use crate::ffi::{SSL_CTX_up_ref, SSL_SESSION_get_master_key, SSL_SESSION_up_ref, SSL_is_server};
4587
4588unsafe fn get_new_idx(f: ffi::CRYPTO_EX_free) -> c_int {
4589    ffi::SSL_CTX_get_ex_new_index(0, ptr::null_mut(), ptr::null_mut(), None, f)
4590}
4591
4592unsafe fn get_new_ssl_idx(f: ffi::CRYPTO_EX_free) -> c_int {
4593    ffi::SSL_get_ex_new_index(0, ptr::null_mut(), ptr::null_mut(), None, f)
4594}
4595
4596fn path_to_cstring(path: &Path) -> Result<CString, ErrorStack> {
4597    CString::new(path.as_os_str().as_encoded_bytes()).map_err(ErrorStack::internal_error)
4598}