From 3cc9a092903cc0443dd7860143e08c129c68ab1c Mon Sep 17 00:00:00 2001 From: Heiko Schaefer Date: Wed, 15 Sep 2021 17:39:47 +0200 Subject: [PATCH] Implement discrete handling of v2 and v3 ExtendedCapabilities. --- openpgp-card/src/card_app.rs | 5 ++ openpgp-card/src/card_do.rs | 10 ++- openpgp-card/src/card_do/extended_cap.rs | 80 +++++++++++++++++------- 3 files changed, 69 insertions(+), 26 deletions(-) diff --git a/openpgp-card/src/card_app.rs b/openpgp-card/src/card_app.rs index 7ab8168..32e1030 100644 --- a/openpgp-card/src/card_app.rs +++ b/openpgp-card/src/card_app.rs @@ -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) }; diff --git a/openpgp-card/src/card_do.rs b/openpgp-card/src/card_do.rs index 9543b7e..1a05473 100644 --- a/openpgp-card/src/card_do.rs +++ b/openpgp-card/src/card_do.rs @@ -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, // v2 + max_resp_len: Option, // v2 + + max_len_special_do: Option, // v3 + pin_block_2_format_support: Option, // v3 + mse_command_support: Option, // v3 } /// 4.1.3.1 Extended length information diff --git a/openpgp-card/src/card_do/extended_cap.rs b/openpgp-card/src/card_do/extended_cap.rs index 79ad0ac..e0a7485 100644 --- a/openpgp-card/src/card_do/extended_cap.rs +++ b/openpgp-card/src/card_do/extended_cap.rs @@ -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 { self.max_len_special_do } pub fn algo_attrs_changeable(&self) -> bool { self.algo_attrs_changeable } + + pub fn max_cmd_len(&self) -> Option { + self.max_cmd_len + } + + pub fn max_resp_len(&self) -> Option { + self.max_resp_len + } } impl TryFrom<(&[u8], u16)> for ExtendedCapabilities { type Error = Error; fn try_from((input, version): (&[u8], u16)) -> Result { - // 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,25 +60,43 @@ 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 { - return Err(anyhow!( - "Illegal value '{}' for pin_block_2_format_support", - pin_block_2_format_support - ) - .into()); - } + let mut max_len_special_do = None; + let mut pin_block_2_format_support = None; + let mut mse_command_support = None; - if mse_command_support > 1 { - return Err(anyhow!( - "Illegal value '{}' for mse_command_support", - mse_command_support - ) - .into()); + 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", + i8 + ) + .into()); + } + + pin_block_2_format_support = Some(i8 != 0); + + if i9 > 1 { + return Err(anyhow!( + "Illegal value '{}' for mse_command_support", + i9 + ) + .into()); + } + mse_command_support = Some(i9 != 0); } Ok(Self { @@ -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 }) } }