Implement discrete handling of v2 and v3 ExtendedCapabilities.

This commit is contained in:
Heiko Schaefer 2021-09-15 17:39:47 +02:00
parent f2e5fea0fc
commit 3cc9a09290
3 changed files with 69 additions and 26 deletions

View file

@ -70,10 +70,15 @@ impl CardApp {
}
}
let ext_cap = ard.get_extended_capabilities()?;
let (max_cmd_bytes, max_rsp_bytes) =
// FIXME: handle cmd/resp limits in ex-cap, for card <3.0 (?)
if let Ok(Some(eli)) = ard.get_extended_length_information() {
(eli.max_command_bytes(), eli.max_response_bytes())
} else if let (Some(cmd), Some(rsp))
= (ext_cap.max_cmd_len(), ext_cap.max_resp_len()) {
(cmd, rsp)
} else {
(255, 255)
};

View file

@ -254,9 +254,13 @@ pub struct ExtendedCapabilities {
sm_algo: u8,
max_len_challenge: u16,
max_len_cardholder_cert: u16,
max_len_special_do: u16,
pin_block_2_format_support: bool,
mse_command_support: bool,
max_cmd_len: Option<u16>, // v2
max_resp_len: Option<u16>, // v2
max_len_special_do: Option<u16>, // v3
pin_block_2_format_support: Option<bool>, // v3
mse_command_support: Option<bool>, // v3
}
/// 4.1.3.1 Extended length information

View file

@ -10,23 +10,35 @@ use crate::card_do::ExtendedCapabilities;
use crate::Error;
impl ExtendedCapabilities {
pub fn max_len_special_do(&self) -> u16 {
pub fn max_len_special_do(&self) -> Option<u16> {
self.max_len_special_do
}
pub fn algo_attrs_changeable(&self) -> bool {
self.algo_attrs_changeable
}
pub fn max_cmd_len(&self) -> Option<u16> {
self.max_cmd_len
}
pub fn max_resp_len(&self) -> Option<u16> {
self.max_resp_len
}
}
impl TryFrom<(&[u8], u16)> for ExtendedCapabilities {
type Error = Error;
fn try_from((input, version): (&[u8], u16)) -> Result<Self, Self::Error> {
// FIXME: handle different card versions.
// e.g. bytes 07/08 and 09/0A have different meanings before and
// after V3.0
// FIXME: check that this fn is not called excessively often
let version = ((version >> 8) as u8, (version & 0xff) as u8);
// FIXME: earlier versions have shorter extended capabilities
assert!(version.0 >= 2);
// v2.x and v3.x should have 10 byte sized extended caps
assert_eq!(
input.len(),
10,
@ -48,26 +60,44 @@ impl TryFrom<(&[u8], u16)> for ExtendedCapabilities {
let max_len_challenge = input[2] as u16 * 256 + input[3] as u16;
let max_len_cardholder_cert = input[4] as u16 * 256 + input[5] as u16;
let max_len_special_do = input[6] as u16 * 256 + input[7] as u16;
let pin_block_2_format_support = input[8];
let mse_command_support = input[9];
let mut max_cmd_len = None;
let mut max_resp_len = None;
if pin_block_2_format_support > 1 {
let mut max_len_special_do = None;
let mut pin_block_2_format_support = None;
let mut mse_command_support = None;
if version.0 == 2 {
// v2.0 until v2.2
max_cmd_len = Some(input[6] as u16 * 256 + input[7] as u16);
max_resp_len = Some(input[8] as u16 * 256 + input[9] as u16);
} else {
// from v3.0
max_len_special_do = Some(input[6] as u16 * 256 + input[7] as u16);
let i8 = input[8];
let i9 = input[9];
if i8 > 1 {
return Err(anyhow!(
"Illegal value '{}' for pin_block_2_format_support",
pin_block_2_format_support
i8
)
.into());
}
if mse_command_support > 1 {
pin_block_2_format_support = Some(i8 != 0);
if i9 > 1 {
return Err(anyhow!(
"Illegal value '{}' for mse_command_support",
mse_command_support
i9
)
.into());
}
mse_command_support = Some(i9 != 0);
}
Ok(Self {
secure_messaging,
@ -82,9 +112,13 @@ impl TryFrom<(&[u8], u16)> for ExtendedCapabilities {
sm_algo,
max_len_challenge,
max_len_cardholder_cert,
max_len_special_do,
pin_block_2_format_support: pin_block_2_format_support != 0,
mse_command_support: mse_command_support != 0,
max_cmd_len, // v2
max_resp_len, // v2
max_len_special_do, // v3
pin_block_2_format_support, // v3
mse_command_support, // v3
})
}
}