diff --git a/bffhd/authentication/fabfire/mod.rs b/bffhd/authentication/fabfire/mod.rs index 5d2d5bb..6c7cb62 100644 --- a/bffhd/authentication/fabfire/mod.rs +++ b/bffhd/authentication/fabfire/mod.rs @@ -2,7 +2,7 @@ mod server; pub use server::FabFire; use rsasl::mechname::Mechname; -use rsasl::registry::{Mechanism, MECHANISMS, Side}; +use rsasl::registry::{Mechanism, Side, MECHANISMS}; const MECHNAME: &'static Mechname = &Mechname::const_new_unchecked(b"X-FABFIRE"); @@ -10,8 +10,8 @@ const MECHNAME: &'static Mechname = &Mechname::const_new_unchecked(b"X-FABFIRE") pub static FABFIRE: Mechanism = Mechanism::build(MECHNAME, 300, None, Some(FabFire::new_server), Side::Client); -use std::marker::PhantomData; use rsasl::property::SizedProperty; +use std::marker::PhantomData; // All Property types must implement Debug. #[derive(Debug)] diff --git a/bffhd/authentication/fabfire/server.rs b/bffhd/authentication/fabfire/server.rs index 36c61f8..3108dd8 100644 --- a/bffhd/authentication/fabfire/server.rs +++ b/bffhd/authentication/fabfire/server.rs @@ -3,7 +3,10 @@ use desfire::desfire::Desfire; use desfire::error::Error as DesfireError; use desfire::iso7816_4::apduresponse::APDUResponse; use rsasl::callback::SessionData; -use rsasl::mechanism::{Authentication, MechanismData, MechanismError, MechanismErrorKind, State, ThisProvider}; +use rsasl::mechanism::{ + Authentication, Demand, DemandReply, MechanismData, MechanismError, MechanismErrorKind, + Provider, State, ThisProvider, +}; use rsasl::prelude::{MessageSent, SASLConfig, SASLError, SessionError}; use rsasl::property::AuthId; use serde::{Deserialize, Serialize}; @@ -62,9 +65,7 @@ impl Display for FabFireError { } } -impl std::error::Error for FabFireError { - -} +impl std::error::Error for FabFireError {} impl MechanismError for FabFireError { fn kind(&self) -> MechanismErrorKind { @@ -92,6 +93,7 @@ struct CardInfo { } struct KeyInfo { + authid: String, key_id: u8, key: Box<[u8]>, } @@ -493,11 +495,19 @@ impl Authentication for FabFire { Ok(_) => { match apdu_response.body { Some(data) => { - let token = String::from_utf8(data).unwrap(); - let prov = - ThisProvider::::with(token.trim_matches(char::from(0))); - let key = session.need_with::(&prov, |key| Ok(Box::from(key.as_slice())))?; - self.key_info = Some(KeyInfo { key_id: 0x01, key }); + let authid = String::from_utf8(data).unwrap(); + let prov = ThisProvider::::with( + authid.trim_matches(char::from(0)), + ); + let key = session + .need_with::(&prov, |key| { + Ok(Box::from(key.as_slice())) + })?; + self.key_info = Some(KeyInfo { + authid, + key_id: 0x01, + key, + }); } None => { tracing::error!("No data in response"); @@ -679,6 +689,25 @@ impl Authentication for FabFire { writer .write_all(&send_buf) .map_err(|e| SessionError::Io { source: e })?; + + struct Prov<'a> { + authid: &'a str, + } + impl<'a> Provider<'a> for Prov<'a> { + fn provide( + &self, + req: &mut Demand<'a>, + ) -> DemandReply<()> + { + req.provide_ref::(self.authid)? + .done() + } + } + let prov = Prov { + authid: &self.key_info.as_ref().unwrap().authid, + }; + session.validate(&prov)?; + return Ok(State::Finished(MessageSent::Yes)); } Err(e) => { diff --git a/bffhd/authentication/fabfire_bin/mod.rs b/bffhd/authentication/fabfire_bin/mod.rs index 7256f62..87e74d6 100644 --- a/bffhd/authentication/fabfire_bin/mod.rs +++ b/bffhd/authentication/fabfire_bin/mod.rs @@ -2,11 +2,10 @@ mod server; pub use server::FabFire; use rsasl::mechname::Mechname; -use rsasl::registry::{Mechanism, MECHANISMS, Side}; +use rsasl::registry::{Mechanism, Side, MECHANISMS}; const MECHNAME: &'static Mechname = &Mechname::const_new_unchecked(b"X-FABFIRE-BIN"); #[linkme::distributed_slice(MECHANISMS)] pub static FABFIRE: Mechanism = Mechanism::build(MECHNAME, 300, None, Some(FabFire::new_server), Side::Client); - diff --git a/bffhd/authentication/fabfire_bin/server.rs b/bffhd/authentication/fabfire_bin/server.rs index be88757..5e8cbb1 100644 --- a/bffhd/authentication/fabfire_bin/server.rs +++ b/bffhd/authentication/fabfire_bin/server.rs @@ -3,7 +3,10 @@ use desfire::desfire::Desfire; use desfire::error::Error as DesfireError; use desfire::iso7816_4::apduresponse::APDUResponse; use rsasl::callback::SessionData; -use rsasl::mechanism::{Authentication, MechanismData, MechanismError, MechanismErrorKind, State, ThisProvider}; +use rsasl::mechanism::{ + Authentication, Demand, DemandReply, MechanismData, MechanismError, MechanismErrorKind, + Provider, State, ThisProvider, +}; use rsasl::prelude::{MessageSent, SASLConfig, SASLError, SessionError}; use rsasl::property::AuthId; use serde::{Deserialize, Serialize}; @@ -62,9 +65,7 @@ impl Display for FabFireError { } } -impl std::error::Error for FabFireError { - -} +impl std::error::Error for FabFireError {} impl MechanismError for FabFireError { fn kind(&self) -> MechanismErrorKind { @@ -92,6 +93,7 @@ struct CardInfo { } struct KeyInfo { + authid: String, key_id: u8, key: Box<[u8]>, } @@ -165,7 +167,7 @@ impl Authentication for FabFire { .write_all(&data) .map_err(|e| SessionError::Io { source: e })?; Ok(State::Running) - }, + } Err(e) => { tracing::error!( "Failed to convert APDUCommand to Vec: {:?}", @@ -209,7 +211,7 @@ impl Authentication for FabFire { .write_all(&data) .map_err(|e| SessionError::Io { source: e })?; Ok(State::Running) - }, + } Err(e) => { tracing::error!("Failed to convert APDUCommand to Vec: {:?}", e); return Err(FabFireError::SerializationError.into()); @@ -266,7 +268,7 @@ impl Authentication for FabFire { .write_all(&data) .map_err(|e| SessionError::Io { source: e })?; Ok(State::Running) - }, + } Err(e) => { tracing::error!("Failed to convert APDUCommand to Vec: {:?}", e); return Err(FabFireError::SerializationError.into()); @@ -327,7 +329,7 @@ impl Authentication for FabFire { .write_all(&data) .map_err(|e| SessionError::Io { source: e })?; Ok(State::Running) - }, + } Err(e) => { tracing::error!("Failed to convert APDUCommand to Vec: {:?}", e); return Err(FabFireError::SerializationError.into()); @@ -351,11 +353,19 @@ impl Authentication for FabFire { Ok(_) => { match apdu_response.body { Some(data) => { - let token = String::from_utf8(data).unwrap(); - let prov = - ThisProvider::::with(token.trim_matches(char::from(0))); - let key = session.need_with::(&prov, |key| Ok(Box::from(key.as_slice())))?; - self.key_info = Some(KeyInfo { key_id: 0x01, key }); + let authid = String::from_utf8(data).unwrap(); + let prov = ThisProvider::::with( + authid.trim_matches(char::from(0)), + ); + let key = session + .need_with::(&prov, |key| { + Ok(Box::from(key.as_slice())) + })?; + self.key_info = Some(KeyInfo { + authid, + key_id: 0x01, + key, + }); } None => { tracing::error!("No data in response"); @@ -380,7 +390,7 @@ impl Authentication for FabFire { .write_all(&data) .map_err(|e| SessionError::Io { source: e })?; Ok(State::Running) - }, + } Err(e) => { tracing::error!("Failed to convert to Vec: {:?}", e); return Err(FabFireError::SerializationError.into()); @@ -429,7 +439,7 @@ impl Authentication for FabFire { .write_all(&data) .map_err(|e| SessionError::Io { source: e })?; Ok(State::Running) - }, + } Err(e) => { tracing::error!("Failed to convert to Vec: {:?}", e); return Err(FabFireError::SerializationError.into()); @@ -446,7 +456,7 @@ impl Authentication for FabFire { tracing::error!("Failed to check response: {:?}", e); Err(FabFireError::ParseError.into()) } - } + }; } Step::Authenticate2 => { // println!("Step: Authenticate2"); @@ -474,9 +484,25 @@ impl Authentication for FabFire { ) .is_ok() { - return Ok(State::Finished(MessageSent::Yes)); + struct Prov<'a> { + authid: &'a str, + } + impl<'a> Provider<'a> for Prov<'a> { + fn provide( + &self, + req: &mut Demand<'a>, + ) -> DemandReply<()> + { + req.provide_ref::(self.authid)?.done() } - }, + } + let prov = Prov { + authid: &self.key_info.as_ref().unwrap().authid, + }; + session.validate(&prov)?; + return Ok(State::Finished(MessageSent::Yes)); + } + } }, None => { tracing::error!("got empty response"); diff --git a/bffhd/authentication/mod.rs b/bffhd/authentication/mod.rs index ea9b777..6ec5c8d 100644 --- a/bffhd/authentication/mod.rs +++ b/bffhd/authentication/mod.rs @@ -1,11 +1,11 @@ use crate::users::Users; use miette::{IntoDiagnostic, WrapErr}; -use std::sync::Arc; -use rsasl::callback::{CallbackError, Request, SessionCallback, SessionData, Context}; +use rsasl::callback::{CallbackError, Context, Request, SessionCallback, SessionData}; use rsasl::mechanism::SessionError; use rsasl::prelude::{Mechname, SASLConfig, SASLServer, Session, Validation}; use rsasl::property::{AuthId, AuthzId, Password}; use rsasl::validate::{Validate, ValidationError}; +use std::sync::Arc; use crate::authentication::fabfire::FabFireCardKey; use crate::users::db::User; @@ -24,30 +24,46 @@ impl Callback { } } impl SessionCallback for Callback { - fn callback(&self, session_data: &SessionData, context: &Context, request: &mut Request) -> Result<(), SessionError> { + fn callback( + &self, + session_data: &SessionData, + context: &Context, + request: &mut Request, + ) -> Result<(), SessionError> { if let Some(authid) = context.get_ref::() { request.satisfy_with::(|| { let user = self.users.get_user(authid).ok_or(CallbackError::NoValue)?; - let kv = user.userdata.kv.get("cardkey").ok_or(CallbackError::NoValue)?; - let card_key = <[u8; 16]>::try_from( - hex::decode(kv).map_err(|_| CallbackError::NoValue)?, - ).map_err(|_| CallbackError::NoValue)?; + let kv = user + .userdata + .kv + .get("cardkey") + .ok_or(CallbackError::NoValue)?; + let card_key = + <[u8; 16]>::try_from(hex::decode(kv).map_err(|_| CallbackError::NoValue)?) + .map_err(|_| CallbackError::NoValue)?; Ok(card_key) })?; } Ok(()) } - fn validate(&self, session_data: &SessionData, context: &Context, validate: &mut Validate<'_>) -> Result<(), ValidationError> { + fn validate( + &self, + session_data: &SessionData, + context: &Context, + validate: &mut Validate<'_>, + ) -> Result<(), ValidationError> { let span = tracing::info_span!(parent: &self.span, "validate"); let _guard = span.enter(); if validate.is::() { match session_data.mechanism().mechanism.as_str() { "PLAIN" => { - let authcid = context.get_ref::() + let authcid = context + .get_ref::() .ok_or(ValidationError::MissingRequiredProperty)?; let authzid = context.get_ref::(); - let password = context.get_ref::() + let password = context + .get_ref::() .ok_or(ValidationError::MissingRequiredProperty)?; // if authzid.is_some() { @@ -56,9 +72,7 @@ impl SessionCallback for Callback { if let Some(user) = self.users.get_user(authcid) { match user.check_password(password) { - Ok(true) => { - validate.finalize::(user) - } + Ok(true) => validate.finalize::(user), Ok(false) => { tracing::warn!(authid=%authcid, "AUTH FAILED: bad password"); } @@ -70,6 +84,14 @@ impl SessionCallback for Callback { tracing::warn!(authid=%authcid, "AUTH FAILED: no such user"); } } + "X-FABFIRE" | "X-FABFIRE-BIN" => { + let authcid = context + .get_ref::() + .ok_or(ValidationError::MissingRequiredProperty)?; + if let Some(user) = self.users.get_user(authcid) { + validate.finalize::(user) + } + } _ => {} } } diff --git a/bffhd/capnp/authenticationsystem.rs b/bffhd/capnp/authenticationsystem.rs index 943933c..c81f547 100644 --- a/bffhd/capnp/authenticationsystem.rs +++ b/bffhd/capnp/authenticationsystem.rs @@ -2,21 +2,21 @@ use capnp::capability::Promise; use capnp::Error; use capnp_rpc::pry; use rsasl::mechname::Mechname; +use rsasl::prelude::State as SaslState; +use rsasl::prelude::{MessageSent, Session}; use rsasl::property::AuthId; use std::fmt; use std::fmt::{Formatter, Write}; use std::io::Cursor; -use rsasl::prelude::{MessageSent, Session}; -use rsasl::prelude::State as SaslState; use tracing::Span; +use crate::authentication::V; use crate::capnp::session::APISession; use crate::session::SessionManager; use api::authenticationsystem_capnp::authentication::{ AbortParams, AbortResults, Server as AuthenticationSystem, StepParams, StepResults, }; use api::authenticationsystem_capnp::{response, response::Error as ErrorCode}; -use crate::authentication::V; const TARGET: &str = "bffh::api::authenticationsystem"; diff --git a/bffhd/initiators/process.rs b/bffhd/initiators/process.rs index d714ec3..79f6bde 100644 --- a/bffhd/initiators/process.rs +++ b/bffhd/initiators/process.rs @@ -1,5 +1,6 @@ use super::Initiator; use super::InitiatorCallbacks; +use crate::resources::modules::fabaccess::Status; use crate::resources::state::State; use crate::utils::linebuffer::LineBuffer; use async_process::{Child, ChildStderr, ChildStdout, Command, Stdio}; @@ -11,7 +12,6 @@ use std::future::Future; use std::io; use std::pin::Pin; use std::task::{Context, Poll}; -use crate::resources::modules::fabaccess::Status; #[derive(Debug, Serialize, Deserialize)] pub enum InputMessage { @@ -63,7 +63,12 @@ struct ProcessState { impl ProcessState { pub fn new(stdout: ChildStdout, stderr: ChildStderr, child: Child) -> Self { - Self { stdout, stderr, stderr_closed: false, child } + Self { + stdout, + stderr, + stderr_closed: false, + child, + } } fn try_process(&mut self, buffer: &[u8], callbacks: &mut InitiatorCallbacks) -> usize { @@ -100,7 +105,9 @@ impl ProcessState { let InputMessage::SetState(status) = state; callbacks.set_status(status); } - Err(error) => tracing::warn!(%error, "process initiator did not send a valid line"), + Err(error) => { + tracing::warn!(%error, "process initiator did not send a valid line") + } } } } @@ -202,8 +209,8 @@ impl Future for Process { impl Initiator for Process { fn new(params: &HashMap, callbacks: InitiatorCallbacks) -> miette::Result - where - Self: Sized, + where + Self: Sized, { let cmd = params .get("cmd") diff --git a/bffhd/session/mod.rs b/bffhd/session/mod.rs index dee72a6..2ac2be7 100644 --- a/bffhd/session/mod.rs +++ b/bffhd/session/mod.rs @@ -1,10 +1,10 @@ use crate::authorization::permissions::Permission; use crate::authorization::roles::Roles; use crate::resources::Resource; +use crate::users::db::User; use crate::users::{db, UserRef}; use crate::Users; use tracing::Span; -use crate::users::db::User; #[derive(Clone)] pub struct SessionManager { @@ -18,7 +18,9 @@ impl SessionManager { } pub fn try_open(&self, parent: &Span, uid: impl AsRef) -> Option { - self.users.get_user(uid.as_ref()).map(|user| self.open(parent, user)) + self.users + .get_user(uid.as_ref()) + .map(|user| self.open(parent, user)) } // TODO: make infallible