basic token operations
Some checks failed
continuous-integration/drone/pr Build is failing

This commit is contained in:
shimun 2020-06-21 19:11:29 +02:00
parent 6c2f5fc7ec
commit ce43cf857d
Signed by: shimun
GPG Key ID: E81D8382DC2F971B
2 changed files with 104 additions and 6 deletions

View File

@ -12,8 +12,10 @@ use std::io::Write;
use std::process::exit;
use std::thread;
use crate::luks::LuksDevice;
use crate::util::sha256;
use std::borrow::Cow;
use std::collections::HashSet;
use std::time::SystemTime;
#[derive(Debug, Eq, PartialEq, Clone)]
@ -282,6 +284,41 @@ pub enum Command {
/// Check if an authenticator is connected
#[structopt(name = "connected")]
Connected,
Token(TokenCommand),
}
#[derive(Debug, StructOpt)]
pub enum TokenCommand {
/// List all tokens associated with the specified device
List {
#[structopt(env = "FIDO2LUKS_DEVICE")]
device: PathBuf,
},
/// Add credential to a keyslot
Add {
#[structopt(env = "FIDO2LUKS_DEVICE")]
device: PathBuf,
#[structopt(flatten)]
credentials: Credentials,
/// Slot to which the credentials will be added
#[structopt(long = "slot", env = "FIDO2LUKS_DEVICE_SLOT")]
slot: u32,
},
/// Remove credentials from token(s)
Remove {
#[structopt(env = "FIDO2LUKS_DEVICE")]
device: PathBuf,
#[structopt(flatten)]
credentials: Credentials,
/// Token from which the credentials will be removed
#[structopt(long = "token")]
token: Option<u32>,
},
/// Remove all unassigned tokens
GC {
#[structopt(env = "FIDO2LUKS_DEVICE")]
device: PathBuf,
},
}
pub fn parse_cmdline() -> Args {
@ -371,7 +408,9 @@ pub fn run_cli() -> Fido2LuksResult<()> {
secret.salt.obtain(&secret.password_helper)
}
};
let other_secret = |salt_q: &str, verify: bool| -> Fido2LuksResult<(Vec<u8>, Option<FidoCredential>)> {
let other_secret = |salt_q: &str,
verify: bool|
-> Fido2LuksResult<(Vec<u8>, Option<FidoCredential>)> {
match other_secret {
OtherSecret {
keyfile: Some(file),
@ -386,7 +425,10 @@ pub fn run_cli() -> Fido2LuksResult<()> {
pin.as_deref(),
)
.map(|(secret, cred)| (secret[..].to_vec(), Some(cred)))?),
_ => Ok((util::read_password(salt_q, verify)?.as_bytes().to_vec(), None)),
_ => Ok((
util::read_password(salt_q, verify)?.as_bytes().to_vec(),
None,
)),
}
};
let secret = |verify: bool| -> Fido2LuksResult<([u8; 32], FidoCredential)> {
@ -399,9 +441,7 @@ pub fn run_cli() -> Fido2LuksResult<()> {
};
// Non overlap
match &args.command {
Command::AddKey {
exclusive, ..
} => {
Command::AddKey { exclusive, .. } => {
let (existing_secret, _) = other_secret("Current password", false)?;
let (new_secret, cred) = secret(true)?;
let added_slot = luks::add_key(
@ -542,5 +582,61 @@ pub fn run_cli() -> Fido2LuksResult<()> {
}
_ => exit(1),
},
Command::Token(cmd) => match cmd {
TokenCommand::List { device } => {
let mut dev = LuksDevice::load(device)?;
let mut creds = Vec::new();
for token in dev.tokens()? {
let (id, token) = token?;
for cred in token.credential.iter() {
if !creds.contains(cred) {
creds.push(cred.clone());
}
}
println!(
"{}:\n\tSlots: {}\n\tCredentials: {}",
id,
if token.keyslots.is_empty() {
"None".into()
} else {
token.keyslots.join(",")
},
token
.credential
.iter()
.map(|cred| format!(
"{} ({})",
cred,
creds.iter().position(|c| c == cred).unwrap().to_string()
))
.collect::<Vec<_>>()
.join(",")
);
}
Ok(())
}
TokenCommand::GC { device } => {
let mut dev = LuksDevice::load(device)?;
let mut creds: HashSet<String> = HashSet::new();
let mut remove = Vec::new();
for token in dev.tokens()? {
let (id, token) = token?;
if token.keyslots.is_empty() {
creds.extend(token.credential);
remove.push(id);
}
}
for id in remove.iter().rev() {
dev.remove_token(*id)?;
}
println!(
"Removed {} tokens, affected credentials: {}",
remove.len(),
creds.into_iter().collect::<Vec<_>>().join(",")
);
Ok(())
}
_ => unimplemented!(),
},
}
}

View File

@ -88,7 +88,9 @@ impl LuksDevice {
}
pub fn remove_token(&mut self, token: u32) -> Fido2LuksResult<()> {
self.device.token_handle().json_set(TokenInput::RemoveToken(token))?;
self.device
.token_handle()
.json_set(TokenInput::RemoveToken(token))?;
Ok(())
}