From 0ce554c329825beffcdf12920905bd6c20170fc0 Mon Sep 17 00:00:00 2001 From: Erik Hollensbe Date: Tue, 22 Feb 2022 11:55:19 -0800 Subject: [PATCH] initial commit w/ linux injector Signed-off-by: Erik Hollensbe --- .gitignore | 2 ++ Cargo.toml | 9 +++++ src/lib.rs | 27 +++++++++++++++ src/linux.rs | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 133 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 src/lib.rs create mode 100644 src/linux.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..96ef6c0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +Cargo.lock diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..260599a --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "ca_injector" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +anyhow = "^1" diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..9302d5d --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,27 @@ +#[cfg(target_os = "linux")] +mod linux; + +pub fn install_ca(filename: &str) -> Result<(), anyhow::Error> { + #[cfg(target_os = "linux")] + return crate::linux::install_ca(filename); + + #[cfg(not(target_os = "linux"))] + Err(anyhow::anyhow!( + "Unable to install CA certificate '{}' on this platform", + filename + )) +} + +pub fn uninstall_ca(filename: &str) -> Result<(), anyhow::Error> { + #[cfg(target_os = "linux")] + return crate::linux::uninstall_ca(filename); + + #[cfg(not(target_os = "linux"))] + Err(anyhow::anyhow!( + "Unable to uninstall CA certificate '{}' on this platform", + filename + )) +} + +#[cfg(test)] +mod tests {} diff --git a/src/linux.rs b/src/linux.rs new file mode 100644 index 0000000..857c3ad --- /dev/null +++ b/src/linux.rs @@ -0,0 +1,95 @@ +use std::{path::PathBuf, str::FromStr}; + +use anyhow::anyhow; + +#[derive(Debug, Clone)] +struct TrustStoreMetadata { + dir: &'static str, + bin: &'static str, + args: Vec<&'static str>, +} + +fn get_trust_store_command() -> Result { + if let Ok(md) = std::fs::metadata("/etc/pki/ca-trust/source/anchors") { + if md.is_dir() { + return Ok(TrustStoreMetadata { + dir: "/etc/pki/ca-trust/source/anchors", + bin: "update-ca-trust", + args: vec!["extract"], + }); + } + } + + if let Ok(md) = std::fs::metadata("/usr/local/share/ca-certificates") { + if md.is_dir() { + return Ok(TrustStoreMetadata { + dir: "/usr/local/share/ca-certificates", + bin: "update-ca-certificates", + args: vec![], + }); + } + } + + if let Ok(md) = std::fs::metadata("/etc/ca-certificates/trust-source/anchors") { + if md.is_dir() { + return Ok(TrustStoreMetadata { + dir: "/etc/ca-certificates/trust-source/anchors", + bin: "trust", + args: vec!["extract-compat"], + }); + } + } + + if let Ok(md) = std::fs::metadata("/usr/share/pki/trust/anchors") { + if md.is_dir() { + return Ok(TrustStoreMetadata { + dir: "/usr/share/pki/trust/anchors", + bin: "update-ca-certificates", + args: vec![], + }); + } + } + + Err(anyhow!("CA location could not be determined")) +} + +fn template_filename(filename: &str, tsc: &TrustStoreMetadata) -> Result { + let pb = PathBuf::from_str(tsc.dir)?; + Ok(pb.join(filename.replace(" ", "_").replace(".crt", ".pem"))) +} + +fn update(tsc: &TrustStoreMetadata) -> Result { + Ok(std::process::Command::new(tsc.bin) + .args(tsc.args.clone()) + .env_clear() + .stdin(std::process::Stdio::null()) + .stdout(std::process::Stdio::null()) + .stderr(std::process::Stdio::null()) + .status()?) +} + +pub fn install_ca(filename: &str) -> Result<(), anyhow::Error> { + let tsc = get_trust_store_command()?; + std::fs::copy(filename, template_filename(filename, &tsc)?)?; + + let res = update(&tsc)?; + + if !res.success() { + return Err(anyhow!("Unable to install CA certificate")); + } + + Ok(()) +} + +pub fn uninstall_ca(filename: &str) -> Result<(), anyhow::Error> { + let tsc = get_trust_store_command()?; + std::fs::remove_file(template_filename(filename, &tsc)?)?; + + let res = update(&tsc)?; + + if !res.success() { + return Err(anyhow!("Unable to uninstall CA certificate")); + } + + Ok(()) +}