A CardClient instance can now contain a CardCaps (which specifies how commands should be sent to the card).
Add max_rsp_bytes field to CardCaps.
This commit is contained in:
parent
9d93570d9f
commit
dbf2e9e3fb
4 changed files with 103 additions and 167 deletions
|
@ -16,7 +16,7 @@ use crate::card_app::CardApp;
|
||||||
use crate::errors::{OcErrorStatus, OpenpgpCardError, SmartcardError};
|
use crate::errors::{OcErrorStatus, OpenpgpCardError, SmartcardError};
|
||||||
use crate::{CardBase, CardCaps, CardClient, CardClientBox};
|
use crate::{CardBase, CardCaps, CardClient, CardClientBox};
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||||
pub(crate) enum Le {
|
pub(crate) enum Le {
|
||||||
None,
|
None,
|
||||||
Short,
|
Short,
|
||||||
|
@ -31,37 +31,34 @@ pub(crate) fn send_command(
|
||||||
card_client: &mut CardClientBox,
|
card_client: &mut CardClientBox,
|
||||||
cmd: Command,
|
cmd: Command,
|
||||||
expect_reply: bool,
|
expect_reply: bool,
|
||||||
card_caps: Option<&CardCaps>,
|
|
||||||
) -> Result<Response, OpenpgpCardError> {
|
) -> Result<Response, OpenpgpCardError> {
|
||||||
let mut resp = Response::try_from(send_command_low_level(
|
let mut resp = Response::try_from(send_command_low_level(
|
||||||
card_client,
|
card_client,
|
||||||
cmd,
|
cmd,
|
||||||
expect_reply,
|
expect_reply,
|
||||||
card_caps,
|
|
||||||
)?)?;
|
)?)?;
|
||||||
|
|
||||||
while resp.status()[0] == 0x61 {
|
while resp.status()[0] == 0x61 {
|
||||||
// More data is available for this command from the card
|
// More data is available for this command from the card
|
||||||
|
|
||||||
log::trace!(" response was truncated, getting more data");
|
log::debug!(" response was truncated, getting more data");
|
||||||
|
|
||||||
// Get additional data
|
// Get additional data
|
||||||
let next = Response::try_from(send_command_low_level(
|
let next = Response::try_from(send_command_low_level(
|
||||||
card_client,
|
card_client,
|
||||||
commands::get_response(),
|
commands::get_response(),
|
||||||
expect_reply,
|
expect_reply,
|
||||||
card_caps,
|
|
||||||
)?)?;
|
)?)?;
|
||||||
|
|
||||||
// FIXME: first check for 0x61xx or 0x9000?
|
// FIXME: first check for 0x61xx or 0x9000?
|
||||||
log::trace!(" appending {} bytes to response", next.raw_data().len());
|
log::debug!(" appending {} bytes to response", next.raw_data().len());
|
||||||
|
|
||||||
// Append new data to resp.data and overwrite status.
|
// Append new data to resp.data and overwrite status.
|
||||||
resp.raw_mut_data().extend_from_slice(next.raw_data());
|
resp.raw_mut_data().extend_from_slice(next.raw_data());
|
||||||
resp.set_status(next.status());
|
resp.set_status(next.status());
|
||||||
}
|
}
|
||||||
|
|
||||||
log::trace!(" final response len: {}", resp.raw_data().len());
|
log::debug!(" final response len: {}", resp.raw_data().len());
|
||||||
|
|
||||||
Ok(resp)
|
Ok(resp)
|
||||||
}
|
}
|
||||||
|
@ -75,29 +72,39 @@ fn send_command_low_level(
|
||||||
card_client: &mut CardClientBox,
|
card_client: &mut CardClientBox,
|
||||||
cmd: Command,
|
cmd: Command,
|
||||||
expect_reply: bool,
|
expect_reply: bool,
|
||||||
card_caps: Option<&CardCaps>,
|
|
||||||
) -> Result<Vec<u8>, OpenpgpCardError> {
|
) -> Result<Vec<u8>, OpenpgpCardError> {
|
||||||
let (ext_support, chaining_support, max_cmd_bytes) =
|
let (ext_support, chaining_support, mut max_cmd_bytes, max_rsp_bytes) =
|
||||||
if let Some(caps) = card_caps {
|
if let Some(caps) = card_client.get_caps() {
|
||||||
log::trace!("found card caps data!");
|
log::debug!("found card caps data!");
|
||||||
|
|
||||||
(
|
(
|
||||||
caps.ext_support,
|
caps.ext_support,
|
||||||
caps.chaining_support,
|
caps.chaining_support,
|
||||||
caps.max_cmd_bytes as usize,
|
caps.max_cmd_bytes as usize,
|
||||||
|
caps.max_rsp_bytes as usize,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
log::trace!("found NO card caps data!");
|
log::debug!("found NO card caps data!");
|
||||||
|
|
||||||
// default settings
|
// default settings
|
||||||
(false, false, 255)
|
(false, false, 255, 255)
|
||||||
};
|
};
|
||||||
|
|
||||||
log::trace!(
|
// If the CardClient implementation has an inherent limit for the cmd
|
||||||
"ext le/lc {}, chaining {}, command chunk size {}",
|
// size, take that limit into account.
|
||||||
|
// (E.g. when using scdaemon as a CardClient 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_cardclient_cmd_bytes) = card_client.max_cmd_len() {
|
||||||
|
max_cmd_bytes = usize::min(max_cmd_bytes, max_cardclient_cmd_bytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
log::debug!(
|
||||||
|
"ext le/lc {}, chaining {}, max cmd {}, max rsp {}",
|
||||||
ext_support,
|
ext_support,
|
||||||
chaining_support,
|
chaining_support,
|
||||||
max_cmd_bytes
|
max_cmd_bytes,
|
||||||
|
max_rsp_bytes
|
||||||
);
|
);
|
||||||
|
|
||||||
// Set Le to 'long', if we're using an extended chunk size.
|
// Set Le to 'long', if we're using an extended chunk size.
|
||||||
|
@ -111,18 +118,20 @@ fn send_command_low_level(
|
||||||
_ => Le::Short,
|
_ => Le::Short,
|
||||||
};
|
};
|
||||||
|
|
||||||
log::trace!(" -> full APDU command: {:x?}", cmd);
|
log::debug!(" -> full APDU command: {:x?}", cmd);
|
||||||
|
|
||||||
let buf_size = if !ext_support {
|
let buf_size = if !ext_support || ext == Le::Short {
|
||||||
pcsc::MAX_BUFFER_SIZE
|
pcsc::MAX_BUFFER_SIZE
|
||||||
} else {
|
} else {
|
||||||
pcsc::MAX_BUFFER_SIZE_EXTENDED
|
max_rsp_bytes
|
||||||
};
|
};
|
||||||
|
|
||||||
|
log::trace!("buf_size {}", buf_size);
|
||||||
|
|
||||||
if chaining_support && !cmd.data.is_empty() {
|
if chaining_support && !cmd.data.is_empty() {
|
||||||
// Send command in chained mode
|
// Send command in chained mode
|
||||||
|
|
||||||
log::trace!("chained command mode");
|
log::debug!("chained command mode");
|
||||||
|
|
||||||
// Break up payload into chunks that fit into one command, each
|
// Break up payload into chunks that fit into one command, each
|
||||||
let chunks: Vec<_> = cmd.data.chunks(max_cmd_bytes).collect();
|
let chunks: Vec<_> = cmd.data.chunks(max_cmd_bytes).collect();
|
||||||
|
@ -138,11 +147,12 @@ fn send_command_low_level(
|
||||||
let serialized = partial
|
let serialized = partial
|
||||||
.serialize(ext)
|
.serialize(ext)
|
||||||
.map_err(OpenpgpCardError::InternalError)?;
|
.map_err(OpenpgpCardError::InternalError)?;
|
||||||
log::trace!(" -> chunked APDU command: {:x?}", &serialized);
|
|
||||||
|
log::debug!(" -> chunked APDU command: {:x?}", &serialized);
|
||||||
|
|
||||||
let resp = card_client.transmit(&serialized, buf_size)?;
|
let resp = card_client.transmit(&serialized, buf_size)?;
|
||||||
|
|
||||||
log::trace!(" <- APDU chunk response: {:x?}", &resp);
|
log::debug!(" <- APDU chunk response: {:x?}", &resp);
|
||||||
|
|
||||||
if resp.len() < 2 {
|
if resp.len() < 2 {
|
||||||
return Err(OcErrorStatus::ResponseLength(resp.len()).into());
|
return Err(OcErrorStatus::ResponseLength(resp.len()).into());
|
||||||
|
@ -175,7 +185,7 @@ fn send_command_low_level(
|
||||||
|
|
||||||
let resp = card_client.transmit(&serialized, buf_size)?;
|
let resp = card_client.transmit(&serialized, buf_size)?;
|
||||||
|
|
||||||
log::trace!(" <- APDU response: {:x?}", resp);
|
log::debug!(" <- APDU response: {:x?}", resp);
|
||||||
|
|
||||||
Ok(resp)
|
Ok(resp)
|
||||||
}
|
}
|
||||||
|
@ -183,11 +193,15 @@ fn send_command_low_level(
|
||||||
|
|
||||||
pub struct PcscClient {
|
pub struct PcscClient {
|
||||||
card: Card,
|
card: Card,
|
||||||
|
card_caps: Option<CardCaps>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PcscClient {
|
impl PcscClient {
|
||||||
fn new(card: Card) -> Self {
|
fn new(card: Card) -> Self {
|
||||||
Self { card }
|
Self {
|
||||||
|
card,
|
||||||
|
card_caps: None,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn list_cards() -> Result<Vec<PcscClient>> {
|
pub fn list_cards() -> Result<Vec<PcscClient>> {
|
||||||
|
@ -204,7 +218,7 @@ impl PcscClient {
|
||||||
/// data").
|
/// data").
|
||||||
pub fn open(card: Card) -> Result<CardBase, OpenpgpCardError> {
|
pub fn open(card: Card) -> Result<CardBase, OpenpgpCardError> {
|
||||||
let card_client = PcscClient::new(card);
|
let card_client = PcscClient::new(card);
|
||||||
let mut ccb = Box::new(card_client) as CardClientBox;
|
let ccb = Box::new(card_client) as CardClientBox;
|
||||||
|
|
||||||
let mut ca = CardApp::new(ccb);
|
let mut ca = CardApp::new(ccb);
|
||||||
let resp = ca.select()?;
|
let resp = ca.select()?;
|
||||||
|
@ -228,8 +242,16 @@ impl CardClient for PcscClient {
|
||||||
)))
|
)))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
log::trace!(" <- APDU response: {:x?}", resp);
|
log::debug!(" <- APDU response: {:x?}", resp);
|
||||||
|
|
||||||
Ok(resp.to_vec())
|
Ok(resp.to_vec())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn init_caps(&mut self, caps: CardCaps) {
|
||||||
|
self.card_caps = Some(caps);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_caps(&self) -> Option<&CardCaps> {
|
||||||
|
self.card_caps.as_ref()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,23 +31,22 @@ use crate::{
|
||||||
|
|
||||||
pub struct CardApp {
|
pub struct CardApp {
|
||||||
card_client: CardClientBox,
|
card_client: CardClientBox,
|
||||||
card_caps: Option<CardCaps>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CardApp {
|
impl CardApp {
|
||||||
pub fn new(card_client: CardClientBox) -> Self {
|
pub fn new(card_client: CardClientBox) -> Self {
|
||||||
Self {
|
Self { card_client }
|
||||||
card_client,
|
|
||||||
card_caps: None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn take_card(self) -> CardClientBox {
|
pub(crate) fn take_card(self) -> CardClientBox {
|
||||||
self.card_client
|
self.card_client
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read capabilities from the card, and set them in the CardApp
|
/// Read capabilities from the card, and set them in the CardApp.
|
||||||
pub fn init_caps(self, ard: &Tlv) -> Result<Self> {
|
///
|
||||||
|
/// Also initializes the underlying CardClient with the caps - some
|
||||||
|
/// implementations may need this information.
|
||||||
|
pub fn init_caps(&mut self, ard: &Tlv) -> Result<()> {
|
||||||
// Determine chaining/extended length support from card
|
// Determine chaining/extended length support from card
|
||||||
// metadata and cache this information in CardApp (as a
|
// metadata and cache this information in CardApp (as a
|
||||||
// CardCaps)
|
// CardCaps)
|
||||||
|
@ -62,44 +61,36 @@ impl CardApp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let max_cmd_bytes = if let Ok(Some(eli)) =
|
let (max_cmd_bytes, max_rsp_bytes) = if let Ok(Some(eli)) =
|
||||||
CardApp::get_extended_length_information(&ard)
|
CardApp::get_extended_length_information(&ard)
|
||||||
{
|
{
|
||||||
eli.max_command_bytes
|
(eli.max_command_bytes, eli.max_response_bytes)
|
||||||
} else {
|
} else {
|
||||||
255
|
(255, 255)
|
||||||
};
|
};
|
||||||
|
|
||||||
let caps = CardCaps {
|
let caps = CardCaps {
|
||||||
ext_support,
|
ext_support,
|
||||||
chaining_support,
|
chaining_support,
|
||||||
max_cmd_bytes,
|
max_cmd_bytes,
|
||||||
|
max_rsp_bytes,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(self.set_caps(caps))
|
self.card_client.init_caps(caps);
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_caps(self, card_caps: CardCaps) -> Self {
|
Ok(())
|
||||||
Self {
|
|
||||||
card_client: self.card_client,
|
|
||||||
card_caps: Some(card_caps),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn card(&mut self) -> &mut CardClientBox {
|
pub fn card(&mut self) -> &mut CardClientBox {
|
||||||
&mut self.card_client
|
&mut self.card_client
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn card_caps(&self) -> Option<&CardCaps> {
|
|
||||||
self.card_caps.as_ref()
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- select ---
|
// --- select ---
|
||||||
|
|
||||||
/// "Select" the OpenPGP card application
|
/// "Select" the OpenPGP card application
|
||||||
pub fn select(&mut self) -> Result<Response, OpenpgpCardError> {
|
pub fn select(&mut self) -> Result<Response, OpenpgpCardError> {
|
||||||
let select_openpgp = commands::select_openpgp();
|
let select_openpgp = commands::select_openpgp();
|
||||||
apdu::send_command(&mut self.card_client, select_openpgp, false, None)
|
apdu::send_command(&mut self.card_client, select_openpgp, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- application data ---
|
// --- application data ---
|
||||||
|
@ -110,10 +101,10 @@ impl CardApp {
|
||||||
/// (the data is stored in the OpenPGPCard object).
|
/// (the data is stored in the OpenPGPCard object).
|
||||||
pub fn get_app_data(&mut self) -> Result<Tlv> {
|
pub fn get_app_data(&mut self) -> Result<Tlv> {
|
||||||
let ad = commands::get_application_data();
|
let ad = commands::get_application_data();
|
||||||
let resp = apdu::send_command(&mut self.card_client, ad, true, None)?;
|
let resp = apdu::send_command(&mut self.card_client, ad, true)?;
|
||||||
let entry = TlvEntry::from(resp.data()?, true)?;
|
let entry = TlvEntry::from(resp.data()?, true)?;
|
||||||
|
|
||||||
log::trace!(" App data TlvEntry: {:x?}", entry);
|
log::debug!(" App data TlvEntry: {:x?}", entry);
|
||||||
|
|
||||||
Ok(Tlv(Tag::from([0x6E]), entry))
|
Ok(Tlv(Tag::from([0x6E]), entry))
|
||||||
}
|
}
|
||||||
|
@ -283,7 +274,6 @@ impl CardApp {
|
||||||
&mut self.card_client,
|
&mut self.card_client,
|
||||||
commands::get_url(),
|
commands::get_url(),
|
||||||
true,
|
true,
|
||||||
self.card_caps.as_ref(),
|
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(String::from_utf8_lossy(resp.data()?).to_string())
|
Ok(String::from_utf8_lossy(resp.data()?).to_string())
|
||||||
|
@ -292,12 +282,7 @@ impl CardApp {
|
||||||
// --- cardholder related data (65) ---
|
// --- cardholder related data (65) ---
|
||||||
pub fn get_cardholder_related_data(&mut self) -> Result<CardHolder> {
|
pub fn get_cardholder_related_data(&mut self) -> Result<CardHolder> {
|
||||||
let crd = commands::cardholder_related_data();
|
let crd = commands::cardholder_related_data();
|
||||||
let resp = apdu::send_command(
|
let resp = apdu::send_command(&mut self.card_client, crd, true)?;
|
||||||
&mut self.card_client,
|
|
||||||
crd,
|
|
||||||
true,
|
|
||||||
self.card_caps.as_ref(),
|
|
||||||
)?;
|
|
||||||
resp.check_ok()?;
|
resp.check_ok()?;
|
||||||
|
|
||||||
CardHolder::try_from(resp.data()?)
|
CardHolder::try_from(resp.data()?)
|
||||||
|
@ -306,12 +291,7 @@ impl CardApp {
|
||||||
// --- security support template (7a) ---
|
// --- security support template (7a) ---
|
||||||
pub fn get_security_support_template(&mut self) -> Result<Tlv> {
|
pub fn get_security_support_template(&mut self) -> Result<Tlv> {
|
||||||
let sst = commands::get_security_support_template();
|
let sst = commands::get_security_support_template();
|
||||||
let resp = apdu::send_command(
|
let resp = apdu::send_command(&mut self.card_client, sst, true)?;
|
||||||
&mut self.card_client,
|
|
||||||
sst,
|
|
||||||
true,
|
|
||||||
self.card_caps.as_ref(),
|
|
||||||
)?;
|
|
||||||
resp.check_ok()?;
|
resp.check_ok()?;
|
||||||
|
|
||||||
Tlv::try_from(resp.data()?)
|
Tlv::try_from(resp.data()?)
|
||||||
|
@ -323,7 +303,6 @@ impl CardApp {
|
||||||
&mut self.card_client,
|
&mut self.card_client,
|
||||||
commands::get_algo_list(),
|
commands::get_algo_list(),
|
||||||
true,
|
true,
|
||||||
self.card_caps.as_ref(),
|
|
||||||
)?;
|
)?;
|
||||||
resp.check_ok()?;
|
resp.check_ok()?;
|
||||||
|
|
||||||
|
@ -339,12 +318,8 @@ impl CardApp {
|
||||||
// [apdu 00 20 00 81 08 40 40 40 40 40 40 40 40]
|
// [apdu 00 20 00 81 08 40 40 40 40 40 40 40 40]
|
||||||
for _ in 0..4 {
|
for _ in 0..4 {
|
||||||
let verify = commands::verify_pw1_81([0x40; 8].to_vec());
|
let verify = commands::verify_pw1_81([0x40; 8].to_vec());
|
||||||
let resp = apdu::send_command(
|
let resp =
|
||||||
&mut self.card_client,
|
apdu::send_command(&mut self.card_client, verify, false)?;
|
||||||
verify,
|
|
||||||
false,
|
|
||||||
self.card_caps.as_ref(),
|
|
||||||
)?;
|
|
||||||
if !(resp.status() == [0x69, 0x82]
|
if !(resp.status() == [0x69, 0x82]
|
||||||
|| resp.status() == [0x69, 0x83])
|
|| resp.status() == [0x69, 0x83])
|
||||||
{
|
{
|
||||||
|
@ -356,12 +331,8 @@ impl CardApp {
|
||||||
// [apdu 00 20 00 83 08 40 40 40 40 40 40 40 40]
|
// [apdu 00 20 00 83 08 40 40 40 40 40 40 40 40]
|
||||||
for _ in 0..4 {
|
for _ in 0..4 {
|
||||||
let verify = commands::verify_pw3([0x40; 8].to_vec());
|
let verify = commands::verify_pw3([0x40; 8].to_vec());
|
||||||
let resp = apdu::send_command(
|
let resp =
|
||||||
&mut self.card_client,
|
apdu::send_command(&mut self.card_client, verify, false)?;
|
||||||
verify,
|
|
||||||
false,
|
|
||||||
self.card_caps.as_ref(),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
if !(resp.status() == [0x69, 0x82]
|
if !(resp.status() == [0x69, 0x82]
|
||||||
|| resp.status() == [0x69, 0x83])
|
|| resp.status() == [0x69, 0x83])
|
||||||
|
@ -372,22 +343,12 @@ impl CardApp {
|
||||||
|
|
||||||
// terminate_df [apdu 00 e6 00 00]
|
// terminate_df [apdu 00 e6 00 00]
|
||||||
let term = commands::terminate_df();
|
let term = commands::terminate_df();
|
||||||
let resp = apdu::send_command(
|
let resp = apdu::send_command(&mut self.card_client, term, false)?;
|
||||||
&mut self.card_client,
|
|
||||||
term,
|
|
||||||
false,
|
|
||||||
self.card_caps.as_ref(),
|
|
||||||
)?;
|
|
||||||
resp.check_ok()?;
|
resp.check_ok()?;
|
||||||
|
|
||||||
// activate_file [apdu 00 44 00 00]
|
// activate_file [apdu 00 44 00 00]
|
||||||
let act = commands::activate_file();
|
let act = commands::activate_file();
|
||||||
let resp = apdu::send_command(
|
let resp = apdu::send_command(&mut self.card_client, act, false)?;
|
||||||
&mut self.card_client,
|
|
||||||
act,
|
|
||||||
false,
|
|
||||||
self.card_caps.as_ref(),
|
|
||||||
)?;
|
|
||||||
resp.check_ok()?;
|
resp.check_ok()?;
|
||||||
|
|
||||||
// FIXME: does the connection need to be re-opened on some cards,
|
// FIXME: does the connection need to be re-opened on some cards,
|
||||||
|
@ -403,22 +364,12 @@ impl CardApp {
|
||||||
assert!(pin.len() >= 6); // FIXME: Err
|
assert!(pin.len() >= 6); // FIXME: Err
|
||||||
|
|
||||||
let verify = commands::verify_pw1_81(pin.as_bytes().to_vec());
|
let verify = commands::verify_pw1_81(pin.as_bytes().to_vec());
|
||||||
apdu::send_command(
|
apdu::send_command(&mut self.card_client, verify, false)
|
||||||
&mut self.card_client,
|
|
||||||
verify,
|
|
||||||
false,
|
|
||||||
self.card_caps.as_ref(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_pw1(&mut self) -> Result<Response, OpenpgpCardError> {
|
pub fn check_pw1(&mut self) -> Result<Response, OpenpgpCardError> {
|
||||||
let verify = commands::verify_pw1_82(vec![]);
|
let verify = commands::verify_pw1_82(vec![]);
|
||||||
apdu::send_command(
|
apdu::send_command(&mut self.card_client, verify, false)
|
||||||
&mut self.card_client,
|
|
||||||
verify,
|
|
||||||
false,
|
|
||||||
self.card_caps.as_ref(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn verify_pw1(
|
pub fn verify_pw1(
|
||||||
|
@ -428,22 +379,12 @@ impl CardApp {
|
||||||
assert!(pin.len() >= 6); // FIXME: Err
|
assert!(pin.len() >= 6); // FIXME: Err
|
||||||
|
|
||||||
let verify = commands::verify_pw1_82(pin.as_bytes().to_vec());
|
let verify = commands::verify_pw1_82(pin.as_bytes().to_vec());
|
||||||
apdu::send_command(
|
apdu::send_command(&mut self.card_client, verify, false)
|
||||||
&mut self.card_client,
|
|
||||||
verify,
|
|
||||||
false,
|
|
||||||
self.card_caps.as_ref(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_pw3(&mut self) -> Result<Response, OpenpgpCardError> {
|
pub fn check_pw3(&mut self) -> Result<Response, OpenpgpCardError> {
|
||||||
let verify = commands::verify_pw3(vec![]);
|
let verify = commands::verify_pw3(vec![]);
|
||||||
apdu::send_command(
|
apdu::send_command(&mut self.card_client, verify, false)
|
||||||
&mut self.card_client,
|
|
||||||
verify,
|
|
||||||
false,
|
|
||||||
self.card_caps.as_ref(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn verify_pw3(
|
pub fn verify_pw3(
|
||||||
|
@ -453,12 +394,7 @@ impl CardApp {
|
||||||
assert!(pin.len() >= 8); // FIXME: Err
|
assert!(pin.len() >= 8); // FIXME: Err
|
||||||
|
|
||||||
let verify = commands::verify_pw3(pin.as_bytes().to_vec());
|
let verify = commands::verify_pw3(pin.as_bytes().to_vec());
|
||||||
apdu::send_command(
|
apdu::send_command(&mut self.card_client, verify, false)
|
||||||
&mut self.card_client,
|
|
||||||
verify,
|
|
||||||
false,
|
|
||||||
self.card_caps.as_ref(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- decrypt ---
|
// --- decrypt ---
|
||||||
|
@ -499,12 +435,7 @@ impl CardApp {
|
||||||
) -> Result<Vec<u8>, OpenpgpCardError> {
|
) -> Result<Vec<u8>, OpenpgpCardError> {
|
||||||
// The OpenPGP card is already connected and PW1 82 has been verified
|
// The OpenPGP card is already connected and PW1 82 has been verified
|
||||||
let dec_cmd = commands::decryption(data);
|
let dec_cmd = commands::decryption(data);
|
||||||
let resp = apdu::send_command(
|
let resp = apdu::send_command(&mut self.card_client, dec_cmd, true)?;
|
||||||
&mut self.card_client,
|
|
||||||
dec_cmd,
|
|
||||||
true,
|
|
||||||
self.card_caps.as_ref(),
|
|
||||||
)?;
|
|
||||||
resp.check_ok()?;
|
resp.check_ok()?;
|
||||||
|
|
||||||
Ok(resp.data().map(|d| d.to_vec())?)
|
Ok(resp.data().map(|d| d.to_vec())?)
|
||||||
|
@ -557,12 +488,7 @@ impl CardApp {
|
||||||
) -> Result<Vec<u8>, OpenpgpCardError> {
|
) -> Result<Vec<u8>, OpenpgpCardError> {
|
||||||
let dec_cmd = commands::signature(data);
|
let dec_cmd = commands::signature(data);
|
||||||
|
|
||||||
let resp = apdu::send_command(
|
let resp = apdu::send_command(&mut self.card_client, dec_cmd, true)?;
|
||||||
&mut self.card_client,
|
|
||||||
dec_cmd,
|
|
||||||
true,
|
|
||||||
self.card_caps.as_ref(),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(resp.data().map(|d| d.to_vec())?)
|
Ok(resp.data().map(|d| d.to_vec())?)
|
||||||
}
|
}
|
||||||
|
@ -574,12 +500,7 @@ impl CardApp {
|
||||||
name: &str,
|
name: &str,
|
||||||
) -> Result<Response, OpenpgpCardError> {
|
) -> Result<Response, OpenpgpCardError> {
|
||||||
let put_name = commands::put_name(name.as_bytes().to_vec());
|
let put_name = commands::put_name(name.as_bytes().to_vec());
|
||||||
apdu::send_command(
|
apdu::send_command(&mut self.card_client, put_name, false)
|
||||||
&mut self.card_client,
|
|
||||||
put_name,
|
|
||||||
false,
|
|
||||||
self.card_caps.as_ref(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_lang(
|
pub fn set_lang(
|
||||||
|
@ -587,22 +508,12 @@ impl CardApp {
|
||||||
lang: &str,
|
lang: &str,
|
||||||
) -> Result<Response, OpenpgpCardError> {
|
) -> Result<Response, OpenpgpCardError> {
|
||||||
let put_lang = commands::put_lang(lang.as_bytes().to_vec());
|
let put_lang = commands::put_lang(lang.as_bytes().to_vec());
|
||||||
apdu::send_command(
|
apdu::send_command(self.card_client.borrow_mut(), put_lang, false)
|
||||||
self.card_client.borrow_mut(),
|
|
||||||
put_lang,
|
|
||||||
false,
|
|
||||||
self.card_caps.as_ref(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_sex(&mut self, sex: Sex) -> Result<Response, OpenpgpCardError> {
|
pub fn set_sex(&mut self, sex: Sex) -> Result<Response, OpenpgpCardError> {
|
||||||
let put_sex = commands::put_sex(sex.as_u8());
|
let put_sex = commands::put_sex(sex.as_u8());
|
||||||
apdu::send_command(
|
apdu::send_command(self.card_client.borrow_mut(), put_sex, false)
|
||||||
self.card_client.borrow_mut(),
|
|
||||||
put_sex,
|
|
||||||
false,
|
|
||||||
self.card_caps.as_ref(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_url(
|
pub fn set_url(
|
||||||
|
@ -610,12 +521,7 @@ impl CardApp {
|
||||||
url: &str,
|
url: &str,
|
||||||
) -> Result<Response, OpenpgpCardError> {
|
) -> Result<Response, OpenpgpCardError> {
|
||||||
let put_url = commands::put_url(url.as_bytes().to_vec());
|
let put_url = commands::put_url(url.as_bytes().to_vec());
|
||||||
apdu::send_command(
|
apdu::send_command(&mut self.card_client, put_url, false)
|
||||||
&mut self.card_client,
|
|
||||||
put_url,
|
|
||||||
false,
|
|
||||||
self.card_caps.as_ref(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn upload_key(
|
pub fn upload_key(
|
||||||
|
|
|
@ -67,8 +67,6 @@ pub(crate) fn upload_key(
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let caps: Option<CardCaps> = card_app.card_caps().copied();
|
|
||||||
|
|
||||||
copy_key_to_card(
|
copy_key_to_card(
|
||||||
card_app.card(),
|
card_app.card(),
|
||||||
key_type,
|
key_type,
|
||||||
|
@ -76,7 +74,6 @@ pub(crate) fn upload_key(
|
||||||
key.get_fp(),
|
key.get_fp(),
|
||||||
algo_cmd,
|
algo_cmd,
|
||||||
key_cmd,
|
key_cmd,
|
||||||
caps.as_ref(),
|
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -375,7 +372,6 @@ fn copy_key_to_card(
|
||||||
fp: Vec<u8>,
|
fp: Vec<u8>,
|
||||||
algo_cmd: Command,
|
algo_cmd: Command,
|
||||||
key_cmd: Command,
|
key_cmd: Command,
|
||||||
card_caps: Option<&CardCaps>,
|
|
||||||
) -> Result<(), OpenpgpCardError> {
|
) -> Result<(), OpenpgpCardError> {
|
||||||
let fp_cmd = commands::put_data(&[key_type.get_fingerprint_put_tag()], fp);
|
let fp_cmd = commands::put_data(&[key_type.get_fingerprint_put_tag()], fp);
|
||||||
|
|
||||||
|
@ -395,11 +391,11 @@ fn copy_key_to_card(
|
||||||
|
|
||||||
// FIXME: Only write algo attributes to the card if "extended
|
// FIXME: Only write algo attributes to the card if "extended
|
||||||
// capabilities" show that they are changeable!
|
// capabilities" show that they are changeable!
|
||||||
apdu::send_command(card_client, algo_cmd, false, card_caps)?.check_ok()?;
|
apdu::send_command(card_client, algo_cmd, false)?.check_ok()?;
|
||||||
|
|
||||||
apdu::send_command(card_client, key_cmd, false, card_caps)?.check_ok()?;
|
apdu::send_command(card_client, key_cmd, false)?.check_ok()?;
|
||||||
apdu::send_command(card_client, fp_cmd, false, card_caps)?.check_ok()?;
|
apdu::send_command(card_client, fp_cmd, false)?.check_ok()?;
|
||||||
apdu::send_command(card_client, time_cmd, false, card_caps)?.check_ok()?;
|
apdu::send_command(card_client, time_cmd, false)?.check_ok()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,17 +27,27 @@ mod tlv;
|
||||||
|
|
||||||
pub trait CardClient {
|
pub trait CardClient {
|
||||||
fn transmit(&mut self, cmd: &[u8], buf_size: usize) -> Result<Vec<u8>>;
|
fn transmit(&mut self, cmd: &[u8], buf_size: usize) -> Result<Vec<u8>>;
|
||||||
|
fn init_caps(&mut self, caps: CardCaps);
|
||||||
|
fn get_caps(&self) -> Option<&CardCaps>;
|
||||||
|
|
||||||
|
/// If a CardClient implementation introduces an inherent limit for
|
||||||
|
/// maximum number of bytes per command, this fn can indicate that
|
||||||
|
/// limit by returning `Some(max_cmd_len)`.
|
||||||
|
fn max_cmd_len(&self) -> Option<usize> {
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type CardClientBox = Box<dyn CardClient + Send + Sync>;
|
pub type CardClientBox = Box<dyn CardClient + Send + Sync>;
|
||||||
|
|
||||||
/// Information about the capabilities of the card.
|
/// Information about the capabilities of the card.
|
||||||
/// (feature configuration from card metadata)
|
/// (feature configuration from card metadata)
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct CardCaps {
|
pub struct CardCaps {
|
||||||
pub(crate) ext_support: bool,
|
pub ext_support: bool,
|
||||||
pub(crate) chaining_support: bool,
|
pub chaining_support: bool,
|
||||||
pub(crate) max_cmd_bytes: u16,
|
pub max_cmd_bytes: u16,
|
||||||
|
pub max_rsp_bytes: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CardCaps {
|
impl CardCaps {
|
||||||
|
@ -45,11 +55,13 @@ impl CardCaps {
|
||||||
ext_support: bool,
|
ext_support: bool,
|
||||||
chaining_support: bool,
|
chaining_support: bool,
|
||||||
max_cmd_bytes: u16,
|
max_cmd_bytes: u16,
|
||||||
|
max_rsp_bytes: u16,
|
||||||
) -> CardCaps {
|
) -> CardCaps {
|
||||||
Self {
|
Self {
|
||||||
ext_support,
|
ext_support,
|
||||||
chaining_support,
|
chaining_support,
|
||||||
max_cmd_bytes,
|
max_cmd_bytes,
|
||||||
|
max_rsp_bytes,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -324,7 +336,7 @@ impl CardBase {
|
||||||
|
|
||||||
let ard = card_app.get_app_data()?;
|
let ard = card_app.get_app_data()?;
|
||||||
|
|
||||||
card_app = card_app.init_caps(&ard)?;
|
card_app.init_caps(&ard)?;
|
||||||
|
|
||||||
Ok(Self { card_app, ard })
|
Ok(Self { card_app, ard })
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue