Skip to content

Commit b3f481d

Browse files
committed
Implement and test SSL_CTX_set_client_hello_cb
1 parent adf2ec8 commit b3f481d

5 files changed

Lines changed: 85 additions & 13 deletions

File tree

MATRIX.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@
143143
| `SSL_CTX_set_client_CA_list` | | :white_check_mark: | :white_check_mark: | :exclamation: [^stub] |
144144
| `SSL_CTX_set_client_cert_cb` | | | | :exclamation: [^stub] |
145145
| `SSL_CTX_set_client_cert_engine` [^engine] | | | | |
146-
| `SSL_CTX_set_client_hello_cb` | | | :white_check_mark: | :exclamation: [^stub] |
146+
| `SSL_CTX_set_client_hello_cb` | | | :white_check_mark: | :white_check_mark: |
147147
| `SSL_CTX_set_cookie_generate_cb` | | | | |
148148
| `SSL_CTX_set_cookie_verify_cb` | | | | |
149149
| `SSL_CTX_set_ct_validation_callback` [^ct] | | | | |

src/callbacks.rs

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use rustls::AlertDescription;
99
use crate::entry::{
1010
SSL_CTX_alpn_select_cb_func, SSL_CTX_cert_cb_func, SSL_CTX_info_callback_func,
1111
SSL_CTX_new_session_cb, SSL_CTX_servername_callback_func, SSL_CTX_sess_get_cb,
12-
SSL_CTX_sess_remove_cb, _SSL_SESSION_free, SSL, SSL_CTX, SSL_SESSION,
12+
SSL_CTX_sess_remove_cb, SSL_client_hello_cb_func, _SSL_SESSION_free, SSL, SSL_CTX, SSL_SESSION,
1313
};
1414
use crate::error::Error;
1515
use crate::ffi;
@@ -281,3 +281,38 @@ impl Info {
281281
const SSL_CB_ALERT: c_int = 0x4000;
282282
const SSL_CB_READ: c_int = 0x0004;
283283
const SSL_CB_WRITE: c_int = 0x0008;
284+
285+
/// Configuration needed to call a client hello callback later
286+
#[derive(Debug, Default, Clone)]
287+
pub struct ClientHelloCallbackConfig {
288+
pub cb: SSL_client_hello_cb_func,
289+
pub context: *mut c_void,
290+
}
291+
292+
impl ClientHelloCallbackConfig {
293+
pub fn invoke(&self) -> Result<(), Error> {
294+
let Some(callback) = self.cb else {
295+
return Ok(());
296+
};
297+
298+
let internal_error = u8::from(AlertDescription::InternalError) as c_int;
299+
300+
let ssl = SslCallbackContext::ssl_ptr();
301+
let mut alert = internal_error;
302+
let result = unsafe { callback(ssl, &mut alert as *mut c_int, self.context) };
303+
304+
if alert != internal_error {
305+
log::trace!("NYI: customised alert during client hello callback");
306+
}
307+
308+
match result {
309+
i if i < 0 => Err(Error::not_supported(
310+
"SSL_client_hello_cb_func requesting suspension",
311+
)),
312+
0 => Err(Error::not_supported(
313+
"SSL_client_hello_cb_func returning error",
314+
)),
315+
_ => Ok(()),
316+
}
317+
}
318+
}

src/entry.rs

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -901,6 +901,21 @@ pub type custom_ext_parse_cb = Option<
901901
) -> c_int,
902902
>;
903903

904+
entry! {
905+
pub fn _SSL_CTX_set_client_hello_cb(
906+
ctx: *mut SSL_CTX,
907+
cb: SSL_client_hello_cb_func,
908+
arg: *mut c_void,
909+
) {
910+
try_clone_arc!(ctx)
911+
.get_mut()
912+
.set_client_hello_callback(cb, arg);
913+
}
914+
}
915+
916+
pub type SSL_client_hello_cb_func =
917+
Option<unsafe extern "C" fn(_ssl: *mut SSL, _al: *mut c_int, _arg: *mut c_void) -> c_int>;
918+
904919
impl Castable for SSL_CTX {
905920
type Ownership = OwnershipArc;
906921
type RustType = NotThreadSafe<Self>;
@@ -2247,17 +2262,6 @@ pub type SSL_CTX_tlsext_ticket_key_evp_cb_func = Option<
22472262
) -> c_int,
22482263
>;
22492264

