chore: checkpoint before Python removal

This commit is contained in:
2026-03-26 22:33:59 +00:00
parent 683cec9307
commit e568ddf82a
29972 changed files with 11269302 additions and 2 deletions

172
vendor/webpki-roots/tests/codegen.rs vendored Normal file
View File

@@ -0,0 +1,172 @@
use std::ascii::escape_default;
use std::fmt::Write;
use std::fs;
use aws_lc_rs::digest;
use pki_types::CertificateDer;
use webpki::anchor_from_trusted_cert;
use webpki_ccadb::fetch_ccadb_roots;
use x509_parser::prelude::AttributeTypeAndValue;
use x509_parser::x509::X509Name;
#[tokio::test]
async fn new_generated_code_is_fresh() {
let tls_roots_map = fetch_ccadb_roots().await;
let mut code = String::with_capacity(256 * 1_024);
code.push_str(HEADER);
code.push_str("pub const TLS_SERVER_ROOTS: &[TrustAnchor<'static>] = &[\n");
let (mut subject, mut spki, mut name_constraints) =
(String::new(), String::new(), String::new());
for root in tls_roots_map.values() {
// Verify the DER FP matches the metadata FP.
let der = root.der();
let calculated_fp = digest::digest(&digest::SHA256, &der);
let metadata_fp = hex::decode(&root.sha256_fingerprint).expect("malformed fingerprint");
assert_eq!(calculated_fp.as_ref(), metadata_fp.as_slice());
let ta_der = CertificateDer::from(der.as_ref());
let ta = anchor_from_trusted_cert(&ta_der).expect("malformed trust anchor der");
subject.clear();
for &b in ta.subject.as_ref() {
write!(&mut subject, "{}", escape_default(b)).unwrap();
}
spki.clear();
for &b in ta.subject_public_key_info.as_ref() {
write!(&mut spki, "{}", escape_default(b)).unwrap();
}
name_constraints.clear();
if let Some(nc) = &root.mozilla_applied_constraints() {
for &b in nc.iter() {
write!(&mut name_constraints, "{}", escape_default(b)).unwrap();
}
}
let (_, parsed_cert) =
x509_parser::parse_x509_certificate(&der).expect("malformed x509 der");
let issuer = name_to_string(parsed_cert.issuer());
let subject_str = name_to_string(parsed_cert.subject());
let label = root.common_name_or_certificate_name.clone();
let serial = root.serial().to_string();
let sha256_fp = root.sha256_fp();
// Write comment
code.push_str(" /*\n");
code.push_str(&format!(" * Issuer: {issuer}\n"));
code.push_str(&format!(" * Subject: {subject_str}\n"));
code.push_str(&format!(" * Label: {label:?}\n"));
code.push_str(&format!(" * Serial: {serial}\n"));
code.push_str(&format!(" * SHA256 Fingerprint: {sha256_fp}\n"));
for ln in root.pem().lines() {
code.push_str(" * ");
code.push_str(ln.trim());
code.push('\n');
}
code.push_str(" */\n");
// Write the code
code.push_str(" TrustAnchor {\n");
code.write_fmt(format_args!(
" subject: Der::from_slice(b\"{subject}\"),\n"
))
.unwrap();
code.write_fmt(format_args!(
" subject_public_key_info: Der::from_slice(b\"{spki}\"),\n"
))
.unwrap();
match name_constraints.is_empty() {
false => code
.write_fmt(format_args!(
" name_constraints: Some(Der::from_slice(b\"{name_constraints}\"))\n"
))
.unwrap(),
true => code.push_str(" name_constraints: None\n"),
}
code.push_str(" },\n\n");
}
code.push_str("];\n");
// Check that the generated code matches the checked-in code
let old = fs::read_to_string("src/lib.rs").unwrap();
if old != code {
fs::write("src/lib.rs", code).unwrap();
panic!("generated code changed");
}
}
/// The built-in x509_parser::X509Name Display impl uses a different sort order than
/// the one historically used by mkcert.org^[0]. We re-create that sort order here to
/// avoid unnecessary churn in the generated code.
///
/// [0]: <https://github.com/Lukasa/mkcert/blob/6911a8f68681f4d6a795c1f6db7b063f75b03b5a/certs/convert_mozilla_certdata.go#L405-L428>
fn name_to_string(name: &X509Name) -> String {
let mut ret = String::with_capacity(256);
if let Some(cn) = name
.iter_common_name()
.next()
.and_then(|cn| cn.as_str().ok())
{
write!(ret, "CN={cn}").unwrap();
}
let mut append_attrs = |attrs: Vec<&AttributeTypeAndValue>, label| {
let str_parts = attrs
.iter()
.filter_map(|attr| attr.as_str().ok())
.collect::<Vec<_>>()
.join("/");
if !str_parts.is_empty() {
if !ret.is_empty() {
ret.push(' ');
}
write!(ret, "{label}={str_parts}").unwrap();
}
};
append_attrs(name.iter_organization().collect(), "O");
append_attrs(name.iter_organizational_unit().collect(), "OU");
ret
}
const HEADER: &str = r#"//! A compiled-in copy of the root certificates trusted by Mozilla.
//!
//! To use this library with rustls 0.22:
//!
//! ```rust
//! let root_store = rustls::RootCertStore {
//! roots: webpki_roots::TLS_SERVER_ROOTS.to_vec(),
//! };
//! ```
//!
//! This library is suitable for use in applications that can always be recompiled and instantly deployed.
//! For applications that are deployed to end-users and cannot be recompiled, or which need certification
//! before deployment, consider a library that uses the platform native certificate verifier such as
//! [rustls-platform-verifier]. This has the additional benefit of supporting OS provided CA constraints
//! and revocation data.
//!
//! [rustls-platform-verifier]: https://docs.rs/rustls-platform-verifier
//
// This library is automatically generated from the Mozilla
// IncludedCACertificateReportPEMCSV report via ccadb.org. Don't edit it.
//
// The generation is done deterministically so you can verify it
// yourself by inspecting and re-running the generation process.
#![no_std]
#![forbid(unsafe_code, unstable_features)]
#![deny(
elided_lifetimes_in_paths,
trivial_casts,
trivial_numeric_casts,
unused_import_braces,
unused_extern_crates,
unused_qualifications
)]
use pki_types::{Der, TrustAnchor};
"#;

