mirror of
https://gitlab.com/fabinfra/fabaccess/bffh.git
synced 2024-11-25 16:17:56 +01:00
Revert binarayfabfire
This commit is contained in:
parent
7a941c3338
commit
410ed8cb33
@ -1,44 +0,0 @@
|
|||||||
mod server;
|
|
||||||
pub use server::FabFire;
|
|
||||||
|
|
||||||
use rsasl::mechname::Mechname;
|
|
||||||
use rsasl::registry::{Mechanism, MECHANISMS};
|
|
||||||
use rsasl::session::Side;
|
|
||||||
|
|
||||||
const MECHNAME: &'static Mechname = &Mechname::const_new_unchecked(b"X-FABFIRE-BIN");
|
|
||||||
|
|
||||||
#[linkme::distributed_slice(MECHANISMS)]
|
|
||||||
pub static FABFIRE_BIN: Mechanism = Mechanism {
|
|
||||||
mechanism: MECHNAME,
|
|
||||||
priority: 300,
|
|
||||||
// In this situation there's one struct for both sides, however you can just as well use
|
|
||||||
// different types than then have different `impl Authentication` instead of checking a value
|
|
||||||
// in self.
|
|
||||||
client: None,
|
|
||||||
server: Some(FabFire::new_server),
|
|
||||||
first: Side::Client,
|
|
||||||
};
|
|
||||||
|
|
||||||
use rsasl::property::{Property, PropertyDefinition, PropertyQ};
|
|
||||||
use std::marker::PhantomData;
|
|
||||||
// All Property types must implement Debug.
|
|
||||||
#[derive(Debug)]
|
|
||||||
// The `PhantomData` in the constructor is only used so external crates can't construct this type.
|
|
||||||
pub struct FabFireCardKey(PhantomData<()>);
|
|
||||||
impl PropertyQ for FabFireCardKey {
|
|
||||||
// This is the type stored for this property. This could also be the struct itself if you
|
|
||||||
// so choose
|
|
||||||
type Item = [u8; 16];
|
|
||||||
// You need to return the constant you define below here for things to work properly
|
|
||||||
fn property() -> Property {
|
|
||||||
FABFIRECARDKEY
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// This const is used by your mechanism to query and by your users to set your property. It
|
|
||||||
// thus needs to be exported from your crate
|
|
||||||
pub const FABFIRECARDKEY: Property = Property::new(&PropertyDefinition::new(
|
|
||||||
// Short name, used in `Debug` output
|
|
||||||
"FabFireCardKey",
|
|
||||||
// A longer user-facing name used in `Display` output
|
|
||||||
"A AES128 key for a FabFire card",
|
|
||||||
));
|
|
@ -1,511 +0,0 @@
|
|||||||
use desfire::desfire::desfire::MAX_BYTES_PER_TRANSACTION;
|
|
||||||
use desfire::desfire::Desfire;
|
|
||||||
use desfire::error::Error as DesfireError;
|
|
||||||
use desfire::iso7816_4::apduresponse::APDUResponse;
|
|
||||||
use rsasl::error::{MechanismError, MechanismErrorKind, SASLError, SessionError};
|
|
||||||
use rsasl::mechanism::Authentication;
|
|
||||||
use rsasl::property::AuthId;
|
|
||||||
use rsasl::session::{SessionData, StepResult};
|
|
||||||
use rsasl::SASL;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use std::convert::TryFrom;
|
|
||||||
use std::fmt::{Debug, Display, Formatter};
|
|
||||||
use std::io::Write;
|
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use crate::authentication::fabfire::FabFireCardKey;
|
|
||||||
|
|
||||||
enum FabFireError {
|
|
||||||
ParseError,
|
|
||||||
SerializationError,
|
|
||||||
DeserializationError(serde_json::Error),
|
|
||||||
CardError(DesfireError),
|
|
||||||
InvalidMagic(String),
|
|
||||||
InvalidToken(String),
|
|
||||||
InvalidURN(String),
|
|
||||||
InvalidCredentials(String),
|
|
||||||
Session(SessionError),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Debug for FabFireError {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
FabFireError::ParseError => write!(f, "ParseError"),
|
|
||||||
FabFireError::SerializationError => write!(f, "SerializationError"),
|
|
||||||
FabFireError::DeserializationError(e) => write!(f, "DeserializationError: {}", e),
|
|
||||||
FabFireError::CardError(err) => write!(f, "CardError: {}", err),
|
|
||||||
FabFireError::InvalidMagic(magic) => write!(f, "InvalidMagic: {}", magic),
|
|
||||||
FabFireError::InvalidToken(token) => write!(f, "InvalidToken: {}", token),
|
|
||||||
FabFireError::InvalidURN(urn) => write!(f, "InvalidURN: {}", urn),
|
|
||||||
FabFireError::InvalidCredentials(credentials) => {
|
|
||||||
write!(f, "InvalidCredentials: {}", credentials)
|
|
||||||
}
|
|
||||||
FabFireError::Session(err) => write!(f, "Session: {}", err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for FabFireError {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
FabFireError::ParseError => write!(f, "ParseError"),
|
|
||||||
FabFireError::SerializationError => write!(f, "SerializationError"),
|
|
||||||
FabFireError::DeserializationError(e) => write!(f, "DeserializationError: {}", e),
|
|
||||||
FabFireError::CardError(err) => write!(f, "CardError: {}", err),
|
|
||||||
FabFireError::InvalidMagic(magic) => write!(f, "InvalidMagic: {}", magic),
|
|
||||||
FabFireError::InvalidToken(token) => write!(f, "InvalidToken: {}", token),
|
|
||||||
FabFireError::InvalidURN(urn) => write!(f, "InvalidURN: {}", urn),
|
|
||||||
FabFireError::InvalidCredentials(credentials) => {
|
|
||||||
write!(f, "InvalidCredentials: {}", credentials)
|
|
||||||
}
|
|
||||||
FabFireError::Session(err) => write!(f, "Session: {}", err),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MechanismError for FabFireError {
|
|
||||||
fn kind(&self) -> MechanismErrorKind {
|
|
||||||
match self {
|
|
||||||
FabFireError::ParseError => MechanismErrorKind::Parse,
|
|
||||||
FabFireError::SerializationError => MechanismErrorKind::Protocol,
|
|
||||||
FabFireError::DeserializationError(_) => MechanismErrorKind::Parse,
|
|
||||||
FabFireError::CardError(_) => MechanismErrorKind::Protocol,
|
|
||||||
FabFireError::InvalidMagic(_) => MechanismErrorKind::Protocol,
|
|
||||||
FabFireError::InvalidToken(_) => MechanismErrorKind::Protocol,
|
|
||||||
FabFireError::InvalidURN(_) => MechanismErrorKind::Protocol,
|
|
||||||
FabFireError::InvalidCredentials(_) => MechanismErrorKind::Protocol,
|
|
||||||
FabFireError::Session(_) => MechanismErrorKind::Protocol,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Deserialize, Serialize)]
|
|
||||||
#[serde(rename_all = "camelCase")]
|
|
||||||
struct CardInfo {
|
|
||||||
#[serde(rename = "UID", with = "hex")]
|
|
||||||
uid: [u8; 7],
|
|
||||||
key_old: Option<Box<[u8]>>,
|
|
||||||
key_new: Option<Box<[u8]>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct KeyInfo {
|
|
||||||
key_id: u8,
|
|
||||||
key: Box<[u8]>,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct AuthInfo {
|
|
||||||
rnd_a: Vec<u8>,
|
|
||||||
rnd_b: Vec<u8>,
|
|
||||||
iv: Vec<u8>,
|
|
||||||
}
|
|
||||||
|
|
||||||
enum Step {
|
|
||||||
New,
|
|
||||||
SelectApp,
|
|
||||||
VerifyMagic,
|
|
||||||
GetURN,
|
|
||||||
GetToken,
|
|
||||||
Authenticate1,
|
|
||||||
Authenticate2,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct FabFire {
|
|
||||||
step: Step,
|
|
||||||
card_info: Option<CardInfo>,
|
|
||||||
key_info: Option<KeyInfo>,
|
|
||||||
auth_info: Option<AuthInfo>,
|
|
||||||
app_id: u32,
|
|
||||||
local_urn: String,
|
|
||||||
desfire: Desfire,
|
|
||||||
}
|
|
||||||
|
|
||||||
const MAGIC: &'static str = "FABACCESS\0DESFIRE\01.0\0";
|
|
||||||
|
|
||||||
impl FabFire {
|
|
||||||
pub fn new_server(_sasl: &SASL) -> Result<Box<dyn Authentication>, SASLError> {
|
|
||||||
Ok(Box::new(Self {
|
|
||||||
step: Step::New,
|
|
||||||
card_info: None,
|
|
||||||
key_info: None,
|
|
||||||
auth_info: None,
|
|
||||||
app_id: 0x464142,
|
|
||||||
local_urn: "urn:fabaccess:lab:innovisionlab".to_string(),
|
|
||||||
desfire: Desfire {
|
|
||||||
card: None,
|
|
||||||
session_key: None,
|
|
||||||
cbc_iv: None,
|
|
||||||
},
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Authentication for FabFire {
|
|
||||||
fn step(
|
|
||||||
&mut self,
|
|
||||||
session: &mut SessionData,
|
|
||||||
input: Option<&[u8]>,
|
|
||||||
writer: &mut dyn Write,
|
|
||||||
) -> StepResult {
|
|
||||||
match self.step {
|
|
||||||
Step::New => {
|
|
||||||
tracing::trace!("Step: New");
|
|
||||||
//receive card info (especially card UID) from reader
|
|
||||||
return match input {
|
|
||||||
None => Err(SessionError::InputDataRequired),
|
|
||||||
Some(_) => {
|
|
||||||
//select application
|
|
||||||
return match self.desfire.select_application_cmd(self.app_id) {
|
|
||||||
Ok(buf) => match Vec::<u8>::try_from(buf) {
|
|
||||||
Ok(data) => {
|
|
||||||
self.step = Step::SelectApp;
|
|
||||||
writer
|
|
||||||
.write_all(&data)
|
|
||||||
.map_err(|e| SessionError::Io { source: e })?;
|
|
||||||
Ok(rsasl::session::Step::NeedsMore(Some(data.len())))
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
tracing::error!(
|
|
||||||
"Failed to convert APDUCommand to Vec<u8>: {:?}",
|
|
||||||
e
|
|
||||||
);
|
|
||||||
return Err(FabFireError::SerializationError.into());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
tracing::error!("Failed to generate APDUCommand: {:?}", e);
|
|
||||||
return Err(FabFireError::SerializationError.into());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Step::SelectApp => {
|
|
||||||
tracing::trace!("Step: SelectApp");
|
|
||||||
// check that we successfully selected the application
|
|
||||||
|
|
||||||
let apdu_response = match input {
|
|
||||||
Some(data) => APDUResponse::new(data),
|
|
||||||
None => return Err(SessionError::InputDataRequired),
|
|
||||||
};
|
|
||||||
|
|
||||||
apdu_response
|
|
||||||
.check()
|
|
||||||
.map_err(|e| FabFireError::CardError(e))?;
|
|
||||||
|
|
||||||
// request the contents of the file containing the magic string
|
|
||||||
const MAGIC_FILE_ID: u8 = 0x01;
|
|
||||||
|
|
||||||
return match self
|
|
||||||
.desfire
|
|
||||||
.read_data_chunk_cmd(MAGIC_FILE_ID, 0, MAGIC.len())
|
|
||||||
{
|
|
||||||
Ok(buf) => match Vec::<u8>::try_from(buf) {
|
|
||||||
Ok(data) => {
|
|
||||||
self.step = Step::VerifyMagic;
|
|
||||||
writer
|
|
||||||
.write_all(&data)
|
|
||||||
.map_err(|e| SessionError::Io { source: e })?;
|
|
||||||
Ok(rsasl::session::Step::NeedsMore(Some(data.len())))
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
tracing::error!("Failed to convert APDUCommand to Vec<u8>: {:?}", e);
|
|
||||||
return Err(FabFireError::SerializationError.into());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
tracing::error!("Failed to generate APDUCommand: {:?}", e);
|
|
||||||
return Err(FabFireError::SerializationError.into());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Step::VerifyMagic => {
|
|
||||||
tracing::trace!("Step: VerifyMagic");
|
|
||||||
// verify the magic string to determine that we have a valid fabfire card
|
|
||||||
let apdu_response = match input {
|
|
||||||
Some(data) => APDUResponse::new(data),
|
|
||||||
None => return Err(SessionError::InputDataRequired),
|
|
||||||
};
|
|
||||||
|
|
||||||
match apdu_response.check() {
|
|
||||||
Ok(_) => {
|
|
||||||
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(e) => {
|
|
||||||
tracing::error!("Got invalid APDUResponse: {:?}", e);
|
|
||||||
return Err(FabFireError::ParseError.into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// request the contents of the file containing the URN
|
|
||||||
const URN_FILE_ID: u8 = 0x02;
|
|
||||||
|
|
||||||
return 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) => {
|
|
||||||
self.step = Step::GetURN;
|
|
||||||
writer
|
|
||||||
.write_all(&data)
|
|
||||||
.map_err(|e| SessionError::Io { source: e })?;
|
|
||||||
Ok(rsasl::session::Step::NeedsMore(Some(data.len())))
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
tracing::error!("Failed to convert APDUCommand to Vec<u8>: {:?}", e);
|
|
||||||
return Err(FabFireError::SerializationError.into());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
tracing::error!("Failed to generate APDUCommand: {:?}", e);
|
|
||||||
return Err(FabFireError::SerializationError.into());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Step::GetURN => {
|
|
||||||
tracing::trace!("Step: GetURN");
|
|
||||||
// parse the urn and match it to our local urn
|
|
||||||
let apdu_response = match input {
|
|
||||||
Some(data) => APDUResponse::new(data),
|
|
||||||
None => return Err(SessionError::InputDataRequired),
|
|
||||||
};
|
|
||||||
|
|
||||||
match apdu_response.check() {
|
|
||||||
Ok(_) => {
|
|
||||||
match apdu_response.body {
|
|
||||||
Some(data) => {
|
|
||||||
let received_urn = String::from_utf8(data).unwrap();
|
|
||||||
if received_urn != self.local_urn {
|
|
||||||
tracing::error!(
|
|
||||||
"URN mismatch: {:?} != {:?}",
|
|
||||||
received_urn,
|
|
||||||
self.local_urn
|
|
||||||
);
|
|
||||||
return Err(FabFireError::ParseError.into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
tracing::error!("No data returned from card");
|
|
||||||
return Err(FabFireError::ParseError.into());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
tracing::error!("Got invalid APDUResponse: {:?}", e);
|
|
||||||
return Err(FabFireError::ParseError.into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// request the contents of the file containing the URN
|
|
||||||
const TOKEN_FILE_ID: u8 = 0x03;
|
|
||||||
|
|
||||||
return 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) => {
|
|
||||||
self.step = Step::GetToken;
|
|
||||||
writer
|
|
||||||
.write_all(&data)
|
|
||||||
.map_err(|e| SessionError::Io { source: e })?;
|
|
||||||
Ok(rsasl::session::Step::NeedsMore(Some(data.len())))
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
tracing::error!("Failed to convert APDUCommand to Vec<u8>: {:?}", e);
|
|
||||||
return Err(FabFireError::SerializationError.into());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
tracing::error!("Failed to generate APDUCommand: {:?}", e);
|
|
||||||
return Err(FabFireError::SerializationError.into());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Step::GetToken => {
|
|
||||||
// println!("Step: GetToken");
|
|
||||||
// parse the token and select the appropriate user
|
|
||||||
let apdu_response = match input {
|
|
||||||
Some(data) => APDUResponse::new(data),
|
|
||||||
None => return Err(SessionError::InputDataRequired),
|
|
||||||
};
|
|
||||||
|
|
||||||
match apdu_response.check() {
|
|
||||||
Ok(_) => {
|
|
||||||
match apdu_response.body {
|
|
||||||
Some(data) => {
|
|
||||||
let token = String::from_utf8(data).unwrap();
|
|
||||||
session.set_property::<AuthId>(Arc::new(
|
|
||||||
token.trim_matches(char::from(0)).to_string(),
|
|
||||||
));
|
|
||||||
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 => {
|
|
||||||
tracing::error!("No data in response");
|
|
||||||
return Err(FabFireError::ParseError.into());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
tracing::error!("Failed to check response: {:?}", e);
|
|
||||||
return Err(FabFireError::ParseError.into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return 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) => {
|
|
||||||
self.step = Step::Authenticate1;
|
|
||||||
writer
|
|
||||||
.write_all(&data)
|
|
||||||
.map_err(|e| SessionError::Io { source: e })?;
|
|
||||||
Ok(rsasl::session::Step::NeedsMore(Some(data.len())))
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
tracing::error!("Failed to convert to Vec<u8>: {:?}", e);
|
|
||||||
return Err(FabFireError::SerializationError.into());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
tracing::error!("Failed to create authenticate command: {:?}", e);
|
|
||||||
return Err(FabFireError::SerializationError.into());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Step::Authenticate1 => {
|
|
||||||
tracing::trace!("Step: Authenticate1");
|
|
||||||
let apdu_response = match input {
|
|
||||||
Some(data) => APDUResponse::new(data),
|
|
||||||
None => return Err(SessionError::InputDataRequired),
|
|
||||||
};
|
|
||||||
|
|
||||||
return match apdu_response.check() {
|
|
||||||
Ok(_) => {
|
|
||||||
match apdu_response.body {
|
|
||||||
Some(data) => {
|
|
||||||
let rnd_b_enc = data.as_slice();
|
|
||||||
|
|
||||||
//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();
|
|
||||||
|
|
||||||
let (cmd_challenge_response, rnd_b, iv) = self
|
|
||||||
.desfire
|
|
||||||
.authenticate_iso_aes_response_cmd(
|
|
||||||
rnd_b_enc,
|
|
||||||
&*(self.key_info.as_ref().unwrap().key),
|
|
||||||
&rnd_a,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
self.auth_info = Some(AuthInfo {
|
|
||||||
rnd_a: Vec::<u8>::from(rnd_a),
|
|
||||||
rnd_b,
|
|
||||||
iv,
|
|
||||||
});
|
|
||||||
match Vec::<u8>::try_from(cmd_challenge_response) {
|
|
||||||
Ok(data) => {
|
|
||||||
self.step = Step::Authenticate2;
|
|
||||||
writer
|
|
||||||
.write_all(&data)
|
|
||||||
.map_err(|e| SessionError::Io { source: e })?;
|
|
||||||
Ok(rsasl::session::Step::NeedsMore(Some(data.len())))
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
tracing::error!("Failed to convert to Vec<u8>: {:?}", e);
|
|
||||||
return Err(FabFireError::SerializationError.into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
tracing::error!("Got invalid response: {:?}", apdu_response);
|
|
||||||
Err(FabFireError::ParseError.into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Err(e) => {
|
|
||||||
tracing::error!("Failed to check response: {:?}", e);
|
|
||||||
Err(FabFireError::ParseError.into())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Step::Authenticate2 => {
|
|
||||||
// println!("Step: Authenticate2");
|
|
||||||
let apdu_response = match input {
|
|
||||||
Some(data) => APDUResponse::new(data),
|
|
||||||
None => return Err(SessionError::InputDataRequired),
|
|
||||||
};
|
|
||||||
|
|
||||||
match apdu_response.check() {
|
|
||||||
Ok(_) => {
|
|
||||||
match apdu_response.body {
|
|
||||||
Some(data) => match self.auth_info.as_ref() {
|
|
||||||
None => {
|
|
||||||
return Err(FabFireError::ParseError.into());
|
|
||||||
}
|
|
||||||
Some(auth_info) => {
|
|
||||||
if self
|
|
||||||
.desfire
|
|
||||||
.authenticate_iso_aes_verify(
|
|
||||||
data.as_slice(),
|
|
||||||
auth_info.rnd_a.as_slice(),
|
|
||||||
auth_info.rnd_b.as_slice(),
|
|
||||||
&*(self.key_info.as_ref().unwrap().key),
|
|
||||||
auth_info.iv.as_slice(),
|
|
||||||
)
|
|
||||||
.is_ok()
|
|
||||||
{
|
|
||||||
return Ok(rsasl::session::Step::Done(None));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
None => {
|
|
||||||
tracing::error!("got empty response");
|
|
||||||
return Err(FabFireError::ParseError.into());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Err(_e) => {
|
|
||||||
tracing::error!("Got invalid response: {:?}", apdu_response);
|
|
||||||
return Err(
|
|
||||||
FabFireError::InvalidCredentials(format!("{}", apdu_response)).into(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Ok(rsasl::session::Step::Done(None));
|
|
||||||
}
|
|
||||||
}
|
|
@ -11,7 +11,6 @@ use crate::authentication::fabfire::FabFireCardKey;
|
|||||||
use crate::users::db::User;
|
use crate::users::db::User;
|
||||||
|
|
||||||
mod fabfire;
|
mod fabfire;
|
||||||
mod fabfire_bin;
|
|
||||||
|
|
||||||
struct Callback {
|
struct Callback {
|
||||||
users: Users,
|
users: Users,
|
||||||
|
Loading…
Reference in New Issue
Block a user