Skip to content

Commit

Permalink
Implement SSL_set0_chain, SSL_set1_chain & SSL_clear_chain_certs
Browse files Browse the repository at this point in the history
  • Loading branch information
ctz committed Apr 9, 2024
1 parent 0a6f130 commit fcf69a5
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 32 deletions.
94 changes: 65 additions & 29 deletions rustls-libssl/src/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use crate::ffi::{
try_mut_slice_int, try_ref_from_ptr, try_slice, try_slice_int, try_str, Castable, OwnershipArc,
OwnershipRef,
};
use crate::x509::{load_certs, OwnedX509};
use crate::x509::{load_certs, OwnedX509, OwnedX509Stack};
use crate::ShutdownResult;

/// Makes a entry function definition.
Expand Down Expand Up @@ -230,6 +230,23 @@ entry! {
inner.set_servername_callback_context(parg);
C_INT_SUCCESS as c_long
}
Ok(SslCtrl::SetChain) => {
let chain = if parg.is_null() {
// this is `SSL_CTX_clear_chain_certs`
vec![]
} else {
match larg {
// this is `SSL_CTX_set1_chain` (incs ref)
1 => OwnedX509Stack::new_copy(parg as *mut stack_st_X509).to_rustls(),
// this is `SSL_CTX_set0_chain` (retain ref)
_ => OwnedX509Stack::new(parg as *mut stack_st_X509).to_rustls(),
}
};

inner.stage_certificate_chain(chain);
C_INT_SUCCESS as i64
}

Err(()) => {
log::warn!("unimplemented _SSL_CTX_ctrl(..., {cmd}, {larg}, ...)");
0
Expand Down Expand Up @@ -499,12 +516,12 @@ entry! {
return Error::null_pointer().raise().into();
}

let chain = vec![CertificateDer::from(OwnedX509::new(x).der_bytes())];
let ee = CertificateDer::from(OwnedX509::new(x).der_bytes());

match ctx
.lock()
.map_err(|_| Error::cannot_lock())
.map(|mut ctx| ctx.stage_certificate_chain(chain))
.map(|mut ctx| ctx.stage_certificate_end(ee))
{
Err(e) => e.raise().into(),
Ok(()) => C_INT_SUCCESS,
Expand Down Expand Up @@ -802,33 +819,51 @@ 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);

match SslCtrl::try_from(cmd) {
Ok(SslCtrl::Mode) => {
log::warn!("unimplemented SSL_set_mode()");
0
}
Ok(SslCtrl::SetMsgCallbackArg) => {
log::warn!("unimplemented SSL_set_msg_callback_arg()");
0
}
Ok(SslCtrl::SetMaxProtoVersion) => {
log::warn!("unimplemented SSL_set_max_proto_version()");
1
}
Ok(SslCtrl::SetTlsExtHostname) => {
let hostname = try_str!(parg as *const c_char);
ssl.lock()
.ok()
.map(|mut ssl| ssl.set_sni_hostname(hostname))
.unwrap_or_default() as c_long
}
// not a defined operation in the OpenSSL API
Ok(SslCtrl::SetTlsExtServerNameCallback) | Ok(SslCtrl::SetTlsExtServerNameArg) => 0,
Err(()) => {
log::warn!("unimplemented _SSL_ctrl(..., {cmd}, {larg}, ...)");
0
let result = if let Ok(mut inner) = ssl.lock() {
match SslCtrl::try_from(cmd) {
Ok(SslCtrl::Mode) => {
log::warn!("unimplemented SSL_set_mode()");
0
}
Ok(SslCtrl::SetMsgCallbackArg) => {
log::warn!("unimplemented SSL_set_msg_callback_arg()");
0
}
Ok(SslCtrl::SetMaxProtoVersion) => {
log::warn!("unimplemented SSL_set_max_proto_version()");
1
}
Ok(SslCtrl::SetTlsExtHostname) => {
let hostname = try_str!(parg as *const c_char);
inner.set_sni_hostname(hostname) as c_long
}
Ok(SslCtrl::SetChain) => {
let chain = if parg.is_null() {
// this is `SSL_clear_chain_certs`
vec![]
} else {
match larg {
// this is `SSL_set1_chain` (incs ref)
1 => OwnedX509Stack::new_copy(parg as *mut stack_st_X509).to_rustls(),
// this is `SSL_set0_chain` (retain ref)
_ => OwnedX509Stack::new(parg as *mut stack_st_X509).to_rustls(),
}
};

inner.stage_certificate_chain(chain);
C_INT_SUCCESS as i64
}
// not a defined operation in the OpenSSL API
Ok(SslCtrl::SetTlsExtServerNameCallback) | Ok(SslCtrl::SetTlsExtServerNameArg) => 0,
Err(()) => {
log::warn!("unimplemented _SSL_ctrl(..., {cmd}, {larg}, ...)");
0
}
}
}
} else {
0
};
result
}
}

