Skip to content

Commit ef8e9a3

Browse files
committed
Use X509_STORE for root certificate storage
In {client,server}.c, see that the effects of `SSL_CTX_load_verify_file` can be observed via `SSL_CTX_get_cert_store`
1 parent 6ab5fa4 commit ef8e9a3

File tree

6 files changed

+108
-29
lines changed

6 files changed

+108
-29
lines changed

src/lib.rs

Lines changed: 14 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use rustls::pki_types::{CertificateDer, ServerName};
1717
use rustls::server::{Accepted, Acceptor, ProducesTickets};
1818
use rustls::{
1919
CipherSuite, ClientConfig, ClientConnection, Connection, HandshakeKind, ProtocolVersion,
20-
RootCertStore, ServerConfig, SignatureScheme, SupportedProtocolVersion,
20+
ServerConfig, SignatureScheme, SupportedProtocolVersion,
2121
};
2222

2323
use not_thread_safe::NotThreadSafe;
@@ -416,7 +416,6 @@ pub struct SslContext {
416416
raw_options: u64,
417417
verify_mode: VerifyMode,
418418
verify_depth: c_int,
419-
verify_roots: RootCertStore,
420419
verify_x509_store: x509::OwnedX509Store,
421420
alpn: Vec<Vec<u8>>,
422421
default_cert_file: Option<PathBuf>,
@@ -447,7 +446,6 @@ impl SslContext {
447446
raw_options: 0,
448447
verify_mode: VerifyMode::default(),
449448
verify_depth: -1,
450-
verify_roots: RootCertStore::empty(),
451449
verify_x509_store: OwnedX509Store::default(),
452450
alpn: vec![],
453451
default_cert_file: None,
@@ -624,12 +622,7 @@ impl SslContext {
624622
&mut self,
625623
certs: Vec<CertificateDer<'static>>,
626624
) -> Result<(), error::Error> {
627-
for c in certs {
628-
self.verify_roots
629-
.add(c)
630-
.map_err(error::Error::from_rustls)?;
631-
}
632-
Ok(())
625+
self.verify_x509_store.add(certs)
633626
}
634627

635628
fn get_x509_store(&self) -> *mut X509_STORE {
@@ -735,8 +728,8 @@ struct Ssl {
735728
mode: ConnMode,
736729
verify_mode: VerifyMode,
737730
verify_depth: c_int,
738-
verify_roots: RootCertStore,
739731
verify_server_name: Option<ServerName<'static>>,
732+
verify_x509_store: x509::OwnedX509Store,
740733
alpn: Vec<Vec<u8>>,
741734
alpn_callback: callbacks::AlpnCallbackConfig,
742735
cert_callback: callbacks::CertCallbackConfig,
@@ -776,8 +769,8 @@ impl Ssl {
776769
mode: inner.method.mode(),
777770
verify_mode: inner.verify_mode,
778771
verify_depth: inner.verify_depth,
779-
verify_roots: Self::load_verify_certs(inner)?,
780772
verify_server_name: None,
773+
verify_x509_store: Self::load_verify_certs(inner)?,
781774
alpn: inner.alpn.clone(),
782775
alpn_callback: inner.alpn_callback.clone(),
783776
cert_callback: inner.cert_callback.clone(),
@@ -1027,7 +1020,7 @@ impl Ssl {
10271020

10281021
let provider = Arc::new(provider::default_provider());
10291022
let verifier = Arc::new(verifier::ServerVerifier::new(
1030-
self.verify_roots.clone().into(),
1023+
self.verify_x509_store.clone(),
10311024
provider.clone(),
10321025
self.verify_mode,
10331026
&self.verify_server_name,
@@ -1112,7 +1105,7 @@ impl Ssl {
11121105
let provider = Arc::new(provider::default_provider());
11131106
let verifier = Arc::new(
11141107
verifier::ClientVerifier::new(
1115-
self.verify_roots.clone().into(),
1108+
&self.verify_x509_store,
11161109
provider.clone(),
11171110
self.verify_mode,
11181111
)
@@ -1435,20 +1428,20 @@ impl Ssl {
14351428
}
14361429
}
14371430

1438-
fn load_verify_certs(ctx: &SslContext) -> Result<RootCertStore, error::Error> {
1439-
let mut verify_roots = ctx.verify_roots.clone();
1440-
1431+
fn load_verify_certs(ctx: &SslContext) -> Result<x509::OwnedX509Store, error::Error> {
14411432
// If verify_roots isn't empty then it was configured with `SSL_CTX_load_verify_file`
14421433
// or `SSL_CTX_load_verify_dir` and we should use it as-is.
1443-
if !ctx.verify_roots.is_empty() {
1444-
return Ok(verify_roots);
1434+
if !ctx.verify_x509_store.is_empty() {
1435+
return Ok(ctx.verify_x509_store.clone());
14451436
}
14461437

14471438
// Otherwise, try to load the default cert file or cert dir.
1439+
let mut verify_roots = x509::OwnedX509Store::default();
1440+
14481441
if let Some(default_cert_file) = &ctx.default_cert_file {
1449-
verify_roots.add_parsable_certificates(x509::load_certs(
1442+
verify_roots.add(x509::load_certs(
14501443
vec![default_cert_file.to_path_buf()].into_iter(),
1451-
)?);
1444+
)?)?;
14521445
} else if let Some(default_cert_dir) = &ctx.default_cert_dir {
14531446
let entries = match fs::read_dir(default_cert_dir) {
14541447
Ok(iter) => iter,
@@ -1457,7 +1450,7 @@ impl Ssl {
14571450
.filter_map(|entry| entry.ok())
14581451
.map(|dir_entry| dir_entry.path());
14591452

1460-
verify_roots.add_parsable_certificates(x509::load_certs(entries)?);
1453+
verify_roots.add(x509::load_certs(entries)?)?;
14611454
}
14621455

14631456
Ok(verify_roots)

src/miri.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,16 @@ pub extern "C" fn X509_STORE_new() -> *mut X509_STORE {
99
Box::into_raw(Box::new(X509_STORE(())))
1010
}
1111

12+
#[no_mangle]
13+
pub extern "C" fn X509_STORE_get0_objects(s: *mut X509_STORE) -> *mut c_void {
14+
ptr::null_mut()
15+
}
16+
17+
#[no_mangle]
18+
pub extern "C" fn OPENSSL_sk_num(sk: *mut c_void) -> c_int {
19+
0
20+
}
21+
1222
#[no_mangle]
1323
pub extern "C" fn X509_STORE_free(ptr: *mut X509_STORE) {
1424
if ptr.is_null() {

src/verifier.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ use rustls::{
1616
pki_types::{CertificateDer, ServerName, UnixTime},
1717
server::danger::{ClientCertVerified, ClientCertVerifier},
1818
server::{ParsedCertificate, WebPkiClientVerifier},
19-
CertificateError, DigitallySignedStruct, DistinguishedName, Error, RootCertStore,
20-
SignatureScheme,
19+
CertificateError, DigitallySignedStruct, DistinguishedName, Error, SignatureScheme,
2120
};
2221

22+
use crate::x509::OwnedX509Store;
2323
use crate::VerifyMode;
2424

2525
/// This is a verifier that implements the selection of bad ideas from OpenSSL:
@@ -29,7 +29,7 @@ use crate::VerifyMode;
2929
/// - that the behaviour defaults to verifying nothing
3030
#[derive(Debug)]
3131
pub struct ServerVerifier {
32-
root_store: Arc<RootCertStore>,
32+
x509_store: OwnedX509Store,
3333

3434
provider: Arc<CryptoProvider>,
3535

@@ -47,13 +47,13 @@ pub struct ServerVerifier {
4747

4848
impl ServerVerifier {
4949
pub fn new(
50-
root_store: Arc<RootCertStore>,
50+
x509_store: OwnedX509Store,
5151
provider: Arc<CryptoProvider>,
5252
mode: VerifyMode,
5353
hostname: &Option<ServerName<'static>>,
5454
) -> Self {
5555
Self {
56-
root_store,
56+
x509_store,
5757
provider,
5858
verify_hostname: hostname.clone(),
5959
mode,
@@ -81,10 +81,11 @@ impl ServerVerifier {
8181
now: UnixTime,
8282
) -> Result<(), Error> {
8383
let end_entity = ParsedCertificate::try_from(end_entity)?;
84+
let root_store = self.x509_store.root_store()?;
8485

8586
verify_server_cert_signed_by_trust_anchor(
8687
&end_entity,
87-
&self.root_store,
88+
&root_store,
8889
intermediates,
8990
now,
9091
self.provider.signature_verification_algorithms.all,
@@ -173,10 +174,12 @@ pub struct ClientVerifier {
173174

174175
impl ClientVerifier {
175176
pub fn new(
176-
root_store: Arc<RootCertStore>,
177+
x509_store: &OwnedX509Store,
177178
provider: Arc<CryptoProvider>,
178179
mode: VerifyMode,
179180
) -> Result<Self, Error> {
181+
let root_store = x509_store.root_store()?;
182+
180183
let (parent, initial_result) = if !mode.server_must_attempt_client_auth() {
181184
(Ok(WebPkiClientVerifier::no_client_auth()), X509_V_OK)
182185
} else {

src/x509.rs

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
use core::ffi::{c_int, c_long, c_void};
22
use core::{ptr, slice};
33
use std::path::PathBuf;
4+
use std::sync::Arc;
45
use std::{fs, io};
56

67
use openssl_sys::{
78
d2i_X509, i2d_X509, stack_st_X509, OPENSSL_free, OPENSSL_sk_new_null, OPENSSL_sk_num,
8-
OPENSSL_sk_push, OPENSSL_sk_value, X509_STORE_free, X509_STORE_new, X509_free, OPENSSL_STACK,
9+
OPENSSL_sk_push, OPENSSL_sk_value, X509_STORE_add_cert, X509_STORE_free,
10+
X509_STORE_get0_objects, X509_STORE_get1_all_certs, X509_STORE_new, X509_free, OPENSSL_STACK,
911
X509, X509_STORE,
1012
};
1113
use rustls::pki_types::pem::PemObject;
1214
use rustls::pki_types::CertificateDer;
15+
use rustls::RootCertStore;
1316

1417
use crate::error::Error;
1518

@@ -233,6 +236,7 @@ impl Drop for OwnedX509 {
233236
}
234237
}
235238

239+
#[derive(Debug)]
236240
pub struct OwnedX509Store {
237241
raw: *mut X509_STORE,
238242
}
@@ -246,6 +250,54 @@ impl OwnedX509Store {
246250
pub fn pointer(&self) -> *mut X509_STORE {
247251
self.raw
248252
}
253+
254+
pub fn len(&self) -> usize {
255+
match unsafe { OPENSSL_sk_num(X509_STORE_get0_objects(self.raw) as *const OPENSSL_STACK) } {
256+
-1 | 0 => 0,
257+
i => i as usize,
258+
}
259+
}
260+
261+
pub fn is_empty(&self) -> bool {
262+
self.len() == 0
263+
}
264+
265+
pub fn add(
266+
&mut self,
267+
cert_ders: impl IntoIterator<Item = CertificateDer<'static>>,
268+
) -> Result<(), Error> {
269+
for cert_der in cert_ders {
270+
let item = OwnedX509::parse_der(cert_der.as_ref())
271+
.ok_or_else(|| Error::bad_data("cannot parse certificate"))?;
272+
match unsafe { X509_STORE_add_cert(self.raw, item.borrow_ref()) } {
273+
1 => {}
274+
_ => {
275+
return Err(Error::bad_data("cannot X509_STORE_add_cert"));
276+
}
277+
}
278+
}
279+
280+
Ok(())
281+
}
282+
283+
pub fn root_store(&self) -> Result<Arc<RootCertStore>, rustls::Error> {
284+
let ptr = unsafe { X509_STORE_get1_all_certs(self.raw) };
285+
286+
if ptr.is_null() {
287+
return Err(rustls::Error::General(
288+
"cannot retrieve trusted certs".to_string(),
289+
));
290+
}
291+
292+
let certs = OwnedX509Stack::new(ptr);
293+
let mut ret = RootCertStore::empty();
294+
295+
for i in 0..certs.len() {
296+
ret.add(certs.item(i).der_bytes().into())?;
297+
}
298+
299+
Ok(ret.into())
300+
}
249301
}
250302

251303
impl Default for OwnedX509Store {
@@ -256,6 +308,15 @@ impl Default for OwnedX509Store {
256308
}
257309
}
258310

311+
impl Clone for OwnedX509Store {
312+
fn clone(&self) -> Self {
313+
unsafe {
314+
X509_STORE_up_ref(self.raw);
315+
}
316+
Self { raw: self.raw }
317+
}
318+
}
319+
259320
impl Drop for OwnedX509Store {
260321
fn drop(&mut self) {
261322
unsafe {
@@ -264,6 +325,9 @@ impl Drop for OwnedX509Store {
264325
}
265326
}
266327

328+
unsafe impl Send for OwnedX509Store {}
329+
unsafe impl Sync for OwnedX509Store {}
330+
267331
pub(crate) fn load_certs<'a>(
268332
file_names: impl Iterator<Item = PathBuf>,
269333
) -> Result<Vec<CertificateDer<'a>>, Error> {
@@ -295,4 +359,5 @@ extern "C" {
295359
);
296360
fn OPENSSL_sk_dup(st: *const OPENSSL_STACK) -> *mut OPENSSL_STACK;
297361
fn X509_up_ref(x: *mut X509) -> c_int;
362+
fn X509_STORE_up_ref(xs: *mut X509_STORE) -> c_int;
298363
}

tests/client.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,12 @@ int main(int argc, char **argv) {
5656
dump_openssl_error_stack();
5757
assert(SSL_CTX_get_verify_mode(ctx) == SSL_VERIFY_PEER);
5858
assert(SSL_CTX_get_verify_callback(ctx) == NULL);
59+
TRACE(sk_X509_OBJECT_num(
60+
X509_STORE_get0_objects(SSL_CTX_get_cert_store(ctx))));
5961
TRACE(SSL_CTX_load_verify_file(ctx, cacert));
6062
dump_openssl_error_stack();
63+
TRACE(sk_X509_OBJECT_num(
64+
X509_STORE_get0_objects(SSL_CTX_get_cert_store(ctx))));
6165
}
6266
printf("SSL_CTX_get_verify_depth default %d\n",
6367
SSL_CTX_get_verify_depth(ctx));

tests/server.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,12 @@ int main(int argc, char **argv) {
128128
if (strcmp(cacert, "unauth") != 0) {
129129
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
130130
dump_openssl_error_stack();
131+
TRACE(sk_X509_OBJECT_num(
132+
X509_STORE_get0_objects(SSL_CTX_get_cert_store(ctx))));
131133
TRACE(SSL_CTX_load_verify_file(ctx, cacert));
132134
dump_openssl_error_stack();
135+
TRACE(sk_X509_OBJECT_num(
136+
X509_STORE_get0_objects(SSL_CTX_get_cert_store(ctx))));
133137
} else {
134138
printf("client auth disabled\n");
135139
}

0 commit comments

Comments
 (0)