Binary file not shown.

Binary file not shown.

Binary file not shown.

202
vendor/webpki-roots/tests/verify.rs vendored Normal file
View File

@@ -0,0 +1,202 @@
use core::time::Duration;
use std::convert::TryFrom;
use pki_types::{CertificateDer, ServerName, SignatureVerificationAlgorithm, UnixTime};
use rcgen::{
BasicConstraints, CertificateParams, CertifiedIssuer, DnType, IsCa, Issuer, KeyPair,
KeyUsagePurpose,
};
use webpki::{anchor_from_trusted_cert, EndEntityCert, Error, KeyUsage};
use x509_parser::extensions::{GeneralName, NameConstraints as X509ParserNameConstraints};
use x509_parser::prelude::FromDer;
use webpki_roots::TLS_SERVER_ROOTS;
#[test]
fn name_constraints() {
for name_constraints in TLS_SERVER_ROOTS
.iter()
.filter_map(|ta| ta.name_constraints.as_ref())
{
let time = UnixTime::since_unix_epoch(Duration::from_secs(0x40000000)); // Time matching rcgen default.
let test_case = ConstraintTest::new(name_constraints.as_ref());
let trust_anchors = &[anchor_from_trusted_cert(&test_case.trust_anchor).unwrap()];
// Each permitted EE should verify without error.
for permitted_ee in test_case.permitted_certs {
webpki::EndEntityCert::try_from(&permitted_ee)
.unwrap()
.verify_for_usage(
ALL_ALGORITHMS,
trust_anchors,
&[],
time,
KeyUsage::server_auth(),
None,
None,
)
.unwrap();
}
// Each forbidden EE should fail to verify with the expected name constraint error.
for forbidden_ee in test_case.forbidden_certs {
let ee = EndEntityCert::try_from(&forbidden_ee).unwrap();
let result = ee.verify_for_usage(
ALL_ALGORITHMS,
trust_anchors,
&[],
time,
KeyUsage::server_auth(),
None,
None,
);
assert!(matches!(result, Err(Error::NameConstraintViolation)));
}
}
}
struct ConstraintTest {
trust_anchor: CertificateDer<'static>,
permitted_certs: Vec<CertificateDer<'static>>,
forbidden_certs: Vec<CertificateDer<'static>>,
}
impl ConstraintTest {
fn new(webpki_name_constraints: &[u8]) -> Self {
let name_constraints = rcgen_name_constraints(webpki_name_constraints);
// Create a trust anchor CA certificate that has the name constraints we want to test.
let trust_anchor = {
let mut params = CertificateParams::new([]).unwrap();
params
.distinguished_name
.push(DnType::CommonName, "Name Constraint Test CA");
params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained);
params.key_usages = vec![
KeyUsagePurpose::KeyCertSign,
KeyUsagePurpose::DigitalSignature,
];
params.name_constraints = Some(name_constraints.clone());
let key = KeyPair::generate().unwrap();
CertifiedIssuer::self_signed(params, key).unwrap()
};
let certs_for_subtrees = |suffix| {
name_constraints
.permitted_subtrees
.iter()
.filter_map(|subtree| match subtree {
rcgen::GeneralSubtree::DnsName(dns_name) => Some(rcgen_ee_for_name(
format!("valid{dns_name}{suffix}"),
&trust_anchor,
)),
_ => None,
})
.collect()
};
Self {
// For each permitted subtree in the name constraints, issue an end entity certificate
// that contains a DNS name matching the permitted subtree base.
permitted_certs: certs_for_subtrees(""),
// For each permitted subtree in the name constraints, issue an end entity certificate
// that contains a DNS name that will **not** match the permitted subtree base.
forbidden_certs: certs_for_subtrees(".invalid"),
trust_anchor: trust_anchor.der().to_owned(),
}
}
}
fn rcgen_ee_for_name(name: String, issuer: &Issuer<'_, KeyPair>) -> CertificateDer<'static> {
let mut ee = CertificateParams::new(vec![name.clone()]).unwrap();
ee.distinguished_name.push(DnType::CommonName, name);
ee.is_ca = IsCa::NoCa;
let key_pair = KeyPair::generate().unwrap();
ee.signed_by(&key_pair, issuer).unwrap().into()
}
/// Convert the webpki trust anchor DER encoding of name constraints to rcgen NameConstraints.
fn rcgen_name_constraints(der: &[u8]) -> rcgen::NameConstraints {
// x509 parser expects the outer SEQUENCE that the webpki trust anchor representation elides
// so wrap the DER up.
let wrapped_der = yasna::construct_der(|writer| {
writer.write_sequence(|writer| {
writer.next().write_der(der);
})
});
// Constraints should parse with no trailing data.
let (trailing, constraints) = X509ParserNameConstraints::from_der(&wrapped_der).unwrap();
assert!(
trailing.is_empty(),
"unexpected trailing DER in name constraint"
);
// There should be at least one permitted subtree.
assert!(
constraints.permitted_subtrees.is_some(),
"empty permitted subtrees in constraints"
);
// We don't expect any excluded subtrees as this time.
assert!(constraints.excluded_subtrees.is_none());
// Collect all of the DNS names from the x509-parser representation, mapping to the rcgen
// representation usable in cert parameters. We don't expect to find any other types of general
// name and x509-parser doesn't parse the subtree minimum and maximum (which we would assert to
// be missing for proper encoding anyway).
let permitted_subtrees = match constraints.permitted_subtrees {
None => Vec::default(),
Some(subtrees) => subtrees
.iter()
.map(|subtree| match &subtree.base {
GeneralName::DNSName(base) => rcgen::GeneralSubtree::DnsName(base.to_string()),
name => panic!("unexpected subtree base general name type: {name}"),
})
.collect(),
};
rcgen::NameConstraints {
permitted_subtrees,
excluded_subtrees: Vec::default(),
}
}
#[test]
fn tubitak_name_constraint_works() {
let root = CertificateDer::from(&include_bytes!("data/tubitak/root.der")[..]);
let inter = CertificateDer::from(&include_bytes!("data/tubitak/inter.der")[..]);
let subj = CertificateDer::from(&include_bytes!("data/tubitak/subj.der")[..]);
let roots = [anchor_from_trusted_cert(&root).unwrap().to_owned()];
let now = UnixTime::since_unix_epoch(Duration::from_secs(1493668479));
let cert = EndEntityCert::try_from(&subj).unwrap();
cert.verify_for_usage(
ALL_ALGORITHMS,
&roots,
&[inter, root],
now,
KeyUsage::server_auth(),
None,
None,
)
.unwrap();
let subject = ServerName::try_from("testssl.kamusm.gov.tr").unwrap();
cert.verify_is_valid_for_subject_name(&subject).unwrap();
}
static ALL_ALGORITHMS: &[&dyn SignatureVerificationAlgorithm] = &[
webpki::aws_lc_rs::ECDSA_P256_SHA256,
webpki::aws_lc_rs::ECDSA_P256_SHA384,
webpki::aws_lc_rs::ECDSA_P384_SHA256,
webpki::aws_lc_rs::ECDSA_P384_SHA384,
webpki::aws_lc_rs::RSA_PKCS1_2048_8192_SHA256,
webpki::aws_lc_rs::RSA_PKCS1_2048_8192_SHA384,
webpki::aws_lc_rs::RSA_PKCS1_2048_8192_SHA512,
webpki::aws_lc_rs::RSA_PKCS1_3072_8192_SHA384,
webpki::aws_lc_rs::RSA_PSS_2048_8192_SHA256_LEGACY_KEY,
webpki::aws_lc_rs::RSA_PSS_2048_8192_SHA384_LEGACY_KEY,
webpki::aws_lc_rs::RSA_PSS_2048_8192_SHA512_LEGACY_KEY,
];