Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions rustls-platform-verifier/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ pub fn assert_cert_error_eq<E: StdError + PartialEq + 'static>(
/// we know the test certificates are valid. This must be updated if the mock certificates
/// are regenerated.
pub(crate) fn verification_time() -> pki_types::UnixTime {
// Sat, 3 January 2026 14:20:06 UTC
pki_types::UnixTime::since_unix_epoch(Duration::from_secs(1_767_450_006))
// Thu, 29 January 2026 04:14:44 UTC
pki_types::UnixTime::since_unix_epoch(Duration::from_secs(1_769_660_084))
}

fn test_provider() -> Arc<CryptoProvider> {
Expand Down
18 changes: 16 additions & 2 deletions rustls-platform-verifier/src/tests/verification_mock/ca.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ func doIt() error {

var err error = nil

root1_key, err := generateRoot("root1", now)
root1_key, err := generateRoot("root1", now, "")
if err != nil {
return err
}
Expand All @@ -96,6 +96,11 @@ func doIt() error {
}
}

_, err = generateRoot("root2", now, "example.com")
if err != nil {
return err
}

return nil
}

Expand Down Expand Up @@ -210,11 +215,12 @@ func generateInt(intName string, serial int64, now time.Time, caKey crypto.Signe
return intKey, nil
}

func generateRoot(name string, now time.Time) (crypto.Signer, error) {
func generateRoot(name string, now time.Time, commonName string) (crypto.Signer, error) {
caKey, err := generateKey()
if err != nil {
return nil, err
}

template := x509.Certificate{
SerialNumber: big.NewInt(1),
Subject: pkix.Name{
Expand All @@ -227,6 +233,14 @@ func generateRoot(name string, now time.Time) (crypto.Signer, error) {
BasicConstraintsValid: true,
}

if len(commonName) != 0 {
template.Subject.CommonName = commonName
template.KeyUsage = 0
// See `generateEndEntity` for list of macOS requirements.
template.ExtKeyUsage = []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}
template.DNSNames = []string{commonName}
}

cert, err := x509.CreateCertificate(rand.Reader, &template, &template, caKey.Public(), caKey)
if err != nil {
return nil, err
Expand Down
57 changes: 50 additions & 7 deletions rustls-platform-verifier/src/tests/verification_mock/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use std::net::{Ipv4Addr, Ipv6Addr};
use std::sync::Arc;

use rustls::client::danger::ServerCertVerifier;
use rustls::pki_types;
use rustls::pki_types::{self, CertificateDer};
#[cfg(not(any(target_vendor = "apple", windows)))]
use rustls::pki_types::{DnsName, ServerName};
use rustls::{CertificateError, Error as TlsError, OtherError};
Expand Down Expand Up @@ -80,13 +80,17 @@ macro_rules! no_error {
};
}

const ROOT1: pki_types::CertificateDer<'static> =
pki_types::CertificateDer::from_slice(include_bytes!("root1.crt"));
const ROOT1: CertificateDer = CertificateDer::from_slice(include_bytes!("root1.crt"));
const ROOT1_INT1: &[u8] = include_bytes!("root1-int1.crt");
const ROOT1_INT1_EXAMPLE_COM_GOOD: &[u8] = include_bytes!("root1-int1-ee_example.com-good.crt");
const ROOT1_INT1_LOCALHOST_IPV4_GOOD: &[u8] = include_bytes!("root1-int1-ee_127.0.0.1-good.crt");
const ROOT1_INT1_LOCALHOST_IPV6_GOOD: &[u8] = include_bytes!("root1-int1-ee_1-good.crt");

// `ffi-testing` is currently only used for Android, which doesn't support extra roots yet.
#[cfg_attr(feature = "ffi-testing", allow(unused))]
#[cfg(not(any(target_os = "android", target_os = "windows")))]
const ROOT2: CertificateDer = CertificateDer::from_slice(include_bytes!("root2.crt"));

const EXAMPLE_COM: &str = "example.com";
const LOCALHOST_IPV4: &str = "127.0.0.1";
const LOCALHOST_IPV6: &str = "::1";
Expand All @@ -111,8 +115,8 @@ pub(super) fn verification_without_mock_root() {
let verifier = Verifier::new(crypto_provider).unwrap();

let server_name = pki_types::ServerName::try_from(EXAMPLE_COM).unwrap();
let end_entity = pki_types::CertificateDer::from(ROOT1_INT1_EXAMPLE_COM_GOOD);
let intermediates = [pki_types::CertificateDer::from(ROOT1_INT1)];
let end_entity = CertificateDer::from(ROOT1_INT1_EXAMPLE_COM_GOOD);
let intermediates = [CertificateDer::from(ROOT1_INT1)];

// Fails because the server cert has no trust root in Windows, and can't since it uses a self-signed CA.
// Similarly on UNIX platforms using the Webpki verifier, it can't fetch extra certificates through
Expand All @@ -139,6 +143,45 @@ fn test_verification_without_mock_root() {
verification_without_mock_root()
}

#[cfg(not(any(target_os = "android", target_os = "windows")))]
#[test]
fn test_selfsigned_cert_with_extra_roots() {
let crypto_provider = test_provider();

let selfsigned = ROOT2;
let roots = vec![selfsigned.clone()];
let server_name = pki_types::ServerName::try_from(EXAMPLE_COM).unwrap();

let verifier = Verifier::new_with_extra_roots(roots, crypto_provider).unwrap();

verifier
.verify_server_cert(&selfsigned, &[], &server_name, &[], verification_time())
.expect("failed to validate singular extra root certificate chain");
}

#[cfg(not(target_os = "android"))]
#[test]
fn test_chain_signed_with_extra_roots() {
let crypto_provider = test_provider();

let server_name = pki_types::ServerName::try_from(EXAMPLE_COM).unwrap();
let end_entity = CertificateDer::from(ROOT1_INT1_EXAMPLE_COM_GOOD);
let intermediates = [CertificateDer::from(ROOT1_INT1)];
let roots = vec![ROOT1];

let verifier = Verifier::new_with_extra_roots(roots, crypto_provider).unwrap();

verifier
.verify_server_cert(
&end_entity,
&intermediates,
&server_name,
&[],
verification_time(),
)
.expect("failed to validate extra root-only certificate chain");
}

// Note: Android does not currently support IP address hosts, so these tests are disabled for
// Android.
// Verifies that our test trust anchor(s) are not trusted when `Verifier::new()`
Expand Down Expand Up @@ -349,10 +392,10 @@ fn test_with_mock_root<E: std::error::Error + PartialEq + 'static>(
let mut chain = test_case
.chain
.iter()
.map(|bytes| pki_types::CertificateDer::from(*bytes));
.map(|bytes| CertificateDer::from(*bytes));

let end_entity = chain.next().unwrap();
let intermediates: Vec<pki_types::CertificateDer<'_>> = chain.collect();
let intermediates: Vec<CertificateDer<'_>> = chain.collect();

let server_name = pki_types::ServerName::try_from(test_case.reference_id).unwrap();

Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file modified rustls-platform-verifier/src/tests/verification_mock/root1.crt
Binary file not shown.
Binary file not shown.
Loading