Introduce set_select_certificate_callback

This commit is contained in:
Anthony Ramine 2021-02-19 16:11:14 +01:00
parent 8b6767094d
commit 9c5c7e3db5
3 changed files with 76 additions and 0 deletions

View File

@ -12,6 +12,7 @@ use std::sync::Arc;
use error::ErrorStack;
use ssl::AlpnError;
use ssl::{ClientHello, SelectCertError};
use ssl::{
SniError, Ssl, SslAlert, SslContext, SslContextRef, SslRef, SslSession, SslSessionRef,
SESSION_CTX_INDEX,
@ -190,6 +191,25 @@ where
}
}
pub unsafe extern "C" fn raw_select_cert<F>(
client_hello: *const ffi::SSL_CLIENT_HELLO,
) -> ffi::ssl_select_cert_result_t
where
F: Fn(&ClientHello) -> Result<(), SelectCertError> + Sync + Send + 'static,
{
let ssl = SslRef::from_ptr_mut((*client_hello).ssl);
let client_hello = &*(client_hello as *const ClientHello);
let callback = ssl
.ssl_context()
.ex_data(SslContext::cached_ex_index::<F>())
.expect("BUG: select cert callback missing") as *const F;
match (*callback)(client_hello) {
Ok(()) => ffi::ssl_select_cert_result_t::ssl_select_cert_success,
Err(e) => e.0,
}
}
pub unsafe extern "C" fn raw_tlsext_status<F>(ssl: *mut ffi::SSL, _: *mut c_void) -> c_int
where
F: Fn(&mut SslRef) -> Result<bool, ErrorStack> + 'static + Sync + Send,

View File

@ -463,6 +463,15 @@ impl AlpnError {
pub const NOACK: AlpnError = AlpnError(ffi::SSL_TLSEXT_ERR_NOACK);
}
/// An error returned from a certificate selection callback.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct SelectCertError(ffi::ssl_select_cert_result_t);
impl SelectCertError {
/// A fatal error occured and the handshake should be terminated.
pub const ERROR: Self = Self(ffi::ssl_select_cert_result_t::ssl_select_cert_error);
}
/// An SSL/TLS protocol version.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct SslVersion(u16);
@ -1084,6 +1093,25 @@ impl SslContextBuilder {
);
}
}
/// Sets a callback that is called before most ClientHello processing and before the decision whether
/// to resume a session is made. The callback may inspect the ClientHello and configure the
/// connection.
///
/// This corresponds to [`SSL_CTX_set_select_certificate_cb`].
///
/// [`SSL_CTX_set_select_certificate_cb`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_select_certificate_cb.html
pub fn set_select_certificate_callback<F>(&mut self, callback: F)
where
F: Fn(&ClientHello) -> Result<(), SelectCertError> + Sync + Send + 'static,
{
unsafe {
self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
ffi::SSL_CTX_set_select_certificate_cb(
self.as_ptr(),
Some(callbacks::raw_select_cert::<F>),
);
}
}
/// Checks for consistency between the private key and certificate.
///
@ -1560,6 +1588,9 @@ pub struct CipherBits {
pub algorithm: i32,
}
#[repr(transparent)]
pub struct ClientHello(ffi::SSL_CLIENT_HELLO);
/// Information about a cipher.
pub struct SslCipher(*mut ffi::SSL_CIPHER);

View File

@ -480,6 +480,31 @@ fn test_alpn_server_unilateral() {
assert_eq!(None, s.ssl().selected_alpn_protocol());
}
#[test]
fn test_select_cert_ok() {
let mut server = Server::builder();
server
.ctx()
.set_select_certificate_callback(|_client_hello| Ok(()));
let server = server.build();
let client = server.client();
client.connect();
}
#[test]
fn test_select_cert_error() {
let mut server = Server::builder();
server.should_error();
server
.ctx()
.set_select_certificate_callback(|_client_hello| Err(ssl::SelectCertError::ERROR));
let server = server.build();
let client = server.client();
client.connect_err();
}
#[test]
#[should_panic(expected = "blammo")]
fn write_panic() {