Skip to content

Commit 18bed5f

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 55a2edc commit 18bed5f

6 files changed

Lines changed: 114 additions & 31 deletions

File tree

src/lib.rs

Lines changed: 13 additions & 22 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,18 @@ 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(
1450-
vec![default_cert_file.to_path_buf()].into_iter(),
1451-
)?);
1442+
verify_roots.add_from_files([default_cert_file.to_path_buf()])?;
14521443
} else if let Some(default_cert_dir) = &ctx.default_cert_dir {
14531444
let entries = match fs::read_dir(default_cert_dir) {
14541445
Ok(iter) => iter,
@@ -1457,7 +1448,7 @@ impl Ssl {
14571448
.filter_map(|entry| entry.ok())
14581449
.map(|dir_entry| dir_entry.path());
14591450

1460-
verify_roots.add_parsable_certificates(x509::load_certs(entries)?);
1451+
verify_roots.add_from_files(entries)?;
14611452
}
14621453

14631454
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: 11 additions & 8 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.to_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,14 +174,16 @@ 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.to_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 {
183-
let builder = WebPkiClientVerifier::builder_with_provider(root_store, provider);
186+
let builder = WebPkiClientVerifier::builder_with_provider(root_store.into(), provider);
184187

185188
if mode.server_must_verify_client() {
186189
(builder.build(), X509_V_ERR_UNSPECIFIED)

src/x509.rs

Lines changed: 72 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@ use std::{fs, io};
55

66
use openssl_sys::{
77
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,
8+
OPENSSL_sk_push, OPENSSL_sk_value, X509_STORE_add_cert, X509_STORE_free,
9+
X509_STORE_get0_objects, X509_STORE_get1_all_certs, X509_STORE_new, X509_free, OPENSSL_STACK,
910
X509, X509_STORE,
1011
};
1112
use rustls::pki_types::pem::PemObject;
1213
use rustls::pki_types::CertificateDer;
14+
use rustls::RootCertStore;
1315

1416
use crate::error::Error;
1517

@@ -233,6 +235,7 @@ impl Drop for OwnedX509 {
233235
}
234236
}
235237

238+
#[derive(Debug)]
236239
pub struct OwnedX509Store {
237240
raw: *mut X509_STORE,
238241
}
@@ -243,9 +246,64 @@ impl OwnedX509Store {
243246
Self { raw: store }
244247
}
245248

249+
pub fn add(
250+
&mut self,
251+
cert_ders: impl IntoIterator<Item = CertificateDer<'static>>,
252+
) -> Result<(), Error> {
253+
for cert_der in cert_ders {
254+
let item = OwnedX509::parse_der(cert_der.as_ref())
255+
.ok_or_else(|| Error::bad_data("cannot parse certificate"))?;
256+
match unsafe { X509_STORE_add_cert(self.raw, item.borrow_ref()) } {
257+
1 => {}
258+
_ => {
259+
return Err(Error::bad_data("cannot X509_STORE_add_cert"));
260+
}
261+
}
262+
}
263+
264+
Ok(())
265+
}
266+
267+
pub fn add_from_files(
268+
&mut self,
269+
file_names: impl IntoIterator<Item = PathBuf>,
270+
) -> Result<(), Error> {
271+
self.add(load_certs(file_names.into_iter())?)
272+
}
273+
274+
pub fn to_root_store(&self) -> Result<RootCertStore, rustls::Error> {
275+
let ptr = unsafe { X509_STORE_get1_all_certs(self.raw) };
276+
277+
if ptr.is_null() {
278+
return Err(rustls::Error::General(
279+
"cannot retrieve trusted certs".to_string(),
280+
));
281+
}
282+
283+
let certs = OwnedX509Stack::new(ptr);
284+
let mut ret = RootCertStore::empty();
285+
286+
for i in 0..certs.len() {
287+
ret.add(certs.item(i).der_bytes().into())?;
288+
}
289+
290+
Ok(ret)
291+
}
292+
246293
pub fn pointer(&self) -> *mut X509_STORE {
247294
self.raw
248295
}
296+
297+
pub fn len(&self) -> usize {
298+
match unsafe { OPENSSL_sk_num(X509_STORE_get0_objects(self.raw) as *const OPENSSL_STACK) } {
299+
-1 | 0 => 0,
300+
i => i as usize,
301+
}
302+
}
303+
304+
pub fn is_empty(&self) -> bool {
305+
self.len() == 0
306+
}
249307
}
250308

251309
impl Default for OwnedX509Store {
@@ -256,6 +314,15 @@ impl Default for OwnedX509Store {
256314
}
257315
}
258316

317+
impl Clone for OwnedX509Store {
318+
fn clone(&self) -> Self {
319+
unsafe {
320+
X509_STORE_up_ref(self.raw);
321+
}
322+
Self { raw: self.raw }
323+
}
324+
}
325+
259326
impl Drop for OwnedX509Store {
260327
fn drop(&mut self) {
261328
unsafe {
@@ -264,6 +331,9 @@ impl Drop for OwnedX509Store {
264331
}
265332
}
266333

334+
unsafe impl Send for OwnedX509Store {}
335+
unsafe impl Sync for OwnedX509Store {}
336+
267337
pub(crate) fn load_certs<'a>(
268338
file_names: impl Iterator<Item = PathBuf>,
269339
) -> Result<Vec<CertificateDer<'a>>, Error> {
@@ -295,4 +365,5 @@ extern "C" {
295365
);
296366
fn OPENSSL_sk_dup(st: *const OPENSSL_STACK) -> *mut OPENSSL_STACK;
297367
fn X509_up_ref(x: *mut X509) -> c_int;
368+
fn X509_STORE_up_ref(xs: *mut X509_STORE) -> c_int;
298369
}

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
@@ -130,8 +130,12 @@ int main(int argc, char **argv) {
130130
if (strcmp(cacert, "unauth") != 0) {
131131
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
132132
dump_openssl_error_stack();
133+
TRACE(sk_X509_OBJECT_num(
134+
X509_STORE_get0_objects(SSL_CTX_get_cert_store(ctx))));
133135
TRACE(SSL_CTX_load_verify_file(ctx, cacert));
134136
dump_openssl_error_stack();
137+
TRACE(sk_X509_OBJECT_num(
138+
X509_STORE_get0_objects(SSL_CTX_get_cert_store(ctx))));
135139
} else {
136140
printf("client auth disabled\n");
137141
}

0 commit comments

Comments
 (0)