rewrite helper
Some checks failed
continuous-integration/drone/push Build is failing
continuous-integration/drone/pr Build is failing

This commit is contained in:
shimun 2020-10-17 17:58:28 +02:00
parent a5c0840a59
commit a264f4c9eb
Signed by: shimun
GPG Key ID: E81D8382DC2F971B
3 changed files with 68 additions and 93 deletions

View File

@ -2,26 +2,19 @@ use crate::error::*;
use crate::luks::{Fido2LuksToken, LuksDevice}; use crate::luks::{Fido2LuksToken, LuksDevice};
use crate::util::sha256; use crate::util::sha256;
use crate::*; use crate::*;
pub use cli_args::Args;
use cli_args::*; use cli_args::*;
use structopt::clap::Shell;
use structopt::StructOpt;
use ctap::{FidoCredential, FidoErrorKind}; use ctap::{FidoCredential, FidoErrorKind};
use std::borrow::Cow;
use std::collections::HashSet;
use std::io::Write; use std::io::Write;
use std::iter::FromIterator;
use std::str::FromStr; use std::str::FromStr;
use std::thread; use std::thread;
use std::time::Duration; use std::time::Duration;
use std::borrow::Cow;
use std::collections::HashSet;
use std::time::SystemTime; use std::time::SystemTime;
use structopt::clap::Shell;
pub use cli_args::Args; use structopt::StructOpt;
use std::iter::FromIterator;
fn read_pin() -> Fido2LuksResult<String> { fn read_pin() -> Fido2LuksResult<String> {
util::read_password("Authenticator PIN", false) util::read_password("Authenticator PIN", false)
@ -86,6 +79,43 @@ pub fn extend_creds_device(
Ok(Vec::from_iter(additional.into_iter())) Ok(Vec::from_iter(additional.into_iter()))
} }
pub fn get_input(
secret: &SecretParameters,
authenticator: &AuthenticatorParameters,
interactive: bool,
q: &str,
verify: bool,
) -> Fido2LuksResult<(Option<String>, [u8; 32])> {
let password_helper = secret
.password_helper
.as_ref()
.map(|helper| move || helper.obtain());
let salt = &secret.salt;
Ok(if interactive {
(
if authenticator.pin {
Some(util::read_password("PIN", false)?)
} else {
None
},
salt.obtain_sha256(Some(|| util::read_password(q, verify)))?,
)
} else {
match (authenticator.pin, authenticator.pin_prefixed) {
(true, false) => (
Some(util::read_password("PIN", false)?),
salt.obtain_sha256(password_helper)?,
),
(true, true) => read_password_pin_prefixed(|| {
salt.obtain(password_helper).and_then(|secret| {
String::from_utf8(secret).map_err(|e| Fido2LuksError::from(e))
})
})?,
(false, _) => (None, salt.obtain_sha256(password_helper)?),
}
})
}
pub fn read_password_pin_prefixed( pub fn read_password_pin_prefixed(
prefixed: impl Fn() -> Fido2LuksResult<String>, prefixed: impl Fn() -> Fido2LuksResult<String>,
) -> Fido2LuksResult<(Option<String>, [u8; 32])> { ) -> Fido2LuksResult<(Option<String>, [u8; 32])> {
@ -136,29 +166,8 @@ pub fn run_cli() -> Fido2LuksResult<()> {
secret, secret,
device, device,
} => { } => {
let (pin, salt) = match ( let (pin, salt) =
&secret.password_helper, get_input(&secret, &authenticator, args.interactive, "Password", false)?;
authenticator.pin,
authenticator.pin_prefixed,
args.interactive,
) {
(Some(phelper), true, true, false) => {
read_password_pin_prefixed(|| phelper.obtain())?
}
(Some(phelper), false, false, false) => {
(None, secret.salt.obtain_sha256(&phelper)?)
}
(phelper, pin, _, _) => (
if pin { Some(read_pin()?) } else { None },
match phelper {
None | Some(PasswordHelper::Stdin) => {
util::read_password_hashed("Password", false)
}
Some(phelper) => secret.salt.obtain_sha256(&phelper),
}?,
),
};
let credentials = if let Some(dev) = device { let credentials = if let Some(dev) = device {
extend_creds_device( extend_creds_device(
credentials credentials
@ -222,31 +231,7 @@ pub fn run_cli() -> Fido2LuksResult<()> {
}; };
let inputs = |q: &str, verify: bool| -> Fido2LuksResult<(Option<String>, [u8; 32])> { let inputs = |q: &str, verify: bool| -> Fido2LuksResult<(Option<String>, [u8; 32])> {
Ok( get_input(&secret, &authenticator, args.interactive, q, verify)
match (
&secret.password_helper,
authenticator.pin,
authenticator.pin_prefixed,
args.interactive,
) {
(Some(phelper), true, true, false) => {
read_password_pin_prefixed(|| phelper.obtain())?
}
(Some(phelper), false, false, false) => {
(None, secret.salt.obtain_sha256(&phelper)?)
}
(_phelper, pin, _, _) => (
if pin { Some(read_pin()?) } else { None },
match &secret.password_helper {
None | Some(PasswordHelper::Stdin) => {
util::read_password_hashed(q, verify)
}
Some(phelper) => secret.salt.obtain_sha256(&phelper),
}?,
),
},
)
}; };
let other_secret = |salt_q: &str, let other_secret = |salt_q: &str,
@ -375,31 +360,7 @@ pub fn run_cli() -> Fido2LuksResult<()> {
retries, retries,
} => { } => {
let inputs = |q: &str, verify: bool| -> Fido2LuksResult<(Option<String>, [u8; 32])> { let inputs = |q: &str, verify: bool| -> Fido2LuksResult<(Option<String>, [u8; 32])> {
Ok( get_input(&secret, &authenticator, args.interactive, q, verify)
match (
&secret.password_helper,
authenticator.pin,
authenticator.pin_prefixed,
args.interactive,
) {
(Some(phelper), true, true, false) => {
read_password_pin_prefixed(|| phelper.obtain())?
}
(Some(phelper), false, false, false) => {
(None, secret.salt.obtain_sha256(&phelper)?)
}
(phelper, pin, _, _) => (
if pin { Some(read_pin()?) } else { None },
match &phelper {
None | Some(PasswordHelper::Stdin) => {
util::read_password_hashed(q, verify)
}
Some(phelper) => secret.salt.obtain_sha256(&phelper),
}?,
),
},
)
}; };
// Cow shouldn't be necessary // Cow shouldn't be necessary

View File

@ -55,11 +55,17 @@ impl fmt::Display for SecretInput {
} }
impl SecretInput { impl SecretInput {
pub fn obtain_string(&self, password_helper: &PasswordHelper) -> Fido2LuksResult<String> { pub fn obtain_string(
&self,
password_helper: Option<impl FnOnce() -> Fido2LuksResult<String>>,
) -> Fido2LuksResult<String> {
Ok(String::from_utf8(self.obtain(password_helper)?)?) Ok(String::from_utf8(self.obtain(password_helper)?)?)
} }
pub fn obtain(&self, password_helper: &PasswordHelper) -> Fido2LuksResult<Vec<u8>> { pub fn obtain(
&self,
password_helper: Option<impl FnOnce() -> Fido2LuksResult<String>>,
) -> Fido2LuksResult<Vec<u8>> {
let mut secret = Vec::new(); let mut secret = Vec::new();
match self { match self {
SecretInput::File { path } => { SecretInput::File { path } => {
@ -67,16 +73,22 @@ impl SecretInput {
let mut do_io = || File::open(path)?.read_to_end(&mut secret); let mut do_io = || File::open(path)?.read_to_end(&mut secret);
do_io().map_err(|cause| Fido2LuksError::KeyfileError { cause })?; do_io().map_err(|cause| Fido2LuksError::KeyfileError { cause })?;
} }
SecretInput::AskPassword => { SecretInput::AskPassword => secret.extend_from_slice(
secret.extend_from_slice(password_helper.obtain()?.as_bytes()) password_helper.ok_or_else(|| Fido2LuksError::AskPassError {
} cause: AskPassError::FailedHelper,
})?()?
.as_bytes(),
),
SecretInput::String(s) => secret.extend_from_slice(s.as_bytes()), SecretInput::String(s) => secret.extend_from_slice(s.as_bytes()),
} }
Ok(secret) Ok(secret)
} }
pub fn obtain_sha256(&self, password_helper: &PasswordHelper) -> Fido2LuksResult<[u8; 32]> { pub fn obtain_sha256(
&self,
password_helper: Option<impl FnOnce() -> Fido2LuksResult<String>>,
) -> Fido2LuksResult<[u8; 32]> {
let mut digest = digest::Context::new(&digest::SHA256); let mut digest = digest::Context::new(&digest::SHA256);
match self { match self {
SecretInput::File { path } => { SecretInput::File { path } => {
@ -198,7 +210,7 @@ mod test {
fn input_salt_obtain() { fn input_salt_obtain() {
assert_eq!( assert_eq!(
SecretInput::String("abc".into()) SecretInput::String("abc".into())
.obtain_sha256(&PasswordHelper::Stdin) .obtain_sha256(None)
.unwrap(), .unwrap(),
[ [
186, 120, 22, 191, 143, 1, 207, 234, 65, 65, 64, 222, 93, 174, 34, 35, 176, 3, 97, 186, 120, 22, 191, 143, 1, 207, 234, 65, 65, 64, 222, 93, 174, 34, 35, 176, 3, 97,

View File

@ -54,6 +54,8 @@ pub enum AskPassError {
IO(io::Error), IO(io::Error),
#[fail(display = "provided passwords don't match")] #[fail(display = "provided passwords don't match")]
Mismatch, Mismatch,
#[fail(display = "failed to call password helper")]
FailedHelper,
} }
#[derive(Debug, Fail)] #[derive(Debug, Fail)]