2250-
entry_stub! {
2251-
pub fn _SSL_CTX_set_client_hello_cb(
2252-
_ctx: *mut SSL_CTX,
2253-
_cb: SSL_client_hello_cb_func,
2254-
_arg: *mut c_void,
2255-
);
2256-
}
2257-
2258-
pub type SSL_client_hello_cb_func =
2259-
Option<unsafe extern "C" fn(_ssl: *mut SSL, _al: *mut c_int, _arg: *mut c_void) -> c_int>;
2260-
22612265
entry_stub! {
22622266
pub fn _SSL_state_string(_ssl: *const SSL) -> *const c_char;
22632267
}

src/lib.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,7 @@ pub struct SslContext {
457457
cert_callback: callbacks::CertCallbackConfig,
458458
servername_callback: callbacks::ServerNameCallbackConfig,
459459
info_callback: callbacks::InfoCallbackConfig,
460+
client_hello_callback: callbacks::ClientHelloCallbackConfig,
460461
auth_keys: sign::CertifiedKeySet,
461462
max_early_data: u32,
462463
}
@@ -488,6 +489,7 @@ impl SslContext {
488489
cert_callback: callbacks::CertCallbackConfig::default(),
489490
servername_callback: callbacks::ServerNameCallbackConfig::default(),
490491
info_callback: callbacks::InfoCallbackConfig::default(),
492+
client_hello_callback: callbacks::ClientHelloCallbackConfig::default(),
491493
auth_keys: sign::CertifiedKeySet::default(),
492494
max_early_data: 0,
493495
}
@@ -606,6 +608,15 @@ impl SslContext {
606608
self.info_callback.cb = callback;
607609
}
608610

611+
fn set_client_hello_callback(
612+
&mut self,
613+
callback: entry::SSL_client_hello_cb_func,
614+
arg: *mut c_void,
615+
) {
616+
self.client_hello_callback.cb = callback;
617+
self.client_hello_callback.context = arg;
618+
}
619+
609620
fn set_max_early_data(&mut self, max: u32) {
610621
self.max_early_data = max;
611622
}
@@ -784,6 +795,7 @@ struct Ssl {
784795
cert_callback: callbacks::CertCallbackConfig,
785796
info_callback: callbacks::InfoCallbackConfig,
786797
servername_callback: callbacks::ServerNameCallbackConfig,
798+
client_hello_callback: callbacks::ClientHelloCallbackConfig,
787799
sni_server_name: Option<ServerName<'static>>,
788800
server_name: Option<CString>,
789801
bio: Option<bio::Bio>,
@@ -826,6 +838,7 @@ impl Ssl {
826838
cert_callback: inner.cert_callback.clone(),
827839
info_callback: inner.info_callback.clone(),
828840
servername_callback: inner.servername_callback.clone(),
841+
client_hello_callback: inner.client_hello_callback.clone(),
829842
sni_server_name: None,
830843
server_name: None,
831844
bio: None,
@@ -1152,6 +1165,8 @@ impl Ssl {
11521165
unreachable!();
11531166
};
11541167

1168+
self.client_hello_callback.invoke()?;
1169+
11551170
self.server_name = accepted
11561171
.client_hello()
11571172
.server_name()

tests/server.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,21 @@ static int sni_callback(SSL *ssl, int *al, void *arg) {
6969
return SSL_TLSEXT_ERR_OK;
7070
}
7171

72+
static int client_hello_cookie = 98765;
73+
74+
static int client_hello_callback(SSL *ssl, int *alert, void *arg) {
75+
printf("in client_hello_callback\n");
76+
assert(ssl != NULL);
77+
assert(arg == &client_hello_cookie);
78+
printf(" *alert = %d\n", *alert);
79+
printf(" SSL_get_servername: %s (%d)\n",
80+
SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name),
81+
SSL_get_servername_type(ssl));
82+
printf(" ssl_ex_data_idx_message: %s\n",
83+
(const char *)SSL_get_ex_data(ssl, ssl_ex_data_idx_message));
84+
return 1;
85+
}
86+
7287
static int sess_new_callback(SSL *ssl, SSL_SESSION *sess) {
7388
printf("in sess_new_callback\n");
7489
assert(ssl != NULL);
@@ -158,6 +173,9 @@ int main(int argc, char **argv) {
158173
SSL_CTX_set_tlsext_servername_arg(ctx, &sni_cookie);
159174
dump_openssl_error_stack();
160175

176+
SSL_CTX_set_client_hello_cb(ctx, client_hello_callback, &client_hello_cookie);
177+
dump_openssl_error_stack();
178+
161179
// Default to no tickets.
162180
SSL_CTX_set_options(ctx, SSL_OP_NO_TICKET);
163181
TRACE(SSL_CTX_set_num_tickets(ctx, 0));

0 commit comments

Comments
 (0)