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