Add fallback trust source installation and improve code formatting
This commit is contained in:
+83
-25
@@ -11,7 +11,6 @@ use std::path::{Path, PathBuf};
|
|||||||
use std::process::{Command, Stdio};
|
use std::process::{Command, Stdio};
|
||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
// Default paths mirror the p11-kit / update-ca-trust layout used by this system.
|
|
||||||
const DEFAULT_ROOT: &str = "/";
|
const DEFAULT_ROOT: &str = "/";
|
||||||
const DEFAULT_ANCHORS_DIR: &str = "/etc/ca-certificates/trust-source/anchors";
|
const DEFAULT_ANCHORS_DIR: &str = "/etc/ca-certificates/trust-source/anchors";
|
||||||
const DEFAULT_EXTRACTED_DIR: &str = "/etc/ca-certificates/extracted";
|
const DEFAULT_EXTRACTED_DIR: &str = "/etc/ca-certificates/extracted";
|
||||||
@@ -20,7 +19,6 @@ const DEFAULT_SSL_CERT_PEM_LINK: &str = "/etc/ssl/cert.pem";
|
|||||||
const DEFAULT_SSL_CA_CERTIFICATES_BUNDLE_LINK: &str = "/etc/ssl/certs/ca-certificates.crt";
|
const DEFAULT_SSL_CA_CERTIFICATES_BUNDLE_LINK: &str = "/etc/ssl/certs/ca-certificates.crt";
|
||||||
const DEFAULT_SSL_CA_BUNDLE_CRT_LINK: &str = "/etc/ssl/certs/ca-bundle.crt";
|
const DEFAULT_SSL_CA_BUNDLE_CRT_LINK: &str = "/etc/ssl/certs/ca-bundle.crt";
|
||||||
const DEFAULT_JAVA_CACERTS_LINK: &str = "/etc/ssl/certs/java/cacerts";
|
const DEFAULT_JAVA_CACERTS_LINK: &str = "/etc/ssl/certs/java/cacerts";
|
||||||
// BLFS make-ca compatibility paths (commonly used by OpenSSL/libgit2 builds on LFS).
|
|
||||||
const DEFAULT_PKI_TLS_CA_BUNDLE_CRT_LINK: &str = "/etc/pki/tls/certs/ca-bundle.crt";
|
const DEFAULT_PKI_TLS_CA_BUNDLE_CRT_LINK: &str = "/etc/pki/tls/certs/ca-bundle.crt";
|
||||||
const DEFAULT_PKI_TLS_CA_BUNDLE_TRUST_CRT_LINK: &str = "/etc/pki/tls/certs/ca-bundle.trust.crt";
|
const DEFAULT_PKI_TLS_CA_BUNDLE_TRUST_CRT_LINK: &str = "/etc/pki/tls/certs/ca-bundle.trust.crt";
|
||||||
const DEFAULT_PKI_TLS_JAVA_CACERTS_LINK: &str = "/etc/pki/tls/java/cacerts";
|
const DEFAULT_PKI_TLS_JAVA_CACERTS_LINK: &str = "/etc/pki/tls/java/cacerts";
|
||||||
@@ -29,9 +27,11 @@ const DEFAULT_CERTDATA_URL: &str =
|
|||||||
const DEFAULT_CERTDATA_OUTPUT: &str = "certdata.txt";
|
const DEFAULT_CERTDATA_OUTPUT: &str = "certdata.txt";
|
||||||
const DEFAULT_MOZILLA_TRUST_P11KIT: &str =
|
const DEFAULT_MOZILLA_TRUST_P11KIT: &str =
|
||||||
"/usr/share/ca-certificates/trust-source/mozilla.trust.p11-kit";
|
"/usr/share/ca-certificates/trust-source/mozilla.trust.p11-kit";
|
||||||
|
const DEFAULT_ETC_MOZILLA_TRUST_P11KIT: &str =
|
||||||
|
"/etc/ca-certificates/trust-source/mozilla.trust.p11-kit";
|
||||||
const DEFAULT_PKI_MOZILLA_TRUST_P11KIT: &str = "/etc/pki/anchors/mozilla.trust.p11-kit";
|
const DEFAULT_PKI_MOZILLA_TRUST_P11KIT: &str = "/etc/pki/anchors/mozilla.trust.p11-kit";
|
||||||
// make-ca uses a pinned ISRG Root X1 to bootstrap downloads from hg.mozilla.org
|
const DEFAULT_PKI_CA_TRUST_SOURCE_MOZILLA_TRUST_P11KIT: &str =
|
||||||
// before the local trust store exists. We do the same for certdata fetch/sync.
|
"/etc/pki/ca-trust/source/mozilla.trust.p11-kit";
|
||||||
const MOZILLA_HG_BOOTSTRAP_ROOT_PEM: &str = r#"-----BEGIN CERTIFICATE-----
|
const MOZILLA_HG_BOOTSTRAP_ROOT_PEM: &str = r#"-----BEGIN CERTIFICATE-----
|
||||||
MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw
|
MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw
|
||||||
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
|
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
|
||||||
@@ -517,11 +517,17 @@ fn resolve_sync_certdata_output(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if dry_run {
|
if dry_run {
|
||||||
return Ok((build_sync_tmp_workspace_path(0).join(DEFAULT_CERTDATA_OUTPUT), None));
|
return Ok((
|
||||||
|
build_sync_tmp_workspace_path(0).join(DEFAULT_CERTDATA_OUTPUT),
|
||||||
|
None,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let workspace = create_sync_tmp_workspace_dir()?;
|
let workspace = create_sync_tmp_workspace_dir()?;
|
||||||
println!("Using temporary certdata workspace: {}", workspace.display());
|
println!(
|
||||||
|
"Using temporary certdata workspace: {}",
|
||||||
|
workspace.display()
|
||||||
|
);
|
||||||
Ok((
|
Ok((
|
||||||
workspace.join(DEFAULT_CERTDATA_OUTPUT),
|
workspace.join(DEFAULT_CERTDATA_OUTPUT),
|
||||||
Some(TempWorkspaceCleanup { path: workspace }),
|
Some(TempWorkspaceCleanup { path: workspace }),
|
||||||
@@ -858,8 +864,7 @@ fn write_bootstrap_ca_tempfile() -> Result<PathBuf> {
|
|||||||
"{}{}",
|
"{}{}",
|
||||||
MOZILLA_HG_BOOTSTRAP_ROOT_PEM, MOZILLA_HG_BOOTSTRAP_DIGICERT_G2_ROOT_PEM
|
MOZILLA_HG_BOOTSTRAP_ROOT_PEM, MOZILLA_HG_BOOTSTRAP_DIGICERT_G2_ROOT_PEM
|
||||||
);
|
);
|
||||||
fs::write(&path, bundle)
|
fs::write(&path, bundle).with_context(|| format!("failed to write {}", path.display()))?;
|
||||||
.with_context(|| format!("failed to write {}", path.display()))?;
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
{
|
{
|
||||||
fs::set_permissions(&path, fs::Permissions::from_mode(0o600))
|
fs::set_permissions(&path, fs::Permissions::from_mode(0o600))
|
||||||
@@ -1091,6 +1096,7 @@ fn run_certdata_convert(args: CertdataConvertArgs) -> Result<()> {
|
|||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let mut rendered_p11kit: Option<String> = None;
|
||||||
if args.dry_run {
|
if args.dry_run {
|
||||||
if let Some(parsed) = &parsed {
|
if let Some(parsed) = &parsed {
|
||||||
let (certs, trusts) = count_cert_and_trust_objects(parsed);
|
let (certs, trusts) = count_cert_and_trust_objects(parsed);
|
||||||
@@ -1100,17 +1106,20 @@ fn run_certdata_convert(args: CertdataConvertArgs) -> Result<()> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
println!("[dry-run] Would write {}", output_host.display());
|
println!("[dry-run] Would write {}", output_host.display());
|
||||||
if should_write_make_ca_mirror(&args.root, &output_target) {
|
let fallback_targets = detect_trust_source_fallback_targets(&args.root, &output_target);
|
||||||
|
if !fallback_targets.is_empty() {
|
||||||
println!(
|
println!(
|
||||||
"[dry-run] Would also write BLFS make-ca compatibility source {}",
|
"[dry-run] If extraction is empty, would retry after installing compatibility trust source(s):"
|
||||||
path_in_root(&args.root, Path::new(DEFAULT_PKI_MOZILLA_TRUST_P11KIT)).display()
|
|
||||||
);
|
);
|
||||||
|
for target in fallback_targets {
|
||||||
|
println!(" - {}", path_in_root(&args.root, &target).display());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let parsed = parsed.context("certdata parse result missing")?;
|
let parsed = parsed.context("certdata parse result missing")?;
|
||||||
let p11kit = convert_certdata_to_p11kit_bundle(&parsed)?;
|
let p11kit = convert_certdata_to_p11kit_bundle(&parsed)?;
|
||||||
install_file(&output_host, p11kit.as_bytes(), args.force, false)?;
|
install_file(&output_host, p11kit.as_bytes(), args.force, false)?;
|
||||||
maybe_install_make_ca_mozilla_mirror(&args.root, &output_target, &p11kit, args.force)?;
|
rendered_p11kit = Some(p11kit);
|
||||||
}
|
}
|
||||||
|
|
||||||
if args.no_extract {
|
if args.no_extract {
|
||||||
@@ -1123,33 +1132,75 @@ fn run_certdata_convert(args: CertdataConvertArgs) -> Result<()> {
|
|||||||
.unwrap_or_else(|| PathBuf::from(DEFAULT_EXTRACTED_DIR));
|
.unwrap_or_else(|| PathBuf::from(DEFAULT_EXTRACTED_DIR));
|
||||||
extract_trust(&args.root, &extract_output, args.dry_run)?;
|
extract_trust(&args.root, &extract_output, args.dry_run)?;
|
||||||
if !args.dry_run {
|
if !args.dry_run {
|
||||||
|
if let Err(err) = ensure_nonempty_extraction_outputs(&args.root, &extract_output) {
|
||||||
|
let Some(p11kit) = rendered_p11kit.as_deref() else {
|
||||||
|
return Err(err);
|
||||||
|
};
|
||||||
|
let fallback_installs =
|
||||||
|
install_fallback_trust_sources(&args.root, &output_target, p11kit, args.force)?;
|
||||||
|
if fallback_installs == 0 {
|
||||||
|
return Err(err);
|
||||||
|
}
|
||||||
|
println!("Retrying trust extraction after installing compatibility trust source(s).");
|
||||||
|
extract_trust(&args.root, &extract_output, false)?;
|
||||||
ensure_nonempty_extraction_outputs(&args.root, &extract_output)?;
|
ensure_nonempty_extraction_outputs(&args.root, &extract_output)?;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
println!("certdata conversion and extraction complete.");
|
println!("certdata conversion and extraction complete.");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_write_make_ca_mirror(root: &Path, output_target: &Path) -> bool {
|
fn detect_trust_source_fallback_targets(_root: &Path, output_target: &Path) -> Vec<PathBuf> {
|
||||||
output_target == Path::new(DEFAULT_MOZILLA_TRUST_P11KIT)
|
if output_target != Path::new(DEFAULT_MOZILLA_TRUST_P11KIT) {
|
||||||
&& path_in_root(root, Path::new("/etc/pki")).exists()
|
return Vec::new();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn maybe_install_make_ca_mozilla_mirror(
|
let mut targets = Vec::new();
|
||||||
|
let fallback_candidates = [
|
||||||
|
DEFAULT_ETC_MOZILLA_TRUST_P11KIT,
|
||||||
|
DEFAULT_PKI_MOZILLA_TRUST_P11KIT,
|
||||||
|
DEFAULT_PKI_CA_TRUST_SOURCE_MOZILLA_TRUST_P11KIT,
|
||||||
|
];
|
||||||
|
let output_target = output_target.to_path_buf();
|
||||||
|
for candidate in fallback_candidates {
|
||||||
|
let candidate_path = PathBuf::from(candidate);
|
||||||
|
if candidate_path == output_target || targets.contains(&candidate_path) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// Always include fallback paths; install_file() will create parent dirs.
|
||||||
|
// Some chroots do not have /etc/pki* until later packages are installed.
|
||||||
|
targets.push(candidate_path);
|
||||||
|
}
|
||||||
|
targets
|
||||||
|
}
|
||||||
|
|
||||||
|
fn install_fallback_trust_sources(
|
||||||
root: &Path,
|
root: &Path,
|
||||||
output_target: &Path,
|
output_target: &Path,
|
||||||
p11kit: &str,
|
p11kit: &str,
|
||||||
force: bool,
|
force: bool,
|
||||||
) -> Result<()> {
|
) -> Result<usize> {
|
||||||
if !should_write_make_ca_mirror(root, output_target) {
|
let mut installed = 0usize;
|
||||||
return Ok(());
|
let targets = detect_trust_source_fallback_targets(root, output_target);
|
||||||
|
if targets.is_empty() {
|
||||||
|
return Ok(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mirror_host = path_in_root(root, Path::new(DEFAULT_PKI_MOZILLA_TRUST_P11KIT));
|
for target in targets {
|
||||||
|
let mirror_host = path_in_root(root, &target);
|
||||||
println!(
|
println!(
|
||||||
"Installing BLFS make-ca compatibility trust source: {}",
|
"Installing compatibility trust source: {}",
|
||||||
mirror_host.display()
|
mirror_host.display()
|
||||||
);
|
);
|
||||||
install_file(&mirror_host, p11kit.as_bytes(), force, false)
|
match install_file(&mirror_host, p11kit.as_bytes(), force, false) {
|
||||||
|
Ok(()) => installed += 1,
|
||||||
|
Err(err) => eprintln!(
|
||||||
|
"warning: unable to install compatibility trust source {}: {err}",
|
||||||
|
mirror_host.display()
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(installed)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ensure_nonempty_extraction_outputs(root: &Path, extract_output: &Path) -> Result<()> {
|
fn ensure_nonempty_extraction_outputs(root: &Path, extract_output: &Path) -> Result<()> {
|
||||||
@@ -2317,7 +2368,8 @@ CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
|
|||||||
#[test]
|
#[test]
|
||||||
fn sync_certdata_output_respects_explicit_path() {
|
fn sync_certdata_output_respects_explicit_path() {
|
||||||
let requested = PathBuf::from("/var/tmp/custom-certdata.txt");
|
let requested = PathBuf::from("/var/tmp/custom-certdata.txt");
|
||||||
let (resolved, cleanup) = resolve_sync_certdata_output(Some(requested.clone()), false).unwrap();
|
let (resolved, cleanup) =
|
||||||
|
resolve_sync_certdata_output(Some(requested.clone()), false).unwrap();
|
||||||
assert_eq!(resolved, requested);
|
assert_eq!(resolved, requested);
|
||||||
assert!(cleanup.is_none());
|
assert!(cleanup.is_none());
|
||||||
}
|
}
|
||||||
@@ -2326,7 +2378,10 @@ CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
|
|||||||
fn sync_certdata_output_uses_tmp_workspace_and_cleans_it() {
|
fn sync_certdata_output_uses_tmp_workspace_and_cleans_it() {
|
||||||
let (resolved, cleanup) = resolve_sync_certdata_output(None, false).unwrap();
|
let (resolved, cleanup) = resolve_sync_certdata_output(None, false).unwrap();
|
||||||
assert!(resolved.starts_with(Path::new("/tmp")));
|
assert!(resolved.starts_with(Path::new("/tmp")));
|
||||||
assert_eq!(resolved.file_name(), Some(OsStr::new(DEFAULT_CERTDATA_OUTPUT)));
|
assert_eq!(
|
||||||
|
resolved.file_name(),
|
||||||
|
Some(OsStr::new(DEFAULT_CERTDATA_OUTPUT))
|
||||||
|
);
|
||||||
let workspace = resolved.parent().unwrap().to_path_buf();
|
let workspace = resolved.parent().unwrap().to_path_buf();
|
||||||
assert!(workspace.exists());
|
assert!(workspace.exists());
|
||||||
|
|
||||||
@@ -2338,7 +2393,10 @@ CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUSTED_DELEGATOR
|
|||||||
fn sync_certdata_output_dry_run_uses_tmp_path_without_creating_workspace() {
|
fn sync_certdata_output_dry_run_uses_tmp_path_without_creating_workspace() {
|
||||||
let (resolved, cleanup) = resolve_sync_certdata_output(None, true).unwrap();
|
let (resolved, cleanup) = resolve_sync_certdata_output(None, true).unwrap();
|
||||||
assert!(resolved.starts_with(Path::new("/tmp")));
|
assert!(resolved.starts_with(Path::new("/tmp")));
|
||||||
assert_eq!(resolved.file_name(), Some(OsStr::new(DEFAULT_CERTDATA_OUTPUT)));
|
assert_eq!(
|
||||||
|
resolved.file_name(),
|
||||||
|
Some(OsStr::new(DEFAULT_CERTDATA_OUTPUT))
|
||||||
|
);
|
||||||
assert!(cleanup.is_none());
|
assert!(cleanup.is_none());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user