test SNI support
This commit is contained in:
parent
6bb3d8f1b5
commit
cb4263f91e
|
|
@ -135,6 +135,8 @@ pub const PKCS5_SALT_LEN: c_int = 8;
|
||||||
pub const SSL_CTRL_OPTIONS: c_int = 32;
|
pub const SSL_CTRL_OPTIONS: c_int = 32;
|
||||||
pub const SSL_CTRL_CLEAR_OPTIONS: c_int = 77;
|
pub const SSL_CTRL_CLEAR_OPTIONS: c_int = 77;
|
||||||
|
|
||||||
|
pub const SSL_CTRL_SET_TLSEXT_SERVERNAME_CB: c_int = 53;
|
||||||
|
pub const SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG: c_int = 54;
|
||||||
pub const SSL_CTRL_SET_TLSEXT_HOSTNAME: c_int = 55;
|
pub const SSL_CTRL_SET_TLSEXT_HOSTNAME: c_int = 55;
|
||||||
pub const SSL_CTRL_EXTRA_CHAIN_CERT: c_int = 14;
|
pub const SSL_CTRL_EXTRA_CHAIN_CERT: c_int = 14;
|
||||||
|
|
||||||
|
|
@ -538,6 +540,8 @@ extern "C" {
|
||||||
pub fn SSL_state_string(ssl: *mut SSL) -> *const c_char;
|
pub fn SSL_state_string(ssl: *mut SSL) -> *const c_char;
|
||||||
pub fn SSL_state_string_long(ssl: *mut SSL) -> *const c_char;
|
pub fn SSL_state_string_long(ssl: *mut SSL) -> *const c_char;
|
||||||
|
|
||||||
|
pub fn SSL_get_servername(ssl: *const SSL, name_type: c_long) -> *const c_char;
|
||||||
|
|
||||||
pub fn SSL_COMP_get_name(comp: *const COMP_METHOD) -> *const c_char;
|
pub fn SSL_COMP_get_name(comp: *const COMP_METHOD) -> *const c_char;
|
||||||
|
|
||||||
pub fn SSL_CTX_new(method: *const SSL_METHOD) -> *mut SSL_CTX;
|
pub fn SSL_CTX_new(method: *const SSL_METHOD) -> *mut SSL_CTX;
|
||||||
|
|
@ -567,6 +571,8 @@ extern "C" {
|
||||||
pub fn SSL_CTX_set_cipher_list(ssl: *mut SSL_CTX, s: *const c_char) -> c_int;
|
pub fn SSL_CTX_set_cipher_list(ssl: *mut SSL_CTX, s: *const c_char) -> c_int;
|
||||||
|
|
||||||
pub fn SSL_CTX_ctrl(ssl: *mut SSL_CTX, cmd: c_int, larg: c_long, parg: *mut c_void) -> c_long;
|
pub fn SSL_CTX_ctrl(ssl: *mut SSL_CTX, cmd: c_int, larg: c_long, parg: *mut c_void) -> c_long;
|
||||||
|
pub fn SSL_CTX_callback_ctrl(ssl: *mut SSL_CTX, cmd: c_int, callback: Option<extern fn()>) -> c_long;
|
||||||
|
|
||||||
#[cfg(feature = "npn")]
|
#[cfg(feature = "npn")]
|
||||||
pub fn SSL_CTX_set_next_protos_advertised_cb(ssl: *mut SSL_CTX,
|
pub fn SSL_CTX_set_next_protos_advertised_cb(ssl: *mut SSL_CTX,
|
||||||
cb: extern "C" fn(ssl: *mut SSL,
|
cb: extern "C" fn(ssl: *mut SSL,
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ pub mod error;
|
||||||
mod tests;
|
mod tests;
|
||||||
|
|
||||||
static mut VERIFY_IDX: c_int = -1;
|
static mut VERIFY_IDX: c_int = -1;
|
||||||
|
static mut SNI_IDX: c_int = -1;
|
||||||
|
|
||||||
/// Manually initialize SSL.
|
/// Manually initialize SSL.
|
||||||
/// It is optional to call this function and safe to do so more than once.
|
/// It is optional to call this function and safe to do so more than once.
|
||||||
|
|
@ -46,6 +47,11 @@ pub fn init() {
|
||||||
None, None);
|
None, None);
|
||||||
assert!(verify_idx >= 0);
|
assert!(verify_idx >= 0);
|
||||||
VERIFY_IDX = verify_idx;
|
VERIFY_IDX = verify_idx;
|
||||||
|
|
||||||
|
let sni_idx = ffi::SSL_CTX_get_ex_new_index(0, ptr::null(), None,
|
||||||
|
None, None);
|
||||||
|
assert!(sni_idx >= 0);
|
||||||
|
SNI_IDX = sni_idx;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -297,6 +303,51 @@ extern fn raw_verify_with_data<T>(preverify_ok: c_int,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern fn raw_sni(ssl: *mut ffi::SSL, ad: &mut c_int, arg: *mut c_void)
|
||||||
|
-> c_int {
|
||||||
|
println!("openssl called raw_sni. ad=={:?}", *ad);
|
||||||
|
unsafe {
|
||||||
|
let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl);
|
||||||
|
let callback = ffi::SSL_CTX_get_ex_data(ssl_ctx, SNI_IDX);
|
||||||
|
let callback: Option<ServerNameCallback> = mem::transmute(callback);
|
||||||
|
let mut ssl = Ssl { ssl: ssl };
|
||||||
|
println!("openssl got callback");
|
||||||
|
|
||||||
|
let res = match callback {
|
||||||
|
None => ffi::SSL_TLSEXT_ERR_ALERT_FATAL,
|
||||||
|
Some(callback) => callback(&mut ssl, ad)
|
||||||
|
};
|
||||||
|
println!("openssl got callback result: {}", res);
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern fn raw_sni_with_data<T>(ssl: *mut ffi::SSL, ad: &mut c_int, arg: *mut c_void) -> c_int
|
||||||
|
where T: Any + 'static {
|
||||||
|
unsafe {
|
||||||
|
let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl);
|
||||||
|
|
||||||
|
let callback = ffi::SSL_CTX_get_ex_data(ssl_ctx, SNI_IDX);
|
||||||
|
let callback: Option<ServerNameCallbackData<T>> = mem::transmute(callback);
|
||||||
|
let mut ssl = Ssl { ssl: ssl };
|
||||||
|
|
||||||
|
let data: Box<T> = mem::transmute(arg);
|
||||||
|
|
||||||
|
let res = match callback {
|
||||||
|
None => ffi::SSL_TLSEXT_ERR_ALERT_FATAL,
|
||||||
|
Some(callback) => callback(&mut ssl, ad, &*data)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Since data might be required on the next verification
|
||||||
|
// it is time to forget about it and avoid dropping
|
||||||
|
// data will be freed once OpenSSL considers it is time
|
||||||
|
// to free all context data
|
||||||
|
mem::forget(data);
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#[cfg(any(feature = "npn", feature = "alpn"))]
|
#[cfg(any(feature = "npn", feature = "alpn"))]
|
||||||
unsafe fn select_proto_using(ssl: *mut ffi::SSL,
|
unsafe fn select_proto_using(ssl: *mut ffi::SSL,
|
||||||
out: *mut *mut c_uchar, outlen: *mut c_uchar,
|
out: *mut *mut c_uchar, outlen: *mut c_uchar,
|
||||||
|
|
@ -404,6 +455,11 @@ pub type VerifyCallbackData<T> = fn(preverify_ok: bool,
|
||||||
x509_ctx: &X509StoreContext,
|
x509_ctx: &X509StoreContext,
|
||||||
data: &T) -> bool;
|
data: &T) -> bool;
|
||||||
|
|
||||||
|
/// The signature of functions that can be used to choose the context depending on the server name
|
||||||
|
pub type ServerNameCallback = fn(ssl: &mut Ssl, ad: &mut i32) -> i32;
|
||||||
|
|
||||||
|
pub type ServerNameCallbackData<T> = fn(ssl: &mut Ssl, ad: &mut i32, data: &T) -> i32;
|
||||||
|
|
||||||
// FIXME: macro may be instead of inlining?
|
// FIXME: macro may be instead of inlining?
|
||||||
#[inline]
|
#[inline]
|
||||||
fn wrap_ssl_result(res: c_int) -> Result<(),SslError> {
|
fn wrap_ssl_result(res: c_int) -> Result<(),SslError> {
|
||||||
|
|
@ -485,6 +541,31 @@ impl SslContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Configures the certificate verification method for new connections.
|
||||||
|
pub fn set_servername_callback(&mut self, callback: Option<ServerNameCallback>) {
|
||||||
|
unsafe {
|
||||||
|
ffi::SSL_CTX_set_ex_data(self.ctx, SNI_IDX,
|
||||||
|
mem::transmute(callback));
|
||||||
|
//let f: extern fn(c_int, *mut ffi::X509_STORE_CTX) -> c_int = raw_sni;
|
||||||
|
let f: extern fn() = mem::transmute(raw_sni);
|
||||||
|
ffi::SSL_CTX_callback_ctrl(self.ctx, ffi::SSL_CTRL_SET_TLSEXT_SERVERNAME_CB, Some(f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_servername_callback_with_data<T>(&mut self, callback: ServerNameCallbackData<T>,
|
||||||
|
data: T)
|
||||||
|
where T: Any + 'static {
|
||||||
|
let data = Box::new(data);
|
||||||
|
unsafe {
|
||||||
|
ffi::SSL_CTX_set_ex_data(self.ctx, SNI_IDX,
|
||||||
|
mem::transmute(Some(callback)));
|
||||||
|
|
||||||
|
ffi::SSL_CTX_ctrl(self.ctx, ffi::SSL_CTRL_SET_TLSEXT_SERVERNAME_ARG, 0, mem::transmute(data));
|
||||||
|
let f: extern fn() = mem::transmute(raw_sni_with_data::<T>);
|
||||||
|
ffi::SSL_CTX_callback_ctrl(self.ctx, ffi::SSL_CTRL_SET_TLSEXT_SERVERNAME_CB, Some(f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Sets verification depth
|
/// Sets verification depth
|
||||||
pub fn set_verify_depth(&mut self, depth: u32) {
|
pub fn set_verify_depth(&mut self, depth: u32) {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
@ -673,6 +754,7 @@ impl SslContext {
|
||||||
ffi::SSL_CTX_set_alpn_select_cb(self.ctx, raw_alpn_select_cb, ptr::null_mut());
|
ffi::SSL_CTX_set_alpn_select_cb(self.ctx, raw_alpn_select_cb, ptr::null_mut());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
|
|
@ -886,6 +968,20 @@ impl Ssl {
|
||||||
SslMethod::from_raw(method)
|
SslMethod::from_raw(method)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the server name for the current connection
|
||||||
|
pub fn get_servername(&self) -> Option<String> {
|
||||||
|
let name = unsafe { ffi::SSL_get_servername(self.ssl, ffi::TLSEXT_NAMETYPE_host_name) };
|
||||||
|
if name == ptr::null() {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("openssl will return servername");
|
||||||
|
unsafe {
|
||||||
|
String::from_utf8(CStr::from_ptr(name).to_bytes().to_vec()).ok()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! make_LibSslError {
|
macro_rules! make_LibSslError {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue