Skip to content

Commit

Permalink
Add extra roots on macos and ios
Browse files Browse the repository at this point in the history
Co-authored-by: ComplexSpaces <[email protected]>
  • Loading branch information
stormshield-gt and complexspaces committed Sep 2, 2024
1 parent 4c758e1 commit 2136496
Showing 1 changed file with 58 additions and 12 deletions.
70 changes: 58 additions & 12 deletions rustls-platform-verifier/src/verification/apple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,21 +43,38 @@ fn system_time_to_cfdate(time: pki_types::UnixTime) -> Result<CFDate, TlsError>
/// A TLS certificate verifier that utilizes the Apple platform certificate facilities.
#[derive(Debug)]
pub struct Verifier {
/// Extra trust anchors to add to the verifier above and beyond those provided by
/// the system-provided trust stores.
extra_roots: Vec<pki_types::CertificateDer<'static>>,
/// Testing only: The root CA certificate to trust.
#[cfg(any(test, feature = "ffi-testing", feature = "dbg"))]
test_only_root_ca_override: Option<Vec<u8>>,
pub(super) crypto_provider: OnceCell<Arc<CryptoProvider>>,
}

impl Verifier {
/// Creates a new instance of a TLS certificate verifier that utilizes the macOS certificate
/// Creates a new instance of a TLS certificate verifier that utilizes the Apple certificate
/// facilities.
///
/// A [`CryptoProvider`] must be set with
/// [`set_provider`][Verifier::set_provider]/[`with_provider`][Verifier::with_provider] or
/// [`CryptoProvider::install_default`] before the verifier can be used.
pub fn new() -> Self {
Self {
extra_roots: Vec::new(),
#[cfg(any(test, feature = "ffi-testing", feature = "dbg"))]
test_only_root_ca_override: None,
crypto_provider: OnceCell::new(),
}
}

/// Creates a new instance of a TLS certificate verifier that utilizes the Apple certificate
/// facilities with the addition of extra root certificates to trust.
///
/// See [Verifier::new] for the external requirements the verifier needs.
pub fn new_with_extra_roots(roots: Vec<pki_types::CertificateDer<'static>>) -> Self {
Self {
extra_roots: roots,
#[cfg(any(test, feature = "ffi-testing", feature = "dbg"))]
test_only_root_ca_override: None,
crypto_provider: OnceCell::new(),
Expand All @@ -68,6 +85,7 @@ impl Verifier {
#[cfg(any(test, feature = "ffi-testing", feature = "dbg"))]
pub(crate) fn new_with_fake_root(root: &[u8]) -> Self {
Self {
extra_roots: Vec::new(),
test_only_root_ca_override: Some(root.into()),
crypto_provider: OnceCell::new(),
}
Expand Down Expand Up @@ -123,21 +141,49 @@ impl Verifier {
.map_err(|e| invalid_certificate(e.to_string()))?;
}

// When testing, support using fake roots and ignoring values present on the system.
let raw_extra_roots = self.extra_roots.iter();

#[cfg(any(test, feature = "ffi-testing", feature = "dbg"))]
let extra_root = self
.test_only_root_ca_override
.as_ref()
.map(|root| pki_types::CertificateDer::from_slice(root));

#[cfg(any(test, feature = "ffi-testing", feature = "dbg"))]
let raw_extra_roots = raw_extra_roots.chain(&extra_root).to_owned();

let extra_roots = raw_extra_roots
.map(|root| {
SecCertificate::from_der(root)
.map_err(|_| TlsError::InvalidCertificate(CertificateError::BadEncoding))
})
.collect::<Result<Vec<_>, _>>()?;

// If any extra roots were provided by the user (or tests), provide them to the trust
// evaluation regardless of their system trust settings or status.
if !extra_roots.is_empty() {
trust_evaluation
.set_anchor_certificates(&extra_roots)
.map_err(|e| TlsError::Other(OtherError(Arc::new(e))))?;

// We want to trust both the system-installed and the extra roots. This must be set
// since calling `SecTrustSetAnchorCertificates` "disables the trusting of any
// anchors other than the ones specified by this function call" by default.
trust_evaluation
.set_trust_anchor_certificates_only(false)
.map_err(|e| TlsError::Other(OtherError(Arc::new(e))))?;
}

// When testing, support using fake roots and ignoring default roots present on the system for
// consistency/reproducibility reasons.
//
// XXX: This does not currently limit revocation from fetching information online, or prevent
// the downloading of root CAs.
#[cfg(any(test, feature = "ffi-testing", feature = "dbg"))]
{
// If these panicked, it would be a programmer bug in the tests.
if let Some(test_root) = &self.test_only_root_ca_override {
let test_root =
SecCertificate::from_der(test_root).expect("failed to parse test root");

// Supply the custom root, which will be the only one trusted during evaluation.
trust_evaluation
.set_anchor_certificates(&[test_root])
.expect("failed to set anchors");
if self.test_only_root_ca_override.is_some() {
// XXX: The test root was already provided to the trust evaluation as an extra root.
// We only need to stop use of the default system-installed roots.

// As per [Apple's docs], building and verifying a certificate chain will
// search through the system and keychain to find certificates that it
Expand Down Expand Up @@ -174,7 +220,7 @@ impl Verifier {
CertificateError::UnknownIssuer,
)),
errors::errSecInvalidExtendedKeyUsage => Ok(TlsError::InvalidCertificate(
CertificateError::Other(OtherError(std::sync::Arc::new(super::EkuError))),
CertificateError::Other(OtherError(Arc::new(super::EkuError))),
)),
errors::errSecCertificateRevoked => {
Ok(TlsError::InvalidCertificate(CertificateError::Revoked))
Expand Down

0 comments on commit 2136496

Please sign in to comment.