This repository has been archived by the owner on Jul 30, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from robocorp/bogdan/show-cert-data
Fork rustls-native-certs && show cert data
- Loading branch information
Showing
9 changed files
with
216 additions
and
12 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
[package] | ||
name = "rustls-native-certs" | ||
version = "0.7.0-alpha.1" | ||
edition = "2021" | ||
rust-version = "1.60" | ||
license = "Apache-2.0 OR ISC OR MIT" | ||
readme = "README.md" | ||
description = "rustls-native-certs allows rustls to use the platform native certificate store" | ||
homepage = "https://github.com/rustls/rustls-native-certs" | ||
repository = "https://github.com/rustls/rustls-native-certs" | ||
categories = ["network-programming", "cryptography"] | ||
|
||
[dependencies] | ||
rustls-pemfile = "=2.0.0-alpha.1" | ||
pki-types = { package = "rustls-pki-types", version = "0.2" } | ||
|
||
[dev-dependencies] | ||
ring = "0.16.5" | ||
rustls = "=0.22.0-alpha.3" | ||
rustls-webpki = "=0.102.0-alpha.3" | ||
serial_test = "2" | ||
untrusted = "0.7.0" # stick to the version ring depends on for now | ||
webpki-roots = "=0.26.0-alpha.1" | ||
x509-parser = "0.15" | ||
|
||
[target.'cfg(windows)'.dependencies] | ||
schannel = "0.1.15" | ||
|
||
[target.'cfg(all(unix, not(target_os = "macos")))'.dependencies] | ||
openssl-probe = "0.1.2" | ||
|
||
[target.'cfg(target_os = "macos")'.dependencies] | ||
security-framework = "2.0.0" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
//! `rustls-native-certs` allows `rustls` to use the platform's native certificate | ||
//! store when operating as a TLS client. | ||
//! | ||
//! It provides a single function [`load_native_certs()`], which returns a | ||
//! collection of certificates found by reading the platform-native | ||
//! certificate store. | ||
//! | ||
//! [`CertificateDer`] here is a marker newtype that denotes a DER-encoded | ||
//! X.509 certificate encoded as a `Vec<u8>`. | ||
//! | ||
//! If you want to load these certificates into a `rustls::RootCertStore`, | ||
//! you'll likely want to do something like this: | ||
//! | ||
//! ```no_run | ||
//! let mut roots = rustls::RootCertStore::empty(); | ||
//! for cert in rustls_native_certs::load_native_certs().expect("could not load platform certs") { | ||
//! roots.add(cert).unwrap(); | ||
//! } | ||
//! ``` | ||
#[cfg(all(unix, not(target_os = "macos")))] | ||
mod unix; | ||
#[cfg(all(unix, not(target_os = "macos")))] | ||
use unix as platform; | ||
|
||
#[cfg(windows)] | ||
mod windows; | ||
#[cfg(windows)] | ||
use windows as platform; | ||
|
||
#[cfg(target_os = "macos")] | ||
mod macos; | ||
#[cfg(target_os = "macos")] | ||
use macos as platform; | ||
|
||
use std::{io::{Error, BufReader, ErrorKind}, path::Path, fs::File}; | ||
|
||
use pki_types::CertificateDer; | ||
|
||
/// Load root certificates found in the platform's native certificate store. | ||
/// | ||
/// 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<Vec<CertificateDer<'static>>, Error> { | ||
platform::load_native_certs() | ||
} | ||
|
||
/// Used inside unix.rs | ||
fn load_pem_certs(path: &Path) -> Result<Vec<CertificateDer<'static>>, Error> { | ||
let f = File::open(path)?; | ||
let mut f = BufReader::new(f); | ||
rustls_pemfile::certs(&mut f) | ||
.collect::<Result<Vec<_>, _>>() | ||
.map_err(|err| { | ||
Error::new( | ||
ErrorKind::InvalidData, | ||
format!("could not load PEM file {path:?}: {err}"), | ||
) | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
use pki_types::CertificateDer; | ||
use security_framework::trust_settings::{Domain, TrustSettings, TrustSettingsForCertificate}; | ||
|
||
use std::collections::HashMap; | ||
use std::io::{Error, ErrorKind}; | ||
|
||
pub fn load_native_certs() -> Result<Vec<CertificateDer<'static>>, Error> { | ||
// 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); | ||
} | ||
} | ||
|
||
let mut certs = Vec::new(); | ||
|
||
// Now we have all the certificates and an idea of whether | ||
// to use them. | ||
for (der, trusted) in all_certs.drain() { | ||
use TrustSettingsForCertificate::*; | ||
if let TrustRoot | TrustAsRoot = trusted { | ||
certs.push(CertificateDer::from(der)); | ||
} | ||
} | ||
|
||
Ok(certs) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
use crate::load_pem_certs; | ||
|
||
use pki_types::CertificateDer; | ||
|
||
use std::io::Error; | ||
|
||
pub fn load_native_certs() -> Result<Vec<CertificateDer<'static>>, Error> { | ||
let likely_locations = openssl_probe::probe(); | ||
|
||
match likely_locations.cert_file { | ||
Some(cert_file) => load_pem_certs(&cert_file), | ||
None => Ok(Vec::new()), | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
use pki_types::CertificateDer; | ||
|
||
use std::io::Error; | ||
|
||
pub fn load_native_certs() -> Result<Vec<CertificateDer<'static>>, Error> { | ||
// My "Personal" | ||
// Root "Trusted Root Certification Authorities" | ||
// Trust "Enterprise Trust" | ||
// CA "Intermediate Certification Authorities" | ||
let store_names = ["My", "Root", "Trust", "CA"]; | ||
let mut certs = Vec::new(); | ||
|
||
for &store_name in &store_names { | ||
// Try to open the store from the current user context and accumulate certificates | ||
if let Ok(current_user_store) = schannel::cert_store::CertStore::open_current_user(store_name) { | ||
for cert in current_user_store.certs() { | ||
certs.push(CertificateDer::from(cert.to_der().to_vec())); | ||
} | ||
} | ||
|
||
// Try to open the store from the local machine context and accumulate certificates | ||
if let Ok(local_machine_store) = schannel::cert_store::CertStore::open_local_machine(store_name) { | ||
for cert in local_machine_store.certs() { | ||
certs.push(CertificateDer::from(cert.to_der().to_vec())); | ||
} | ||
} | ||
} | ||
|
||
Ok(certs) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters