This commit is contained in:
parent
55bae4161e
commit
63f29249d3
7
Cargo.lock
generated
7
Cargo.lock
generated
@ -383,6 +383,7 @@ dependencies = [
|
|||||||
"failure",
|
"failure",
|
||||||
"hex",
|
"hex",
|
||||||
"libcryptsetup-rs",
|
"libcryptsetup-rs",
|
||||||
|
"pamsm",
|
||||||
"ring",
|
"ring",
|
||||||
"rpassword",
|
"rpassword",
|
||||||
"serde",
|
"serde",
|
||||||
@ -596,6 +597,12 @@ version = "0.20.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1ab52be62400ca80aa00285d25253d7f7c437b7375c4de678f5405d3afe82ca5"
|
checksum = "1ab52be62400ca80aa00285d25253d7f7c437b7375c4de678f5405d3afe82ca5"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pamsm"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3580ed2ebe075c74db583233318abf4b07bc8d9a40c7691d0ae9c186e19e43dd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "peeking_take_while"
|
name = "peeking_take_while"
|
||||||
version = "0.1.2"
|
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_json = "1.0.51"
|
||||||
serde_derive = "1.0.106"
|
serde_derive = "1.0.106"
|
||||||
serde = "1.0.106"
|
serde = "1.0.106"
|
||||||
|
pamsm = { version = "0.4.1", features = ["libpam"] }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
ctap_hmac = { version="0.4.2", features = ["request_multiple"] }
|
ctap_hmac = { version="0.4.2", features = ["request_multiple"] }
|
||||||
@ -41,12 +42,22 @@ panic = 'abort'
|
|||||||
incremental = false
|
incremental = false
|
||||||
overflow-checks = 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]
|
[package.metadata.deb]
|
||||||
depends = "$auto, cryptsetup"
|
depends = "$auto, cryptsetup"
|
||||||
build-depends = "libclang-dev, libcryptsetup-dev"
|
build-depends = "libclang-dev, libcryptsetup-dev"
|
||||||
extended-description = "Decrypt your LUKS partition using a FIDO2 compatible authenticator"
|
extended-description = "Decrypt your LUKS partition using a FIDO2 compatible authenticator"
|
||||||
assets = [
|
assets = [
|
||||||
["target/release/fido2luks", "usr/bin/", "755"],
|
["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"],
|
["fido2luks.bash", "usr/share/bash-completion/completions/fido2luks", "644"],
|
||||||
["initramfs-tools/keyscript.sh", "/lib/cryptsetup/scripts/fido2luks", "755" ],
|
["initramfs-tools/keyscript.sh", "/lib/cryptsetup/scripts/fido2luks", "755" ],
|
||||||
["initramfs-tools/hook/fido2luks.sh", "etc/initramfs-tools/hooks/", "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