allow another fido device to be used as previous secret
This commit is contained in:
parent
ad2451f548
commit
d5c0d48f03
104
src/cli.rs
104
src/cli.rs
@ -4,7 +4,7 @@ use crate::*;
|
|||||||
|
|
||||||
use structopt::StructOpt;
|
use structopt::StructOpt;
|
||||||
|
|
||||||
use ctap::FidoCredential;
|
use ctap::{FidoCredential, FidoErrorKind};
|
||||||
use failure::_core::fmt::{Display, Error, Formatter};
|
use failure::_core::fmt::{Display, Error, Formatter};
|
||||||
use failure::_core::str::FromStr;
|
use failure::_core::str::FromStr;
|
||||||
use failure::_core::time::Duration;
|
use failure::_core::time::Duration;
|
||||||
@ -65,7 +65,7 @@ pub struct Args {
|
|||||||
|
|
||||||
#[derive(Debug, StructOpt, Clone)]
|
#[derive(Debug, StructOpt, Clone)]
|
||||||
pub struct SecretGeneration {
|
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")]
|
#[structopt(name = "credential-id", env = "FIDO2LUKS_CREDENTIAL_ID")]
|
||||||
pub credential_ids: CommaSeparated<HexEncoded>,
|
pub credential_ids: CommaSeparated<HexEncoded>,
|
||||||
/// Salt for secret generation, defaults to 'ask'
|
/// Salt for secret generation, defaults to 'ask'
|
||||||
@ -99,14 +99,6 @@ pub struct SecretGeneration {
|
|||||||
pub await_authenticator: u64,
|
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 {
|
impl SecretGeneration {
|
||||||
pub fn patch(&self, args: &Args) -> Self {
|
pub fn patch(&self, args: &Args) -> Self {
|
||||||
let mut me = self.clone();
|
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)]
|
#[derive(Debug, StructOpt)]
|
||||||
pub enum Command {
|
pub enum Command {
|
||||||
#[structopt(name = "print-secret")]
|
#[structopt(name = "print-secret")]
|
||||||
@ -168,9 +195,8 @@ pub enum Command {
|
|||||||
/// Will wipe all other keys
|
/// Will wipe all other keys
|
||||||
#[structopt(short = "e", long = "exclusive")]
|
#[structopt(short = "e", long = "exclusive")]
|
||||||
exclusive: bool,
|
exclusive: bool,
|
||||||
/// Use a keyfile instead of typing a previous password
|
#[structopt(flatten)]
|
||||||
#[structopt(short = "d", long = "keyfile")]
|
existing_secret: OtherSecret,
|
||||||
keyfile: Option<PathBuf>,
|
|
||||||
#[structopt(flatten)]
|
#[structopt(flatten)]
|
||||||
secret_gen: SecretGeneration,
|
secret_gen: SecretGeneration,
|
||||||
#[structopt(flatten)]
|
#[structopt(flatten)]
|
||||||
@ -184,9 +210,8 @@ pub enum Command {
|
|||||||
/// Add the password and keep the key
|
/// Add the password and keep the key
|
||||||
#[structopt(short = "a", long = "add-password")]
|
#[structopt(short = "a", long = "add-password")]
|
||||||
add_password: bool,
|
add_password: bool,
|
||||||
/// Use a keyfile instead of typing a previous password
|
#[structopt(flatten)]
|
||||||
#[structopt(short = "d", long = "keyfile")]
|
replacement: OtherSecret,
|
||||||
keyfile: Option<PathBuf>,
|
|
||||||
#[structopt(flatten)]
|
#[structopt(flatten)]
|
||||||
secret_gen: SecretGeneration,
|
secret_gen: SecretGeneration,
|
||||||
#[structopt(flatten)]
|
#[structopt(flatten)]
|
||||||
@ -244,16 +269,13 @@ pub fn run_cli() -> Fido2LuksResult<()> {
|
|||||||
Command::AddKey {
|
Command::AddKey {
|
||||||
device,
|
device,
|
||||||
exclusive,
|
exclusive,
|
||||||
keyfile,
|
existing_secret,
|
||||||
ref secret_gen,
|
ref secret_gen,
|
||||||
luks_settings,
|
luks_settings,
|
||||||
} => {
|
} => {
|
||||||
let secret = secret_gen.patch(&args).obtain_secret()?;
|
let secret_gen = secret_gen.patch(&args);
|
||||||
let old_secret = if let Some(keyfile) = keyfile.clone() {
|
let old_secret = existing_secret.obtain(&secret_gen, false, "Existing password")?;
|
||||||
util::read_keyfile(keyfile.clone())
|
let secret = secret_gen.obtain_secret()?;
|
||||||
} else {
|
|
||||||
util::read_password("Old password", false).map(|p| p.as_bytes().to_vec())
|
|
||||||
}?;
|
|
||||||
let added_slot = luks::add_key(
|
let added_slot = luks::add_key(
|
||||||
device.clone(),
|
device.clone(),
|
||||||
&secret,
|
&secret,
|
||||||
@ -280,16 +302,13 @@ pub fn run_cli() -> Fido2LuksResult<()> {
|
|||||||
Command::ReplaceKey {
|
Command::ReplaceKey {
|
||||||
device,
|
device,
|
||||||
add_password,
|
add_password,
|
||||||
keyfile,
|
replacement,
|
||||||
ref secret_gen,
|
ref secret_gen,
|
||||||
luks_settings,
|
luks_settings,
|
||||||
} => {
|
} => {
|
||||||
|
let secret_gen = secret_gen.patch(&args);
|
||||||
let secret = secret_gen.patch(&args).obtain_secret()?;
|
let secret = secret_gen.patch(&args).obtain_secret()?;
|
||||||
let new_secret = if let Some(keyfile) = keyfile.clone() {
|
let new_secret = replacement.obtain(&secret_gen, true, "Replacement password")?;
|
||||||
util::read_keyfile(keyfile.clone())
|
|
||||||
} else {
|
|
||||||
util::read_password("Password to add", *add_password).map(|p| p.as_bytes().to_vec())
|
|
||||||
}?;
|
|
||||||
let slot = if *add_password {
|
let slot = if *add_password {
|
||||||
luks::add_key(device, &new_secret[..], &secret, luks_settings.kdf_time)
|
luks::add_key(device, &new_secret[..], &secret, luks_settings.kdf_time)
|
||||||
} else {
|
} else {
|
||||||
@ -310,16 +329,25 @@ pub fn run_cli() -> Fido2LuksResult<()> {
|
|||||||
} => {
|
} => {
|
||||||
let mut retries = *retries;
|
let mut retries = *retries;
|
||||||
loop {
|
loop {
|
||||||
let secret = secret_gen.patch(&args).obtain_secret()?;
|
match secret_gen
|
||||||
match luks::open_container(&device, &name, &secret) {
|
.patch(&args)
|
||||||
Err(e) => match e {
|
.obtain_secret()
|
||||||
Fido2LuksError::WrongSecret if retries > 0 => {
|
.and_then(|secret| luks::open_container(&device, &name, &secret))
|
||||||
retries -= 1;
|
{
|
||||||
eprintln!("{}", e);
|
Err(e) => {
|
||||||
continue;
|
match e {
|
||||||
|
Fido2LuksError::WrongSecret if retries > 0 => (),
|
||||||
|
Fido2LuksError::AuthenticatorError { ref cause }
|
||||||
|
if cause.kind() == FidoErrorKind::Timeout && retries > 0 =>
|
||||||
|
{
|
||||||
|
()
|
||||||
|
}
|
||||||
|
|
||||||
|
e => break Err(e)?,
|
||||||
}
|
}
|
||||||
e => Err(e)?,
|
retries -= 1;
|
||||||
},
|
eprintln!("{}", e);
|
||||||
|
}
|
||||||
res => break res,
|
res => break res,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user