From 0ed53f5cc9302710d2f37e2c6909c5b9a1333ca4 Mon Sep 17 00:00:00 2001 From: Nadja Reitzenstein Date: Tue, 1 Nov 2022 10:47:51 +0100 Subject: [PATCH] Update to latest rsasl --- Cargo.lock | 9 ++- Cargo.toml | 12 ++-- bffhd/authentication/fabfire/server.rs | 4 +- bffhd/authentication/mod.rs | 90 +++++++++++++------------- bffhd/capnp/authenticationsystem.rs | 44 ++++++------- bffhd/capnp/connection.rs | 7 +- bffhd/initiators/mod.rs | 2 +- bffhd/session/mod.rs | 37 +++++------ bffhd/users/db.rs | 4 +- 9 files changed, 107 insertions(+), 102 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 91fd5ed..2e0806a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -937,9 +937,7 @@ dependencies = [ [[package]] name = "desfire" -version = "0.2.0-alpha2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "337f0fcd6ef888be0962aeff547f1b219f4190ea785b5c33328f071e91405411" +version = "0.2.0-alpha1" dependencies = [ "aes", "block-modes", @@ -2506,8 +2504,9 @@ dependencies = [ [[package]] name = "rsasl" -version = "2.0.0-rc.2" -source = "git+https://github.com/dequbed/rsasl.git?branch=development#19d2346dc76e5f3b449e3e3ab35c72205c6c4907" +version = "2.0.0-rc.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "103603eacc28423095a1366653d823e5d2f4bac86bf7874b8f370d320b671207" dependencies = [ "acid_io", "linkme", diff --git a/Cargo.toml b/Cargo.toml index 6831a30..3be5027 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -84,7 +84,9 @@ capnp = "0.14" capnp-rpc = "0.14.1" # API Authentication -desfire = "0.2.0-alpha1" +#desfire = "0.2.0-alpha1" +desfire = { path = "../nfc_rs" } + hex = { version = "0.4.3", features = ["serde"] } futures-signals = "0.3.22" @@ -112,10 +114,9 @@ rustls-native-certs = "0.6.1" shadow-rs = "0.11" [dependencies.rsasl] -git = "https://github.com/dequbed/rsasl.git" -branch = "development" +version = "2.0.0-rc.3" default_features = false -features = ["unstable_custom_mechanism", "provider", "registry_static", "plain"] +features = ["unstable_custom_mechanism", "provider", "registry_static", "config_builder", "plain"] [dev-dependencies] futures-test = "0.3.16" @@ -126,3 +127,6 @@ shadow-rs = "0.11" [workspace] members = ["runtime/*", "modules/*", "api"] + +[patch.crates-io] +desfire = { path = "../nfc_rs" } \ No newline at end of file diff --git a/bffhd/authentication/fabfire/server.rs b/bffhd/authentication/fabfire/server.rs index 3fa99f5..36c61f8 100644 --- a/bffhd/authentication/fabfire/server.rs +++ b/bffhd/authentication/fabfire/server.rs @@ -3,7 +3,7 @@ use desfire::desfire::Desfire; use desfire::error::Error as DesfireError; use desfire::iso7816_4::apduresponse::APDUResponse; use rsasl::callback::SessionData; -use rsasl::mechanism::{Authentication, MechanismError, MechanismErrorKind, State, ThisProvider}; +use rsasl::mechanism::{Authentication, MechanismData, MechanismError, MechanismErrorKind, State, ThisProvider}; use rsasl::prelude::{MessageSent, SASLConfig, SASLError, SessionError}; use rsasl::property::AuthId; use serde::{Deserialize, Serialize}; @@ -177,7 +177,7 @@ impl FabFire { impl Authentication for FabFire { fn step( &mut self, - session: &mut SessionData, + session: &mut MechanismData<'_>, input: Option<&[u8]>, writer: &mut dyn Write, ) -> Result { diff --git a/bffhd/authentication/mod.rs b/bffhd/authentication/mod.rs index 2b7a23b..68ff703 100644 --- a/bffhd/authentication/mod.rs +++ b/bffhd/authentication/mod.rs @@ -1,12 +1,14 @@ use crate::users::Users; -use miette::{Context, IntoDiagnostic}; +use miette::{IntoDiagnostic, WrapErr}; use std::sync::Arc; -use rsasl::callback::{CallbackError, Request, SessionCallback, SessionData}; +use rsasl::callback::{CallbackError, Request, SessionCallback, SessionData, Context}; use rsasl::mechanism::SessionError; -use rsasl::prelude::{Mechname, SASLConfig, SASLServer, Session}; -use rsasl::property::AuthId; +use rsasl::prelude::{Mechname, SASLConfig, SASLServer, Session, Validation}; +use rsasl::property::{AuthId, AuthzId, Password}; +use rsasl::validate::{Validate, ValidationError}; use crate::authentication::fabfire::FabFireCardKey; +use crate::users::db::User; mod fabfire; @@ -21,7 +23,7 @@ impl Callback { } } impl SessionCallback for Callback { - fn callback(&self, session_data: &SessionData, context: &rsasl::callback::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)?; @@ -35,48 +37,51 @@ impl SessionCallback for Callback { Ok(()) } - /*fn validate( - &self, - session: &mut SessionData, - validation: Validation, - _mechanism: &Mechname, - ) -> Result<(), SessionError> { + 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(); - match validation { - validations::SIMPLE => { - let authnid = session - .get_property::() - .ok_or(SessionError::no_property::())?; - tracing::debug!(authid=%authnid, "SIMPLE validation requested"); + if validate.is::() { + match session_data.mechanism().mechanism.as_str() { + "PLAIN" => { + let authcid = context.get_ref::() + .ok_or(ValidationError::MissingRequiredProperty)?; + let authzid = context.get_ref::(); + let password = context.get_ref::() + .ok_or(ValidationError::MissingRequiredProperty)?; - if let Some(user) = self.users.get_user(authnid.as_str()) { - let passwd = session - .get_property::() - .ok_or(SessionError::no_property::())?; - - if user - .check_password(passwd.as_bytes()) - .map_err(|_e| SessionError::AuthenticationFailure)? - { - return Ok(()); - } else { - tracing::warn!(authid=%authnid, "AUTH FAILED: bad password"); + if authzid.is_some() { + return Ok(()) } - } else { - tracing::warn!(authid=%authnid, "AUTH FAILED: no such user '{}'", authnid); - } - Err(SessionError::AuthenticationFailure) - } - _ => { - tracing::error!(?validation, "Unimplemented validation requested"); - Err(SessionError::no_validate(validation)) + if let Some(user) = self.users.get_user(authcid) { + match user.check_password(password) { + Ok(true) => { + validate.finalize::(user) + } + Ok(false) => { + tracing::warn!(authid=%authcid, "AUTH FAILED: bad password"); + } + Err(error) => { + tracing::warn!(authid=%authcid, "Bad DB entry: {}", error); + } + } + } else { + tracing::warn!(authid=%authcid, "AUTH FAILED: no such user"); + } + } + _ => {} } } - }*/ + Ok(()) + } } +pub struct V; +impl Validation for V { + type Value = User; +} + +#[derive(Clone)] struct Inner { rsasl: Arc, } @@ -101,7 +106,7 @@ impl AuthenticationHandle { .with_callback(Callback::new(userdb)) .unwrap(); - let mechs: Vec<&'static str> = SASLServer::new(config.clone()) + let mechs: Vec<&'static str> = SASLServer::::new(config.clone()) .get_available() .into_iter() .map(|m| m.mechanism.as_str()) @@ -114,17 +119,14 @@ impl AuthenticationHandle { } } - pub fn start(&self, mechanism: &Mechname) -> miette::Result { + pub fn start(&self, mechanism: &Mechname) -> miette::Result> { Ok(SASLServer::new(self.inner.rsasl.clone()) .start_suggested(mechanism) .into_diagnostic() .wrap_err("Failed to start a SASL authentication with the given mechanism")?) } - pub fn list_available_mechs(&self) -> impl IntoIterator { + pub fn sess(&self) -> SASLServer { SASLServer::new(self.inner.rsasl.clone()) - .get_available() - .into_iter() - .map(|m| m.mechanism) } } diff --git a/bffhd/capnp/authenticationsystem.rs b/bffhd/capnp/authenticationsystem.rs index 2e10967..943933c 100644 --- a/bffhd/capnp/authenticationsystem.rs +++ b/bffhd/capnp/authenticationsystem.rs @@ -16,6 +16,7 @@ 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"; @@ -28,7 +29,7 @@ impl Authentication { pub fn new( parent: &Span, mechanism: &Mechname, /* TODO: this is stored in session as well, get it out of there. */ - session: Session, + session: Session, sessionmanager: SessionManager, ) -> Self { let span = tracing::info_span!( @@ -93,7 +94,7 @@ enum State { InvalidMechanism, Finished, Aborted, - Running(Session, SessionManager), + Running(Session, SessionManager), } impl AuthenticationSystem for Authentication { @@ -122,36 +123,35 @@ impl AuthenticationSystem for Authentication { { let data: &[u8] = pry!(pry!(params.get()).get_data()); - let mut out = Cursor::new(Vec::new()); + let mut out = Vec::new(); match session.step(Some(data), &mut out) { Ok(SaslState::Finished(sent)) => { self.state = State::Finished; - let uid = pry!(session.get_property::().ok_or_else(|| { - tracing::warn!("Authentication didn't provide an authid as required."); - capnp::Error::failed( - "Authentication didn't provide an authid as required".to_string(), - ) - })); - let session = pry!(manager.open(&self.span, uid.as_ref()).ok_or_else(|| { - tracing::warn!(uid = uid.as_str(), "Failed to lookup the given user"); - capnp::Error::failed("Failed to lookup the given user".to_string()) - })); + if let Some(user) = session.validation() { + let session = manager.open(&self.span, user); + response = Response { + union_field: "successful", + }; - response = Response { - union_field: "successful", - }; + let mut builder = builder.init_successful(); + if sent == MessageSent::Yes { + builder.set_additional_data(out.as_slice()); + } - let mut builder = builder.init_successful(); - if sent == MessageSent::Yes { - builder.set_additional_data(out.into_inner().as_slice()); + APISession::build(session, builder) + } else { + let mut builder = builder.init_failed(); + builder.set_code(ErrorCode::InvalidCredentials); + + response = Response { + union_field: "error", + }; } - - APISession::build(session, builder) } Ok(SaslState::Running) => { self.state = State::Running(session, manager); - builder.set_challenge(out.into_inner().as_slice()); + builder.set_challenge(out.as_slice()); response = Response { union_field: "challenge", diff --git a/bffhd/capnp/connection.rs b/bffhd/capnp/connection.rs index 9595ed9..2e96dc6 100644 --- a/bffhd/capnp/connection.rs +++ b/bffhd/capnp/connection.rs @@ -95,9 +95,10 @@ impl bootstrap::Server for BootCap { let builder = result.get(); let mechs: Vec<_> = self .authentication - .list_available_mechs() + .sess() + .get_available() .into_iter() - .map(|m| m.as_str()) + .map(|m| m.mechanism.as_str()) .collect(); let mut mechbuilder = builder.init_mechs(mechs.len() as u32); for (i, m) in mechs.iter().enumerate() { @@ -146,7 +147,7 @@ impl bootstrap::Server for BootCap { tracing::trace!(params.mechanism = mechanism, "method call"); - let mechname = Mechname::new(mechanism.as_bytes()); + let mechname = Mechname::parse(mechanism.as_bytes()); let auth = if let Ok(mechname) = mechname { if let Ok(session) = self.authentication.start(mechname) { Authentication::new(&self.span, mechname, session, self.sessionmanager.clone()) diff --git a/bffhd/initiators/mod.rs b/bffhd/initiators/mod.rs index f20ee9d..c5cf613 100644 --- a/bffhd/initiators/mod.rs +++ b/bffhd/initiators/mod.rs @@ -56,7 +56,7 @@ impl InitiatorCallbacks { } pub fn open_session(&self, uid: &str) -> Option { - self.sessions.open(&self.span, uid) + self.sessions.try_open(&self.span, uid) } } diff --git a/bffhd/session/mod.rs b/bffhd/session/mod.rs index 87eb902..dee72a6 100644 --- a/bffhd/session/mod.rs +++ b/bffhd/session/mod.rs @@ -4,6 +4,7 @@ use crate::resources::Resource; use crate::users::{db, UserRef}; use crate::Users; use tracing::Span; +use crate::users::db::User; #[derive(Clone)] pub struct SessionManager { @@ -16,25 +17,25 @@ impl SessionManager { Self { users, roles } } + pub fn try_open(&self, parent: &Span, uid: impl AsRef) -> Option { + self.users.get_user(uid.as_ref()).map(|user| self.open(parent, user)) + } + // TODO: make infallible - pub fn open(&self, parent: &Span, uid: impl AsRef) -> Option { - let uid = uid.as_ref(); - if let Some(user) = self.users.get_user(uid) { - let span = tracing::info_span!( - target: "bffh::api", - parent: parent, - "session", - uid = uid, - ); - tracing::trace!(parent: &span, uid, ?user, "opening session"); - Some(SessionHandle { - span, - users: self.users.clone(), - roles: self.roles.clone(), - user: UserRef::new(user.id), - }) - } else { - None + pub fn open(&self, parent: &Span, user: User) -> SessionHandle { + let uid = user.id.as_str(); + let span = tracing::info_span!( + target: "bffh::api", + parent: parent, + "session", + uid, + ); + tracing::trace!(parent: &span, uid, ?user, "opening session"); + SessionHandle { + span, + users: self.users.clone(), + roles: self.roles.clone(), + user: UserRef::new(user.id), } } } diff --git a/bffhd/users/db.rs b/bffhd/users/db.rs index cc13b20..761fbc5 100644 --- a/bffhd/users/db.rs +++ b/bffhd/users/db.rs @@ -34,11 +34,9 @@ fn hash_pw(pw: &[u8]) -> argon2::Result { } impl User { - pub fn check_password(&self, pwd: &[u8]) -> miette::Result { + pub fn check_password(&self, pwd: &[u8]) -> Result { if let Some(ref encoded) = self.userdata.passwd { argon2::verify_encoded(encoded, pwd) - .into_diagnostic() - .wrap_err("Stored password is an invalid string") } else { Ok(false) }