Skip to content

Commit

Permalink
Merge remote-tracking branch 'gt/ctap-hid-fido2' into 0.3.0-alpha
Browse files Browse the repository at this point in the history
  • Loading branch information
shimunn committed Mar 3, 2024
2 parents 238d877 + 871b286 commit acd4021
Show file tree
Hide file tree
Showing 10 changed files with 745 additions and 643 deletions.
1,057 changes: 527 additions & 530 deletions Cargo.lock

Large diffs are not rendered by default.

11 changes: 6 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "fido2luks"
version = "0.3.0-alpha"
version = "0.3.1-alpha"
authors = ["shimunn <[email protected]>"]
edition = "2018"

Expand All @@ -14,25 +14,26 @@ categories = ["command-line-utilities"]
license = "MPL-2.0"

[dependencies]
ctap_hmac = { version="0.4.5", features = ["request_multiple"] }
hex = "0.3.2"
ring = "0.13.5"
ring = "0.16.5"
failure = "0.1.5"
rpassword = "4.0.1"
structopt = "0.3.2"
libcryptsetup-rs = "0.9.1"
serde_json = "1.0.51"
serde_derive = "1.0.116"
serde = "1.0.116"
anyhow = "1.0.56"
ctap-hid-fido2 = "3.4.1"

[build-dependencies]
ctap_hmac = { version="0.4.5", features = ["request_multiple"] }
hex = "0.3.2"
ring = "0.13.5"
ring = "0.16.5"
failure = "0.1.5"
rpassword = "4.0.1"
libcryptsetup-rs = "0.9.1"
structopt = "0.3.2"
anyhow = "1.0.56"

[profile.release]
lto = true
Expand Down
8 changes: 6 additions & 2 deletions build.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
#![allow(warnings)]
#[macro_use]
extern crate failure;
extern crate ctap_hmac as ctap;

#[path = "src/cli_args/mod.rs"]
mod cli_args;
Expand All @@ -12,17 +11,22 @@ mod util;

use cli_args::Args;
use std::env;
use std::fs;
use std::path::PathBuf;
use std::str::FromStr;
use structopt::clap::Shell;
use structopt::StructOpt;

