This commit is contained in:
parent
55bae4161e
commit
63f29249d3
7
Cargo.lock
generated
7
Cargo.lock
generated
@ -383,6 +383,7 @@ dependencies = [
|
||||
"failure",
|
||||
"hex",
|
||||
"libcryptsetup-rs",
|
||||
"pamsm",
|
||||
"ring",
|
||||
"rpassword",
|
||||
"serde",
|
||||
@ -596,6 +597,12 @@ version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ab52be62400ca80aa00285d25253d7f7c437b7375c4de678f5405d3afe82ca5"
|
||||
|
||||
[[package]]
|
||||
name = "pamsm"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3580ed2ebe075c74db583233318abf4b07bc8d9a40c7691d0ae9c186e19e43dd"
|
||||
|
||||
[[package]]
|
||||
name = "peeking_take_while"
|
||||
version = "0.1.2"
|
||||
|
11
Cargo.toml
11
Cargo.toml
@ -24,6 +24,7 @@ libcryptsetup-rs = "0.4.1"
|
||||
serde_json = "1.0.51"
|
||||
serde_derive = "1.0.106"
|
||||
serde = "1.0.106"
|
||||
pamsm = { version = "0.4.1", features = ["libpam"] }
|
||||
|
||||
[build-dependencies]
|
||||
ctap_hmac = { version="0.4.2", features = ["request_multiple"] }
|
||||
@ -41,12 +42,22 @@ panic = 'abort'
|
||||
incremental = false
|
||||
overflow-checks = false
|
||||
|
||||
[[bin]]
|
||||
name = "fido2luks"
|
||||
path = "src/main.rs"
|
||||
|
||||
[lib]
|
||||
name = "fido2luks_pam"
|
||||
path = "src/lib.rs"
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[package.metadata.deb]
|
||||
depends = "$auto, cryptsetup"
|
||||
build-depends = "libclang-dev, libcryptsetup-dev"
|
||||
extended-description = "Decrypt your LUKS partition using a FIDO2 compatible authenticator"
|
||||
assets = [
|
||||
["target/release/fido2luks", "usr/bin/", "755"],
|
||||
["target/release/libfido2luks_pam.so", "usr/lib/x86_64-linux-gnu/security/pam_fido2luks", "755"],
|
||||
["fido2luks.bash", "usr/share/bash-completion/completions/fido2luks", "644"],
|
||||
["initramfs-tools/keyscript.sh", "/lib/cryptsetup/scripts/fido2luks", "755" ],
|
||||
["initramfs-tools/hook/fido2luks.sh", "etc/initramfs-tools/hooks/", "755" ],
|
||||
|
111
src/lib.rs
Normal file
111
src/lib.rs
Normal file
@ -0,0 +1,111 @@
|
||||
#[macro_use]
|
||||
extern crate failure;
|
||||
extern crate ctap_hmac as ctap;
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
#[macro_use]
|
||||
extern crate pamsm;
|
||||
use crate::cli_args::{CommaSeparated, HexEncoded};
|
||||
use crate::device::*;
|
||||
use crate::error::*;
|
||||
use crate::luks::*;
|
||||
use ctap::FidoCredential;
|
||||
use failure::_core::time::Duration;
|
||||
use pamsm::PamLibExt;
|
||||
use pamsm::*;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::ffi::CStr;
|
||||
use std::str::FromStr;
|
||||
|
||||
pub mod cli_args;
|
||||
pub mod device;
|
||||
pub mod error;
|
||||
pub mod luks;
|
||||
pub mod util;
|
||||
|
||||
struct PamFido2Luks;
|
||||
|
||||
impl PamFido2Luks {
|
||||
fn open(&self, password: String, args: Vec<String>) -> Fido2LuksResult<()> {
|
||||
let args: HashMap<String, String> = args
|
||||
.into_iter()
|
||||
.filter_map(|arg| {
|
||||
let mut parts = arg.split("=");
|
||||
parts
|
||||
.by_ref()
|
||||
.next()
|
||||
.map(|key| (key.to_string(), parts.collect::<Vec<_>>().join("=")))
|
||||
})
|
||||
.collect();
|
||||
|
||||
let credentials = args
|
||||
.get("credentials")
|
||||
.map(|creds| {
|
||||
<CommaSeparated<String>>::from_str(creds)
|
||||
.expect("Invalid credentials")
|
||||
.0 //TODO: proper error handling
|
||||
})
|
||||
.unwrap_or_default();
|
||||
let pin = args.get("pin");
|
||||
let device = args.get("device");
|
||||
let name = args.get("name");
|
||||
|
||||
if let (Some(device), Some(name)) = (device, name) {
|
||||
let mut device = LuksDevice::load(device)?;
|
||||
let mut additional_credentials: HashSet<String> = HashSet::new();
|
||||
if device.is_luks2()? {
|
||||
for token in device.tokens()? {
|
||||
let (_, token) = token?;
|
||||
additional_credentials.extend(token.credential.into_iter());
|
||||
}
|
||||
}
|
||||
let credentials: Vec<FidoCredential> = credentials
|
||||
.into_iter()
|
||||
.chain(additional_credentials.into_iter())
|
||||
.map(|cred| HexEncoded::from_str(cred.as_str()))
|
||||
.map(|cred| FidoCredential {
|
||||
id: cred.unwrap().0,
|
||||
public_key: None,
|
||||
})
|
||||
.collect();
|
||||
let credentials: Vec<&FidoCredential> = credentials.iter().collect();
|
||||
if !credentials.is_empty() {
|
||||
let secret = util::sha256(&[&perform_challenge(
|
||||
&credentials[..],
|
||||
&util::sha256(&[password.as_bytes()]),
|
||||
Duration::from_secs(15),
|
||||
pin.map(AsRef::as_ref),
|
||||
)?
|
||||
.0[..]]);
|
||||
device.activate(name.as_str(), &secret[..], None)?;
|
||||
} else {
|
||||
unimplemented!("custom error")
|
||||
}
|
||||
unimplemented!()
|
||||
} else {
|
||||
unimplemented!("custom error")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PamServiceModule for PamFido2Luks {
|
||||
fn authenticate(pamh: Pam, flag: PamFlag, args: Vec<String>) -> PamError {
|
||||
let password = match pamh.get_authtok(None) {
|
||||
Err(_) => return PamError::AUTH_ERR,
|
||||
Ok(p) => p.map(|s| s.to_str().map(str::to_string).unwrap()),
|
||||
};
|
||||
if let Some(password) = password {
|
||||
match PamFido2Luks.open(password, args) {
|
||||
Ok(_) => PamError::SUCCESS,
|
||||
Err(e) => match e {
|
||||
//TODO: output more detailed error
|
||||
_ => PamError::AUTH_ERR,
|
||||
},
|
||||
}
|
||||
} else {
|
||||
PamError::AUTH_ERR
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pam_module!(PamFido2Luks);
|
Loading…
x
Reference in New Issue
Block a user