refactor opening of cards
This commit is contained in:
parent
1187e816d0
commit
de0645ef0e
6 changed files with 84 additions and 110 deletions
|
@ -186,7 +186,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||
// Open fresh Card for signing
|
||||
// -----------------------------
|
||||
// let oc = CardBase::open_by_ident(&test_card_ident)?;
|
||||
let mut oc = ScdClient::open_scdc(SOCKET)?;
|
||||
let oc = ScdClient::open_scdc(SOCKET)?;
|
||||
|
||||
// Sign
|
||||
match oc.verify_pw1_for_signing("123456") {
|
||||
|
@ -220,7 +220,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||
|
||||
println!("The following OpenPGP cards are connected to your system:");
|
||||
|
||||
let cards = openpgp_card::CardBase::list_cards()?;
|
||||
let cards = openpgp_card::CardBase::list_cards_pcsc()?;
|
||||
for c in cards {
|
||||
println!(" '{}'", c.get_aid()?.ident());
|
||||
}
|
||||
|
|
|
@ -5,14 +5,14 @@ pub mod command;
|
|||
pub mod commands;
|
||||
pub mod response;
|
||||
|
||||
use anyhow::Result;
|
||||
use anyhow::{anyhow, Result};
|
||||
use pcsc::Card;
|
||||
use std::convert::TryFrom;
|
||||
|
||||
use crate::apdu::command::Command;
|
||||
use crate::apdu::response::Response;
|
||||
use crate::errors::{OcErrorStatus, OpenpgpCardError, SmartcardError};
|
||||
use crate::{CardCaps, CardClient};
|
||||
use crate::{CardBase, CardCaps, CardClient, CardClientBox};
|
||||
|
||||
#[derive(Clone, Copy, PartialEq)]
|
||||
pub(crate) enum Le {
|
||||
|
@ -26,7 +26,7 @@ pub(crate) enum Le {
|
|||
/// If the reply is truncated, this fn assembles all the parts and returns
|
||||
/// them as one aggregated Response.
|
||||
pub(crate) fn send_command(
|
||||
card_client: &mut Box<dyn CardClient + Send + Sync>,
|
||||
card_client: &mut CardClientBox,
|
||||
cmd: Command,
|
||||
expect_reply: bool,
|
||||
card_caps: Option<&CardCaps>,
|
||||
|
@ -70,7 +70,7 @@ pub(crate) fn send_command(
|
|||
/// If the response is chained, this fn only returns one chunk, the caller
|
||||
/// needs take care of chained responses
|
||||
fn send_command_low_level(
|
||||
card_client: &mut Box<dyn CardClient + Send + Sync>,
|
||||
card_client: &mut CardClientBox,
|
||||
cmd: Command,
|
||||
expect_reply: bool,
|
||||
card_caps: Option<&CardCaps>,
|
||||
|
@ -184,9 +184,27 @@ pub struct PcscClient {
|
|||
}
|
||||
|
||||
impl PcscClient {
|
||||
pub fn new(card: Card) -> Self {
|
||||
fn new(card: Card) -> Self {
|
||||
Self { card }
|
||||
}
|
||||
|
||||
/// Take a PCSC Card object and try to open the OpenPGP card applet.
|
||||
/// If successful, wrap and return the resulting CardClient as a
|
||||
/// CardBase object (which involves caching the "application related
|
||||
/// data").
|
||||
pub fn open(card: Card) -> Result<CardBase, OpenpgpCardError> {
|
||||
let card_client = PcscClient::new(card);
|
||||
let mut ccb = Box::new(card_client) as CardClientBox;
|
||||
|
||||
let select_openpgp = commands::select_openpgp();
|
||||
let resp = send_command(&mut ccb, select_openpgp, false, None)?;
|
||||
|
||||
if resp.is_ok() {
|
||||
CardBase::open_card(ccb)
|
||||
} else {
|
||||
Err(anyhow!("Couldn't open OpenPGP application").into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl CardClient for PcscClient {
|
||||
|
|
|
@ -13,34 +13,28 @@ use std::borrow::BorrowMut;
|
|||
use std::convert::TryFrom;
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use pcsc::*;
|
||||
|
||||
use apdu::{commands, response::Response};
|
||||
use parse::{
|
||||
use crate::apdu::{commands, response::Response};
|
||||
use crate::errors::OpenpgpCardError;
|
||||
use crate::parse::{
|
||||
algo_attrs::Algo, algo_info::AlgoInfo, application_id::ApplicationId,
|
||||
cardholder::CardHolder, extended_cap::ExtendedCap,
|
||||
extended_length_info::ExtendedLengthInfo, fingerprint,
|
||||
historical::Historical, pw_status::PWStatus, KeySet,
|
||||
};
|
||||
use tlv::Tlv;
|
||||
|
||||
use crate::errors::OpenpgpCardError;
|
||||
use crate::tlv::tag::Tag;
|
||||
use crate::tlv::TlvEntry;
|
||||
|
||||
use crate::Hash;
|
||||
use crate::tlv::{tag::Tag, Tlv, TlvEntry};
|
||||
use crate::{
|
||||
apdu, key_upload, parse, tlv, CardCaps, CardClient, CardUploadableKey,
|
||||
DecryptMe, KeyType, Sex,
|
||||
apdu, key_upload, parse, tlv, CardCaps, CardClientBox, CardUploadableKey,
|
||||
DecryptMe, Hash, KeyType, Sex,
|
||||
};
|
||||
|
||||
pub struct CardApp {
|
||||
card_client: Box<dyn CardClient + Send + Sync>,
|
||||
card_client: CardClientBox,
|
||||
card_caps: Option<CardCaps>,
|
||||
}
|
||||
|
||||
impl CardApp {
|
||||
pub fn new(card_client: Box<dyn CardClient + Send + Sync>) -> Self {
|
||||
pub fn new(card_client: CardClientBox) -> Self {
|
||||
Self {
|
||||
card_client,
|
||||
card_caps: None,
|
||||
|
@ -54,7 +48,7 @@ impl CardApp {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn card(&mut self) -> &mut Box<dyn CardClient + Send + Sync> {
|
||||
pub fn card(&mut self) -> &mut CardClientBox {
|
||||
&mut self.card_client
|
||||
}
|
||||
|
||||
|
|
|
@ -10,12 +10,11 @@ use crate::errors::OpenpgpCardError;
|
|||
use crate::parse::algo_attrs::{Algo, RsaAttrs};
|
||||
use crate::parse::algo_info::AlgoInfo;
|
||||
use crate::tlv::{tag::Tag, Tlv, TlvEntry};
|
||||
use crate::{apdu, CardCaps, CardClient};
|
||||
use crate::{apdu, CardCaps, CardClientBox};
|
||||
use crate::{
|
||||
tlv, CardUploadableKey, EccKey, EccType, KeyType, PrivateKeyMaterial,
|
||||
RSAKey,
|
||||
};
|
||||
use pcsc::Card;
|
||||
|
||||
/// Upload an explicitly selected Key to the card as a specific KeyType.
|
||||
///
|
||||
|
@ -370,7 +369,7 @@ fn ecc_algo_attrs_cmd(
|
|||
}
|
||||
|
||||
fn copy_key_to_card(
|
||||
card_client: &mut Box<dyn CardClient + Send + Sync>,
|
||||
card_client: &mut CardClientBox,
|
||||
key_type: KeyType,
|
||||
ts: u64,
|
||||
fp: Vec<u8>,
|
||||
|
|
|
@ -30,6 +30,8 @@ pub trait CardClient {
|
|||
fn transmit(&mut self, cmd: &[u8], buf_size: usize) -> Result<Vec<u8>>;
|
||||
}
|
||||
|
||||
pub type CardClientBox = Box<dyn CardClient + Send + Sync>;
|
||||
|
||||
/// Information about the capabilities of the card.
|
||||
/// (feature configuration from card metadata)
|
||||
#[derive(Clone, Copy)]
|
||||
|
@ -250,12 +252,12 @@ impl CardBase {
|
|||
Self { card_app, ard }
|
||||
}
|
||||
|
||||
/// Get all cards that can be opened as an OpenPGP card applet
|
||||
pub fn list_cards() -> Result<Vec<Self>> {
|
||||
/// Get all cards that can be opened as an OpenPGP card applet via pcsc
|
||||
pub fn list_cards_pcsc() -> Result<Vec<Self>> {
|
||||
let cards = card::get_cards().map_err(|err| anyhow!(err))?;
|
||||
let ocs: Vec<_> = cards
|
||||
.into_iter()
|
||||
.map(Self::open_card)
|
||||
.map(PcscClient::open)
|
||||
.map(|oc| oc.ok())
|
||||
.flatten()
|
||||
.collect();
|
||||
|
@ -267,7 +269,7 @@ impl CardBase {
|
|||
///
|
||||
/// The ident is constructed as a concatenation of manufacturer
|
||||
/// id, a colon, and the card serial. Example: "1234:5678ABCD".
|
||||
pub fn open_by_ident(ident: &str) -> Result<Self, OpenpgpCardError> {
|
||||
pub fn open_by_ident_pcsc(ident: &str) -> Result<Self, OpenpgpCardError> {
|
||||
let cards = card::get_cards().map_err(|e| {
|
||||
OpenpgpCardError::Smartcard(SmartcardError::Error(format!(
|
||||
"{:?}",
|
||||
|
@ -276,7 +278,7 @@ impl CardBase {
|
|||
})?;
|
||||
|
||||
for card in cards {
|
||||
let res = Self::open_card(card);
|
||||
let res = PcscClient::open(card);
|
||||
if let Ok(opened_card) = res {
|
||||
let res = opened_card.get_aid();
|
||||
if let Ok(aid) = res {
|
||||
|
@ -293,7 +295,7 @@ impl CardBase {
|
|||
}
|
||||
|
||||
/// Open connection to some card and select the openpgp applet
|
||||
pub fn open_yolo() -> Result<Self, OpenpgpCardError> {
|
||||
pub fn open_yolo_pcsc() -> Result<Self, OpenpgpCardError> {
|
||||
let mut cards = card::get_cards().map_err(|e| {
|
||||
OpenpgpCardError::Smartcard(SmartcardError::Error(format!(
|
||||
"{:?}",
|
||||
|
@ -304,57 +306,46 @@ impl CardBase {
|
|||
// randomly use the first card in the list
|
||||
let card = cards.swap_remove(0);
|
||||
|
||||
Self::open_card(card)
|
||||
PcscClient::open(card)
|
||||
}
|
||||
|
||||
/// Open connection to a specific card and select the openpgp applet
|
||||
fn open_card(card: Card) -> Result<Self, OpenpgpCardError> {
|
||||
let select_openpgp = commands::select_openpgp();
|
||||
/// Set up connection (cache "application related data") to a
|
||||
/// CardClient, on which the openpgp applet has already been opened.
|
||||
pub fn open_card(ccb: CardClientBox) -> Result<Self, OpenpgpCardError> {
|
||||
// read and cache "application related data"
|
||||
let mut card_app = CardApp::new(ccb);
|
||||
let ard = card_app.get_app_data()?;
|
||||
|
||||
let card_client = PcscClient::new(card);
|
||||
let mut ccb =
|
||||
Box::new(card_client) as Box<dyn CardClient + Send + Sync>;
|
||||
// Determine chaining/extended length support from card
|
||||
// metadata and cache this information in CardApp (as a
|
||||
// CardCaps)
|
||||
|
||||
let resp = apdu::send_command(&mut ccb, select_openpgp, false, None)?;
|
||||
let mut ext_support = false;
|
||||
let mut chaining_support = false;
|
||||
|
||||
if resp.is_ok() {
|
||||
// read and cache "application related data"
|
||||
let mut card_app = CardApp::new(ccb);
|
||||
let ard = card_app.get_app_data()?;
|
||||
|
||||
// Determine chaining/extended length support from card
|
||||
// metadata and cache this information in CardApp (as a
|
||||
// CardCaps)
|
||||
|
||||
let mut ext_support = false;
|
||||
let mut chaining_support = false;
|
||||
|
||||
if let Ok(hist) = CardApp::get_historical(&ard) {
|
||||
if let Some(cc) = hist.get_card_capabilities() {
|
||||
chaining_support = cc.get_command_chaining();
|
||||
ext_support = cc.get_extended_lc_le();
|
||||
}
|
||||
if let Ok(hist) = CardApp::get_historical(&ard) {
|
||||
if let Some(cc) = hist.get_card_capabilities() {
|
||||
chaining_support = cc.get_command_chaining();
|
||||
ext_support = cc.get_extended_lc_le();
|
||||
}
|
||||
|
||||
let max_cmd_bytes = if let Ok(Some(eli)) =
|
||||
CardApp::get_extended_length_information(&ard)
|
||||
{
|
||||
eli.max_command_bytes
|
||||
} else {
|
||||
255
|
||||
};
|
||||
|
||||
let caps = CardCaps {
|
||||
ext_support,
|
||||
chaining_support,
|
||||
max_cmd_bytes,
|
||||
};
|
||||
let card_app = card_app.set_caps(caps);
|
||||
|
||||
Ok(Self { card_app, ard })
|
||||
} else {
|
||||
Err(anyhow!("Couldn't open OpenPGP application").into())
|
||||
}
|
||||
|
||||
let max_cmd_bytes = if let Ok(Some(eli)) =
|
||||
CardApp::get_extended_length_information(&ard)
|
||||
{
|
||||
eli.max_command_bytes
|
||||
} else {
|
||||
255
|
||||
};
|
||||
|
||||
let caps = CardCaps {
|
||||
ext_support,
|
||||
chaining_support,
|
||||
max_cmd_bytes,
|
||||
};
|
||||
let card_app = card_app.set_caps(caps);
|
||||
|
||||
Ok(Self { card_app, ard })
|
||||
}
|
||||
|
||||
// --- application data ---
|
||||
|
|
|
@ -5,9 +5,8 @@ use sequoia_ipc::assuan::{Client, Response};
|
|||
use std::sync::{Arc, Mutex};
|
||||
use tokio::runtime::Runtime;
|
||||
|
||||
use openpgp_card::card_app::CardApp;
|
||||
use openpgp_card::errors::OpenpgpCardError;
|
||||
use openpgp_card::{CardBase, CardCaps, CardClient};
|
||||
use openpgp_card::{CardBase, CardClient, CardClientBox};
|
||||
|
||||
lazy_static! {
|
||||
pub(crate) static ref RT: Mutex<Runtime> =
|
||||
|
@ -23,40 +22,9 @@ impl ScdClient {
|
|||
/// backend.
|
||||
pub fn open_scdc(socket: &str) -> Result<CardBase, OpenpgpCardError> {
|
||||
let card_client = ScdClient::new(socket)?;
|
||||
let card_client_box =
|
||||
Box::new(card_client) as Box<dyn CardClient + Send + Sync>;
|
||||
let card_client_box = Box::new(card_client) as CardClientBox;
|
||||
|
||||
// read and cache "application related data"
|
||||
let mut card_app = CardApp::new(card_client_box);
|
||||
let ard = card_app.get_app_data()?;
|
||||
|
||||
// Determine chaining/extended length support from card
|
||||
// metadata and cache this information in CardApp (as a
|
||||
// CardCaps)
|
||||
|
||||
let mut ext_support = false;
|
||||
let mut chaining_support = false;
|
||||
|
||||
if let Ok(hist) = CardApp::get_historical(&ard) {
|
||||
if let Some(cc) = hist.get_card_capabilities() {
|
||||
chaining_support = cc.get_command_chaining();
|
||||
ext_support = cc.get_extended_lc_le();
|
||||
}
|
||||
}
|
||||
|
||||
let max_cmd_bytes = if let Ok(Some(eli)) =
|
||||
CardApp::get_extended_length_information(&ard)
|
||||
{
|
||||
eli.max_command_bytes
|
||||
} else {
|
||||
255
|
||||
};
|
||||
|
||||
let caps = CardCaps::new(ext_support, chaining_support, max_cmd_bytes);
|
||||
|
||||
let card_app = card_app.set_caps(caps);
|
||||
|
||||
Ok(CardBase::new(card_app, ard))
|
||||
CardBase::open_card(card_client_box)
|
||||
}
|
||||
|
||||
pub fn new(socket: &str) -> Result<Self> {
|
||||
|
@ -80,6 +48,10 @@ impl CardClient for ScdClient {
|
|||
|
||||
while let Some(response) = rt.block_on(client.next()) {
|
||||
println!("res: {:x?}", response);
|
||||
if let Err(_) = response {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
if let Ok(Response::Data { partial }) = response {
|
||||
let res = partial;
|
||||
|
||||
|
|
Loading…
Reference in a new issue