Skip to main content

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