use crate::error::*; use crate::util::sha256; use ctap::{ self, extensions::hmac::{FidoHmacCredential, HmacExtension}, 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(name: Option<&str>) -> PublicKeyCredentialUserEntity { PublicKeyCredentialUserEntity { id: &[0u8], name: name.unwrap_or(""), icon: None, display_name: name, } } 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)?, devs => { for mut dev in devs.into_iter() { match dev .make_hmac_credential_full( authenticator_rp(), authenticator_user(name), &[0u8; 32], &[], authenticator_options(), ) .map(|cred| cred.into()) { //TODO: make credentials device specific Ok(cred) => { return Ok(cred); } Err(e) => { errs.push(e); } } } } } Err(errs.pop().ok_or(Fido2LuksError::NoAuthenticatorError)?)? } pub fn perform_challenge(credential_id: &str, salt: &[u8; 32]) -> Fido2LuksResult<[u8; 32]> { let cred = FidoHmacCredential { id: hex::decode(credential_id).unwrap(), 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.get_hmac_assertion(&cred, &sha256(&[&salt[..]]), None, None) { Ok(secret) => { return Ok(secret.0); } Err(e) => { errs.push(e); } } } } } Err(errs.pop().ok_or(Fido2LuksError::NoAuthenticatorError)?)? } pub fn get_devices() -> Fido2LuksResult> { let mut devices = Vec::with_capacity(2); for di in ctap::get_devices()? { match FidoDevice::new(&di) { Err(e) => match e.kind() { FidoErrorKind::ParseCtap | FidoErrorKind::DeviceUnsupported => (), err => Err(FidoError::from(err))?, }, Ok(dev) => devices.push(dev), } } Ok(devices) }