backend: add CardBackend::limit_card_caps

This mechanism allows the pcsc backend to signal to openpgp-card that a reader doesn't support "extended length".
This commit is contained in:
Heiko Schaefer 2023-09-02 23:16:42 +02:00
parent e476103e6d
commit 31eee9e738
No known key found for this signature in database
GPG key ID: 4A849A1904CCBD7D
4 changed files with 44 additions and 16 deletions

View file

@ -12,6 +12,11 @@
/// A [CardBackend] is only used to get access to a [CardTransaction] object,
/// which supports transmitting commands to the card.
pub trait CardBackend {
/// If a CardBackend introduces a additional (possibly backend-specific)
/// limits for any fields in CardCaps, this fn can indicate that limit by
/// returning an amended [`CardCaps`].
fn limit_card_caps(&self, card_caps: CardCaps) -> CardCaps;
fn transaction(
&mut self,
reselect_application: Option<&[u8]>,

View file

@ -188,7 +188,7 @@ impl Card {
let ext_cap = ard.extended_capabilities()?;
// Get max command/response byte sizes from card
let (mut max_cmd_bytes, max_rsp_bytes) = if let Ok(Some(eli)) =
let (max_cmd_bytes, max_rsp_bytes) = if let Ok(Some(eli)) =
ard.extended_length_information()
{
// In card 3.x, max lengths come from ExtendedLengthInfo
@ -205,21 +205,6 @@ impl Card {
let pw1_max = pw_status.pw1_max_len();
let pw3_max = pw_status.pw3_max_len();
// If the CardTransaction implementation has an inherent limit for the cmd
// size, take that limit into account.
// (E.g. when using scdaemon as a CardTransaction backend, there is a
// limitation to 1000 bytes length for Assuan commands, which
// translates to maximum command length of a bit under 500 bytes)
if let Some(max_card_cmd_bytes) = tx.tx.max_cmd_len() {
max_cmd_bytes = u16::min(max_cmd_bytes, max_card_cmd_bytes as u16);
}
// FIXME: add a more general mechanism to ask the backend for
// amendments to the CardCaps (e.g. to change support for
// "extended length")
//
// Also see https://blog.apdu.fr/posts/2011/05/extended-apdu-status-per-reader/
let caps = CardCaps::new(
ext_support,
chaining_support,
@ -239,6 +224,12 @@ impl Card {
drop(tx);
// General mechanism to ask the backend for amendments to
// the CardCaps (e.g. to change support for "extended length")
//
// Also see https://blog.apdu.fr/posts/2011/05/extended-apdu-status-per-reader/
let caps = op.card.limit_card_caps(caps);
(caps, imm)
};

View file

@ -546,6 +546,25 @@ impl PcscBackend {
}
impl CardBackend for PcscBackend {
fn limit_card_caps(&self, card_caps: CardCaps) -> CardCaps {
let mut ext = card_caps.ext_support();
// Disable "extended length" support when the card reader is known not to support it
if self.reader_name.starts_with("ACS ACR122U") {
log::debug!("Disabling ext_support for reader {}", self.reader_name);
ext = false;
}
CardCaps::new(
ext,
card_caps.chaining_support(),
card_caps.max_cmd_bytes(),
card_caps.max_rsp_bytes(),
card_caps.pw1_max_len(),
card_caps.pw3_max_len(),
)
}
/// Get a CardTransaction for this PcscBackend (this starts a transaction)
fn transaction(
&mut self,

View file

@ -212,6 +212,19 @@ impl ScdBackend {
}
impl CardBackend for ScdBackend {
fn limit_card_caps(&self, card_caps: CardCaps) -> CardCaps {
let max_cmd_bytes = u16::min(APDU_CMD_BYTES_MAX as u16, card_caps.max_cmd_bytes());
CardCaps::new(
card_caps.ext_support(),
card_caps.chaining_support(),
max_cmd_bytes,
card_caps.max_rsp_bytes(),
card_caps.pw1_max_len(),
card_caps.pw3_max_len(),
)
}
fn transaction(
&mut self,
_reselect_application: Option<&[u8]>,