Skip to content

Commit

Permalink
Implement ex_data functions for SSL and SSL_CTX
Browse files Browse the repository at this point in the history
  • Loading branch information
ctz committed Apr 9, 2024
1 parent 183d65f commit 0a6f130
Show file tree
Hide file tree
Showing 6 changed files with 280 additions and 24 deletions.
8 changes: 4 additions & 4 deletions rustls-libssl/MATRIX.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@
| `SSL_CTX_get_client_cert_cb` | | | |
| `SSL_CTX_get_default_passwd_cb` | | | |
| `SSL_CTX_get_default_passwd_cb_userdata` | | | |
| `SSL_CTX_get_ex_data` | | :white_check_mark: | :exclamation: [^stub] |
| `SSL_CTX_get_ex_data` | | :white_check_mark: | :white_check_mark: |
| `SSL_CTX_get_info_callback` | | | |
| `SSL_CTX_get_keylog_callback` | | | |
| `SSL_CTX_get_max_early_data` | | :white_check_mark: | :white_check_mark: |
Expand Down Expand Up @@ -156,7 +156,7 @@
| `SSL_CTX_set_default_verify_file` | | | :white_check_mark: |
| `SSL_CTX_set_default_verify_paths` | | | :white_check_mark: |
| `SSL_CTX_set_default_verify_store` | | | :exclamation: [^stub] |
| `SSL_CTX_set_ex_data` | | :white_check_mark: | :exclamation: [^stub] |
| `SSL_CTX_set_ex_data` | | :white_check_mark: | :white_check_mark: |
| `SSL_CTX_set_generate_session_id` | | | |
| `SSL_CTX_set_info_callback` | | :white_check_mark: | :exclamation: [^stub] |
| `SSL_CTX_set_keylog_callback` | :white_check_mark: | | :exclamation: [^stub] |
Expand Down Expand Up @@ -336,7 +336,7 @@
| `SSL_get_default_timeout` | | | |
| `SSL_get_early_data_status` | | | |
| `SSL_get_error` | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| `SSL_get_ex_data` | :white_check_mark: | :white_check_mark: | :exclamation: [^stub] |
| `SSL_get_ex_data` | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| `SSL_get_ex_data_X509_STORE_CTX_idx` | | :white_check_mark: | :exclamation: [^stub] |
| `SSL_get_fd` | | | |
| `SSL_get_finished` | | | |
Expand Down Expand Up @@ -436,7 +436,7 @@
| `SSL_set_default_passwd_cb` | | | |
| `SSL_set_default_passwd_cb_userdata` | | | |
| `SSL_set_default_read_buffer_len` | | | |
| `SSL_set_ex_data` | :white_check_mark: | :white_check_mark: | :exclamation: [^stub] |
| `SSL_set_ex_data` | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| `SSL_set_fd` [^sock] | :white_check_mark: | :white_check_mark: | :white_check_mark: |
| `SSL_set_generate_session_id` | | | |
| `SSL_set_hostflags` | | | |
Expand Down
107 changes: 88 additions & 19 deletions rustls-libssl/src/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use crate::bio::{Bio, BIO, BIO_METHOD};
use crate::callbacks::Callbacks;
use crate::error::{ffi_panic_boundary, Error, MysteriouslyOppositeReturnValue};
use crate::evp_pkey::EvpPkey;
use crate::ex_data::ExData;
use crate::ffi::{
clone_arc, free_arc, str_from_cstring, to_arc_mut_ptr, try_clone_arc, try_from,
try_mut_slice_int, try_ref_from_ptr, try_slice, try_slice_int, try_str, Castable, OwnershipArc,
Expand Down Expand Up @@ -108,12 +109,28 @@ impl Castable for SSL_METHOD {
type RustType = SSL_METHOD;
}

type SSL_CTX = crate::SslContext;
pub type SSL_CTX = crate::SslContext;

entry! {
pub fn _SSL_CTX_new(meth: *const SSL_METHOD) -> *mut SSL_CTX {
let method = try_ref_from_ptr!(meth);
to_arc_mut_ptr(Mutex::new(crate::SslContext::new(method)))
let out = to_arc_mut_ptr(Mutex::new(crate::SslContext::new(method)));
let ex_data = match ExData::new_ssl_ctx(out) {
None => {
_SSL_CTX_free(out);
return ptr::null_mut();
}
Some(ex_data) => ex_data,
};

// safety: we just made this object, the point must be valid and
// the lock must be non-poisoned.
clone_arc(out)
.unwrap()
.lock()
.map(|mut ctx| ctx.install_ex_data(ex_data))
.unwrap();
out
}
}

Expand All @@ -131,6 +148,32 @@ entry! {
}
}

entry! {
pub fn _SSL_CTX_set_ex_data(ctx: *mut SSL_CTX, idx: c_int, data: *mut c_void) -> c_int {
let ctx = try_clone_arc!(ctx);

match ctx
.lock()
.map_err(|_| Error::cannot_lock())
.and_then(|mut ctx| ctx.set_ex_data(idx, data))
{
Err(e) => e.raise().into(),
Ok(()) => C_INT_SUCCESS,
}
}
}

