Handle SW_EXACT_LENGTH (0x6c??) in send_command()

This commit is contained in:
Heiko Schaefer 2021-09-17 13:36:20 +02:00
parent 60c67d3ebe
commit a39f25d8a3
2 changed files with 36 additions and 9 deletions

View file

@ -11,6 +11,7 @@ pub mod response;
use anyhow::Result; use anyhow::Result;
use std::convert::TryFrom; use std::convert::TryFrom;
use crate::apdu::command::Expect;
use crate::apdu::{command::Command, response::RawResponse}; use crate::apdu::{command::Command, response::RawResponse};
use crate::{CardClientBox, Error, StatusBytes}; use crate::{CardClientBox, Error, StatusBytes};
@ -28,10 +29,22 @@ pub(crate) fn send_command(
) -> Result<RawResponse, Error> { ) -> Result<RawResponse, Error> {
let mut resp = RawResponse::try_from(send_command_low_level( let mut resp = RawResponse::try_from(send_command_low_level(
card_client, card_client,
cmd, cmd.clone(),
expect_reply, if expect_reply {
Expect::Some
} else {
Expect::Empty
},
)?)?; )?)?;
if let StatusBytes::UnknownStatus(0x6c, size) = resp.status() {
resp = RawResponse::try_from(send_command_low_level(
card_client,
cmd,
Expect::Short(size),
)?)?;
}
while let StatusBytes::OkBytesAvailable(_) = resp.status() { while let StatusBytes::OkBytesAvailable(_) = resp.status() {
// More data is available for this command from the card // More data is available for this command from the card
log::debug!(" chained response, getting more data"); log::debug!(" chained response, getting more data");
@ -40,7 +53,7 @@ pub(crate) fn send_command(
let next = RawResponse::try_from(send_command_low_level( let next = RawResponse::try_from(send_command_low_level(
card_client, card_client,
commands::get_response(), commands::get_response(),
expect_reply, Expect::Some,
)?)?; )?)?;
match next.status() { match next.status() {
@ -71,7 +84,7 @@ pub(crate) fn send_command(
fn send_command_low_level( fn send_command_low_level(
card_client: &mut CardClientBox, card_client: &mut CardClientBox,
cmd: Command, cmd: Command,
expect_response: bool, expect_response: Expect,
) -> Result<Vec<u8>, Error> { ) -> Result<Vec<u8>, Error> {
let (ext_support, chaining_support, mut max_cmd_bytes, max_rsp_bytes) = let (ext_support, chaining_support, mut max_cmd_bytes, max_rsp_bytes) =
if let Some(caps) = card_client.get_caps() { if let Some(caps) = card_client.get_caps() {

View file

@ -6,6 +6,13 @@
use anyhow::Result; use anyhow::Result;
#[derive(Clone, Copy)]
pub enum Expect {
Empty,
Some,
Short(u8),
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub(crate) struct Command { pub(crate) struct Command {
// Class byte (CLA) // Class byte (CLA)
@ -63,7 +70,7 @@ impl Command {
pub(crate) fn serialize( pub(crate) fn serialize(
&self, &self,
ext_len: bool, ext_len: bool,
expect_response: bool, expect_response: Expect,
) -> Result<Vec<u8>> { ) -> Result<Vec<u8>> {
// FIXME? (from scd/apdu.c): // FIXME? (from scd/apdu.c):
// T=0 does not allow the use of Lc together with Le; // T=0 does not allow the use of Lc together with Le;
@ -101,18 +108,22 @@ impl Command {
/// Encode value for Le field /// Encode value for Le field
/// ("maximum number of bytes expected in the response data field"). /// ("maximum number of bytes expected in the response data field").
fn make_le(nc: u16, ext_len: bool, expect_response: bool) -> Vec<u8> { fn make_le(nc: u16, ext_len: bool, expect_response: Expect) -> Vec<u8> {
match (ext_len, expect_response) { match (ext_len, expect_response) {
(_, false) => { (_, Expect::Empty) => {
// No response data expected. // No response data expected.
// "If the Le field is absent, then Ne is zero" // "If the Le field is absent, then Ne is zero"
vec![] vec![]
} }
(false, true) => { (false, Expect::Some) => {
// A short Le field consists of one byte with any value // A short Le field consists of one byte with any value
vec![0] vec![0]
} }
(true, true) => { (false, Expect::Short(size)) => {
// A short Le field consists of one byte with any value
vec![size]
}
(true, Expect::Some) => {
if nc == 0 { if nc == 0 {
// "three bytes (one byte set to '00' followed by two // "three bytes (one byte set to '00' followed by two
// bytes with any value) if the Lc field is absent" // bytes with any value) if the Lc field is absent"
@ -123,6 +134,9 @@ impl Command {
vec![0, 0] vec![0, 0]
} }
} }
_ => {
unreachable!("This should not happen")
}
} }
} }
} }