Skip to content

Commit

Permalink
Implement certificate, ALPN & error accessor functions
Browse files Browse the repository at this point in the history
  • Loading branch information
ctz committed Mar 26, 2024
1 parent 3032b3d commit 5eb6dd3
Show file tree
Hide file tree
Showing 3 changed files with 218 additions and 3 deletions.
9 changes: 9 additions & 0 deletions rustls-libssl/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,17 @@ const ENTRYPOINTS: &[&str] = &[
"SSL_CTX_set_verify",
"SSL_CTX_up_ref",
"SSL_free",
"SSL_get0_alpn_selected",
"SSL_get0_peer_certificate",
"SSL_get0_verified_chain",
"SSL_get1_peer_certificate",
"SSL_get_current_cipher",
"SSL_get_error",
"SSL_get_options",
"SSL_get_peer_cert_chain",
"SSL_get_shutdown",
"SSL_get_verify_result",
"SSL_get_version",
"SSL_has_pending",
"SSL_is_server",
"SSL_new",
Expand Down
111 changes: 110 additions & 1 deletion rustls-libssl/src/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ use std::os::raw::{c_char, c_int, c_long, c_uchar, c_uint, c_void};
use std::sync::Mutex;
use std::{fs, io, path::PathBuf};

use openssl_sys::{OPENSSL_malloc, X509_STORE, X509_STORE_CTX};
use openssl_sys::{
stack_st_X509, OPENSSL_malloc, X509, X509_STORE, X509_STORE_CTX, X509_V_ERR_UNSPECIFIED,
};

use crate::bio::{Bio, BIO};
use crate::error::{ffi_panic_boundary, Error, MysteriouslyOppositeReturnValue};
Expand Down Expand Up @@ -632,6 +634,113 @@ entry! {
}
}

entry! {
pub fn _SSL_get_error(ssl: *const SSL, _ret_code: c_int) -> c_int {
let ssl = try_clone_arc!(ssl);
ssl.lock()
.map_err(|_| Error::cannot_lock())
.map(|mut ssl| ssl.get_error() as c_int)
.map_err(|err| err.raise())
.unwrap_or_default()
}
}

entry! {
pub fn _SSL_get0_alpn_selected(ssl: *const SSL, data: *mut *const c_uchar, len: *mut c_uint) {
if data.is_null() || len.is_null() {
return;
}

let ssl = try_clone_arc!(ssl);

match ssl.lock().ok().and_then(|mut ssl| {
ssl.get_agreed_alpn().map(|proto| {
unsafe {
// nb. alpn protocols are limited to 255 octets
ptr::write(len, proto.len() as u32);
ptr::write(data, proto.as_ptr());
};
})
}) {
Some(()) => {}
None => unsafe {
ptr::write(len, 0);
ptr::write(data, ptr::null());
},
}
}
}

entry! {
pub fn _SSL_get_peer_cert_chain(ssl: *const SSL) -> *mut stack_st_X509 {
let ssl = try_clone_arc!(ssl);
ssl.lock()
.ok()
.and_then(|mut ssl| ssl.get_peer_cert_chain().map(|x509| x509.pointer()))
.unwrap_or_else(ptr::null_mut)
}
}

entry! {
pub fn _SSL_get0_verified_chain(ssl: *const SSL) -> *mut stack_st_X509 {
_SSL_get_peer_cert_chain(ssl)
}
}

entry! {
pub fn _SSL_get0_peer_certificate(ssl: *const SSL) -> *mut X509 {
let ssl = try_clone_arc!(ssl);
ssl.lock()
.ok()
.and_then(|mut ssl| ssl.get_peer_cert().map(|x509| x509.borrow_ref()))
.unwrap_or_else(ptr::null_mut)
}
}

entry! {
pub fn _SSL_get1_peer_certificate(ssl: *const SSL) -> *mut X509 {
let ssl = try_clone_arc!(ssl);
ssl.lock()
.ok()
.and_then(|mut ssl| ssl.get_peer_cert().map(|x509| x509.up_ref()))
.unwrap_or_else(ptr::null_mut)
}
}

entry! {
pub fn _SSL_get_current_cipher(ssl: *const SSL) -> *const SSL_CIPHER {
let ssl = try_clone_arc!(ssl);
ssl.lock()
.ok()
.and_then(|ssl| ssl.get_negotiated_cipher_suite_id())
.and_then(crate::SslCipher::find_by_id)
.map(|cipher| cipher as *const SSL_CIPHER)
.unwrap_or_else(ptr::null)
}
}

