Make c_helpers optional

This commit is contained in:
Steven Fackler 2016-08-09 21:58:48 -07:00
parent 2f46c793e5
commit 0854632ff5
9 changed files with 182 additions and 131 deletions

View File

@ -26,6 +26,10 @@ rfc5114 = ["openssl-sys/rfc5114"]
ecdh_auto = ["openssl-sys/ecdh_auto"] ecdh_auto = ["openssl-sys/ecdh_auto"]
pkcs5_pbkdf2_hmac = ["openssl-sys/pkcs5_pbkdf2_hmac"] pkcs5_pbkdf2_hmac = ["openssl-sys/pkcs5_pbkdf2_hmac"]
c_helpers = ["gcc"]
x509_clone = ["c_helpers"]
ssl_context_clone = ["c_helpers"]
[dependencies] [dependencies]
bitflags = ">= 0.5.0, < 0.8.0" bitflags = ">= 0.5.0, < 0.8.0"
lazy_static = "0.2" lazy_static = "0.2"
@ -34,7 +38,7 @@ openssl-sys = { version = "0.7.14", path = "../openssl-sys" }
openssl-sys-extras = { version = "0.7.14", path = "../openssl-sys-extras" } openssl-sys-extras = { version = "0.7.14", path = "../openssl-sys-extras" }
[build-dependencies] [build-dependencies]
gcc = "0.3" gcc = { version = "0.3", optional = true }
[dev-dependencies] [dev-dependencies]
rustc-serialize = "0.3" rustc-serialize = "0.3"

View File

@ -1,9 +1,11 @@
#[cfg(feature = "c_helpers")]
mod imp {
extern crate gcc; extern crate gcc;
use std::env; use std::env;
use std::path::PathBuf; use std::path::PathBuf;
fn main() { pub fn main() {
let mut config = gcc::Config::new(); let mut config = gcc::Config::new();
if let Some(paths) = env::var_os("DEP_OPENSSL_INCLUDE") { if let Some(paths) = env::var_os("DEP_OPENSSL_INCLUDE") {
@ -14,3 +16,13 @@ fn main() {
config.file("src/c_helpers.c").compile("libc_helpers.a"); config.file("src/c_helpers.c").compile("libc_helpers.a");
} }
}
#[cfg(not(feature = "c_helpers"))]
mod imp {
pub fn main() {}
}
fn main() {
imp::main()
}

7
openssl/src/c_helpers.rs Normal file
View File

@ -0,0 +1,7 @@
use ffi;
#[allow(dead_code)]
extern "C" {
pub fn rust_SSL_CTX_clone(cxt: *mut ffi::SSL_CTX);
pub fn rust_X509_clone(x509: *mut ffi::X509);
}

View File

@ -101,7 +101,7 @@ mod tests {
5FBD3") 5FBD3")
.unwrap(); .unwrap();
let dh = DH::from_params(p, g, q).unwrap(); let dh = DH::from_params(p, g, q).unwrap();
ctx.set_tmp_dh(dh).unwrap(); ctx.set_tmp_dh(&dh).unwrap();
} }
#[test] #[test]
@ -109,6 +109,6 @@ mod tests {
let mut ctx = SslContext::new(Sslv23).unwrap(); let mut ctx = SslContext::new(Sslv23).unwrap();
let params = include_bytes!("../../test/dhparams.pem"); let params = include_bytes!("../../test/dhparams.pem");
let dh = DH::from_pem(params).ok().expect("Failed to load PEM"); let dh = DH::from_pem(params).ok().expect("Failed to load PEM");
ctx.set_tmp_dh(dh).unwrap(); ctx.set_tmp_dh(&dh).unwrap();
} }
} }

View File

@ -24,6 +24,8 @@ mod macros;
pub mod asn1; pub mod asn1;
mod bio; mod bio;
pub mod bn; pub mod bn;
#[cfg(feature = "c_helpers")]
mod c_helpers;
pub mod crypto; pub mod crypto;
pub mod dh; pub mod dh;
pub mod error; pub mod error;

View File

