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