Browse Source

feat: install_cert support linux

Signed-off-by: zu1k <[email protected]>
zu1k 3 years ago
parent
commit
6384cff251

+ 14 - 2
Cargo.lock

@@ -1092,6 +1092,18 @@ dependencies = [
  "tempfile",
 ]
 
+[[package]]
+name = "nix"
+version = "0.25.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e322c04a9e3440c327fca7b6c8a63e6890a32fa2ad689db972425f07e0d22abb"
+dependencies = [
+ "autocfg",
+ "bitflags",
+ "cfg-if",
+ "libc",
+]
+
 [[package]]
 name = "nom"
 version = "7.1.1"
@@ -1921,10 +1933,10 @@ checksum = "f1ee9bd9239c339d714d657fac840c6d2a4f9c45f4f9ec7b0975113458be78db"
 
 [[package]]
 name = "trust_cert"
-version = "0.0.1"
+version = "0.0.2"
 dependencies = [
  "cfg-if",
- "libc",
+ "nix",
  "rcgen",
  "windows",
 ]

+ 2 - 2
crates/trust_cert/Cargo.toml

@@ -1,6 +1,6 @@
 [package]
 name = "trust_cert"
-version = "0.0.1"
+version = "0.0.2"
 edition = "2021"
 
 [dependencies]
@@ -8,7 +8,7 @@ cfg-if = "1"
 rcgen = { version = "0.9", features = ["x509-parser"] }
 
 [target.'cfg(unix)'.dependencies]
-libc = "0.2"
+nix = { version = "0.25", default-features = false, features = ["user"] }
 
 [target.'cfg(windows)'.dependencies]
 windows = { version = "0.39", features = ["Win32_Security_Cryptography", "Win32_Foundation"] }

+ 2 - 3
crates/trust_cert/src/lib.rs

@@ -10,10 +10,9 @@ mod linux;
 pub fn trust_cert(cert: Certificate) {
     cfg_if::cfg_if! {
         if #[cfg(windows)] {
-            windows::install_cert(cert.serialize_der().unwrap());
+            windows::install_cert(cert);
         } else  if #[cfg(target_os = "linux")]  {
-            todo!()
-            // linux::install_cert();
+            linux::install_cert(cert);
         } else {
             panic!("not implemented on this target")
         }

+ 45 - 43
crates/trust_cert/src/linux.rs

@@ -1,61 +1,62 @@
-use std::{env, fs, io::Write, path::Path, process::Command};
+use nix::unistd::getegid;
+use rcgen::Certificate;
+use std::{env, fs, path::Path, process::Command};
 
-pub fn install_cert() {
-    let (system_trust_filename, system_trust_cmd) = {
+pub fn install_cert(cert: Certificate) {
+    if getegid().as_raw() != 0 {
+        println!("Please run with root permission");
+        return;
+    }
+
+    let (system_trust_filename, trust_cmd, trust_cmd_args) = {
         if path_exist("/etc/pki/ca-trust/source/anchors/") {
             (
                 "/etc/pki/ca-trust/source/anchors/{cert-name}.pem",
-                vec!["update-ca-trust", "extract"],
+                "update-ca-trust",
+                vec!["extract"],
             )
         } else if path_exist("/usr/local/share/ca-certificates/") {
             (
                 "/usr/local/share/ca-certificates/{cert-name}.crt",
-                vec!["update-ca-certificates"],
+                "update-ca-certificates",
+                vec![],
             )
         } else if path_exist("/etc/ca-certificates/trust-source/anchors/") {
             (
                 "/etc/ca-certificates/trust-source/anchors/{cert-name}.crt",
-                vec!["trust", "extract-compat"],
+                "trust",
+                vec!["extract-compat"],
             )
         } else if path_exist("/usr/share/pki/trust/anchors") {
             (
                 "/usr/share/pki/trust/anchors/{cert-name}.pem",
-                vec!["update-ca-certificates"],
+                "update-ca-certificates",
+                vec![],
             )
         } else {
-            (
-                "/etc/pki/ca-trust/source/anchors/{cert-name}.pem",
-                vec!["update-ca-trust", "extract"],
-            )
+            ("good-mitm.pem", "", vec![])
         }
     };
 
-    let cert = Path::new(&get_ca_root()).join("mitm-vip-unlocker.pem");
-    let cert = fs::read(cert).unwrap();
-
-    let system_trust_name = system_trust_filename.replace("{cert-name}", "mitm-vip-unlocker");
-    let mut cmd = cmd_with_sudo(vec!["tee", &system_trust_name])
-        .spawn()
-        .unwrap();
-    let stdin = cmd.stdin.as_mut().unwrap();
-    stdin.write_all(&cert).unwrap();
+    let cert = cert.serialize_pem().expect("serialize cert to pem format");
+    let system_trust_name = system_trust_filename.replace("{cert-name}", "good-mitm");
+    fs::write(system_trust_name, cert).expect("write cert to system trust ca location");
 
-    cmd_with_sudo(system_trust_cmd).status().unwrap();
-}
-
-fn cmd_with_sudo(cmd: Vec<&str>) -> Command {
-    let mut cmd = cmd;
-    if unsafe { libc::getegid() } == 0 {
-        let mut command = Command::new(cmd[0]);
-        command.args(&cmd[1..]);
-        return command;
+    if trust_cmd.is_empty() {
+        println!(
+            "Installing to the system store is not yet supported on this Linux 😣 but Firefox and/or Chrome/Chromium will still work.",
+        );
+        let cert_path = Path::new(&get_ca_root()).join("good-mitm.pem");
+        println!(
+            "You can also manually install the root certificate at {}.",
+            cert_path.to_str().unwrap()
+        );
+    } else {
+        Command::new(trust_cmd)
+            .args(trust_cmd_args)
+            .status()
+            .expect("failed to execute trust command");
     }
-
-    let mut sudo_cmd = vec!["--prompt=Sudo password:", "--"];
-    sudo_cmd.append(&mut cmd);
-    let mut command = Command::new("sudo");
-    command.args(&sudo_cmd);
-    command
 }
 
 fn get_ca_root() -> String {
@@ -63,32 +64,33 @@ fn get_ca_root() -> String {
         return v;
     }
 
-    let dir = {
-        if let Ok(v) = env::var("XDG_DATA_HOM") {
+    let mut dir = {
+        if let Ok(v) = env::var("XDG_DATA_HOME") {
             return v;
         }
         if let Ok(v) = env::var("HOME") {
             return Path::new(&v)
                 .join(".local")
                 .join("share")
-                .into_os_string()
-                .into_string()
+                .to_str()
+                .map(|s| s.to_string())
                 .unwrap();
         }
         String::new()
     };
 
-    if dir.is_empty() {
-        String::new()
-    } else {
-        Path::new(&dir)
+    if !dir.is_empty() {
+        dir = Path::new(&dir)
             .join("mitm")
             .into_os_string()
             .into_string()
             .unwrap()
     }
+
+    dir
 }
 
+#[inline]
 fn path_exist(path: &str) -> bool {
     Path::new(path).exists()
 }

+ 2 - 2
crates/trust_cert/src/windows.rs

@@ -6,8 +6,8 @@ use windows::Win32::{
     },
 };
 
-pub fn install_cert(cert: Vec<u8>) {
-    let mut cert = cert;
+pub fn install_cert(cert: Certificate) {
+    let mut cert = cert.serialize_der().unwrap();
     unsafe {
         // get root store
         let store = CertOpenSystemStoreA(0, PSTR(String::from("ROOT\0").as_mut_ptr()));