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