allow another fido device to be used as previous secret

This commit is contained in:
shimun 2020-04-06 20:18:00 +02:00
parent ad2451f548
commit d5c0d48f03
Signed by: shimun
GPG Key ID: E81D8382DC2F971B

View File

@ -4,7 +4,7 @@ use crate::*;
use structopt::StructOpt;
use ctap::FidoCredential;
use ctap::{FidoCredential, FidoErrorKind};
use failure::_core::fmt::{Display, Error, Formatter};
use failure::_core::str::FromStr;
use failure::_core::time::Duration;
@ -65,7 +65,7 @@ pub struct Args {
#[derive(Debug, StructOpt, Clone)]
pub struct SecretGeneration {
/// FIDO credential ids, generate using fido2luks credential
/// FIDO credential ids, seperated by ',' generate using fido2luks credential
#[structopt(name = "credential-id", env = "FIDO2LUKS_CREDENTIAL_ID")]
pub credential_ids: CommaSeparated<HexEncoded>,
/// Salt for secret generation, defaults to 'ask'
@ -99,14 +99,6 @@ pub struct SecretGeneration {
pub await_authenticator: u64,
}
#[derive(Debug, StructOpt, Clone)]
pub struct LuksSettings {
/// Number of milliseconds required to derive the volume decryption key
/// Defaults to 10ms when using an authenticator or the default by cryptsetup when using a password
#[structopt(long = "kdf-time", name = "kdf-time")]
kdf_time: Option<u64>,
}
impl SecretGeneration {
pub fn patch(&self, args: &Args) -> Self {
let mut me = self.clone();
@ -150,6 +142,41 @@ impl SecretGeneration {
}
}
#[derive(Debug, StructOpt, Clone)]
pub struct LuksSettings {
/// Number of milliseconds required to derive the volume decryption key
/// Defaults to 10ms when using an authenticator or the default by cryptsetup when using a password
#[structopt(long = "kdf-time", name = "kdf-time")]
kdf_time: Option<u64>,
}
#[derive(Debug, StructOpt, Clone)]
pub struct OtherSecret {
/// Use a keyfile instead of a password
#[structopt(short = "d", long = "keyfile", conflicts_with = "fido_device")]
keyfile: Option<PathBuf>,
/// Use another fido device instead of a password
/// Note: this requires for the credential fot the other device to be passed as argument as well
#[structopt(short = "f", long = "fido-device", conflicts_with = "keyfile")]
fido_device: bool,
}
impl OtherSecret {
pub fn obtain(
&self,
secret_gen: &SecretGeneration,
verify_password: bool,
password_question: &str,
) -> Fido2LuksResult<Vec<u8>> {
match &self.keyfile {
Some(keyfile) => util::read_keyfile(keyfile.clone()),
None if self.fido_device => Ok(Vec::from(&secret_gen.obtain_secret()?[..])),
None => util::read_password(password_question, verify_password)
.map(|p| p.as_bytes().to_vec()),
}
}
}
#[derive(Debug, StructOpt)]
pub enum Command {
#[structopt(name = "print-secret")]
@ -168,9 +195,8 @@ pub enum Command {
/// Will wipe all other keys
#[structopt(short = "e", long = "exclusive")]
exclusive: bool,
/// Use a keyfile instead of typing a previous password
#[structopt(short = "d", long = "keyfile")]
keyfile: Option<PathBuf>,
#[structopt(flatten)]
existing_secret: OtherSecret,
#[structopt(flatten)]
secret_gen: SecretGeneration,
#[structopt(flatten)]
@ -184,9 +210,8 @@ pub enum Command {
/// Add the password and keep the key
#[structopt(short = "a", long = "add-password")]
add_password: bool,
/// Use a keyfile instead of typing a previous password
#[structopt(short = "d", long = "keyfile")]
keyfile: Option<PathBuf>,
#[structopt(flatten)]
replacement: OtherSecret,
#[structopt(flatten)]
secret_gen: SecretGeneration,
#[structopt(flatten)]
@ -244,16 +269,13 @@ pub fn run_cli() -> Fido2LuksResult<()> {
Command::AddKey {
device,
exclusive,
keyfile,
existing_secret,
ref secret_gen,
luks_settings,
} => {
let secret = secret_gen.patch(&args).obtain_secret()?;
let old_secret = if let Some(keyfile) = keyfile.clone() {
util::read_keyfile(keyfile.clone())
} else {
util::read_password("Old password", false).map(|p| p.as_bytes().to_vec())
}?;
let secret_gen = secret_gen.patch(&args);
let old_secret = existing_secret.obtain(&secret_gen, false, "Existing password")?;
let secret = secret_gen.obtain_secret()?;
let added_slot = luks::add_key(
device.clone(),
&secret,
@ -280,16 +302,13 @@ pub fn run_cli() -> Fido2LuksResult<()> {
Command::ReplaceKey {
device,
add_password,
keyfile,
replacement,
ref secret_gen,
luks_settings,
} => {
let secret_gen = secret_gen.patch(&args);
let secret = secret_gen.patch(&args).obtain_secret()?;
let new_secret = if let Some(keyfile) = keyfile.clone() {
util::read_keyfile(keyfile.clone())
} else {
util::read_password("Password to add", *add_password).map(|p| p.as_bytes().to_vec())
}?;
let new_secret = replacement.obtain(&secret_gen, true, "Replacement password")?;
let slot = if *add_password {
luks::add_key(device, &new_secret[..], &secret, luks_settings.kdf_time)
} else {
@ -310,16 +329,25 @@ pub fn run_cli() -> Fido2LuksResult<()> {
} => {
let mut retries = *retries;
loop {
let secret = secret_gen.patch(&args).obtain_secret()?;
match luks::open_container(&device, &name, &secret) {
Err(e) => match e {
Fido2LuksError::WrongSecret if retries > 0 => {
match secret_gen
.patch(&args)
.obtain_secret()
.and_then(|secret| luks::open_container(&device, &name, &secret))
{
Err(e) => {
match e {
Fido2LuksError::WrongSecret if retries > 0 => (),
Fido2LuksError::AuthenticatorError { ref cause }
if cause.kind() == FidoErrorKind::Timeout && retries > 0 =>
{
()
}
e => break Err(e)?,
}
retries -= 1;
eprintln!("{}", e);
continue;
}
e => Err(e)?,
},
res => break res,
}
}