variant_ssl/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 openssl::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 openssl::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::cipher_ctx::CipherCtxRef;
61#[cfg(ossl300)]
62use crate::cvt_long;
63use crate::dh::{Dh, DhRef};
64use crate::ec::EcKeyRef;
65use crate::error::ErrorStack;
66use crate::ex_data::Index;
67#[cfg(ossl111)]
68use crate::hash::MessageDigest;
69use crate::hmac::HMacCtxRef;
70#[cfg(ossl300)]
71use crate::mac_ctx::MacCtxRef;
72#[cfg(any(ossl110, libressl270))]
73use crate::nid::Nid;
74use crate::pkey::{HasPrivate, PKeyRef, Params, Private};
75#[cfg(ossl300)]
76use crate::pkey::{PKey, Public};
77use crate::srtp::{SrtpProtectionProfile, SrtpProtectionProfileRef};
78use crate::ssl::bio::BioMethod;
79use crate::ssl::callbacks::*;
80use crate::ssl::error::InnerError;
81use crate::stack::{Stack, StackRef, Stackable};
82use crate::util;
83use crate::util::{ForeignTypeExt, ForeignTypeRefExt};
84use crate::x509::store::{X509Store, X509StoreBuilderRef, X509StoreRef};
85#[cfg(any(ossl102, boringssl, libressl261))]
86use crate::x509::verify::X509VerifyParamRef;
87use crate::x509::{X509Name, X509Ref, X509StoreContextRef, X509VerifyResult, X509};
88use crate::{cvt, cvt_n, cvt_p, init};
89use bitflags::bitflags;
90use cfg_if::cfg_if;
91use foreign_types::{ForeignType, ForeignTypeRef, Opaque};
92use libc::{c_char, c_int, c_long, c_uchar, c_uint, c_void};
93use once_cell::sync::{Lazy, OnceCell};
94use openssl_macros::corresponds;
95use std::any::TypeId;
96use std::collections::HashMap;
97use std::ffi::{CStr, CString};
98use std::fmt;
99use std::io;
100use std::io::prelude::*;
101use std::marker::PhantomData;
102use std::mem::{self, ManuallyDrop, MaybeUninit};
103use std::ops::{Deref, DerefMut};
104use std::panic::resume_unwind;
105use std::path::Path;
106use std::ptr;
107use std::str;
108use std::sync::{Arc, Mutex};
109
110pub use crate::ssl::connector::{
111    ConnectConfiguration, SslAcceptor, SslAcceptorBuilder, SslConnector, SslConnectorBuilder,
112};
113pub use crate::ssl::error::{Error, ErrorCode, HandshakeError};
114
115mod bio;
116mod callbacks;
117#[cfg(boringssl)]
118mod client_hello;
119mod connector;
120mod error;
121#[cfg(test)]
122mod test;
123
124#[cfg(boringssl)]
125pub use client_hello::ClientHello;
126
127/// Returns the OpenSSL name of a cipher corresponding to an RFC-standard cipher name.
128///
129/// If the cipher has no corresponding OpenSSL name, the string `(NONE)` is returned.
130///
131/// Requires OpenSSL 1.1.1 or newer.
132#[corresponds(OPENSSL_cipher_name)]
133#[cfg(ossl111)]
134pub fn cipher_name(std_name: &str) -> &'static str {
135    unsafe {
136        ffi::init();
137
138        let s = CString::new(std_name).unwrap();
139        let ptr = ffi::OPENSSL_cipher_name(s.as_ptr());
140        CStr::from_ptr(ptr).to_str().unwrap()
141    }
142}
143
144cfg_if! {
145    if #[cfg(ossl300)] {
146        type SslOptionsRepr = u64;
147    } else if #[cfg(boringssl)] {
148        type SslOptionsRepr = u32;
149    } else {
150        type SslOptionsRepr = libc::c_ulong;
151    }
152}
153
154bitflags! {
155    /// Options controlling the behavior of an `SslContext`.
156    #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
157    #[repr(transparent)]
158    pub struct SslOptions: SslOptionsRepr {
159        /// Disables a countermeasure against an SSLv3/TLSv1.0 vulnerability affecting CBC ciphers.
160        const DONT_INSERT_EMPTY_FRAGMENTS = ffi::SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS as SslOptionsRepr;
161
162        /// A "reasonable default" set of options which enables compatibility flags.
163        #[cfg(not(boringssl))]
164        const ALL = ffi::SSL_OP_ALL as SslOptionsRepr;
165
166        /// Do not query the MTU.
167        ///
168        /// Only affects DTLS connections.
169        const NO_QUERY_MTU = ffi::SSL_OP_NO_QUERY_MTU as SslOptionsRepr;
170
171        /// Enables Cookie Exchange as described in [RFC 4347 Section 4.2.1].
172        ///
173        /// Only affects DTLS connections.
174        ///
175        /// [RFC 4347 Section 4.2.1]: https://tools.ietf.org/html/rfc4347#section-4.2.1
176        #[cfg(not(boringssl))]
177        const COOKIE_EXCHANGE = ffi::SSL_OP_COOKIE_EXCHANGE as SslOptionsRepr;
178
179        /// Disables the use of session tickets for session resumption.
180        const NO_TICKET = ffi::SSL_OP_NO_TICKET as SslOptionsRepr;
181
182        /// Always start a new session when performing a renegotiation on the server side.
183        #[cfg(not(boringssl))]
184        const NO_SESSION_RESUMPTION_ON_RENEGOTIATION =
185            ffi::SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION as SslOptionsRepr;
186
187        /// Disables the use of TLS compression.
188        #[cfg(not(boringssl))]
189        const NO_COMPRESSION = ffi::SSL_OP_NO_COMPRESSION as SslOptionsRepr;
190
191        /// Allow legacy insecure renegotiation with servers or clients that do not support secure
192        /// renegotiation.
193        const ALLOW_UNSAFE_LEGACY_RENEGOTIATION =
194            ffi::SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION as SslOptionsRepr;
195
196        /// Creates a new key for each session when using ECDHE.
197        ///
198        /// This is always enabled in OpenSSL 1.1.0.
199        const SINGLE_ECDH_USE = ffi::SSL_OP_SINGLE_ECDH_USE as SslOptionsRepr;
200
201        /// Creates a new key for each session when using DHE.
202        ///
203        /// This is always enabled in OpenSSL 1.1.0.
204        const SINGLE_DH_USE = ffi::SSL_OP_SINGLE_DH_USE as SslOptionsRepr;
205
206        /// Use the server's preferences rather than the client's when selecting a cipher.
207        ///
208        /// This has no effect on the client side.
209        const CIPHER_SERVER_PREFERENCE = ffi::SSL_OP_CIPHER_SERVER_PREFERENCE as SslOptionsRepr;
210
211        /// Disables version rollback attach detection.
212        const TLS_ROLLBACK_BUG = ffi::SSL_OP_TLS_ROLLBACK_BUG as SslOptionsRepr;
213
214        /// Disables the use of SSLv2.
215        const NO_SSLV2 = ffi::SSL_OP_NO_SSLv2 as SslOptionsRepr;
216
217        /// Disables the use of SSLv3.
218        const NO_SSLV3 = ffi::SSL_OP_NO_SSLv3 as SslOptionsRepr;
219
220        /// Disables the use of TLSv1.0.
221        const NO_TLSV1 = ffi::SSL_OP_NO_TLSv1 as SslOptionsRepr;
222
223        /// Disables the use of TLSv1.1.
224        const NO_TLSV1_1 = ffi::SSL_OP_NO_TLSv1_1 as SslOptionsRepr;
225
226        /// Disables the use of TLSv1.2.
227        const NO_TLSV1_2 = ffi::SSL_OP_NO_TLSv1_2 as SslOptionsRepr;
228
229        /// Disables the use of TLSv1.3.
230        ///
231        /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer.
232        #[cfg(any(boringssl, ossl111, libressl340))]
233        const NO_TLSV1_3 = ffi::SSL_OP_NO_TLSv1_3 as SslOptionsRepr;
234
235        /// Disables the use of DTLSv1.0
236        ///
237        /// Requires OpenSSL 1.0.2 or LibreSSL 3.3.2 or newer.
238        #[cfg(any(boringssl, ossl102, ossl110, libressl332))]
239        const NO_DTLSV1 = ffi::SSL_OP_NO_DTLSv1 as SslOptionsRepr;
240
241        /// Disables the use of DTLSv1.2.
242        ///
243        /// Requires OpenSSL 1.0.2 or LibreSSL 3.3.2 or newer.
244        #[cfg(any(boringssl, ossl102, ossl110, libressl332))]
245        const NO_DTLSV1_2 = ffi::SSL_OP_NO_DTLSv1_2 as SslOptionsRepr;
246
247        /// Disables the use of all (D)TLS protocol versions.
248        ///
249        /// This can be used as a mask when whitelisting protocol versions.
250        ///
251        /// Requires OpenSSL 1.0.2 or newer.
252        ///
253        /// # Examples
254        ///
255        /// Only support TLSv1.2:
256        ///
257        /// ```rust
258        /// use openssl::ssl::SslOptions;
259        ///
260        /// let options = SslOptions::NO_SSL_MASK & !SslOptions::NO_TLSV1_2;
261        /// ```
262        #[cfg(any(ossl102, ossl110))]
263        const NO_SSL_MASK = ffi::SSL_OP_NO_SSL_MASK as SslOptionsRepr;
264
265        /// Disallow all renegotiation in TLSv1.2 and earlier.
266        ///
267        /// Requires OpenSSL 1.1.0h or newer.
268        #[cfg(any(boringssl, ossl110h))]
269        const NO_RENEGOTIATION = ffi::SSL_OP_NO_RENEGOTIATION as SslOptionsRepr;
270
271        /// Enable TLSv1.3 Compatibility mode.
272        ///
273        /// Requires OpenSSL 1.1.1 or newer. This is on by default in 1.1.1, but a future version
274        /// may have this disabled by default.
275        #[cfg(ossl111)]
276        const ENABLE_MIDDLEBOX_COMPAT = ffi::SSL_OP_ENABLE_MIDDLEBOX_COMPAT as SslOptionsRepr;
277
278        /// Prioritize ChaCha ciphers when preferred by clients.
279        ///
280        /// Temporarily reprioritize ChaCha20-Poly1305 ciphers to the top of the server cipher list
281        /// if a ChaCha20-Poly1305 cipher is at the top of the client cipher list. This helps those
282        /// clients (e.g. mobile) use ChaCha20-Poly1305 if that cipher is anywhere in the server
283        /// cipher list; but still allows other clients to use AES and other ciphers.
284        ///
285        /// Requires enable [`SslOptions::CIPHER_SERVER_PREFERENCE`].
286        /// Requires OpenSSL 1.1.1 or newer.
287        ///
288        /// [`SslOptions::CIPHER_SERVER_PREFERENCE`]: struct.SslOptions.html#associatedconstant.CIPHER_SERVER_PREFERENCE
289        #[cfg(ossl111)]
290        const PRIORITIZE_CHACHA = ffi::SSL_OP_PRIORITIZE_CHACHA as SslOptionsRepr;
291    }
292}
293
294bitflags! {
295    /// Options controlling the behavior of an `SslContext`.
296    #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
297    #[repr(transparent)]
298    pub struct SslMode: SslBitType {
299        /// Enables "short writes".
300        ///
301        /// Normally, a write in OpenSSL will always write out all of the requested data, even if it
302        /// requires more than one TLS record or write to the underlying stream. This option will
303        /// cause a write to return after writing a single TLS record instead.
304        const ENABLE_PARTIAL_WRITE = ffi::SSL_MODE_ENABLE_PARTIAL_WRITE;
305
306        /// Disables a check that the data buffer has not moved between calls when operating in a
307        /// non-blocking context.
308        const ACCEPT_MOVING_WRITE_BUFFER = ffi::SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER;
309
310        /// Enables automatic retries after TLS session events such as renegotiations or heartbeats.
311        ///
312        /// By default, OpenSSL will return a `WantRead` error after a renegotiation or heartbeat.
313        /// This option will cause OpenSSL to automatically continue processing the requested
314        /// operation instead.
315        ///
316        /// Note that `SslStream::read` and `SslStream::write` will automatically retry regardless
317        /// of the state of this option. It only affects `SslStream::ssl_read` and
318        /// `SslStream::ssl_write`.
319        const AUTO_RETRY = ffi::SSL_MODE_AUTO_RETRY;
320
321        /// Disables automatic chain building when verifying a peer's certificate.
322        ///
323        /// TLS peers are responsible for sending the entire certificate chain from the leaf to a
324        /// trusted root, but some will incorrectly not do so. OpenSSL will try to build the chain
325        /// out of certificates it knows of, and this option will disable that behavior.
326        const NO_AUTO_CHAIN = ffi::SSL_MODE_NO_AUTO_CHAIN;
327
328        /// Release memory buffers when the session does not need them.
329        ///
330        /// This saves ~34 KiB of memory for idle streams.
331        const RELEASE_BUFFERS = ffi::SSL_MODE_RELEASE_BUFFERS;
332
333        /// Sends the fake `TLS_FALLBACK_SCSV` cipher suite in the ClientHello message of a
334        /// handshake.
335        ///
336        /// This should only be enabled if a client has failed to connect to a server which
337        /// attempted to downgrade the protocol version of the session.
338        ///
339        /// Do not use this unless you know what you're doing!
340        #[cfg(not(libressl))]
341        const SEND_FALLBACK_SCSV = ffi::SSL_MODE_SEND_FALLBACK_SCSV;
342
343        /// Enable asynchronous processing.
344        ///
345        /// TLS I/O operations may indicate a retry with SSL_ERROR_WANT_ASYNC with this mode set
346        /// if an asynchronous capable engine is used to perform cryptographic operations.
347        ///
348        /// Do not use this unless you know what you're doing!
349        #[cfg(ossl110)]
350        const ASYNC = ffi::SSL_MODE_ASYNC;
351    }
352}
353
354/// A type specifying the kind of protocol an `SslContext` will speak.
355#[derive(Copy, Clone)]
356pub struct SslMethod(*const ffi::SSL_METHOD);
357
358impl SslMethod {
359    /// Support all versions of the TLS protocol.
360    #[corresponds(TLS_method)]
361    pub fn tls() -> SslMethod {
362        unsafe { SslMethod(TLS_method()) }
363    }
364
365    /// Support all versions of the DTLS protocol.
366    #[corresponds(DTLS_method)]
367    pub fn dtls() -> SslMethod {
368        unsafe { SslMethod(DTLS_method()) }
369    }
370
371    /// Support all versions of the TLS protocol, explicitly as a client.
372    #[corresponds(TLS_client_method)]
373    pub fn tls_client() -> SslMethod {
374        unsafe { SslMethod(TLS_client_method()) }
375    }
376
377    /// Support all versions of the TLS protocol, explicitly as a server.
378    #[corresponds(TLS_server_method)]
379    pub fn tls_server() -> SslMethod {
380        unsafe { SslMethod(TLS_server_method()) }
381    }
382
383    #[cfg(tongsuo)]
384    #[corresponds(NTLS_client_method)]
385    pub fn ntls_client() -> SslMethod {
386        unsafe { SslMethod(ffi::NTLS_client_method()) }
387    }
388
389    #[cfg(tongsuo)]
390    #[corresponds(NTLS_server_method)]
391    pub fn ntls_server() -> SslMethod {
392        unsafe { SslMethod(ffi::NTLS_server_method()) }
393    }
394
395    /// Support all versions of the DTLS protocol, explicitly as a client.
396    #[corresponds(DTLS_client_method)]
397    #[cfg(any(boringssl, ossl110, libressl291))]
398    pub fn dtls_client() -> SslMethod {
399        unsafe { SslMethod(DTLS_client_method()) }
400    }
401
402    /// Support all versions of the DTLS protocol, explicitly as a server.
403    #[corresponds(DTLS_server_method)]
404    #[cfg(any(boringssl, ossl110, libressl291))]
405    pub fn dtls_server() -> SslMethod {
406        unsafe { SslMethod(DTLS_server_method()) }
407    }
408
409    /// Constructs an `SslMethod` from a pointer to the underlying OpenSSL value.
410    ///
411    /// # Safety
412    ///
413    /// The caller must ensure the pointer is valid.
414    pub unsafe fn from_ptr(ptr: *const ffi::SSL_METHOD) -> SslMethod {
415        SslMethod(ptr)
416    }
417
418    /// Returns a pointer to the underlying OpenSSL value.
419    #[allow(clippy::trivially_copy_pass_by_ref)]
420    pub fn as_ptr(&self) -> *const ffi::SSL_METHOD {
421        self.0
422    }
423}
424
425unsafe impl Sync for SslMethod {}
426unsafe impl Send for SslMethod {}
427
428bitflags! {
429    /// Options controlling the behavior of certificate verification.
430    #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
431    #[repr(transparent)]
432    pub struct SslVerifyMode: i32 {
433        /// Verifies that the peer's certificate is trusted.
434        ///
435        /// On the server side, this will cause OpenSSL to request a certificate from the client.
436        const PEER = ffi::SSL_VERIFY_PEER;
437
438        /// Disables verification of the peer's certificate.
439        ///
440        /// On the server side, this will cause OpenSSL to not request a certificate from the
441        /// client. On the client side, the certificate will be checked for validity, but the
442        /// negotiation will continue regardless of the result of that check.
443        const NONE = ffi::SSL_VERIFY_NONE;
444
445        /// On the server side, abort the handshake if the client did not send a certificate.
446        ///
447        /// This should be paired with `SSL_VERIFY_PEER`. It has no effect on the client side.
448        const FAIL_IF_NO_PEER_CERT = ffi::SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
449    }
450}
451
452#[cfg(boringssl)]
453type SslBitType = c_int;
454#[cfg(not(boringssl))]
455type SslBitType = c_long;
456
457#[cfg(boringssl)]
458type SslTimeTy = u64;
459#[cfg(not(boringssl))]
460type SslTimeTy = c_long;
461
462bitflags! {
463    /// Options controlling the behavior of session caching.
464    #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
465    #[repr(transparent)]
466    pub struct SslSessionCacheMode: SslBitType {
467        /// No session caching for the client or server takes place.
468        const OFF = ffi::SSL_SESS_CACHE_OFF;
469
470        /// Enable session caching on the client side.
471        ///
472        /// OpenSSL has no way of identifying the proper session to reuse automatically, so the
473        /// application is responsible for setting it explicitly via [`SslRef::set_session`].
474        ///
475        /// [`SslRef::set_session`]: struct.SslRef.html#method.set_session
476        const CLIENT = ffi::SSL_SESS_CACHE_CLIENT;
477
478        /// Enable session caching on the server side.
479        ///
480        /// This is the default mode.
481        const SERVER = ffi::SSL_SESS_CACHE_SERVER;
482
483        /// Enable session caching on both the client and server side.
484        const BOTH = ffi::SSL_SESS_CACHE_BOTH;
485
486        /// Disable automatic removal of expired sessions from the session cache.
487        const NO_AUTO_CLEAR = ffi::SSL_SESS_CACHE_NO_AUTO_CLEAR;
488
489        /// Disable use of the internal session cache for session lookups.
490        const NO_INTERNAL_LOOKUP = ffi::SSL_SESS_CACHE_NO_INTERNAL_LOOKUP;
491
492        /// Disable use of the internal session cache for session storage.
493        const NO_INTERNAL_STORE = ffi::SSL_SESS_CACHE_NO_INTERNAL_STORE;
494
495        /// Disable use of the internal session cache for storage and lookup.
496        const NO_INTERNAL = ffi::SSL_SESS_CACHE_NO_INTERNAL;
497    }
498}
499
500#[cfg(ossl111)]
501bitflags! {
502    /// Which messages and under which conditions an extension should be added or expected.
503    #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
504    #[repr(transparent)]
505    pub struct ExtensionContext: c_uint {
506        /// This extension is only allowed in TLS
507        const TLS_ONLY = ffi::SSL_EXT_TLS_ONLY;
508        /// This extension is only allowed in DTLS
509        const DTLS_ONLY = ffi::SSL_EXT_DTLS_ONLY;
510        /// Some extensions may be allowed in DTLS but we don't implement them for it
511        const TLS_IMPLEMENTATION_ONLY = ffi::SSL_EXT_TLS_IMPLEMENTATION_ONLY;
512        /// Most extensions are not defined for SSLv3 but EXT_TYPE_renegotiate is
513        const SSL3_ALLOWED = ffi::SSL_EXT_SSL3_ALLOWED;
514        /// Extension is only defined for TLS1.2 and below
515        const TLS1_2_AND_BELOW_ONLY = ffi::SSL_EXT_TLS1_2_AND_BELOW_ONLY;
516        /// Extension is only defined for TLS1.3 and above
517        const TLS1_3_ONLY = ffi::SSL_EXT_TLS1_3_ONLY;
518        /// Ignore this extension during parsing if we are resuming
519        const IGNORE_ON_RESUMPTION = ffi::SSL_EXT_IGNORE_ON_RESUMPTION;
520        const CLIENT_HELLO = ffi::SSL_EXT_CLIENT_HELLO;
521        /// Really means TLS1.2 or below
522        const TLS1_2_SERVER_HELLO = ffi::SSL_EXT_TLS1_2_SERVER_HELLO;
523        const TLS1_3_SERVER_HELLO = ffi::SSL_EXT_TLS1_3_SERVER_HELLO;
524        const TLS1_3_ENCRYPTED_EXTENSIONS = ffi::SSL_EXT_TLS1_3_ENCRYPTED_EXTENSIONS;
525        const TLS1_3_HELLO_RETRY_REQUEST = ffi::SSL_EXT_TLS1_3_HELLO_RETRY_REQUEST;
526        const TLS1_3_CERTIFICATE = ffi::SSL_EXT_TLS1_3_CERTIFICATE;
527        const TLS1_3_NEW_SESSION_TICKET = ffi::SSL_EXT_TLS1_3_NEW_SESSION_TICKET;
528        const TLS1_3_CERTIFICATE_REQUEST = ffi::SSL_EXT_TLS1_3_CERTIFICATE_REQUEST;
529    }
530}
531
532/// TLS Extension Type
533#[derive(Copy, Clone)]
534pub struct TlsExtType(c_uint);
535
536impl TlsExtType {
537    /// server name.
538    ///
539    /// This corresponds to `TLSEXT_TYPE_server_name`.
540    pub const SERVER_NAME: TlsExtType = TlsExtType(ffi::TLSEXT_TYPE_server_name as _);
541
542    /// application layer protocol negotiation.
543    ///
544    /// This corresponds to `TLSEXT_TYPE_application_layer_protocol_negotiation`.
545    pub const ALPN: TlsExtType =
546        TlsExtType(ffi::TLSEXT_TYPE_application_layer_protocol_negotiation as _);
547
548    /// Constructs an `TlsExtType` from a raw value.
549    pub fn from_raw(raw: c_uint) -> TlsExtType {
550        TlsExtType(raw)
551    }
552
553    /// Returns the raw value represented by this type.
554    #[allow(clippy::trivially_copy_pass_by_ref)]
555    pub fn as_raw(&self) -> c_uint {
556        self.0
557    }
558}
559
560/// An identifier of the format of a certificate or key file.
561#[derive(Copy, Clone)]
562pub struct SslFiletype(c_int);
563
564impl SslFiletype {
565    /// The PEM format.
566    ///
567    /// This corresponds to `SSL_FILETYPE_PEM`.
568    pub const PEM: SslFiletype = SslFiletype(ffi::SSL_FILETYPE_PEM);
569
570    /// The ASN1 format.
571    ///
572    /// This corresponds to `SSL_FILETYPE_ASN1`.
573    pub const ASN1: SslFiletype = SslFiletype(ffi::SSL_FILETYPE_ASN1);
574
575    /// Constructs an `SslFiletype` from a raw OpenSSL value.
576    pub fn from_raw(raw: c_int) -> SslFiletype {
577        SslFiletype(raw)
578    }
579
580    /// Returns the raw OpenSSL value represented by this type.
581    #[allow(clippy::trivially_copy_pass_by_ref)]
582    pub fn as_raw(&self) -> c_int {
583        self.0
584    }
585}
586
587/// An identifier of a certificate status type.
588#[derive(Copy, Clone)]
589pub struct StatusType(c_int);
590
591impl StatusType {
592    /// An OSCP status.
593    pub const OCSP: StatusType = StatusType(ffi::TLSEXT_STATUSTYPE_ocsp);
594
595    /// Constructs a `StatusType` from a raw OpenSSL value.
596    pub fn from_raw(raw: c_int) -> StatusType {
597        StatusType(raw)
598    }
599
600    /// Returns the raw OpenSSL value represented by this type.
601    #[allow(clippy::trivially_copy_pass_by_ref)]
602    pub fn as_raw(&self) -> c_int {
603        self.0
604    }
605}
606
607/// An identifier of a session name type.
608#[derive(Copy, Clone)]
609pub struct NameType(c_int);
610
611impl NameType {
612    /// A host name.
613    pub const HOST_NAME: NameType = NameType(ffi::TLSEXT_NAMETYPE_host_name);
614
615    /// Constructs a `StatusType` from a raw OpenSSL value.
616    pub fn from_raw(raw: c_int) -> StatusType {
617        StatusType(raw)
618    }
619
620    /// Returns the raw OpenSSL value represented by this type.
621    #[allow(clippy::trivially_copy_pass_by_ref)]
622    pub fn as_raw(&self) -> c_int {
623        self.0
624    }
625}
626
627static INDEXES: Lazy<Mutex<HashMap<TypeId, c_int>>> = Lazy::new(|| Mutex::new(HashMap::new()));
628static SSL_INDEXES: Lazy<Mutex<HashMap<TypeId, c_int>>> = Lazy::new(|| Mutex::new(HashMap::new()));
629static SESSION_CTX_INDEX: OnceCell<Index<Ssl, SslContext>> = OnceCell::new();
630
631fn try_get_session_ctx_index() -> Result<&'static Index<Ssl, SslContext>, ErrorStack> {
632    SESSION_CTX_INDEX.get_or_try_init(Ssl::new_ex_index)
633}
634
635unsafe extern "C" fn free_data_box<T>(
636    _parent: *mut c_void,
637    ptr: *mut c_void,
638    _ad: *mut ffi::CRYPTO_EX_DATA,
639    _idx: c_int,
640    _argl: c_long,
641    _argp: *mut c_void,
642) {
643    if !ptr.is_null() {
644        let _ = Box::<T>::from_raw(ptr as *mut T);
645    }
646}
647
648/// An error returned from the SNI callback.
649#[derive(Debug, Copy, Clone, PartialEq, Eq)]
650pub struct SniError(c_int);
651
652impl SniError {
653    /// Abort the handshake with a fatal alert.
654    pub const ALERT_FATAL: SniError = SniError(ffi::SSL_TLSEXT_ERR_ALERT_FATAL);
655
656    /// Send a warning alert to the client and continue the handshake.
657    pub const ALERT_WARNING: SniError = SniError(ffi::SSL_TLSEXT_ERR_ALERT_WARNING);
658
659    pub const NOACK: SniError = SniError(ffi::SSL_TLSEXT_ERR_NOACK);
660}
661
662/// An SSL/TLS alert.
663#[derive(Debug, Copy, Clone, PartialEq, Eq)]
664pub struct SslAlert(c_int);
665
666impl SslAlert {
667    /// Alert 112 - `unrecognized_name`.
668    pub const UNRECOGNIZED_NAME: SslAlert = SslAlert(ffi::SSL_AD_UNRECOGNIZED_NAME);
669    pub const ILLEGAL_PARAMETER: SslAlert = SslAlert(ffi::SSL_AD_ILLEGAL_PARAMETER);
670    pub const DECODE_ERROR: SslAlert = SslAlert(ffi::SSL_AD_DECODE_ERROR);
671    pub const NO_APPLICATION_PROTOCOL: SslAlert = SslAlert(ffi::SSL_AD_NO_APPLICATION_PROTOCOL);
672}
673
674/// An error returned from an ALPN selection callback.
675///
676/// Requires BoringSSL or OpenSSL 1.0.2 or LibreSSL 2.6.1 or newer.
677#[cfg(any(ossl102, libressl261, boringssl))]
678#[derive(Debug, Copy, Clone, PartialEq, Eq)]
679pub struct AlpnError(c_int);
680
681#[cfg(any(ossl102, libressl261, boringssl))]
682impl AlpnError {
683    /// Terminate the handshake with a fatal alert.
684    pub const ALERT_FATAL: AlpnError = AlpnError(ffi::SSL_TLSEXT_ERR_ALERT_FATAL);
685
686    /// Do not select a protocol, but continue the handshake.
687    pub const NOACK: AlpnError = AlpnError(ffi::SSL_TLSEXT_ERR_NOACK);
688}
689
690/// An error returned from a client hello callback.
691///
692/// Requires OpenSSL 1.1.1 or newer.
693#[cfg(ossl111)]
694#[derive(Debug, Copy, Clone, PartialEq, Eq)]
695pub struct ClientHelloError(c_int);
696
697#[cfg(ossl111)]
698impl ClientHelloError {
699    /// Terminate the connection.
700    pub const ERROR: ClientHelloError = ClientHelloError(ffi::SSL_CLIENT_HELLO_ERROR);
701
702    /// Return from the handshake with an `ErrorCode::WANT_CLIENT_HELLO_CB` error.
703    pub const RETRY: ClientHelloError = ClientHelloError(ffi::SSL_CLIENT_HELLO_RETRY);
704}
705
706/// Session Ticket Key CB result type
707#[derive(Debug, Copy, Clone, PartialEq, Eq)]
708pub struct TicketKeyStatus(c_int);
709
710impl TicketKeyStatus {
711    /// Session Ticket Key is not set/retrieved for current session
712    pub const FAILED: TicketKeyStatus = TicketKeyStatus(0);
713    /// Session Ticket Key is set, and no renew is needed
714    pub const SUCCESS: TicketKeyStatus = TicketKeyStatus(1);
715    /// Session Ticket Key is set, and a new ticket will be needed
716    pub const SUCCESS_AND_RENEW: TicketKeyStatus = TicketKeyStatus(2);
717}
718
719/// An error returned from a certificate selection callback.
720#[derive(Debug, Copy, Clone, PartialEq, Eq)]
721#[cfg(boringssl)]
722pub struct SelectCertError(ffi::ssl_select_cert_result_t);
723
724#[cfg(boringssl)]
725impl SelectCertError {
726    /// A fatal error occurred and the handshake should be terminated.
727    pub const ERROR: Self = Self(ffi::ssl_select_cert_result_t_ssl_select_cert_error);
728
729    /// The operation could not be completed and should be retried later.
730    pub const RETRY: Self = Self(ffi::ssl_select_cert_result_t_ssl_select_cert_retry);
731
732    /// Although an encrypted ClientHelloInner was decrypted, it should be discarded.
733    /// The certificate selection callback will then be called again, passing in the
734    /// ClientHelloOuter instead. From there, the handshake will proceed
735    /// without retry_configs, to signal to the client to disable ECH.
736    /// This value may only be returned when |SSL_ech_accepted| returnes one.
737    #[cfg(bssl_google)]
738    pub const DISABLE_ECH: Self = Self(ffi::ssl_select_cert_result_t_ssl_select_cert_disable_ech);
739}
740
741/// SSL CT validation mode.
742#[cfg(ossl111)]
743#[derive(Debug, Copy, Clone, PartialEq, Eq)]
744pub struct SslCtValidationMode(c_int);
745
746#[cfg(ossl111)]
747impl SslCtValidationMode {
748    pub const PERMISSIVE: SslCtValidationMode =
749        SslCtValidationMode(ffi::SSL_CT_VALIDATION_PERMISSIVE as c_int);
750    pub const STRICT: SslCtValidationMode =
751        SslCtValidationMode(ffi::SSL_CT_VALIDATION_STRICT as c_int);
752}
753
754/// TLS Certificate Compression Algorithm IDs, defined by IANA
755#[derive(Debug, Copy, Clone, PartialEq, Eq)]
756pub struct CertCompressionAlgorithm(c_int);
757
758impl CertCompressionAlgorithm {
759    pub const ZLIB: CertCompressionAlgorithm = CertCompressionAlgorithm(1);
760    pub const BROTLI: CertCompressionAlgorithm = CertCompressionAlgorithm(2);
761    pub const ZSTD: CertCompressionAlgorithm = CertCompressionAlgorithm(3);
762}
763
764/// An SSL/TLS protocol version.
765#[derive(Debug, Copy, Clone, PartialEq, Eq)]
766pub struct SslVersion(c_int);
767
768impl SslVersion {
769    /// SSLv3
770    pub const SSL3: SslVersion = SslVersion(ffi::SSL3_VERSION);
771
772    /// TLSv1.0
773    pub const TLS1: SslVersion = SslVersion(ffi::TLS1_VERSION);
774
775    /// TLSv1.1
776    pub const TLS1_1: SslVersion = SslVersion(ffi::TLS1_1_VERSION);
777
778    /// TLSv1.2
779    pub const TLS1_2: SslVersion = SslVersion(ffi::TLS1_2_VERSION);
780
781    /// TLSv1.3
782    ///
783    /// Requires BoringSSL or OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer.
784    #[cfg(any(ossl111, libressl340, boringssl))]
785    pub const TLS1_3: SslVersion = SslVersion(ffi::TLS1_3_VERSION);
786
787    #[cfg(tongsuo)]
788    pub const NTLS1_1: SslVersion = SslVersion(ffi::NTLS1_1_VERSION);
789
790    /// DTLSv1.0
791    ///
792    /// DTLS 1.0 corresponds to TLS 1.1.
793    pub const DTLS1: SslVersion = SslVersion(ffi::DTLS1_VERSION);
794
795    /// DTLSv1.2
796    ///
797    /// DTLS 1.2 corresponds to TLS 1.2 to harmonize versions. There was never a DTLS 1.1.
798    #[cfg(any(ossl102, libressl332, boringssl))]
799    pub const DTLS1_2: SslVersion = SslVersion(ffi::DTLS1_2_VERSION);
800}
801
802cfg_if! {
803    if #[cfg(boringssl)] {
804        type SslCacheTy = i64;
805        type SslCacheSize = libc::c_ulong;
806        type MtuTy = u32;
807        type ModeTy = u32;
808        type SizeTy = usize;
809    } else {
810        type SslCacheTy = i64;
811        type SslCacheSize = c_long;
812        type MtuTy = c_long;
813        type ModeTy = c_long;
814        type SizeTy = u32;
815    }
816}
817
818/// A standard implementation of protocol selection for Application Layer Protocol Negotiation
819/// (ALPN).
820///
821/// `server` should contain the server's list of supported protocols and `client` the client's. They
822/// must both be in the ALPN wire format. See the documentation for
823/// [`SslContextBuilder::set_alpn_protos`] for details.
824///
825/// It will select the first protocol supported by the server which is also supported by the client.
826///
827/// [`SslContextBuilder::set_alpn_protos`]: struct.SslContextBuilder.html#method.set_alpn_protos
828#[corresponds(SSL_select_next_proto)]
829pub fn select_next_proto<'a>(server: &'a [u8], client: &'a [u8]) -> Option<&'a [u8]> {
830    unsafe {
831        let mut out = ptr::null_mut();
832        let mut outlen = 0;
833        let r = ffi::SSL_select_next_proto(
834            &mut out,
835            &mut outlen,
836            server.as_ptr(),
837            server.len() as c_uint,
838            client.as_ptr(),
839            client.len() as c_uint,
840        );
841        if r == ffi::OPENSSL_NPN_NEGOTIATED {
842            Some(util::from_raw_parts(out as *const u8, outlen as usize))
843        } else {
844            None
845        }
846    }
847}
848
849/// A builder for `SslContext`s.
850pub struct SslContextBuilder(SslContext);
851
852impl SslContextBuilder {
853    /// Creates a new `SslContextBuilder`.
854    #[corresponds(SSL_CTX_new)]
855    pub fn new(method: SslMethod) -> Result<SslContextBuilder, ErrorStack> {
856        unsafe {
857            init();
858            let ctx = cvt_p(ffi::SSL_CTX_new(method.as_ptr()))?;
859
860            Ok(SslContextBuilder::from_ptr(ctx))
861        }
862    }
863
864    /// Creates an `SslContextBuilder` from a pointer to a raw OpenSSL value.
865    ///
866    /// # Safety
867    ///
868    /// The caller must ensure that the pointer is valid and uniquely owned by the builder.
869    pub unsafe fn from_ptr(ctx: *mut ffi::SSL_CTX) -> SslContextBuilder {
870        SslContextBuilder(SslContext::from_ptr(ctx))
871    }
872
873    /// Returns a pointer to the raw OpenSSL value.
874    pub fn as_ptr(&self) -> *mut ffi::SSL_CTX {
875        self.0.as_ptr()
876    }
877
878    #[cfg(tongsuo)]
879    #[corresponds(SSL_CTX_enable_ntls)]
880    pub fn enable_ntls(&mut self) {
881        unsafe { ffi::SSL_CTX_enable_ntls(self.as_ptr()) }
882    }
883
884    #[cfg(tongsuo)]
885    #[corresponds(SSL_CTX_disable_ntls)]
886    pub fn disable_ntls(&mut self) {
887        unsafe { ffi::SSL_CTX_disable_ntls(self.as_ptr()) }
888    }
889
890    #[cfg(all(tongsuo, ossl300))]
891    #[corresponds(SSL_CTX_enable_force_ntls)]
892    pub fn enable_force_ntls(&mut self) {
893        unsafe { ffi::SSL_CTX_enable_force_ntls(self.as_ptr()) }
894    }
895
896    #[cfg(all(tongsuo, ossl300))]
897    #[corresponds(SSL_CTX_disable_force_ntls)]
898    pub fn disable_force_ntls(&mut self) {
899        unsafe { ffi::SSL_CTX_disable_force_ntls(self.as_ptr()) }
900    }
901
902    #[cfg(tongsuo)]
903    #[corresponds(SSL_CTX_enable_sm_tls13_strict)]
904    pub fn enable_sm_tls13_strict(&mut self) {
905        unsafe { ffi::SSL_CTX_enable_sm_tls13_strict(self.as_ptr()) }
906    }
907
908    #[cfg(tongsuo)]
909    #[corresponds(SSL_CTX_disable_sm_tls13_strict)]
910    pub fn disable_sm_tls13_strict(&mut self) {
911        unsafe { ffi::SSL_CTX_disable_sm_tls13_strict(self.as_ptr()) }
912    }
913
914    /// Configures the certificate verification method for new connections.
915    #[corresponds(SSL_CTX_set_verify)]
916    pub fn set_verify(&mut self, mode: SslVerifyMode) {
917        unsafe {
918            ffi::SSL_CTX_set_verify(self.as_ptr(), mode.bits() as c_int, None);
919        }
920    }
921
922    /// Configures the certificate verification method for new connections and
923    /// registers a verification callback.
924    ///
925    /// The callback is passed a boolean indicating if OpenSSL's internal verification succeeded as
926    /// well as a reference to the `X509StoreContext` which can be used to examine the certificate
927    /// chain. It should return a boolean indicating if verification succeeded.
928    #[corresponds(SSL_CTX_set_verify)]
929    pub fn set_verify_callback<F>(&mut self, mode: SslVerifyMode, verify: F)
930    where
931        F: Fn(bool, &mut X509StoreContextRef) -> bool + 'static + Sync + Send,
932    {
933        unsafe {
934            self.set_ex_data(SslContext::cached_ex_index::<F>(), verify);
935            ffi::SSL_CTX_set_verify(self.as_ptr(), mode.bits() as c_int, Some(raw_verify::<F>));
936        }
937    }
938
939    /// Configures the server name indication (SNI) callback for new connections.
940    ///
941    /// SNI is used to allow a single server to handle requests for multiple domains, each of which
942    /// has its own certificate chain and configuration.
943    ///
944    /// Obtain the server name with the `servername` method and then set the corresponding context
945    /// with `set_ssl_context`
946    #[corresponds(SSL_CTX_set_tlsext_servername_callback)]
947    // FIXME tlsext prefix?
948    pub fn set_servername_callback<F>(&mut self, callback: F)
949    where
950        F: Fn(&mut SslRef, &mut SslAlert) -> Result<(), SniError> + 'static + Sync + Send,
951    {
952        unsafe {
953            // The SNI callback is somewhat unique in that the callback associated with the original
954            // context associated with an SSL can be used even if the SSL's context has been swapped
955            // out. When that happens, we wouldn't be able to look up the callback's state in the
956            // context's ex data. Instead, pass the pointer directly as the servername arg. It's
957            // still stored in ex data to manage the lifetime.
958            let arg = self.set_ex_data_inner(SslContext::cached_ex_index::<F>(), callback);
959            ffi::SSL_CTX_set_tlsext_servername_arg(self.as_ptr(), arg);
960            ffi::SSL_CTX_set_tlsext_servername_callback(self.as_ptr(), Some(raw_sni::<F>));
961        }
962    }
963
964    /// Sets the certificate verification depth.
965    ///
966    /// If the peer's certificate chain is longer than this value, verification will fail.
967    #[corresponds(SSL_CTX_set_verify_depth)]
968    pub fn set_verify_depth(&mut self, depth: u32) {
969        unsafe {
970            ffi::SSL_CTX_set_verify_depth(self.as_ptr(), depth as c_int);
971        }
972    }
973
974    /// Sets a custom certificate store for verifying peer certificates.
975    ///
976    /// Requires AWS-LC or OpenSSL 1.0.2 or newer.
977    #[corresponds(SSL_CTX_set0_verify_cert_store)]
978    #[cfg(any(ossl102, boringssl))]
979    pub fn set_verify_cert_store(&mut self, cert_store: X509Store) -> Result<(), ErrorStack> {
980        unsafe {
981            let ptr = cert_store.as_ptr();
982            cvt(ffi::SSL_CTX_set0_verify_cert_store(self.as_ptr(), ptr) as c_int)?;
983            mem::forget(cert_store);
984
985            Ok(())
986        }
987    }
988
989    /// Replaces the context's certificate store.
990    #[corresponds(SSL_CTX_set_cert_store)]
991    pub fn set_cert_store(&mut self, cert_store: X509Store) {
992        unsafe {
993            ffi::SSL_CTX_set_cert_store(self.as_ptr(), cert_store.as_ptr());
994            mem::forget(cert_store);
995        }
996    }
997
998    /// Controls read ahead behavior.
999    ///
1000    /// If enabled, OpenSSL will read as much data as is available from the underlying stream,
1001    /// instead of a single record at a time.
1002    ///
1003    /// It has no effect when used with DTLS.
1004    #[corresponds(SSL_CTX_set_read_ahead)]
1005    pub fn set_read_ahead(&mut self, read_ahead: bool) {
1006        unsafe {
1007            ffi::SSL_CTX_set_read_ahead(self.as_ptr(), read_ahead as SslBitType);
1008        }
1009    }
1010
1011    /// Sets the mode used by the context, returning the new mode bit mask.
1012    ///
1013    /// Options already set before are not cleared.
1014    #[corresponds(SSL_CTX_set_mode)]
1015    pub fn set_mode(&mut self, mode: SslMode) -> SslMode {
1016        unsafe {
1017            let bits = ffi::SSL_CTX_set_mode(self.as_ptr(), mode.bits() as ModeTy) as SslBitType;
1018            SslMode::from_bits_retain(bits)
1019        }
1020    }
1021
1022    /// Clear the mode used by the context, returning the new mode bit mask.
1023    #[corresponds(SSL_CTX_clear_mode)]
1024    pub fn clear_mode(&mut self, mode: SslMode) -> SslMode {
1025        unsafe {
1026            let bits = ffi::SSL_CTX_clear_mode(self.as_ptr(), mode.bits() as ModeTy) as SslBitType;
1027            SslMode::from_bits_retain(bits)
1028        }
1029    }
1030
1031    /// Returns the mode set for the context.
1032    #[corresponds(SSL_CTX_get_mode)]
1033    pub fn mode(&self) -> SslMode {
1034        unsafe {
1035            let bits = ffi::SSL_CTX_get_mode(self.as_ptr()) as SslBitType;
1036            SslMode::from_bits_retain(bits)
1037        }
1038    }
1039
1040    /// Configure OpenSSL to use the default built-in DH parameters.
1041    ///
1042    /// If “auto” DH parameters are switched on then the parameters will be selected to be
1043    /// consistent with the size of the key associated with the server's certificate.
1044    /// If there is no certificate (e.g. for PSK ciphersuites), then it it will be consistent
1045    /// with the size of the negotiated symmetric cipher key.
1046    ///
1047    /// Requires OpenSSL 3.0.0.
1048    #[corresponds(SSL_CTX_set_dh_auto)]
1049    #[cfg(ossl300)]
1050    pub fn set_dh_auto(&mut self, onoff: bool) -> Result<(), ErrorStack> {
1051        unsafe { cvt(ffi::SSL_CTX_set_dh_auto(self.as_ptr(), onoff as c_int)).map(|_| ()) }
1052    }
1053
1054    /// Sets the parameters to be used during ephemeral Diffie-Hellman key exchange.
1055    #[corresponds(SSL_CTX_set_tmp_dh)]
1056    pub fn set_tmp_dh(&mut self, dh: &DhRef<Params>) -> Result<(), ErrorStack> {
1057        unsafe { cvt(ffi::SSL_CTX_set_tmp_dh(self.as_ptr(), dh.as_ptr()) as c_int).map(|_| ()) }
1058    }
1059
1060    /// Sets the callback which will generate parameters to be used during ephemeral Diffie-Hellman
1061    /// key exchange.
1062    ///
1063    /// The callback is provided with a reference to the `Ssl` for the session, as well as a boolean
1064    /// indicating if the selected cipher is export-grade, and the key length. The export and key
1065    /// length options are archaic and should be ignored in almost all cases.
1066    #[corresponds(SSL_CTX_set_tmp_dh_callback)]
1067    pub fn set_tmp_dh_callback<F>(&mut self, callback: F)
1068    where
1069        F: Fn(&mut SslRef, bool, u32) -> Result<Dh<Params>, ErrorStack> + 'static + Sync + Send,
1070    {
1071        unsafe {
1072            self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
1073
1074            ffi::SSL_CTX_set_tmp_dh_callback(self.as_ptr(), Some(raw_tmp_dh::<F>));
1075        }
1076    }
1077
1078    /// Sets the parameters to be used during ephemeral elliptic curve Diffie-Hellman key exchange.
1079    #[corresponds(SSL_CTX_set_tmp_ecdh)]
1080    pub fn set_tmp_ecdh(&mut self, key: &EcKeyRef<Params>) -> Result<(), ErrorStack> {
1081        unsafe { cvt(ffi::SSL_CTX_set_tmp_ecdh(self.as_ptr(), key.as_ptr()) as c_int).map(|_| ()) }
1082    }
1083
1084    /// Use the default locations of trusted certificates for verification.
1085    ///
1086    /// These locations are read from the `SSL_CERT_FILE` and `SSL_CERT_DIR` environment variables
1087    /// if present, or defaults specified at OpenSSL build time otherwise.
1088    #[corresponds(SSL_CTX_set_default_verify_paths)]
1089    pub fn set_default_verify_paths(&mut self) -> Result<(), ErrorStack> {
1090        unsafe { cvt(ffi::SSL_CTX_set_default_verify_paths(self.as_ptr())).map(|_| ()) }
1091    }
1092
1093    /// Loads trusted root certificates from a file.
1094    ///
1095    /// The file should contain a sequence of PEM-formatted CA certificates.
1096    #[corresponds(SSL_CTX_load_verify_locations)]
1097    pub fn set_ca_file<P: AsRef<Path>>(&mut self, file: P) -> Result<(), ErrorStack> {
1098        self.load_verify_locations(Some(file.as_ref()), None)
1099    }
1100
1101    /// Loads trusted root certificates from a file and/or a directory.
1102    #[corresponds(SSL_CTX_load_verify_locations)]
1103    pub fn load_verify_locations(
1104        &mut self,
1105        ca_file: Option<&Path>,
1106        ca_path: Option<&Path>,
1107    ) -> Result<(), ErrorStack> {
1108        let ca_file = ca_file.map(|p| CString::new(p.as_os_str().to_str().unwrap()).unwrap());
1109        let ca_path = ca_path.map(|p| CString::new(p.as_os_str().to_str().unwrap()).unwrap());
1110        unsafe {
1111            cvt(ffi::SSL_CTX_load_verify_locations(
1112                self.as_ptr(),
1113                ca_file.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
1114                ca_path.as_ref().map_or(ptr::null(), |s| s.as_ptr()),
1115            ))
1116            .map(|_| ())
1117        }
1118    }
1119
1120    /// Sets the list of CA names sent to the client.
1121    ///
1122    /// The CA certificates must still be added to the trust root - they are not automatically set
1123    /// as trusted by this method.
1124    #[corresponds(SSL_CTX_set_client_CA_list)]
1125    pub fn set_client_ca_list(&mut self, list: Stack<X509Name>) {
1126        unsafe {
1127            ffi::SSL_CTX_set_client_CA_list(self.as_ptr(), list.as_ptr());
1128            mem::forget(list);
1129        }
1130    }
1131
1132    /// Add the provided CA certificate to the list sent by the server to the client when
1133    /// requesting client-side TLS authentication.
1134    #[corresponds(SSL_CTX_add_client_CA)]
1135    pub fn add_client_ca(&mut self, cacert: &X509Ref) -> Result<(), ErrorStack> {
1136        unsafe { cvt(ffi::SSL_CTX_add_client_CA(self.as_ptr(), cacert.as_ptr())).map(|_| ()) }
1137    }
1138
1139    /// Set the context identifier for sessions.
1140    ///
1141    /// This value identifies the server's session cache to clients, telling them when they're
1142    /// able to reuse sessions. It should be set to a unique value per server, unless multiple
1143    /// servers share a session cache.
1144    ///
1145    /// This value should be set when using client certificates, or each request will fail its
1146    /// handshake and need to be restarted.
1147    #[corresponds(SSL_CTX_set_session_id_context)]
1148    pub fn set_session_id_context(&mut self, sid_ctx: &[u8]) -> Result<(), ErrorStack> {
1149        unsafe {
1150            assert!(sid_ctx.len() <= c_uint::MAX as usize);
1151            cvt(ffi::SSL_CTX_set_session_id_context(
1152                self.as_ptr(),
1153                sid_ctx.as_ptr(),
1154                sid_ctx.len() as SizeTy,
1155            ))
1156            .map(|_| ())
1157        }
1158    }
1159
1160    /// Loads a leaf certificate from a file.
1161    ///
1162    /// Only a single certificate will be loaded - use `add_extra_chain_cert` to add the remainder
1163    /// of the certificate chain, or `set_certificate_chain_file` to load the entire chain from a
1164    /// single file.
1165    #[corresponds(SSL_CTX_use_certificate_file)]
1166    pub fn set_certificate_file<P: AsRef<Path>>(
1167        &mut self,
1168        file: P,
1169        file_type: SslFiletype,
1170    ) -> Result<(), ErrorStack> {
1171        let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap();
1172        unsafe {
1173            cvt(ffi::SSL_CTX_use_certificate_file(
1174                self.as_ptr(),
1175                file.as_ptr() as *const _,
1176                file_type.as_raw(),
1177            ))
1178            .map(|_| ())
1179        }
1180    }
1181
1182    /// Loads a certificate chain from a file.
1183    ///
1184    /// The file should contain a sequence of PEM-formatted certificates, the first being the leaf
1185    /// certificate, and the remainder forming the chain of certificates up to and including the
1186    /// trusted root certificate.
1187    #[corresponds(SSL_CTX_use_certificate_chain_file)]
1188    pub fn set_certificate_chain_file<P: AsRef<Path>>(
1189        &mut self,
1190        file: P,
1191    ) -> Result<(), ErrorStack> {
1192        let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap();
1193        unsafe {
1194            cvt(ffi::SSL_CTX_use_certificate_chain_file(
1195                self.as_ptr(),
1196                file.as_ptr() as *const _,
1197            ))
1198            .map(|_| ())
1199        }
1200    }
1201
1202    /// Sets the leaf certificate.
1203    ///
1204    /// Use `add_extra_chain_cert` to add the remainder of the certificate chain.
1205    #[corresponds(SSL_CTX_use_certificate)]
1206    pub fn set_certificate(&mut self, cert: &X509Ref) -> Result<(), ErrorStack> {
1207        unsafe { cvt(ffi::SSL_CTX_use_certificate(self.as_ptr(), cert.as_ptr())).map(|_| ()) }
1208    }
1209
1210    /// Appends a certificate to the certificate chain.
1211    ///
1212    /// This chain should contain all certificates necessary to go from the certificate specified by
1213    /// `set_certificate` to a trusted root.
1214    #[corresponds(SSL_CTX_add_extra_chain_cert)]
1215    pub fn add_extra_chain_cert(&mut self, cert: X509) -> Result<(), ErrorStack> {
1216        unsafe {
1217            cvt(ffi::SSL_CTX_add_extra_chain_cert(self.as_ptr(), cert.as_ptr()) as c_int)?;
1218            mem::forget(cert);
1219            Ok(())
1220        }
1221    }
1222
1223    #[cfg(tongsuo)]
1224    #[corresponds(SSL_CTX_use_enc_certificate_file)]
1225    pub fn set_enc_certificate_file<P: AsRef<Path>>(
1226        &mut self,
1227        file: P,
1228        file_type: SslFiletype,
1229    ) -> Result<(), ErrorStack> {
1230        let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap();
1231        unsafe {
1232            cvt(ffi::SSL_CTX_use_enc_certificate_file(
1233                self.as_ptr(),
1234                file.as_ptr() as *const _,
1235                file_type.as_raw(),
1236            ))
1237            .map(|_| ())
1238        }
1239    }
1240
1241    #[cfg(tongsuo)]
1242    #[corresponds(SSL_CTX_use_enc_certificate)]
1243    pub fn set_enc_certificate(&mut self, cert: &X509Ref) -> Result<(), ErrorStack> {
1244        unsafe {
1245            cvt(ffi::SSL_CTX_use_enc_certificate(
1246                self.as_ptr(),
1247                cert.as_ptr(),
1248            ))
1249            .map(|_| ())
1250        }
1251    }
1252
1253    #[cfg(tongsuo)]
1254    #[corresponds(SSL_CTX_use_sign_certificate_file)]
1255    pub fn set_sign_certificate_file<P: AsRef<Path>>(
1256        &mut self,
1257        file: P,
1258        file_type: SslFiletype,
1259    ) -> Result<(), ErrorStack> {
1260        let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap();
1261        unsafe {
1262            cvt(ffi::SSL_CTX_use_sign_certificate_file(
1263                self.as_ptr(),
1264                file.as_ptr() as *const _,
1265                file_type.as_raw(),
1266            ))
1267            .map(|_| ())
1268        }
1269    }
1270
1271    #[cfg(tongsuo)]
1272    #[corresponds(SSL_CTX_use_sign_certificate)]
1273    pub fn set_sign_certificate(&mut self, cert: &X509Ref) -> Result<(), ErrorStack> {
1274        unsafe {
1275            cvt(ffi::SSL_CTX_use_sign_certificate(
1276                self.as_ptr(),
1277                cert.as_ptr(),
1278            ))
1279            .map(|_| ())
1280        }
1281    }
1282
1283    /// Loads the private key from a file.
1284    #[corresponds(SSL_CTX_use_PrivateKey_file)]
1285    pub fn set_private_key_file<P: AsRef<Path>>(
1286        &mut self,
1287        file: P,
1288        file_type: SslFiletype,
1289    ) -> Result<(), ErrorStack> {
1290        let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap();
1291        unsafe {
1292            cvt(ffi::SSL_CTX_use_PrivateKey_file(
1293                self.as_ptr(),
1294                file.as_ptr() as *const _,
1295                file_type.as_raw(),
1296            ))
1297            .map(|_| ())
1298        }
1299    }
1300
1301    /// Sets the private key.
1302    #[corresponds(SSL_CTX_use_PrivateKey)]
1303    pub fn set_private_key<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack>
1304    where
1305        T: HasPrivate,
1306    {
1307        unsafe { cvt(ffi::SSL_CTX_use_PrivateKey(self.as_ptr(), key.as_ptr())).map(|_| ()) }
1308    }
1309
1310    #[cfg(tongsuo)]
1311    #[corresponds(SSL_CTX_use_enc_PrivateKey_file)]
1312    pub fn set_enc_private_key_file<P: AsRef<Path>>(
1313        &mut self,
1314        file: P,
1315        file_type: SslFiletype,
1316    ) -> Result<(), ErrorStack> {
1317        let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap();
1318        unsafe {
1319            cvt(ffi::SSL_CTX_use_enc_PrivateKey_file(
1320                self.as_ptr(),
1321                file.as_ptr() as *const _,
1322                file_type.as_raw(),
1323            ))
1324            .map(|_| ())
1325        }
1326    }
1327
1328    #[cfg(tongsuo)]
1329    #[corresponds(SSL_CTX_use_enc_PrivateKey)]
1330    pub fn set_enc_private_key<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack>
1331    where
1332        T: HasPrivate,
1333    {
1334        unsafe { cvt(ffi::SSL_CTX_use_enc_PrivateKey(self.as_ptr(), key.as_ptr())).map(|_| ()) }
1335    }
1336
1337    #[cfg(tongsuo)]
1338    #[corresponds(SSL_CTX_use_sign_PrivateKey_file)]
1339    pub fn set_sign_private_key_file<P: AsRef<Path>>(
1340        &mut self,
1341        file: P,
1342        file_type: SslFiletype,
1343    ) -> Result<(), ErrorStack> {
1344        let file = CString::new(file.as_ref().as_os_str().to_str().unwrap()).unwrap();
1345        unsafe {
1346            cvt(ffi::SSL_CTX_use_sign_PrivateKey_file(
1347                self.as_ptr(),
1348                file.as_ptr() as *const _,
1349                file_type.as_raw(),
1350            ))
1351            .map(|_| ())
1352        }
1353    }
1354
1355    #[cfg(tongsuo)]
1356    #[corresponds(SSL_CTX_use_sign_PrivateKey)]
1357    pub fn set_sign_private_key<T>(&mut self, key: &PKeyRef<T>) -> Result<(), ErrorStack>
1358    where
1359        T: HasPrivate,
1360    {
1361        unsafe {
1362            cvt(ffi::SSL_CTX_use_sign_PrivateKey(
1363                self.as_ptr(),
1364                key.as_ptr(),
1365            ))
1366            .map(|_| ())
1367        }
1368    }
1369
1370    /// Sets the list of supported ciphers for protocols before TLSv1.3.
1371    ///
1372    /// The `set_ciphersuites` method controls the cipher suites for TLSv1.3.
1373    ///
1374    /// See [`ciphers`] for details on the format.
1375    ///
1376    /// [`ciphers`]: https://www.openssl.org/docs/manmaster/apps/ciphers.html
1377    #[corresponds(SSL_CTX_set_cipher_list)]
1378    pub fn set_cipher_list(&mut self, cipher_list: &str) -> Result<(), ErrorStack> {
1379        let cipher_list = CString::new(cipher_list).unwrap();
1380        unsafe {
1381            cvt(ffi::SSL_CTX_set_cipher_list(
1382                self.as_ptr(),
1383                cipher_list.as_ptr() as *const _,
1384            ))
1385            .map(|_| ())
1386        }
1387    }
1388
1389    /// Sets the list of supported ciphers for the TLSv1.3 protocol.
1390    ///
1391    /// The `set_cipher_list` method controls the cipher suites for protocols before TLSv1.3.
1392    ///
1393    /// The format consists of TLSv1.3 cipher suite names separated by `:` characters in order of
1394    /// preference.
1395    ///
1396    /// Requires AWS-LC or OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer.
1397    #[corresponds(SSL_CTX_set_ciphersuites)]
1398    #[cfg(any(ossl111, libressl340, bssl_aws))]
1399    pub fn set_ciphersuites(&mut self, cipher_list: &str) -> Result<(), ErrorStack> {
1400        let cipher_list = CString::new(cipher_list).unwrap();
1401        unsafe {
1402            cvt(ffi::SSL_CTX_set_ciphersuites(
1403                self.as_ptr(),
1404                cipher_list.as_ptr() as *const _,
1405            ))
1406            .map(|_| ())
1407        }
1408    }
1409
1410    /// Enables ECDHE key exchange with an automatically chosen curve list.
1411    ///
1412    /// Requires OpenSSL 1.0.2.
1413    #[corresponds(SSL_CTX_set_ecdh_auto)]
1414    #[cfg(any(libressl, all(ossl102, not(ossl110))))]
1415    pub fn set_ecdh_auto(&mut self, onoff: bool) -> Result<(), ErrorStack> {
1416        unsafe { cvt(ffi::SSL_CTX_set_ecdh_auto(self.as_ptr(), onoff as c_int)).map(|_| ()) }
1417    }
1418
1419    /// Sets the options used by the context, returning the old set.
1420    ///
1421    /// # Note
1422    ///
1423    /// This *enables* the specified options, but does not disable unspecified options. Use
1424    /// `clear_options` for that.
1425    #[corresponds(SSL_CTX_set_options)]
1426    pub fn set_options(&mut self, option: SslOptions) -> SslOptions {
1427        let bits =
1428            unsafe { ffi::SSL_CTX_set_options(self.as_ptr(), option.bits()) } as SslOptionsRepr;
1429        SslOptions::from_bits_retain(bits)
1430    }
1431
1432    /// Returns the options used by the context.
1433    #[corresponds(SSL_CTX_get_options)]
1434    pub fn options(&self) -> SslOptions {
1435        let bits = unsafe { ffi::SSL_CTX_get_options(self.as_ptr()) } as SslOptionsRepr;
1436        SslOptions::from_bits_retain(bits)
1437    }
1438
1439    /// Clears the options used by the context, returning the old set.
1440    #[corresponds(SSL_CTX_clear_options)]
1441    pub fn clear_options(&mut self, option: SslOptions) -> SslOptions {
1442        let bits =
1443            unsafe { ffi::SSL_CTX_clear_options(self.as_ptr(), option.bits()) } as SslOptionsRepr;
1444        SslOptions::from_bits_retain(bits)
1445    }
1446
1447    /// Sets the minimum supported protocol version.
1448    ///
1449    /// A value of `None` will enable protocol versions down to the lowest version supported by
1450    /// OpenSSL.
1451    ///
1452    /// Requires BoringSSL or OpenSSL 1.1.0 or LibreSSL 2.6.1 or newer.
1453    #[corresponds(SSL_CTX_set_min_proto_version)]
1454    #[cfg(any(ossl110, libressl261, boringssl))]
1455    pub fn set_min_proto_version(&mut self, version: Option<SslVersion>) -> Result<(), ErrorStack> {
1456        unsafe {
1457            cvt(ffi::SSL_CTX_set_min_proto_version(
1458                self.as_ptr(),
1459                version.map_or(0, |v| v.0 as _),
1460            ))
1461            .map(|_| ())
1462        }
1463    }
1464
1465    /// Sets the maximum supported protocol version.
1466    ///
1467    /// A value of `None` will enable protocol versions up to the highest version supported by
1468    /// OpenSSL.
1469    ///
1470    /// Requires BoringSSL or OpenSSL 1.1.0 or or LibreSSL 2.6.1 or newer.
1471    #[corresponds(SSL_CTX_set_max_proto_version)]
1472    #[cfg(any(ossl110, libressl261, boringssl))]
1473    pub fn set_max_proto_version(&mut self, version: Option<SslVersion>) -> Result<(), ErrorStack> {
1474        unsafe {
1475            cvt(ffi::SSL_CTX_set_max_proto_version(
1476                self.as_ptr(),
1477                version.map_or(0, |v| v.0 as _),
1478            ))
1479            .map(|_| ())
1480        }
1481    }
1482
1483    /// Gets the minimum supported protocol version.
1484    ///
1485    /// A value of `None` indicates that all versions down to the lowest version supported by
1486    /// OpenSSL are enabled.
1487    ///
1488    /// Requires OpenSSL 1.1.0g or LibreSSL 2.7.0 or newer.
1489    #[corresponds(SSL_CTX_get_min_proto_version)]
1490    #[cfg(any(ossl110g, libressl270))]
1491    pub fn min_proto_version(&mut self) -> Option<SslVersion> {
1492        unsafe {
1493            let r = ffi::SSL_CTX_get_min_proto_version(self.as_ptr());
1494            if r == 0 {
1495                None
1496            } else {
1497                Some(SslVersion(r))
1498            }
1499        }
1500    }
1501
1502    /// Gets the maximum supported protocol version.
1503    ///
1504    /// A value of `None` indicates that all versions up to the highest version supported by
1505    /// OpenSSL are enabled.
1506    ///
1507    /// Requires OpenSSL 1.1.0g or LibreSSL 2.7.0 or newer.
1508    #[corresponds(SSL_CTX_get_max_proto_version)]
1509    #[cfg(any(ossl110g, libressl270))]
1510    pub fn max_proto_version(&mut self) -> Option<SslVersion> {
1511        unsafe {
1512            let r = ffi::SSL_CTX_get_max_proto_version(self.as_ptr());
1513            if r == 0 {
1514                None
1515            } else {
1516                Some(SslVersion(r))
1517            }
1518        }
1519    }
1520
1521    /// Sets the protocols to sent to the server for Application Layer Protocol Negotiation (ALPN).
1522    ///
1523    /// The input must be in ALPN "wire format". It consists of a sequence of supported protocol
1524    /// names prefixed by their byte length. For example, the protocol list consisting of `spdy/1`
1525    /// and `http/1.1` is encoded as `b"\x06spdy/1\x08http/1.1"`. The protocols are ordered by
1526    /// preference.
1527    ///
1528    /// Requires BoringSSL or OpenSSL 1.0.2 or LibreSSL 2.6.1 or newer.
1529    #[corresponds(SSL_CTX_set_alpn_protos)]
1530    #[cfg(any(ossl102, libressl261, boringssl))]
1531    pub fn set_alpn_protos(&mut self, protocols: &[u8]) -> Result<(), ErrorStack> {
1532        unsafe {
1533            assert!(protocols.len() <= c_uint::MAX as usize);
1534            let r = ffi::SSL_CTX_set_alpn_protos(
1535                self.as_ptr(),
1536                protocols.as_ptr(),
1537                protocols.len() as _,
1538            );
1539            // fun fact, SSL_CTX_set_alpn_protos has a reversed return code D:
1540            if r == 0 {
1541                Ok(())
1542            } else {
1543                Err(ErrorStack::get())
1544            }
1545        }
1546    }
1547
1548    /// Enables the DTLS extension "use_srtp" as defined in RFC5764.
1549    #[corresponds(SSL_CTX_set_tlsext_use_srtp)]
1550    pub fn set_tlsext_use_srtp(&mut self, protocols: &str) -> Result<(), ErrorStack> {
1551        unsafe {
1552            let cstr = CString::new(protocols).unwrap();
1553
1554            let r = ffi::SSL_CTX_set_tlsext_use_srtp(self.as_ptr(), cstr.as_ptr());
1555            // fun fact, set_tlsext_use_srtp has a reversed return code D:
1556            if r == 0 {
1557                Ok(())
1558            } else {
1559                Err(ErrorStack::get())
1560            }
1561        }
1562    }
1563
1564    /// Sets the callback used by a server to select a protocol for Application Layer Protocol
1565    /// Negotiation (ALPN).
1566    ///
1567    /// The callback is provided with the client's protocol list in ALPN wire format. See the
1568    /// documentation for [`SslContextBuilder::set_alpn_protos`] for details. It should return one
1569    /// of those protocols on success. The [`select_next_proto`] function implements the standard
1570    /// protocol selection algorithm.
1571    ///
1572    /// Requires BoringSSL or OpenSSL 1.0.2 or LibreSSL 2.6.1 or newer.
1573    ///
1574    /// [`SslContextBuilder::set_alpn_protos`]: struct.SslContextBuilder.html#method.set_alpn_protos
1575    /// [`select_next_proto`]: fn.select_next_proto.html
1576    #[corresponds(SSL_CTX_set_alpn_select_cb)]
1577    #[cfg(any(ossl102, libressl261, boringssl))]
1578    pub fn set_alpn_select_callback<F>(&mut self, callback: F)
1579    where
1580        F: for<'a> Fn(&mut SslRef, &'a [u8]) -> Result<&'a [u8], AlpnError> + 'static + Sync + Send,
1581    {
1582        unsafe {
1583            self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
1584            ffi::SSL_CTX_set_alpn_select_cb(
1585                self.as_ptr(),
1586                Some(callbacks::raw_alpn_select::<F>),
1587                ptr::null_mut(),
1588            );
1589        }
1590    }
1591
1592    /// Checks for consistency between the private key and certificate.
1593    #[corresponds(SSL_CTX_check_private_key)]
1594    pub fn check_private_key(&self) -> Result<(), ErrorStack> {
1595        unsafe { cvt(ffi::SSL_CTX_check_private_key(self.as_ptr())).map(|_| ()) }
1596    }
1597
1598    /// Returns a shared reference to the context's certificate store.
1599    #[corresponds(SSL_CTX_get_cert_store)]
1600    pub fn cert_store(&self) -> &X509StoreBuilderRef {
1601        unsafe { X509StoreBuilderRef::from_ptr(ffi::SSL_CTX_get_cert_store(self.as_ptr())) }
1602    }
1603
1604    /// Returns a mutable reference to the context's certificate store.
1605    #[corresponds(SSL_CTX_get_cert_store)]
1606    pub fn cert_store_mut(&mut self) -> &mut X509StoreBuilderRef {
1607        unsafe { X509StoreBuilderRef::from_ptr_mut(ffi::SSL_CTX_get_cert_store(self.as_ptr())) }
1608    }
1609
1610    /// Returns a reference to the X509 verification configuration.
1611    ///
1612    /// Requires BoringSSL or OpenSSL 1.0.2 or newer.
1613    #[corresponds(SSL_CTX_get0_param)]
1614    #[cfg(any(ossl102, boringssl, libressl261))]
1615    pub fn verify_param(&self) -> &X509VerifyParamRef {
1616        unsafe { X509VerifyParamRef::from_ptr(ffi::SSL_CTX_get0_param(self.as_ptr())) }
1617    }
1618
1619    /// Returns a mutable reference to the X509 verification configuration.
1620    ///
1621    /// Requires BoringSSL or OpenSSL 1.0.2 or newer.
1622    #[corresponds(SSL_CTX_get0_param)]
1623    #[cfg(any(ossl102, boringssl, libressl261))]
1624    pub fn verify_param_mut(&mut self) -> &mut X509VerifyParamRef {
1625        unsafe { X509VerifyParamRef::from_ptr_mut(ffi::SSL_CTX_get0_param(self.as_ptr())) }
1626    }
1627
1628    /// Registers a certificate decompression algorithm on ctx with ID alg_id.
1629    ///
1630    /// This corresponds to [`SSL_CTX_add_cert_compression_alg`].
1631    ///
1632    /// [`SSL_CTX_add_cert_compression_alg`]: https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#SSL_CTX_add_cert_compression_alg
1633    ///
1634    /// Requires BoringSSL or Tongsuo.
1635    #[cfg(any(boringssl, tongsuo))]
1636    pub fn add_cert_decompression_alg<F>(
1637        &mut self,
1638        alg_id: CertCompressionAlgorithm,
1639        decompress: F,
1640    ) -> Result<(), ErrorStack>
1641    where
1642        F: Fn(&[u8], &mut [u8]) -> usize + Send + Sync + 'static,
1643    {
1644        unsafe {
1645            self.set_ex_data(SslContext::cached_ex_index::<F>(), decompress);
1646            cvt(ffi::SSL_CTX_add_cert_compression_alg(
1647                self.as_ptr(),
1648                alg_id.0 as _,
1649                None,
1650                Some(raw_cert_decompression::<F>),
1651            ))
1652            .map(|_| ())
1653        }
1654    }
1655
1656    /// Specify the preferred cert compression algorithms
1657    #[corresponds(SSL_CTX_set1_cert_comp_preference)]
1658    #[cfg(ossl320)]
1659    pub fn set_cert_comp_preference(
1660        &mut self,
1661        algs: &[CertCompressionAlgorithm],
1662    ) -> Result<(), ErrorStack> {
1663        let mut algs = algs.iter().map(|v| v.0).collect::<Vec<c_int>>();
1664        unsafe {
1665            cvt(ffi::SSL_CTX_set1_cert_comp_preference(
1666                self.as_ptr(),
1667                algs.as_mut_ptr(),
1668                algs.len(),
1669            ))
1670            .map(|_| ())
1671        }
1672    }
1673
1674    /// Enables OCSP stapling on all client SSL objects created from ctx
1675    ///
1676    /// This corresponds to [`SSL_CTX_enable_ocsp_stapling`].
1677    ///
1678    /// [`SSL_CTX_enable_ocsp_stapling`]: https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#SSL_CTX_enable_ocsp_stapling
1679    ///
1680    /// Requires BoringSSL.
1681    #[cfg(boringssl)]
1682    pub fn enable_ocsp_stapling(&mut self) {
1683        unsafe { ffi::SSL_CTX_enable_ocsp_stapling(self.as_ptr()) }
1684    }
1685
1686    /// Enables SCT requests on all client SSL objects created from ctx
1687    ///
1688    /// This corresponds to [`SSL_CTX_enable_signed_cert_timestamps`].
1689    ///
1690    /// [`SSL_CTX_enable_signed_cert_timestamps`]: https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#SSL_CTX_enable_signed_cert_timestamps
1691    ///
1692    /// Requires BoringSSL.
1693    #[cfg(boringssl)]
1694    pub fn enable_signed_cert_timestamps(&mut self) {
1695        unsafe { ffi::SSL_CTX_enable_signed_cert_timestamps(self.as_ptr()) }
1696    }
1697
1698    /// Set whether to enable GREASE on all client SSL objects created from ctx
1699    ///
1700    /// This corresponds to [`SSL_CTX_set_grease_enabled`].
1701    ///
1702    /// [`SSL_CTX_set_grease_enabled`]: https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#SSL_CTX_set_grease_enabled
1703    ///
1704    /// Requires BoringSSL.
1705    #[cfg(boringssl)]
1706    pub fn set_grease_enabled(&mut self, enabled: bool) {
1707        unsafe { ffi::SSL_CTX_set_grease_enabled(self.as_ptr(), enabled as c_int) }
1708    }
1709
1710    /// Configures whether sockets on ctx should permute extensions.
1711    ///
1712    /// This corresponds to [`SSL_CTX_set_permute_extensions`].
1713    ///
1714    /// [`SSL_CTX_set_permute_extensions`]: https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#SSL_CTX_set_permute_extensions
1715    ///
1716    /// Requires BoringSSL.
1717    #[cfg(boringssl)]
1718    pub fn set_permute_extensions(&mut self, enabled: bool) {
1719        unsafe { ffi::SSL_CTX_set_permute_extensions(self.as_ptr(), enabled as c_int) }
1720    }
1721
1722    /// Enable the processing of signed certificate timestamps (SCTs) for all connections that share the given SSL context.
1723    #[corresponds(SSL_CTX_enable_ct)]
1724    #[cfg(ossl111)]
1725    pub fn enable_ct(&mut self, validation_mode: SslCtValidationMode) -> Result<(), ErrorStack> {
1726        unsafe { cvt(ffi::SSL_CTX_enable_ct(self.as_ptr(), validation_mode.0)).map(|_| ()) }
1727    }
1728
1729    /// Check whether CT processing is enabled.
1730    #[corresponds(SSL_CTX_ct_is_enabled)]
1731    #[cfg(ossl111)]
1732    pub fn ct_is_enabled(&self) -> bool {
1733        unsafe { ffi::SSL_CTX_ct_is_enabled(self.as_ptr()) == 1 }
1734    }
1735
1736    /// Sets the status response a client wishes the server to reply with.
1737    #[corresponds(SSL_CTX_set_tlsext_status_type)]
1738    #[cfg(not(boringssl))]
1739    pub fn set_status_type(&mut self, type_: StatusType) -> Result<(), ErrorStack> {
1740        unsafe {
1741            cvt(ffi::SSL_CTX_set_tlsext_status_type(self.as_ptr(), type_.as_raw()) as c_int)
1742                .map(|_| ())
1743        }
1744    }
1745
1746    /// Sets the callback dealing with OCSP stapling.
1747    ///
1748    /// On the client side, this callback is responsible for validating the OCSP status response
1749    /// returned by the server. The status may be retrieved with the `SslRef::ocsp_status` method.
1750    /// A response of `Ok(true)` indicates that the OCSP status is valid, and a response of
1751    /// `Ok(false)` indicates that the OCSP status is invalid and the handshake should be
1752    /// terminated.
1753    ///
1754    /// On the server side, this callback is responsible for setting the OCSP status response to be
1755    /// returned to clients. The status may be set with the `SslRef::set_ocsp_status` method. A
1756    /// response of `Ok(true)` indicates that the OCSP status should be returned to the client, and
1757    /// `Ok(false)` indicates that the status should not be returned to the client.
1758    #[corresponds(SSL_CTX_set_tlsext_status_cb)]
1759    pub fn set_status_callback<F>(&mut self, callback: F) -> Result<(), ErrorStack>
1760    where
1761        F: Fn(&mut SslRef) -> Result<bool, ErrorStack> + 'static + Sync + Send,
1762    {
1763        unsafe {
1764            self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
1765            cvt(
1766                ffi::SSL_CTX_set_tlsext_status_cb(self.as_ptr(), Some(raw_tlsext_status::<F>))
1767                    as c_int,
1768            )
1769            .map(|_| ())
1770        }
1771    }
1772
1773    #[corresponds(SSL_CTX_set_tlsext_ticket_key_evp_cb)]
1774    #[cfg(ossl300)]
1775    pub fn set_ticket_key_evp_callback<F>(&mut self, callback: F) -> Result<(), ErrorStack>
1776    where
1777        F: Fn(
1778                &mut SslRef,
1779                &mut [u8],
1780                &mut [u8],
1781                &mut CipherCtxRef,
1782                &mut MacCtxRef,
1783                bool,
1784            ) -> Result<TicketKeyStatus, ErrorStack>
1785            + 'static
1786            + Sync
1787            + Send,
1788    {
1789        unsafe {
1790            self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
1791            cvt(ffi::SSL_CTX_set_tlsext_ticket_key_evp_cb(
1792                self.as_ptr(),
1793                Some(raw_tlsext_ticket_key_evp::<F>),
1794            ) as c_int)
1795            .map(|_| ())
1796        }
1797    }
1798
1799    #[corresponds(SSL_CTX_set_tlsext_ticket_key_cb)]
1800    pub fn set_ticket_key_callback<F>(&mut self, callback: F) -> Result<(), ErrorStack>
1801    where
1802        F: Fn(
1803                &mut SslRef,
1804                &mut [u8],
1805                &mut [u8],
1806                &mut CipherCtxRef,
1807                &mut HMacCtxRef,
1808                bool,
1809            ) -> Result<TicketKeyStatus, ErrorStack>
1810            + 'static
1811            + Sync
1812            + Send,
1813    {
1814        unsafe {
1815            self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
1816            cvt(ffi::SSL_CTX_set_tlsext_ticket_key_cb(
1817                self.as_ptr(),
1818                Some(raw_tlsext_ticket_key::<F>),
1819            ) as c_int)
1820            .map(|_| ())
1821        }
1822    }
1823
1824    /// Sets the callback for providing an identity and pre-shared key for a TLS-PSK client.
1825    ///
1826    /// The callback will be called with the SSL context, an identity hint if one was provided
1827    /// by the server, a mutable slice for each of the identity and pre-shared key bytes. The
1828    /// identity must be written as a null-terminated C string.
1829    #[corresponds(SSL_CTX_set_psk_client_callback)]
1830    #[cfg(not(osslconf = "OPENSSL_NO_PSK"))]
1831    pub fn set_psk_client_callback<F>(&mut self, callback: F)
1832    where
1833        F: Fn(&mut SslRef, Option<&[u8]>, &mut [u8], &mut [u8]) -> Result<usize, ErrorStack>
1834            + 'static
1835            + Sync
1836            + Send,
1837    {
1838        unsafe {
1839            self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
1840            ffi::SSL_CTX_set_psk_client_callback(self.as_ptr(), Some(raw_client_psk::<F>));
1841        }
1842    }
1843
1844    /// Sets the callback for providing an identity and pre-shared key for a TLS-PSK server.
1845    ///
1846    /// The callback will be called with the SSL context, an identity provided by the client,
1847    /// and, a mutable slice for the pre-shared key bytes. The callback returns the number of
1848    /// bytes in the pre-shared key.
1849    #[corresponds(SSL_CTX_set_psk_server_callback)]
1850    #[cfg(not(osslconf = "OPENSSL_NO_PSK"))]
1851    pub fn set_psk_server_callback<F>(&mut self, callback: F)
1852    where
1853        F: Fn(&mut SslRef, Option<&[u8]>, &mut [u8]) -> Result<usize, ErrorStack>
1854            + 'static
1855            + Sync
1856            + Send,
1857    {
1858        unsafe {
1859            self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
1860            ffi::SSL_CTX_set_psk_server_callback(self.as_ptr(), Some(raw_server_psk::<F>));
1861        }
1862    }
1863
1864    /// Sets the callback which is called when new sessions are negotiated.
1865    ///
1866    /// This can be used by clients to implement session caching. While in TLSv1.2 the session is
1867    /// available to access via [`SslRef::session`] immediately after the handshake completes, this
1868    /// is not the case for TLSv1.3. There, a session is not generally available immediately, and
1869    /// the server may provide multiple session tokens to the client over a single session. The new
1870    /// session callback is a portable way to deal with both cases.
1871    ///
1872    /// Note that session caching must be enabled for the callback to be invoked, and it defaults
1873    /// off for clients. [`set_session_cache_mode`] controls that behavior.
1874    ///
1875    /// [`SslRef::session`]: struct.SslRef.html#method.session
1876    /// [`set_session_cache_mode`]: #method.set_session_cache_mode
1877    #[corresponds(SSL_CTX_sess_set_new_cb)]
1878    pub fn set_new_session_callback<F>(&mut self, callback: F)
1879    where
1880        F: Fn(&mut SslRef, SslSession) + 'static + Sync + Send,
1881    {
1882        unsafe {
1883            self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
1884            ffi::SSL_CTX_sess_set_new_cb(self.as_ptr(), Some(callbacks::raw_new_session::<F>));
1885        }
1886    }
1887
1888    /// Sets the callback which is called when sessions are removed from the context.
1889    ///
1890    /// Sessions can be removed because they have timed out or because they are considered faulty.
1891    #[corresponds(SSL_CTX_sess_set_remove_cb)]
1892    pub fn set_remove_session_callback<F>(&mut self, callback: F)
1893    where
1894        F: Fn(&SslContextRef, &SslSessionRef) + 'static + Sync + Send,
1895    {
1896        unsafe {
1897            self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
1898            ffi::SSL_CTX_sess_set_remove_cb(
1899                self.as_ptr(),
1900                Some(callbacks::raw_remove_session::<F>),
1901            );
1902        }
1903    }
1904
1905    /// Sets the callback which is called when a client proposed to resume a session but it was not
1906    /// found in the internal cache.
1907    ///
1908    /// The callback is passed a reference to the session ID provided by the client. It should
1909    /// return the session corresponding to that ID if available. This is only used for servers, not
1910    /// clients.
1911    ///
1912    /// # Safety
1913    ///
1914    /// The returned `SslSession` must not be associated with a different `SslContext`.
1915    #[corresponds(SSL_CTX_sess_set_get_cb)]
1916    pub unsafe fn set_get_session_callback<F>(&mut self, callback: F)
1917    where
1918        F: Fn(&mut SslRef, &[u8]) -> Option<SslSession> + 'static + Sync + Send,
1919    {
1920        self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
1921        ffi::SSL_CTX_sess_set_get_cb(self.as_ptr(), Some(callbacks::raw_get_session::<F>));
1922    }
1923
1924    /// Sets the TLS key logging callback.
1925    ///
1926    /// The callback is invoked whenever TLS key material is generated, and is passed a line of NSS
1927    /// SSLKEYLOGFILE-formatted text. This can be used by tools like Wireshark to decrypt message
1928    /// traffic. The line does not contain a trailing newline.
1929    ///
1930    /// Requires OpenSSL 1.1.1 or newer.
1931    #[corresponds(SSL_CTX_set_keylog_callback)]
1932    #[cfg(any(ossl111, boringssl))]
1933    pub fn set_keylog_callback<F>(&mut self, callback: F)
1934    where
1935        F: Fn(&SslRef, &str) + 'static + Sync + Send,
1936    {
1937        unsafe {
1938            self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
1939            ffi::SSL_CTX_set_keylog_callback(self.as_ptr(), Some(callbacks::raw_keylog::<F>));
1940        }
1941    }
1942
1943    /// Sets the session caching mode use for connections made with the context.
1944    ///
1945    /// Returns the previous session caching mode.
1946    #[corresponds(SSL_CTX_set_session_cache_mode)]
1947    pub fn set_session_cache_mode(&mut self, mode: SslSessionCacheMode) -> SslSessionCacheMode {
1948        unsafe {
1949            let bits = ffi::SSL_CTX_set_session_cache_mode(self.as_ptr(), mode.bits());
1950            SslSessionCacheMode::from_bits_retain(bits)
1951        }
1952    }
1953
1954    /// Sets the callback for generating an application cookie for TLS1.3
1955    /// stateless handshakes.
1956    ///
1957    /// The callback will be called with the SSL context and a slice into which the cookie
1958    /// should be written. The callback should return the number of bytes written.
1959    #[corresponds(SSL_CTX_set_stateless_cookie_generate_cb)]
1960    #[cfg(ossl111)]
1961    pub fn set_stateless_cookie_generate_cb<F>(&mut self, callback: F)
1962    where
1963        F: Fn(&mut SslRef, &mut [u8]) -> Result<usize, ErrorStack> + 'static + Sync + Send,
1964    {
1965        unsafe {
1966            self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
1967            ffi::SSL_CTX_set_stateless_cookie_generate_cb(
1968                self.as_ptr(),
1969                Some(raw_stateless_cookie_generate::<F>),
1970            );
1971        }
1972    }
1973
1974    /// Sets the callback for verifying an application cookie for TLS1.3
1975    /// stateless handshakes.
1976    ///
1977    /// The callback will be called with the SSL context and the cookie supplied by the
1978    /// client. It should return true if and only if the cookie is valid.
1979    ///
1980    /// Note that the OpenSSL implementation independently verifies the integrity of
1981    /// application cookies using an HMAC before invoking the supplied callback.
1982    #[corresponds(SSL_CTX_set_stateless_cookie_verify_cb)]
1983    #[cfg(ossl111)]
1984    pub fn set_stateless_cookie_verify_cb<F>(&mut self, callback: F)
1985    where
1986        F: Fn(&mut SslRef, &[u8]) -> bool + 'static + Sync + Send,
1987    {
1988        unsafe {
1989            self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
1990            ffi::SSL_CTX_set_stateless_cookie_verify_cb(
1991                self.as_ptr(),
1992                Some(raw_stateless_cookie_verify::<F>),
1993            )
1994        }
1995    }
1996
1997    /// Sets the callback for generating a DTLSv1 cookie
1998    ///
1999    /// The callback will be called with the SSL context and a slice into which the cookie
2000    /// should be written. The callback should return the number of bytes written.
2001    #[corresponds(SSL_CTX_set_cookie_generate_cb)]
2002    #[cfg(not(boringssl))]
2003    pub fn set_cookie_generate_cb<F>(&mut self, callback: F)
2004    where
2005        F: Fn(&mut SslRef, &mut [u8]) -> Result<usize, ErrorStack> + 'static + Sync + Send,
2006    {
2007        unsafe {
2008            self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
2009            ffi::SSL_CTX_set_cookie_generate_cb(self.as_ptr(), Some(raw_cookie_generate::<F>));
2010        }
2011    }
2012
2013    /// Sets the callback for verifying a DTLSv1 cookie
2014    ///
2015    /// The callback will be called with the SSL context and the cookie supplied by the
2016    /// client. It should return true if and only if the cookie is valid.
2017    #[corresponds(SSL_CTX_set_cookie_verify_cb)]
2018    #[cfg(not(boringssl))]
2019    pub fn set_cookie_verify_cb<F>(&mut self, callback: F)
2020    where
2021        F: Fn(&mut SslRef, &[u8]) -> bool + 'static + Sync + Send,
2022    {
2023        unsafe {
2024            self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
2025            ffi::SSL_CTX_set_cookie_verify_cb(self.as_ptr(), Some(raw_cookie_verify::<F>));
2026        }
2027    }
2028
2029    /// Sets the extra data at the specified index.
2030    ///
2031    /// This can be used to provide data to callbacks registered with the context. Use the
2032    /// `SslContext::new_ex_index` method to create an `Index`.
2033    // FIXME should return a result
2034    #[corresponds(SSL_CTX_set_ex_data)]
2035    pub fn set_ex_data<T>(&mut self, index: Index<SslContext, T>, data: T) {
2036        self.set_ex_data_inner(index, data);
2037    }
2038
2039    fn set_ex_data_inner<T>(&mut self, index: Index<SslContext, T>, data: T) -> *mut c_void {
2040        match self.ex_data_mut(index) {
2041            Some(v) => {
2042                *v = data;
2043                (v as *mut T).cast()
2044            }
2045            _ => unsafe {
2046                let data = Box::into_raw(Box::new(data)) as *mut c_void;
2047                ffi::SSL_CTX_set_ex_data(self.as_ptr(), index.as_raw(), data);
2048                data
2049            },
2050        }
2051    }
2052
2053    fn ex_data_mut<T>(&mut self, index: Index<SslContext, T>) -> Option<&mut T> {
2054        unsafe {
2055            let data = ffi::SSL_CTX_get_ex_data(self.as_ptr(), index.as_raw());
2056            if data.is_null() {
2057                None
2058            } else {
2059                Some(&mut *data.cast())
2060            }
2061        }
2062    }
2063
2064    /// Adds a custom extension for a TLS/DTLS client or server for all supported protocol versions.
2065    ///
2066    /// Requires OpenSSL 1.1.1 or newer.
2067    #[corresponds(SSL_CTX_add_custom_ext)]
2068    #[cfg(ossl111)]
2069    pub fn add_custom_ext<AddFn, ParseFn, T>(
2070        &mut self,
2071        ext_type: u16,
2072        context: ExtensionContext,
2073        add_cb: AddFn,
2074        parse_cb: ParseFn,
2075    ) -> Result<(), ErrorStack>
2076    where
2077        AddFn: Fn(
2078                &mut SslRef,
2079                ExtensionContext,
2080                Option<(usize, &X509Ref)>,
2081            ) -> Result<Option<T>, SslAlert>
2082            + 'static
2083            + Sync
2084            + Send,
2085        T: AsRef<[u8]> + 'static + Sync + Send,
2086        ParseFn: Fn(
2087                &mut SslRef,
2088                ExtensionContext,
2089                &[u8],
2090                Option<(usize, &X509Ref)>,
2091            ) -> Result<(), SslAlert>
2092            + 'static
2093            + Sync
2094            + Send,
2095    {
2096        let ret = unsafe {
2097            self.set_ex_data(SslContext::cached_ex_index::<AddFn>(), add_cb);
2098            self.set_ex_data(SslContext::cached_ex_index::<ParseFn>(), parse_cb);
2099
2100            ffi::SSL_CTX_add_custom_ext(
2101                self.as_ptr(),
2102                ext_type as c_uint,
2103                context.bits(),
2104                Some(raw_custom_ext_add::<AddFn, T>),
2105                Some(raw_custom_ext_free::<T>),
2106                ptr::null_mut(),
2107                Some(raw_custom_ext_parse::<ParseFn>),
2108                ptr::null_mut(),
2109            )
2110        };
2111        if ret == 1 {
2112            Ok(())
2113        } else {
2114            Err(ErrorStack::get())
2115        }
2116    }
2117
2118    /// Sets the maximum amount of early data that will be accepted on incoming connections.
2119    ///
2120    /// Defaults to 0.
2121    ///
2122    /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer.
2123    #[corresponds(SSL_CTX_set_max_early_data)]
2124    #[cfg(any(ossl111, libressl340))]
2125    pub fn set_max_early_data(&mut self, bytes: u32) -> Result<(), ErrorStack> {
2126        if unsafe { ffi::SSL_CTX_set_max_early_data(self.as_ptr(), bytes) } == 1 {
2127            Ok(())
2128        } else {
2129            Err(ErrorStack::get())
2130        }
2131    }
2132
2133    /// Sets a callback that is called before most ClientHello processing and before the decision whether
2134    /// to resume a session is made. The callback may inspect the ClientHello and configure the
2135    /// connection.
2136    ///
2137    /// This corresponds to [`SSL_CTX_set_select_certificate_cb`].
2138    ///
2139    /// [`SSL_CTX_set_select_certificate_cb`]: https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#SSL_CTX_set_select_certificate_cb
2140    ///
2141    /// Requires BoringSSL.
2142    #[cfg(boringssl)]
2143    pub fn set_select_certificate_callback<F>(&mut self, callback: F)
2144    where
2145        F: Fn(ClientHello<'_>) -> Result<(), SelectCertError> + Sync + Send + 'static,
2146    {
2147        unsafe {
2148            self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
2149            ffi::SSL_CTX_set_select_certificate_cb(
2150                self.as_ptr(),
2151                Some(callbacks::raw_select_cert::<F>),
2152            );
2153        }
2154    }
2155
2156    /// Sets a callback which will be invoked just after the client's hello message is received.
2157    ///
2158    /// Requires OpenSSL 1.1.1 or newer.
2159    #[corresponds(SSL_CTX_set_client_hello_cb)]
2160    #[cfg(ossl111)]
2161    pub fn set_client_hello_callback<F>(&mut self, callback: F)
2162    where
2163        F: Fn(&mut SslRef, &mut SslAlert) -> Result<(), ClientHelloError> + 'static + Sync + Send,
2164    {
2165        unsafe {
2166            let ptr = self.set_ex_data_inner(SslContext::cached_ex_index::<F>(), callback);
2167            ffi::SSL_CTX_set_client_hello_cb(
2168                self.as_ptr(),
2169                Some(callbacks::raw_client_hello::<F>),
2170                ptr,
2171            );
2172        }
2173    }
2174
2175    /// Sets the context's session cache size limit, returning the previous limit.
2176    ///
2177    /// A value of 0 means that the cache size is unbounded.
2178    #[corresponds(SSL_CTX_sess_set_cache_size)]
2179    #[allow(clippy::useless_conversion)]
2180    pub fn set_session_cache_size(&mut self, size: i32) -> i64 {
2181        unsafe {
2182            ffi::SSL_CTX_sess_set_cache_size(self.as_ptr(), size as SslCacheSize) as SslCacheTy
2183        }
2184    }
2185
2186    /// Sets the context's supported signature algorithms.
2187    ///
2188    /// Requires OpenSSL 1.0.2 or newer.
2189    #[corresponds(SSL_CTX_set1_sigalgs_list)]
2190    #[cfg(ossl102)]
2191    pub fn set_sigalgs_list(&mut self, sigalgs: &str) -> Result<(), ErrorStack> {
2192        let sigalgs = CString::new(sigalgs).unwrap();
2193        unsafe {
2194            cvt(ffi::SSL_CTX_set1_sigalgs_list(self.as_ptr(), sigalgs.as_ptr()) as c_int)
2195                .map(|_| ())
2196        }
2197    }
2198
2199    /// Sets the context's supported elliptic curve groups.
2200    ///
2201    /// Requires BoringSSL or OpenSSL 1.1.1 or LibreSSL 2.5.1 or newer.
2202    #[corresponds(SSL_CTX_set1_groups_list)]
2203    #[cfg(any(ossl111, boringssl, libressl251))]
2204    pub fn set_groups_list(&mut self, groups: &str) -> Result<(), ErrorStack> {
2205        let groups = CString::new(groups).unwrap();
2206        unsafe {
2207            cvt(ffi::SSL_CTX_set1_groups_list(self.as_ptr(), groups.as_ptr()) as c_int).map(|_| ())
2208        }
2209    }
2210
2211    /// Sets the number of TLS 1.3 session tickets that will be sent to a client after a full
2212    /// handshake.
2213    ///
2214    /// Requires OpenSSL 1.1.1 or newer.
2215    #[corresponds(SSL_CTX_set_num_tickets)]
2216    #[cfg(any(ossl111, boringssl))]
2217    pub fn set_num_tickets(&mut self, num_tickets: usize) -> Result<(), ErrorStack> {
2218        unsafe { cvt(ffi::SSL_CTX_set_num_tickets(self.as_ptr(), num_tickets)).map(|_| ()) }
2219    }
2220
2221    /// Set the context's security level to a value between 0 and 5, inclusive.
2222    /// A security value of 0 allows allows all parameters and algorithms.
2223    ///
2224    /// Requires OpenSSL 1.1.0 or newer.
2225    #[corresponds(SSL_CTX_set_security_level)]
2226    #[cfg(any(ossl110, libressl360))]
2227    pub fn set_security_level(&mut self, level: u32) {
2228        unsafe { ffi::SSL_CTX_set_security_level(self.as_ptr(), level as c_int) }
2229    }
2230
2231    /// Consumes the builder, returning a new `SslContext`.
2232    pub fn build(self) -> SslContext {
2233        self.0
2234    }
2235}
2236
2237foreign_type_and_impl_send_sync! {
2238    type CType = ffi::SSL_CTX;
2239    fn drop = ffi::SSL_CTX_free;
2240
2241    /// A context object for TLS streams.
2242    ///
2243    /// Applications commonly configure a single `SslContext` that is shared by all of its
2244    /// `SslStreams`.
2245    pub struct SslContext;
2246
2247    /// Reference to [`SslContext`]
2248    ///
2249    /// [`SslContext`]: struct.SslContext.html
2250    pub struct SslContextRef;
2251}
2252
2253impl Clone for SslContext {
2254    fn clone(&self) -> Self {
2255        (**self).to_owned()
2256    }
2257}
2258
2259impl ToOwned for SslContextRef {
2260    type Owned = SslContext;
2261
2262    fn to_owned(&self) -> Self::Owned {
2263        unsafe {
2264            SSL_CTX_up_ref(self.as_ptr());
2265            SslContext::from_ptr(self.as_ptr())
2266        }
2267    }
2268}
2269
2270// TODO: add useful info here
2271impl fmt::Debug for SslContext {
2272    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
2273        write!(fmt, "SslContext")
2274    }
2275}
2276
2277impl SslContext {
2278    /// Creates a new builder object for an `SslContext`.
2279    pub fn builder(method: SslMethod) -> Result<SslContextBuilder, ErrorStack> {
2280        SslContextBuilder::new(method)
2281    }
2282
2283    /// Returns a new extra data index.
2284    ///
2285    /// Each invocation of this function is guaranteed to return a distinct index. These can be used
2286    /// to store data in the context that can be retrieved later by callbacks, for example.
2287    #[corresponds(SSL_CTX_get_ex_new_index)]
2288    pub fn new_ex_index<T>() -> Result<Index<SslContext, T>, ErrorStack>
2289    where
2290        T: 'static + Sync + Send,
2291    {
2292        unsafe {
2293            ffi::init();
2294            let idx = cvt_n(get_new_idx(Some(free_data_box::<T>)))?;
2295            Ok(Index::from_raw(idx))
2296        }
2297    }
2298
2299    // FIXME should return a result?
2300    fn cached_ex_index<T>() -> Index<SslContext, T>
2301    where
2302        T: 'static + Sync + Send,
2303    {
2304        unsafe {
2305            let idx = *INDEXES
2306                .lock()
2307                .unwrap_or_else(|e| e.into_inner())
2308                .entry(TypeId::of::<T>())
2309                .or_insert_with(|| SslContext::new_ex_index::<T>().unwrap().as_raw());
2310            Index::from_raw(idx)
2311        }
2312    }
2313}
2314
2315impl SslContextRef {
2316    /// Returns the certificate associated with this `SslContext`, if present.
2317    ///
2318    /// Requires OpenSSL 1.0.2 or LibreSSL 2.7.0 or newer.
2319    #[corresponds(SSL_CTX_get0_certificate)]
2320    #[cfg(any(ossl102, libressl270))]
2321    pub fn certificate(&self) -> Option<&X509Ref> {
2322        unsafe {
2323            let ptr = ffi::SSL_CTX_get0_certificate(self.as_ptr());
2324            X509Ref::from_const_ptr_opt(ptr)
2325        }
2326    }
2327
2328    /// Returns the private key associated with this `SslContext`, if present.
2329    ///
2330    /// Requires OpenSSL 1.0.2 or LibreSSL 3.4.0 or newer.
2331    #[corresponds(SSL_CTX_get0_privatekey)]
2332    #[cfg(any(ossl102, libressl340))]
2333    pub fn private_key(&self) -> Option<&PKeyRef<Private>> {
2334        unsafe {
2335            let ptr = ffi::SSL_CTX_get0_privatekey(self.as_ptr());
2336            PKeyRef::from_const_ptr_opt(ptr)
2337        }
2338    }
2339
2340    /// Returns a shared reference to the certificate store used for verification.
2341    #[corresponds(SSL_CTX_get_cert_store)]
2342    pub fn cert_store(&self) -> &X509StoreRef {
2343        unsafe { X509StoreRef::from_ptr(ffi::SSL_CTX_get_cert_store(self.as_ptr())) }
2344    }
2345
2346    /// Returns a shared reference to the stack of certificates making up the chain from the leaf.
2347    #[corresponds(SSL_CTX_get_extra_chain_certs)]
2348    pub fn extra_chain_certs(&self) -> &StackRef<X509> {
2349        unsafe {
2350            let mut chain = ptr::null_mut();
2351            ffi::SSL_CTX_get_extra_chain_certs(self.as_ptr(), &mut chain);
2352            StackRef::from_const_ptr_opt(chain).expect("extra chain certs must not be null")
2353        }
2354    }
2355
2356    /// Returns a reference to the extra data at the specified index.
2357    #[corresponds(SSL_CTX_get_ex_data)]
2358    pub fn ex_data<T>(&self, index: Index<SslContext, T>) -> Option<&T> {
2359        unsafe {
2360            let data = ffi::SSL_CTX_get_ex_data(self.as_ptr(), index.as_raw());
2361            if data.is_null() {
2362                None
2363            } else {
2364                Some(&*(data as *const T))
2365            }
2366        }
2367    }
2368
2369    /// Gets the maximum amount of early data that will be accepted on incoming connections.
2370    ///
2371    /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer.
2372    #[corresponds(SSL_CTX_get_max_early_data)]
2373    #[cfg(any(ossl111, libressl340))]
2374    pub fn max_early_data(&self) -> u32 {
2375        unsafe { ffi::SSL_CTX_get_max_early_data(self.as_ptr()) }
2376    }
2377
2378    /// Adds a session to the context's cache.
2379    ///
2380    /// Returns `true` if the session was successfully added to the cache, and `false` if it was already present.
2381    ///
2382    /// # Safety
2383    ///
2384    /// The caller of this method is responsible for ensuring that the session has never been used with another
2385    /// `SslContext` than this one.
2386    #[corresponds(SSL_CTX_add_session)]
2387    pub unsafe fn add_session(&self, session: &SslSessionRef) -> bool {
2388        ffi::SSL_CTX_add_session(self.as_ptr(), session.as_ptr()) != 0
2389    }
2390
2391    /// Removes a session from the context's cache and marks it as non-resumable.
2392    ///
2393    /// Returns `true` if the session was successfully found and removed, and `false` otherwise.
2394    ///
2395    /// # Safety
2396    ///
2397    /// The caller of this method is responsible for ensuring that the session has never been used with another
2398    /// `SslContext` than this one.
2399    #[corresponds(SSL_CTX_remove_session)]
2400    pub unsafe fn remove_session(&self, session: &SslSessionRef) -> bool {
2401        ffi::SSL_CTX_remove_session(self.as_ptr(), session.as_ptr()) != 0
2402    }
2403
2404    /// Returns the context's session cache size limit.
2405    ///
2406    /// A value of 0 means that the cache size is unbounded.
2407    #[corresponds(SSL_CTX_sess_get_cache_size)]
2408    #[allow(clippy::unnecessary_cast)]
2409    pub fn session_cache_size(&self) -> i64 {
2410        unsafe { ffi::SSL_CTX_sess_get_cache_size(self.as_ptr()) as i64 }
2411    }
2412
2413    /// Returns the verify mode that was set on this context from [`SslContextBuilder::set_verify`].
2414    ///
2415    /// [`SslContextBuilder::set_verify`]: struct.SslContextBuilder.html#method.set_verify
2416    #[corresponds(SSL_CTX_get_verify_mode)]
2417    pub fn verify_mode(&self) -> SslVerifyMode {
2418        let mode = unsafe { ffi::SSL_CTX_get_verify_mode(self.as_ptr()) };
2419        SslVerifyMode::from_bits(mode).expect("SSL_CTX_get_verify_mode returned invalid mode")
2420    }
2421
2422    /// Gets the number of TLS 1.3 session tickets that will be sent to a client after a full
2423    /// handshake.
2424    ///
2425    /// Requires OpenSSL 1.1.1 or newer.
2426    #[corresponds(SSL_CTX_get_num_tickets)]
2427    #[cfg(ossl111)]
2428    pub fn num_tickets(&self) -> usize {
2429        unsafe { ffi::SSL_CTX_get_num_tickets(self.as_ptr()) }
2430    }
2431
2432    /// Get the context's security level, which controls the allowed parameters
2433    /// and algorithms.
2434    ///
2435    /// Requires OpenSSL 1.1.0 or newer.
2436    #[corresponds(SSL_CTX_get_security_level)]
2437    #[cfg(any(ossl110, libressl360))]
2438    pub fn security_level(&self) -> u32 {
2439        unsafe { ffi::SSL_CTX_get_security_level(self.as_ptr()) as u32 }
2440    }
2441}
2442
2443/// Information about the state of a cipher.
2444pub struct CipherBits {
2445    /// The number of secret bits used for the cipher.
2446    pub secret: i32,
2447
2448    /// The number of bits processed by the chosen algorithm.
2449    pub algorithm: i32,
2450}
2451
2452/// Information about a cipher.
2453pub struct SslCipher(*mut ffi::SSL_CIPHER);
2454
2455impl ForeignType for SslCipher {
2456    type CType = ffi::SSL_CIPHER;
2457    type Ref = SslCipherRef;
2458
2459    #[inline]
2460    unsafe fn from_ptr(ptr: *mut ffi::SSL_CIPHER) -> SslCipher {
2461        SslCipher(ptr)
2462    }
2463
2464    #[inline]
2465    fn as_ptr(&self) -> *mut ffi::SSL_CIPHER {
2466        self.0
2467    }
2468}
2469
2470impl Stackable for SslCipher {
2471    type StackType = ffi::stack_st_SSL_CIPHER;
2472}
2473
2474impl Deref for SslCipher {
2475    type Target = SslCipherRef;
2476
2477    fn deref(&self) -> &SslCipherRef {
2478        unsafe { SslCipherRef::from_ptr(self.0) }
2479    }
2480}
2481
2482impl DerefMut for SslCipher {
2483    fn deref_mut(&mut self) -> &mut SslCipherRef {
2484        unsafe { SslCipherRef::from_ptr_mut(self.0) }
2485    }
2486}
2487
2488/// Reference to an [`SslCipher`].
2489///
2490/// [`SslCipher`]: struct.SslCipher.html
2491pub struct SslCipherRef(Opaque);
2492
2493impl ForeignTypeRef for SslCipherRef {
2494    type CType = ffi::SSL_CIPHER;
2495}
2496
2497impl SslCipherRef {
2498    /// Returns the name of the cipher.
2499    #[corresponds(SSL_CIPHER_get_name)]
2500    pub fn name(&self) -> &'static str {
2501        unsafe {
2502            let ptr = ffi::SSL_CIPHER_get_name(self.as_ptr());
2503            CStr::from_ptr(ptr).to_str().unwrap()
2504        }
2505    }
2506
2507    /// Returns the RFC-standard name of the cipher, if one exists.
2508    ///
2509    /// Requires OpenSSL 1.1.1 or newer.
2510    #[corresponds(SSL_CIPHER_standard_name)]
2511    #[cfg(ossl111)]
2512    pub fn standard_name(&self) -> Option<&'static str> {
2513        unsafe {
2514            let ptr = ffi::SSL_CIPHER_standard_name(self.as_ptr());
2515            if ptr.is_null() {
2516                None
2517            } else {
2518                Some(CStr::from_ptr(ptr).to_str().unwrap())
2519            }
2520        }
2521    }
2522
2523    /// Returns the SSL/TLS protocol version that first defined the cipher.
2524    #[corresponds(SSL_CIPHER_get_version)]
2525    pub fn version(&self) -> &'static str {
2526        let version = unsafe {
2527            let ptr = ffi::SSL_CIPHER_get_version(self.as_ptr());
2528            CStr::from_ptr(ptr as *const _)
2529        };
2530
2531        str::from_utf8(version.to_bytes()).unwrap()
2532    }
2533
2534    /// Returns the number of bits used for the cipher.
2535    #[corresponds(SSL_CIPHER_get_bits)]
2536    #[allow(clippy::useless_conversion)]
2537    pub fn bits(&self) -> CipherBits {
2538        unsafe {
2539            let mut algo_bits = 0;
2540            let secret_bits = ffi::SSL_CIPHER_get_bits(self.as_ptr(), &mut algo_bits);
2541            CipherBits {
2542                secret: secret_bits.into(),
2543                algorithm: algo_bits.into(),
2544            }
2545        }
2546    }
2547
2548    /// Returns a textual description of the cipher.
2549    #[corresponds(SSL_CIPHER_description)]
2550    pub fn description(&self) -> String {
2551        unsafe {
2552            // SSL_CIPHER_description requires a buffer of at least 128 bytes.
2553            let mut buf = [0; 128];
2554            let ptr = ffi::SSL_CIPHER_description(self.as_ptr(), buf.as_mut_ptr(), 128);
2555            String::from_utf8(CStr::from_ptr(ptr as *const _).to_bytes().to_vec()).unwrap()
2556        }
2557    }
2558
2559    /// Returns the handshake digest of the cipher.
2560    ///
2561    /// Requires OpenSSL 1.1.1 or newer.
2562    #[corresponds(SSL_CIPHER_get_handshake_digest)]
2563    #[cfg(ossl111)]
2564    pub fn handshake_digest(&self) -> Option<MessageDigest> {
2565        unsafe {
2566            let ptr = ffi::SSL_CIPHER_get_handshake_digest(self.as_ptr());
2567            if ptr.is_null() {
2568                None
2569            } else {
2570                Some(MessageDigest::from_ptr(ptr))
2571            }
2572        }
2573    }
2574
2575    /// Returns the NID corresponding to the cipher.
2576    ///
2577    /// Requires OpenSSL 1.1.0 or LibreSSL 2.7.0 or newer.
2578    #[corresponds(SSL_CIPHER_get_cipher_nid)]
2579    #[cfg(any(ossl110, libressl270))]
2580    pub fn cipher_nid(&self) -> Option<Nid> {
2581        let n = unsafe { ffi::SSL_CIPHER_get_cipher_nid(self.as_ptr()) };
2582        if n == 0 {
2583            None
2584        } else {
2585            Some(Nid::from_raw(n))
2586        }
2587    }
2588}
2589
2590impl fmt::Debug for SslCipherRef {
2591    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
2592        write!(fmt, "{}", self.name())
2593    }
2594}
2595
2596/// A stack of selected ciphers, and a stack of selected signalling cipher suites
2597#[derive(Debug)]
2598pub struct CipherLists {
2599    pub suites: Stack<SslCipher>,
2600    pub signalling_suites: Stack<SslCipher>,
2601}
2602
2603foreign_type_and_impl_send_sync! {
2604    type CType = ffi::SSL_SESSION;
2605    fn drop = ffi::SSL_SESSION_free;
2606
2607    /// An encoded SSL session.
2608    ///
2609    /// These can be cached to share sessions across connections.
2610    pub struct SslSession;
2611
2612    /// Reference to [`SslSession`].
2613    ///
2614    /// [`SslSession`]: struct.SslSession.html
2615    pub struct SslSessionRef;
2616}
2617
2618impl Clone for SslSession {
2619    fn clone(&self) -> SslSession {
2620        SslSessionRef::to_owned(self)
2621    }
2622}
2623
2624impl SslSession {
2625    from_der! {
2626        /// Deserializes a DER-encoded session structure.
2627        #[corresponds(d2i_SSL_SESSION)]
2628        from_der,
2629        SslSession,
2630        ffi::d2i_SSL_SESSION
2631    }
2632}
2633
2634impl ToOwned for SslSessionRef {
2635    type Owned = SslSession;
2636
2637    fn to_owned(&self) -> SslSession {
2638        unsafe {
2639            SSL_SESSION_up_ref(self.as_ptr());
2640            SslSession(self.as_ptr())
2641        }
2642    }
2643}
2644
2645impl SslSessionRef {
2646    /// Returns the SSL session ID.
2647    #[corresponds(SSL_SESSION_get_id)]
2648    pub fn id(&self) -> &[u8] {
2649        unsafe {
2650            let mut len = 0;
2651            let p = ffi::SSL_SESSION_get_id(self.as_ptr(), &mut len);
2652            #[allow(clippy::unnecessary_cast)]
2653            util::from_raw_parts(p as *const u8, len as usize)
2654        }
2655    }
2656
2657    /// Returns the length of the master key.
2658    #[corresponds(SSL_SESSION_get_master_key)]
2659    pub fn master_key_len(&self) -> usize {
2660        unsafe { SSL_SESSION_get_master_key(self.as_ptr(), ptr::null_mut(), 0) }
2661    }
2662
2663    /// Copies the master key into the provided buffer.
2664    ///
2665    /// Returns the number of bytes written, or the size of the master key if the buffer is empty.
2666    #[corresponds(SSL_SESSION_get_master_key)]
2667    pub fn master_key(&self, buf: &mut [u8]) -> usize {
2668        unsafe { SSL_SESSION_get_master_key(self.as_ptr(), buf.as_mut_ptr(), buf.len()) }
2669    }
2670
2671    /// Gets the maximum amount of early data that can be sent on this session.
2672    ///
2673    /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer.
2674    #[corresponds(SSL_SESSION_get_max_early_data)]
2675    #[cfg(any(ossl111, libressl340))]
2676    pub fn max_early_data(&self) -> u32 {
2677        unsafe { ffi::SSL_SESSION_get_max_early_data(self.as_ptr()) }
2678    }
2679
2680    /// Returns the time at which the session was established, in seconds since the Unix epoch.
2681    #[corresponds(SSL_SESSION_get_time)]
2682    #[allow(clippy::useless_conversion)]
2683    pub fn time(&self) -> SslTimeTy {
2684        unsafe { ffi::SSL_SESSION_get_time(self.as_ptr()) }
2685    }
2686
2687    /// Returns the sessions timeout, in seconds.
2688    ///
2689    /// A session older than this time should not be used for session resumption.
2690    #[corresponds(SSL_SESSION_get_timeout)]
2691    #[allow(clippy::useless_conversion)]
2692    pub fn timeout(&self) -> i64 {
2693        unsafe { ffi::SSL_SESSION_get_timeout(self.as_ptr()).into() }
2694    }
2695
2696    /// Returns the session's TLS protocol version.
2697    ///
2698    /// Requires OpenSSL 1.1.0 or LibreSSL 2.7.0 or newer.
2699    #[corresponds(SSL_SESSION_get_protocol_version)]
2700    #[cfg(any(ossl110, libressl270))]
2701    pub fn protocol_version(&self) -> SslVersion {
2702        unsafe {
2703            let version = ffi::SSL_SESSION_get_protocol_version(self.as_ptr());
2704            SslVersion(version)
2705        }
2706    }
2707
2708    /// Returns the session's TLS protocol version.
2709    #[corresponds(SSL_SESSION_get_protocol_version)]
2710    #[cfg(boringssl)]
2711    pub fn protocol_version(&self) -> SslVersion {
2712        unsafe {
2713            let version = ffi::SSL_SESSION_get_protocol_version(self.as_ptr());
2714            SslVersion(version as _)
2715        }
2716    }
2717
2718    to_der! {
2719        /// Serializes the session into a DER-encoded structure.
2720        #[corresponds(i2d_SSL_SESSION)]
2721        to_der,
2722        ffi::i2d_SSL_SESSION
2723    }
2724}
2725
2726foreign_type_and_impl_send_sync! {
2727    type CType = ffi::SSL;
2728    fn drop = ffi::SSL_free;
2729
2730    /// The state of an SSL/TLS session.
2731    ///
2732    /// `Ssl` objects are created from an [`SslContext`], which provides configuration defaults.
2733    /// These defaults can be overridden on a per-`Ssl` basis, however.
2734    ///
2735    /// [`SslContext`]: struct.SslContext.html
2736    pub struct Ssl;
2737
2738    /// Reference to an [`Ssl`].
2739    ///
2740    /// [`Ssl`]: struct.Ssl.html
2741    pub struct SslRef;
2742}
2743
2744impl fmt::Debug for Ssl {
2745    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
2746        fmt::Debug::fmt(&**self, fmt)
2747    }
2748}
2749
2750impl Ssl {
2751    /// Returns a new extra data index.
2752    ///
2753    /// Each invocation of this function is guaranteed to return a distinct index. These can be used
2754    /// to store data in the context that can be retrieved later by callbacks, for example.
2755    #[corresponds(SSL_get_ex_new_index)]
2756    pub fn new_ex_index<T>() -> Result<Index<Ssl, T>, ErrorStack>
2757    where
2758        T: 'static + Sync + Send,
2759    {
2760        unsafe {
2761            ffi::init();
2762            let idx = cvt_n(get_new_ssl_idx(Some(free_data_box::<T>)))?;
2763            Ok(Index::from_raw(idx))
2764        }
2765    }
2766
2767    // FIXME should return a result?
2768    fn cached_ex_index<T>() -> Index<Ssl, T>
2769    where
2770        T: 'static + Sync + Send,
2771    {
2772        unsafe {
2773            let idx = *SSL_INDEXES
2774                .lock()
2775                .unwrap_or_else(|e| e.into_inner())
2776                .entry(TypeId::of::<T>())
2777                .or_insert_with(|| Ssl::new_ex_index::<T>().unwrap().as_raw());
2778            Index::from_raw(idx)
2779        }
2780    }
2781
2782    /// Creates a new `Ssl`.
2783    #[corresponds(SSL_new)]
2784    pub fn new(ctx: &SslContextRef) -> Result<Ssl, ErrorStack> {
2785        let session_ctx_index = try_get_session_ctx_index()?;
2786        unsafe {
2787            let ptr = cvt_p(ffi::SSL_new(ctx.as_ptr()))?;
2788            let mut ssl = Ssl::from_ptr(ptr);
2789            ssl.set_ex_data(*session_ctx_index, ctx.to_owned());
2790
2791            Ok(ssl)
2792        }
2793    }
2794
2795    /// Initiates a client-side TLS handshake.
2796    /// # Warning
2797    ///
2798    /// OpenSSL's default configuration is insecure. It is highly recommended to use
2799    /// `SslConnector` rather than `Ssl` directly, as it manages that configuration.
2800    #[corresponds(SSL_connect)]
2801    #[allow(deprecated)]
2802    pub fn connect<S>(self, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
2803    where
2804        S: Read + Write,
2805    {
2806        SslStreamBuilder::new(self, stream).connect()
2807    }
2808
2809    /// Initiates a server-side TLS handshake.
2810    ///
2811    /// # Warning
2812    ///
2813    /// OpenSSL's default configuration is insecure. It is highly recommended to use
2814    /// `SslAcceptor` rather than `Ssl` directly, as it manages that configuration.
2815    #[corresponds(SSL_accept)]
2816    #[allow(deprecated)]
2817    pub fn accept<S>(self, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
2818    where
2819        S: Read + Write,
2820    {
2821        SslStreamBuilder::new(self, stream).accept()
2822    }
2823}
2824
2825impl fmt::Debug for SslRef {
2826    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
2827        fmt.debug_struct("Ssl")
2828            .field("state", &self.state_string_long())
2829            .field("verify_result", &self.verify_result())
2830            .finish()
2831    }
2832}
2833
2834impl SslRef {
2835    #[cfg(not(feature = "tongsuo"))]
2836    fn get_raw_rbio(&self) -> *mut ffi::BIO {
2837        unsafe { ffi::SSL_get_rbio(self.as_ptr()) }
2838    }
2839
2840    #[cfg(feature = "tongsuo")]
2841    fn get_raw_rbio(&self) -> *mut ffi::BIO {
2842        unsafe {
2843            let bio = ffi::SSL_get_rbio(self.as_ptr());
2844            bio::find_correct_bio(bio)
2845        }
2846    }
2847
2848    fn get_error(&self, ret: c_int) -> ErrorCode {
2849        unsafe { ErrorCode::from_raw(ffi::SSL_get_error(self.as_ptr(), ret)) }
2850    }
2851
2852    /// Sets the mode used by the SSL, returning the new mode bit mask.
2853    ///
2854    /// Options already set before are not cleared.
2855    #[corresponds(SSL_set_mode)]
2856    pub fn set_mode(&mut self, mode: SslMode) -> SslMode {
2857        unsafe {
2858            let bits = ffi::SSL_set_mode(self.as_ptr(), mode.bits() as ModeTy) as SslBitType;
2859            SslMode::from_bits_retain(bits)
2860        }
2861    }
2862
2863    /// Clear the mode used by the SSL, returning the new mode bit mask.
2864    #[corresponds(SSL_clear_mode)]
2865    pub fn clear_mode(&mut self, mode: SslMode) -> SslMode {
2866        unsafe {
2867            let bits = ffi::SSL_clear_mode(self.as_ptr(), mode.bits() as ModeTy) as SslBitType;
2868            SslMode::from_bits_retain(bits)
2869        }
2870    }
2871
2872    /// Returns the mode set for the SSL.
2873    #[corresponds(SSL_get_mode)]
2874    pub fn mode(&self) -> SslMode {
2875        unsafe {
2876            let bits = ffi::SSL_get_mode(self.as_ptr()) as SslBitType;
2877            SslMode::from_bits_retain(bits)
2878        }
2879    }
2880
2881    /// Configure as an outgoing stream from a client.
2882    #[corresponds(SSL_set_connect_state)]
2883    pub fn set_connect_state(&mut self) {
2884        unsafe { ffi::SSL_set_connect_state(self.as_ptr()) }
2885    }
2886
2887    /// Configure as an incoming stream to a server.
2888    #[corresponds(SSL_set_accept_state)]
2889    pub fn set_accept_state(&mut self) {
2890        unsafe { ffi::SSL_set_accept_state(self.as_ptr()) }
2891    }
2892
2893    #[cfg(boringssl)]
2894    #[corresponds(SSL_ech_accepted)]
2895    pub fn ech_accepted(&self) -> bool {
2896        unsafe { ffi::SSL_ech_accepted(self.as_ptr()) != 0 }
2897    }
2898
2899    #[cfg(tongsuo)]
2900    #[corresponds(SSL_is_ntls)]
2901    pub fn is_ntls(&mut self) -> bool {
2902        unsafe { ffi::SSL_is_ntls(self.as_ptr()) != 0 }
2903    }
2904
2905    #[cfg(tongsuo)]
2906    #[corresponds(SSL_enable_ntls)]
2907    pub fn enable_ntls(&mut self) {
2908        unsafe { ffi::SSL_enable_ntls(self.as_ptr()) }
2909    }
2910
2911    #[cfg(tongsuo)]
2912    #[corresponds(SSL_disable_ntls)]
2913    pub fn disable_ntls(&mut self) {
2914        unsafe { ffi::SSL_disable_ntls(self.as_ptr()) }
2915    }
2916
2917    #[cfg(all(tongsuo, ossl300))]
2918    #[corresponds(SSL_enable_force_ntls)]
2919    pub fn enable_force_ntls(&mut self) {
2920        unsafe { ffi::SSL_enable_force_ntls(self.as_ptr()) }
2921    }
2922
2923    #[cfg(all(tongsuo, ossl300))]
2924    #[corresponds(SSL_disable_force_ntls)]
2925    pub fn disable_force_ntls(&mut self) {
2926        unsafe { ffi::SSL_disable_force_ntls(self.as_ptr()) }
2927    }
2928
2929    #[cfg(tongsuo)]
2930    #[corresponds(SSL_enable_sm_tls13_strict)]
2931    pub fn enable_sm_tls13_strict(&mut self) {
2932        unsafe { ffi::SSL_enable_sm_tls13_strict(self.as_ptr()) }
2933    }
2934
2935    #[cfg(tongsuo)]
2936    #[corresponds(SSL_disable_sm_tls13_strict)]
2937    pub fn disable_sm_tls13_strict(&mut self) {
2938        unsafe { ffi::SSL_disable_sm_tls13_strict(self.as_ptr()) }
2939    }
2940
2941    /// Like [`SslContextBuilder::set_verify`].
2942    ///
2943    /// [`SslContextBuilder::set_verify`]: struct.SslContextBuilder.html#method.set_verify
2944    #[corresponds(SSL_set_verify)]
2945    pub fn set_verify(&mut self, mode: SslVerifyMode) {
2946        unsafe { ffi::SSL_set_verify(self.as_ptr(), mode.bits() as c_int, None) }
2947    }
2948
2949    /// Returns the verify mode that was set using `set_verify`.
2950    #[corresponds(SSL_set_verify_mode)]
2951    pub fn verify_mode(&self) -> SslVerifyMode {
2952        let mode = unsafe { ffi::SSL_get_verify_mode(self.as_ptr()) };
2953        SslVerifyMode::from_bits(mode).expect("SSL_get_verify_mode returned invalid mode")
2954    }
2955
2956    /// Like [`SslContextBuilder::set_verify_callback`].
2957    ///
2958    /// [`SslContextBuilder::set_verify_callback`]: struct.SslContextBuilder.html#method.set_verify_callback
2959    #[corresponds(SSL_set_verify)]
2960    pub fn set_verify_callback<F>(&mut self, mode: SslVerifyMode, verify: F)
2961    where
2962        F: Fn(bool, &mut X509StoreContextRef) -> bool + 'static + Sync + Send,
2963    {
2964        unsafe {
2965            // this needs to be in an Arc since the callback can register a new callback!
2966            self.set_ex_data(Ssl::cached_ex_index(), Arc::new(verify));
2967            ffi::SSL_set_verify(
2968                self.as_ptr(),
2969                mode.bits() as c_int,
2970                Some(ssl_raw_verify::<F>),
2971            );
2972        }
2973    }
2974
2975    /// Like [`SslContextBuilder::set_dh_auto`].
2976    ///
2977    /// [`SslContextBuilder::set_dh_auto`]: struct.SslContextBuilder.html#method.set_dh_auto
2978    #[corresponds(SSL_set_dh_auto)]
2979    #[cfg(ossl300)]
2980    pub fn set_dh_auto(&mut self, onoff: bool) -> Result<(), ErrorStack> {
2981        unsafe { cvt(ffi::SSL_set_dh_auto(self.as_ptr(), onoff as c_int)).map(|_| ()) }
2982    }
2983
2984    /// Like [`SslContextBuilder::set_tmp_dh`].
2985    ///
2986    /// [`SslContextBuilder::set_tmp_dh`]: struct.SslContextBuilder.html#method.set_tmp_dh
2987    #[corresponds(SSL_set_tmp_dh)]
2988    pub fn set_tmp_dh(&mut self, dh: &DhRef<Params>) -> Result<(), ErrorStack> {
2989        unsafe { cvt(ffi::SSL_set_tmp_dh(self.as_ptr(), dh.as_ptr()) as c_int).map(|_| ()) }
2990    }
2991
2992    /// Like [`SslContextBuilder::set_tmp_dh_callback`].
2993    ///
2994    /// [`SslContextBuilder::set_tmp_dh_callback`]: struct.SslContextBuilder.html#method.set_tmp_dh_callback
2995    #[corresponds(SSL_set_tmp_dh_callback)]
2996    pub fn set_tmp_dh_callback<F>(&mut self, callback: F)
2997    where
2998        F: Fn(&mut SslRef, bool, u32) -> Result<Dh<Params>, ErrorStack> + 'static + Sync + Send,
2999    {
3000        unsafe {
3001            // this needs to be in an Arc since the callback can register a new callback!
3002            self.set_ex_data(Ssl::cached_ex_index(), Arc::new(callback));
3003            ffi::SSL_set_tmp_dh_callback(self.as_ptr(), Some(raw_tmp_dh_ssl::<F>));
3004        }
3005    }
3006
3007    /// Like [`SslContextBuilder::set_tmp_ecdh`].
3008    ///
3009    /// [`SslContextBuilder::set_tmp_ecdh`]: struct.SslContextBuilder.html#method.set_tmp_ecdh
3010    #[corresponds(SSL_set_tmp_ecdh)]
3011    pub fn set_tmp_ecdh(&mut self, key: &EcKeyRef<Params>) -> Result<(), ErrorStack> {
3012        unsafe { cvt(ffi::SSL_set_tmp_ecdh(self.as_ptr(), key.as_ptr()) as c_int).map(|_| ()) }
3013    }
3014
3015    /// Like [`SslContextBuilder::set_ecdh_auto`].
3016    ///
3017    /// Requires OpenSSL 1.0.2 or LibreSSL.
3018    ///
3019    /// [`SslContextBuilder::set_tmp_ecdh`]: struct.SslContextBuilder.html#method.set_tmp_ecdh
3020    #[corresponds(SSL_set_ecdh_auto)]
3021    #[cfg(any(all(ossl102, not(ossl110)), libressl))]
3022    pub fn set_ecdh_auto(&mut self, onoff: bool) -> Result<(), ErrorStack> {
3023        unsafe { cvt(ffi::SSL_set_ecdh_auto(self.as_ptr(), onoff as c_int)).map(|_| ()) }
3024    }
3025
3026    /// Like [`SslContextBuilder::set_alpn_protos`].
3027    ///
3028    /// Requires BoringSSL or OpenSSL 1.0.2 or LibreSSL 2.6.1 or newer.
3029    ///
3030    /// [`SslContextBuilder::set_alpn_protos`]: struct.SslContextBuilder.html#method.set_alpn_protos
3031    #[corresponds(SSL_set_alpn_protos)]
3032    #[cfg(any(ossl102, libressl261, boringssl))]
3033    pub fn set_alpn_protos(&mut self, protocols: &[u8]) -> Result<(), ErrorStack> {
3034        unsafe {
3035            assert!(protocols.len() <= c_uint::MAX as usize);
3036            let r =
3037                ffi::SSL_set_alpn_protos(self.as_ptr(), protocols.as_ptr(), protocols.len() as _);
3038            // fun fact, SSL_set_alpn_protos has a reversed return code D:
3039            if r == 0 {
3040                Ok(())
3041            } else {
3042                Err(ErrorStack::get())
3043            }
3044        }
3045    }
3046
3047    /// Returns the current cipher if the session is active.
3048    #[corresponds(SSL_get_current_cipher)]
3049    pub fn current_cipher(&self) -> Option<&SslCipherRef> {
3050        unsafe {
3051            let ptr = ffi::SSL_get_current_cipher(self.as_ptr());
3052
3053            SslCipherRef::from_const_ptr_opt(ptr)
3054        }
3055    }
3056
3057    /// Returns a short string describing the state of the session.
3058    #[corresponds(SSL_state_string)]
3059    pub fn state_string(&self) -> &'static str {
3060        let state = unsafe {
3061            let ptr = ffi::SSL_state_string(self.as_ptr());
3062            CStr::from_ptr(ptr as *const _)
3063        };
3064
3065        str::from_utf8(state.to_bytes()).unwrap()
3066    }
3067
3068    /// Returns a longer string describing the state of the session.
3069    #[corresponds(SSL_state_string_long)]
3070    pub fn state_string_long(&self) -> &'static str {
3071        let state = unsafe {
3072            let ptr = ffi::SSL_state_string_long(self.as_ptr());
3073            CStr::from_ptr(ptr as *const _)
3074        };
3075
3076        str::from_utf8(state.to_bytes()).unwrap()
3077    }
3078
3079    /// Sets the host name to be sent to the server for Server Name Indication (SNI).
3080    ///
3081    /// It has no effect for a server-side connection.
3082    #[corresponds(SSL_set_tlsext_host_name)]
3083    pub fn set_hostname(&mut self, hostname: &str) -> Result<(), ErrorStack> {
3084        let cstr = CString::new(hostname).unwrap();
3085        unsafe {
3086            cvt(ffi::SSL_set_tlsext_host_name(self.as_ptr(), cstr.as_ptr() as *mut _) as c_int)
3087                .map(|_| ())
3088        }
3089    }
3090
3091    /// Returns the peer's certificate, if present.
3092    #[corresponds(SSL_get_peer_certificate)]
3093    pub fn peer_certificate(&self) -> Option<X509> {
3094        unsafe {
3095            let ptr = SSL_get1_peer_certificate(self.as_ptr());
3096            X509::from_ptr_opt(ptr)
3097        }
3098    }
3099
3100    /// Returns the certificate chain of the peer, if present.
3101    ///
3102    /// On the client side, the chain includes the leaf certificate, but on the server side it does
3103    /// not. Fun!
3104    #[corresponds(SSL_get_peer_cert_chain)]
3105    pub fn peer_cert_chain(&self) -> Option<&StackRef<X509>> {
3106        unsafe {
3107            let ptr = ffi::SSL_get_peer_cert_chain(self.as_ptr());
3108            StackRef::from_const_ptr_opt(ptr)
3109        }
3110    }
3111
3112    /// Returns the verified certificate chain of the peer, including the leaf certificate.
3113    ///
3114    /// If verification was not successful (i.e. [`verify_result`] does not return
3115    /// [`X509VerifyResult::OK`]), this chain may be incomplete or invalid.
3116    ///
3117    /// Requires OpenSSL 1.1.0 or newer.
3118    ///
3119    /// [`verify_result`]: #method.verify_result
3120    /// [`X509VerifyResult::OK`]: ../x509/struct.X509VerifyResult.html#associatedconstant.OK
3121    #[corresponds(SSL_get0_verified_chain)]
3122    #[cfg(ossl110)]
3123    pub fn verified_chain(&self) -> Option<&StackRef<X509>> {
3124        unsafe {
3125            let ptr = ffi::SSL_get0_verified_chain(self.as_ptr());
3126            StackRef::from_const_ptr_opt(ptr)
3127        }
3128    }
3129
3130    /// Like [`SslContext::certificate`].
3131    #[corresponds(SSL_get_certificate)]
3132    pub fn certificate(&self) -> Option<&X509Ref> {
3133        unsafe {
3134            let ptr = ffi::SSL_get_certificate(self.as_ptr());
3135            X509Ref::from_const_ptr_opt(ptr)
3136        }
3137    }
3138
3139    /// Like [`SslContext::private_key`].
3140    ///
3141    /// [`SslContext::private_key`]: struct.SslContext.html#method.private_key
3142    #[corresponds(SSL_get_privatekey)]
3143    pub fn private_key(&self) -> Option<&PKeyRef<Private>> {
3144        unsafe {
3145            let ptr = ffi::SSL_get_privatekey(self.as_ptr());
3146            PKeyRef::from_const_ptr_opt(ptr)
3147        }
3148    }
3149
3150    /// Returns the protocol version of the session.
3151    #[corresponds(SSL_version)]
3152    pub fn version2(&self) -> Option<SslVersion> {
3153        unsafe {
3154            let r = ffi::SSL_version(self.as_ptr());
3155            if r == 0 {
3156                None
3157            } else {
3158                Some(SslVersion(r))
3159            }
3160        }
3161    }
3162
3163    /// Returns a string describing the protocol version of the session.
3164    #[corresponds(SSL_get_version)]
3165    pub fn version_str(&self) -> &'static str {
3166        let version = unsafe {
3167            let ptr = ffi::SSL_get_version(self.as_ptr());
3168            CStr::from_ptr(ptr as *const _)
3169        };
3170
3171        str::from_utf8(version.to_bytes()).unwrap()
3172    }
3173
3174    /// Returns the protocol selected via Application Layer Protocol Negotiation (ALPN).
3175    ///
3176    /// The protocol's name is returned is an opaque sequence of bytes. It is up to the client
3177    /// to interpret it.
3178    ///
3179    /// Requires BoringSSL or OpenSSL 1.0.2 or LibreSSL 2.6.1 or newer.
3180    #[corresponds(SSL_get0_alpn_selected)]
3181    #[cfg(any(ossl102, libressl261, boringssl))]
3182    pub fn selected_alpn_protocol(&self) -> Option<&[u8]> {
3183        unsafe {
3184            let mut data: *const c_uchar = ptr::null();
3185            let mut len: c_uint = 0;
3186            // Get the negotiated protocol from the SSL instance.
3187            // `data` will point at a `c_uchar` array; `len` will contain the length of this array.
3188            ffi::SSL_get0_alpn_selected(self.as_ptr(), &mut data, &mut len);
3189
3190            if data.is_null() {
3191                None
3192            } else {
3193                Some(util::from_raw_parts(data, len as usize))
3194            }
3195        }
3196    }
3197
3198    /// Enables the DTLS extension "use_srtp" as defined in RFC5764.
3199    #[corresponds(SSL_set_tlsext_use_srtp)]
3200    pub fn set_tlsext_use_srtp(&mut self, protocols: &str) -> Result<(), ErrorStack> {
3201        unsafe {
3202            let cstr = CString::new(protocols).unwrap();
3203
3204            let r = ffi::SSL_set_tlsext_use_srtp(self.as_ptr(), cstr.as_ptr());
3205            // fun fact, set_tlsext_use_srtp has a reversed return code D:
3206            if r == 0 {
3207                Ok(())
3208            } else {
3209                Err(ErrorStack::get())
3210            }
3211        }
3212    }
3213
3214    /// Gets all SRTP profiles that are enabled for handshake via set_tlsext_use_srtp
3215    ///
3216    /// DTLS extension "use_srtp" as defined in RFC5764 has to be enabled.
3217    #[corresponds(SSL_get_srtp_profiles)]
3218    pub fn srtp_profiles(&self) -> Option<&StackRef<SrtpProtectionProfile>> {
3219        unsafe {
3220            let chain = ffi::SSL_get_srtp_profiles(self.as_ptr());
3221
3222            StackRef::from_const_ptr_opt(chain)
3223        }
3224    }
3225
3226    /// Gets the SRTP profile selected by handshake.
3227    ///
3228    /// DTLS extension "use_srtp" as defined in RFC5764 has to be enabled.
3229    #[corresponds(SSL_get_selected_srtp_profile)]
3230    pub fn selected_srtp_profile(&self) -> Option<&SrtpProtectionProfileRef> {
3231        unsafe {
3232            let profile = ffi::SSL_get_selected_srtp_profile(self.as_ptr());
3233
3234            SrtpProtectionProfileRef::from_const_ptr_opt(profile)
3235        }
3236    }
3237
3238    /// Returns the number of bytes remaining in the currently processed TLS record.
3239    ///
3240    /// If this is greater than 0, the next call to `read` will not call down to the underlying
3241    /// stream.
3242    #[corresponds(SSL_pending)]
3243    pub fn pending(&self) -> usize {
3244        unsafe { ffi::SSL_pending(self.as_ptr()) as usize }
3245    }
3246
3247    /// Returns the servername sent by the client via Server Name Indication (SNI).
3248    ///
3249    /// It is only useful on the server side.
3250    ///
3251    /// # Note
3252    ///
3253    /// While the SNI specification requires that servernames be valid domain names (and therefore
3254    /// ASCII), OpenSSL does not enforce this restriction. If the servername provided by the client
3255    /// is not valid UTF-8, this function will return `None`. The `servername_raw` method returns
3256    /// the raw bytes and does not have this restriction.
3257    ///
3258    /// [`SSL_get_servername`]: https://www.openssl.org/docs/manmaster/man3/SSL_get_servername.html
3259    #[corresponds(SSL_get_servername)]
3260    // FIXME maybe rethink in 0.11?
3261    pub fn servername(&self, type_: NameType) -> Option<&str> {
3262        self.servername_raw(type_)
3263            .and_then(|b| str::from_utf8(b).ok())
3264    }
3265
3266    /// Returns the servername sent by the client via Server Name Indication (SNI).
3267    ///
3268    /// It is only useful on the server side.
3269    ///
3270    /// # Note
3271    ///
3272    /// Unlike `servername`, this method does not require the name be valid UTF-8.
3273    #[corresponds(SSL_get_servername)]
3274    pub fn servername_raw(&self, type_: NameType) -> Option<&[u8]> {
3275        unsafe {
3276            let name = ffi::SSL_get_servername(self.as_ptr(), type_.0);
3277            if name.is_null() {
3278                None
3279            } else {
3280                Some(CStr::from_ptr(name as *const _).to_bytes())
3281            }
3282        }
3283    }
3284
3285    /// Changes the context corresponding to the current connection.
3286    ///
3287    /// It is most commonly used in the Server Name Indication (SNI) callback.
3288    #[corresponds(SSL_set_SSL_CTX)]
3289    pub fn set_ssl_context(&mut self, ctx: &SslContextRef) -> Result<(), ErrorStack> {
3290        unsafe { cvt_p(ffi::SSL_set_SSL_CTX(self.as_ptr(), ctx.as_ptr())).map(|_| ()) }
3291    }
3292
3293    /// Returns the context corresponding to the current connection.
3294    #[corresponds(SSL_get_SSL_CTX)]
3295    pub fn ssl_context(&self) -> &SslContextRef {
3296        unsafe {
3297            let ssl_ctx = ffi::SSL_get_SSL_CTX(self.as_ptr());
3298            SslContextRef::from_ptr(ssl_ctx)
3299        }
3300    }
3301
3302    /// Returns a mutable reference to the X509 verification configuration.
3303    ///
3304    /// Requires BoringSSL or OpenSSL 1.0.2 or newer.
3305    #[corresponds(SSL_get0_param)]
3306    #[cfg(any(ossl102, boringssl, libressl261))]
3307    pub fn param_mut(&mut self) -> &mut X509VerifyParamRef {
3308        unsafe { X509VerifyParamRef::from_ptr_mut(ffi::SSL_get0_param(self.as_ptr())) }
3309    }
3310
3311    /// Returns the certificate verification result.
3312    #[corresponds(SSL_get_verify_result)]
3313    pub fn verify_result(&self) -> X509VerifyResult {
3314        unsafe { X509VerifyResult::from_raw(ffi::SSL_get_verify_result(self.as_ptr()) as c_int) }
3315    }
3316
3317    /// Returns a shared reference to the SSL session.
3318    #[corresponds(SSL_get_session)]
3319    pub fn session(&self) -> Option<&SslSessionRef> {
3320        unsafe {
3321            let p = ffi::SSL_get_session(self.as_ptr());
3322            SslSessionRef::from_const_ptr_opt(p)
3323        }
3324    }
3325
3326    /// Copies the `client_random` value sent by the client in the TLS handshake into a buffer.
3327    ///
3328    /// Returns the number of bytes copied, or if the buffer is empty, the size of the `client_random`
3329    /// value.
3330    ///
3331    /// Requires OpenSSL 1.1.0 or LibreSSL 2.7.0 or newer.
3332    #[corresponds(SSL_get_client_random)]
3333    #[cfg(any(ossl110, libressl270))]
3334    pub fn client_random(&self, buf: &mut [u8]) -> usize {
3335        unsafe {
3336            ffi::SSL_get_client_random(self.as_ptr(), buf.as_mut_ptr() as *mut c_uchar, buf.len())
3337        }
3338    }
3339
3340    /// Copies the `server_random` value sent by the server in the TLS handshake into a buffer.
3341    ///
3342    /// Returns the number of bytes copied, or if the buffer is empty, the size of the `server_random`
3343    /// value.
3344    ///
3345    /// Requires OpenSSL 1.1.0 or LibreSSL 2.7.0 or newer.
3346    #[corresponds(SSL_get_server_random)]
3347    #[cfg(any(ossl110, libressl270))]
3348    pub fn server_random(&self, buf: &mut [u8]) -> usize {
3349        unsafe {
3350            ffi::SSL_get_server_random(self.as_ptr(), buf.as_mut_ptr() as *mut c_uchar, buf.len())
3351        }
3352    }
3353
3354    /// Derives keying material for application use in accordance to RFC 5705.
3355    #[corresponds(SSL_export_keying_material)]
3356    pub fn export_keying_material(
3357        &self,
3358        out: &mut [u8],
3359        label: &str,
3360        context: Option<&[u8]>,
3361    ) -> Result<(), ErrorStack> {
3362        unsafe {
3363            let (context, contextlen, use_context) = match context {
3364                Some(context) => (context.as_ptr() as *const c_uchar, context.len(), 1),
3365                None => (ptr::null(), 0, 0),
3366            };
3367            cvt(ffi::SSL_export_keying_material(
3368                self.as_ptr(),
3369                out.as_mut_ptr() as *mut c_uchar,
3370                out.len(),
3371                label.as_ptr() as *const c_char,
3372                label.len(),
3373                context,
3374                contextlen,
3375                use_context,
3376            ))
3377            .map(|_| ())
3378        }
3379    }
3380
3381    /// Derives keying material for application use in accordance to RFC 5705.
3382    ///
3383    /// This function is only usable with TLSv1.3, wherein there is no distinction between an empty context and no
3384    /// context. Therefore, unlike `export_keying_material`, `context` must always be supplied.
3385    ///
3386    /// Requires OpenSSL 1.1.1 or newer.
3387    #[corresponds(SSL_export_keying_material_early)]
3388    #[cfg(ossl111)]
3389    pub fn export_keying_material_early(
3390        &self,
3391        out: &mut [u8],
3392        label: &str,
3393        context: &[u8],
3394    ) -> Result<(), ErrorStack> {
3395        unsafe {
3396            cvt(ffi::SSL_export_keying_material_early(
3397                self.as_ptr(),
3398                out.as_mut_ptr() as *mut c_uchar,
3399                out.len(),
3400                label.as_ptr() as *const c_char,
3401                label.len(),
3402                context.as_ptr() as *const c_uchar,
3403                context.len(),
3404            ))
3405            .map(|_| ())
3406        }
3407    }
3408
3409    /// Sets the session to be used.
3410    ///
3411    /// This should be called before the handshake to attempt to reuse a previously established
3412    /// session. If the server is not willing to reuse the session, a new one will be transparently
3413    /// negotiated.
3414    ///
3415    /// # Safety
3416    ///
3417    /// The caller of this method is responsible for ensuring that the session is associated
3418    /// with the same `SslContext` as this `Ssl`.
3419    #[corresponds(SSL_set_session)]
3420    pub unsafe fn set_session(&mut self, session: &SslSessionRef) -> Result<(), ErrorStack> {
3421        cvt(ffi::SSL_set_session(self.as_ptr(), session.as_ptr())).map(|_| ())
3422    }
3423
3424    /// Determines if the session provided to `set_session` was successfully reused.
3425    #[corresponds(SSL_session_reused)]
3426    pub fn session_reused(&self) -> bool {
3427        unsafe { ffi::SSL_session_reused(self.as_ptr()) != 0 }
3428    }
3429
3430    /// Causes ssl (which must be the client end of a connection) to request a stapled OCSP response from the server
3431    ///
3432    /// This corresponds to [`SSL_enable_ocsp_stapling`].
3433    ///
3434    /// [`SSL_enable_ocsp_stapling`]: https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#SSL_enable_ocsp_stapling
3435    ///
3436    /// Requires BoringSSL.
3437    #[cfg(boringssl)]
3438    pub fn enable_ocsp_stapling(&mut self) {
3439        unsafe { ffi::SSL_enable_ocsp_stapling(self.as_ptr()) }
3440    }
3441
3442    /// Causes ssl (which must be the client end of a connection) to request SCTs from the server
3443    ///
3444    /// This corresponds to [`SSL_enable_signed_cert_timestamps`].
3445    ///
3446    /// [`SSL_enable_signed_cert_timestamps`]: https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#SSL_enable_signed_cert_timestamps
3447    ///
3448    /// Requires BoringSSL.
3449    #[cfg(boringssl)]
3450    pub fn enable_signed_cert_timestamps(&mut self) {
3451        unsafe { ffi::SSL_enable_signed_cert_timestamps(self.as_ptr()) }
3452    }
3453
3454    /// Configures whether sockets on ssl should permute extensions.
3455    ///
3456    /// This corresponds to [`SSL_set_permute_extensions`].
3457    ///
3458    /// [`SSL_set_permute_extensions`]: https://commondatastorage.googleapis.com/chromium-boringssl-docs/ssl.h.html#SSL_set_permute_extensions
3459    ///
3460    /// Requires BoringSSL.
3461    #[cfg(boringssl)]
3462    pub fn set_permute_extensions(&mut self, enabled: bool) {
3463        unsafe { ffi::SSL_set_permute_extensions(self.as_ptr(), enabled as c_int) }
3464    }
3465
3466    /// Enable the processing of signed certificate timestamps (SCTs) for the given SSL connection.
3467    #[corresponds(SSL_enable_ct)]
3468    #[cfg(ossl111)]
3469    pub fn enable_ct(&mut self, validation_mode: SslCtValidationMode) -> Result<(), ErrorStack> {
3470        unsafe { cvt(ffi::SSL_enable_ct(self.as_ptr(), validation_mode.0)).map(|_| ()) }
3471    }
3472
3473    /// Check whether CT processing is enabled.
3474    #[corresponds(SSL_ct_is_enabled)]
3475    #[cfg(ossl111)]
3476    pub fn ct_is_enabled(&self) -> bool {
3477        unsafe { ffi::SSL_ct_is_enabled(self.as_ptr()) == 1 }
3478    }
3479
3480    /// Sets the status response a client wishes the server to reply with.
3481    #[corresponds(SSL_set_tlsext_status_type)]
3482    pub fn set_status_type(&mut self, type_: StatusType) -> Result<(), ErrorStack> {
3483        unsafe {
3484            cvt(ffi::SSL_set_tlsext_status_type(self.as_ptr(), type_.as_raw()) as c_int).map(|_| ())
3485        }
3486    }
3487
3488    /// Determines if current session used Extended Master Secret
3489    ///
3490    /// Returns `None` if the handshake is still in-progress.
3491    #[corresponds(SSL_get_extms_support)]
3492    #[cfg(ossl110)]
3493    pub fn extms_support(&self) -> Option<bool> {
3494        unsafe {
3495            match ffi::SSL_get_extms_support(self.as_ptr()) {
3496                -1 => None,
3497                ret => Some(ret != 0),
3498            }
3499        }
3500    }
3501
3502    /// Returns the server's OCSP response, if present.
3503    #[corresponds(SSL_get_tlsext_status_ocsp_resp)]
3504    #[cfg(not(boringssl))]
3505    pub fn ocsp_status(&self) -> Option<&[u8]> {
3506        unsafe {
3507            let mut p = ptr::null_mut();
3508            let len = ffi::SSL_get_tlsext_status_ocsp_resp(self.as_ptr(), &mut p);
3509
3510            if len < 0 {
3511                None
3512            } else {
3513                Some(util::from_raw_parts(p as *const u8, len as usize))
3514            }
3515        }
3516    }
3517
3518    /// Returns the server's OCSP response, if present.
3519    #[corresponds(SSL_get0_ocsp_response)]
3520    #[cfg(boringssl)]
3521    pub fn ocsp_status(&self) -> Option<&[u8]> {
3522        unsafe {
3523            let mut p = ptr::null();
3524            let mut len: usize = 0;
3525            ffi::SSL_get0_ocsp_response(self.as_ptr(), &mut p, &mut len);
3526
3527            if len == 0 {
3528                None
3529            } else {
3530                Some(util::from_raw_parts(p as *const u8, len))
3531            }
3532        }
3533    }
3534
3535    /// Sets the OCSP response to be returned to the client.
3536    #[corresponds(SSL_set_tlsext_status_ocsp_resp)]
3537    #[cfg(not(boringssl))]
3538    pub fn set_ocsp_status(&mut self, response: &[u8]) -> Result<(), ErrorStack> {
3539        unsafe {
3540            assert!(response.len() <= c_int::MAX as usize);
3541            let p = cvt_p(ffi::OPENSSL_malloc(response.len() as _))?;
3542            ptr::copy_nonoverlapping(response.as_ptr(), p as *mut u8, response.len());
3543            cvt(ffi::SSL_set_tlsext_status_ocsp_resp(
3544                self.as_ptr(),
3545                p as *mut c_uchar,
3546                response.len() as c_long,
3547            ) as c_int)
3548            .map(|_| ())
3549            .map_err(|e| {
3550                ffi::OPENSSL_free(p);
3551                e
3552            })
3553        }
3554    }
3555
3556    /// Sets the OCSP response to be returned to the client.
3557    #[corresponds(SSL_set_ocsp_response)]
3558    #[cfg(boringssl)]
3559    pub fn set_ocsp_status(&mut self, response: &[u8]) -> Result<(), ErrorStack> {
3560        unsafe {
3561            cvt(ffi::SSL_set_ocsp_response(
3562                self.as_ptr(),
3563                response.as_ptr(),
3564                response.len(),
3565            ))
3566            .map(|_| ())
3567        }
3568    }
3569
3570    /// Determines if this `Ssl` is configured for server-side or client-side use.
3571    #[corresponds(SSL_is_server)]
3572    pub fn is_server(&self) -> bool {
3573        unsafe { SSL_is_server(self.as_ptr()) != 0 }
3574    }
3575
3576    /// Sets the extra data at the specified index.
3577    ///
3578    /// This can be used to provide data to callbacks registered with the context. Use the
3579    /// `Ssl::new_ex_index` method to create an `Index`.
3580    // FIXME should return a result
3581    #[corresponds(SSL_set_ex_data)]
3582    pub fn set_ex_data<T>(&mut self, index: Index<Ssl, T>, data: T) {
3583        match self.ex_data_mut(index) {
3584            Some(v) => *v = data,
3585            None => unsafe {
3586                let data = Box::new(data);
3587                ffi::SSL_set_ex_data(
3588                    self.as_ptr(),
3589                    index.as_raw(),
3590                    Box::into_raw(data) as *mut c_void,
3591                );
3592            },
3593        }
3594    }
3595
3596    /// Returns a reference to the extra data at the specified index.
3597    #[corresponds(SSL_get_ex_data)]
3598    pub fn ex_data<T>(&self, index: Index<Ssl, T>) -> Option<&T> {
3599        unsafe {
3600            let data = ffi::SSL_get_ex_data(self.as_ptr(), index.as_raw());
3601            if data.is_null() {
3602                None
3603            } else {
3604                Some(&*(data as *const T))
3605            }
3606        }
3607    }
3608
3609    /// Returns a mutable reference to the extra data at the specified index.
3610    #[corresponds(SSL_get_ex_data)]
3611    pub fn ex_data_mut<T>(&mut self, index: Index<Ssl, T>) -> Option<&mut T> {
3612        unsafe {
3613            let data = ffi::SSL_get_ex_data(self.as_ptr(), index.as_raw());
3614            if data.is_null() {
3615                None
3616            } else {
3617                Some(&mut *(data as *mut T))
3618            }
3619        }
3620    }
3621
3622    /// Sets the maximum amount of early data that will be accepted on this connection.
3623    ///
3624    /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer.
3625    #[corresponds(SSL_set_max_early_data)]
3626    #[cfg(any(ossl111, libressl340))]
3627    pub fn set_max_early_data(&mut self, bytes: u32) -> Result<(), ErrorStack> {
3628        if unsafe { ffi::SSL_set_max_early_data(self.as_ptr(), bytes) } == 1 {
3629            Ok(())
3630        } else {
3631            Err(ErrorStack::get())
3632        }
3633    }
3634
3635    /// Gets the maximum amount of early data that can be sent on this connection.
3636    ///
3637    /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer.
3638    #[corresponds(SSL_get_max_early_data)]
3639    #[cfg(any(ossl111, libressl340))]
3640    pub fn max_early_data(&self) -> u32 {
3641        unsafe { ffi::SSL_get_max_early_data(self.as_ptr()) }
3642    }
3643
3644    /// Copies the contents of the last Finished message sent to the peer into the provided buffer.
3645    ///
3646    /// The total size of the message is returned, so this can be used to determine the size of the
3647    /// buffer required.
3648    #[corresponds(SSL_get_finished)]
3649    pub fn finished(&self, buf: &mut [u8]) -> usize {
3650        unsafe { ffi::SSL_get_finished(self.as_ptr(), buf.as_mut_ptr() as *mut c_void, buf.len()) }
3651    }
3652
3653    /// Copies the contents of the last Finished message received from the peer into the provided
3654    /// buffer.
3655    ///
3656    /// The total size of the message is returned, so this can be used to determine the size of the
3657    /// buffer required.
3658    #[corresponds(SSL_get_peer_finished)]
3659    pub fn peer_finished(&self, buf: &mut [u8]) -> usize {
3660        unsafe {
3661            ffi::SSL_get_peer_finished(self.as_ptr(), buf.as_mut_ptr() as *mut c_void, buf.len())
3662        }
3663    }
3664
3665    /// Determines if the initial handshake has been completed.
3666    #[corresponds(SSL_is_init_finished)]
3667    #[cfg(ossl110)]
3668    pub fn is_init_finished(&self) -> bool {
3669        unsafe { ffi::SSL_is_init_finished(self.as_ptr()) != 0 }
3670    }
3671
3672    /// Determines if the client's hello message is in the SSLv2 format.
3673    ///
3674    /// This can only be used inside of the client hello callback. Otherwise, `false` is returned.
3675    ///
3676    /// Requires OpenSSL 1.1.1 or newer.
3677    #[corresponds(SSL_client_hello_isv2)]
3678    #[cfg(ossl111)]
3679    pub fn client_hello_isv2(&self) -> bool {
3680        unsafe { ffi::SSL_client_hello_isv2(self.as_ptr()) != 0 }
3681    }
3682
3683    /// Returns the legacy version field of the client's hello message.
3684    ///
3685    /// This can only be used inside of the client hello callback. Otherwise, `None` is returned.
3686    ///
3687    /// Requires OpenSSL 1.1.1 or newer.
3688    #[corresponds(SSL_client_hello_get0_legacy_version)]
3689    #[cfg(ossl111)]
3690    pub fn client_hello_legacy_version(&self) -> Option<SslVersion> {
3691        unsafe {
3692            let version = ffi::SSL_client_hello_get0_legacy_version(self.as_ptr());
3693            if version == 0 {
3694                None
3695            } else {
3696                Some(SslVersion(version as c_int))
3697            }
3698        }
3699    }
3700
3701    /// Returns the random field of the client's hello message.
3702    ///
3703    /// This can only be used inside of the client hello callback. Otherwise, `None` is returned.
3704    ///
3705    /// Requires OpenSSL 1.1.1 or newer.
3706    #[corresponds(SSL_client_hello_get0_random)]
3707    #[cfg(ossl111)]
3708    pub fn client_hello_random(&self) -> Option<&[u8]> {
3709        unsafe {
3710            let mut ptr = ptr::null();
3711            let len = ffi::SSL_client_hello_get0_random(self.as_ptr(), &mut ptr);
3712            if len == 0 {
3713                None
3714            } else {
3715                Some(util::from_raw_parts(ptr, len))
3716            }
3717        }
3718    }
3719
3720    /// Returns the session ID field of the client's hello message.
3721    ///
3722    /// This can only be used inside of the client hello callback. Otherwise, `None` is returned.
3723    ///
3724    /// Requires OpenSSL 1.1.1 or newer.
3725    #[corresponds(SSL_client_hello_get0_session_id)]
3726    #[cfg(ossl111)]
3727    pub fn client_hello_session_id(&self) -> Option<&[u8]> {
3728        unsafe {
3729            let mut ptr = ptr::null();
3730            let len = ffi::SSL_client_hello_get0_session_id(self.as_ptr(), &mut ptr);
3731            if len == 0 {
3732                None
3733            } else {
3734                Some(util::from_raw_parts(ptr, len))
3735            }
3736        }
3737    }
3738
3739    /// Returns the ciphers field of the client's hello message.
3740    ///
3741    /// This can only be used inside of the client hello callback. Otherwise, `None` is returned.
3742    ///
3743    /// Requires OpenSSL 1.1.1 or newer.
3744    #[corresponds(SSL_client_hello_get0_ciphers)]
3745    #[cfg(ossl111)]
3746    pub fn client_hello_ciphers(&self) -> Option<&[u8]> {
3747        unsafe {
3748            let mut ptr = ptr::null();
3749            let len = ffi::SSL_client_hello_get0_ciphers(self.as_ptr(), &mut ptr);
3750            if len == 0 {
3751                None
3752            } else {
3753                Some(util::from_raw_parts(ptr, len))
3754            }
3755        }
3756    }
3757
3758    /// Provides access to individual extensions from the ClientHello on a per-extension basis.
3759    ///
3760    /// This can only be used inside of the client hello callback. Otherwise, `None` is returned.
3761    ///
3762    /// Requires OpenSSL 1.1.1 or newer.
3763    #[cfg(ossl111)]
3764    pub fn client_hello_ext(&self, ext_type: TlsExtType) -> Option<&[u8]> {
3765        unsafe {
3766            let mut ptr = ptr::null();
3767            let mut len = 0usize;
3768            let r = ffi::SSL_client_hello_get0_ext(
3769                self.as_ptr(),
3770                ext_type.as_raw() as _,
3771                &mut ptr,
3772                &mut len,
3773            );
3774            if r == 0 {
3775                None
3776            } else {
3777                Some(util::from_raw_parts(ptr, len))
3778            }
3779        }
3780    }
3781
3782    /// Decodes a slice of wire-format cipher suite specification bytes. Unsupported cipher suites
3783    /// are ignored.
3784    ///
3785    /// Requires OpenSSL 1.1.1 or newer.
3786    #[corresponds(SSL_bytes_to_cipher_list)]
3787    #[cfg(ossl111)]
3788    pub fn bytes_to_cipher_list(
3789        &self,
3790        bytes: &[u8],
3791        isv2format: bool,
3792    ) -> Result<CipherLists, ErrorStack> {
3793        unsafe {
3794            let ptr = bytes.as_ptr();
3795            let len = bytes.len();
3796            let mut sk = ptr::null_mut();
3797            let mut scsvs = ptr::null_mut();
3798            let res = ffi::SSL_bytes_to_cipher_list(
3799                self.as_ptr(),
3800                ptr,
3801                len,
3802                isv2format as c_int,
3803                &mut sk,
3804                &mut scsvs,
3805            );
3806            if res == 1 {
3807                Ok(CipherLists {
3808                    suites: Stack::from_ptr(sk),
3809                    signalling_suites: Stack::from_ptr(scsvs),
3810                })
3811            } else {
3812                Err(ErrorStack::get())
3813            }
3814        }
3815    }
3816
3817    /// Returns the compression methods field of the client's hello message.
3818    ///
3819    /// This can only be used inside of the client hello callback. Otherwise, `None` is returned.
3820    ///
3821    /// Requires OpenSSL 1.1.1 or newer.
3822    #[corresponds(SSL_client_hello_get0_compression_methods)]
3823    #[cfg(ossl111)]
3824    pub fn client_hello_compression_methods(&self) -> Option<&[u8]> {
3825        unsafe {
3826            let mut ptr = ptr::null();
3827            let len = ffi::SSL_client_hello_get0_compression_methods(self.as_ptr(), &mut ptr);
3828            if len == 0 {
3829                None
3830            } else {
3831                Some(util::from_raw_parts(ptr, len))
3832            }
3833        }
3834    }
3835
3836    /// Sets the MTU used for DTLS connections.
3837    #[corresponds(SSL_set_mtu)]
3838    pub fn set_mtu(&mut self, mtu: u32) -> Result<(), ErrorStack> {
3839        unsafe { cvt(ffi::SSL_set_mtu(self.as_ptr(), mtu as MtuTy) as c_int).map(|_| ()) }
3840    }
3841
3842    /// Returns the PSK identity hint used during connection setup.
3843    ///
3844    /// May return `None` if no PSK identity hint was used during the connection setup.
3845    #[corresponds(SSL_get_psk_identity_hint)]
3846    #[cfg(not(osslconf = "OPENSSL_NO_PSK"))]
3847    pub fn psk_identity_hint(&self) -> Option<&[u8]> {
3848        unsafe {
3849            let ptr = ffi::SSL_get_psk_identity_hint(self.as_ptr());
3850            if ptr.is_null() {
3851                None
3852            } else {
3853                Some(CStr::from_ptr(ptr).to_bytes())
3854            }
3855        }
3856    }
3857
3858    /// Returns the PSK identity used during connection setup.
3859    #[corresponds(SSL_get_psk_identity)]
3860    #[cfg(not(osslconf = "OPENSSL_NO_PSK"))]
3861    pub fn psk_identity(&self) -> Option<&[u8]> {
3862        unsafe {
3863            let ptr = ffi::SSL_get_psk_identity(self.as_ptr());
3864            if ptr.is_null() {
3865                None
3866            } else {
3867                Some(CStr::from_ptr(ptr).to_bytes())
3868            }
3869        }
3870    }
3871
3872    #[corresponds(SSL_add0_chain_cert)]
3873    #[cfg(any(ossl102, boringssl))]
3874    pub fn add_chain_cert(&mut self, chain: X509) -> Result<(), ErrorStack> {
3875        unsafe {
3876            cvt(ffi::SSL_add0_chain_cert(self.as_ptr(), chain.as_ptr()) as c_int).map(|_| ())?;
3877            mem::forget(chain);
3878        }
3879        Ok(())
3880    }
3881
3882    /// Sets a new default TLS/SSL method for SSL objects
3883    #[cfg(not(boringssl))]
3884    pub fn set_method(&mut self, method: SslMethod) -> Result<(), ErrorStack> {
3885        unsafe {
3886            cvt(ffi::SSL_set_ssl_method(self.as_ptr(), method.as_ptr()))?;
3887        };
3888        Ok(())
3889    }
3890
3891    /// Loads the private key from a file.
3892    #[corresponds(SSL_use_Private_Key_file)]
3893    pub fn set_private_key_file<P: AsRef<Path>>(
3894        &mut self,
3895        path: P,
3896        ssl_file_type: SslFiletype,
3897    ) -> Result<(), ErrorStack> {
3898        let p = path.as_ref().as_os_str().to_str().unwrap();
3899        let key_file = CString::new(p).unwrap();
3900        unsafe {
3901            cvt(ffi::SSL_use_PrivateKey_file(
3902                self.as_ptr(),
3903                key_file.as_ptr(),
3904                ssl_file_type.as_raw(),
3905            ))?;
3906        };
3907        Ok(())
3908    }
3909
3910    /// Sets the private key.
3911    #[corresponds(SSL_use_PrivateKey)]
3912    pub fn set_private_key(&mut self, pkey: &PKeyRef<Private>) -> Result<(), ErrorStack> {
3913        unsafe {
3914            cvt(ffi::SSL_use_PrivateKey(self.as_ptr(), pkey.as_ptr()))?;
3915        };
3916        Ok(())
3917    }
3918
3919    #[cfg(tongsuo)]
3920    #[corresponds(SSL_use_enc_Private_Key_file)]
3921    pub fn set_enc_private_key_file<P: AsRef<Path>>(
3922        &mut self,
3923        path: P,
3924        ssl_file_type: SslFiletype,
3925    ) -> Result<(), ErrorStack> {
3926        let p = path.as_ref().as_os_str().to_str().unwrap();
3927        let key_file = CString::new(p).unwrap();
3928        unsafe {
3929            cvt(ffi::SSL_use_enc_PrivateKey_file(
3930                self.as_ptr(),
3931                key_file.as_ptr(),
3932                ssl_file_type.as_raw(),
3933            ))?;
3934        };
3935        Ok(())
3936    }
3937
3938    #[cfg(tongsuo)]
3939    #[corresponds(SSL_use_enc_PrivateKey)]
3940    pub fn set_enc_private_key(&mut self, pkey: &PKeyRef<Private>) -> Result<(), ErrorStack> {
3941        unsafe {
3942            cvt(ffi::SSL_use_enc_PrivateKey(self.as_ptr(), pkey.as_ptr()))?;
3943        };
3944        Ok(())
3945    }
3946
3947    #[cfg(tongsuo)]
3948    #[corresponds(SSL_use_sign_Private_Key_file)]
3949    pub fn set_sign_private_key_file<P: AsRef<Path>>(
3950        &mut self,
3951        path: P,
3952        ssl_file_type: SslFiletype,
3953    ) -> Result<(), ErrorStack> {
3954        let p = path.as_ref().as_os_str().to_str().unwrap();
3955        let key_file = CString::new(p).unwrap();
3956        unsafe {
3957            cvt(ffi::SSL_use_sign_PrivateKey_file(
3958                self.as_ptr(),
3959                key_file.as_ptr(),
3960                ssl_file_type.as_raw(),
3961            ))?;
3962        };
3963        Ok(())
3964    }
3965
3966    #[cfg(tongsuo)]
3967    #[corresponds(SSL_use_sign_PrivateKey)]
3968    pub fn set_sign_private_key(&mut self, pkey: &PKeyRef<Private>) -> Result<(), ErrorStack> {
3969        unsafe {
3970            cvt(ffi::SSL_use_sign_PrivateKey(self.as_ptr(), pkey.as_ptr()))?;
3971        };
3972        Ok(())
3973    }
3974
3975    /// Sets the certificate
3976    #[corresponds(SSL_use_certificate)]
3977    pub fn set_certificate(&mut self, cert: &X509Ref) -> Result<(), ErrorStack> {
3978        unsafe {
3979            cvt(ffi::SSL_use_certificate(self.as_ptr(), cert.as_ptr()))?;
3980        };
3981        Ok(())
3982    }
3983
3984    #[cfg(tongsuo)]
3985    #[corresponds(SSL_use_enc_certificate)]
3986    pub fn set_enc_certificate(&mut self, cert: &X509Ref) -> Result<(), ErrorStack> {
3987        unsafe {
3988            cvt(ffi::SSL_use_enc_certificate(self.as_ptr(), cert.as_ptr()))?;
3989        };
3990        Ok(())
3991    }
3992
3993    #[cfg(tongsuo)]
3994    #[corresponds(SSL_use_sign_certificate)]
3995    pub fn set_sign_certificate(&mut self, cert: &X509Ref) -> Result<(), ErrorStack> {
3996        unsafe {
3997            cvt(ffi::SSL_use_sign_certificate(self.as_ptr(), cert.as_ptr()))?;
3998        };
3999        Ok(())
4000    }
4001
4002    /// Loads a certificate chain from a file.
4003    ///
4004    /// The file should contain a sequence of PEM-formatted certificates, the first being the leaf
4005    /// certificate, and the remainder forming the chain of certificates up to and including the
4006    /// trusted root certificate.
4007    #[corresponds(SSL_use_certificate_chain_file)]
4008    #[cfg(any(ossl110, libressl332))]
4009    pub fn set_certificate_chain_file<P: AsRef<Path>>(
4010        &mut self,
4011        path: P,
4012    ) -> Result<(), ErrorStack> {
4013        let p = path.as_ref().as_os_str().to_str().unwrap();
4014        let cert_file = CString::new(p).unwrap();
4015        unsafe {
4016            cvt(ffi::SSL_use_certificate_chain_file(
4017                self.as_ptr(),
4018                cert_file.as_ptr(),
4019            ))?;
4020        };
4021        Ok(())
4022    }
4023
4024    /// Sets ca certificate that client trusted
4025    #[corresponds(SSL_add_client_CA)]
4026    pub fn add_client_ca(&mut self, cacert: &X509Ref) -> Result<(), ErrorStack> {
4027        unsafe {
4028            cvt(ffi::SSL_add_client_CA(self.as_ptr(), cacert.as_ptr()))?;
4029        };
4030        Ok(())
4031    }
4032
4033    // Sets the list of CAs sent to the client when requesting a client certificate for the chosen ssl
4034    #[corresponds(SSL_set_client_CA_list)]
4035    pub fn set_client_ca_list(&mut self, list: Stack<X509Name>) {
4036        unsafe { ffi::SSL_set_client_CA_list(self.as_ptr(), list.as_ptr()) }
4037        mem::forget(list);
4038    }
4039
4040    /// Sets the minimum supported protocol version.
4041    ///
4042    /// A value of `None` will enable protocol versions down to the lowest version supported by
4043    /// OpenSSL.
4044    ///
4045    /// Requires BoringSSL or OpenSSL 1.1.0 or LibreSSL 2.6.1 or newer.
4046    #[corresponds(SSL_set_min_proto_version)]
4047    #[cfg(any(ossl110, libressl261, boringssl))]
4048    pub fn set_min_proto_version(&mut self, version: Option<SslVersion>) -> Result<(), ErrorStack> {
4049        unsafe {
4050            cvt(ffi::SSL_set_min_proto_version(
4051                self.as_ptr(),
4052                version.map_or(0, |v| v.0 as _),
4053            ))
4054            .map(|_| ())
4055        }
4056    }
4057
4058    /// Sets the maximum supported protocol version.
4059    ///
4060    /// A value of `None` will enable protocol versions up to the highest version supported by
4061    /// OpenSSL.
4062    ///
4063    /// Requires BoringSSL or OpenSSL 1.1.0 or or LibreSSL 2.6.1 or newer.
4064    #[corresponds(SSL_set_max_proto_version)]
4065    #[cfg(any(ossl110, libressl261, boringssl))]
4066    pub fn set_max_proto_version(&mut self, version: Option<SslVersion>) -> Result<(), ErrorStack> {
4067        unsafe {
4068            cvt(ffi::SSL_set_max_proto_version(
4069                self.as_ptr(),
4070                version.map_or(0, |v| v.0 as _),
4071            ))
4072            .map(|_| ())
4073        }
4074    }
4075
4076    /// Sets the list of supported ciphers for the TLSv1.3 protocol.
4077    ///
4078    /// The `set_cipher_list` method controls the cipher suites for protocols before TLSv1.3.
4079    ///
4080    /// The format consists of TLSv1.3 cipher suite names separated by `:` characters in order of
4081    /// preference.
4082    ///
4083    /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer.
4084    #[corresponds(SSL_set_ciphersuites)]
4085    #[cfg(any(ossl111, libressl340))]
4086    pub fn set_ciphersuites(&mut self, cipher_list: &str) -> Result<(), ErrorStack> {
4087        let cipher_list = CString::new(cipher_list).unwrap();
4088        unsafe {
4089            cvt(ffi::SSL_set_ciphersuites(
4090                self.as_ptr(),
4091                cipher_list.as_ptr() as *const _,
4092            ))
4093            .map(|_| ())
4094        }
4095    }
4096
4097    /// Sets the list of supported ciphers for protocols before TLSv1.3.
4098    ///
4099    /// The `set_ciphersuites` method controls the cipher suites for TLSv1.3.
4100    ///
4101    /// See [`ciphers`] for details on the format.
4102    ///
4103    /// [`ciphers`]: https://www.openssl.org/docs/manmaster/apps/ciphers.html
4104    #[corresponds(SSL_set_cipher_list)]
4105    pub fn set_cipher_list(&mut self, cipher_list: &str) -> Result<(), ErrorStack> {
4106        let cipher_list = CString::new(cipher_list).unwrap();
4107        unsafe {
4108            cvt(ffi::SSL_set_cipher_list(
4109                self.as_ptr(),
4110                cipher_list.as_ptr() as *const _,
4111            ))
4112            .map(|_| ())
4113        }
4114    }
4115
4116    /// Set the certificate store used for certificate verification
4117    #[corresponds(SSL_set_cert_store)]
4118    #[cfg(any(ossl102, boringssl))]
4119    pub fn set_verify_cert_store(&mut self, cert_store: X509Store) -> Result<(), ErrorStack> {
4120        unsafe {
4121            cvt(ffi::SSL_set0_verify_cert_store(self.as_ptr(), cert_store.as_ptr()) as c_int)?;
4122            mem::forget(cert_store);
4123            Ok(())
4124        }
4125    }
4126
4127    /// Sets the number of TLS 1.3 session tickets that will be sent to a client after a full
4128    /// handshake.
4129    ///
4130    /// Requires OpenSSL 1.1.1 or newer.
4131    #[corresponds(SSL_set_num_tickets)]
4132    #[cfg(ossl111)]
4133    pub fn set_num_tickets(&mut self, num_tickets: usize) -> Result<(), ErrorStack> {
4134        unsafe { cvt(ffi::SSL_set_num_tickets(self.as_ptr(), num_tickets)).map(|_| ()) }
4135    }
4136
4137    /// Gets the number of TLS 1.3 session tickets that will be sent to a client after a full
4138    /// handshake.
4139    ///
4140    /// Requires OpenSSL 1.1.1 or newer.
4141    #[corresponds(SSL_get_num_tickets)]
4142    #[cfg(ossl111)]
4143    pub fn num_tickets(&self) -> usize {
4144        unsafe { ffi::SSL_get_num_tickets(self.as_ptr()) }
4145    }
4146
4147    /// Set the context's security level to a value between 0 and 5, inclusive.
4148    /// A security value of 0 allows allows all parameters and algorithms.
4149    ///
4150    /// Requires OpenSSL 1.1.0 or newer.
4151    #[corresponds(SSL_set_security_level)]
4152    #[cfg(any(ossl110, libressl360))]
4153    pub fn set_security_level(&mut self, level: u32) {
4154        unsafe { ffi::SSL_set_security_level(self.as_ptr(), level as c_int) }
4155    }
4156
4157    /// Get the connection's security level, which controls the allowed parameters
4158    /// and algorithms.
4159    ///
4160    /// Requires OpenSSL 1.1.0 or newer.
4161    #[corresponds(SSL_get_security_level)]
4162    #[cfg(any(ossl110, libressl360))]
4163    pub fn security_level(&self) -> u32 {
4164        unsafe { ffi::SSL_get_security_level(self.as_ptr()) as u32 }
4165    }
4166
4167    /// Get the temporary key provided by the peer that is used during key
4168    /// exchange.
4169    // We use an owned value because EVP_KEY free need to be called when it is
4170    // dropped
4171    #[corresponds(SSL_get_peer_tmp_key)]
4172    #[cfg(ossl300)]
4173    pub fn peer_tmp_key(&self) -> Result<PKey<Public>, ErrorStack> {
4174        unsafe {
4175            let mut key = ptr::null_mut();
4176            match cvt_long(ffi::SSL_get_peer_tmp_key(self.as_ptr(), &mut key)) {
4177                Ok(_) => Ok(PKey::<Public>::from_ptr(key)),
4178                Err(e) => Err(e),
4179            }
4180        }
4181    }
4182
4183    /// Returns the temporary key from the local end of the connection that is
4184    /// used during key exchange.
4185    // We use an owned value because EVP_KEY free need to be called when it is
4186    // dropped
4187    #[corresponds(SSL_get_tmp_key)]
4188    #[cfg(ossl300)]
4189    pub fn tmp_key(&self) -> Result<PKey<Private>, ErrorStack> {
4190        unsafe {
4191            let mut key = ptr::null_mut();
4192            match cvt_long(ffi::SSL_get_tmp_key(self.as_ptr(), &mut key)) {
4193                Ok(_) => Ok(PKey::<Private>::from_ptr(key)),
4194                Err(e) => Err(e),
4195            }
4196        }
4197    }
4198}
4199
4200/// An SSL stream midway through the handshake process.
4201#[derive(Debug)]
4202pub struct MidHandshakeSslStream<S> {
4203    stream: SslStream<S>,
4204    error: Error,
4205}
4206
4207impl<S> MidHandshakeSslStream<S> {
4208    /// Returns a shared reference to the inner stream.
4209    pub fn get_ref(&self) -> &S {
4210        self.stream.get_ref()
4211    }
4212
4213    /// Returns a mutable reference to the inner stream.
4214    pub fn get_mut(&mut self) -> &mut S {
4215        self.stream.get_mut()
4216    }
4217
4218    /// Returns a shared reference to the `Ssl` of the stream.
4219    pub fn ssl(&self) -> &SslRef {
4220        self.stream.ssl()
4221    }
4222
4223    /// Returns a mutable reference to the `Ssl` of the stream.
4224    pub fn ssl_mut(&mut self) -> &mut SslRef {
4225        self.stream.ssl_mut()
4226    }
4227
4228    /// Returns the underlying error which interrupted this handshake.
4229    pub fn error(&self) -> &Error {
4230        &self.error
4231    }
4232
4233    /// Consumes `self`, returning its error.
4234    pub fn into_error(self) -> Error {
4235        self.error
4236    }
4237}
4238
4239impl<S> MidHandshakeSslStream<S>
4240where
4241    S: Read + Write,
4242{
4243    /// Restarts the handshake process.
4244    ///
4245    #[corresponds(SSL_do_handshake)]
4246    pub fn handshake(mut self) -> Result<SslStream<S>, HandshakeError<S>> {
4247        match self.stream.do_handshake() {
4248            Ok(()) => Ok(self.stream),
4249            Err(error) => {
4250                self.error = error;
4251                match self.error.code() {
4252                    ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => {
4253                        Err(HandshakeError::WouldBlock(self))
4254                    }
4255                    _ => Err(HandshakeError::Failure(self)),
4256                }
4257            }
4258        }
4259    }
4260}
4261
4262/// A TLS session over a stream.
4263pub struct SslStream<S> {
4264    ssl: ManuallyDrop<Ssl>,
4265    method: ManuallyDrop<BioMethod>,
4266    _p: PhantomData<S>,
4267}
4268
4269impl<S> Drop for SslStream<S> {
4270    fn drop(&mut self) {
4271        // ssl holds a reference to method internally so it has to drop first
4272        unsafe {
4273            ManuallyDrop::drop(&mut self.ssl);
4274            ManuallyDrop::drop(&mut self.method);
4275        }
4276    }
4277}
4278
4279impl<S> fmt::Debug for SslStream<S>
4280where
4281    S: fmt::Debug,
4282{
4283    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
4284        fmt.debug_struct("SslStream")
4285            .field("stream", &self.get_ref())
4286            .field("ssl", &self.ssl())
4287            .finish()
4288    }
4289}
4290
4291impl<S: Read + Write> SslStream<S> {
4292    /// Creates a new `SslStream`.
4293    ///
4294    /// This function performs no IO; the stream will not have performed any part of the handshake
4295    /// with the peer. If the `Ssl` was configured with [`SslRef::set_connect_state`] or
4296    /// [`SslRef::set_accept_state`], the handshake can be performed automatically during the first
4297    /// call to read or write. Otherwise the `connect` and `accept` methods can be used to
4298    /// explicitly perform the handshake.
4299    #[corresponds(SSL_set_bio)]
4300    pub fn new(ssl: Ssl, stream: S) -> Result<Self, ErrorStack> {
4301        let (bio, method) = bio::new(stream)?;
4302        unsafe {
4303            ffi::SSL_set_bio(ssl.as_ptr(), bio, bio);
4304        }
4305
4306        Ok(SslStream {
4307            ssl: ManuallyDrop::new(ssl),
4308            method: ManuallyDrop::new(method),
4309            _p: PhantomData,
4310        })
4311    }
4312
4313    /// Read application data transmitted by a client before handshake completion.
4314    ///
4315    /// Useful for reducing latency, but vulnerable to replay attacks. Call
4316    /// [`SslRef::set_accept_state`] first.
4317    ///
4318    /// Returns `Ok(0)` if all early data has been read.
4319    ///
4320    /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer.
4321    #[corresponds(SSL_read_early_data)]
4322    #[cfg(any(ossl111, libressl340))]
4323    pub fn read_early_data(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
4324        let mut read = 0;
4325        let ret = unsafe {
4326            ffi::SSL_read_early_data(
4327                self.ssl.as_ptr(),
4328                buf.as_ptr() as *mut c_void,
4329                buf.len(),
4330                &mut read,
4331            )
4332        };
4333        match ret {
4334            ffi::SSL_READ_EARLY_DATA_ERROR => Err(self.make_error(ret)),
4335            ffi::SSL_READ_EARLY_DATA_SUCCESS => Ok(read),
4336            ffi::SSL_READ_EARLY_DATA_FINISH => Ok(0),
4337            _ => unreachable!(),
4338        }
4339    }
4340
4341    /// Send data to the server without blocking on handshake completion.
4342    ///
4343    /// Useful for reducing latency, but vulnerable to replay attacks. Call
4344    /// [`SslRef::set_connect_state`] first.
4345    ///
4346    /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer.
4347    #[corresponds(SSL_write_early_data)]
4348    #[cfg(any(ossl111, libressl340))]
4349    pub fn write_early_data(&mut self, buf: &[u8]) -> Result<usize, Error> {
4350        let mut written = 0;
4351        let ret = unsafe {
4352            ffi::SSL_write_early_data(
4353                self.ssl.as_ptr(),
4354                buf.as_ptr() as *const c_void,
4355                buf.len(),
4356                &mut written,
4357            )
4358        };
4359        if ret > 0 {
4360            Ok(written)
4361        } else {
4362            Err(self.make_error(ret))
4363        }
4364    }
4365
4366    /// Initiates a client-side TLS handshake.
4367    ///
4368    /// # Warning
4369    ///
4370    /// OpenSSL's default configuration is insecure. It is highly recommended to use
4371    /// `SslConnector` rather than `Ssl` directly, as it manages that configuration.
4372    #[corresponds(SSL_connect)]
4373    pub fn connect(&mut self) -> Result<(), Error> {
4374        let ret = unsafe { ffi::SSL_connect(self.ssl.as_ptr()) };
4375        if ret > 0 {
4376            Ok(())
4377        } else {
4378            Err(self.make_error(ret))
4379        }
4380    }
4381
4382    /// Initiates a server-side TLS handshake.
4383    ///
4384    /// # Warning
4385    ///
4386    /// OpenSSL's default configuration is insecure. It is highly recommended to use
4387    /// `SslAcceptor` rather than `Ssl` directly, as it manages that configuration.
4388    #[corresponds(SSL_accept)]
4389    pub fn accept(&mut self) -> Result<(), Error> {
4390        let ret = unsafe { ffi::SSL_accept(self.ssl.as_ptr()) };
4391        if ret > 0 {
4392            Ok(())
4393        } else {
4394            Err(self.make_error(ret))
4395        }
4396    }
4397
4398    /// Initiates the handshake.
4399    ///
4400    /// This will fail if `set_accept_state` or `set_connect_state` was not called first.
4401    #[corresponds(SSL_do_handshake)]
4402    pub fn do_handshake(&mut self) -> Result<(), Error> {
4403        let ret = unsafe { ffi::SSL_do_handshake(self.ssl.as_ptr()) };
4404        if ret > 0 {
4405            Ok(())
4406        } else {
4407            Err(self.make_error(ret))
4408        }
4409    }
4410
4411    /// Perform a stateless server-side handshake.
4412    ///
4413    /// Requires that cookie generation and verification callbacks were
4414    /// set on the SSL context.
4415    ///
4416    /// Returns `Ok(true)` if a complete ClientHello containing a valid cookie
4417    /// was read, in which case the handshake should be continued via
4418    /// `accept`. If a HelloRetryRequest containing a fresh cookie was
4419    /// transmitted, `Ok(false)` is returned instead. If the handshake cannot
4420    /// proceed at all, `Err` is returned.
4421    #[corresponds(SSL_stateless)]
4422    #[cfg(ossl111)]
4423    pub fn stateless(&mut self) -> Result<bool, ErrorStack> {
4424        match unsafe { ffi::SSL_stateless(self.ssl.as_ptr()) } {
4425            1 => Ok(true),
4426            0 => Ok(false),
4427            -1 => Err(ErrorStack::get()),
4428            _ => unreachable!(),
4429        }
4430    }
4431
4432    /// Like `read`, but takes a possibly-uninitialized slice.
4433    ///
4434    /// # Safety
4435    ///
4436    /// No portion of `buf` will be de-initialized by this method. If the method returns `Ok(n)`,
4437    /// then the first `n` bytes of `buf` are guaranteed to be initialized.
4438    #[corresponds(SSL_read_ex)]
4439    pub fn read_uninit(&mut self, buf: &mut [MaybeUninit<u8>]) -> io::Result<usize> {
4440        loop {
4441            match self.ssl_read_uninit(buf) {
4442                Ok(n) => return Ok(n),
4443                Err(ref e) if e.code() == ErrorCode::ZERO_RETURN => return Ok(0),
4444                Err(ref e) if e.code() == ErrorCode::SYSCALL && e.io_error().is_none() => {
4445                    return Ok(0);
4446                }
4447                Err(ref e) if e.code() == ErrorCode::WANT_READ && e.io_error().is_none() => {}
4448                Err(e) => {
4449                    return Err(e
4450                        .into_io_error()
4451                        .unwrap_or_else(|e| io::Error::new(io::ErrorKind::Other, e)));
4452                }
4453            }
4454        }
4455    }
4456
4457    /// Like `read`, but returns an `ssl::Error` rather than an `io::Error`.
4458    ///
4459    /// It is particularly useful with a non-blocking socket, where the error value will identify if
4460    /// OpenSSL is waiting on read or write readiness.
4461    #[corresponds(SSL_read_ex)]
4462    pub fn ssl_read(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
4463        // SAFETY: `ssl_read_uninit` does not de-initialize the buffer.
4464        unsafe {
4465            self.ssl_read_uninit(util::from_raw_parts_mut(
4466                buf.as_mut_ptr().cast::<MaybeUninit<u8>>(),
4467                buf.len(),
4468            ))
4469        }
4470    }
4471
4472    /// Like `read_ssl`, but takes a possibly-uninitialized slice.
4473    ///
4474    /// # Safety
4475    ///
4476    /// No portion of `buf` will be de-initialized by this method. If the method returns `Ok(n)`,
4477    /// then the first `n` bytes of `buf` are guaranteed to be initialized.
4478    #[corresponds(SSL_read_ex)]
4479    pub fn ssl_read_uninit(&mut self, buf: &mut [MaybeUninit<u8>]) -> Result<usize, Error> {
4480        cfg_if! {
4481            if #[cfg(any(ossl111, libressl350))] {
4482                let mut readbytes = 0;
4483                let ret = unsafe {
4484                    ffi::SSL_read_ex(
4485                        self.ssl().as_ptr(),
4486                        buf.as_mut_ptr().cast(),
4487                        buf.len(),
4488                        &mut readbytes,
4489                    )
4490                };
4491
4492                if ret > 0 {
4493                    Ok(readbytes)
4494                } else {
4495                    Err(self.make_error(ret))
4496                }
4497            } else {
4498                if buf.is_empty() {
4499                    return Ok(0);
4500                }
4501
4502                let len = usize::min(c_int::MAX as usize, buf.len()) as c_int;
4503                let ret = unsafe {
4504                    ffi::SSL_read(self.ssl().as_ptr(), buf.as_mut_ptr().cast(), len)
4505                };
4506                if ret > 0 {
4507                    Ok(ret as usize)
4508                } else {
4509                    Err(self.make_error(ret))
4510                }
4511            }
4512        }
4513    }
4514
4515    /// Like `write`, but returns an `ssl::Error` rather than an `io::Error`.
4516    ///
4517    /// It is particularly useful with a non-blocking socket, where the error value will identify if
4518    /// OpenSSL is waiting on read or write readiness.
4519    #[corresponds(SSL_write_ex)]
4520    pub fn ssl_write(&mut self, buf: &[u8]) -> Result<usize, Error> {
4521        cfg_if! {
4522            if #[cfg(any(ossl111, libressl350))] {
4523                let mut written = 0;
4524                let ret = unsafe {
4525                    ffi::SSL_write_ex(
4526                        self.ssl().as_ptr(),
4527                        buf.as_ptr().cast(),
4528                        buf.len(),
4529                        &mut written,
4530                    )
4531                };
4532
4533                if ret > 0 {
4534                    Ok(written)
4535                } else {
4536                    Err(self.make_error(ret))
4537                }
4538            } else {
4539                if buf.is_empty() {
4540                    return Ok(0);
4541                }
4542
4543                let len = usize::min(c_int::MAX as usize, buf.len()) as c_int;
4544                let ret = unsafe {
4545                    ffi::SSL_write(self.ssl().as_ptr(), buf.as_ptr().cast(), len)
4546                };
4547                if ret > 0 {
4548                    Ok(ret as usize)
4549                } else {
4550                    Err(self.make_error(ret))
4551                }
4552            }
4553        }
4554    }
4555
4556    /// Reads data from the stream, without removing it from the queue.
4557    #[corresponds(SSL_peek_ex)]
4558    pub fn ssl_peek(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
4559        cfg_if! {
4560            if #[cfg(any(ossl111, libressl350))] {
4561                let mut readbytes = 0;
4562                let ret = unsafe {
4563                    ffi::SSL_peek_ex(
4564                        self.ssl().as_ptr(),
4565                        buf.as_mut_ptr().cast(),
4566                        buf.len(),
4567                        &mut readbytes,
4568                    )
4569                };
4570
4571                if ret > 0 {
4572                    Ok(readbytes)
4573                } else {
4574                    Err(self.make_error(ret))
4575                }
4576            } else {
4577                if buf.is_empty() {
4578                    return Ok(0);
4579                }
4580
4581                let len = usize::min(c_int::MAX as usize, buf.len()) as c_int;
4582                let ret = unsafe {
4583                    ffi::SSL_peek(self.ssl().as_ptr(), buf.as_mut_ptr().cast(), len)
4584                };
4585                if ret > 0 {
4586                    Ok(ret as usize)
4587                } else {
4588                    Err(self.make_error(ret))
4589                }
4590            }
4591        }
4592    }
4593
4594    /// Shuts down the session.
4595    ///
4596    /// The shutdown process consists of two steps. The first step sends a close notify message to
4597    /// the peer, after which `ShutdownResult::Sent` is returned. The second step awaits the receipt
4598    /// of a close notify message from the peer, after which `ShutdownResult::Received` is returned.
4599    ///
4600    /// While the connection may be closed after the first step, it is recommended to fully shut the
4601    /// session down. In particular, it must be fully shut down if the connection is to be used for
4602    /// further communication in the future.
4603    #[corresponds(SSL_shutdown)]
4604    pub fn shutdown(&mut self) -> Result<ShutdownResult, Error> {
4605        match unsafe { ffi::SSL_shutdown(self.ssl.as_ptr()) } {
4606            0 => Ok(ShutdownResult::Sent),
4607            1 => Ok(ShutdownResult::Received),
4608            n => Err(self.make_error(n)),
4609        }
4610    }
4611
4612    /// Returns the session's shutdown state.
4613    #[corresponds(SSL_get_shutdown)]
4614    pub fn get_shutdown(&mut self) -> ShutdownState {
4615        unsafe {
4616            let bits = ffi::SSL_get_shutdown(self.ssl.as_ptr());
4617            ShutdownState::from_bits_retain(bits)
4618        }
4619    }
4620
4621    /// Sets the session's shutdown state.
4622    ///
4623    /// This can be used to tell OpenSSL that the session should be cached even if a full two-way
4624    /// shutdown was not completed.
4625    #[corresponds(SSL_set_shutdown)]
4626    pub fn set_shutdown(&mut self, state: ShutdownState) {
4627        unsafe { ffi::SSL_set_shutdown(self.ssl.as_ptr(), state.bits()) }
4628    }
4629}
4630
4631impl<S> SslStream<S> {
4632    fn make_error(&mut self, ret: c_int) -> Error {
4633        self.check_panic();
4634
4635        let code = self.ssl.get_error(ret);
4636
4637        let cause = match code {
4638            ErrorCode::SSL => Some(InnerError::Ssl(ErrorStack::get())),
4639            ErrorCode::SYSCALL => {
4640                let errs = ErrorStack::get();
4641                if errs.errors().is_empty() {
4642                    self.get_bio_error().map(InnerError::Io)
4643                } else {
4644                    Some(InnerError::Ssl(errs))
4645                }
4646            }
4647            ErrorCode::ZERO_RETURN => None,
4648            ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => {
4649                self.get_bio_error().map(InnerError::Io)
4650            }
4651            _ => None,
4652        };
4653
4654        Error { code, cause }
4655    }
4656
4657    fn check_panic(&mut self) {
4658        if let Some(err) = unsafe { bio::take_panic::<S>(self.ssl.get_raw_rbio()) } {
4659            resume_unwind(err)
4660        }
4661    }
4662
4663    fn get_bio_error(&mut self) -> Option<io::Error> {
4664        unsafe { bio::take_error::<S>(self.ssl.get_raw_rbio()) }
4665    }
4666
4667    /// Returns a shared reference to the underlying stream.
4668    pub fn get_ref(&self) -> &S {
4669        unsafe {
4670            let bio = self.ssl.get_raw_rbio();
4671            bio::get_ref(bio)
4672        }
4673    }
4674
4675    /// Returns a mutable reference to the underlying stream.
4676    ///
4677    /// # Warning
4678    ///
4679    /// It is inadvisable to read from or write to the underlying stream as it
4680    /// will most likely corrupt the SSL session.
4681    pub fn get_mut(&mut self) -> &mut S {
4682        unsafe {
4683            let bio = self.ssl.get_raw_rbio();
4684            bio::get_mut(bio)
4685        }
4686    }
4687
4688    /// Returns a shared reference to the `Ssl` object associated with this stream.
4689    pub fn ssl(&self) -> &SslRef {
4690        &self.ssl
4691    }
4692
4693    /// Returns a mutable reference to the `Ssl` object associated with this stream.
4694    pub fn ssl_mut(&mut self) -> &mut SslRef {
4695        &mut self.ssl
4696    }
4697}
4698
4699impl<S: Read + Write> Read for SslStream<S> {
4700    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
4701        // SAFETY: `read_uninit` does not de-initialize the buffer
4702        unsafe {
4703            self.read_uninit(util::from_raw_parts_mut(
4704                buf.as_mut_ptr().cast::<MaybeUninit<u8>>(),
4705                buf.len(),
4706            ))
4707        }
4708    }
4709}
4710
4711impl<S: Read + Write> Write for SslStream<S> {
4712    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
4713        loop {
4714            match self.ssl_write(buf) {
4715                Ok(n) => return Ok(n),
4716                Err(ref e) if e.code() == ErrorCode::WANT_READ && e.io_error().is_none() => {}
4717                Err(e) => {
4718                    return Err(e
4719                        .into_io_error()
4720                        .unwrap_or_else(|e| io::Error::new(io::ErrorKind::Other, e)));
4721                }
4722            }
4723        }
4724    }
4725
4726    fn flush(&mut self) -> io::Result<()> {
4727        self.get_mut().flush()
4728    }
4729}
4730
4731/// A partially constructed `SslStream`, useful for unusual handshakes.
4732#[deprecated(
4733    since = "0.10.32",
4734    note = "use the methods directly on Ssl/SslStream instead"
4735)]
4736pub struct SslStreamBuilder<S> {
4737    inner: SslStream<S>,
4738}
4739
4740#[allow(deprecated)]
4741impl<S> SslStreamBuilder<S>
4742where
4743    S: Read + Write,
4744{
4745    /// Begin creating an `SslStream` atop `stream`
4746    pub fn new(ssl: Ssl, stream: S) -> Self {
4747        Self {
4748            inner: SslStream::new(ssl, stream).unwrap(),
4749        }
4750    }
4751
4752    /// Perform a stateless server-side handshake
4753    ///
4754    /// Requires that cookie generation and verification callbacks were
4755    /// set on the SSL context.
4756    ///
4757    /// Returns `Ok(true)` if a complete ClientHello containing a valid cookie
4758    /// was read, in which case the handshake should be continued via
4759    /// `accept`. If a HelloRetryRequest containing a fresh cookie was
4760    /// transmitted, `Ok(false)` is returned instead. If the handshake cannot
4761    /// proceed at all, `Err` is returned.
4762    #[corresponds(SSL_stateless)]
4763    #[cfg(ossl111)]
4764    pub fn stateless(&mut self) -> Result<bool, ErrorStack> {
4765        match unsafe { ffi::SSL_stateless(self.inner.ssl.as_ptr()) } {
4766            1 => Ok(true),
4767            0 => Ok(false),
4768            -1 => Err(ErrorStack::get()),
4769            _ => unreachable!(),
4770        }
4771    }
4772
4773    /// Configure as an outgoing stream from a client.
4774    #[corresponds(SSL_set_connect_state)]
4775    pub fn set_connect_state(&mut self) {
4776        unsafe { ffi::SSL_set_connect_state(self.inner.ssl.as_ptr()) }
4777    }
4778
4779    /// Configure as an incoming stream to a server.
4780    #[corresponds(SSL_set_accept_state)]
4781    pub fn set_accept_state(&mut self) {
4782        unsafe { ffi::SSL_set_accept_state(self.inner.ssl.as_ptr()) }
4783    }
4784
4785    /// See `Ssl::connect`
4786    pub fn connect(mut self) -> Result<SslStream<S>, HandshakeError<S>> {
4787        match self.inner.connect() {
4788            Ok(()) => Ok(self.inner),
4789            Err(error) => match error.code() {
4790                ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => {
4791                    Err(HandshakeError::WouldBlock(MidHandshakeSslStream {
4792                        stream: self.inner,
4793                        error,
4794                    }))
4795                }
4796                _ => Err(HandshakeError::Failure(MidHandshakeSslStream {
4797                    stream: self.inner,
4798                    error,
4799                })),
4800            },
4801        }
4802    }
4803
4804    /// See `Ssl::accept`
4805    pub fn accept(mut self) -> Result<SslStream<S>, HandshakeError<S>> {
4806        match self.inner.accept() {
4807            Ok(()) => Ok(self.inner),
4808            Err(error) => match error.code() {
4809                ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => {
4810                    Err(HandshakeError::WouldBlock(MidHandshakeSslStream {
4811                        stream: self.inner,
4812                        error,
4813                    }))
4814                }
4815                _ => Err(HandshakeError::Failure(MidHandshakeSslStream {
4816                    stream: self.inner,
4817                    error,
4818                })),
4819            },
4820        }
4821    }
4822
4823    /// Initiates the handshake.
4824    ///
4825    /// This will fail if `set_accept_state` or `set_connect_state` was not called first.
4826    #[corresponds(SSL_do_handshake)]
4827    pub fn handshake(mut self) -> Result<SslStream<S>, HandshakeError<S>> {
4828        match self.inner.do_handshake() {
4829            Ok(()) => Ok(self.inner),
4830            Err(error) => match error.code() {
4831                ErrorCode::WANT_READ | ErrorCode::WANT_WRITE => {
4832                    Err(HandshakeError::WouldBlock(MidHandshakeSslStream {
4833                        stream: self.inner,
4834                        error,
4835                    }))
4836                }
4837                _ => Err(HandshakeError::Failure(MidHandshakeSslStream {
4838                    stream: self.inner,
4839                    error,
4840                })),
4841            },
4842        }
4843    }
4844
4845    /// Read application data transmitted by a client before handshake
4846    /// completion.
4847    ///
4848    /// Useful for reducing latency, but vulnerable to replay attacks. Call
4849    /// `set_accept_state` first.
4850    ///
4851    /// Returns `Ok(0)` if all early data has been read.
4852    ///
4853    /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer.
4854    #[corresponds(SSL_read_early_data)]
4855    #[cfg(any(ossl111, libressl340))]
4856    pub fn read_early_data(&mut self, buf: &mut [u8]) -> Result<usize, Error> {
4857        self.inner.read_early_data(buf)
4858    }
4859
4860    /// Send data to the server without blocking on handshake completion.
4861    ///
4862    /// Useful for reducing latency, but vulnerable to replay attacks. Call
4863    /// `set_connect_state` first.
4864    ///
4865    /// Requires OpenSSL 1.1.1 or LibreSSL 3.4.0 or newer.
4866    #[corresponds(SSL_write_early_data)]
4867    #[cfg(any(ossl111, libressl340))]
4868    pub fn write_early_data(&mut self, buf: &[u8]) -> Result<usize, Error> {
4869        self.inner.write_early_data(buf)
4870    }
4871}
4872
4873#[allow(deprecated)]
4874impl<S> SslStreamBuilder<S> {
4875    /// Returns a shared reference to the underlying stream.
4876    pub fn get_ref(&self) -> &S {
4877        unsafe {
4878            let bio = self.inner.ssl.get_raw_rbio();
4879            bio::get_ref(bio)
4880        }
4881    }
4882
4883    /// Returns a mutable reference to the underlying stream.
4884    ///
4885    /// # Warning
4886    ///
4887    /// It is inadvisable to read from or write to the underlying stream as it
4888    /// will most likely corrupt the SSL session.
4889    pub fn get_mut(&mut self) -> &mut S {
4890        unsafe {
4891            let bio = self.inner.ssl.get_raw_rbio();
4892            bio::get_mut(bio)
4893        }
4894    }
4895
4896    /// Returns a shared reference to the `Ssl` object associated with this builder.
4897    pub fn ssl(&self) -> &SslRef {
4898        &self.inner.ssl
4899    }
4900
4901    /// Returns a mutable reference to the `Ssl` object associated with this builder.
4902    pub fn ssl_mut(&mut self) -> &mut SslRef {
4903        &mut self.inner.ssl
4904    }
4905}
4906
4907/// The result of a shutdown request.
4908#[derive(Copy, Clone, Debug, PartialEq, Eq)]
4909pub enum ShutdownResult {
4910    /// A close notify message has been sent to the peer.
4911    Sent,
4912
4913    /// A close notify response message has been received from the peer.
4914    Received,
4915}
4916
4917bitflags! {
4918    /// The shutdown state of a session.
4919    #[derive(Copy, Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
4920    #[repr(transparent)]
4921    pub struct ShutdownState: c_int {
4922        /// A close notify message has been sent to the peer.
4923        const SENT = ffi::SSL_SENT_SHUTDOWN;
4924        /// A close notify message has been received from the peer.
4925        const RECEIVED = ffi::SSL_RECEIVED_SHUTDOWN;
4926    }
4927}
4928
4929cfg_if! {
4930    if #[cfg(any(boringssl, ossl110, libressl273))] {
4931        use ffi::{SSL_CTX_up_ref, SSL_SESSION_get_master_key, SSL_SESSION_up_ref, SSL_is_server};
4932    } else {
4933        #[allow(bad_style)]
4934        pub unsafe fn SSL_CTX_up_ref(ssl: *mut ffi::SSL_CTX) -> c_int {
4935            ffi::CRYPTO_add_lock(
4936                &mut (*ssl).references,
4937                1,
4938                ffi::CRYPTO_LOCK_SSL_CTX,
4939                "mod.rs\0".as_ptr() as *const _,
4940                line!() as c_int,
4941            );
4942            0
4943        }
4944
4945        #[allow(bad_style)]
4946        pub unsafe fn SSL_SESSION_get_master_key(
4947            session: *const ffi::SSL_SESSION,
4948            out: *mut c_uchar,
4949            mut outlen: usize,
4950        ) -> usize {
4951            if outlen == 0 {
4952                return (*session).master_key_length as usize;
4953            }
4954            if outlen > (*session).master_key_length as usize {
4955                outlen = (*session).master_key_length as usize;
4956            }
4957            ptr::copy_nonoverlapping((*session).master_key.as_ptr(), out, outlen);
4958            outlen
4959        }
4960
4961        #[allow(bad_style)]
4962        pub unsafe fn SSL_is_server(s: *mut ffi::SSL) -> c_int {
4963            (*s).server
4964        }
4965
4966        #[allow(bad_style)]
4967        pub unsafe fn SSL_SESSION_up_ref(ses: *mut ffi::SSL_SESSION) -> c_int {
4968            ffi::CRYPTO_add_lock(
4969                &mut (*ses).references,
4970                1,
4971                ffi::CRYPTO_LOCK_SSL_CTX,
4972                "mod.rs\0".as_ptr() as *const _,
4973                line!() as c_int,
4974            );
4975            0
4976        }
4977    }
4978}
4979
4980cfg_if! {
4981    if #[cfg(ossl300)] {
4982        use ffi::SSL_get1_peer_certificate;
4983    } else {
4984        use ffi::SSL_get_peer_certificate as SSL_get1_peer_certificate;
4985    }
4986}
4987cfg_if! {
4988    if #[cfg(any(boringssl, ossl110, libressl291))] {
4989        use ffi::{TLS_method, DTLS_method, TLS_client_method, TLS_server_method, DTLS_server_method, DTLS_client_method};
4990    } else {
4991        use ffi::{
4992            SSLv23_method as TLS_method, DTLSv1_method as DTLS_method, SSLv23_client_method as TLS_client_method,
4993            SSLv23_server_method as TLS_server_method,
4994        };
4995    }
4996}
4997cfg_if! {
4998    if #[cfg(ossl110)] {
4999        unsafe fn get_new_idx(f: ffi::CRYPTO_EX_free) -> c_int {
5000            ffi::CRYPTO_get_ex_new_index(
5001                ffi::CRYPTO_EX_INDEX_SSL_CTX,
5002                0,
5003                ptr::null_mut(),
5004                None,
5005                None,
5006                f,
5007            )
5008        }
5009
5010        unsafe fn get_new_ssl_idx(f: ffi::CRYPTO_EX_free) -> c_int {
5011            ffi::CRYPTO_get_ex_new_index(
5012                ffi::CRYPTO_EX_INDEX_SSL,
5013                0,
5014                ptr::null_mut(),
5015                None,
5016                None,
5017                f,
5018            )
5019        }
5020    } else {
5021        use std::sync::Once;
5022
5023        unsafe fn get_new_idx(f: ffi::CRYPTO_EX_free) -> c_int {
5024            // hack around https://rt.openssl.org/Ticket/Display.html?id=3710&user=guest&pass=guest
5025            static ONCE: Once = Once::new();
5026            ONCE.call_once(|| {
5027                cfg_if! {
5028                    if #[cfg(not(boringssl))] {
5029                        ffi::SSL_CTX_get_ex_new_index(0, ptr::null_mut(), None, None, None);
5030                    } else {
5031                        ffi::SSL_CTX_get_ex_new_index(0, ptr::null_mut(), ptr::null_mut(), None, None);
5032                    }
5033                }
5034            });
5035
5036            cfg_if! {
5037                if #[cfg(not(boringssl))] {
5038                    ffi::SSL_CTX_get_ex_new_index(0, ptr::null_mut(), None, None, f)
5039                } else {
5040                    ffi::SSL_CTX_get_ex_new_index(0, ptr::null_mut(), ptr::null_mut(), None, f)
5041                }
5042            }
5043        }
5044
5045        unsafe fn get_new_ssl_idx(f: ffi::CRYPTO_EX_free) -> c_int {
5046            // hack around https://rt.openssl.org/Ticket/Display.html?id=3710&user=guest&pass=guest
5047            static ONCE: Once = Once::new();
5048            ONCE.call_once(|| {
5049                #[cfg(not(boringssl))]
5050                ffi::SSL_get_ex_new_index(0, ptr::null_mut(), None, None, None);
5051                #[cfg(boringssl)]
5052                ffi::SSL_get_ex_new_index(0, ptr::null_mut(), ptr::null_mut(), None, None);
5053            });
5054
5055            #[cfg(not(boringssl))]
5056            return ffi::SSL_get_ex_new_index(0, ptr::null_mut(), None, None, f);
5057            #[cfg(boringssl)]
5058            return ffi::SSL_get_ex_new_index(0, ptr::null_mut(), ptr::null_mut(), None, f);
5059        }
5060    }
5061}