entry! {
pub fn _SSL_CTX_get_ex_data(ctx: *const SSL_CTX, idx: c_int) -> *mut c_void {
let ctx = try_clone_arc!(ctx);

ctx.lock()
.ok()
.map(|mut ctx| ctx.get_ex_data(idx))
.unwrap_or_else(ptr::null_mut)
}
}

entry! {
pub fn _SSL_CTX_get_options(ctx: *const SSL_CTX) -> u64 {
let ctx = try_clone_arc!(ctx);
Expand Down Expand Up @@ -695,7 +738,23 @@ entry! {
None => return ptr::null_mut(),
};

to_arc_mut_ptr(Mutex::new(ssl))
let out = to_arc_mut_ptr(Mutex::new(ssl));
let ex_data = match ExData::new_ssl(out) {
None => {
_SSL_free(out);
return ptr::null_mut();
}
Some(ex_data) => ex_data,
};

// safety: we just made this object, the point must be valid and
// the lock must be non-poisoned.
clone_arc(out)
.unwrap()
.lock()
.map(|mut ssl| ssl.install_ex_data(ex_data))
.unwrap();
out
}
}

Expand All @@ -713,6 +772,32 @@ entry! {
}
}

entry! {
pub fn _SSL_set_ex_data(ssl: *mut SSL, idx: c_int, data: *mut c_void) -> c_int {
let ssl = try_clone_arc!(ssl);

match ssl
.lock()
.map_err(|_| Error::cannot_lock())
.and_then(|mut ssl| ssl.set_ex_data(idx, data))
{
Err(e) => e.raise().into(),
Ok(()) => C_INT_SUCCESS,
}
}
}

entry! {
pub fn _SSL_get_ex_data(ssl: *const SSL, idx: c_int) -> *mut c_void {
let ssl = try_clone_arc!(ssl);

ssl.lock()
.ok()
.map(|mut ssl| ssl.get_ex_data(idx))
.unwrap_or_else(ptr::null_mut)
}
}