fn main() {
let env_outdir = env::var_os("OUT_DIR").unwrap();
let outdir = PathBuf::from(PathBuf::from(env_outdir).ancestors().nth(3).unwrap());
fs::create_dir_all(&outdir).unwrap();
// generate completion scripts, zsh does panic for some reason
for shell in Shell::variants().iter().filter(|shell| **shell != "zsh") {
Args::clap().gen_completions(
env!("CARGO_PKG_NAME"),
Shell::from_str(shell).unwrap(),
env!("CARGO_MANIFEST_DIR"),
&outdir,
);
}
}
2 changes: 1 addition & 1 deletion flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
forPkgs = pkgs:
let
naersk-lib = naersk.lib."${pkgs.system}";
buildInputs = with pkgs; [ cryptsetup cryptsetup.dev ];
buildInputs = with pkgs; [ cryptsetup cryptsetup.dev udev.dev ];
nativeBuildInputs = with pkgs; [
rustPlatform.bindgenHook
pkg-config
Expand Down
97 changes: 64 additions & 33 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@ use crate::util::sha256;
use crate::*;
pub use cli_args::Args;
use cli_args::*;
use ctap::{FidoCredential, FidoErrorKind};
use ctap_hid_fido2::public_key_credential_descriptor::PublicKeyCredentialDescriptor;
use std::borrow::Cow;
use std::collections::HashSet;
use std::io::Write;
use std::iter::FromIterator;
use std::path::Path;
use std::str::FromStr;
use std::thread;
use std::time::Duration;
use std::time::SystemTime;
use structopt::clap::Shell;
Expand All @@ -26,31 +25,31 @@ fn derive_secret(
salt: &[u8; 32],
timeout: u64,
pin: Option<&str>,
) -> Fido2LuksResult<([u8; 32], FidoCredential)> {
) -> Fido2LuksResult<([u8; 32], PublicKeyCredentialDescriptor)> {
if credentials.is_empty() {
return Err(Fido2LuksError::InsufficientCredentials);
}
let timeout = Duration::from_secs(timeout);
let start = SystemTime::now();

while let Ok(el) = start.elapsed() {
if el > timeout {
return Err(error::Fido2LuksError::NoAuthenticatorError);
}
if get_devices()
.map(|devices| !devices.is_empty())
.unwrap_or(false)
{
break;
}
thread::sleep(Duration::from_millis(500));
}
//while let Ok(el) = start.elapsed() {
// if el > timeout {
// return Err(error::Fido2LuksError::NoAuthenticatorError);
// }
// if get_devices()
// .map(|devices| !devices.is_empty())
// .unwrap_or(false)
// {
// break;
// }
// thread::sleep(Duration::from_millis(500));
//}

let credentials = credentials
.iter()
.map(|hex| FidoCredential {
.map(|hex| PublicKeyCredentialDescriptor {
id: hex.0.clone(),
public_key: None,
ctype: Default::default(),
})
.collect::<Vec<_>>();
let credentials = credentials.iter().collect::<Vec<_>>();
Expand Down Expand Up @@ -182,7 +181,8 @@ pub fn run_cli() -> Fido2LuksResult<()> {
} else {
None
};
let cred = make_credential_id(Some(name.as_ref()), pin)?;
let cred =
make_credential_id(Some(name.as_str()).filter(|name| name.len() > 0), pin, &[])?;
println!("{}", hex::encode(&cred.id));
Ok(())
}
Expand Down Expand Up @@ -289,7 +289,10 @@ pub fn run_cli() -> Fido2LuksResult<()> {

let other_secret = |salt_q: &str,
verify: bool|
-> Fido2LuksResult<(Vec<u8>, Option<FidoCredential>)> {
-> Fido2LuksResult<(
Vec<u8>,
Option<PublicKeyCredentialDescriptor>,
)> {
match other_secret {
OtherSecret {
keyfile: Some(file),
Expand All @@ -314,22 +317,38 @@ pub fn run_cli() -> Fido2LuksResult<()> {
)),
}
};
let secret = |q: &str,
verify: bool,
credentials: &[HexEncoded]|
-> Fido2LuksResult<([u8; 32], FidoCredential)> {
let (pin, salt) = inputs(q, verify)?;
prompt_interaction(interactive);
derive_secret(credentials, &salt, authenticator.await_time, pin.as_deref())
};
let secret =
|q: &str,
verify: bool,
credentials: &[HexEncoded]|
-> Fido2LuksResult<([u8; 32], PublicKeyCredentialDescriptor)> {
let (pin, salt) = inputs(q, verify)?;
prompt_interaction(interactive);
derive_secret(credentials, &salt, authenticator.await_time, pin.as_deref())
};
// Non overlap
match &args.command {
Command::AddKey {
exclusive,
generate_credential,
comment,
..
} => {
let (existing_secret, _) = other_secret("Current password", false)?;
let (existing_secret, existing_credential) =
other_secret("Current password", false)?;
let excluded_credential = existing_credential.as_ref();
let exclude_list = excluded_credential
.as_ref()
.map(core::slice::from_ref)
.unwrap_or_default();
existing_credential.iter().for_each(|cred| {
log(&|| {
format!(
"using credential to unlock container: {}",
hex::encode(&cred.id)
)
})
});
let (new_secret, cred) = if *generate_credential && luks2 {
let cred = make_credential_id(
Some(derive_credential_name(luks.device.as_path()).as_str()),
Expand All @@ -340,6 +359,7 @@ pub fn run_cli() -> Fido2LuksResult<()> {
None
})
.as_deref(),
dbg!(exclude_list),
)?;
log(&|| {
format!(
Expand All @@ -361,6 +381,7 @@ pub fn run_cli() -> Fido2LuksResult<()> {
Some(&cred.id[..])
.filter(|_| !luks.disable_token || *generate_credential)
.filter(|_| luks2),
comment.as_deref().map(String::from),
)?;
if *exclusive {
let destroyed = luks_dev.remove_keyslots(&[added_slot])?;
Expand Down Expand Up @@ -396,6 +417,7 @@ pub fn run_cli() -> Fido2LuksResult<()> {
.filter(|_| !luks.disable_token)
.filter(|_| luks2)
.map(|cred| &cred.id[..]),
None,
)
} else {
let slot = luks_dev.replace_key(
Expand Down Expand Up @@ -501,9 +523,8 @@ pub fn run_cli() -> Fido2LuksResult<()> {
Err(e) => {
match e {
Fido2LuksError::WrongSecret if retries > 0 => {}
Fido2LuksError::AuthenticatorError { ref cause }
if cause.kind() == FidoErrorKind::Timeout && retries > 0 => {}

//Fido2LuksError::AuthenticatorError { ref cause }
// if cause.kind() == FidoErrorKind::Timeout && retries > 0 => {}
e => return Err(e),
};
retries -= 1;
Expand Down Expand Up @@ -544,8 +565,13 @@ pub fn run_cli() -> Fido2LuksResult<()> {
continue;
}
println!(
"{}:\n\tSlots: {}\n\tCredentials: {}",
"{}{}:\n\tSlots: {}\n\tCredentials: {}",
id,
token
.comment
.as_deref()
.map(|comment| format!(" - {}", comment))
.unwrap_or_default(),
if token.keyslots.is_empty() {
"None".into()
} else {
Expand All @@ -571,6 +597,7 @@ pub fn run_cli() -> Fido2LuksResult<()> {
TokenCommand::Add {
device,
credentials,
comment,
slot,
} => {
let mut dev = LuksDevice::load(device)?;
Expand All @@ -582,7 +609,11 @@ pub fn run_cli() -> Fido2LuksResult<()> {
}
}
let count = if tokens.is_empty() {
dev.add_token(&Fido2LuksToken::with_credentials(&credentials.0, *slot))?;
dev.add_token(&Fido2LuksToken::with_credentials(
&credentials.0,
*slot,
comment.as_deref().map(String::from),
))?;
1
} else {
tokens.len()
Expand Down
8 changes: 7 additions & 1 deletion src/cli_args/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,9 @@ pub enum Command {
luks: LuksParameters,
#[structopt(flatten)]
credentials: Credentials,
/// Comment to be associated with this credential
#[structopt(long = "comment")]
comment: Option<String>,
#[structopt(flatten)]
authenticator: AuthenticatorParameters,
#[structopt(flatten)]
Expand Down Expand Up @@ -254,7 +257,7 @@ pub enum Command {
#[structopt(flatten)]
authenticator: AuthenticatorParameters,
/// Name to be displayed on the authenticator display
#[structopt(env = "FIDO2LUKS_CREDENTIAL_NAME", default_value = "fido2luks")]
#[structopt(env = "FIDO2LUKS_CREDENTIAL_NAME", default_value = "")]
name: String,
},
/// Check if an authenticator is connected
Expand Down Expand Up @@ -295,6 +298,9 @@ pub enum TokenCommand {
long = "creds"
)]
credentials: CommaSeparated<HexEncoded>,
/// Comment to be associated with this credential
#[structopt(long = "comment")]
comment: Option<String>,
/// Slot to which the credentials will be added
#[structopt(long = "slot", env = "FIDO2LUKS_DEVICE_SLOT")]
slot: u32,
Expand Down
Loading

0 comments on commit acd4021

Please sign in to comment.