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