From 721dded6d2f0135ce15b0f422b670382835faf7d Mon Sep 17 00:00:00 2001 From: shimun Date: Thu, 9 Jan 2020 00:02:30 +0100 Subject: [PATCH 1/2] WIP: 0.2.2 Warning: This release cointains changes to way credentials are generated, which may cause your authenticator to reject the old credential. --- Cargo.toml | 4 ++-- src/cli.rs | 4 ---- src/device.rs | 44 +++++++++++++++++++++++++++++++++++++++----- src/main.rs | 10 ++-------- src/util.rs | 11 +++++++++++ 5 files changed, 54 insertions(+), 19 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f1d9cb5..3d19332 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "fido2luks" -version = "0.2.1" +version = "0.2.2" authors = ["shimunn "] edition = "2018" @@ -15,7 +15,7 @@ license-file = "LICENSE" [dependencies] #ctap = "0.1.0" -ctap_hmac = "0.1.1" +ctap_hmac = "0.2.1" cryptsetup-rs = "0.2.1" libcryptsetup-sys = "0.1.2" diff --git a/src/cli.rs b/src/cli.rs index ac7c24a..761eb33 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -70,10 +70,6 @@ pub fn add_password_to_luks( Ok(slot) } -pub fn authenticator_connected() -> Fido2LuksResult { - Ok(!device::get_devices()?.is_empty()) -} - #[derive(Debug, StructOpt)] pub struct Args { /// Request passwords via Stdin instead of using the password helper diff --git a/src/device.rs b/src/device.rs index c574fdc..30aca2c 100644 --- a/src/device.rs +++ b/src/device.rs @@ -1,11 +1,39 @@ use crate::error::*; +use crate::util::sha256; use ctap::{ self, extensions::hmac::{FidoHmacCredential, HmacExtension}, - FidoDevice, FidoError, FidoErrorKind, + AuthenticatorOptions, FidoDevice, FidoError, FidoErrorKind, PublicKeyCredentialRpEntity, + PublicKeyCredentialUserEntity, }; +const RP_ID: &'static str = "fido2luks"; + +fn authenticator_options() -> Option { + Some(AuthenticatorOptions { + uv: false, //TODO: should get this from config + rk: true, + }) +} + +fn authenticator_rp() -> PublicKeyCredentialRpEntity<'static> { + PublicKeyCredentialRpEntity { + id: RP_ID, + name: None, + icon: None, + } +} + +fn authenticator_user() -> PublicKeyCredentialUserEntity<'static> { + PublicKeyCredentialUserEntity { + id: &[0u8], + name: "", + icon: None, + display_name: None, + } +} + pub fn make_credential_id() -> Fido2LuksResult { let mut errs = Vec::new(); match get_devices()? { @@ -13,7 +41,13 @@ pub fn make_credential_id() -> Fido2LuksResult { devs => { for mut dev in devs.into_iter() { match dev - .make_credential("fido2luks", &[0u8], "", &[0u8; 32]) + .make_hmac_credential_full( + authenticator_rp(), + authenticator_user(), + &[0u8; 32], + &[], + authenticator_options(), + ) .map(|cred| cred.into()) { //TODO: make credentials device specific @@ -33,16 +67,16 @@ pub fn make_credential_id() -> Fido2LuksResult { pub fn perform_challenge(credential_id: &str, salt: &[u8; 32]) -> Fido2LuksResult<[u8; 32]> { let cred = FidoHmacCredential { id: hex::decode(credential_id).unwrap(), - rp_id: "hmac".to_string(), + rp_id: RP_ID.to_string(), }; let mut errs = Vec::new(); match get_devices()? { ref devs if devs.is_empty() => Err(Fido2LuksError::NoAuthenticatorError)?, devs => { for mut dev in devs.into_iter() { - match dev.hmac_challange(&cred, &salt[..]) { + match dev.get_hmac_assertion(&cred, &sha256(&[&salt[..]]), None, None) { Ok(secret) => { - return Ok(secret); + return Ok(secret.0); } Err(e) => { errs.push(e); diff --git a/src/main.rs b/src/main.rs index e7ac839..050fc8f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,9 +7,8 @@ use crate::device::*; use crate::error::*; use cryptsetup_rs as luks; use cryptsetup_rs::Luks1CryptDevice; -use ring::digest; -use std::io::{self}; +use std::io; use std::path::PathBuf; use std::process::exit; @@ -26,12 +25,7 @@ fn open_container(device: &PathBuf, name: &str, secret: &[u8; 32]) -> Fido2LuksR } fn assemble_secret(hmac_result: &[u8], salt: &[u8]) -> [u8; 32] { - let mut digest = digest::Context::new(&digest::SHA256); - digest.update(salt); - digest.update(hmac_result); - let mut secret = [0u8; 32]; - secret.as_mut().copy_from_slice(digest.finish().as_ref()); - secret + util::sha256(&[salt, hmac_result]) } fn main() -> Fido2LuksResult<()> { diff --git a/src/util.rs b/src/util.rs index 516cd35..e7366d0 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,8 +1,19 @@ use crate::error::*; +use ring::digest; use std::fs::File; use std::io::Read; use std::path::PathBuf; +pub fn sha256<'a>(messages: &[&[u8]]) -> [u8; 32] { + let mut digest = digest::Context::new(&digest::SHA256); + for m in messages.iter() { + digest.update(m); + } + let mut secret = [0u8; 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("")))? { ref pass From 7f2668eded0dc13754ca8b21e42a5c96ca82cc46 Mon Sep 17 00:00:00 2001 From: shimun Date: Fri, 10 Jan 2020 21:32:39 +0100 Subject: [PATCH 2/2] allow for named credentials --- Cargo.lock | 34 ++++++++++++++++++++++++++++++---- README.md | 2 +- src/cli.rs | 10 +++++++--- src/device.rs | 10 +++++----- 4 files changed, 43 insertions(+), 13 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 87535c5..2c11f2a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -115,15 +115,25 @@ dependencies = [ "uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "csv-core" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ctap_hmac" -version = "0.1.1" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "cbor-codec 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "hex 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -173,10 +183,10 @@ dependencies = [ [[package]] name = "fido2luks" -version = "0.2.1" +version = "0.2.2" dependencies = [ "cryptsetup-rs 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "ctap_hmac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ctap_hmac 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "libcryptsetup-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -208,6 +218,11 @@ name = "hex" version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "hex" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "lazy_static" version = "1.4.0" @@ -235,6 +250,14 @@ dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "memchr" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "num-derive" version = "0.2.5" @@ -619,7 +642,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum cryptsetup-rs 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8b1eb6abff80fdc7b52c37b3e58f5a4cbda78bffc01ac7b02c1296552a07028a" -"checksum ctap_hmac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4f91b9400ac9c99e3280065f5bfd6eb7f0a9bb737a7fd166fda4153338e115e3" +"checksum csv-core 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9b5cadb6b25c77aeff80ba701712494213f4a8418fcda2ee11b6560c3ad0bf4c" +"checksum ctap_hmac 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4d57004228e303ed0d161f081020240d969ce18b623c3f4503645e1a06b42ae7" "checksum errno 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "c2a071601ed01b988f896ab14b95e67335d1eeb50190932a1320f7fe3cadc84e" "checksum errno-dragonfly 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "14ca354e36190500e1e1fb267c647932382b54053c50b14970856c0b00a35067" "checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" @@ -628,10 +652,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum gcc 0.3.55 (registry+https://github.com/rust-lang/crates.io-index)" = "8f5f3913fa0bfe7ee1fd8248b6b9f42a5af4b9d65ec2dd2c3c26132b950ecfc2" "checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" "checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" +"checksum hex 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "023b39be39e3a2da62a94feb433e91e8bcd37676fbc8bea371daf52b7a769a3e" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" "checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba" "checksum libcryptsetup-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f8cab37dfc7316ea263a42ffa51b4b75c9022538576350d7a416de697384f596" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" +"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" "checksum num-derive 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "eafd0b45c5537c3ba526f79d3e75120036502bebacbb3f3220914067ce39dbf2" "checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" "checksum pkg-config 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "72d5370d90f49f70bd033c3d75e87fc529fbfff9d6f7cccef07d6170079d91ea" diff --git a/README.md b/README.md index 74497e2..fe7e03c 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ This will allow you to unlock your luks encrypted disk with an fido2 compatible key -Note: This has only been tested under Fedora 30 using a Solo Key +Note: This has only been tested under Fedora 31 using a Solo Key, Trezor Model T ## Setup diff --git a/src/cli.rs b/src/cli.rs index 761eb33..a0b3830 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -177,7 +177,11 @@ pub enum Command { }, /// Generate a new FIDO credential #[structopt(name = "credential")] - Credential, + Credential { + /// Name to be displayed on the authenticator if it has a display + #[structopt(env = "FIDO2LUKS_CREDENTIAL_NAME")] + name: Option, + }, /// Check if an authenticator is connected #[structopt(name = "connected")] Connected, @@ -191,8 +195,8 @@ pub fn run_cli() -> Fido2LuksResult<()> { let mut stdout = io::stdout(); let args = parse_cmdline(); match &args.command { - Command::Credential => { - let cred = make_credential_id()?; + Command::Credential { name } => { + let cred = make_credential_id(name.as_ref().map(|n| n.as_ref()))?; println!("{}", hex::encode(&cred.id)); Ok(()) } diff --git a/src/device.rs b/src/device.rs index 30aca2c..8f6d6fc 100644 --- a/src/device.rs +++ b/src/device.rs @@ -25,16 +25,16 @@ fn authenticator_rp() -> PublicKeyCredentialRpEntity<'static> { } } -fn authenticator_user() -> PublicKeyCredentialUserEntity<'static> { +fn authenticator_user(name: Option<&str>) -> PublicKeyCredentialUserEntity { PublicKeyCredentialUserEntity { id: &[0u8], - name: "", + name: name.unwrap_or(""), icon: None, - display_name: None, + display_name: name, } } -pub fn make_credential_id() -> Fido2LuksResult { +pub fn make_credential_id(name: Option<&str>) -> Fido2LuksResult { let mut errs = Vec::new(); match get_devices()? { ref devs if devs.is_empty() => Err(Fido2LuksError::NoAuthenticatorError)?, @@ -43,7 +43,7 @@ pub fn make_credential_id() -> Fido2LuksResult { match dev .make_hmac_credential_full( authenticator_rp(), - authenticator_user(), + authenticator_user(name), &[0u8; 32], &[], authenticator_options(),