mirror of
https://gitlab.com/fabinfra/fabaccess/bffh.git
synced 2024-11-21 14:37:56 +01:00
fix fabfire mechanism integration and improve logging
This commit is contained in:
parent
41f8b83cd5
commit
831b18128d
@ -12,6 +12,7 @@ use std::convert::TryFrom;
|
||||
use std::sync::Arc;
|
||||
use desfire::desfire::desfire::MAX_BYTES_PER_TRANSACTION;
|
||||
use rsasl::property::AuthId;
|
||||
use tracing::{error, trace};
|
||||
use crate::authentication::fabfire::FabFireCardKey;
|
||||
|
||||
enum FabFireError {
|
||||
@ -152,7 +153,7 @@ impl Authentication for FabFire {
|
||||
fn step(&mut self, session: &mut SessionData, input: Option<&[u8]>, writer: &mut dyn Write) -> StepResult {
|
||||
match self.step {
|
||||
Step::New => {
|
||||
// println!("Step: New");
|
||||
tracing::trace!("Step: New");
|
||||
//receive card info (especially card UID) from reader
|
||||
return match input {
|
||||
None => { Err(SessionError::InputDataRequired) }
|
||||
@ -160,7 +161,7 @@ impl Authentication for FabFire {
|
||||
self.card_info = match serde_json::from_slice(cardinfo) {
|
||||
Ok(card_info) => Some(card_info),
|
||||
Err(e) => {
|
||||
// eprintln!("{:?}", e);
|
||||
tracing::error!("Deserializing card_info failed: {:?}", e);
|
||||
return Err(FabFireError::DeserializationError(e).into());
|
||||
}
|
||||
};
|
||||
@ -169,12 +170,12 @@ impl Authentication for FabFire {
|
||||
Ok(buf) => match Vec::<u8>::try_from(buf) {
|
||||
Ok(data) => data,
|
||||
Err(e) => {
|
||||
// eprintln!("Failed to convert APDUCommand to Vec<u8>: {:?}", e);
|
||||
tracing::error!("Failed to convert APDUCommand to Vec<u8>: {:?}", e);
|
||||
return Err(FabFireError::SerializationError.into());
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
// eprintln!("Failed to generate APDUCommand: {:?}", e);
|
||||
tracing::error!("Failed to generate APDUCommand: {:?}", e);
|
||||
return Err(FabFireError::SerializationError.into());
|
||||
}
|
||||
};
|
||||
@ -186,7 +187,7 @@ impl Authentication for FabFire {
|
||||
Ok(rsasl::session::Step::NeedsMore(Some(send_buf.len())))
|
||||
}
|
||||
Err(e) => {
|
||||
// eprintln!("Failed to serialize APDUCommand: {:?}", e);
|
||||
tracing::error!("Failed to serialize APDUCommand: {:?}", e);
|
||||
Err(FabFireError::SerializationError.into())
|
||||
}
|
||||
};
|
||||
@ -194,14 +195,14 @@ impl Authentication for FabFire {
|
||||
};
|
||||
}
|
||||
Step::SelectApp => {
|
||||
// println!("Step: SelectApp");
|
||||
tracing::trace!("Step: SelectApp");
|
||||
// check that we successfully selected the application
|
||||
let response: CardCommand = match input {
|
||||
None => { return Err(SessionError::InputDataRequired); }
|
||||
Some(buf) => match serde_json::from_slice(buf).map_err(|e| FabFireError::DeserializationError(e)) {
|
||||
Ok(response) => response,
|
||||
Err(e) => {
|
||||
// eprintln!("{:?}", e);
|
||||
tracing::error!("Deserializing data from card failed: {:?}", e);
|
||||
return Err(e.into());
|
||||
}
|
||||
}
|
||||
@ -210,7 +211,7 @@ impl Authentication for FabFire {
|
||||
let apdu_response = match response {
|
||||
CardCommand::readPICC { data } => { APDUResponse::new(&*data) }
|
||||
_ => {
|
||||
// eprintln!("Unexpected response: {:?}", response);
|
||||
tracing::error!("Unexpected response: {:?}", response);
|
||||
return Err(FabFireError::ParseError.into());
|
||||
}
|
||||
};
|
||||
@ -223,11 +224,13 @@ impl Authentication for FabFire {
|
||||
let buf = match self.desfire.read_data_chunk_cmd(MAGIC_FILE_ID, 0, MAGIC.len()) {
|
||||
Ok(buf) => match Vec::<u8>::try_from(buf) {
|
||||
Ok(data) => data,
|
||||
Err(_) => {
|
||||
Err(e) => {
|
||||
tracing::error!("Failed to convert APDUCommand to Vec<u8>: {:?}", e);
|
||||
return Err(FabFireError::SerializationError.into());
|
||||
}
|
||||
},
|
||||
Err(_) => {
|
||||
Err(e) => {
|
||||
tracing::error!("Failed to generate APDUCommand: {:?}", e);
|
||||
return Err(FabFireError::SerializationError.into());
|
||||
}
|
||||
};
|
||||
@ -238,20 +241,21 @@ impl Authentication for FabFire {
|
||||
writer.write_all(&send_buf).map_err(|e| SessionError::Io { source: e })?;
|
||||
Ok(rsasl::session::Step::NeedsMore(Some(send_buf.len())))
|
||||
}
|
||||
Err(_) => {
|
||||
Err(e) => {
|
||||
tracing::error!("Failed to serialize APDUCommand: {:?}", e);
|
||||
Err(FabFireError::SerializationError.into())
|
||||
}
|
||||
};
|
||||
}
|
||||
Step::VerifyMagic => {
|
||||
// println!("Step: VerifyMagic");
|
||||
tracing::trace!("Step: VerifyMagic");
|
||||
// verify the magic string to determine that we have a valid fabfire card
|
||||
let response: CardCommand = match input {
|
||||
None => { return Err(SessionError::InputDataRequired); }
|
||||
Some(buf) => match serde_json::from_slice(buf).map_err(|e| FabFireError::DeserializationError(e)) {
|
||||
Ok(response) => response,
|
||||
Err(e) => {
|
||||
// eprintln!("{:?}", e);
|
||||
tracing::error!("Deserializing data from card failed: {:?}", e);
|
||||
return Err(e.into());
|
||||
}
|
||||
}
|
||||
@ -260,7 +264,7 @@ impl Authentication for FabFire {
|
||||
let apdu_response = match response {
|
||||
CardCommand::readPICC { data } => { APDUResponse::new(&*data) }
|
||||
_ => {
|
||||
// eprintln!("Unexpected response: {:?}", response);
|
||||
tracing::error!("Unexpected response: {:?}", response);
|
||||
return Err(FabFireError::ParseError.into());
|
||||
}
|
||||
};
|
||||
@ -271,15 +275,18 @@ impl Authentication for FabFire {
|
||||
match apdu_response.body {
|
||||
Some(data) => {
|
||||
if std::str::from_utf8(data.as_slice()) != Ok(MAGIC) {
|
||||
tracing::error!("Invalid magic string");
|
||||
return Err(FabFireError::ParseError.into());
|
||||
}
|
||||
}
|
||||
None => {
|
||||
tracing::error!("No data returned from card");
|
||||
return Err(FabFireError::ParseError.into());
|
||||
}
|
||||
};
|
||||
}
|
||||
Err(_) => {
|
||||
Err(e) => {
|
||||
tracing::error!("Got invalid APDUResponse: {:?}", e);
|
||||
return Err(FabFireError::ParseError.into());
|
||||
}
|
||||
}
|
||||
@ -291,11 +298,13 @@ impl Authentication for FabFire {
|
||||
let buf = match self.desfire.read_data_chunk_cmd(URN_FILE_ID, 0, self.local_urn.as_bytes().len()) { // TODO: support urn longer than 47 Bytes
|
||||
Ok(buf) => match Vec::<u8>::try_from(buf) {
|
||||
Ok(data) => data,
|
||||
Err(_) => {
|
||||
Err(e) => {
|
||||
tracing::error!("Failed to convert APDUCommand to Vec<u8>: {:?}", e);
|
||||
return Err(FabFireError::SerializationError.into());
|
||||
}
|
||||
},
|
||||
Err(_) => {
|
||||
Err(e) => {
|
||||
tracing::error!("Failed to generate APDUCommand: {:?}", e);
|
||||
return Err(FabFireError::SerializationError.into());
|
||||
}
|
||||
};
|
||||
@ -306,20 +315,21 @@ impl Authentication for FabFire {
|
||||
writer.write_all(&send_buf).map_err(|e| SessionError::Io { source: e })?;
|
||||
Ok(rsasl::session::Step::NeedsMore(Some(send_buf.len())))
|
||||
}
|
||||
Err(_) => {
|
||||
Err(e) => {
|
||||
tracing::error!("Failed to serialize APDUCommand: {:?}", e);
|
||||
Err(FabFireError::SerializationError.into())
|
||||
}
|
||||
};
|
||||
}
|
||||
Step::GetURN => {
|
||||
// println!("Step: GetURN");
|
||||
tracing::trace!("Step: GetURN");
|
||||
// parse the urn and match it to our local urn
|
||||
let response: CardCommand = match input {
|
||||
None => { return Err(SessionError::InputDataRequired); }
|
||||
Some(buf) => match serde_json::from_slice(buf).map_err(|e| FabFireError::DeserializationError(e)) {
|
||||
Ok(response) => response,
|
||||
Err(e) => {
|
||||
// eprintln!("{:?}", e);
|
||||
tracing::error!("Deserializing data from card failed: {:?}", e);
|
||||
return Err(e.into());
|
||||
}
|
||||
}
|
||||
@ -328,7 +338,7 @@ impl Authentication for FabFire {
|
||||
let apdu_response = match response {
|
||||
CardCommand::readPICC { data } => { APDUResponse::new(&*data) }
|
||||
_ => {
|
||||
// eprintln!("Unexpected response: {:?}", response);
|
||||
tracing::error!("Unexpected response: {:?}", response);
|
||||
return Err(FabFireError::ParseError.into());
|
||||
}
|
||||
};
|
||||
@ -340,18 +350,18 @@ impl Authentication for FabFire {
|
||||
Some(data) => {
|
||||
let received_urn = String::from_utf8(data).unwrap();
|
||||
if received_urn != self.local_urn {
|
||||
// eprintln!("URN mismatch: {:?} != {:?}", received_urn, self.local_urn);
|
||||
tracing::error!("URN mismatch: {:?} != {:?}", received_urn, self.local_urn);
|
||||
return Err(FabFireError::ParseError.into());
|
||||
}
|
||||
}
|
||||
None => {
|
||||
// eprintln!("No data in response");
|
||||
tracing::error!("No data returned from card");
|
||||
return Err(FabFireError::ParseError.into());
|
||||
}
|
||||
};
|
||||
}
|
||||
Err(e) => {
|
||||
// eprintln!("Invalid response: {:?}", e);
|
||||
tracing::error!("Got invalid APDUResponse: {:?}", e);
|
||||
return Err(FabFireError::ParseError.into());
|
||||
}
|
||||
}
|
||||
@ -361,11 +371,13 @@ impl Authentication for FabFire {
|
||||
let buf = match self.desfire.read_data_chunk_cmd(TOKEN_FILE_ID, 0, MAX_BYTES_PER_TRANSACTION) { // TODO: support data longer than 47 Bytes
|
||||
Ok(buf) => match Vec::<u8>::try_from(buf) {
|
||||
Ok(data) => data,
|
||||
Err(_) => {
|
||||
Err(e) => {
|
||||
tracing::error!("Failed to convert APDUCommand to Vec<u8>: {:?}", e);
|
||||
return Err(FabFireError::SerializationError.into());
|
||||
}
|
||||
},
|
||||
Err(_) => {
|
||||
Err(e) => {
|
||||
tracing::error!("Failed to generate APDUCommand: {:?}", e);
|
||||
return Err(FabFireError::SerializationError.into());
|
||||
}
|
||||
};
|
||||
@ -376,7 +388,8 @@ impl Authentication for FabFire {
|
||||
writer.write_all(&send_buf).map_err(|e| SessionError::Io { source: e })?;
|
||||
Ok(rsasl::session::Step::NeedsMore(Some(send_buf.len())))
|
||||
}
|
||||
Err(_) => {
|
||||
Err(e) => {
|
||||
tracing::error!("Failed to serialize APDUCommand: {:?}", e);
|
||||
Err(FabFireError::SerializationError.into())
|
||||
}
|
||||
};
|
||||
@ -389,7 +402,7 @@ impl Authentication for FabFire {
|
||||
Some(buf) => match serde_json::from_slice(buf).map_err(|e| FabFireError::DeserializationError(e)) {
|
||||
Ok(response) => response,
|
||||
Err(e) => {
|
||||
// eprintln!("{:?}", e);
|
||||
tracing::error!("Deserializing data from card failed: {:?}", e);
|
||||
return Err(e.into());
|
||||
}
|
||||
}
|
||||
@ -398,7 +411,7 @@ impl Authentication for FabFire {
|
||||
let apdu_response = match response {
|
||||
CardCommand::readPICC { data } => { APDUResponse::new(&*data) }
|
||||
_ => {
|
||||
// eprintln!("Unexpected response: {:?}", response);
|
||||
tracing::error!("Unexpected response: {:?}", response);
|
||||
return Err(FabFireError::ParseError.into());
|
||||
}
|
||||
};
|
||||
@ -413,22 +426,24 @@ impl Authentication for FabFire {
|
||||
let key = match session.get_property_or_callback::<FabFireCardKey>() {
|
||||
Ok(Some(key)) => Box::from(key.as_slice()),
|
||||
Ok(None) => {
|
||||
tracing::error!("No keys on file for token");
|
||||
return Err(FabFireError::InvalidCredentials("No keys on file for token".to_string()).into());
|
||||
}
|
||||
Err(e) => {
|
||||
tracing::error!("Failed to get key: {:?}", e);
|
||||
return Err(FabFireError::Session(e).into());
|
||||
}
|
||||
};
|
||||
self.key_info = Some(KeyInfo{ key_id: 0x01, key });
|
||||
}
|
||||
None => {
|
||||
// eprintln!("No data in response");
|
||||
tracing::error!("No data in response");
|
||||
return Err(FabFireError::ParseError.into());
|
||||
}
|
||||
};
|
||||
}
|
||||
Err(e) => {
|
||||
// eprintln!("Invalid response: {:?}", e);
|
||||
tracing::error!("Failed to check response: {:?}", e);
|
||||
return Err(FabFireError::ParseError.into());
|
||||
}
|
||||
}
|
||||
@ -436,11 +451,13 @@ impl Authentication for FabFire {
|
||||
let buf = match self.desfire.authenticate_iso_aes_challenge_cmd(self.key_info.as_ref().unwrap().key_id) {
|
||||
Ok(buf) => match Vec::<u8>::try_from(buf) {
|
||||
Ok(data) => data,
|
||||
Err(_) => {
|
||||
Err(e) => {
|
||||
tracing::error!("Failed to convert to Vec<u8>: {:?}", e);
|
||||
return Err(FabFireError::SerializationError.into());
|
||||
}
|
||||
},
|
||||
Err(_) => {
|
||||
Err(e) => {
|
||||
tracing::error!("Failed to create authenticate command: {:?}", e);
|
||||
return Err(FabFireError::SerializationError.into());
|
||||
}
|
||||
};
|
||||
@ -451,19 +468,20 @@ impl Authentication for FabFire {
|
||||
writer.write_all(&send_buf).map_err(|e| SessionError::Io { source: e })?;
|
||||
Ok(rsasl::session::Step::NeedsMore(Some(send_buf.len())))
|
||||
}
|
||||
Err(_) => {
|
||||
Err(e) => {
|
||||
tracing::error!("Failed to serialize command: {:?}", e);
|
||||
Err(FabFireError::SerializationError.into())
|
||||
}
|
||||
};
|
||||
}
|
||||
Step::Authenticate1 => {
|
||||
// println!("Step: Authenticate1");
|
||||
tracing::trace!("Step: Authenticate1");
|
||||
let response: CardCommand = match input {
|
||||
None => { return Err(SessionError::InputDataRequired); }
|
||||
Some(buf) => match serde_json::from_slice(buf).map_err(|e| FabFireError::DeserializationError(e)) {
|
||||
Ok(response) => response,
|
||||
Err(e) => {
|
||||
// eprintln!("{:?}", e);
|
||||
tracing::error!("Failed to deserialize response: {:?}", e);
|
||||
return Err(e.into());
|
||||
}
|
||||
}
|
||||
@ -472,7 +490,7 @@ impl Authentication for FabFire {
|
||||
let apdu_response = match response {
|
||||
CardCommand::readPICC { data } => { APDUResponse::new(&*data) }
|
||||
_ => {
|
||||
// eprintln!("Unexpected response: {:?}", response);
|
||||
tracing::error!("Unexpected response: {:?}", response);
|
||||
return Err(FabFireError::ParseError.into());
|
||||
}
|
||||
};
|
||||
@ -487,7 +505,6 @@ impl Authentication for FabFire {
|
||||
//FIXME: This is ugly, we should find a better way to make the function testable
|
||||
//TODO: Check if we need a CSPRNG here
|
||||
let rnd_a: [u8; 16] = rand::random();
|
||||
// println!("RND_A: {:x?}", rnd_a);
|
||||
|
||||
let (cmd_challenge_response,
|
||||
rnd_b,
|
||||
@ -498,7 +515,8 @@ impl Authentication for FabFire {
|
||||
self.auth_info = Some(AuthInfo { rnd_a: Vec::<u8>::from(rnd_a), rnd_b, iv });
|
||||
let buf = match Vec::<u8>::try_from(cmd_challenge_response) {
|
||||
Ok(data) => data,
|
||||
Err(_) => {
|
||||
Err(e) => {
|
||||
tracing::error!("Failed to convert to Vec<u8>: {:?}", e);
|
||||
return Err(FabFireError::SerializationError.into());
|
||||
}
|
||||
};
|
||||
@ -509,17 +527,20 @@ impl Authentication for FabFire {
|
||||
writer.write_all(&send_buf).map_err(|e| SessionError::Io { source: e })?;
|
||||
Ok(rsasl::session::Step::NeedsMore(Some(send_buf.len())))
|
||||
}
|
||||
Err(_) => {
|
||||
Err(e) => {
|
||||
tracing::error!("Failed to serialize command: {:?}", e);
|
||||
Err(FabFireError::SerializationError.into())
|
||||
}
|
||||
};
|
||||
}
|
||||
None => {
|
||||
tracing::error!("Got invalid response: {:?}", apdu_response);
|
||||
return Err(FabFireError::ParseError.into());
|
||||
}
|
||||
};
|
||||
}
|
||||
Err(_) => {
|
||||
Err(e) => {
|
||||
tracing::error!("Failed to check response: {:?}", e);
|
||||
return Err(FabFireError::ParseError.into());
|
||||
}
|
||||
}
|
||||
@ -531,7 +552,7 @@ impl Authentication for FabFire {
|
||||
Some(buf) => match serde_json::from_slice(buf).map_err(|e| FabFireError::DeserializationError(e)) {
|
||||
Ok(response) => response,
|
||||
Err(e) => {
|
||||
// eprintln!("{:?}", e);
|
||||
tracing::error!("Failed to deserialize response: {:?}", e);
|
||||
return Err(e.into());
|
||||
}
|
||||
}
|
||||
@ -540,7 +561,7 @@ impl Authentication for FabFire {
|
||||
let apdu_response = match response {
|
||||
CardCommand::readPICC { data } => { APDUResponse::new(&*data) }
|
||||
_ => {
|
||||
// eprintln!("Unexpected response: {:?}", response);
|
||||
tracing::error!("Got invalid response: {:?}", response);
|
||||
return Err(FabFireError::ParseError.into());
|
||||
}
|
||||
};
|
||||
@ -570,7 +591,8 @@ impl Authentication for FabFire {
|
||||
writer.write_all(&send_buf).map_err(|e| SessionError::Io { source: e })?;
|
||||
return Ok(rsasl::session::Step::Done(Some(send_buf.len())))
|
||||
}
|
||||
Err(_) => {
|
||||
Err(e) => {
|
||||
tracing::error!("Failed to serialize command: {:?}", e);
|
||||
Err(FabFireError::SerializationError.into())
|
||||
}
|
||||
};
|
||||
@ -579,11 +601,13 @@ impl Authentication for FabFire {
|
||||
}
|
||||
}
|
||||
None => {
|
||||
tracing::error!("got empty response");
|
||||
return Err(FabFireError::ParseError.into());
|
||||
}
|
||||
};
|
||||
}
|
||||
Err(_) => {
|
||||
Err(e) => {
|
||||
tracing::error!("Got invalid response: {:?}", apdu_response);
|
||||
return Err(FabFireError::InvalidCredentials(format!("{}", apdu_response)).into());
|
||||
}
|
||||
}
|
||||
|
@ -5,9 +5,10 @@ use rsasl::mechname::Mechname;
|
||||
use rsasl::property::{AuthId, Password};
|
||||
use rsasl::session::{Session, SessionData};
|
||||
use rsasl::validate::{validations, Validation};
|
||||
use rsasl::{SASL};
|
||||
use rsasl::{Property, SASL};
|
||||
use std::sync::Arc;
|
||||
use rsasl::registry::Mechanism;
|
||||
use crate::authentication::fabfire::FabFireCardKey;
|
||||
|
||||
mod fabfire;
|
||||
|
||||
@ -20,6 +21,28 @@ impl Callback {
|
||||
}
|
||||
}
|
||||
impl rsasl::callback::Callback for Callback {
|
||||
fn provide_prop(
|
||||
&self,
|
||||
session: &mut rsasl::session::SessionData,
|
||||
property: Property,
|
||||
) -> Result<(), SessionError> {
|
||||
match property {
|
||||
fabfire::FABFIRECARDKEY => {
|
||||
let authcid = session.get_property_or_callback::<AuthId>()?;
|
||||
let user = self.users.get_user(authcid.unwrap().as_ref())
|
||||
.ok_or(SessionError::AuthenticationFailure)?;
|
||||
let kv = user.userdata.kv.get("cardkey")
|
||||
.ok_or(SessionError::AuthenticationFailure)?;
|
||||
let card_key = <[u8; 16]>::try_from(hex::decode(kv)
|
||||
.map_err(|_| SessionError::AuthenticationFailure)?)
|
||||
.map_err(|_| SessionError::AuthenticationFailure)?;
|
||||
session.set_property::<FabFireCardKey>(Arc::new(card_key));
|
||||
Ok(())
|
||||
}
|
||||
_ => Err(SessionError::NoProperty { property }),
|
||||
}
|
||||
}
|
||||
|
||||
fn validate(
|
||||
&self,
|
||||
session: &mut SessionData,
|
||||
|
@ -63,7 +63,7 @@ pub struct UserData {
|
||||
|
||||
/// Additional data storage
|
||||
#[serde(flatten, skip_serializing_if = "HashMap::is_empty")]
|
||||
kv: HashMap<String, String>,
|
||||
pub kv: HashMap<String, String>,
|
||||
}
|
||||
|
||||
impl UserData {
|
||||
|
@ -11,3 +11,6 @@ passwd = "secret"
|
||||
# It will get stored in the `kv` field in UserData.
|
||||
# This is not used for anything at the moment
|
||||
noot = "noot!"
|
||||
|
||||
# Store the card specific AES key in kv userdata
|
||||
cardkey = "7ab8704a61b5317e1fe4cae9e3e1fd8d"
|
||||
|
Loading…
Reference in New Issue
Block a user