Skip to content

Commit

Permalink
builder for root_cert_store
Browse files Browse the repository at this point in the history
  • Loading branch information
cpu committed Oct 3, 2023
1 parent df26cf9 commit ce31cd5
Show file tree
Hide file tree
Showing 3 changed files with 144 additions and 33 deletions.
111 changes: 92 additions & 19 deletions src/cipher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -430,35 +430,47 @@ impl rustls_certified_key {
}
}

/// A root certificate store.
/// <https://docs.rs/rustls/latest/rustls/struct.RootCertStore.html>
pub struct rustls_root_cert_store {
/// A `rustls_root_cert_store` being constructed. A builder can be modified by,
/// adding trust anchor root certificates with `rustls_root_cert_store_builder_add_pem`.
/// Once you're done adding root certificates, call `rustls_root_cert_store_builder_build`
/// to turn it into a `rustls_root_cert_store`. This object is not safe
/// for concurrent mutation.
pub struct rustls_root_cert_store_builder {
// We use the opaque struct pattern to tell C about our types without
// telling them what's inside.
// https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs
_private: [u8; 0],
}

impl CastPtr for rustls_root_cert_store {
type RustType = RootCertStore;
pub(crate) struct RootCertStoreBuilder {
roots: RootCertStore,
}

impl ArcCastPtr for rustls_root_cert_store {}
impl CastPtr for rustls_root_cert_store_builder {
type RustType = Option<RootCertStoreBuilder>;
}

impl rustls_root_cert_store {
/// Create a rustls_root_cert_store. Caller owns the memory and must
/// eventually call rustls_root_cert_store_free. The store starts out empty.
/// Caller must add root certificates with rustls_root_cert_store_add_pem.
/// <https://docs.rs/rustls/latest/rustls/struct.RootCertStore.html#method.empty>
impl BoxCastPtr for rustls_root_cert_store_builder {}

impl rustls_root_cert_store_builder {
/// Create a `rustls_root_cert_store_builder`. Caller owns the memory and must
/// eventually call `rustls_root_cert_store_builder_build`, then free the
/// resulting `rustls_root_cert_store`.
///
/// If you wish to abandon the builder without calling `rustls_root_cert_store_builder_build`,
/// it must be freed with `rustls_root_cert_store_builder_free`.
#[no_mangle]
pub extern "C" fn rustls_root_cert_store_new() -> *const rustls_root_cert_store {
pub extern "C" fn rustls_root_cert_store_builder_new() -> *mut rustls_root_cert_store_builder {
ffi_panic_boundary! {
let store = rustls::RootCertStore::empty();
ArcCastPtr::to_const_ptr(store)
let builder = RootCertStoreBuilder {
roots: RootCertStore::empty(),
};
BoxCastPtr::to_mut_ptr(Some(builder))
}
}

/// Add one or more certificates to the root cert store using PEM encoded data.
/// Add one or more certificates to the root cert store builder using PEM
/// encoded data.
///
/// When `strict` is true an error will return a `CertificateParseError`
/// result. So will an attempt to parse data that has zero certificates.
Expand All @@ -467,15 +479,19 @@ impl rustls_root_cert_store {
/// This may be useful on systems that have syntactically invalid root
/// certificates.
#[no_mangle]
pub extern "C" fn rustls_root_cert_store_add_pem(
store: *mut rustls_root_cert_store,
pub extern "C" fn rustls_root_cert_store_builder_add_pem(
builder: *mut rustls_root_cert_store_builder,
pem: *const u8,
pem_len: size_t,
strict: bool,
) -> rustls_result {
ffi_panic_boundary! {
let certs_pem: &[u8] = try_slice!(pem, pem_len);
let store: &mut RootCertStore = try_mut_from_ptr!(store);
let builder: &mut Option<RootCertStoreBuilder> = try_mut_from_ptr!(builder);
let builder = match builder {
None => return AlreadyUsed,
Some(b) => b,
};

let certs_der: Result<Vec<CertificateDer>, _> = rustls_pemfile::certs(&mut Cursor::new(certs_pem)).collect();
let certs_der = match certs_der {
Expand All @@ -491,11 +507,68 @@ impl rustls_root_cert_store {
return rustls_result::CertificateParseError;
}

store.roots.append(&mut new_store.roots);
builder.roots.roots.append(&mut new_store.roots);

rustls_result::Ok
}
}

/// Create a new `rustls_root_cert_store` from the builder.
///
/// The builder is consumed and cannot be used again, but must still be freed.
///
/// The root cert store can be used in several `rustls_web_pki_client_cert_verifier_builder_new`
/// instances and must be freed by the application when no longer needed. See the documentation of
/// `rustls_root_cert_store_free` for details about lifetime.
#[no_mangle]
pub extern "C" fn rustls_root_cert_store_builder_build(
builder: *mut rustls_root_cert_store_builder,
root_cert_store_out: *mut *const rustls_root_cert_store,
) -> rustls_result {
ffi_panic_boundary! {
let builder: &mut Option<RootCertStoreBuilder> = try_mut_from_ptr!(builder);
let builder = match builder {
None => return AlreadyUsed,
Some(b) => b,
};

unsafe {
*root_cert_store_out = ArcCastPtr::to_const_ptr(builder.roots.clone());
}

rustls_result::Ok
}
}

/// Free a `rustls_root_cert_store_builder` previously returned from
/// `rustls_root_cert_store_builder_new`. Calling with NULL is fine. Must not be
/// called twice with the same value.
#[no_mangle]
pub extern "C" fn rustls_root_cert_store_builder_free(
builder: *mut rustls_root_cert_store_builder,
) {
ffi_panic_boundary! {
BoxCastPtr::to_box(builder);
}
}
}

/// A root certificate store.
/// <https://docs.rs/rustls/latest/rustls/struct.RootCertStore.html>
pub struct rustls_root_cert_store {
// We use the opaque struct pattern to tell C about our types without
// telling them what's inside.
// https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs
_private: [u8; 0],
}

impl CastPtr for rustls_root_cert_store {
type RustType = RootCertStore;
}

impl ArcCastPtr for rustls_root_cert_store {}

impl rustls_root_cert_store {
/// Free a rustls_root_cert_store previously returned from rustls_root_cert_store_builder_build.
/// Calling with NULL is fine. Must not be called twice with the same value.
#[no_mangle]
Expand Down
51 changes: 41 additions & 10 deletions src/rustls.h
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,15 @@ typedef struct rustls_iovec rustls_iovec;
*/
typedef struct rustls_root_cert_store rustls_root_cert_store;

/**
* A `rustls_root_cert_store` being constructed. A builder can be modified by,
* adding trust anchor root certificates with `rustls_root_cert_store_builder_add_pem`.
* Once you're done adding root certificates, call `rustls_root_cert_store_builder_build`
* to turn it into a `rustls_root_cert_store`. This object is not safe
* for concurrent mutation.
*/
typedef struct rustls_root_cert_store_builder rustls_root_cert_store_builder;

/**
* A server config that is done being constructed and is now read-only.
* Under the hood, this object corresponds to an `Arc<ServerConfig>`.
Expand Down Expand Up @@ -920,15 +929,18 @@ rustls_result rustls_certified_key_clone_with_ocsp(const struct rustls_certified
void rustls_certified_key_free(const struct rustls_certified_key *key);

/**
* Create a rustls_root_cert_store. Caller owns the memory and must
* eventually call rustls_root_cert_store_free. The store starts out empty.
* Caller must add root certificates with rustls_root_cert_store_add_pem.
* <https://docs.rs/rustls/latest/rustls/struct.RootCertStore.html#method.empty>
* Create a `rustls_root_cert_store_builder`. Caller owns the memory and must
* eventually call `rustls_root_cert_store_builder_build`, then free the
* resulting `rustls_root_cert_store`.
*
* If you wish to abandon the builder without calling `rustls_root_cert_store_builder_build`,
* it must be freed with `rustls_root_cert_store_builder_free`.
*/
const struct rustls_root_cert_store *rustls_root_cert_store_new(void);
struct rustls_root_cert_store_builder *rustls_root_cert_store_builder_new(void);

/**
* Add one or more certificates to the root cert store using PEM encoded data.
* Add one or more certificates to the root cert store builder using PEM
* encoded data.
*
* When `strict` is true an error will return a `CertificateParseError`
* result. So will an attempt to parse data that has zero certificates.
Expand All @@ -937,10 +949,29 @@ const struct rustls_root_cert_store *rustls_root_cert_store_new(void);
* This may be useful on systems that have syntactically invalid root
* certificates.
*/
rustls_result rustls_root_cert_store_add_pem(struct rustls_root_cert_store *store,
const uint8_t *pem,
size_t pem_len,
bool strict);
rustls_result rustls_root_cert_store_builder_add_pem(struct rustls_root_cert_store_builder *builder,
const uint8_t *pem,
size_t pem_len,
bool strict);

/**
* Create a new `rustls_root_cert_store` from the builder.
*
* The builder is consumed and cannot be used again, but must still be freed.
*
* The root cert store can be used in several `rustls_web_pki_client_cert_verifier_builder_new`
* instances and must be freed by the application when no longer needed. See the documentation of
* `rustls_root_cert_store_free` for details about lifetime.
*/
rustls_result rustls_root_cert_store_builder_build(struct rustls_root_cert_store_builder *builder,
const struct rustls_root_cert_store **root_cert_store_out);

/**
* Free a `rustls_root_cert_store_builder` previously returned from
* `rustls_root_cert_store_builder_new`. Calling with NULL is fine. Must not be
* called twice with the same value.
*/
void rustls_root_cert_store_builder_free(struct rustls_root_cert_store_builder *builder);

/**
* Free a rustls_root_cert_store previously returned from rustls_root_cert_store_builder_build.
Expand Down
15 changes: 11 additions & 4 deletions tests/server.c
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,8 @@ main(int argc, const char **argv)
struct rustls_connection *rconn = NULL;
const struct rustls_certified_key *certified_key = NULL;
struct rustls_slice_bytes alpn_http11;
struct rustls_root_cert_store *client_cert_root_store = NULL;
struct rustls_root_cert_store_builder *client_cert_root_store_builder = NULL;
const struct rustls_root_cert_store *client_cert_root_store = NULL;
struct rustls_web_pki_client_cert_verifier_builder
*client_cert_verifier_builder = NULL;
const struct rustls_client_cert_verifier *client_cert_verifier = NULL;
Expand Down Expand Up @@ -287,9 +288,14 @@ main(int argc, const char **argv)
goto cleanup;
}

client_cert_root_store = rustls_root_cert_store_new();
result = rustls_root_cert_store_add_pem(
client_cert_root_store, (uint8_t *)certbuf, certbuf_len, true);
client_cert_root_store_builder = rustls_root_cert_store_builder_new();
result = rustls_root_cert_store_builder_add_pem(
client_cert_root_store_builder, (uint8_t *)certbuf, certbuf_len, true);
if(result != RUSTLS_RESULT_OK) {
goto cleanup;
}
result = rustls_root_cert_store_builder_build(
client_cert_root_store_builder, &client_cert_root_store);
if(result != RUSTLS_RESULT_OK) {
goto cleanup;
}
Expand Down Expand Up @@ -397,6 +403,7 @@ main(int argc, const char **argv)

cleanup:
rustls_certified_key_free(certified_key);
rustls_root_cert_store_builder_free(client_cert_root_store_builder);
rustls_root_cert_store_free(client_cert_root_store);
rustls_web_pki_client_cert_verifier_builder_free(
client_cert_verifier_builder);
Expand Down

0 comments on commit ce31cd5

Please sign in to comment.