entry! {
pub fn _SSL_ctrl(ssl: *mut SSL, cmd: c_int, larg: c_long, parg: *mut c_void) -> c_long {
let ssl = try_clone_arc!(ssl);
Expand Down Expand Up @@ -1629,22 +1714,6 @@ macro_rules! entry_stub {
// things we support and should be able to implement to
// some extent:

entry_stub! {
pub fn _SSL_CTX_set_ex_data(_ssl: *mut SSL_CTX, _idx: c_int, _data: *mut c_void) -> c_int;
}

entry_stub! {
pub fn _SSL_CTX_get_ex_data(_ssl: *const SSL_CTX, _idx: c_int) -> *mut c_void;
}

entry_stub! {
pub fn _SSL_set_ex_data(_ssl: *mut SSL, _idx: c_int, _data: *mut c_void) -> c_int;
}

entry_stub! {
pub fn _SSL_get_ex_data(_ssl: *const SSL, _idx: c_int) -> *mut c_void;
}

entry_stub! {
pub fn _SSL_get_ex_data_X509_STORE_CTX_idx() -> c_int;
}
Expand Down
110 changes: 110 additions & 0 deletions rustls-libssl/src/ex_data.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
use core::ffi::{c_int, c_void};
use core::ptr;

use crate::entry::{SSL, SSL_CTX};
use crate::error::Error;

/// Safe(ish), owning wrapper around an OpenSSL `CRYPTO_EX_DATA`.
///
/// `ty` and `owner` allow us to drop this object with no extra context.
///
/// Because this refers to the object that contains it, a two-step
/// construction is needed.
pub struct ExData {
ex_data: CRYPTO_EX_DATA,
ty: c_int,
owner: *mut c_void,
}

impl ExData {
/// Makes a new CRYPTO_EX_DATA for an SSL object.
pub fn new_ssl(ssl: *mut SSL) -> Option<Self> {
let mut ex_data = CRYPTO_EX_DATA::default();
let owner = ssl as *mut c_void;
let ty = CRYPTO_EX_INDEX_SSL;
let rc = unsafe { CRYPTO_new_ex_data(ty, owner, &mut ex_data) };
if rc == 1 {
Some(Self { ex_data, ty, owner })
} else {
None
}
}

/// Makes a new CRYPTO_EX_DATA for an SSL_CTX object.
pub fn new_ssl_ctx(ctx: *mut SSL_CTX) -> Option<Self> {
let mut ex_data = CRYPTO_EX_DATA::default();
let owner = ctx as *mut c_void;
let ty = CRYPTO_EX_INDEX_SSL_CTX;
let rc = unsafe { CRYPTO_new_ex_data(ty, owner, &mut ex_data) };
if rc == 1 {
Some(Self { ex_data, ty, owner })
} else {
None
}
}

pub fn set(&mut self, idx: c_int, data: *mut c_void) -> Result<(), Error> {
let rc = unsafe { CRYPTO_set_ex_data(&mut self.ex_data, idx, data) };
if rc == 1 {
Ok(())
} else {
Err(Error::bad_data("CRYPTO_set_ex_data"))
}
}

pub fn get(&self, idx: c_int) -> *mut c_void {
unsafe { CRYPTO_get_ex_data(&self.ex_data, idx) }
}
}

impl Drop for ExData {
fn drop(&mut self) {
if !self.owner.is_null() {
unsafe {
CRYPTO_free_ex_data(self.ty, self.owner, &mut self.ex_data);
};
self.owner = ptr::null_mut();
}
}
}

impl Default for ExData {
fn default() -> Self {
Self {
ex_data: CRYPTO_EX_DATA::default(),
ty: -1,
owner: ptr::null_mut(),
}
}
}

/// This has the same layout prefix as `struct crypto_ex_data_st` aka
/// `CRYPTO_EX_DATA` -- just two pointers. We don't need to know
/// the types of these; the API lets us treat them opaquely.
///
/// This is _not_ owning.
#[repr(C)]
struct CRYPTO_EX_DATA {
ctx: *mut c_void,
sk: *mut c_void,
}

impl Default for CRYPTO_EX_DATA {
fn default() -> Self {
Self {
ctx: ptr::null_mut(),
sk: ptr::null_mut(),
}
}
}

// See `crypto.h`
const CRYPTO_EX_INDEX_SSL: c_int = 0;
const CRYPTO_EX_INDEX_SSL_CTX: c_int = 1;

extern "C" {
fn CRYPTO_new_ex_data(class_index: c_int, obj: *mut c_void, ed: *mut CRYPTO_EX_DATA) -> c_int;
fn CRYPTO_set_ex_data(ed: *mut CRYPTO_EX_DATA, index: c_int, data: *mut c_void) -> c_int;
fn CRYPTO_get_ex_data(ed: *const CRYPTO_EX_DATA, index: c_int) -> *mut c_void;
fn CRYPTO_free_ex_data(class_index: c_int, obj: *mut c_void, ed: *mut CRYPTO_EX_DATA);
}
29 changes: 29 additions & 0 deletions rustls-libssl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ mod constants;
mod entry;
mod error;
mod evp_pkey;
mod ex_data;
#[macro_use]
#[allow(unused_macros, dead_code, unused_imports)]
mod ffi;
Expand Down Expand Up @@ -211,6 +212,7 @@ static TLS13_CHACHA20_POLY1305_SHA256: SslCipher = SslCipher {

pub struct SslContext {
method: &'static SslMethod,
ex_data: ex_data::ExData,
raw_options: u64,
verify_mode: VerifyMode,
verify_depth: c_int,
Expand All @@ -230,6 +232,7 @@ impl SslContext {
fn new(method: &'static SslMethod) -> Self {
Self {
method,
ex_data: ex_data::ExData::default(),
raw_options: 0,
verify_mode: VerifyMode::default(),
verify_depth: -1,
Expand All @@ -246,6 +249,18 @@ impl SslContext {
}
}

fn install_ex_data(&mut self, ex_data: ex_data::ExData) {
self.ex_data = ex_data;
}

fn set_ex_data(&mut self, idx: c_int, data: *mut c_void) -> Result<(), error::Error> {
self.ex_data.set(idx, data)
}

fn get_ex_data(&mut self, idx: c_int) -> *mut c_void {
self.ex_data.get(idx)
}

fn get_options(&self) -> u64 {
self.raw_options
}
Expand Down Expand Up @@ -417,6 +432,7 @@ fn encode_alpn<'a>(iter: impl Iterator<Item = &'a [u8]>) -> Vec<u8> {

struct Ssl {
ctx: Arc<Mutex<SslContext>>,
ex_data: ex_data::ExData,
raw_options: u64,
mode: ConnMode,
verify_mode: VerifyMode,
Expand Down Expand Up @@ -451,6 +467,7 @@ impl Ssl {
fn new(ctx: Arc<Mutex<SslContext>>, inner: &SslContext) -> Result<Self, error::Error> {
Ok(Self {
ctx,
ex_data: ex_data::ExData::default(),
raw_options: inner.raw_options,
mode: inner.method.mode(),
verify_mode: inner.verify_mode,
Expand All @@ -473,6 +490,18 @@ impl Ssl {
})
}

fn install_ex_data(&mut self, ex_data: ex_data::ExData) {
self.ex_data = ex_data;
}

fn set_ex_data(&mut self, idx: c_int, data: *mut c_void) -> Result<(), error::Error> {
self.ex_data.set(idx, data)
}

fn get_ex_data(&mut self, idx: c_int) -> *mut c_void {
self.ex_data.get(idx)
}

fn set_ctx(&mut self, ctx: Arc<Mutex<SslContext>>) {
// there are no docs for `SSL_set_SSL_CTX`. it seems the only
// meaningful reason to use this is key/certificate switching
Expand Down
Loading

0 comments on commit 0a6f130

Please sign in to comment.