rustls_native_certs/
rustls.rs

1use rustls::RootCertStore;
2use std::io::{Error, ErrorKind};
3use std::io::BufRead;
4use crate::RootStoreBuilder;
5
6/// Like `Result<T,E>`, but allows for functions that can return partially complete
7/// work alongside an error.
8///
9/// *This type is available only if the crate is built with the "rustls" feature.*
10pub type PartialResult<T, E> = Result<T, (Option<T>, E)>;
11
12/// Loads root certificates found in the platform's native certificate
13/// store.
14///
15/// On success, this returns a `rustls::RootCertStore` loaded with a
16/// snapshop of the root certificates found on this platform.  This
17/// function fails in a platform-specific way, expressed in a `std::io::Error`.
18///
19/// This function can be expensive: on some platforms it involves loading
20/// and parsing a ~300KB disk file.  It's therefore prudent to call
21/// this sparingly.
22///
23/// *This function is available only if the crate is built with the "rustls" feature.*
24pub fn load_native_certs() -> PartialResult<RootCertStore, Error> {
25    struct RootCertStoreLoader {
26        store: RootCertStore,
27    };
28    impl RootStoreBuilder for RootCertStoreLoader {
29        fn load_der(&mut self, der: Vec<u8>) -> Result<(), Error> {
30            self.store.add(&rustls::Certificate(der))
31                .map_err(|err| Error::new(ErrorKind::InvalidData, err))
32        }
33        fn load_pem_file(&mut self, rd: &mut dyn BufRead) -> Result<(), Error> {
34            self.store.add_pem_file(rd)
35                .map(|_| ())
36                .map_err(|()| Error::new(ErrorKind::InvalidData, format!("could not load PEM file")))
37        }
38    }
39    let mut loader = RootCertStoreLoader {
40        store: RootCertStore::empty(),
41    };
42    match crate::build_native_certs(&mut loader) {
43        Err(err) if loader.store.is_empty() => Err((None, err)),
44        Err(err) => Err((Some(loader.store), err)),
45        Ok(()) => Ok(loader.store),
46    }
47}