From 16183f41f66536d00d490abdd3435ad281372251 Mon Sep 17 00:00:00 2001 From: Ted Mielczarek Date: Fri, 26 May 2017 14:51:04 -0400 Subject: [PATCH 1/2] Expose PSK via a SslContextBuilder::set_psk_callback method --- openssl-sys/src/lib.rs | 8 +++++++ openssl/src/ssl/mod.rs | 49 ++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 55 insertions(+), 2 deletions(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index 8f5003a3..de04ed38 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -2252,6 +2252,14 @@ extern "C" { arg: *mut c_void) -> c_int, arg: *mut c_void); + pub fn SSL_CTX_set_psk_client_callback(ssl: *mut SSL_CTX, + psk_client_cb: extern "C" fn(*mut SSL, + *const c_char, + *mut c_char, + c_uint, + *mut c_uchar, + c_uint) + -> c_uint); pub fn SSL_select_next_proto(out: *mut *mut c_uchar, outlen: *mut c_uchar, inbuf: *const c_uchar, diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 0f24499d..b58bbf41 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -73,10 +73,10 @@ use ffi; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::{c_int, c_void, c_long, c_ulong}; -use libc::{c_uchar, c_uint}; +use libc::{c_char, c_uchar, c_uint}; use std::any::Any; use std::any::TypeId; -use std::borrow::Borrow; +use std::borrow::{Borrow, Cow}; use std::cmp; use std::collections::HashMap; use std::ffi::{CStr, CString}; @@ -307,6 +307,39 @@ extern "C" fn raw_verify(preverify_ok: c_int, x509_ctx: *mut ffi::X509_STORE_ } } +extern "C" fn raw_psk(ssl: *mut ffi::SSL, + hint: *const c_char, + identity: *mut c_char, + _max_identity_len: c_uint, + psk: *mut c_uchar, + _max_psk_len: c_uint) -> c_uint + where F: Fn(&mut SslRef, &str) -> Result<(String, Vec), ErrorStack> + Any + 'static + Sync + Send +{ + unsafe { + let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl as *const _); + let callback = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_callback_idx::()); + let ssl = SslRef::from_ptr_mut(ssl); + let callback = &*(callback as *mut F); + let cstr_hint = if hint != ptr::null() { Cow::Borrowed(CStr::from_ptr(hint)) } else { Cow::Owned(CString::new("").unwrap()) }; + if let Ok(s) = cstr_hint.to_str() { + match callback(ssl, s) { + Ok((identity_out, psk_out)) => { + if let Ok(id) = CString::new(identity_out) { + //TODO: validate max_identity_len, max_psk_len + let id = id.into_bytes_with_nul(); + ptr::copy(id.as_ptr() as *mut i8, identity, id.len()); + ptr::copy(psk_out.as_ptr(), psk, psk_out.len()); + psk_out.len() as u32 + } else { 0 } + } + Err(_) => 0, + } + } else { + 0 + } + } +} + extern "C" fn ssl_raw_verify(preverify_ok: c_int, x509_ctx: *mut ffi::X509_STORE_CTX) -> c_int where F: Fn(bool, &X509StoreContextRef) -> bool + Any + 'static + Sync + Send { @@ -977,6 +1010,18 @@ impl SslContextBuilder { } } + pub fn set_psk_callback(&mut self, callback: F) + where F: Fn(&mut SslRef, &str) -> Result<(String, Vec), ErrorStack> + Any + 'static + Sync + Send + { + unsafe { + let callback = Box::new(callback); + ffi::SSL_CTX_set_ex_data(self.as_ptr(), + get_callback_idx::(), + mem::transmute(callback)); + ffi::SSL_CTX_set_psk_client_callback(self.as_ptr(), raw_psk::) + } + } + pub fn build(self) -> SslContext { let ctx = SslContext(self.0); mem::forget(self); From 4de58596d930559f90cb96a993415ebc0b0ce876 Mon Sep 17 00:00:00 2001 From: Ted Mielczarek Date: Fri, 2 Jun 2017 08:20:03 -0400 Subject: [PATCH 2/2] Make some changes for review comments --- openssl-sys/src/lib.rs | 15 +++++++------- openssl/src/ssl/mod.rs | 45 ++++++++++++++++++++++-------------------- 2 files changed, 32 insertions(+), 28 deletions(-) diff --git a/openssl-sys/src/lib.rs b/openssl-sys/src/lib.rs index de04ed38..06d37dab 100644 --- a/openssl-sys/src/lib.rs +++ b/openssl-sys/src/lib.rs @@ -2252,14 +2252,15 @@ extern "C" { arg: *mut c_void) -> c_int, arg: *mut c_void); + #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] pub fn SSL_CTX_set_psk_client_callback(ssl: *mut SSL_CTX, - psk_client_cb: extern "C" fn(*mut SSL, - *const c_char, - *mut c_char, - c_uint, - *mut c_uchar, - c_uint) - -> c_uint); + psk_client_cb: Option c_uint>); pub fn SSL_select_next_proto(out: *mut *mut c_uchar, outlen: *mut c_uchar, inbuf: *const c_uchar, diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index b58bbf41..0a380b6f 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -76,7 +76,7 @@ use libc::{c_int, c_void, c_long, c_ulong}; use libc::{c_char, c_uchar, c_uint}; use std::any::Any; use std::any::TypeId; -use std::borrow::{Borrow, Cow}; +use std::borrow::Borrow; use std::cmp; use std::collections::HashMap; use std::ffi::{CStr, CString}; @@ -307,35 +307,32 @@ extern "C" fn raw_verify(preverify_ok: c_int, x509_ctx: *mut ffi::X509_STORE_ } } +#[cfg(not(osslconf = "OPENSSL_NO_PSK"))] extern "C" fn raw_psk(ssl: *mut ffi::SSL, hint: *const c_char, identity: *mut c_char, - _max_identity_len: c_uint, + max_identity_len: c_uint, psk: *mut c_uchar, - _max_psk_len: c_uint) -> c_uint - where F: Fn(&mut SslRef, &str) -> Result<(String, Vec), ErrorStack> + Any + 'static + Sync + Send + max_psk_len: c_uint) -> c_uint + where F: Fn(&mut SslRef, Option<&[u8]>, &mut [u8], &mut [u8]) -> Result + Any + 'static + Sync + Send { unsafe { let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl as *const _); let callback = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_callback_idx::()); let ssl = SslRef::from_ptr_mut(ssl); let callback = &*(callback as *mut F); - let cstr_hint = if hint != ptr::null() { Cow::Borrowed(CStr::from_ptr(hint)) } else { Cow::Owned(CString::new("").unwrap()) }; - if let Ok(s) = cstr_hint.to_str() { - match callback(ssl, s) { - Ok((identity_out, psk_out)) => { - if let Ok(id) = CString::new(identity_out) { - //TODO: validate max_identity_len, max_psk_len - let id = id.into_bytes_with_nul(); - ptr::copy(id.as_ptr() as *mut i8, identity, id.len()); - ptr::copy(psk_out.as_ptr(), psk, psk_out.len()); - psk_out.len() as u32 - } else { 0 } - } - Err(_) => 0, - } + let hint = if hint != ptr::null() { + Some(CStr::from_ptr(hint).to_bytes()) } else { - 0 + None + }; + // Give the callback mutable slices into which it can write the identity and psk. + let identity_sl = slice::from_raw_parts_mut(identity as *mut u8, + max_identity_len as usize); + let psk_sl = slice::from_raw_parts_mut(psk as *mut u8, max_psk_len as usize); + match callback(ssl, hint, identity_sl, psk_sl) { + Ok(psk_len) => psk_len as u32, + _ => 0, } } } @@ -1010,15 +1007,21 @@ impl SslContextBuilder { } } + /// Sets the callback for providing an identity and pre-shared key for a TLS-PSK client. + /// + /// The callback will be called with the SSL context, an identity hint if one was provided + /// by the server, a mut slice for each of the identity and pre-shared key bytes. The identity + /// must be written as a null-terminated C string. + #[cfg(not(osslconf = "OPENSSL_NO_PSK"))] pub fn set_psk_callback(&mut self, callback: F) - where F: Fn(&mut SslRef, &str) -> Result<(String, Vec), ErrorStack> + Any + 'static + Sync + Send + where F: Fn(&mut SslRef, Option<&[u8]>, &mut [u8], &mut [u8]) -> Result + Any + 'static + Sync + Send { unsafe { let callback = Box::new(callback); ffi::SSL_CTX_set_ex_data(self.as_ptr(), get_callback_idx::(), mem::transmute(callback)); - ffi::SSL_CTX_set_psk_client_callback(self.as_ptr(), raw_psk::) + ffi::SSL_CTX_set_psk_client_callback(self.as_ptr(), Some(raw_psk::)) } }