Skip to content

Commit

Permalink
impl SSL_CTX_set_default_verify_paths and friends
Browse files Browse the repository at this point in the history
Adds:

* SSL_CTX_set_default_verify_paths
* SSL_CTX_set_default_verify_dir
* SSL_CTX_set_default_verify_file

Stubs:

* SSL_CTX_set_default_verify_store

We take a dep on `openssl-probe` in order to get convenient handling of
the `SSL_CERT_DIR` and `SSL_CERT_FILE` env vars, and default locations
for the verify paths.

There is likely some fine-tuning to do (e.g. with respect to the
`X509_LOOKUP` API surface), but is a step in the right direction for the
simple cases.
  • Loading branch information
cpu committed Apr 3, 2024
1 parent 33fffd7 commit e122674
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 1 deletion.
7 changes: 7 additions & 0 deletions rustls-libssl/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions rustls-libssl/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ crate-type = ["cdylib"]
[dependencies]
env_logger = "0.10"
log = "0.4"
openssl-probe = "0.1"
openssl-sys = "0.9.98"
rustls = "0.22"
rustls-pemfile = "2"
4 changes: 4 additions & 0 deletions rustls-libssl/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ const ENTRYPOINTS: &[&str] = &[
"SSL_CTX_get_cert_store",
"SSL_CTX_get_ex_data",
"SSL_CTX_get_options",
"SSL_CTX_set_default_verify_paths",
"SSL_CTX_set_default_verify_dir",
"SSL_CTX_set_default_verify_file",
"SSL_CTX_set_default_verify_store",
"SSL_CTX_load_verify_dir",
"SSL_CTX_load_verify_file",
"SSL_CTX_new",
Expand Down
47 changes: 47 additions & 0 deletions rustls-libssl/src/entry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,48 @@ fn load_verify_files(ctx: &Mutex<SSL_CTX>, file_names: impl Iterator<Item = Path
}
}

entry! {
pub fn _SSL_CTX_set_default_verify_paths(ctx: *mut SSL_CTX) -> c_int {
let ctx = try_clone_arc!(ctx);
match ctx
.lock()
.map_err(|_| Error::cannot_lock())
.map(|mut ctx| ctx.set_default_verify_paths())
{
Err(e) => e.raise().into(),
Ok(()) => C_INT_SUCCESS,
}
}
}

entry! {
pub fn _SSL_CTX_set_default_verify_dir(ctx: *mut SSL_CTX) -> c_int {
let ctx = try_clone_arc!(ctx);
match ctx
.lock()
.map_err(|_| Error::cannot_lock())
.map(|mut ctx| ctx.set_default_verify_dir())
{
Err(e) => e.raise().into(),
Ok(()) => C_INT_SUCCESS,
}
}
}

entry! {
pub fn _SSL_CTX_set_default_verify_file(ctx: *mut SSL_CTX) -> c_int {
let ctx = try_clone_arc!(ctx);
match ctx
.lock()
.map_err(|_| Error::cannot_lock())
.map(|mut ctx| ctx.set_default_verify_file())
{
Err(e) => e.raise().into(),
Ok(()) => C_INT_SUCCESS,
}
}
}

entry! {
pub fn _SSL_CTX_load_verify_file(ctx: *mut SSL_CTX, ca_file: *const c_char) -> c_int {
let ctx = try_clone_arc!(ctx);
Expand Down Expand Up @@ -1007,6 +1049,11 @@ entry_stub! {
) -> c_int;
}

// The SSL_CTX X509_STORE isn't being meaningfully used yet.
entry_stub! {
pub fn _SSL_CTX_set_default_verify_store(_ctx: *mut SSL_CTX) -> c_int;
}

pub struct SSL_SESSION;

entry_stub! {
Expand Down
56 changes: 55 additions & 1 deletion rustls-libssl/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
use core::ffi::{c_int, CStr};
use std::fs;
use std::io::{ErrorKind, Read, Write};
use std::path::PathBuf;
use std::sync::{Arc, Mutex};

use openssl_probe::ProbeResult;
use openssl_sys::{
SSL_ERROR_NONE, SSL_ERROR_SSL, SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE, X509_STORE,
X509_V_ERR_UNSPECIFIED,
Expand Down Expand Up @@ -205,6 +208,8 @@ pub struct SslContext {
verify_roots: RootCertStore,
verify_x509_store: x509::OwnedX509Store,
alpn: Vec<Vec<u8>>,
default_cert_file: Option<PathBuf>,
default_cert_dir: Option<PathBuf>,
}

impl SslContext {
Expand All @@ -216,6 +221,8 @@ impl SslContext {
verify_roots: RootCertStore::empty(),
verify_x509_store: x509::OwnedX509Store::new(),
alpn: vec![],
default_cert_file: None,
default_cert_dir: None,
}
}

Expand All @@ -237,6 +244,25 @@ impl SslContext {
self.verify_mode = mode;
}

fn set_default_verify_paths(&mut self) {
let ProbeResult {
cert_file,
cert_dir,
} = openssl_probe::probe();
self.default_cert_file = cert_file;
self.default_cert_dir = cert_dir;
}

fn set_default_verify_dir(&mut self) {
let ProbeResult { cert_dir, .. } = openssl_probe::probe();
self.default_cert_dir = cert_dir;
}

fn set_default_verify_file(&mut self) {
let ProbeResult { cert_file, .. } = openssl_probe::probe();
self.default_cert_file = cert_file;
}

fn add_trusted_certs(
&mut self,
certs: Vec<CertificateDer<'static>>,
Expand Down Expand Up @@ -303,7 +329,7 @@ impl Ssl {
raw_options: inner.raw_options,
mode: inner.method.mode(),
verify_mode: inner.verify_mode,
verify_roots: inner.verify_roots.clone(),
verify_roots: Self::load_verify_certs(inner)?,
verify_server_name: None,
alpn: inner.alpn.clone(),
sni_server_name: None,
Expand Down Expand Up @@ -633,6 +659,34 @@ impl Ssl {
None => SSL_ERROR_SSL,
}
}

fn load_verify_certs(ctx: &SslContext) -> Result<RootCertStore, error::Error> {
let mut verify_roots = ctx.verify_roots.clone();

// If verify_roots isn't empty then it was configured with `SSL_CTX_load_verify_file`
// or `SSL_CTX_load_verify_dir` and we should use it as-is.
if !ctx.verify_roots.is_empty() {
return Ok(verify_roots);
}

// Otherwise, try to load the default cert file or cert dir.
if let Some(default_cert_file) = &ctx.default_cert_file {
verify_roots.add_parsable_certificates(x509::load_certs(
vec![default_cert_file.to_path_buf()].into_iter(),
)?);
} else if let Some(default_cert_dir) = &ctx.default_cert_dir {
let entries = match fs::read_dir(default_cert_dir) {
Ok(iter) => iter,
Err(err) => return Err(error::Error::from_io(err).raise()),
}
.filter_map(|entry| entry.ok())
.map(|dir_entry| dir_entry.path());

verify_roots.add_parsable_certificates(x509::load_certs(entries)?);
}

Ok(verify_roots)
}
}

#[derive(Default)]
Expand Down

0 comments on commit e122674

Please sign in to comment.