made some stuff work

Signed-off-by: Erik Hollensbe <git@hollensbe.org>
This commit is contained in:
Erik Hollensbe
2022-02-28 01:33:39 -08:00
parent 0ce554c329
commit f56e54565c
8 changed files with 198 additions and 14 deletions
+3
View File
@@ -0,0 +1,3 @@
/target
/.cargo
/.rustup
+2
View File
@@ -1,2 +1,4 @@
/target
Cargo.lock
/.cargo
/.rustup
+9
View File
@@ -7,3 +7,12 @@ edition = "2021"
[dependencies]
anyhow = "^1"
which = "^4"
glob = "^0.3"
log = "^0.4"
[dev-dependencies]
coyote = "*"
openssl = "*"
tempdir = "*"
env_logger = "*"
+10
View File
@@ -0,0 +1,10 @@
# vim: ft=dockerfile
FROM debian:latest
RUN apt-get update -qq && apt-get install curl libnss3-tools build-essential libssl-dev pkg-config ca-certificates -y
COPY hack/rustup.sh /bin
RUN chmod 755 /bin/rustup.sh
CMD ["bash", "-c", "source /bin/rustup.sh && cd /root/ca_injector && cargo test -- --nocapture"]
+9
View File
@@ -0,0 +1,9 @@
DOCKER_IMAGE=ca-injector-test
DOCKER_RUN=docker run -e RUST_BACKTRACE=full -it --rm -v ${PWD}:/root/ca_injector -v ${PWD}/.rustup:/root/.rustup -v ${PWD}/.cargo:/root/.cargo ${DOCKER_IMAGE}
test: build
mkdir -p .cargo .rustup
${DOCKER_RUN}
build:
docker build -t ${DOCKER_IMAGE} .
+13
View File
@@ -0,0 +1,13 @@
#!/bin/bash
if [ ! -x $HOME/.cargo/bin/rustup ]
then
curl -sSL sh.rustup.rs >/tmp/rustup.sh && bash /tmp/rustup.sh -y
fi
if [ -f $HOME/.cargo/env ]
then
. $HOME/.cargo/env
fi
rustup default stable
-3
View File
@@ -22,6 +22,3 @@ pub fn uninstall_ca(filename: &str) -> Result<(), anyhow::Error> {
filename
))
}
#[cfg(test)]
mod tests {}
+152 -11
View File
@@ -1,8 +1,103 @@
use std::{path::PathBuf, str::FromStr};
use std::{
path::{Path, PathBuf},
str::FromStr,
};
use anyhow::anyhow;
use glob::glob;
use which::which;
fn certutil() -> Result<PathBuf, anyhow::Error> {
Ok(which("certutil")?)
}
fn nssdbs() -> Result<Vec<PathBuf>, anyhow::Error> {
let home_var = std::env::var("HOME").unwrap_or("/".to_string());
let home = Path::new(home_var.as_str());
// append all firefox profiles on the machine for the given user
// FIXME might want to enumerate all firefox profiles on the whole machine later
let mut paths = glob(home.join(".mozilla/firefox/*").to_str().unwrap())?
.map(|p| p.unwrap())
.collect::<Vec<PathBuf>>();
let mut other_paths = vec![
home.join(".pki/nssdb"),
home.join("snap/chromium/current/.pki/nssdb"),
PathBuf::from_str("/etc/pki/nssdb")?,
];
paths.append(&mut other_paths);
Ok(paths)
}
fn install_nss(filename: &str) -> Result<(), anyhow::Error> {
let certutil = certutil()?;
for db in nssdbs()? {
match db.metadata() {
Ok(meta) => {
if meta.is_dir() {
log::debug!(
"Running certutil for {} against {} to install the cert",
db.display(),
filename
);
std::process::Command::new(certutil.clone())
.args(vec![
"-A",
"-d",
db.to_str().unwrap(),
"-t",
"C,,",
"-n",
filename,
"-i",
filename,
])
.env_clear()
.stdin(std::process::Stdio::null())
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.status()?;
}
}
_ => {}
}
}
Ok(())
}
fn uninstall_nss(filename: &str) -> Result<(), anyhow::Error> {
let certutil = certutil()?;
for db in nssdbs()? {
match db.metadata() {
Ok(meta) => {
if meta.is_dir() {
log::debug!(
"Running certutil for {} against {} to install the cert",
db.display(),
filename
);
std::process::Command::new(certutil.clone())
.args(vec!["-D", "-d", db.to_str().unwrap(), "-n", filename])
.env_clear()
.stdin(std::process::Stdio::null())
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.status()?;
}
}
_ => {}
}
}
Ok(())
}
#[derive(Debug, Clone)]
struct TrustStoreMetadata {
dir: &'static str,
bin: &'static str,
@@ -24,7 +119,7 @@ fn get_trust_store_command() -> Result<TrustStoreMetadata, anyhow::Error> {
if md.is_dir() {
return Ok(TrustStoreMetadata {
dir: "/usr/local/share/ca-certificates",
bin: "update-ca-certificates",
bin: "/usr/sbin/update-ca-certificates",
args: vec![],
});
}
@@ -55,13 +150,21 @@ fn get_trust_store_command() -> Result<TrustStoreMetadata, anyhow::Error> {
fn template_filename(filename: &str, tsc: &TrustStoreMetadata) -> Result<PathBuf, anyhow::Error> {
let pb = PathBuf::from_str(tsc.dir)?;
Ok(pb.join(filename.replace(" ", "_").replace(".crt", ".pem")))
Ok(pb.join(
Path::new(filename)
.file_name()
.unwrap()
.to_string_lossy()
.replace(" ", "_")
.replace(".pem", ".crt"),
))
}
fn update(tsc: &TrustStoreMetadata) -> Result<std::process::ExitStatus, anyhow::Error> {
fn update_ca(tsc: &TrustStoreMetadata) -> Result<std::process::ExitStatus, anyhow::Error> {
log::debug!("Executing {} {:?}", tsc.bin, tsc.args);
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())
@@ -70,26 +173,64 @@ fn update(tsc: &TrustStoreMetadata) -> Result<std::process::ExitStatus, anyhow::
pub fn install_ca(filename: &str) -> Result<(), anyhow::Error> {
let tsc = get_trust_store_command()?;
std::fs::copy(filename, template_filename(filename, &tsc)?)?;
let new_filename = template_filename(filename, &tsc)?;
let res = update(&tsc)?;
log::debug!(
"copying cert from {} to {}",
filename.to_string(),
new_filename.display()
);
std::fs::copy(filename, new_filename)?;
let res = update_ca(&tsc)?;
if !res.success() {
return Err(anyhow!("Unable to install CA certificate"));
}
Ok(())
Ok(install_nss(filename)?)
}
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)?;
let res = update_ca(&tsc)?;
if !res.success() {
return Err(anyhow!("Unable to uninstall CA certificate"));
}
Ok(())
Ok(uninstall_nss(filename)?)
}
#[cfg(test)]
mod tests {
use tempdir::TempDir;
#[test]
fn test_install() {
env_logger::builder()
.filter_level(log::LevelFilter::Debug)
.init();
use coyote::acme::ca::CA;
for filename in vec![
"test.pem",
"file with spaces.pem",
"certificate.crt",
"this_other_thing.crt",
] {
let ca = CA::new_test_ca().unwrap();
let dir = TempDir::new("").unwrap();
let test_pem = dir.path().join(filename);
std::fs::write(test_pem.clone(), ca.certificate().to_pem().unwrap()).unwrap();
super::install_ca(test_pem.to_str().unwrap()).unwrap();
super::uninstall_ca(test_pem.to_str().unwrap()).unwrap();
}
}
}