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 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
|
#![cfg(any(feature = "ring", feature = "aws-lc-rs"))]
use core::time::Duration;
use std::collections::HashMap;
use std::fs::File;
use base64::{Engine as _, engine::general_purpose};
use bzip2::read::BzDecoder;
use pki_types::{
CertificateDer, ServerName, SignatureVerificationAlgorithm, TrustAnchor, UnixTime,
};
use serde::Deserialize;
use webpki::{KeyUsage, anchor_from_trusted_cert};
// All of the BetterTLS testcases use P256 keys.
static ALGS: &[&dyn SignatureVerificationAlgorithm] = &[
#[cfg(feature = "ring")]
webpki::ring::ECDSA_P256_SHA256,
#[cfg(feature = "aws-lc-rs")]
webpki::aws_lc_rs::ECDSA_P256_SHA256,
];
#[ignore] // Runs slower than other unit tests - opt-in with `cargo test -- --include-ignored`
#[test]
fn path_building() {
let better_tls = testdata();
let root_der = &better_tls.root_der();
let root_der = CertificateDer::from(root_der.as_slice());
let roots = &[anchor_from_trusted_cert(&root_der).expect("invalid trust anchor")];
let suite = "pathbuilding";
run_testsuite(
suite,
better_tls
.suites
.get(suite)
.unwrap_or_else(|| panic!("missing {suite} suite")),
roots,
);
}
#[ignore] // Runs slower than other unit tests - opt-in with `cargo test -- --include-ignored`
#[test]
fn name_constraints() {
let better_tls = testdata();
let root_der = &better_tls.root_der();
let root_der = CertificateDer::from(root_der.as_slice());
let roots = &[anchor_from_trusted_cert(&root_der).expect("invalid trust anchor")];
let suite = "nameconstraints";
run_testsuite(
suite,
better_tls
.suites
.get(suite)
.unwrap_or_else(|| panic!("missing {suite} suite")),
roots,
);
}
fn run_testsuite(suite_name: &str, suite: &BetterTlsSuite, roots: &[TrustAnchor]) {
for testcase in &suite.test_cases {
println!("Testing {suite_name} test case {}", testcase.id);
let certs_der = testcase.certs_der();
let ee_der = CertificateDer::from(certs_der[0].as_slice());
let intermediates = &certs_der[1..]
.iter()
.map(|cert| CertificateDer::from(cert.as_slice()))
.collect::<Vec<_>>();
let ee_cert = webpki::EndEntityCert::try_from(&ee_der).expect("invalid end entity cert");
// Set the time to the time of test case generation. This ensures that the test case
// certificates won't expire.
let now = UnixTime::since_unix_epoch(Duration::from_secs(1_691_788_832));
let result = ee_cert
.verify_for_usage(
ALGS,
roots,
intermediates,
now,
KeyUsage::server_auth(),
None,
None,
)
.and_then(|_| {
ee_cert.verify_is_valid_for_subject_name(
&ServerName::try_from(testcase.hostname.as_str())
.expect("invalid testcase hostname"),
)
});
match testcase.expected {
ExpectedResult::Accept => assert!(result.is_ok(), "expected success, got {result:?}"),
ExpectedResult::Reject => {
assert!(result.is_err(), "expected failure, got {result:?}")
}
}
}
}
fn testdata() -> BetterTls {
let mut data_file = File::open(concat!(env!("SOURCEPACKAGEDIR"),"third-party/bettertls/bettertls.tests.json.bz2"))
.expect("failed to open data file");
let decompressor = BzDecoder::new(&mut data_file);
let better_tls: BetterTls = serde_json::from_reader(decompressor).expect("invalid test JSON");
println!("Testing BetterTLS revision {:?}", better_tls.revision);
better_tls
}
#[derive(Deserialize, Debug)]
struct BetterTls {
#[serde(rename(deserialize = "betterTlsRevision"))]
revision: String,
#[serde(rename(deserialize = "trustRoot"))]
root: String,
suites: HashMap<String, BetterTlsSuite>,
}
impl BetterTls {
fn root_der(&self) -> Vec<u8> {
general_purpose::STANDARD
.decode(&self.root)
.expect("invalid trust anchor base64")
}
}
#[derive(Deserialize, Debug)]
struct BetterTlsSuite {
#[serde(rename(deserialize = "testCases"))]
test_cases: Vec<BetterTlsTest>,
}
#[derive(Deserialize, Debug)]
struct BetterTlsTest {
id: u32,
certificates: Vec<String>,
hostname: String,
expected: ExpectedResult,
}
impl BetterTlsTest {
fn certs_der(&self) -> Vec<Vec<u8>> {
self.certificates
.iter()
.map(|cert| {
general_purpose::STANDARD
.decode(cert)
.expect("invalid cert base64")
})
.collect()
}
}
#[derive(Deserialize, Debug)]
#[serde(rename_all = "UPPERCASE")]
enum ExpectedResult {
Accept,
Reject,
}
|