aboutsummaryrefslogtreecommitdiff
path: root/openssl/src
diff options
context:
space:
mode:
Diffstat (limited to 'openssl/src')
-rw-r--r--openssl/src/rsa.rs141
-rw-r--r--openssl/src/ssl/callbacks.rs274
-rw-r--r--openssl/src/ssl/mod.rs440
-rw-r--r--openssl/src/ssl/test.rs150
-rw-r--r--openssl/src/x509/mod.rs22
-rw-r--r--openssl/src/x509/tests.rs4
6 files changed, 559 insertions, 472 deletions
diff --git a/openssl/src/rsa.rs b/openssl/src/rsa.rs
index 6a591b69..0ad55b96 100644
--- a/openssl/src/rsa.rs
+++ b/openssl/src/rsa.rs
@@ -30,16 +30,16 @@
//! }
//! ```
use ffi;
+use foreign_types::{ForeignType, ForeignTypeRef};
+use libc::c_int;
use std::fmt;
-use std::ptr;
use std::mem;
-use libc::c_int;
-use foreign_types::{ForeignType, ForeignTypeRef};
+use std::ptr;
-use {cvt, cvt_n, cvt_p};
use bn::{BigNum, BigNumRef};
use error::ErrorStack;
use pkey::{HasPrivate, HasPublic, Private, Public};
+use {cvt, cvt_n, cvt_p};
/// Type of encryption padding to use.
///
@@ -77,6 +77,23 @@ generic_foreign_type_and_impl_send_sync! {
pub struct RsaRef<T>;
}
+impl<T> Clone for Rsa<T> {
+ fn clone(&self) -> Rsa<T> {
+ (**self).to_owned()
+ }
+}
+
+impl<T> ToOwned for RsaRef<T> {
+ type Owned = Rsa<T>;
+
+ fn to_owned(&self) -> Rsa<T> {
+ unsafe {
+ ffi::RSA_up_ref(self.as_ptr());
+ Rsa::from_ptr(self.as_ptr())
+ }
+ }
+}
+
impl<T> RsaRef<T>
where
T: HasPrivate,
@@ -465,47 +482,95 @@ impl Rsa<Public> {
}
}
-impl Rsa<Private> {
- /// Creates a new RSA key with private components (public components are assumed).
+pub struct RsaPrivateKeyBuilder {
+ rsa: Rsa<Private>,
+}
+
+impl RsaPrivateKeyBuilder {
+ /// Creates a new `RsaPrivateKeyBuilder`.
///
/// `n` is the modulus common to both public and private key.
/// `e` is the public exponent and `d` is the private exponent.
- /// `p` and `q` are the first and second factors of `n`.
- /// `dmp1`, `dmq1`, and `iqmp` are the exponents and coefficient for
- /// Chinese Remainder Theorem calculations which is used to speed up RSA operations.
///
- /// This corresponds to [`RSA_new`] and uses [`RSA_set0_key`],
- /// [`RSA_set0_factors`], and [`RSA_set0_crt_params`].
+ /// This corresponds to [`RSA_new`] and uses [`RSA_set0_key`].
///
/// [`RSA_new`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_new.html
/// [`RSA_set0_key`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_set0_key.html
+ pub fn new(n: BigNum, e: BigNum, d: BigNum) -> Result<RsaPrivateKeyBuilder, ErrorStack> {
+ unsafe {
+ let rsa = Rsa::from_ptr(cvt_p(ffi::RSA_new())?);
+ cvt(compat::set_key(rsa.0, n.as_ptr(), e.as_ptr(), d.as_ptr()))?;
+ mem::forget((n, e, d));
+ Ok(RsaPrivateKeyBuilder { rsa })
+ }
+ }
+
+ /// Sets the factors of the Rsa key.
+ ///
+ /// `p` and `q` are the first and second factors of `n`.
+ ///
+ /// This correspond to [`RSA_set0_factors`].
+ ///
/// [`RSA_set0_factors`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_set0_factors.html
+ pub fn set_factors(self, p: BigNum, q: BigNum) -> Result<RsaPrivateKeyBuilder, ErrorStack> {
+ unsafe {
+ cvt(compat::set_factors(self.rsa.0, p.as_ptr(), q.as_ptr()))?;
+ mem::forget((p, q));
+ }
+ Ok(self)
+ }
+
+ /// Sets the Chinese Remainder Theorem params of the Rsa key.
+ ///
+ /// `dmp1`, `dmq1`, and `iqmp` are the exponents and coefficient for
+ /// CRT calculations which is used to speed up RSA operations.
+ ///
+ /// This correspond to [`RSA_set0_crt_params`].
+ ///
/// [`RSA_set0_crt_params`]: https://www.openssl.org/docs/man1.1.0/crypto/RSA_set0_crt_params.html
- pub fn from_private_components(
- n: BigNum,
- e: BigNum,
- d: BigNum,
- p: BigNum,
- q: BigNum,
+ pub fn set_crt_params(
+ self,
dmp1: BigNum,
dmq1: BigNum,
iqmp: BigNum,
- ) -> Result<Rsa<Private>, ErrorStack> {
+ ) -> Result<RsaPrivateKeyBuilder, ErrorStack> {
unsafe {
- let rsa = Rsa::from_ptr(cvt_p(ffi::RSA_new())?);
- cvt(compat::set_key(rsa.0, n.as_ptr(), e.as_ptr(), d.as_ptr()))?;
- mem::forget((n, e, d));
- cvt(compat::set_factors(rsa.0, p.as_ptr(), q.as_ptr()))?;
- mem::forget((p, q));
cvt(compat::set_crt_params(
- rsa.0,
+ self.rsa.0,
dmp1.as_ptr(),
dmq1.as_ptr(),
iqmp.as_ptr(),
))?;
mem::forget((dmp1, dmq1, iqmp));
- Ok(rsa)
}
+ Ok(self)
+ }
+
+ /// Returns the Rsa key.
+ pub fn build(self) -> Rsa<Private> {
+ self.rsa
+ }
+}
+
+impl Rsa<Private> {
+ /// Creates a new RSA key with private components (public components are assumed).
+ ///
+ /// This a convenience method over
+ /// `Rsa::build(n, e, q)?.set_factors(p, q)?.set_crt_params(dmp1, dmq1, iqmp)?.build()`
+ pub fn from_private_components(
+ n: BigNum,
+ e: BigNum,
+ d: BigNum,
+ p: BigNum,
+ q: BigNum,
+ dmp1: BigNum,
+ dmq1: BigNum,
+ iqmp: BigNum,
+ ) -> Result<Rsa<Private>, ErrorStack> {
+ Ok(RsaPrivateKeyBuilder::new(n, e, d)?
+ .set_factors(p, q)?
+ .set_crt_params(dmp1, dmq1, iqmp)?
+ .build())
}
/// Generates a public/private key pair with the specified size.
@@ -617,8 +682,8 @@ mod compat {
#[cfg(ossl10x)]
mod compat {
- use libc::c_int;
use ffi::{BIGNUM, RSA};
+ use libc::c_int;
pub unsafe fn key(r: *const RSA) -> [*const BIGNUM; 3] {
[(*r).n, (*r).e, (*r).d]
@@ -783,27 +848,41 @@ mod test {
let msg = "Hello, world!".as_bytes();
let mut encrypted = vec![0; pubkey.size() as usize];
- let len = pubkey.public_encrypt(&msg, &mut encrypted, Padding::PKCS1).unwrap();
+ let len = pubkey
+ .public_encrypt(&msg, &mut encrypted, Padding::PKCS1)
+ .unwrap();
assert!(len > msg.len());
let mut decrypted = vec![0; keypair.size() as usize];
- let len = keypair.private_decrypt(&encrypted, &mut decrypted, Padding::PKCS1).unwrap();
+ let len = keypair
+ .private_decrypt(&encrypted, &mut decrypted, Padding::PKCS1)
+ .unwrap();
assert_eq!(len, msg.len());
assert_eq!("Hello, world!", String::from_utf8_lossy(&decrypted[..len]));
}
#[test]
fn test_pem_pkcs1_padding() {
- let keypair = super::Rsa::generate(512).unwrap();
+ let keypair = super::Rsa::generate(2048).unwrap();
let pubkey_pem = keypair.public_key_to_pem_pkcs1().unwrap();
let pubkey = super::Rsa::public_key_from_pem_pkcs1(&pubkey_pem).unwrap();
let msg = "foo".as_bytes();
let mut encrypted1 = vec![0; pubkey.size() as usize];
let mut encrypted2 = vec![0; pubkey.size() as usize];
- let len1 = pubkey.public_encrypt(&msg, &mut encrypted1, Padding::PKCS1).unwrap();
- let len2 = pubkey.public_encrypt(&msg, &mut encrypted2, Padding::PKCS1).unwrap();
+ let len1 = pubkey
+ .public_encrypt(&msg, &mut encrypted1, Padding::PKCS1)
+ .unwrap();
+ let len2 = pubkey
+ .public_encrypt(&msg, &mut encrypted2, Padding::PKCS1)
+ .unwrap();
assert!(len1 > (msg.len() + 1));
assert_eq!(len1, len2);
assert_ne!(encrypted1, encrypted2);
}
+
+ #[test]
+ fn clone() {
+ let key = Rsa::generate(2048).unwrap();
+ key.clone();
+ }
}
diff --git a/openssl/src/ssl/callbacks.rs b/openssl/src/ssl/callbacks.rs
index bff71022..fd5b7ef5 100644
--- a/openssl/src/ssl/callbacks.rs
+++ b/openssl/src/ssl/callbacks.rs
@@ -1,45 +1,49 @@
use ffi;
-use libc::{c_char, c_int, c_uchar, c_uint, c_void};
+use foreign_types::ForeignType;
+use foreign_types::ForeignTypeRef;
#[cfg(ossl111)]
use libc::size_t;
+use libc::{c_char, c_int, c_uchar, c_uint, c_void};
use std::ffi::CStr;
+use std::mem;
use std::ptr;
use std::slice;
-use std::mem;
#[cfg(ossl111)]
use std::str;
-use foreign_types::ForeignTypeRef;
-use foreign_types::ForeignType;
+use std::sync::Arc;
-use error::ErrorStack;
use dh::Dh;
#[cfg(any(ossl101, ossl102))]
use ec::EcKey;
+use error::ErrorStack;
use pkey::Params;
-use ssl::{get_callback_idx, get_ssl_callback_idx, SniError, SslAlert, SslContextRef, SslRef,
- SslSession, SslSessionRef};
#[cfg(any(ossl102, ossl110))]
use ssl::AlpnError;
-use x509::X509StoreContextRef;
#[cfg(ossl111)]
use ssl::ExtensionContext;
+use ssl::{SniError, Ssl, SslAlert, SslContext, SslContextRef, SslRef, SslSession, SslSessionRef};
#[cfg(ossl111)]
use x509::X509Ref;
+use x509::{X509StoreContext, X509StoreContextRef};
pub extern "C" fn raw_verify<F>(preverify_ok: c_int, x509_ctx: *mut ffi::X509_STORE_CTX) -> c_int
where
F: Fn(bool, &mut X509StoreContextRef) -> bool + 'static + Sync + Send,
{
unsafe {
- let idx = ffi::SSL_get_ex_data_X509_STORE_CTX_idx();
- let ssl = ffi::X509_STORE_CTX_get_ex_data(x509_ctx, idx);
- let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl as *const _);
- let verify = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_callback_idx::<F>());
- let verify: &F = &*(verify as *mut F);
-
let ctx = X509StoreContextRef::from_ptr_mut(x509_ctx);
-
- verify(preverify_ok != 0, ctx) as c_int
+ let ssl_idx = X509StoreContext::ssl_idx().expect("BUG: store context ssl index missing");
+ let verify_idx = SslContext::cached_ex_index::<F>();
+
+ // raw pointer shenanigans to break the borrow of ctx
+ // the callback can't mess with its own ex_data slot so this is safe
+ let verify = ctx.ex_data(ssl_idx)
+ .expect("BUG: store context missing ssl")
+ .ssl_context()
+ .ex_data(verify_idx)
+ .expect("BUG: verify callback missing") as *const F;
+
+ (*verify)(preverify_ok != 0, ctx) as c_int
}
}
@@ -59,10 +63,12 @@ where
+ 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::<F>());
let ssl = SslRef::from_ptr_mut(ssl);
- let callback = &*(callback as *mut F);
+ let callback_idx = SslContext::cached_ex_index::<F>();
+
+ let callback = ssl.ssl_context()
+ .ex_data(callback_idx)
+ .expect("BUG: psk callback missing") as *const F;
let hint = if hint != ptr::null() {
Some(CStr::from_ptr(hint).to_bytes())
} else {
@@ -71,7 +77,7 @@ where
// 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) {
+ match (*callback)(ssl, hint, identity_sl, psk_sl) {
Ok(psk_len) => psk_len as u32,
_ => 0,
}
@@ -86,14 +92,17 @@ where
F: Fn(bool, &mut X509StoreContextRef) -> bool + 'static + Sync + Send,
{
unsafe {
- let idx = ffi::SSL_get_ex_data_X509_STORE_CTX_idx();
- let ssl = ffi::X509_STORE_CTX_get_ex_data(x509_ctx, idx);
- let verify = ffi::SSL_get_ex_data(ssl as *const _, get_ssl_callback_idx::<F>());
- let verify: &F = &*(verify as *mut F);
-
let ctx = X509StoreContextRef::from_ptr_mut(x509_ctx);
+ let ssl_idx = X509StoreContext::ssl_idx().expect("BUG: store context ssl index missing");
+ let callback_idx = Ssl::cached_ex_index::<Arc<F>>();
+
+ let callback = ctx.ex_data(ssl_idx)
+ .expect("BUG: store context missing ssl")
+ .ex_data(callback_idx)
+ .expect("BUG: ssl verify callback missing")
+ .clone();
- verify(preverify_ok != 0, ctx) as c_int
+ callback(preverify_ok != 0, ctx) as c_int
}
}
@@ -102,13 +111,13 @@ where
F: Fn(&mut SslRef, &mut SslAlert) -> Result<(), SniError> + 'static + Sync + Send,
{
unsafe {
- let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl);
- let callback = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_callback_idx::<F>());
- let callback: &F = &*(callback as *mut F);
let ssl = SslRef::from_ptr_mut(ssl);
+ let callback = ssl.ssl_context()
+ .ex_data(SslContext::cached_ex_index::<F>())
+ .expect("BUG: sni callback missing") as *const F;
let mut alert = SslAlert(*al);
- let r = callback(ssl, &mut alert);
+ let r = (*callback)(ssl, &mut alert);
*al = alert.0;
match r {
Ok(()) => ffi::SSL_TLSEXT_ERR_OK,
@@ -130,13 +139,13 @@ where
F: for<'a> Fn(&mut SslRef, &'a [u8]) -> Result<&'a [u8], AlpnError> + 'static + Sync + Send,
{
unsafe {
- let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl);
- let callback = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_callback_idx::<F>());
- let callback: &F = &*(callback as *mut F);
let ssl = SslRef::from_ptr_mut(ssl);
+ let callback = ssl.ssl_context()
+ .ex_data(SslContext::cached_ex_index::<F>())
+ .expect("BUG: alpn callback missing") as *const F;
let protos = slice::from_raw_parts(inbuf as *const u8, inlen as usize);
- match callback(ssl, protos) {
+ match (*callback)(ssl, protos) {
Ok(proto) => {
*out = proto.as_ptr() as *const c_uchar;
*outlen = proto.len() as c_uchar;
@@ -155,12 +164,12 @@ pub unsafe extern "C" fn raw_tmp_dh<F>(
where
F: Fn(&mut SslRef, bool, u32) -> Result<Dh<Params>, ErrorStack> + 'static + Sync + Send,
{
- let ctx = ffi::SSL_get_SSL_CTX(ssl);
- let callback = ffi::SSL_CTX_get_ex_data(ctx, get_callback_idx::<F>());
- let callback = &*(callback as *mut F);
-
let ssl = SslRef::from_ptr_mut(ssl);
- match callback(ssl, is_export != 0, keylength as u32) {
+ let callback = ssl.ssl_context()
+ .ex_data(SslContext::cached_ex_index::<F>())
+ .expect("BUG: tmp dh callback missing") as *const F;
+
+ match (*callback)(ssl, is_export != 0, keylength as u32) {
Ok(dh) => {
let ptr = dh.as_ptr();
mem::forget(dh);
@@ -182,12 +191,12 @@ pub unsafe extern "C" fn raw_tmp_ecdh<F>(
where
F: Fn(&mut SslRef, bool, u32) -> Result<EcKey<Params>, ErrorStack> + 'static + Sync + Send,
{
- let ctx = ffi::SSL_get_SSL_CTX(ssl);
- let callback = ffi::SSL_CTX_get_ex_data(ctx, get_callback_idx::<F>());
- let callback = &*(callback as *mut F);
-
let ssl = SslRef::from_ptr_mut(ssl);
- match callback(ssl, is_export != 0, keylength as u32) {
+ let callback = ssl.ssl_context()
+ .ex_data(SslContext::cached_ex_index::<F>())
+ .expect("BUG: tmp ecdh callback missing") as *const F;
+
+ match (*callback)(ssl, is_export != 0, keylength as u32) {
Ok(ec_key) => {
let ptr = ec_key.as_ptr();
mem::forget(ec_key);
@@ -208,10 +217,11 @@ pub unsafe extern "C" fn raw_tmp_dh_ssl<F>(
where
F: Fn(&mut SslRef, bool, u32) -> Result<Dh<Params>, ErrorStack> + 'static + Sync + Send,
{
- let callback = ffi::SSL_get_ex_data(ssl, get_ssl_callback_idx::<F>());
- let callback = &*(callback as *mut F);
-
let ssl = SslRef::from_ptr_mut(ssl);
+ let callback = ssl.ex_data(Ssl::cached_ex_index::<Arc<F>>())
+ .expect("BUG: ssl tmp dh callback missing")
+ .clone();
+
match callback(ssl, is_export != 0, keylength as u32) {
Ok(dh) => {
let ptr = dh.as_ptr();
@@ -234,10 +244,11 @@ pub unsafe extern "C" fn raw_tmp_ecdh_ssl<F>(
where
F: Fn(&mut SslRef, bool, u32) -> Result<EcKey<Params>, ErrorStack> + 'static + Sync + Send,
{
- let callback = ffi::SSL_get_ex_data(ssl, get_ssl_callback_idx::<F>());
- let callback = &*(callback as *mut F);
-
let ssl = SslRef::from_ptr_mut(ssl);
+ let callback = ssl.ex_data(Ssl::cached_ex_index::<Arc<F>>())
+ .expect("BUG: ssl tmp ecdh callback missing")
+ .clone();
+
match callback(ssl, is_export != 0, keylength as u32) {
Ok(ec_key) => {
let ptr = ec_key.as_ptr();
@@ -255,12 +266,11 @@ pub unsafe extern "C" fn raw_tlsext_status<F>(ssl: *mut ffi::SSL, _: *mut c_void
where
F: Fn(&mut SslRef) -> Result<bool, ErrorStack> + 'static + Sync + Send,
{
- let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl as *const _);
- let callback = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_callback_idx::<F>());
- let callback = &*(callback as *mut F);
-
let ssl = SslRef::from_ptr_mut(ssl);
- let ret = callback(ssl);
+ let callback = ssl.ssl_context()
+ .ex_data(SslContext::cached_ex_index::<F>())
+ .expect("BUG: ocsp callback missing") as *const F;
+ let ret = (*callback)(ssl);
if ssl.is_server() {
match ret {
@@ -290,14 +300,13 @@ pub unsafe extern "C" fn raw_new_session<F>(
where
F: Fn(&mut SslRef, SslSession) + 'static + Sync + Send,
{
- let ssl_ctx = ffi::SSL_get_SSL_CTX(ssl as *const _);
- let callback = ffi::SSL_CTX_get_ex_data(ssl_ctx, get_callback_idx::<F>());
- let callback = &*(callback as *mut F);
-
let ssl = SslRef::from_ptr_mut(ssl);
+ let callback = ssl.ssl_context()
+ .ex_data(SslContext::cached_ex_index::<F>())
+ .expect("BUG: new session callback missing") as *const F;
let session = SslSession::from_ptr(session);
- callback(ssl, session);
+ (*callback)(ssl, session);
// the return code doesn't indicate error vs success, but whether or not we consumed the session
1
@@ -309,18 +318,17 @@ pub unsafe extern "C" fn raw_remove_session<F>(
) where
F: Fn(&SslContextRef, &SslSessionRef) + 'static + Sync + Send,
{
- let callback = ffi::SSL_CTX_get_ex_data(ctx, get_callback_idx::<F>());
- let callback = &*(callback as *mut F);
-
let ctx = SslContextRef::from_ptr(ctx);
+ let callback = ctx.ex_data(SslContext::cached_ex_index::<F>())
+ .expect("BUG: remove session callback missing");
let session = SslSessionRef::from_ptr(session);
callback(ctx, session)
}
-#[cfg(any(ossl110))]
+#[cfg(ossl110)]
type DataPtr = *const c_uchar;
-#[cfg(not(any(ossl110)))]
+#[cfg(not(ossl110))]
type DataPtr = *mut c_uchar;
pub unsafe extern "C" fn raw_get_session<F>(
@@ -332,14 +340,13 @@ pub unsafe extern "C" fn raw_get_session<F>(
where
F: Fn(&mut SslRef, &[u8]) -> Option<SslSession> + 'static + Sync + Send,
{
- let ctx = ffi::SSL_get_SSL_CTX(ssl as *const _);
- let callback = ffi::SSL_CTX_get_ex_data(ctx, get_callback_idx::<F>());
- let callback = &*(callback as *mut F);
-
let ssl = SslRef::from_ptr_mut(ssl);
+ let callback = ssl.ssl_context()
+ .ex_data(SslContext::cached_ex_index::<F>())
+ .expect("BUG: get session callback missing") as *const F;
let data = slice::from_raw_parts(data as *const u8, len as usize);
- match callback(ssl, data) {
+ match (*callback)(ssl, data) {
Some(session) => {
let p = session.as_ptr();
mem::forget(p);
@@ -355,11 +362,10 @@ pub unsafe extern "C" fn raw_keylog<F>(ssl: *const ffi::SSL, line: *const c_char
where
F: Fn(&SslRef, &str) + 'static + Sync + Send,
{
- let ctx = ffi::SSL_get_SSL_CTX(ssl as *const _);
- let callback = ffi::SSL_CTX_get_ex_data(ctx, get_callback_idx::<F>());
- let callback = &*(callback as *mut F);
-
let ssl = SslRef::from_ptr(ssl as *mut _);
+ let callback = ssl.ssl_context()
+ .ex_data(SslContext::cached_ex_index::<F>())
+ .expect("BUG: get session callback missing");
let line = CStr::from_ptr(line).to_bytes();
let line = str::from_utf8_unchecked(line);
@@ -367,7 +373,7 @@ where
}
#[cfg(ossl111)]
-pub extern "C" fn raw_stateless_cookie_generate<F>(
+pub unsafe extern "C" fn raw_stateless_cookie_generate<F>(
ssl: *mut ffi::SSL,
cookie: *mut c_uchar,
cookie_len: *mut size_t,
@@ -375,28 +381,25 @@ pub extern "C" fn raw_stateless_cookie_generate<F>(
where
F: Fn(&mut SslRef, &mut [u8]) -> Result<usize, ErrorStack> + '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::<F>());
- let ssl = SslRef::from_ptr_mut(ssl);
- let callback = &*(callback as *mut F);
- let slice =
- slice::from_raw_parts_mut(cookie as *mut u8, ffi::SSL_COOKIE_LENGTH as usize);
- match callback(ssl, slice) {
- Ok(len) => {
- *cookie_len = len as size_t;
- 1
- }
- Err(e) => {
- e.put();
- 0
- }
+ let ssl = SslRef::from_ptr_mut(ssl);
+ let callback = ssl.ssl_context()
+ .ex_data(SslContext::cached_ex_index::<F>())
+ .expect("BUG: stateless cookie generate callback missing") as *const F;
+ let slice = slice::from_raw_parts_mut(cookie as *mut u8, ffi::SSL_COOKIE_LENGTH as usize);
+ match (*callback)(ssl, slice) {
+ Ok(len) => {
+ *cookie_len = len as size_t;
+ 1
+ }
+ Err(e) => {
+ e.put();
+ 0
}
}
}
#[cfg(ossl111)]
-pub extern "C" fn raw_stateless_cookie_verify<F>(
+pub unsafe extern "C" fn raw_stateless_cookie_verify<F>(
ssl: *mut ffi::SSL,
cookie: *const c_uchar,
cookie_len: size_t,
@@ -404,15 +407,12 @@ pub extern "C" fn raw_stateless_cookie_verify<F>(
where
F: Fn(&mut SslRef, &[u8]) -> bool + '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::<F>());
- let ssl = SslRef::from_ptr_mut(ssl);
- let callback = &*(callback as *mut F);
- let slice =
- slice::from_raw_parts(cookie as *const c_uchar as *const u8, cookie_len as usize);
- callback(ssl, slice) as c_int
- }
+ let ssl = SslRef::from_ptr_mut(ssl);
+ let callback = ssl.ssl_context()
+ .ex_data(SslContext::cached_ex_index::<F>())
+ .expect("BUG: stateless cookie verify callback missing") as *const F;
+ let slice = slice::from_raw_parts(cookie as *const c_uchar as *const u8, cookie_len as usize);
+ (*callback)(ssl, slice) as c_int
}
pub extern "C" fn raw_cookie_generate<F>(
@@ -424,15 +424,15 @@ where
F: Fn(&mut SslRef, &mut [u8]) -> Result<usize, ErrorStack> + '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::<F>());
let ssl = SslRef::from_ptr_mut(ssl);
- let callback = &*(callback as *mut F);
+ let callback = ssl.ssl_context()
+ .ex_data(SslContext::cached_ex_index::<F>())
+ .expect("BUG: cookie generate callback missing") as *const F;
// We subtract 1 from DTLS1_COOKIE_LENGTH as the ostensible value, 256, is erroneous but retained for
// compatibility. See comments in dtls1.h.
let slice =
slice::from_raw_parts_mut(cookie as *mut u8, ffi::DTLS1_COOKIE_LENGTH as usize - 1);
- match callback(ssl, slice) {
+ match (*callback)(ssl, slice) {
Ok(len) => {
*cookie_len = len as c_uint;
1
@@ -460,13 +460,13 @@ where
F: Fn(&mut SslRef, &[u8]) -> bool + '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::<F>());
let ssl = SslRef::from_ptr_mut(ssl);
- let callback = &*(callback as *mut F);
+ let callback = ssl.ssl_context()
+ .ex_data(SslContext::cached_ex_index::<F>())
+ .expect("BUG: cookie verify callback missing") as *const F;
let slice =
slice::from_raw_parts(cookie as *const c_uchar as *const u8, cookie_len as usize);
- callback(ssl, slice) as c_int
+ (*callback)(ssl, slice) as c_int
}
}
@@ -487,35 +487,39 @@ pub extern "C" fn raw_custom_ext_add<F, T>(
) -> c_int
where
F: Fn(&mut SslRef, ExtensionContext, Option<(usize, &X509Ref)>) -> Result<Option<T>, SslAlert>
- + 'static,
+ + 'static
+ + Sync
+ + Send,
T: AsRef<[u8]> + '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::<F>());
- let callback = &*(callback as *mut F);
let ssl = SslRef::from_ptr_mut(ssl);
+ let callback = ssl.ssl_context()
+ .ex_data(SslContext::cached_ex_index::<F>())
+ .expect("BUG: custom ext add callback missing") as *const F;
let ectx = ExtensionContext::from_bits_truncate(context);
let cert = if ectx.contains(ExtensionContext::TLS1_3_CERTIFICATE) {
Some((chainidx, X509Ref::from_ptr(x)))
} else {
None
};
- match (callback)(ssl, ectx, cert) {
+ match (*callback)(ssl, ectx, cert) {
Ok(None) => 0,
Ok(Some(buf)) => {
- *outlen = buf.as_ref().len() as size_t;
+ *outlen = buf.as_ref().len();
*out = buf.as_ref().as_ptr();
- let idx = get_ssl_callback_idx::<CustomExtAddState<T>>();
- let ptr = ffi::SSL_get_ex_data(ssl.as_ptr(), idx);
- if ptr.is_null() {
- let x = Box::into_raw(Box::<CustomExtAddState<T>>::new(CustomExtAddState(
- Some(buf),
- ))) as *mut c_void;
- ffi::SSL_set_ex_data(ssl.as_ptr(), idx, x);
- } else {
- *(ptr as *mut _) = CustomExtAddState(Some(buf))
+ let idx = Ssl::cached_ex_index::<CustomExtAddState<T>>();
+ let mut buf = Some(buf);
+ let new = match ssl.ex_data_mut(idx) {
+ Some(state) => {
+ state.0 = buf.take();
+ false
+ }
+ None => true,
+ };
+ if new {
+ ssl.set_ex_data(idx, CustomExtAddState(buf));
}
1
}
@@ -538,9 +542,11 @@ pub extern "C" fn raw_custom_ext_free<T>(
T: 'static + Sync + Send,
{
unsafe {
- let state = ffi::SSL_get_ex_data(ssl, get_ssl_callback_idx::<CustomExtAddState<T>>());
- let state = &mut (*(state as *mut CustomExtAddState<T>)).0;
- state.take();
+ let ssl = SslRef::from_ptr_mut(ssl);
+ let idx = Ssl::cached_ex_index::<CustomExtAddState<T>>();
+ if let Some(state) = ssl.ex_data_mut(idx) {
+ state.0 = None;
+ }
}
}
@@ -557,14 +563,16 @@ pub extern "C" fn raw_custom_ext_parse<F>(
_: *mut c_void,
) -> c_int
where
- F: FnMut(&mut SslRef, ExtensionContext, &[u8], Option<(usize, &X509Ref)>) -> Result<(), SslAlert>
- + 'static,
+ F: Fn(&mut SslRef, ExtensionContext, &[u8], Option<(usize, &X509Ref)>) -> Result<(), SslAlert>
+ + '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::<F>());
let ssl = SslRef::from_ptr_mut(ssl);
- let callback = &mut *(callback as *mut F);
+ let callback = ssl.ssl_context()
+ .ex_data(SslContext::cached_ex_index::<F>())
+ .expect("BUG: custom ext parse callback missing") as *const F;
let ectx = ExtensionContext::from_bits_truncate(context);
let slice = slice::from_raw_parts(input as *const u8, inlen as usize);
let cert = if ectx.contains(ExtensionContext::TLS1_3_CERTIFICATE) {
@@ -572,7 +580,7 @@ where
} else {
None
};
- match callback(ssl, ectx, slice, cert) {
+ match (*callback)(ssl, ectx, slice, cert) {
Ok(()) => 1,
Err(alert) => {
*al = alert.0;
diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs
index 0f9e8935..8dc605ed 100644
--- a/openssl/src/ssl/mod.rs
+++ b/openssl/src/ssl/mod.rs
@@ -7,7 +7,7 @@
//!
//! To connect as a client to a remote server:
//!
-//! ```
+//! ```no_run
//! use openssl::ssl::{SslMethod, SslConnector};
//! use std::io::{Read, Write};
//! use std::net::TcpStream;
@@ -75,38 +75,39 @@ use std::path::Path;
use std::ptr;
use std::slice;
use std::str;
-use std::sync::Mutex;
+use std::sync::{Arc, Mutex};
-use {cvt, cvt_n, cvt_p, init};
use dh::{Dh, DhRef};
-use ec::EcKeyRef;
#[cfg(any(ossl101, ossl102))]
use ec::EcKey;
-use x509::{X509, X509Name, X509Ref, X509StoreContextRef, X509VerifyResult};
-use x509::store::{X509StoreBuilderRef, X509StoreRef};
-#[cfg(any(ossl102, ossl110))]
-use x509::store::X509Store;
-#[cfg(any(ossl102, ossl110))]
-use x509::verify::X509VerifyParamRef;
-use pkey::{HasPrivate, PKeyRef, Params, Private};
+use ec::EcKeyRef;
use error::ErrorStack;
use ex_data::Index;
-use stack::{Stack, StackRef};
-use ssl::bio::BioMethod;
-use ssl::error::InnerError;
-use ssl::callbacks::*;
-use nid::Nid;
#[cfg(ossl111)]
use hash::MessageDigest;
+use nid::Nid;
+use pkey::{HasPrivate, PKeyRef, Params, Private};
+use ssl::bio::BioMethod;
+use ssl::callbacks::*;
+use ssl::error::InnerError;
+use stack::{Stack, StackRef};
+#[cfg(any(ossl102, ossl110))]
+use x509::store::X509Store;
+use x509::store::{X509StoreBuilderRef, X509StoreRef};
+#[cfg(any(ossl102, ossl110))]
+use x509::verify::X509VerifyParamRef;
+use x509::{X509, X509Name, X509Ref, X509StoreContextRef, X509VerifyResult};
+use {cvt, cvt_n, cvt_p, init};
-pub use ssl::connector::{ConnectConfiguration, SslAcceptor, SslAcceptorBuilder, SslConnector,
- SslConnectorBuilder};
+pub use ssl::connector::{
+ ConnectConfiguration, SslAcceptor, SslAcceptorBuilder, SslConnector, SslConnectorBuilder,
+};
pub use ssl::error::{Error, ErrorCode, HandshakeError};
-mod error;
+mod bio;
mod callbacks;
mod connector;
-mod bio;
+mod error;
#[cfg(test)]
mod test;
@@ -465,25 +466,6 @@ lazy_static! {
static ref SSL_INDEXES: Mutex<HashMap<TypeId, c_int>> = Mutex::new(HashMap::new());
}
-// Creates a static index for user data of type T
-// Registers a destructor for the data which will be called
-// when context is freed
-fn get_callback_idx<T: 'static>() -> c_int {
- *INDEXES
- .lock()
- .unwrap()
- .entry(TypeId::of::<T>())
- .or_insert_with(|| get_new_idx::<T>())
-}
-
-fn get_ssl_callback_idx<T: 'static>() -> c_int {
- *SSL_INDEXES
- .lock()
- .unwrap()
- .entry(TypeId::of::<T>())
- .or_insert_with(|| get_new_ssl_idx::<T>())
-}
-
unsafe extern "C" fn free_data_box<T>(
_parent: *mut c_void,
ptr: *mut c_void,
@@ -497,22 +479,6 @@ unsafe extern "C" fn free_data_box<T>(
}
}
-fn get_new_idx<T>() -> c_int {
- unsafe {
- let idx = compat::get_new_idx(free_data_box::<T>);
- assert!(idx >= 0);
- idx
- }
-}
-
-fn get_new_ssl_idx<T>() -> c_int {
- unsafe {
- let idx = compat::get_new_ssl_idx(free_data_box::<T>);
- assert!(idx >= 0);
- idx
- }
-}
-
/// An error returned from the SNI callback.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct SniError(c_int);
@@ -668,12 +634,7 @@ impl SslContextBuilder {
F: Fn(bool, &mut X509StoreContextRef) -> bool + 'static + Sync + Send,
{
unsafe {
- let verify = Box::new(verify);
- ffi::SSL_CTX_set_ex_data(
- self.as_ptr(),
- get_callback_idx::<F>(),
- mem::transmute(verify),
- );
+ self.set_ex_data(SslContext::cached_ex_index::<F>(), verify);
ffi::SSL_CTX_set_verify(self.as_ptr(), mode.bits as c_int, Some(raw_verify::<F>));
}
}
@@ -694,12 +655,7 @@ impl SslContextBuilder {
F: Fn(&mut SslRef, &mut SslAlert) -> Result<(), SniError> + 'static + Sync + Send,
{
unsafe {
- let callback = Box::new(callback);
- ffi::SSL_CTX_set_ex_data(
- self.as_ptr(),
- get_callback_idx::<F>(),
- mem::transmute(callback),
- );
+ self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
let f: extern "C" fn(_, _, _) -> _ = raw_sni::<F>;
let f: extern "C" fn() = mem::transmute(f);
ffi::SSL_CTX_set_tlsext_servername_callback(self.as_ptr(), Some(f));
@@ -789,14 +745,8 @@ impl SslContextBuilder {
F: Fn(&mut SslRef, bool, u32) -> Result<Dh<Params>, ErrorStack> + 'static + Sync + Send,
{
unsafe {
- let callback = Box::new(callback);
- ffi::SSL_CTX_set_ex_data(
- self.as_ptr(),
- get_callback_idx::<F>(),
- Box::into_raw(callback) as *mut c_void,
- );
- let f: unsafe extern "C" fn(_, _, _) -> _ = raw_tmp_dh::<F>;
- ffi::SSL_CTX_set_tmp_dh_callback(self.as_ptr(), f);
+ self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
+ ffi::SSL_CTX_set_tmp_dh_callback(self.as_ptr(), raw_tmp_dh::<F>);
}
}
@@ -823,14 +773,8 @@ impl SslContextBuilder {
F: Fn(&mut SslRef, bool, u32) -> Result<EcKey<Params>, ErrorStack> + 'static + Sync + Send,
{
unsafe {
- let callback = Box::new(callback);
- ffi::SSL_CTX_set_ex_data(
- self.as_ptr(),
- get_callback_idx::<F>(),
- Box::into_raw(callback) as *mut c_void,
- );
- let f: unsafe extern "C" fn(_, _, _) -> _ = raw_tmp_ecdh::<F>;
- ffi::SSL_CTX_set_tmp_ecdh_callback(self.as_ptr(), f);
+ self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
+ ffi::SSL_CTX_set_tmp_ecdh_callback(self.as_ptr(), raw_tmp_ecdh::<F>);
}
}
@@ -1119,10 +1063,10 @@ impl SslContextBuilder {
///
/// This corresponds to [`SSL_CTX_get_min_proto_version`].
///
- /// Requires OpenSSL 1.1.0 or newer.
+ /// Requires OpenSSL 1.1.0g or newer.
///
/// [`SSL_CTX_get_min_proto_version`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_set_min_proto_version.html
- #[cfg(any(ossl110))]
+ #[cfg(any(ossl110g))]
pub fn min_proto_version(&mut self) -> Option<SslVersion> {
unsafe {
let r = ffi::SSL_CTX_get_min_proto_version(self.as_ptr());
@@ -1141,10 +1085,10 @@ impl SslContextBuilder {
///
/// This corresponds to [`SSL_CTX_get_max_proto_version`].
///
- /// Requires OpenSSL 1.1.0 or newer.
+ /// Requires OpenSSL 1.1.0g or newer.
///
/// [`SSL_CTX_get_max_proto_version`]: https://www.openssl.org/docs/man1.1.0/ssl/SSL_set_min_proto_version.html
- #[cfg(any(ossl110))]
+ #[cfg(any(ossl110g))]
pub fn max_proto_version(&mut self) -> Option<SslVersion> {
unsafe {
let r = ffi::SSL_CTX_get_max_proto_version(self.as_ptr());
@@ -1207,12 +1151,7 @@ impl SslContextBuilder {
F: for<'a> Fn(&mut SslRef, &'a [u8]) -> Result<&'a [u8], AlpnError> + 'static + Sync + Send,
{
unsafe {
- let callback = Box::new(callback);
- ffi::SSL_CTX_set_ex_data(
- self.as_ptr(),
- get_callback_idx::<F>(),
- Box::into_raw(callback) as *mut c_void,
- );
+ self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
ffi::SSL_CTX_set_alpn_select_cb(
self.as_ptr(),
callbacks::raw_alpn_select::<F>,
@@ -1269,14 +1208,11 @@ impl SslContextBuilder {
F: Fn(&mut SslRef) -> Result<bool, ErrorStack> + 'static + Sync + Send,
{
unsafe {
- let callback = Box::new(callback);
- ffi::SSL_CTX_set_ex_data(
- self.as_ptr(),
- get_callback_idx::<F>(),
- Box::into_raw(callback) as *mut c_void,
- );
- let f: unsafe extern "C" fn(_, _) -> _ = raw_tlsext_status::<F>;
- cvt(ffi::SSL_CTX_set_tlsext_status_cb(self.as_ptr(), Some(f)) as c_int).map(|_| ())
+ self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
+ cvt(
+ ffi::SSL_CTX_set_tlsext_status_cb(self.as_ptr(), Some(raw_tlsext_status::<F>))
+ as c_int,
+ ).map(|_| ())
}
}
@@ -1298,13 +1234,8 @@ impl SslContextBuilder {
+ Send,
{
unsafe {
- let callback = Box::new(callback);
- ffi::SSL_CTX_set_ex_data(
- self.as_ptr(),
- get_callback_idx::<F>(),
- mem::transmute(callback),
- );
- ffi::SSL_CTX_set_psk_client_callback(self.as_ptr(), Some(raw_psk::<F>))
+ self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
+ ffi::SSL_CTX_set_psk_client_callback(self.as_ptr(), Some(raw_psk::<F>));
}
}
@@ -1329,12 +1260,7 @@ impl SslContextBuilder {
F: Fn(&mut SslRef, SslSession) + 'static + Sync + Send,
{
unsafe {
- let callback = Box::new(callback);
- ffi::SSL_CTX_set_ex_data(
- self.as_ptr(),
- get_callback_idx::<F>(),
- Box::into_raw(callback) as *mut _,
- );
+ self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
ffi::SSL_CTX_sess_set_new_cb(self.as_ptr(), Some(callbacks::raw_new_session::<F>));
}
}
@@ -1351,12 +1277,7 @@ impl SslContextBuilder {
F: Fn(&SslContextRef, &SslSessionRef) + 'static + Sync + Send,
{
unsafe {
- let callback = Box::new(callback);
- ffi::SSL_CTX_set_ex_data(
- self.as_ptr(),
- get_callback_idx::<F>(),
- Box::into_raw(callback) as *mut _,
- );
+ self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
ffi::SSL_CTX_sess_set_remove_cb(
self.as_ptr(),
Some(callbacks::raw_remove_session::<F>),
@@ -1382,12 +1303,7 @@ impl SslContextBuilder {
where
F: Fn(&mut SslRef, &[u8]) -> Option<SslSession> + 'static + Sync + Send,
{
- let callback = Box::new(callback);
- ffi::SSL_CTX_set_ex_data(
- self.as_ptr(),
- get_callback_idx::<F>(),
- Box::into_raw(callback) as *mut _,
- );
+ self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
ffi::SSL_CTX_sess_set_get_cb(self.as_ptr(), Some(callbacks::raw_get_session::<F>));
}
@@ -1408,12 +1324,7 @@ impl SslContextBuilder {
F: Fn(&SslRef, &str) + 'static + Sync + Send,
{
unsafe {
- let callback = Box::new(callback);
- ffi::SSL_CTX_set_ex_data(
- self.as_ptr(),
- get_callback_idx::<F>(),
- Box::into_raw(callback) as *mut _,
- );
+ self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
ffi::SSL_CTX_set_keylog_callback(self.as_ptr(), Some(callbacks::raw_keylog::<F>));
}
}
@@ -1445,13 +1356,11 @@ impl SslContextBuilder {
F: Fn(&mut SslRef, &mut [u8]) -> Result<usize, ErrorStack> + 'static + Sync + Send,
{
unsafe {
- let callback = Box::new(callback);
- ffi::SSL_CTX_set_ex_data(
+ self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
+ ffi::SSL_CTX_set_stateless_cookie_generate_cb(
self.as_ptr(),
- get_callback_idx::<F>(),
- Box::into_raw(callback) as *mut _,
+ Some(raw_stateless_cookie_generate::<F>),
);
- ffi::SSL_CTX_set_stateless_cookie_generate_cb(self.as_ptr(), Some(raw_stateless_cookie_generate::<F>))
}
}
@@ -1471,13 +1380,11 @@ impl SslContextBuilder {
F: Fn(&mut SslRef, &[u8]) -> bool + 'static + Sync + Send,
{
unsafe {
- let callback = Box::new(callback);
- ffi::SSL_CTX_set_ex_data(
+ self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
+ ffi::SSL_CTX_set_stateless_cookie_verify_cb(
self.as_ptr(),
- get_callback_idx::<F>(),
- Box::into_raw(callback) as *mut _,
- );
- ffi::SSL_CTX_set_stateless_cookie_verify_cb(self.as_ptr(), Some(raw_stateless_cookie_verify::<F>))
+ Some(raw_stateless_cookie_verify::<F>),
+ )
}
}
@@ -1492,13 +1399,8 @@ impl SslContextBuilder {
F: Fn(&mut SslRef, &mut [u8]) -> Result<usize, ErrorStack> + 'static + Sync + Send,
{
unsafe {
- let callback = Box::new(callback);
- ffi::SSL_CTX_set_ex_data(
- self.as_ptr(),
- get_callback_idx::<F>(),
- Box::into_raw(callback) as *mut _,
- );
- ffi::SSL_CTX_set_cookie_generate_cb(self.as_ptr(), Some(raw_cookie_generate::<F>))
+ self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
+ ffi::SSL_CTX_set_cookie_generate_cb(self.as_ptr(), Some(raw_cookie_generate::<F>));
}
}
@@ -1513,13 +1415,8 @@ impl SslContextBuilder {
F: Fn(&mut SslRef, &[u8]) -> bool + 'static + Sync + Send,
{
unsafe {
- let callback = Box::new(callback);
- ffi::SSL_CTX_set_ex_data(
- self.as_ptr(),
- get_callback_idx::<F>(),
- Box::into_raw(callback) as *mut _,
- );
- ffi::SSL_CTX_set_cookie_verify_cb(self.as_ptr(), Some(raw_cookie_verify::<F>))
+ self.set_ex_data(SslContext::cached_ex_index::<F>(), callback);
+ ffi::SSL_CTX_set_cookie_verify_cb(self.as_ptr(), Some(raw_cookie_verify::<F>));
}
}
@@ -1571,19 +1468,8 @@ impl SslContextBuilder {
+ Send,
{
let ret = unsafe {
- let add_cb = Box::new(add_cb);
- ffi::SSL_CTX_set_ex_data(
- self.as_ptr(),
- get_callback_idx::<AddFn>(),
- Box::into_raw(add_cb) as *mut _,
- );
-
- let parse_cb = Box::new(parse_cb);
- ffi::SSL_CTX_set_ex_data(
- self.as_ptr(),
- get_callback_idx::<ParseFn>(),
- Box::into_raw(parse_cb) as *mut _,
- );
+ self.set_ex_data(SslContext::cached_ex_index::<AddFn>(), add_cb);
+ self.set_ex_data(SslContext::cached_ex_index::<ParseFn>(), parse_cb);
ffi::SSL_CTX_add_custom_ext(
self.as_ptr(),
@@ -1665,6 +1551,21 @@ impl SslContext {
Ok(Index::from_raw(idx))
}
}
+
+ // FIXME should return a result?
+ fn cached_ex_index<T>() -> Index<SslContext, T>
+ where
+ T: 'static + Sync + Send,
+ {
+ unsafe {
+ let idx = *INDEXES
+ .lock()
+ .unwrap_or_else(|e| e.into_inner())
+ .entry(TypeId::of::<T>())
+ .or_insert_with(|| SslContext::new_ex_index::<T>().unwrap().as_raw());
+ Index::from_raw(idx)
+ }
+ }
}
impl SslContextRef {
@@ -1914,6 +1815,19 @@ impl Clone for SslSession {
}
}
+impl SslSession {
+ from_der! {
+ /// Deserializes a DER-encoded session structure.
+ ///
+ /// This corresponds to [`d2i_SSL_SESSION`].
+ ///
+ /// [`d2i_SSL_SESSION`]: https://www.openssl.org/docs/man1.0.2/ssl/d2i_SSL_SESSION.html
+ from_der,
+ SslSession,
+ ffi::d2i_SSL_SESSION
+ }
+}
+
impl ToOwned for SslSessionRef {
type Owned = SslSession;
@@ -1958,6 +1872,16 @@ impl SslSessionRef {
pub fn master_key(&self, buf: &mut [u8]) -> usize {
unsafe { compat::SSL_SESSION_get_master_key(self.as_ptr(), buf.as_mut_ptr(), buf.len()) }
}
+
+ to_der! {
+ /// Serializes the session into a DER-encoded structure.
+ ///
+ /// This corresponds to [`i2d_SSL_SESSION`].
+ ///
+ /// [`i2d_SSL_SESSION`]: https://www.openssl.org/docs/man1.0.2/ssl/i2d_SSL_SESSION.html
+ to_der,
+ ffi::i2d_SSL_SESSION
+ }
}
foreign_type! {
@@ -1978,6 +1902,15 @@ foreign_type! {
pub struct SslRef;
}
+unsafe impl Sync for Ssl {}
+unsafe impl Send for Ssl {}
+
+impl fmt::Debug for Ssl {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Debug::fmt(&**self, fmt)
+ }
+}
+
impl Ssl {
/// Returns a new extra data index.
///
@@ -1997,6 +1930,67 @@ impl Ssl {
Ok(Index::from_raw(idx))
}
}
+
+ // FIXME should return a result?
+ fn cached_ex_index<T>() -> Index<Ssl, T>
+ where
+ T: 'static + Sync + Send,
+ {
+ unsafe {
+ let idx = *SSL_INDEXES
+ .lock()
+ .unwrap_or_else(|e| e.into_inner())
+ .entry(TypeId::of::<T>())
+ .or_insert_with(|| Ssl::new_ex_index::<T>().unwrap().as_raw());
+ Index::from_raw(idx)
+ }
+ }
+
+ /// Creates a new `Ssl`.
+ ///
+ /// This corresponds to [`SSL_new`].
+ ///
+ /// [`SSL_new`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_new.html
+ pub fn new(ctx: &SslContext) -> Result<Ssl, ErrorStack> {
+ unsafe {
+ let ssl = cvt_p(ffi::SSL_new(ctx.as_ptr()))?;
+ Ok(Ssl::from_ptr(ssl))
+ }
+ }
+
+ /// Initiates a client-side TLS handshake.
+ ///
+ /// This corresponds to [`SSL_connect`].
+ ///
+ /// # Warning
+ ///
+ /// OpenSSL's default configuration is insecure. It is highly recommended to use
+ /// `SslConnector` rather than `Ssl` directly, as it manages that configuration.
+ ///
+ /// [`SSL_connect`]: https://www.openssl.org/docs/manmaster/man3/SSL_connect.html
+ pub fn connect<S>(self, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
+ where
+ S: Read + Write,
+ {
+ SslStreamBuilder::new(self, stream).connect()
+ }
+
+ /// Initiates a server-side TLS handshake.
+ ///
+ /// This corresponds to [`SSL_accept`].
+ ///
+ /// # Warning
+ ///
+ /// OpenSSL's default configuration is insecure. It is highly recommended to use
+ /// `SslAcceptor` rather than `Ssl` directly, as it manages that configuration.
+ ///
+ /// [`SSL_accept`]: https://www.openssl.org/docs/manmaster/man3/SSL_accept.html
+ pub fn accept<S>(self, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
+ where
+ S: Read + Write,
+ {
+ SslStreamBuilder::new(self, stream).accept()
+ }
}
impl fmt::Debug for SslRef {
@@ -2048,12 +2042,8 @@ impl SslRef {
F: Fn(bool, &mut X509StoreContextRef) -> bool + 'static + Sync + Send,
{
unsafe {
- let verify = Box::new(verify);
- ffi::SSL_set_ex_data(
- self.as_ptr(),
- get_ssl_callback_idx::<F>(),
- mem::transmute(verify),
- );
+ // this needs to be in an Arc since the callback can register a new callback!
+ self.set_ex_data(Ssl::cached_ex_index(), Arc::new(verify));
ffi::SSL_set_verify(self.as_ptr(), mode.bits as c_int, Some(ssl_raw_verify::<F>));
}
}
@@ -2079,14 +2069,9 @@ impl SslRef {
F: Fn(&mut SslRef, bool, u32) -> Result<Dh<Params>, ErrorStack> + 'static + Sync + Send,
{
unsafe {
- let callback = Box::new(callback);
- ffi::SSL_set_ex_data(
- self.as_ptr(),
- get_ssl_callback_idx::<F>(),
- Box::into_raw(callback) as *mut c_void,
- );
- let f: unsafe extern "C" fn(_, _, _) -> _ = raw_tmp_dh_ssl::<F>;
- ffi::SSL_set_tmp_dh_callback(self.as_ptr(), f);
+ // this needs to be in an Arc since the callback can register a new callback!
+ self.set_ex_data(Ssl::cached_ex_index(), Arc::new(callback));
+ ffi::SSL_set_tmp_dh_callback(self.as_ptr(), raw_tmp_dh_ssl::<F>);
}
}
@@ -2112,14 +2097,9 @@ impl SslRef {
F: Fn(&mut SslRef, bool, u32) -> Result<EcKey<Params>, ErrorStack> + 'static + Sync + Send,
{
unsafe {
- let callback = Box::new(callback);
- ffi::SSL_set_ex_data(
- self.as_ptr(),
- get_ssl_callback_idx::<F>(),
- Box::into_raw(callback) as *mut c_void,
- );
- let f: unsafe extern "C" fn(_, _, _) -> _ = raw_tmp_ecdh_ssl::<F>;
- ffi::SSL_set_tmp_ecdh_callback(self.as_ptr(), f);
+ // this needs to be in an Arc since the callback can register a new callback!
+ self.set_ex_data(Ssl::cached_ex_index(), Arc::new(callback));
+ ffi::SSL_set_tmp_ecdh_callback(self.as_ptr(), raw_tmp_ecdh_ssl::<F>);
}
}
@@ -2598,63 +2578,22 @@ impl SslRef {
}
}
}
-}
-
-unsafe impl Sync for Ssl {}
-unsafe impl Send for Ssl {}
-
-impl fmt::Debug for Ssl {
- fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- fmt::Debug::fmt(&**self, fmt)
- }
-}
-impl Ssl {
- /// Creates a new `Ssl`.
+ /// Returns a mutable reference to the extra data at the specified index.
///
- /// This corresponds to [`SSL_new`].
+ /// This corresponds to [`SSL_get_ex_data`].
///
- /// [`SSL_new`]: https://www.openssl.org/docs/man1.0.2/ssl/SSL_new.html
- pub fn new(ctx: &SslContext) -> Result<Ssl, ErrorStack> {
+ /// [`SSL_get_ex_data`]: https://www.openssl.org/docs/manmaster/man3/SSL_set_ex_data.html
+ pub fn ex_data_mut<T>(&mut self, index: Index<Ssl, T>) -> Option<&mut T> {
unsafe {
- let ssl = cvt_p(ffi::SSL_new(ctx.as_ptr()))?;
- Ok(Ssl::from_ptr(ssl))
+ let data = ffi::SSL_get_ex_data(self.as_ptr(), index.as_raw());
+ if data.is_null() {
+ None
+ } else {
+ Some(&mut *(data as *mut T))
+ }
}
}
-
- /// Initiates a client-side TLS handshake.
- ///
- /// This corresponds to [`SSL_connect`].
- ///
- /// # Warning
- ///
- /// OpenSSL's default configuration is insecure. It is highly recommended to use
- /// `SslConnector` rather than `Ssl` directly, as it manages that configuration.
- ///
- /// [`SSL_connect`]: https://www.openssl.org/docs/manmaster/man3/SSL_connect.html
- pub fn connect<S>(self, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
- where
- S: Read + Write,
- {
- SslStreamBuilder::new(self, stream).connect()
- }
-
- /// Initiates a server-side TLS handshake.
- ///
- /// This corresponds to [`SSL_accept`].
- ///
- /// # Warning
- ///
- /// OpenSSL's default configuration is insecure. It is highly recommended to use
- /// `SslAcceptor` rather than `Ssl` directly, as it manages that configuration.
- ///
- /// [`SSL_accept`]: https://www.openssl.org/docs/manmaster/man3/SSL_accept.html
- pub fn accept<S>(self, stream: S) -> Result<SslStream<S>, HandshakeError<S>>
- where
- S: Read + Write,
- {
- SslStreamBuilder::new(self, stream).accept()
- }
}
/// An SSL stream midway through the handshake process.
@@ -2927,11 +2866,12 @@ impl<S: Read + Write> Write for SslStream<S> {
/// A partially constructed `SslStream`, useful for unusual handshakes.
pub struct SslStreamBuilder<S> {
- inner: SslStream<S>
+ inner: SslStream<S>,
}
impl<S> SslStreamBuilder<S>
- where S: Read + Write
+where
+ S: Read + Write,
{
/// Begin creating an `SslStream` atop `stream`
pub fn new(ssl: Ssl, stream: S) -> Self {
@@ -3030,7 +2970,9 @@ impl<S> SslStreamBuilder<S> {
}
/// Returns a shared reference to the `Ssl` object associated with this builder.
- pub fn ssl(&self) -> &SslRef { &self.inner.ssl }
+ pub fn ssl(&self) -> &SslRef {
+ &self.inner.ssl
+ }
}
/// The result of a shutdown request.
@@ -3050,8 +2992,10 @@ mod compat {
use ffi;
use libc::c_int;
- pub use ffi::{SSL_CTX_clear_options, SSL_CTX_get_options, SSL_CTX_set_options, SSL_CTX_up_ref,
- SSL_SESSION_get_master_key, SSL_SESSION_up_ref, SSL_is_server};
+ pub use ffi::{
+ SSL_CTX_clear_options, SSL_CTX_get_options, SSL_CTX_set_options, SSL_CTX_up_ref,
+ SSL_SESSION_get_master_key, SSL_SESSION_up_ref, SSL_is_server,
+ };
pub unsafe fn get_new_idx(f: ffi::CRYPTO_EX_free) -> c_int {
ffi::CRYPTO_get_ex_new_index(
diff --git a/openssl/src/ssl/test.rs b/openssl/src/ssl/test.rs
index ddcb49ff..2e906728 100644
--- a/openssl/src/ssl/test.rs
+++ b/openssl/src/ssl/test.rs
@@ -17,16 +17,17 @@ use tempdir::TempDir;
use dh::Dh;
use hash::MessageDigest;
use ocsp::{OcspResponse, OcspResponseStatus};
+use pkey::PKey;
use ssl;
-use ssl::{Error, HandshakeError, ShutdownResult, Ssl, SslAcceptor, SslConnector, SslContext,
- SslFiletype, SslMethod, SslSessionCacheMode, SslStream, MidHandshakeSslStream,
- SslVerifyMode, StatusType};
#[cfg(any(ossl110, ossl111))]
use ssl::SslVersion;
-use x509::{X509, X509Name, X509StoreContext, X509VerifyResult};
+use ssl::{
+ Error, HandshakeError, MidHandshakeSslStream, ShutdownResult, Ssl, SslAcceptor, SslConnector,
+ SslContext, SslFiletype, SslMethod, SslSessionCacheMode, SslStream, SslVerifyMode, StatusType,
+};
#[cfg(any(ossl102, ossl110))]
use x509::verify::X509CheckFlags;
-use pkey::PKey;
+use x509::{X509, X509Name, X509StoreContext, X509VerifyResult};
use std::net::UdpSocket;
@@ -762,6 +763,7 @@ fn refcount_ssl_context() {
}
#[test]
+#[cfg_attr(libressl250, ignore)]
fn default_verify_paths() {
let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
ctx.set_default_verify_paths().unwrap();
@@ -831,6 +833,7 @@ fn verify_invalid_hostname() {
}
#[test]
+#[cfg_attr(libressl250, ignore)]
fn connector_valid_hostname() {
let connector = SslConnector::builder(SslMethod::tls()).unwrap().build();
@@ -855,6 +858,7 @@ fn connector_invalid_hostname() {
}
#[test]
+#[cfg_attr(libressl250, ignore)]
fn connector_invalid_no_hostname_verification() {
let connector = SslConnector::builder(SslMethod::tls()).unwrap().build();
@@ -1175,6 +1179,7 @@ fn idle_session() {
}
#[test]
+#[cfg_attr(libressl250, ignore)]
fn active_session() {
let connector = SslConnector::builder(SslMethod::tls()).unwrap().build();
@@ -1323,7 +1328,9 @@ fn no_version_overlap() {
ctx.set_private_key_file(&Path::new("test/key.pem"), SslFiletype::PEM)
.unwrap();
ctx.set_max_proto_version(Some(SslVersion::TLS1_1)).unwrap();
+ #[cfg(ossl110g)]
assert_eq!(ctx.min_proto_version(), None);
+ #[cfg(ossl110g)]
assert_eq!(ctx.max_proto_version(), Some(SslVersion::TLS1_1));
let ssl = Ssl::new(&ctx.build()).unwrap();
ssl.accept(stream).unwrap_err();
@@ -1332,7 +1339,9 @@ fn no_version_overlap() {
let stream = TcpStream::connect(addr).unwrap();
let mut ctx = SslContext::builder(SslMethod::tls()).unwrap();
ctx.set_min_proto_version(Some(SslVersion::TLS1_2)).unwrap();
+ #[cfg(ossl110g)]
assert_eq!(ctx.min_proto_version(), Some(SslVersion::TLS1_2));
+ #[cfg(ossl110g)]
assert_eq!(ctx.max_proto_version(), None);
let ssl = Ssl::new(&ctx.build()).unwrap();
ssl.connect(stream).unwrap_err();
@@ -1391,74 +1400,89 @@ fn _check_kinds() {
is_sync::<SslStream<TcpStream>>();
}
-#[derive(Debug)]
-struct MemoryStream {
- incoming: io::Cursor<Vec<u8>>,
- outgoing: Vec<u8>,
-}
-
-impl MemoryStream {
- pub fn new() -> Self { Self {
- incoming: io::Cursor::new(Vec::new()),
- outgoing: Vec::new(),
- }}
+#[test]
+#[cfg(ossl111)]
+fn stateless() {
+ use super::SslOptions;
- pub fn extend_incoming(&mut self, data: &[u8]) {
- self.incoming.get_mut().extend_from_slice(data);
+ #[derive(Debug)]
+ struct MemoryStream {
+ incoming: io::Cursor<Vec<u8>>,
+ outgoing: Vec<u8>,
}
- pub fn take_outgoing(&mut self) -> Outgoing { Outgoing(&mut self.outgoing) }
-}
+ impl MemoryStream {
+ pub fn new() -> Self {
+ Self {
+ incoming: io::Cursor::new(Vec::new()),
+ outgoing: Vec::new(),
+ }
+ }
-impl Read for MemoryStream {
- fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
- let n = self.incoming.read(buf)?;
- if self.incoming.position() == self.incoming.get_ref().len() as u64 {
- self.incoming.set_position(0);
- self.incoming.get_mut().clear();
+ pub fn extend_incoming(&mut self, data: &[u8]) {
+ self.incoming.get_mut().extend_from_slice(data);
}
- if n == 0 {
- return Err(io::Error::new(io::ErrorKind::WouldBlock, "no data available"));
+
+ pub fn take_outgoing(&mut self) -> Outgoing {
+ Outgoing(&mut self.outgoing)
}
- Ok(n)
}
-}
-impl Write for MemoryStream {
- fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
- self.outgoing.write(buf)
+ impl Read for MemoryStream {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ let n = self.incoming.read(buf)?;
+ if self.incoming.position() == self.incoming.get_ref().len() as u64 {
+ self.incoming.set_position(0);
+ self.incoming.get_mut().clear();
+ }
+ if n == 0 {
+ return Err(io::Error::new(
+ io::ErrorKind::WouldBlock,
+ "no data available",
+ ));
+ }
+ Ok(n)
+ }
}
- fn flush(&mut self) -> io::Result<()> { Ok(()) }
-}
-
-pub struct Outgoing<'a>(&'a mut Vec<u8>);
+ impl Write for MemoryStream {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ self.outgoing.write(buf)
+ }
-impl<'a> Drop for Outgoing<'a> {
- fn drop(&mut self) {
- self.0.clear();
+ fn flush(&mut self) -> io::Result<()> {
+ Ok(())
+ }
}
-}
-impl<'a> ::std::ops::Deref for Outgoing<'a> {
- type Target = [u8];
- fn deref(&self) -> &[u8] { &self.0 }
-}
+ pub struct Outgoing<'a>(&'a mut Vec<u8>);
-impl<'a> AsRef<[u8]> for Outgoing<'a> {
- fn as_ref(&self) -> &[u8] { &self.0 }
-}
+ impl<'a> Drop for Outgoing<'a> {
+ fn drop(&mut self) {
+ self.0.clear();
+ }
+ }
-fn send(from: &mut MemoryStream, to: &mut MemoryStream) {
- to.extend_incoming(&from.take_outgoing());
-}
+ impl<'a> ::std::ops::Deref for Outgoing<'a> {
+ type Target = [u8];
+ fn deref(&self) -> &[u8] {
+ &self.0
+ }
+ }
-#[test]
-#[cfg(ossl111)]
-fn stateless() {
- use super::SslOptions;
+ impl<'a> AsRef<[u8]> for Outgoing<'a> {
+ fn as_ref(&self) -> &[u8] {
+ &self.0
+ }
+ }
- fn hs<S: ::std::fmt::Debug>(stream: Result<SslStream<S>, HandshakeError<S>>) -> Result<SslStream<S>, MidHandshakeSslStream<S>> {
+ fn send(from: &mut MemoryStream, to: &mut MemoryStream) {
+ to.extend_incoming(&from.take_outgoing());
+ }
+
+ fn hs<S: ::std::fmt::Debug>(
+ stream: Result<SslStream<S>, HandshakeError<S>>,
+ ) -> Result<SslStream<S>, MidHandshakeSslStream<S>> {
match stream {
Ok(stream) => Ok(stream),
Err(HandshakeError::WouldBlock(stream)) => Err(stream),
@@ -1475,14 +1499,20 @@ fn stateless() {
let client_stream = Ssl::new(&client_ctx.build()).unwrap();
let mut server_ctx = SslContext::builder(SslMethod::tls()).unwrap();
- server_ctx.set_certificate_file(&Path::new("test/cert.pem"), SslFiletype::PEM)
+ server_ctx
+ .set_certificate_file(&Path::new("test/cert.pem"), SslFiletype::PEM)
.unwrap();
- server_ctx.set_private_key_file(&Path::new("test/key.pem"), SslFiletype::PEM)
+ server_ctx
+ .set_private_key_file(&Path::new("test/key.pem"), SslFiletype::PEM)
.unwrap();
const COOKIE: &[u8] = b"chocolate chip";
- server_ctx.set_stateless_cookie_generate_cb(|_tls, buf| { buf[0..COOKIE.len()].copy_from_slice(COOKIE); Ok(COOKIE.len()) });
+ server_ctx.set_stateless_cookie_generate_cb(|_tls, buf| {
+ buf[0..COOKIE.len()].copy_from_slice(COOKIE);
+ Ok(COOKIE.len())
+ });
server_ctx.set_stateless_cookie_verify_cb(|_tls, buf| buf == COOKIE);
- let mut server_stream = ssl::SslStreamBuilder::new(Ssl::new(&server_ctx.build()).unwrap(), MemoryStream::new());
+ let mut server_stream =
+ ssl::SslStreamBuilder::new(Ssl::new(&server_ctx.build()).unwrap(), MemoryStream::new());
//
// Handshake
diff --git a/openssl/src/x509/mod.rs b/openssl/src/x509/mod.rs
index 011a2d96..c1ae3b16 100644
--- a/openssl/src/x509/mod.rs
+++ b/openssl/src/x509/mod.rs
@@ -1069,6 +1069,28 @@ impl X509ReqRef {
X509NameRef::from_ptr(name)
}
}
+
+ /// Returns the public key of the certificate request.
+ ///
+ /// This corresponds to [`X509_REQ_get_pubkey"]
+ ///
+ /// [`X509_REQ_get_pubkey`]: https://www.openssl.org/docs/man1.1.0/crypto/X509_REQ_get_pubkey.html
+ pub fn public_key(&self) -> Result<PKey<Public>, ErrorStack> {
+ unsafe {
+ let key = cvt_p(ffi::X509_REQ_get_pubkey(self.as_ptr()))?;
+ Ok(PKey::from_ptr(key))
+ }
+ }
+
+ /// Returns the extensions of the certificate request.
+ ///
+ /// This corresponds to [`X509_REQ_get_extensions"]
+ pub fn extensions(&self) -> Result<Stack<X509Extension>, ErrorStack> {
+ unsafe {
+ let extensions = cvt_p(ffi::X509_REQ_get_extensions(self.as_ptr()))?;
+ Ok(Stack::from_ptr(extensions))
+ }
+ }
}
/// The result of peer certificate verification.
diff --git a/openssl/src/x509/tests.rs b/openssl/src/x509/tests.rs
index fa8056ad..7ef4d160 100644
--- a/openssl/src/x509/tests.rs
+++ b/openssl/src/x509/tests.rs
@@ -234,6 +234,10 @@ fn x509_req_builder() {
builder.add_extensions(&extensions).unwrap();
builder.sign(&pkey, MessageDigest::sha256()).unwrap();
+
+ let req = builder.build();
+ assert!(req.public_key().unwrap().public_eq(&pkey));
+ assert_eq!(req.extensions().unwrap().len(), extensions.len());
}
#[test]