entry! {
pub fn _SSL_get_version(ssl: *const SSL) -> *const c_char {
let ssl = try_clone_arc!(ssl);
ssl.lock()
.ok()
.and_then(|ssl| ssl.get_negotiated_cipher_suite_id())
.and_then(crate::SslCipher::find_by_id)
.map(|cipher| cipher.version.as_ptr())
.unwrap_or_else(ptr::null)
}
}

entry! {
pub fn _SSL_get_verify_result(ssl: *const SSL) -> c_long {
let ssl = try_clone_arc!(ssl);
ssl.lock()
.ok()
.map(|ssl| ssl.get_last_verification_result())
.unwrap_or(X509_V_ERR_UNSPECIFIED as i64)
}
}

impl Castable for SSL {
type Ownership = OwnershipArc;
type RustType = Mutex<SSL>;
Expand Down
101 changes: 99 additions & 2 deletions rustls-libssl/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
use core::ffi::CStr;
use core::ffi::{c_int, CStr};
use std::io::{ErrorKind, Read, Write};
use std::sync::{Arc, Mutex};

use openssl_sys::X509_STORE;
use openssl_sys::{
SSL_ERROR_NONE, SSL_ERROR_SSL, SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE, X509_STORE,
X509_V_ERR_UNSPECIFIED,
};
use rustls::crypto::ring as provider;
use rustls::pki_types::{CertificateDer, ServerName};
use rustls::{CipherSuite, ClientConfig, ClientConnection, Connection, RootCertStore};
Expand Down Expand Up @@ -288,6 +291,8 @@ struct Ssl {
bio: Option<bio::Bio>,
conn: Option<Connection>,
verifier: Option<Arc<verifier::ServerVerifier>>,
peer_cert: Option<x509::OwnedX509>,
peer_cert_chain: Option<x509::OwnedX509Stack>,
shutdown_flags: ShutdownFlags,
}

Expand All @@ -305,6 +310,8 @@ impl Ssl {
bio: None,
conn: None,
verifier: None,
peer_cert: None,
peer_cert_chain: None,
shutdown_flags: ShutdownFlags::default(),
}
}
Expand Down Expand Up @@ -536,6 +543,96 @@ impl Ssl {
})
.unwrap_or_default()
}

fn get_agreed_alpn(&mut self) -> Option<&[u8]> {
self.conn.as_ref().and_then(|conn| conn.alpn_protocol())
}

fn init_peer_cert(&mut self) {
let conn = match &self.conn {
Some(conn) => conn,
None => return,
};

let certs = match conn.peer_certificates() {
Some(certs) => certs,
None => return,
};

let mut stack = x509::OwnedX509Stack::empty();
for (i, cert) in certs.iter().enumerate() {
let converted = match x509::OwnedX509::parse_der(cert.as_ref()) {
Some(converted) => converted,
None => return,
};

if i == 0 {
if !self.is_server() {
// See docs for `SSL_get_peer_cert_chain`:
// "If called on the client side, the stack also contains
// the peer's certificate; if called on the server side, the peer's
// certificate must be obtained separately"
stack.push(&converted);
}
self.peer_cert = Some(converted);
} else {
stack.push(&converted);
}
}

self.peer_cert_chain = Some(stack);
}

fn get_peer_cert(&mut self) -> Option<&x509::OwnedX509> {
if self.peer_cert.is_none() {
self.init_peer_cert();
}
self.peer_cert.as_ref()
}

fn get_peer_cert_chain(&mut self) -> Option<&x509::OwnedX509Stack> {
if self.peer_cert_chain.is_none() {
self.init_peer_cert();
}
self.peer_cert_chain.as_ref()
}

fn get_negotiated_cipher_suite_id(&self) -> Option<CipherSuite> {
self.conn
.as_ref()
.and_then(|conn| conn.negotiated_cipher_suite())
.map(|suite| suite.suite())
}

fn get_last_verification_result(&self) -> i64 {
if let Some(verifier) = &self.verifier {
verifier.last_result()
} else {
X509_V_ERR_UNSPECIFIED as i64
}
}

fn get_error(&mut self) -> c_int {
match &mut self.conn {
Some(ref mut conn) => {
if let Err(e) = conn.process_new_packets() {
error::Error::from_rustls(e).raise();
return SSL_ERROR_SSL;
}

if let Some(bio) = self.bio.as_ref() {
if bio.read_would_block() {
return SSL_ERROR_WANT_READ;
} else if bio.write_would_block() {
return SSL_ERROR_WANT_WRITE;
}
}

SSL_ERROR_NONE
}
None => SSL_ERROR_SSL,
}
}
}

#[derive(Default)]
Expand Down

0 comments on commit 5eb6dd3

Please sign in to comment.