From 0b19760175f372afa6ccf7df174055986afebc59 Mon Sep 17 00:00:00 2001 From: shimun Date: Tue, 28 Apr 2020 19:09:53 +0200 Subject: [PATCH] hint slots --- src/cli.rs | 6 +-- src/error.rs | 18 +++++++++ src/luks.rs | 109 +++++++++++++++++---------------------------------- 3 files changed, 56 insertions(+), 77 deletions(-) diff --git a/src/cli.rs b/src/cli.rs index c1fa2b1..12ce8bf 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -417,7 +417,7 @@ pub fn run_cli() -> Fido2LuksResult<()> { device, &name[..], Box::new(|mut creds| { - let secret = SecretGeneration { + let (secret, cred) = SecretGeneration { credential_ids: CommaSeparated( creds .iter() @@ -429,8 +429,8 @@ pub fn run_cli() -> Fido2LuksResult<()> { await_authenticator: 100, verify_password: None, } - .obtain_secret("Password"); - secret.map(|s| s.to_vec().into_boxed_slice()) + .obtain_secret_and_credential("Password")?; + Ok((secret, hex::encode(cred.id))) }), ), Command::Connected => match get_devices() { diff --git a/src/error.rs b/src/error.rs index 2959de7..18e3bee 100644 --- a/src/error.rs +++ b/src/error.rs @@ -56,9 +56,27 @@ pub enum LuksError { InvalidToken(String), #[fail(display = "No token found")] NoToken, + #[fail(display = "The device already exists")] + DeviceExists, +} + +impl LuksError { + pub fn activate(e: LibcryptErr) -> Fido2LuksError { + match e { + LibcryptErr::IOError(ref io) => match io.raw_os_error() { + Some(1) if io.kind() == ErrorKind::PermissionDenied => Fido2LuksError::WrongSecret, + Some(17) => Fido2LuksError::LuksError { + cause: LuksError::DeviceExists, + }, + _ => return Fido2LuksError::CryptsetupError { cause: e }, + }, + _ => Fido2LuksError::CryptsetupError { cause: e }, + } + } } use libcryptsetup_rs::LibcryptErr; +use std::io::ErrorKind; use std::string::FromUtf8Error; use Fido2LuksError::*; diff --git a/src/luks.rs b/src/luks.rs index 03b1807..bbf24ac 100644 --- a/src/luks.rs +++ b/src/luks.rs @@ -5,6 +5,7 @@ use libcryptsetup_rs::{ size_t, CryptActivateFlags, CryptDevice, CryptInit, CryptLuks2Token, CryptTokenInfo, EncryptionFormat, KeyslotInfo, LibcryptErr, }; +use std::collections::{HashMap, HashSet}; use std::path::Path; use std::result::Result; @@ -49,7 +50,7 @@ struct Fido2LuksToken { impl Fido2LuksToken { fn new(credential_id: impl AsRef<[u8]>, slot: u32) -> Self { Self { - type_: "fido2luks\0".into(), + type_: "fido2luks\0".into(), // Doubles as c style string credential: vec![hex::encode(credential_id)], keyslots: vec![slot.to_string()], } @@ -68,72 +69,12 @@ pub fn open_container>(path: P, name: &str, secret: &[u8]) -> Fid pub fn open_container_token>( path: P, name: &str, - mut secret: Box) -> Fido2LuksResult>>, + mut secret: Box) -> Fido2LuksResult<([u8; 32], String)>>, ) -> Fido2LuksResult<()> { let mut device = load_device_handle(path)?; check_luks2(&mut device)?; - /* - // https://gitlab.com/cryptsetup/cryptsetup/-/blob/0b38128e21175b24f8dd1ad06257754af3d4437f/lib/libcryptsetup.h#L2096 - let mut token_data: Option = None; - fn open_token( - mut device: CryptDevice, - id: i32, - data: Option<&mut Box) -> Fido2LuksResult>>>, - ) -> Result, LibcryptErr> { - dbg!("handler"); - let token: Fido2LuksToken = serde_json::from_value( device.token_handle().json_get(id as u32)?).map_err(|e| LibcryptErr::Other(e.to_string()))?; - if let Some(secret_gen) = data { - secret_gen(token.credential).map_err(|e| LibcryptErr::Other(dbg!(e).to_string())) - } else { - Err(LibcryptErr::Other("No secret_gen".into())) - } - } - //c_token_handler_open!(ext_open_token, Fido2LuksToken, open_token); - extern "C" fn ext_open_token( - cd: *mut libcryptsetup_rs_sys::crypt_device, - token_id: std::os::raw::c_int, - buffer: *mut *mut std::os::raw::c_char, - buffer_len: *mut size_t, - usrptr: *mut std::os::raw::c_void, - ) -> std::os::raw::c_int { - let device = CryptDevice::from_ptr(cd); - let generic_ptr = usrptr as *mut Box) -> Fido2LuksResult>>; - let generic_ref = unsafe { generic_ptr.as_mut() }; - match open_token(device, token_id, generic_ref) { - Ok(secret) => unsafe { - *buffer = Box::into_raw(secret) as *mut std::os::raw::c_char; - 0 - }, - Err(_) => -1, - } - } - fn free_token(boxed: Box<[u8]>) {} - c_token_handler_free!(ext_free_token, free_token); - fn validate_token( - device: &mut CryptDevice, - json: serde_json::value::Value, - ) -> Result<(), LibcryptErr> { - Ok(()) - } - c_token_handler_validate!(ext_validate_token, validate_token); - - - fn dump_token(device: &mut CryptDevice, json: serde_json::value::Value) { - - } - c_token_handler_dump!(ext_dump_token, dump_token);*/ - /*CryptLuks2Token::register("fido2luks\0", Some(ext_open_token), None, None, None)?; - dbg!("here"); - //let mut salt = salt.to_vec().into_boxed_slice(); - match device.token_handle().activate_by_token(Some(&name),None, Some(&mut secret), CryptActivateFlags::empty()) { - Err(e) => match e { - LibcryptErr::IOError(_) => Err(Fido2LuksError::LuksError { cause: LuksError::NoToken}), - _ => Err(e)? - }, - ok => Ok(ok?) - }*/ - let mut creds = Vec::new(); + let mut creds = HashMap::new(); for i in 0..256 { let (status, type_) = device.token_handle().status(i)?; if status == CryptTokenInfo::Inactive { @@ -151,18 +92,38 @@ pub fn open_container_token>( serde_json::from_value(json.clone()).map_err(|_| Fido2LuksError::LuksError { cause: LuksError::InvalidToken(json.to_string()), })?; - creds.extend_from_slice(&info.credential[..]); + let slots = || { + info.keyslots + .iter() + .filter_map(|slot| slot.parse::().ok()) + }; + for cred in info.credential.iter().cloned() { + creds + .entry(cred) + .or_insert_with(|| slots().collect::>()) + .extend(slots()); + } } - device - .activate_handle() - .activate_by_passphrase( - Some(name), - None, - secret(dbg!(creds))?.as_ref(), - CryptActivateFlags::empty(), - ) - .map(|_slot| ()) - .map_err(|_e| Fido2LuksError::WrongSecret) + let (secret, credential) = secret(dbg!(creds.keys().cloned().collect()))?; + + let slots = creds.get(&credential).unwrap(); + let mut slots = slots + .iter() + .cloned() + .map(Option::Some) + .chain(std::iter::once(None).take(slots.is_empty() as usize)); + for slot in slots { + match device + .activate_handle() + .activate_by_passphrase(Some(name), slot, &secret, CryptActivateFlags::empty()) + .map(|_slot| ()) + .map_err(LuksError::activate) + { + Err(Fido2LuksError::WrongSecret) => (), + res => return res, + } + } + Err(Fido2LuksError::WrongSecret) } pub fn add_key>(