-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(trust_store): incomplete implementation
- Loading branch information
1 parent
a8ee68f
commit 00fd8f3
Showing
7 changed files
with
247 additions
and
38 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
use openssl::error::ErrorStack; | ||
use std::{error::Error, fmt, io}; | ||
|
||
#[derive(Debug)] | ||
pub enum TrustStoreError { | ||
PEMFileCreationError(io::Error), | ||
PEMEncodingError(ErrorStack), | ||
WriteToFileError(io::Error), | ||
} | ||
|
||
impl fmt::Display for TrustStoreError { | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
match self { | ||
Self::PEMEncodingError(err) => { | ||
write!(f, "Trust Store PEM Encoding Failed: {}", err) | ||
} | ||
Self::PEMFileCreationError(err) => { | ||
write!(f, "Trust Store PEM File creation Failed: {}", err) | ||
} | ||
Self::WriteToFileError(err) => { | ||
write!(f, "Trust Store Writing to PEM file: {}", err) | ||
} | ||
} | ||
} | ||
} | ||
|
||
impl Error for TrustStoreError {} | ||
|
||
#[derive(Debug)] | ||
pub enum NSSStore { | ||
PEMFileCreationError(io::Error), | ||
PEMEncodingError(ErrorStack), | ||
WriteToFileError(io::Error), | ||
CertUtilFailed(String), | ||
NSSProfileNotFound, | ||
} | ||
|
||
impl fmt::Display for NSSStore { | ||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | ||
match self { | ||
Self::CertUtilFailed(desc) => { | ||
write!(f, "Certutil command failed: {}", desc) | ||
} | ||
Self::NSSProfileNotFound => { | ||
write!(f, "NSS Profile Not Found") | ||
} | ||
Self::PEMEncodingError(err) => { | ||
write!(f, "NSS Store PEM Encoding Failed: {}", err) | ||
} | ||
Self::PEMFileCreationError(err) => { | ||
write!(f, "NSS Store PEM File creation Failed: {}", err) | ||
} | ||
Self::WriteToFileError(err) => { | ||
write!(f, "NSS Store Writing to PEM file: {}", err) | ||
} | ||
} | ||
} | ||
} | ||
|
||
impl Error for NSSStore {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,19 @@ | ||
#[cfg(target_os = "windows")] | ||
mod windows; | ||
|
||
#[cfg(target_os = "macos")] | ||
mod macos; | ||
mod errors; | ||
mod nss; | ||
mod nss_profile; | ||
|
||
#[cfg(target_os = "linux")] | ||
mod linux; | ||
|
||
#[cfg(target_os = "macos")] | ||
mod macos; | ||
#[cfg(target_os = "windows")] | ||
pub use self::windows::*; | ||
mod windows; | ||
|
||
#[cfg(target_os = "linux")] | ||
pub use self::linux::*; | ||
#[cfg(target_os = "macos")] | ||
pub use self::macos::*; | ||
#[cfg(target_os = "windows")] | ||
pub use self::windows::*; | ||
|
||
#[cfg(target_os = "linux")] | ||
pub use self::linux::*; | ||
pub use self::nss::*; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
use super::nss_profile::NSSProfile; | ||
use crate::trust_stores::errors::NSSStore; | ||
use openssl::x509::X509; | ||
use std::io::{self, Write}; | ||
use std::path::PathBuf; | ||
use std::{ | ||
fs::{self, File}, | ||
path::Path, | ||
process::Command, | ||
}; | ||
|
||
pub struct NSSValue { | ||
pub certificate: X509, | ||
} | ||
|
||
impl NSSValue { | ||
fn get_available_profile() -> Option<NSSProfile> { | ||
let profiles: [NSSProfile; 3] = [ | ||
NSSProfile::PkiNssdb, | ||
NSSProfile::ChromiumNssdb, | ||
NSSProfile::Firefox, | ||
]; | ||
|
||
for profile in profiles { | ||
if let Some(_path) = profile.get_valid_path() { | ||
return Some(profile); | ||
} | ||
} | ||
|
||
None | ||
} | ||
|
||
pub fn install_certificate(&self) -> Result<(), NSSStore> { | ||
if let Some(profile) = NSSValue::get_available_profile() { | ||
if let Some(path) = profile.get_valid_path() { | ||
println!("Adding certificate to NSS profile: {}", path.display()); | ||
let pem_path: PathBuf = Path::new(&path).join("vanish-root.crt"); | ||
|
||
if let Err(err) = fs::create_dir_all(&path) { | ||
eprintln!( | ||
"Failed to create directory: {}. Error: {}", | ||
path.display(), | ||
err | ||
); | ||
return Err(NSSStore::PEMFileCreationError(err)); | ||
} | ||
|
||
NSSValue::save_cert(&self.certificate, pem_path.to_str().unwrap())?; | ||
NSSValue::run_certutil(&pem_path, &path)?; | ||
} | ||
} else { | ||
eprintln!("No valid NSS profile found."); | ||
return Err(NSSStore::NSSProfileNotFound); | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
||
fn save_cert(cert: &X509, path: &str) -> Result<(), NSSStore> { | ||
let mut file: File = File::create(path).map_err(NSSStore::PEMFileCreationError)?; | ||
file.write_all(&cert.to_pem().map_err(NSSStore::PEMEncodingError)?) | ||
.map_err(NSSStore::WriteToFileError)?; | ||
Ok(()) | ||
} | ||
|
||
fn run_certutil(cert_path: &Path, profile_path: &Path) -> Result<(), NSSStore> { | ||
let status = Command::new("certutil") | ||
.arg("-A") | ||
.arg("-d") | ||
.arg(format!("sql:{}", profile_path.display())) | ||
.arg("-t") | ||
.arg("C,,") | ||
.arg("-n") | ||
.arg("vanish-root") | ||
.arg("-i") | ||
.arg(cert_path) | ||
.status() | ||
.map_err(|err: io::Error| NSSStore::CertUtilFailed(err.to_string()))?; | ||
|
||
if !status.success() { | ||
return Err(NSSStore::CertUtilFailed("certutil command failed".into())); | ||
} | ||
|
||
Ok(()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
use std::path::{Path, PathBuf}; | ||
|
||
pub enum NSSProfile { | ||
PkiNssdb, | ||
ChromiumNssdb, | ||
Firefox, | ||
} | ||
|
||
impl NSSProfile { | ||
pub fn get_valid_path(&self) -> Option<PathBuf> { | ||
match self { | ||
NSSProfile::PkiNssdb => { | ||
let path: PathBuf = dirs::home_dir()?.join(".pki/nssdb"); | ||
if path.exists() { | ||
Some(path) | ||
} else { | ||
None | ||
} | ||
} | ||
NSSProfile::ChromiumNssdb => { | ||
let path: PathBuf = dirs::home_dir()?.join("snap/chromium/current/.pki/nssdb"); | ||
if path.exists() { | ||
Some(path) | ||
} else { | ||
None | ||
} | ||
} | ||
NSSProfile::Firefox => { | ||
let firefox_paths: [&str; 9] = [ | ||
"/usr/bin/firefox", | ||
"/usr/bin/firefox-nightly", | ||
"/usr/bin/firefox-developer-edition", | ||
"/snap/firefox", | ||
"/Applications/Firefox.app", | ||
"/Applications/FirefoxDeveloperEdition.app", | ||
"/Applications/Firefox Developer Edition.app", | ||
"/Applications/Firefox Nightly.app", | ||
"C:\\Program Files\\Mozilla Firefox", | ||
]; | ||
|
||
for path in firefox_paths.iter() { | ||
let profile_path: &Path = Path::new(path); | ||
if profile_path.exists() { | ||
return Some(profile_path.to_path_buf()); | ||
} | ||
} | ||
None | ||
} | ||
} | ||
} | ||
} |