Expand Down Expand Up @@ -1686,6 +1721,7 @@ num_enum! {
SetTlsExtServerNameCallback = 53,
SetTlsExtServerNameArg = 54,
SetTlsExtHostname = 55,
SetChain = 88,
SetMaxProtoVersion = 124,
}
}
Expand Down
4 changes: 4 additions & 0 deletions rustls-libssl/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,10 @@ impl SslContext {
self.cert_callback = callbacks::CertCallbackConfig { cb, context };
}

fn stage_certificate_end(&mut self, end: CertificateDer<'static>) {
self.auth_keys.stage_certificate_end(end)
}

fn stage_certificate_chain(&mut self, chain: Vec<CertificateDer<'static>>) {
self.auth_keys.stage_certificate_chain(chain)
}
Expand Down
19 changes: 16 additions & 3 deletions rustls-libssl/src/sign.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ pub struct CertifiedKeySet {
/// `SSL_CTX_use_PrivateKey_file`.
pending_cert_chain: Option<Vec<CertificateDer<'static>>>,

/// Last `SSL_CTX_use_certificate` result, prepended to chain during commit.
/// May be absent.
pending_cert_end: Option<CertificateDer<'static>>,

/// The key and certificate we're currently using.
///
/// TODO: support multiple key types, and demultiplex them by type.
Expand All @@ -34,10 +38,19 @@ impl CertifiedKeySet {
self.pending_cert_chain = Some(chain);
}

pub fn stage_certificate_end(&mut self, end: CertificateDer<'static>) {
self.pending_cert_end = Some(end);
}

pub fn commit_private_key(&mut self, key: EvpPkey) -> Result<(), error::Error> {
let chain = match self.pending_cert_chain.take() {
Some(chain) => chain,
None => {
let chain = match (self.pending_cert_end.take(), self.pending_cert_chain.take()) {
(Some(end), Some(mut chain)) => {
chain.insert(0, end);
chain
}
(None, Some(chain)) => chain,
(Some(end), None) => vec![end],
(None, None) => {
return Err(error::Error::bad_data("no certificate found for key"));
}
};
Expand Down
29 changes: 29 additions & 0 deletions rustls-libssl/src/x509.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,35 @@ impl OwnedX509Stack {
}
}

/// Make one by adopting ownership of an existing pointer.
pub fn new(raw: *mut stack_st_X509) -> Self {
Self { raw }
}

/// Make one by copying existing stack.
pub fn new_copy(other: *const stack_st_X509) -> Self {
let mut ret = Self::empty();

let len = match unsafe { OPENSSL_sk_num(other as *const OPENSSL_STACK) } {
-1 => 0,
x => x as usize,
};

for index in 0..len {
let item_ptr = unsafe {
OPENSSL_sk_value(other as *const OPENSSL_STACK, index as c_int) as *mut X509
};
// item_ptr belongs to caller.
let item = OwnedX509::new(item_ptr);
// item belongs to `OwnedX509` -- ensure caller's ref is not stolen
item.up_ref();
// `ret` takes its own ref
ret.push(&item);
}

ret
}

pub fn from_rustls(certs: &Vec<CertificateDer<'static>>) -> Self {
let mut r = Self::empty();
for c in certs {
Expand Down

0 comments on commit fcf69a5

Please sign in to comment.