Warning: This release cointains changes to way credentials are generated, which may cause your authenticator to reject the old credential.
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "fido2luks"
|
name = "fido2luks"
|
||||||
version = "0.2.1"
|
version = "0.2.2"
|
||||||
authors = ["shimunn <shimun@shimun.net>"]
|
authors = ["shimunn <shimun@shimun.net>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
@@ -15,7 +15,7 @@ license-file = "LICENSE"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
#ctap = "0.1.0"
|
#ctap = "0.1.0"
|
||||||
ctap_hmac = "0.1.1"
|
ctap_hmac = "0.2.1"
|
||||||
cryptsetup-rs = "0.2.1"
|
cryptsetup-rs = "0.2.1"
|
||||||
libcryptsetup-sys = "0.1.2"
|
libcryptsetup-sys = "0.1.2"
|
||||||
|
|
||||||
|
@@ -70,10 +70,6 @@ pub fn add_password_to_luks(
|
|||||||
Ok(slot)
|
Ok(slot)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn authenticator_connected() -> Fido2LuksResult<bool> {
|
|
||||||
Ok(!device::get_devices()?.is_empty())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, StructOpt)]
|
#[derive(Debug, StructOpt)]
|
||||||
pub struct Args {
|
pub struct Args {
|
||||||
/// Request passwords via Stdin instead of using the password helper
|
/// Request passwords via Stdin instead of using the password helper
|
||||||
|
@@ -1,11 +1,39 @@
|
|||||||
use crate::error::*;
|
use crate::error::*;
|
||||||
|
use crate::util::sha256;
|
||||||
|
|
||||||
use ctap::{
|
use ctap::{
|
||||||
self,
|
self,
|
||||||
extensions::hmac::{FidoHmacCredential, HmacExtension},
|
extensions::hmac::{FidoHmacCredential, HmacExtension},
|
||||||
FidoDevice, FidoError, FidoErrorKind,
|
AuthenticatorOptions, FidoDevice, FidoError, FidoErrorKind, PublicKeyCredentialRpEntity,
|
||||||
|
PublicKeyCredentialUserEntity,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const RP_ID: &'static str = "fido2luks";
|
||||||
|
|
||||||
|
fn authenticator_options() -> Option<AuthenticatorOptions> {
|
||||||
|
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<FidoHmacCredential> {
|
pub fn make_credential_id() -> Fido2LuksResult<FidoHmacCredential> {
|
||||||
let mut errs = Vec::new();
|
let mut errs = Vec::new();
|
||||||
match get_devices()? {
|
match get_devices()? {
|
||||||
@@ -13,7 +41,13 @@ pub fn make_credential_id() -> Fido2LuksResult<FidoHmacCredential> {
|
|||||||
devs => {
|
devs => {
|
||||||
for mut dev in devs.into_iter() {
|
for mut dev in devs.into_iter() {
|
||||||
match dev
|
match dev
|
||||||
.make_credential("fido2luks", &[0u8], "", &[0u8; 32])
|
.make_hmac_credential_full(
|
||||||
|
authenticator_rp(),
|
||||||
|
authenticator_user(),
|
||||||
|
&[0u8; 32],
|
||||||
|
&[],
|
||||||
|
authenticator_options(),
|
||||||
|
)
|
||||||
.map(|cred| cred.into())
|
.map(|cred| cred.into())
|
||||||
{
|
{
|
||||||
//TODO: make credentials device specific
|
//TODO: make credentials device specific
|
||||||
@@ -33,16 +67,16 @@ pub fn make_credential_id() -> Fido2LuksResult<FidoHmacCredential> {
|
|||||||
pub fn perform_challenge(credential_id: &str, salt: &[u8; 32]) -> Fido2LuksResult<[u8; 32]> {
|
pub fn perform_challenge(credential_id: &str, salt: &[u8; 32]) -> Fido2LuksResult<[u8; 32]> {
|
||||||
let cred = FidoHmacCredential {
|
let cred = FidoHmacCredential {
|
||||||
id: hex::decode(credential_id).unwrap(),
|
id: hex::decode(credential_id).unwrap(),
|
||||||
rp_id: "hmac".to_string(),
|
rp_id: RP_ID.to_string(),
|
||||||
};
|
};
|
||||||
let mut errs = Vec::new();
|
let mut errs = Vec::new();
|
||||||
match get_devices()? {
|
match get_devices()? {
|
||||||
ref devs if devs.is_empty() => Err(Fido2LuksError::NoAuthenticatorError)?,
|
ref devs if devs.is_empty() => Err(Fido2LuksError::NoAuthenticatorError)?,
|
||||||
devs => {
|
devs => {
|
||||||
for mut dev in devs.into_iter() {
|
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) => {
|
Ok(secret) => {
|
||||||
return Ok(secret);
|
return Ok(secret.0);
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
errs.push(e);
|
errs.push(e);
|
||||||
|
10
src/main.rs
10
src/main.rs
@@ -7,9 +7,8 @@ use crate::device::*;
|
|||||||
use crate::error::*;
|
use crate::error::*;
|
||||||
use cryptsetup_rs as luks;
|
use cryptsetup_rs as luks;
|
||||||
use cryptsetup_rs::Luks1CryptDevice;
|
use cryptsetup_rs::Luks1CryptDevice;
|
||||||
use ring::digest;
|
|
||||||
|
|
||||||
use std::io::{self};
|
use std::io;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process::exit;
|
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] {
|
fn assemble_secret(hmac_result: &[u8], salt: &[u8]) -> [u8; 32] {
|
||||||
let mut digest = digest::Context::new(&digest::SHA256);
|
util::sha256(&[salt, hmac_result])
|
||||||
digest.update(salt);
|
|
||||||
digest.update(hmac_result);
|
|
||||||
let mut secret = [0u8; 32];
|
|
||||||
secret.as_mut().copy_from_slice(digest.finish().as_ref());
|
|
||||||
secret
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> Fido2LuksResult<()> {
|
fn main() -> Fido2LuksResult<()> {
|
||||||
|
11
src/util.rs
11
src/util.rs
@@ -1,8 +1,19 @@
|
|||||||
use crate::error::*;
|
use crate::error::*;
|
||||||
|
use ring::digest;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::path::PathBuf;
|
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<String> {
|
pub fn read_password(q: &str, verify: bool) -> Fido2LuksResult<String> {
|
||||||
match rpassword::read_password_from_tty(Some(&[q, ": "].join("")))? {
|
match rpassword::read_password_from_tty(Some(&[q, ": "].join("")))? {
|
||||||
ref pass
|
ref pass
|
||||||
|
Reference in New Issue
Block a user