diff --git a/src/cli.rs b/src/cli.rs index 4890522..0f09b3d 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -17,7 +17,7 @@ use structopt::clap::Shell; use structopt::StructOpt; fn read_pin() -> Fido2LuksResult { - util::read_password("Authenticator PIN", false) + util::read_password_tty("Authenticator PIN", false) } fn derive_secret( @@ -98,14 +98,11 @@ pub fn get_input( } else { None }, - salt.obtain_sha256(Some(|| util::read_password(q, verify)))?, + salt.obtain_sha256(Some(|| util::read_password_tty(q, verify)))?, ) } else { match (authenticator.pin, authenticator.pin_prefixed) { - (true, false) => ( - Some(read_pin()?), - salt.obtain_sha256(password_helper)?, - ), + (true, false) => (Some(read_pin()?), 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)) @@ -143,6 +140,11 @@ pub fn parse_cmdline() -> Args { pub fn run_cli() -> Fido2LuksResult<()> { let mut stdout = io::stdout(); let args = parse_cmdline(); + let log = |message: &dyn Fn() -> String| { + if args.verbose { + eprintln!("{}", message()); + } + }; match &args.command { Command::Credential { authenticator, @@ -168,7 +170,10 @@ pub fn run_cli() -> Fido2LuksResult<()> { } => { let (pin, salt) = get_input(&secret, &authenticator, args.interactive, "Password", false)?; - let credentials = if let Some(dev) = device { + let credentials = if let Some(path) = device { + let mut dev = LuksDevice::load(path)?; + let luks2 = dev.is_luks2()?; + log(&|| format!("luks2 supported: {}", luks2)); extend_creds_device( credentials .ids @@ -176,17 +181,28 @@ pub fn run_cli() -> Fido2LuksResult<()> { .map(|cs| cs.0) .unwrap_or_default() .as_slice(), - &mut LuksDevice::load(dev)?, + &mut dev, )? } else { credentials.ids.clone().map(|cs| cs.0).unwrap_or_default() }; - let (secret, _cred) = derive_secret( + log(&|| { + format!( + "credentials: {}", + credentials + .iter() + .map(ToString::to_string) + .collect::>() + .join(", ") + ) + }); + let (secret, cred) = derive_secret( credentials.as_slice(), &salt, authenticator.await_time, pin.as_deref(), )?; + log(&|| format!("credential used: {}", hex::encode(&cred.id))); if *binary { stdout.write_all(&secret[..])?; } else { @@ -216,6 +232,8 @@ pub fn run_cli() -> Fido2LuksResult<()> { let luks2 = luks_dev.is_luks2()?; + log(&|| format!("luks2 supported: {}", luks2)); + let credentials = if !luks.disable_token && luks2 { extend_creds_device( credentials @@ -229,7 +247,16 @@ pub fn run_cli() -> Fido2LuksResult<()> { } else { credentials.ids.clone().map(|cs| cs.0).unwrap_or_default() }; - + log(&|| { + format!( + "credentials: {}", + credentials + .iter() + .map(ToString::to_string) + .collect::>() + .join(", ") + ) + }); let inputs = |q: &str, verify: bool| -> Fido2LuksResult<(Option, [u8; 32])> { get_input(&secret, &authenticator, args.interactive, q, verify) }; @@ -255,7 +282,7 @@ pub fn run_cli() -> Fido2LuksResult<()> { .map(|(secret, cred)| (secret[..].to_vec(), Some(cred)))?) } _ => Ok(( - util::read_password(salt_q, verify)?.as_bytes().to_vec(), + util::read_password_tty(salt_q, verify)?.as_bytes().to_vec(), None, )), } @@ -284,6 +311,7 @@ pub fn run_cli() -> Fido2LuksResult<()> { } else { secret(true, &credentials) }?; + log(&|| format!("credential used: {}", hex::encode(&cred.id))); let added_slot = luks_dev.add_key( &new_secret, &existing_secret[..], @@ -341,6 +369,9 @@ pub fn run_cli() -> Fido2LuksResult<()> { } Ok(slot) }?; + if let Some(cred) = cred { + log(&|| format!("credential used: {}", hex::encode(&cred.id))); + } println!( "Added to password to device {}, slot: {}", luks.device.display(), @@ -377,21 +408,38 @@ pub fn run_cli() -> Fido2LuksResult<()> { let mut retries = *retries; let mut luks_dev = LuksDevice::load(&luks.device)?; + let luks2 = luks_dev.is_luks2()?; + log(&|| format!("luks2 supported: {}", luks2)); loop { let slot = if let Some(ref credentials) = credentials.ids { - secret(Cow::Borrowed(&credentials.0)).and_then(|(secret, _cred)| { + log(&|| { + format!( + "credentials: {}", + credentials + .0 + .iter() + .map(ToString::to_string) + .collect::>() + .join(", ") + ) + }); + secret(Cow::Borrowed(&credentials.0)).and_then(|(secret, cred)| { + log(&|| format!("credential used: {}", hex::encode(&cred.id))); luks_dev.activate(&name, &secret, luks.slot, *dry_run) }) - } else if luks_dev.is_luks2()? && !luks.disable_token { + } else if luks2 && !luks.disable_token { luks_dev.activate_token( &name, Box::new(|credentials: Vec| { + log(&|| format!("credentials: {}", credentials.join(", "))); let creds = credentials .into_iter() .flat_map(|cred| HexEncoded::from_str(cred.as_ref()).ok()) .collect::>(); - secret(Cow::Owned(creds)) - .map(|(secret, cred)| (secret, hex::encode(&cred.id))) + secret(Cow::Owned(creds)).map(|(secret, cred)| { + log(&|| format!("credential used: {}", hex::encode(&cred.id))); + (secret, hex::encode(&cred.id)) + }) }), luks.slot, *dry_run, @@ -414,7 +462,10 @@ pub fn run_cli() -> Fido2LuksResult<()> { retries -= 1; eprintln!("{}", e); } - res => break res.map(|_| ()), + Ok(slot) => { + log(&|| format!("keyslot: {}", slot)); + break Ok(()); + } } } } diff --git a/src/cli_args/config.rs b/src/cli_args/config.rs index bb1bb57..a223b83 100644 --- a/src/cli_args/config.rs +++ b/src/cli_args/config.rs @@ -163,7 +163,7 @@ impl PasswordHelper { use PasswordHelper::*; match self { Systemd => unimplemented!(), - Stdin => Ok(util::read_password("Password", true)?), + Stdin => Ok(util::read_password("Password", true, false)?), Script(password_helper) => { let password = Command::new("sh") .arg("-c") diff --git a/src/cli_args/mod.rs b/src/cli_args/mod.rs index 5b9acad..5c1c024 100644 --- a/src/cli_args/mod.rs +++ b/src/cli_args/mod.rs @@ -147,6 +147,8 @@ pub struct Args { /// Request passwords via Stdin instead of using the password helper #[structopt(short = "i", long = "interactive")] pub interactive: bool, + #[structopt(short = "v", long = "verbose")] + pub verbose: bool, #[structopt(subcommand)] pub command: Command, } diff --git a/src/util.rs b/src/util.rs index 3676480..5ca21ff 100644 --- a/src/util.rs +++ b/src/util.rs @@ -13,9 +13,17 @@ pub fn sha256(messages: &[&[u8]]) -> [u8; 32] { secret.as_mut().copy_from_slice(digest.finish().as_ref()); secret } - -pub fn read_password(q: &str, verify: bool) -> Fido2LuksResult { - match rpassword::read_password_from_tty(Some(&[q, ": "].join("")))? { +pub fn read_password_tty(q: &str, verify: bool) -> Fido2LuksResult { + read_password(q, verify, true) +} +pub fn read_password(q: &str, verify: bool, tty: bool) -> Fido2LuksResult { + let res = if tty { + rpassword::read_password_from_tty(Some(&[q, ": "].join(""))) + } else { + print!("{}: ", q); + rpassword::read_password() + }?; + match res { ref pass if verify && &rpassword::read_password_from_tty(Some(&[q, "(again): "].join(" ")))? @@ -29,10 +37,6 @@ pub fn read_password(q: &str, verify: bool) -> Fido2LuksResult { } } -pub fn read_password_hashed(q: &str, verify: bool) -> Fido2LuksResult<[u8; 32]> { - read_password(q, verify).map(|pass| sha256(&[pass.as_bytes()])) -} - pub fn read_keyfile>(path: P) -> Fido2LuksResult> { let mut file = File::open(path.into())?; let mut key = Vec::new();