1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
use security_framework::trust_settings::{ Domain, TrustSettings, TrustSettingsForCertificate }; use rustls::RootCertStore; use std::io::{Error, ErrorKind}; use std::collections::HashMap; /// Loads root certificates found in the platform's native certificate /// store. /// /// On success, this returns a `rustls::RootCertStore` loaded with a /// snapshop of the root certificates found on this platform. This /// function fails in a platform-specific way, expressed in a `std::io::Error`. /// /// This function can be expensive: on some platforms it involves loading /// and parsing a ~300KB disk file. It's therefore prudent to call /// this sparingly. pub fn load_native_certs() -> Result<RootCertStore, Error> { let mut store = RootCertStore::empty(); // The various domains are designed to interact like this: // // "Per-user Trust Settings override locally administered // Trust Settings, which in turn override the System Trust // Settings." // // So we collect the certificates in this order; as a map of // their DER encoding to what we'll do with them. We don't // overwrite existing elements, which mean User settings // trump Admin trump System, as desired. let mut all_certs = HashMap::new(); for domain in &[Domain::User, Domain::Admin, Domain::System] { let ts = TrustSettings::new(*domain); let iter = ts.iter() .map_err(|err| Error::new(ErrorKind::Other, err))?; for cert in iter { let der = cert.to_der(); // If there are no specific trust settings, the default // is to trust the certificate as a root cert. Weird API but OK. // The docs say: // // "Note that an empty Trust Settings array means "always trust this cert, // with a resulting kSecTrustSettingsResult of kSecTrustSettingsResultTrustRoot". let trusted = ts.tls_trust_settings_for_certificate(&cert) .map_err(|err| Error::new(ErrorKind::Other, err))? .unwrap_or(TrustSettingsForCertificate::TrustRoot); all_certs.entry(der) .or_insert(trusted); } } // Now we have all the certificates and an idea of whether // to use them. for (der, trusted) in all_certs.drain() { match trusted { TrustSettingsForCertificate::TrustRoot | TrustSettingsForCertificate::TrustAsRoot => { store.add(&rustls::Certificate(der)) .map_err(|err| Error::new(ErrorKind::InvalidData, err))?; }, _ => {} // discard } } Ok(store) }