@ -37,10 +37,6 @@ use self::bio::BioMethod;
#[doc(inline)] #[doc(inline)]
pub use ssl::error::Error; pub use ssl::error::Error;
extern "C" {
fn rust_SSL_CTX_clone(cxt: *mut ffi::SSL_CTX);
}
bitflags! { bitflags! {
pub flags SslContextOptions: c_long { pub flags SslContextOptions: c_long {
const SSL_OP_MICROSOFT_SESS_ID_BUG = ffi::SSL_OP_MICROSOFT_SESS_ID_BUG, const SSL_OP_MICROSOFT_SESS_ID_BUG = ffi::SSL_OP_MICROSOFT_SESS_ID_BUG,
@ -259,13 +255,13 @@ extern "C" fn ssl_raw_verify<F>(preverify_ok: c_int, x509_ctx: *mut ffi::X509_ST
} }
extern "C" fn raw_sni<F>(ssl: *mut ffi::SSL, al: *mut c_int, _arg: *mut c_void) -> c_int extern "C" fn raw_sni<F>(ssl: *mut ffi::SSL, al: *mut c_int, _arg: *mut c_void) -> c_int
where F: Fn(&mut SslSlice) -> Result<(), SniError> + Any + 'static + Sync + Send where F: Fn(&mut SslRef) -> Result<(), SniError> + Any + 'static + Sync + Send
{ {
unsafe { unsafe {
let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl); let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl);
let callback = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_verify_data_idx::<F>()); let callback = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_verify_data_idx::<F>());
let callback: &F = mem::transmute(callback); let callback: &F = mem::transmute(callback);
let mut ssl = SslSlice::from_ptr(ssl); let mut ssl = SslRef::from_ptr(ssl);
match callback(&mut ssl) { match callback(&mut ssl) {
Ok(()) => ffi::SSL_TLSEXT_ERR_OK, Ok(()) => ffi::SSL_TLSEXT_ERR_OK,
@ -403,67 +399,22 @@ fn wrap_ssl_result(res: c_int) -> Result<(), ErrorStack> {
} }
} }
/// An SSL context object /// A borrowed SSL context object.
/// pub struct SslContextRef<'a>(*mut ffi::SSL_CTX, PhantomData<&'a ()>);
/// Internally ref-counted, use `.clone()` in the same way as Rc and Arc.
pub struct SslContext { impl<'a> SslContextRef<'a> {
ctx: *mut ffi::SSL_CTX, pub unsafe fn from_ptr(ctx: *mut ffi::SSL_CTX) -> SslContextRef<'a> {
SslContextRef(ctx, PhantomData)
} }
unsafe impl Send for SslContext {} pub fn as_ptr(&self) -> *mut ffi::SSL_CTX {
unsafe impl Sync for SslContext {} self.0
impl Clone for SslContext {
fn clone(&self) -> Self {
unsafe { SslContext::new_ref(self.ctx) }
}
}
// TODO: add useful info here
impl fmt::Debug for SslContext {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "SslContext")
}
}
impl Drop for SslContext {
fn drop(&mut self) {
unsafe { ffi::SSL_CTX_free(self.ctx) }
}
}
impl SslContext {
// Create a new SslContext given an existing ref, and incriment ref-count appropriately.
unsafe fn new_ref(ctx: *mut ffi::SSL_CTX) -> SslContext {
rust_SSL_CTX_clone(ctx);
SslContext { ctx: ctx }
}
/// Creates a new SSL context.
pub fn new(method: SslMethod) -> Result<SslContext, ErrorStack> {
init();
let ctx = try_ssl_null!(unsafe { ffi::SSL_CTX_new(method.to_raw()) });
let mut ctx = SslContext { ctx: ctx };
match method {
#[cfg(feature = "dtlsv1")]
SslMethod::Dtlsv1 => ctx.set_read_ahead(1),
#[cfg(feature = "dtlsv1_2")]
SslMethod::Dtlsv1_2 => ctx.set_read_ahead(1),
_ => {}
}
// this is a bit dubious (?)
try!(ctx.set_mode(ffi::SSL_MODE_AUTO_RETRY | ffi::SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER));
Ok(ctx)
} }
/// Configures the certificate verification method for new connections. /// Configures the certificate verification method for new connections.
pub fn set_verify(&mut self, mode: SslVerifyMode) { pub fn set_verify(&mut self, mode: SslVerifyMode) {
unsafe { unsafe {
ffi::SSL_CTX_set_verify(self.ctx, mode.bits as c_int, None); ffi::SSL_CTX_set_verify(self.as_ptr(), mode.bits as c_int, None);
} }
} }
@ -474,8 +425,8 @@ impl SslContext {
{ {
unsafe { unsafe {
let verify = Box::new(verify); let verify = Box::new(verify);
ffi::SSL_CTX_set_ex_data(self.ctx, get_verify_data_idx::<F>(), mem::transmute(verify)); ffi::SSL_CTX_set_ex_data(self.as_ptr(), get_verify_data_idx::<F>(), mem::transmute(verify));
ffi::SSL_CTX_set_verify(self.ctx, mode.bits as c_int, Some(raw_verify::<F>)); ffi::SSL_CTX_set_verify(self.as_ptr(), mode.bits as c_int, Some(raw_verify::<F>));
} }
} }
@ -484,36 +435,38 @@ impl SslContext {
/// Obtain the server name with `servername` then set the corresponding context /// Obtain the server name with `servername` then set the corresponding context
/// with `set_ssl_context` /// with `set_ssl_context`
pub fn set_servername_callback<F>(&mut self, callback: F) pub fn set_servername_callback<F>(&mut self, callback: F)
where F: Fn(&mut SslSlice) -> Result<(), SniError> + Any + 'static + Sync + Send where F: Fn(&mut SslRef) -> Result<(), SniError> + Any + 'static + Sync + Send
{ {
unsafe { unsafe {
let callback = Box::new(callback); let callback = Box::new(callback);
ffi::SSL_CTX_set_ex_data(self.ctx, get_verify_data_idx::<F>(), mem::transmute(callback)); ffi::SSL_CTX_set_ex_data(self.as_ptr(),
get_verify_data_idx::<F>(),
mem::transmute(callback));
let f: extern "C" fn(_, _, _) -> _ = raw_sni::<F>; let f: extern "C" fn(_, _, _) -> _ = raw_sni::<F>;
let f: extern "C" fn() = mem::transmute(f); let f: extern "C" fn() = mem::transmute(f);
ffi::SSL_CTX_set_tlsext_servername_callback(self.ctx, Some(f)); ffi::SSL_CTX_set_tlsext_servername_callback(self.as_ptr(), 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 {
ffi::SSL_CTX_set_verify_depth(self.ctx, depth as c_int); ffi::SSL_CTX_set_verify_depth(self.as_ptr(), depth as c_int);
} }
} }
pub fn set_read_ahead(&mut self, m: u32) { pub fn set_read_ahead(&mut self, m: u32) {
unsafe { unsafe {
ffi::SSL_CTX_set_read_ahead(self.ctx, m as c_long); ffi::SSL_CTX_set_read_ahead(self.as_ptr(), m as c_long);
} }
} }
fn set_mode(&mut self, mode: c_long) -> Result<(), ErrorStack> { fn set_mode(&mut self, mode: c_long) -> Result<(), ErrorStack> {
wrap_ssl_result(unsafe { ffi::SSL_CTX_set_mode(self.ctx, mode) as c_int }) wrap_ssl_result(unsafe { ffi::SSL_CTX_set_mode(self.as_ptr(), mode) as c_int })
} }
pub fn set_tmp_dh(&mut self, dh: DH) -> Result<(), ErrorStack> { pub fn set_tmp_dh(&mut self, dh: &DH) -> Result<(), ErrorStack> {
wrap_ssl_result(unsafe { ffi::SSL_CTX_set_tmp_dh(self.ctx, dh.raw()) as i32 }) wrap_ssl_result(unsafe { ffi::SSL_CTX_set_tmp_dh(self.as_ptr(), dh.raw()) as i32 })
} }
/// Use the default locations of trusted certificates for verification. /// Use the default locations of trusted certificates for verification.
@ -522,7 +475,7 @@ impl SslContext {
/// environment variables if present, or defaults specified at OpenSSL /// environment variables if present, or defaults specified at OpenSSL
/// build time otherwise. /// build time otherwise.
pub fn set_default_verify_paths(&mut self) -> Result<(), ErrorStack> { pub fn set_default_verify_paths(&mut self) -> Result<(), ErrorStack> {
wrap_ssl_result(unsafe { ffi::SSL_CTX_set_default_verify_paths(self.ctx) }) wrap_ssl_result(unsafe { ffi::SSL_CTX_set_default_verify_paths(self.as_ptr()) })
} }
#[allow(non_snake_case)] #[allow(non_snake_case)]
@ -530,7 +483,7 @@ impl SslContext {
pub fn set_CA_file<P: AsRef<Path>>(&mut self, file: P) -> Result<(), ErrorStack> { pub fn set_CA_file<P: AsRef<Path>>(&mut self, file: P) -> Result<(), ErrorStack> {
let file = CString::new(file.as_ref().as_os_str().to_str().expect("invalid utf8")).unwrap(); let file = CString::new(file.as_ref().as_os_str().to_str().expect("invalid utf8")).unwrap();
wrap_ssl_result(unsafe { wrap_ssl_result(unsafe {
ffi::SSL_CTX_load_verify_locations(self.ctx, file.as_ptr() as *const _, ptr::null()) ffi::SSL_CTX_load_verify_locations(self.as_ptr(), file.as_ptr() as *const _, ptr::null())
}) })
} }
@ -544,7 +497,7 @@ impl SslContext {
/// handshake and need to be restarted. /// handshake and need to be restarted.
pub fn set_session_id_context(&mut self, sid_ctx: &[u8]) -> Result<(), ErrorStack> { pub fn set_session_id_context(&mut self, sid_ctx: &[u8]) -> Result<(), ErrorStack> {
wrap_ssl_result(unsafe { wrap_ssl_result(unsafe {
ffi::SSL_CTX_set_session_id_context(self.ctx, sid_ctx.as_ptr(), sid_ctx.len() as u32) ffi::SSL_CTX_set_session_id_context(self.as_ptr(), sid_ctx.as_ptr(), sid_ctx.len() as u32)
}) })
} }
@ -555,7 +508,7 @@ impl SslContext {
-> Result<(), ErrorStack> { -> Result<(), ErrorStack> {
let file = CString::new(file.as_ref().as_os_str().to_str().expect("invalid utf8")).unwrap(); let file = CString::new(file.as_ref().as_os_str().to_str().expect("invalid utf8")).unwrap();
wrap_ssl_result(unsafe { wrap_ssl_result(unsafe {
ffi::SSL_CTX_use_certificate_file(self.ctx, ffi::SSL_CTX_use_certificate_file(self.as_ptr(),
file.as_ptr() as *const _, file.as_ptr() as *const _,
file_type as c_int) file_type as c_int)
}) })
@ -568,7 +521,7 @@ impl SslContext {
-> Result<(), ErrorStack> { -> Result<(), ErrorStack> {
let file = CString::new(file.as_ref().as_os_str().to_str().expect("invalid utf8")).unwrap(); let file = CString::new(file.as_ref().as_os_str().to_str().expect("invalid utf8")).unwrap();
wrap_ssl_result(unsafe { wrap_ssl_result(unsafe {
ffi::SSL_CTX_use_certificate_chain_file(self.ctx, ffi::SSL_CTX_use_certificate_chain_file(self.as_ptr(),
file.as_ptr() as *const _, file.as_ptr() as *const _,
file_type as c_int) file_type as c_int)
}) })
@ -576,14 +529,14 @@ impl SslContext {
/// Specifies the certificate /// Specifies the certificate
pub fn set_certificate(&mut self, cert: &X509Ref) -> Result<(), ErrorStack> { pub fn set_certificate(&mut self, cert: &X509Ref) -> Result<(), ErrorStack> {
wrap_ssl_result(unsafe { ffi::SSL_CTX_use_certificate(self.ctx, cert.handle()) }) wrap_ssl_result(unsafe { ffi::SSL_CTX_use_certificate(self.as_ptr(), cert.handle()) })
} }
/// Adds a certificate to the certificate chain presented together with the /// Adds a certificate to the certificate chain presented together with the
/// certificate specified using set_certificate() /// certificate specified using set_certificate()
pub fn add_extra_chain_cert(&mut self, cert: &X509Ref) -> Result<(), ErrorStack> { pub fn add_extra_chain_cert(&mut self, cert: &X509Ref) -> Result<(), ErrorStack> {
wrap_ssl_result(unsafe { wrap_ssl_result(unsafe {
ffi::SSL_CTX_add_extra_chain_cert(self.ctx, cert.handle()) as c_int ffi::SSL_CTX_add_extra_chain_cert(self.as_ptr(), cert.handle()) as c_int
}) })
} }
@ -594,7 +547,7 @@ impl SslContext {
-> Result<(), ErrorStack> { -> Result<(), ErrorStack> {
let file = CString::new(file.as_ref().as_os_str().to_str().expect("invalid utf8")).unwrap(); let file = CString::new(file.as_ref().as_os_str().to_str().expect("invalid utf8")).unwrap();
wrap_ssl_result(unsafe { wrap_ssl_result(unsafe {
ffi::SSL_CTX_use_PrivateKey_file(self.ctx, ffi::SSL_CTX_use_PrivateKey_file(self.as_ptr(),
file.as_ptr() as *const _, file.as_ptr() as *const _,
file_type as c_int) file_type as c_int)
}) })
@ -602,18 +555,18 @@ impl SslContext {
/// Specifies the private key /// Specifies the private key
pub fn set_private_key(&mut self, key: &PKey) -> Result<(), ErrorStack> { pub fn set_private_key(&mut self, key: &PKey) -> Result<(), ErrorStack> {
wrap_ssl_result(unsafe { ffi::SSL_CTX_use_PrivateKey(self.ctx, key.handle()) }) wrap_ssl_result(unsafe { ffi::SSL_CTX_use_PrivateKey(self.as_ptr(), key.handle()) })
} }
/// Check consistency of private key and certificate /// Check consistency of private key and certificate
pub fn check_private_key(&mut self) -> Result<(), ErrorStack> { pub fn check_private_key(&mut self) -> Result<(), ErrorStack> {
wrap_ssl_result(unsafe { ffi::SSL_CTX_check_private_key(self.ctx) }) wrap_ssl_result(unsafe { ffi::SSL_CTX_check_private_key(self.as_ptr()) })
} }
pub fn set_cipher_list(&mut self, cipher_list: &str) -> Result<(), ErrorStack> { pub fn set_cipher_list(&mut self, cipher_list: &str) -> Result<(), ErrorStack> {
wrap_ssl_result(unsafe { wrap_ssl_result(unsafe {
let cipher_list = CString::new(cipher_list).unwrap(); let cipher_list = CString::new(cipher_list).unwrap();
ffi::SSL_CTX_set_cipher_list(self.ctx, cipher_list.as_ptr() as *const _) ffi::SSL_CTX_set_cipher_list(self.as_ptr(), cipher_list.as_ptr() as *const _)
}) })
} }
@ -623,21 +576,21 @@ impl SslContext {
/// This method requires OpenSSL >= 1.0.2 or LibreSSL and the `ecdh_auto` feature. /// This method requires OpenSSL >= 1.0.2 or LibreSSL and the `ecdh_auto` feature.
#[cfg(feature = "ecdh_auto")] #[cfg(feature = "ecdh_auto")]
pub fn set_ecdh_auto(&mut self, onoff: bool) -> Result<(), ErrorStack> { pub fn set_ecdh_auto(&mut self, onoff: bool) -> Result<(), ErrorStack> {
wrap_ssl_result(unsafe { ffi::SSL_CTX_set_ecdh_auto(self.ctx, onoff as c_long) as c_int }) wrap_ssl_result(unsafe { ffi::SSL_CTX_set_ecdh_auto(self.as_ptr(), onoff as c_long) as c_int })
} }
pub fn set_options(&mut self, option: SslContextOptions) -> SslContextOptions { pub fn set_options(&mut self, option: SslContextOptions) -> SslContextOptions {
let ret = unsafe { ffi::SSL_CTX_set_options(self.ctx, option.bits()) }; let ret = unsafe { ffi::SSL_CTX_set_options(self.as_ptr(), option.bits()) };
SslContextOptions::from_bits(ret).unwrap() SslContextOptions::from_bits(ret).unwrap()
} }
pub fn options(&self) -> SslContextOptions { pub fn options(&self) -> SslContextOptions {
let ret = unsafe { ffi::SSL_CTX_get_options(self.ctx) }; let ret = unsafe { ffi::SSL_CTX_get_options(self.as_ptr()) };
SslContextOptions::from_bits(ret).unwrap() SslContextOptions::from_bits(ret).unwrap()
} }
pub fn clear_options(&mut self, option: SslContextOptions) -> SslContextOptions { pub fn clear_options(&mut self, option: SslContextOptions) -> SslContextOptions {
let ret = unsafe { ffi::SSL_CTX_clear_options(self.ctx, option.bits()) }; let ret = unsafe { ffi::SSL_CTX_clear_options(self.as_ptr(), option.bits()) };
SslContextOptions::from_bits(ret).unwrap() SslContextOptions::from_bits(ret).unwrap()
} }
@ -654,16 +607,16 @@ impl SslContext {
unsafe { unsafe {
// Attach the protocol list to the OpenSSL context structure, // Attach the protocol list to the OpenSSL context structure,
// so that we can refer to it within the callback. // so that we can refer to it within the callback.
ffi::SSL_CTX_set_ex_data(self.ctx, *NPN_PROTOS_IDX, mem::transmute(protocols)); ffi::SSL_CTX_set_ex_data(self.as_ptr(), *NPN_PROTOS_IDX, mem::transmute(protocols));
// Now register the callback that performs the default protocol // Now register the callback that performs the default protocol
// matching based on the client-supported list of protocols that // matching based on the client-supported list of protocols that
// has been saved. // has been saved.
ffi::SSL_CTX_set_next_proto_select_cb(self.ctx, ffi::SSL_CTX_set_next_proto_select_cb(self.as_ptr(),
raw_next_proto_select_cb, raw_next_proto_select_cb,
ptr::null_mut()); ptr::null_mut());
// Also register the callback to advertise these protocols, if a server socket is // Also register the callback to advertise these protocols, if a server socket is
// created with the context. // created with the context.
ffi::SSL_CTX_set_next_protos_advertised_cb(self.ctx, ffi::SSL_CTX_set_next_protos_advertised_cb(self.as_ptr(),
raw_next_protos_advertise_cb, raw_next_protos_advertise_cb,
ptr::null_mut()); ptr::null_mut());
} }
@ -682,22 +635,98 @@ impl SslContext {
let protocols: Box<Vec<u8>> = Box::new(ssl_encode_byte_strings(protocols)); let protocols: Box<Vec<u8>> = Box::new(ssl_encode_byte_strings(protocols));
unsafe { unsafe {
// Set the context's internal protocol list for use if we are a server // Set the context's internal protocol list for use if we are a server
ffi::SSL_CTX_set_alpn_protos(self.ctx, protocols.as_ptr(), protocols.len() as c_uint); ffi::SSL_CTX_set_alpn_protos(self.as_ptr(), protocols.as_ptr(), protocols.len() as c_uint);
// Rather than use the argument to the callback to contain our data, store it in the // Rather than use the argument to the callback to contain our data, store it in the
// ssl ctx's ex_data so that we can configure a function to free it later. In the // ssl ctx's ex_data so that we can configure a function to free it later. In the
// future, it might make sense to pull this into our internal struct Ssl instead of // future, it might make sense to pull this into our internal struct Ssl instead of
// leaning on openssl and using function pointers. // leaning on openssl and using function pointers.
ffi::SSL_CTX_set_ex_data(self.ctx, *ALPN_PROTOS_IDX, mem::transmute(protocols)); ffi::SSL_CTX_set_ex_data(self.as_ptr(), *ALPN_PROTOS_IDX, mem::transmute(protocols));
// Now register the callback that performs the default protocol // Now register the callback that performs the default protocol
// matching based on the client-supported list of protocols that // matching based on the client-supported list of protocols that
// has been saved. // has been saved.
ffi::SSL_CTX_set_alpn_select_cb(self.ctx, raw_alpn_select_cb, ptr::null_mut()); ffi::SSL_CTX_set_alpn_select_cb(self.as_ptr(), raw_alpn_select_cb, ptr::null_mut());
} }
} }
} }
/// An owned SSL context object.
pub struct SslContext(SslContextRef<'static>);
unsafe impl Send for SslContext {}
unsafe impl Sync for SslContext {}
#[cfg(feature = "ssl_context_clone")]
impl Clone for SslContext {
/// Requires the `ssl_context_clone` feature.
fn clone(&self) -> Self {
unsafe {
::c_helpers::rust_SSL_CTX_clone(self.as_ptr());
SslContext::from_ptr(self.as_ptr())
}
}
}
// TODO: add useful info here
impl fmt::Debug for SslContext {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "SslContext")
}
}
impl Drop for SslContext {
fn drop(&mut self) {
unsafe { ffi::SSL_CTX_free(self.as_ptr()) }
}
}
impl Deref for SslContext {
type Target = SslContextRef<'static>;
fn deref(&self) -> &SslContextRef<'static> {
&self.0
}
}
impl DerefMut for SslContext {
fn deref_mut(&mut self) -> &mut SslContextRef<'static> {
&mut self.0
}
}
impl SslContext {
/// Creates a new SSL context.
pub fn new(method: SslMethod) -> Result<SslContext, ErrorStack> {
init();
let mut ctx = unsafe {
let ctx = try_ssl_null!(ffi::SSL_CTX_new(method.to_raw()));
SslContext::from_ptr(ctx)
};
match method {
#[cfg(feature = "dtlsv1")]
SslMethod::Dtlsv1 => ctx.set_read_ahead(1),
#[cfg(feature = "dtlsv1_2")]
SslMethod::Dtlsv1_2 => ctx.set_read_ahead(1),
_ => {}
}
// this is a bit dubious (?)
try!(ctx.set_mode(ffi::SSL_MODE_AUTO_RETRY | ffi::SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER));
Ok(ctx)
}
pub unsafe fn from_ptr(ctx: *mut ffi::SSL_CTX) -> SslContext {
SslContext(SslContextRef::from_ptr(ctx))
}
pub fn as_ptr(&self) -> *mut ffi::SSL_CTX {
(**self).as_ptr()
}
}
pub struct CipherBits { pub struct CipherBits {
/// The number of secret bits used for the cipher. /// The number of secret bits used for the cipher.
@ -768,22 +797,22 @@ impl<'a> SslCipher<'a> {
} }
} }
pub struct SslSlice<'a>(*mut ffi::SSL, PhantomData<&'a ()>); pub struct SslRef<'a>(*mut ffi::SSL, PhantomData<&'a ()>);
unsafe impl<'a> Send for SslSlice<'a> {} unsafe impl<'a> Send for SslRef<'a> {}
unsafe impl<'a> Sync for SslSlice<'a> {} unsafe impl<'a> Sync for SslRef<'a> {}
impl<'a> fmt::Debug for SslSlice<'a> { impl<'a> fmt::Debug for SslRef<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("SslSlice") fmt.debug_struct("SslRef")
.field("state", &self.state_string_long()) .field("state", &self.state_string_long())
.finish() .finish()
} }
} }
impl<'a> SslSlice<'a> { impl<'a> SslRef<'a> {
pub unsafe fn from_ptr(ssl: *mut ffi::SSL) -> SslSlice<'a> { pub unsafe fn from_ptr(ssl: *mut ffi::SSL) -> SslRef<'a> {
SslSlice(ssl, PhantomData) SslRef(ssl, PhantomData)
} }
pub fn as_ptr(&self) -> *mut ffi::SSL { pub fn as_ptr(&self) -> *mut ffi::SSL {
@ -1004,23 +1033,23 @@ impl<'a> SslSlice<'a> {
} }
/// Changes the context corresponding to the current connection. /// Changes the context corresponding to the current connection.
pub fn set_ssl_context(&mut self, ctx: &SslContext) -> Result<(), ErrorStack> { pub fn set_ssl_context(&mut self, ctx: &SslContextRef) -> Result<(), ErrorStack> {
unsafe { unsafe {
try_ssl_null!(ffi::SSL_set_SSL_CTX(self.as_ptr(), ctx.ctx)); try_ssl_null!(ffi::SSL_set_SSL_CTX(self.as_ptr(), ctx.as_ptr()));
} }
Ok(()) Ok(())
} }
/// Returns the context corresponding to the current connection /// Returns the context corresponding to the current connection
pub fn ssl_context(&self) -> SslContext { pub fn ssl_context(&self) -> SslContextRef<'a> {
unsafe { unsafe {
let ssl_ctx = ffi::SSL_get_SSL_CTX(self.as_ptr()); let ssl_ctx = ffi::SSL_get_SSL_CTX(self.as_ptr());
SslContext::new_ref(ssl_ctx) SslContextRef::from_ptr(ssl_ctx)
} }
} }
} }
pub struct Ssl(SslSlice<'static>); pub struct Ssl(SslRef<'static>);
impl fmt::Debug for Ssl { impl fmt::Debug for Ssl {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
@ -1037,15 +1066,15 @@ impl Drop for Ssl {
} }
impl Deref for Ssl { impl Deref for Ssl {
type Target = SslSlice<'static>; type Target = SslRef<'static>;
fn deref(&self) -> &SslSlice<'static> { fn deref(&self) -> &SslRef<'static> {
&self.0 &self.0
} }
} }
impl DerefMut for Ssl { impl DerefMut for Ssl {
fn deref_mut(&mut self) -> &mut SslSlice<'static> { fn deref_mut(&mut self) -> &mut SslRef<'static> {
&mut self.0 &mut self.0
} }
} }
@ -1053,13 +1082,13 @@ impl DerefMut for Ssl {
impl Ssl { impl Ssl {
pub fn new(ctx: &SslContext) -> Result<Ssl, ErrorStack> { pub fn new(ctx: &SslContext) -> Result<Ssl, ErrorStack> {
unsafe { unsafe {
let ssl = try_ssl_null!(ffi::SSL_new(ctx.ctx)); let ssl = try_ssl_null!(ffi::SSL_new(ctx.as_ptr()));
Ok(Ssl::from_ptr(ssl)) Ok(Ssl::from_ptr(ssl))
} }
} }
pub unsafe fn from_ptr(ssl: *mut ffi::SSL) -> Ssl { pub unsafe fn from_ptr(ssl: *mut ffi::SSL) -> Ssl {
Ssl(SslSlice::from_ptr(ssl)) Ssl(SslRef::from_ptr(ssl))
} }
} }

View File

@ -473,14 +473,12 @@ impl Deref for X509 {
} }
} }
extern "C" { #[cfg(feature = "x509_clone")]
fn rust_X509_clone(x509: *mut ffi::X509);
}
impl Clone for X509 { impl Clone for X509 {
/// Requires the `x509_clone` feature.
fn clone(&self) -> X509 { fn clone(&self) -> X509 {
unsafe { unsafe {
rust_X509_clone(self.handle()); ::c_helpers::rust_X509_clone(self.handle());
X509::new(self.handle()) X509::new(self.handle())
} }
} }

View File

@ -26,8 +26,7 @@ fn get_generator() -> X509Generator {
fn pkey() -> PKey { fn pkey() -> PKey {
let rsa = RSA::generate(2048).unwrap(); let rsa = RSA::generate(2048).unwrap();
let mut pkey = PKey::from_rsa(rsa).unwrap(); PKey::from_rsa(rsa).unwrap()
pkey
} }
#[test] #[test]

View File

@ -4,7 +4,7 @@ set -e
MAIN_TARGETS=https://static.rust-lang.org/dist MAIN_TARGETS=https://static.rust-lang.org/dist
if [ "$TEST_FEATURES" == "true" ]; then if [ "$TEST_FEATURES" == "true" ]; then
FEATURES="tlsv1_2 tlsv1_1 dtlsv1 dtlsv1_2 sslv3 aes_xts aes_ctr npn alpn rfc5114 ecdh_auto pkcs5_pbkdf2_hmac" FEATURES="tlsv1_2 tlsv1_1 dtlsv1 dtlsv1_2 sslv3 aes_xts aes_ctr npn alpn rfc5114 ecdh_auto pkcs5_pbkdf2_hmac x509_clone ssl_context_clone"
fi fi
if [ "$TRAVIS_OS_NAME" != "osx" ]; then if [ "$TRAVIS_OS_NAME" != "osx" ]; then