diff --git a/src/cli_args.rs b/src/cli/cli_args.rs similarity index 98% rename from src/cli_args.rs rename to src/cli/cli_args.rs index 4003582..f317fb6 100644 --- a/src/cli_args.rs +++ b/src/cli/cli_args.rs @@ -1,10 +1,10 @@ +use crate::cli::config::*; use crate::*; - use structopt::clap::AppSettings; use structopt::StructOpt; -use failure::_core::fmt::{Display, Error, Formatter}; -use failure::_core::str::FromStr; +use std::fmt::{Display, Error, Formatter}; +use std::str::FromStr; #[derive(Debug, Eq, PartialEq, Clone)] pub struct HexEncoded(pub Vec); @@ -112,7 +112,7 @@ pub struct SecretParameters { env = "FIDO2LUKS_SALT", default_value = "ask" )] - pub salt: InputSalt, + pub salt: SecretInput, /// Script used to obtain passwords, overridden by --interactive flag #[structopt( name = "password-helper", diff --git a/src/config.rs b/src/cli/config.rs similarity index 65% rename from src/config.rs rename to src/cli/config.rs index 28faa69..d2ef46c 100644 --- a/src/config.rs +++ b/src/cli/config.rs @@ -10,33 +10,33 @@ use std::process::Command; use std::str::FromStr; #[derive(Debug, Clone, PartialEq)] -pub enum InputSalt { +pub enum SecretInput { AskPassword, String(String), File { path: PathBuf }, } -impl Default for InputSalt { +impl Default for SecretInput { fn default() -> Self { - InputSalt::AskPassword + SecretInput::AskPassword } } -impl From<&str> for InputSalt { +impl From<&str> for SecretInput { fn from(s: &str) -> Self { let mut parts = s.split(':'); match parts.next() { - Some("ask") | Some("Ask") => InputSalt::AskPassword, - Some("file") => InputSalt::File { + Some("ask") | Some("Ask") => SecretInput::AskPassword, + Some("file") => SecretInput::File { path: parts.collect::>().join(":").into(), }, - Some("string") => InputSalt::String(parts.collect::>().join(":")), + Some("string") => SecretInput::String(parts.collect::>().join(":")), _ => Self::default(), } } } -impl FromStr for InputSalt { +impl FromStr for SecretInput { type Err = Fido2LuksError; fn from_str(s: &str) -> Result { @@ -44,21 +44,42 @@ impl FromStr for InputSalt { } } -impl fmt::Display for InputSalt { +impl fmt::Display for SecretInput { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { f.write_str(&match self { - InputSalt::AskPassword => "ask".to_string(), - InputSalt::String(s) => ["string", s].join(":"), - InputSalt::File { path } => ["file", path.display().to_string().as_str()].join(":"), + SecretInput::AskPassword => "ask".to_string(), + SecretInput::String(s) => ["string", s].join(":"), + SecretInput::File { path } => ["file", path.display().to_string().as_str()].join(":"), }) } } -impl InputSalt { - pub fn obtain(&self, password_helper: &PasswordHelper) -> Fido2LuksResult<[u8; 32]> { +impl SecretInput { + pub fn obtain_string(&self, password_helper: &PasswordHelper) -> Fido2LuksResult { + Ok(String::from_utf8(self.obtain(password_helper)?)?) + } + + pub fn obtain(&self, password_helper: &PasswordHelper) -> Fido2LuksResult> { + let mut secret = Vec::new(); + match self { + SecretInput::File { path } => { + //TODO: replace with try_blocks + let mut do_io = || File::open(path)?.read_to_end(&mut secret); + do_io().map_err(|cause| Fido2LuksError::KeyfileError { cause })?; + } + SecretInput::AskPassword => { + secret.extend_from_slice(password_helper.obtain()?.as_bytes()) + } + + SecretInput::String(s) => secret.extend_from_slice(s.as_bytes()), + } + Ok(secret) + } + + pub fn obtain_sha256(&self, password_helper: &PasswordHelper) -> Fido2LuksResult<[u8; 32]> { let mut digest = digest::Context::new(&digest::SHA256); match self { - InputSalt::File { path } => { + SecretInput::File { path } => { let mut do_io = || { let mut reader = File::open(path)?; let mut buf = [0u8; 512]; @@ -73,10 +94,7 @@ impl InputSalt { }; do_io().map_err(|cause| Fido2LuksError::KeyfileError { cause })?; } - InputSalt::AskPassword => { - digest.update(password_helper.obtain()?.as_bytes()); - } - InputSalt::String(s) => digest.update(s.as_bytes()), + _ => digest.update(self.obtain(password_helper)?.as_slice()), } let mut salt = [0u8; 32]; salt.as_mut().copy_from_slice(digest.finish().as_ref()); @@ -157,23 +175,29 @@ mod test { #[test] fn input_salt_from_str() { assert_eq!( - "file:/tmp/abc".parse::().unwrap(), - InputSalt::File { + "file:/tmp/abc".parse::().unwrap(), + SecretInput::File { path: "/tmp/abc".into() } ); assert_eq!( - "string:abc".parse::().unwrap(), - InputSalt::String("abc".into()) + "string:abc".parse::().unwrap(), + SecretInput::String("abc".into()) + ); + assert_eq!( + "ask".parse::().unwrap(), + SecretInput::AskPassword + ); + assert_eq!( + "lol".parse::().unwrap(), + SecretInput::default() ); - assert_eq!("ask".parse::().unwrap(), InputSalt::AskPassword); - assert_eq!("lol".parse::().unwrap(), InputSalt::default()); } #[test] fn input_salt_obtain() { assert_eq!( - InputSalt::String("abc".into()) + SecretInput::String("abc".into()) .obtain(&PasswordHelper::Stdin) .unwrap(), [ diff --git a/src/cli.rs b/src/cli/mod.rs similarity index 97% rename from src/cli.rs rename to src/cli/mod.rs index 9cb893b..2993398 100644 --- a/src/cli.rs +++ b/src/cli/mod.rs @@ -1,25 +1,30 @@ -use crate::cli_args::*; use crate::error::*; use crate::luks::{Fido2LuksToken, LuksDevice}; use crate::util::sha256; use crate::*; +use cli_args::*; +use config::*; use structopt::clap::Shell; use structopt::StructOpt; use ctap::{FidoCredential, FidoErrorKind}; -use failure::_core::str::FromStr; -use failure::_core::time::Duration; use std::io::{Read, Write}; -use std::process::exit; +use std::str::FromStr; use std::thread; +use std::time::Duration; use std::borrow::Cow; use std::collections::HashSet; use std::fs::File; use std::time::SystemTime; +pub use cli_args::Args; + +mod cli_args; +mod config; + fn read_pin(ap: &AuthenticatorParameters) -> Fido2LuksResult { if let Some(src) = ap.pin_source.as_ref() { let mut pin = String::new(); @@ -106,7 +111,7 @@ pub fn run_cli() -> Fido2LuksResult<()> { let salt = if interactive || secret.password_helper == PasswordHelper::Stdin { util::read_password_hashed("Password", false) } else { - secret.salt.obtain(&secret.password_helper) + secret.salt.obtain_sha256(&secret.password_helper) }?; let (secret, _cred) = derive_secret( credentials.ids.0.as_slice(), @@ -150,7 +155,7 @@ pub fn run_cli() -> Fido2LuksResult<()> { if interactive || secret.password_helper == PasswordHelper::Stdin { util::read_password_hashed(q, verify) } else { - secret.salt.obtain(&secret.password_helper) + secret.salt.obtain_sha256(&secret.password_helper) } }; let other_secret = |salt_q: &str, @@ -267,7 +272,7 @@ pub fn run_cli() -> Fido2LuksResult<()> { if interactive || secret.password_helper == PasswordHelper::Stdin { util::read_password_hashed(q, verify) } else { - secret.salt.obtain(&secret.password_helper) + secret.salt.obtain_sha256(&secret.password_helper) } }; diff --git a/src/error.rs b/src/error.rs index 0f7a34c..03d9741 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,5 +1,9 @@ use ctap::FidoError; +use libcryptsetup_rs::LibcryptErr; use std::io; +use std::io::ErrorKind; +use std::string::FromUtf8Error; +use Fido2LuksError::*; pub type Fido2LuksResult = Result; @@ -81,11 +85,6 @@ impl From for Fido2LuksError { } } -use libcryptsetup_rs::LibcryptErr; -use std::io::ErrorKind; -use std::string::FromUtf8Error; -use Fido2LuksError::*; - impl From for Fido2LuksError { fn from(e: FidoError) -> Self { AuthenticatorError { cause: e } diff --git a/src/main.rs b/src/main.rs index c716d50..3dcac67 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,7 +4,6 @@ extern crate ctap_hmac as ctap; #[macro_use] extern crate serde_derive; use crate::cli::*; -use crate::config::*; use crate::device::*; use crate::error::*; use std::io; @@ -12,8 +11,6 @@ use std::path::PathBuf; use std::process::exit; mod cli; -mod cli_args; -mod config; mod device; mod error; mod luks;