pam module
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
shimun 2020-09-25 00:23:36 +02:00
parent 55bae4161e
commit 63f29249d3
Signed by: shimun
GPG Key ID: E81D8382DC2F971B
3 changed files with 129 additions and 0 deletions

7
Cargo.lock generated
View File

@ -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"

View File

@ -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
View 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);