Change the API for interactions between openpgp-card and backends.

The goal of this change is a cleaner structure, and in particular to make it the default for client-code to obtain a CardApp with pre-initialized "capabilities" (that is, init_caps() gets called implicitely).
This commit is contained in:
Heiko Schaefer 2021-11-11 15:28:44 +01:00
parent 288a2a8325
commit d55985807c
No known key found for this signature in database
GPG key ID: 4A849A1904CCBD7D
14 changed files with 147 additions and 173 deletions

View file

@ -97,16 +97,12 @@ impl TestCard {
let res = ScdClient::shutdown_scd(None);
log::trace!(" Attempt to shutdown scd: {:?}", res);
for card_client in PcscClient::cards()? {
let mut ca = CardApp::from(card_client);
for mut ca in PcscClient::cards()? {
// Set Card Capabilities (chaining, command length, ..)
let ard = ca.get_application_related_data()?;
let app_id = ard.get_application_id()?;
if app_id.ident().as_str() == ident.to_uppercase() {
ca.init_caps(&ard)?;
// println!("opened pcsc card {}", ident);
return Ok(ca);
@ -116,8 +112,7 @@ impl TestCard {
Err(anyhow!("Pcsc card {} not found", ident))
}
Self::Scdc(serial) => {
let card_client = ScdClient::open_by_serial(None, serial)?;
let mut ca = CardApp::from(card_client);
let mut ca = ScdClient::open_by_serial(None, serial)?;
// Set Card Capabilities (chaining, command length, ..)
let ard = ca.get_application_related_data()?;

View file

@ -9,8 +9,7 @@ use openpgp_card_sequoia::card::Open;
fn main() -> Result<()> {
println!("The following OpenPGP cards are connected to your system:");
for ccb in PcscClient::cards()? {
let mut ca = ccb.into();
for mut ca in PcscClient::cards()? {
let open = Open::open(&mut ca)?;
println!(" {}", open.application_identifier()?.ident());
}

View file

@ -22,7 +22,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let pin_file = &args[1];
let cert_file = &args[2];
let mut ca = PcscClient::open_by_ident(&card_ident)?.into();
let mut ca = PcscClient::open_by_ident(card_ident)?;
let mut open = Open::open(&mut ca)?;
let pin = std::fs::read_to_string(pin_file)?;

View file

@ -23,7 +23,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let pin_file = &args[1];
let cert_file = &args[2];
let mut ca = PcscClient::open_by_ident(&card_ident)?.into();
let mut ca = PcscClient::open_by_ident(card_ident)?;
let mut open = Open::open(&mut ca)?;
let pin = std::fs::read_to_string(pin_file)?;

View file

@ -35,7 +35,7 @@ fn main() -> Result<(), Box<dyn Error>> {
let test_card_ident = env::var("TEST_CARD_IDENT");
if let Ok(test_card_ident) = test_card_ident {
let mut card = PcscClient::open_by_ident(&test_card_ident)?.into();
let mut card = PcscClient::open_by_ident(&test_card_ident)?;
let mut open = Open::open(&mut card)?;
// card metadata
@ -150,7 +150,7 @@ fn main() -> Result<(), Box<dyn Error>> {
// -----------------------------
// Open fresh Card for decrypt
// -----------------------------
let mut card = PcscClient::open_by_ident(&test_card_ident)?.into();
let mut card = PcscClient::open_by_ident(&test_card_ident)?;
let mut open = Open::open(&mut card)?;
// Check that we're still using the expected card
@ -189,7 +189,7 @@ fn main() -> Result<(), Box<dyn Error>> {
// -----------------------------
// Open fresh Card for signing
// -----------------------------
let mut card = PcscClient::open_by_ident(&test_card_ident)?.into();
let mut card = PcscClient::open_by_ident(&test_card_ident)?;
let mut open = Open::open(&mut card)?;
// Sign
@ -219,8 +219,7 @@ fn main() -> Result<(), Box<dyn Error>> {
println!("The following OpenPGP cards are connected to your system:");
for card in PcscClient::cards()? {
let mut card = card.into();
for mut card in PcscClient::cards()? {
let open = Open::open(&mut card)?;
println!(" {}", open.application_identifier()?.ident());
}

View file

@ -13,7 +13,7 @@ use std::convert::TryFrom;
use crate::apdu::command::Expect;
use crate::apdu::{command::Command, response::RawResponse};
use crate::{CardClientBox, Error, StatusBytes};
use crate::{CardClient, Error, StatusBytes};
/// "Maximum amount of bytes in a short APDU command or response" (from pcsc)
const MAX_BUFFER_SIZE: usize = 264;
@ -23,7 +23,7 @@ const MAX_BUFFER_SIZE: usize = 264;
/// 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 CardClientBox,
card_client: &mut dyn CardClient,
cmd: Command,
expect_reply: bool,
) -> Result<RawResponse, Error> {
@ -82,7 +82,7 @@ pub(crate) fn send_command(
/// If the response is chained, this fn only returns one chunk, the caller
/// needs to re-assemble the chained response-parts.
fn send_command_low_level(
card_client: &mut CardClientBox,
card_client: &mut dyn CardClient,
cmd: Command,
expect_response: Expect,
) -> Result<Vec<u8>, Error> {

View file

@ -3,7 +3,6 @@
//! CardApp exposes functionality of the "OpenPGP card" application.
use std::borrow::BorrowMut;
use std::convert::TryFrom;
use std::convert::TryInto;
@ -19,7 +18,7 @@ use crate::crypto_data::{
CardUploadableKey, Cryptogram, Hash, PublicKeyMaterial,
};
use crate::tlv::{tag::Tag, value::Value, Tlv};
use crate::{apdu, keys, CardCaps, CardClientBox, KeyType};
use crate::{apdu, keys, CardCaps, CardClient, CardClientBox, KeyType};
use crate::{Error, StatusBytes};
/// Low-level access to OpenPGP card functionality.
@ -33,22 +32,26 @@ pub struct CardApp {
card_client: CardClientBox,
}
impl From<CardClientBox> for CardApp {
fn from(card_client: CardClientBox) -> Self {
Self { card_client }
}
}
impl From<CardApp> for CardClientBox {
fn from(card_app: CardApp) -> CardClientBox {
card_app.card_client
}
}
impl CardApp {
/// Get a CardApp based on a CardClient.
///
/// It is expected that SELECT has already been performed on the card.
///
/// This fn calls CardClient::init_caps(). It should probably only be used
/// by backend implementations, not by user code. User Code should get
/// a fully initialized CardApp from their backend implementation.
pub fn initialize(card_client: CardClientBox) -> Result<Self> {
let mut ca = Self { card_client };
let ard = ca.get_application_related_data()?;
ca.init_caps(&ard)?;
Ok(ca)
}
/// Get the CardClient for this CardApp
pub(crate) fn get_card_client(&mut self) -> &mut CardClientBox {
&mut self.card_client
pub(crate) fn card_client(&mut self) -> &mut dyn CardClient {
&mut *self.card_client
}
/// Initialize the CardCaps settings in the underlying CardClient
@ -95,15 +98,6 @@ impl CardApp {
Ok(())
}
// --- select ---
/// Select the OpenPGP card application
pub fn select(&mut self) -> Result<Response, Error> {
let select_openpgp = commands::select_openpgp();
apdu::send_command(&mut self.card_client, select_openpgp, false)?
.try_into()
}
// --- get data ---
/// Get the "application related data" from the card.
@ -115,7 +109,7 @@ impl CardApp {
&mut self,
) -> Result<ApplicationRelatedData> {
let ad = commands::get_application_data();
let resp = apdu::send_command(&mut self.card_client, ad, true)?;
let resp = apdu::send_command(self.card_client(), ad, true)?;
let value = Value::from(resp.data()?, true)?;
log::debug!(" App data Value: {:x?}", value);
@ -130,7 +124,7 @@ impl CardApp {
assert!((1..=4).contains(&num));
let cmd = commands::get_private_do(num);
let resp = apdu::send_command(&mut self.card_client, cmd, true)?;
let resp = apdu::send_command(self.card_client(), cmd, true)?;
Ok(resp.data()?.to_vec())
}
@ -166,11 +160,8 @@ impl CardApp {
// --- URL (5f50) ---
pub fn get_url(&mut self) -> Result<String> {
let resp = apdu::send_command(
&mut self.card_client,
commands::get_url(),
true,
)?;
let resp =
apdu::send_command(self.card_client(), commands::get_url(), true)?;
Ok(String::from_utf8_lossy(resp.data()?).to_string())
}
@ -180,7 +171,7 @@ impl CardApp {
&mut self,
) -> Result<CardholderRelatedData> {
let crd = commands::cardholder_related_data();
let resp = apdu::send_command(&mut self.card_client, crd, true)?;
let resp = apdu::send_command(self.card_client(), crd, true)?;
resp.check_ok()?;
CardholderRelatedData::try_from(resp.data()?)
@ -191,7 +182,7 @@ impl CardApp {
&mut self,
) -> Result<SecuritySupportTemplate> {
let sst = commands::get_security_support_template();
let resp = apdu::send_command(&mut self.card_client, sst, true)?;
let resp = apdu::send_command(self.card_client(), sst, true)?;
resp.check_ok()?;
let tlv = Tlv::try_from(resp.data()?)?;
@ -219,13 +210,13 @@ impl CardApp {
/// certificate (if the card supports multiple certificates).
pub fn get_cardholder_certificate(&mut self) -> Result<Response, Error> {
let cmd = commands::get_cardholder_certificate();
apdu::send_command(&mut self.card_client, cmd, true)?.try_into()
apdu::send_command(self.card_client(), cmd, true)?.try_into()
}
/// DO "Algorithm Information"
pub fn get_algo_info(&mut self) -> Result<Option<AlgoInfo>> {
let resp = apdu::send_command(
&mut self.card_client,
self.card_client(),
commands::get_algo_list(),
true,
)?;
@ -250,7 +241,7 @@ impl CardApp {
let data = tlv.serialize();
let cmd = commands::select_data(num, data);
apdu::send_command(&mut self.card_client, cmd, true)?.try_into()
apdu::send_command(self.card_client(), cmd, true)?.try_into()
}
// ----------
@ -268,8 +259,7 @@ impl CardApp {
// [apdu 00 20 00 81 08 40 40 40 40 40 40 40 40]
for _ in 0..4 {
let verify = commands::verify_pw1_81([0x40; 8].to_vec());
let resp =
apdu::send_command(&mut self.card_client, verify, false)?;
let resp = apdu::send_command(self.card_client(), verify, false)?;
if !(resp.status() == StatusBytes::SecurityStatusNotSatisfied
|| resp.status() == StatusBytes::AuthenticationMethodBlocked
|| matches!(resp.status(), StatusBytes::PasswordNotChecked(_)))
@ -282,8 +272,7 @@ impl CardApp {
// [apdu 00 20 00 83 08 40 40 40 40 40 40 40 40]
for _ in 0..4 {
let verify = commands::verify_pw3([0x40; 8].to_vec());
let resp =
apdu::send_command(&mut self.card_client, verify, false)?;
let resp = apdu::send_command(self.card_client(), verify, false)?;
if !(resp.status() == StatusBytes::SecurityStatusNotSatisfied
|| resp.status() == StatusBytes::AuthenticationMethodBlocked
@ -295,12 +284,12 @@ impl CardApp {
// terminate_df [apdu 00 e6 00 00]
let term = commands::terminate_df();
let resp = apdu::send_command(&mut self.card_client, term, false)?;
let resp = apdu::send_command(self.card_client(), term, false)?;
resp.check_ok()?;
// activate_file [apdu 00 44 00 00]
let act = commands::activate_file();
let resp = apdu::send_command(&mut self.card_client, act, false)?;
let resp = apdu::send_command(self.card_client(), act, false)?;
resp.check_ok()?;
Ok(())
@ -317,7 +306,7 @@ impl CardApp {
pin: &str,
) -> Result<Response, Error> {
let verify = commands::verify_pw1_81(pin.as_bytes().to_vec());
apdu::send_command(&mut self.card_client, verify, false)?.try_into()
apdu::send_command(self.card_client(), verify, false)?.try_into()
}
/// Check the current access of PW1 for signing (mode 81).
@ -328,14 +317,14 @@ impl CardApp {
/// e.g. yubikey 5)
pub fn check_pw1_for_signing(&mut self) -> Result<Response, Error> {
let verify = commands::verify_pw1_81(vec![]);
apdu::send_command(&mut self.card_client, verify, false)?.try_into()
apdu::send_command(self.card_client(), verify, false)?.try_into()
}
/// Verify PW1 (user) and set an appropriate access status.
/// (For operations except signing, mode 82).
pub fn verify_pw1(&mut self, pin: &str) -> Result<Response, Error> {
let verify = commands::verify_pw1_82(pin.as_bytes().to_vec());
apdu::send_command(&mut self.card_client, verify, false)?.try_into()
apdu::send_command(self.card_client(), verify, false)?.try_into()
}
/// Check the current access of PW1.
@ -347,13 +336,13 @@ impl CardApp {
/// e.g. yubikey 5)
pub fn check_pw1(&mut self) -> Result<Response, Error> {
let verify = commands::verify_pw1_82(vec![]);
apdu::send_command(&mut self.card_client, verify, false)?.try_into()
apdu::send_command(self.card_client(), verify, false)?.try_into()
}
/// Verify PW3 (admin) and set an appropriate access status.
pub fn verify_pw3(&mut self, pin: &str) -> Result<Response, Error> {
let verify = commands::verify_pw3(pin.as_bytes().to_vec());
apdu::send_command(&mut self.card_client, verify, false)?.try_into()
apdu::send_command(self.card_client(), verify, false)?.try_into()
}
/// Check the current access of PW3 (admin).
@ -364,7 +353,7 @@ impl CardApp {
/// e.g. yubikey 5)
pub fn check_pw3(&mut self) -> Result<Response, Error> {
let verify = commands::verify_pw3(vec![]);
apdu::send_command(&mut self.card_client, verify, false)?.try_into()
apdu::send_command(self.card_client(), verify, false)?.try_into()
}
/// Change the value of PW1 (user password).
@ -380,7 +369,7 @@ impl CardApp {
data.extend(new.as_bytes());
let change = commands::change_pw1(data);
apdu::send_command(&mut self.card_client, change, false)?.try_into()
apdu::send_command(self.card_client(), change, false)?.try_into()
}
/// Change the value of PW3 (admin password).
@ -396,7 +385,7 @@ impl CardApp {
data.extend(new.as_bytes());
let change = commands::change_pw3(data);
apdu::send_command(&mut self.card_client, change, false)?.try_into()
apdu::send_command(self.card_client(), change, false)?.try_into()
}
/// Reset the error counter for PW1 (user password) and set a new value
@ -412,7 +401,7 @@ impl CardApp {
resetting_code: Option<Vec<u8>>,
) -> Result<Response, Error> {
let reset = commands::reset_retry_counter_pw1(resetting_code, new_pw1);
apdu::send_command(&mut self.card_client, reset, false)?.try_into()
apdu::send_command(self.card_client(), reset, false)?.try_into()
}
// --- decrypt ---
@ -460,7 +449,7 @@ impl CardApp {
fn pso_decipher(&mut self, data: Vec<u8>) -> Result<Vec<u8>, Error> {
// The OpenPGP card is already connected and PW1 82 has been verified
let dec_cmd = commands::decryption(data);
let resp = apdu::send_command(&mut self.card_client, dec_cmd, true)?;
let resp = apdu::send_command(self.card_client(), dec_cmd, true)?;
resp.check_ok()?;
Ok(resp.data().map(|d| d.to_vec())?)
@ -522,7 +511,7 @@ impl CardApp {
) -> Result<Vec<u8>, Error> {
let cds_cmd = commands::signature(data);
let resp = apdu::send_command(&mut self.card_client, cds_cmd, true)?;
let resp = apdu::send_command(self.card_client(), cds_cmd, true)?;
Ok(resp.data().map(|d| d.to_vec())?)
}
@ -553,7 +542,7 @@ impl CardApp {
data: Vec<u8>,
) -> Result<Vec<u8>, Error> {
let ia_cmd = commands::internal_authenticate(data);
let resp = apdu::send_command(&mut self.card_client, ia_cmd, true)?;
let resp = apdu::send_command(self.card_client(), ia_cmd, true)?;
Ok(resp.data().map(|d| d.to_vec())?)
}
@ -571,31 +560,29 @@ impl CardApp {
assert!((1..=4).contains(&num));
let cmd = commands::put_private_do(num, data);
let resp = apdu::send_command(&mut self.card_client, cmd, true)?;
let resp = apdu::send_command(self.card_client(), cmd, true)?;
Ok(resp.data()?.to_vec())
}
pub fn set_name(&mut self, name: &str) -> Result<Response, Error> {
let put_name = commands::put_name(name.as_bytes().to_vec());
apdu::send_command(&mut self.card_client, put_name, false)?.try_into()
apdu::send_command(self.card_client(), put_name, false)?.try_into()
}
pub fn set_lang(&mut self, lang: &str) -> Result<Response, Error> {
let put_lang = commands::put_lang(lang.as_bytes().to_vec());
apdu::send_command(self.card_client.borrow_mut(), put_lang, false)?
.try_into()
apdu::send_command(self.card_client(), put_lang, false)?.try_into()
}
pub fn set_sex(&mut self, sex: Sex) -> Result<Response, Error> {
let put_sex = commands::put_sex((&sex).into());
apdu::send_command(self.card_client.borrow_mut(), put_sex, false)?
.try_into()
apdu::send_command(self.card_client(), put_sex, false)?.try_into()
}
pub fn set_url(&mut self, url: &str) -> Result<Response, Error> {
let put_url = commands::put_url(url.as_bytes().to_vec());
apdu::send_command(&mut self.card_client, put_url, false)?.try_into()
apdu::send_command(self.card_client(), put_url, false)?.try_into()
}
pub fn set_creation_time(
@ -617,7 +604,7 @@ impl CardApp {
time_value,
);
apdu::send_command(&mut self.card_client, time_cmd, false)?.try_into()
apdu::send_command(self.card_client(), time_cmd, false)?.try_into()
}
pub fn set_fingerprint(
@ -630,7 +617,7 @@ impl CardApp {
fp.as_bytes().to_vec(),
);
apdu::send_command(self.get_card_client(), fp_cmd, false)?.try_into()
apdu::send_command(self.card_client(), fp_cmd, false)?.try_into()
}
/// Set PW Status Bytes.
@ -652,7 +639,7 @@ impl CardApp {
let data = pw_status.serialize_for_put(long);
let cmd = commands::put_pw_status(data);
apdu::send_command(self.get_card_client(), cmd, false)?.try_into()
apdu::send_command(self.card_client(), cmd, false)?.try_into()
}
/// Set cardholder certificate (for AUT, DEC or SIG).
@ -664,7 +651,7 @@ impl CardApp {
data: Vec<u8>,
) -> Result<Response, Error> {
let cmd = commands::put_cardholder_certificate(data);
apdu::send_command(&mut self.card_client, cmd, false)?.try_into()
apdu::send_command(self.card_client(), cmd, false)?.try_into()
}
/// Set algorithm attributes
@ -680,7 +667,7 @@ impl CardApp {
algo.get_data()?,
);
apdu::send_command(&mut self.card_client, cmd, false)?.try_into()
apdu::send_command(self.card_client(), cmd, false)?.try_into()
}
/// Set resetting code
@ -690,7 +677,7 @@ impl CardApp {
resetting_code: Vec<u8>,
) -> Result<Response, Error> {
let cmd = commands::put_data(&[0xd3], resetting_code);
apdu::send_command(&mut self.card_client, cmd, false)?.try_into()
apdu::send_command(self.card_client(), cmd, false)?.try_into()
}
/// Import an existing private key to the card.

View file

@ -135,9 +135,7 @@ pub(crate) fn generate_asymmetric_key_pair(
let crt = get_crt(key_type)?;
let gen_key_cmd = commands::gen_key(crt.serialize().to_vec());
let card_client = card_app.get_card_client();
let resp = apdu::send_command(card_client, gen_key_cmd, true)?;
let resp = apdu::send_command(card_app.card_client(), gen_key_cmd, true)?;
resp.check_ok()?;
let tlv = Tlv::try_from(resp.data()?)?;
@ -164,7 +162,7 @@ pub(crate) fn get_pub_key(
let get_pub_key_cmd = commands::get_pub_key(crt.serialize().to_vec());
let resp =
apdu::send_command(card_app.get_card_client(), get_pub_key_cmd, true)?;
apdu::send_command(card_app.card_client(), get_pub_key_cmd, true)?;
resp.check_ok()?;
let tlv = Tlv::try_from(resp.data()?)?;
@ -216,8 +214,7 @@ pub(crate) fn key_import(
card_app.set_algorithm_attributes(key_type, &algo)?;
}
apdu::send_command(card_app.get_card_client(), key_cmd, false)?
.check_ok()?;
apdu::send_command(card_app.card_client(), key_cmd, false)?.check_ok()?;
card_app.set_fingerprint(fp, key_type)?;
card_app.set_creation_time(key.get_ts(), key_type)?;

View file

@ -25,10 +25,8 @@
//! crate offers a higher level wrapper based on the
//! [Sequoia PGP](https://sequoia-pgp.org/) implementation.
use anyhow::Result;
pub mod algorithm;
mod apdu;
pub(crate) mod apdu;
mod card_app;
pub mod card_do;
pub mod crypto_data;
@ -40,6 +38,11 @@ pub use crate::apdu::response::Response;
pub use crate::card_app::CardApp;
pub use crate::errors::{Error, SmartcardError, StatusBytes};
use anyhow::Result;
use std::convert::TryInto;
use crate::apdu::commands;
/// The CardClient trait defines communication with an OpenPGP card via a
/// backend implementation (e.g. the pcsc backend in the crate
/// [openpgp-card-pcsc](https://crates.io/crates/openpgp-card-pcsc)).
@ -75,6 +78,14 @@ pub trait CardClient {
/// A boxed CardClient (which is Send+Sync).
pub type CardClientBox = Box<dyn CardClient + Send + Sync>;
impl dyn CardClient {
/// Select the OpenPGP card application
pub fn select(&mut self) -> Result<Response, Error> {
let select_openpgp = commands::select_openpgp();
apdu::send_command(self, select_openpgp, false)?.try_into()
}
}
/// Configuration of the capabilities of the card.
///
/// This configuration is used to determine e.g. if chaining or extended

View file

@ -4,9 +4,7 @@
use anyhow::{anyhow, Result};
use pcsc::{Card, Context, Protocols, Scope, ShareMode};
use openpgp_card::{
CardApp, CardCaps, CardClient, CardClientBox, Error, SmartcardError,
};
use openpgp_card::{CardApp, CardCaps, CardClient, Error, SmartcardError};
pub struct PcscClient {
card: Card,
@ -21,6 +19,11 @@ impl PcscClient {
}
}
/// Get an initialized CardApp from a card
fn into_card_app(self) -> Result<CardApp> {
CardApp::initialize(Box::new(self))
}
/// Opened PCSC Cards without selecting the OpenPGP card application
fn pcsc_cards() -> Result<Vec<Card>, SmartcardError> {
let ctx = match Context::establish(Scope::User) {
@ -84,56 +87,43 @@ impl PcscClient {
/// Return all cards on which the OpenPGP application could be selected.
///
/// Each card is opened and has the OpenPGP application selected.
pub fn cards() -> Result<Vec<CardClientBox>> {
let cards = Self::unopened_cards()?
.into_iter()
.map(Self::select)
.map(|res| res.ok())
.flatten()
.map(|ca| ca.into())
.collect();
/// Cards are initialized via init_caps().
pub fn cards() -> Result<Vec<CardApp>> {
let mut cards = vec![];
for mut card in Self::unopened_cards()? {
if Self::select(&mut card).is_ok() {
if let Ok(ca) = card.into_card_app() {
cards.push(ca);
}
}
}
Ok(cards)
}
/// Try to select the OpenPGP application on a card
fn select(card_client: PcscClient) -> Result<CardApp, Error> {
let ccb = Box::new(card_client) as CardClientBox;
let mut ca = CardApp::from(ccb);
if ca.select().is_ok() {
Ok(ca)
fn select(card_client: &mut PcscClient) -> Result<(), Error> {
if <dyn CardClient>::select(card_client).is_ok() {
Ok(())
} else {
Err(Error::Smartcard(SmartcardError::SelectOpenPGPCardFailed))
}
}
/// Get application related data from the card and check if 'ident'
/// matches
fn match_by_ident(
mut ca: CardApp,
ident: &str,
) -> Result<Option<CardClientBox>, Error> {
let ard = ca.get_application_related_data()?;
let aid = ard.get_application_id()?;
if aid.ident() == ident {
Ok(Some(ca.into()))
} else {
Ok(None)
}
}
/// Returns the OpenPGP card that matches `ident`, if it is available.
/// The OpenPGP application of the `CardClientBox` has been selected.
pub fn open_by_ident(ident: &str) -> Result<CardClientBox, Error> {
for card in Self::unopened_cards()? {
if let Ok(ca) = Self::select(card) {
if let Some(matched_card) =
PcscClient::match_by_ident(ca, ident)?
{
return Ok(matched_card);
}
/// A fully initialized CardApp is returned: application has been
/// selected, init_caps() has been performed.
pub fn open_by_ident(ident: &str) -> Result<CardApp, Error> {
for mut card in Self::unopened_cards()? {
Self::select(&mut card)?;
let mut ca = card.into_card_app()?;
let ard = ca.get_application_related_data()?;
let aid = ard.get_application_id()?;
if aid.ident() == ident {
return Ok(ca);
}
}

View file

@ -13,7 +13,7 @@ use sequoia_ipc::gnupg::{Agent, Context};
use std::sync::Mutex;
use tokio::runtime::Runtime;
use openpgp_card::Error;
use openpgp_card::{CardApp, Error};
use openpgp_card::{CardCaps, CardClient, CardClientBox};
lazy_static! {
@ -118,11 +118,11 @@ impl ScdClient {
pub fn open_by_serial(
agent: Option<Agent>,
serial: &str,
) -> Result<CardClientBox, Error> {
) -> Result<CardApp, Error> {
let mut card = ScdClient::new(agent, true)?;
card.select_card(serial)?;
Ok(Box::new(card) as CardClientBox)
Ok(CardApp::initialize(Box::new(card))?)
}
/// Ask scdameon to switch to using a specific OpenPGP card, based on

View file

@ -13,7 +13,7 @@ mod cli;
fn main() -> Result<(), Box<dyn std::error::Error>> {
let cli = cli::Cli::from_args();
let mut card = PcscClient::open_by_ident(&cli.ident)?.into();
let mut card = PcscClient::open_by_ident(&cli.ident)?;
let mut open = Open::open(&mut card)?;
match cli.cmd {
@ -145,15 +145,13 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let res = if let Some(rst) = rst {
// reset to new user pin
open.reset_user_pin(&rst, &newpin1)
} else if let Some(mut admin) = open.admin_card() {
admin.reset_user_pin(&newpin1)
} else {
if let Some(mut admin) = open.admin_card() {
admin.reset_user_pin(&newpin1)
} else {
return Err(anyhow::anyhow!(
"Failed to use card in admin-mode."
)
.into());
}
return Err(anyhow::anyhow!(
"Failed to use card in admin-mode."
)
.into());
};
if res.is_err() {

View file

@ -71,7 +71,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
admin_pin,
cmd,
} => {
let mut card = util::open_card(&ident)?.into();
let mut card = util::open_card(&ident)?;
let mut open = Open::open(&mut card)?;
match cmd {
@ -137,8 +137,7 @@ fn list_cards() -> Result<()> {
if !cards.is_empty() {
println!("Available OpenPGP cards:");
for card in cards {
let mut card = card.into();
for mut card in cards {
let open = Open::open(&mut card)?;
println!(" {}", open.application_identifier()?.ident());
}
@ -149,18 +148,17 @@ fn list_cards() -> Result<()> {
}
fn print_status(ident: Option<String>, verbose: bool) -> Result<()> {
let ccb = if let Some(ident) = ident {
let mut ca = if let Some(ident) = ident {
util::open_card(&ident)?
} else {
let mut cards = util::cards()?;
if cards.len() == 1 {
cards.pop().unwrap()
} else {
return Err(anyhow::anyhow!("Found {} cards", cards.len()).into());
return Err(anyhow::anyhow!("Found {} cards", cards.len()));
}
};
let mut card = ccb.into();
let mut open = Open::open(&mut card)?;
let mut open = Open::open(&mut ca)?;
print!("OpenPGP card {}", open.application_identifier()?.ident());
@ -291,10 +289,10 @@ fn decrypt(
let input = util::open_or_stdin(input.as_deref())?;
let mut card = util::open_card(&ident)?.into();
let mut card = util::open_card(ident)?;
let mut open = Open::open(&mut card)?;
let mut user = util::get_user(&mut open, &pin_file)?;
let mut user = util::get_user(&mut open, pin_file)?;
let d = user.decryptor(&cert, &p)?;
let db = DecryptorBuilder::from_reader(input)?;
@ -316,10 +314,10 @@ fn sign_detached(
let mut input = util::open_or_stdin(input.as_deref())?;
let mut card = util::open_card(&ident)?.into();
let mut card = util::open_card(ident)?;
let mut open = Open::open(&mut card)?;
let mut sign = util::get_sign(&mut open, &pin_file)?;
let mut sign = util::get_sign(&mut open, pin_file)?;
let s = sign.signer(&cert, &p)?;
let message = Armorer::new(Message::new(std::io::stdout())).build()?;
@ -333,7 +331,7 @@ fn sign_detached(
fn factory_reset(ident: &str) -> Result<()> {
println!("Resetting Card {}", ident);
let mut card = util::open_card(ident)?.into();
let mut card = util::open_card(ident)?;
Open::open(&mut card)?.factory_reset()
}
@ -341,16 +339,16 @@ fn key_import_yolo(mut admin: Admin, key: &Cert) -> Result<()> {
let p = StandardPolicy::new();
let sig =
openpgp_card_sequoia::sq_util::get_subkey(&key, &p, KeyType::Signing)?;
openpgp_card_sequoia::sq_util::get_subkey(key, &p, KeyType::Signing)?;
let dec = openpgp_card_sequoia::sq_util::get_subkey(
&key,
key,
&p,
KeyType::Decryption,
)?;
let auth = openpgp_card_sequoia::sq_util::get_subkey(
&key,
key,
&p,
KeyType::Authentication,
)?;
@ -382,7 +380,7 @@ fn key_import_explicit(
if let Some(sig_fp) = sig_fp {
if let Some(sig) =
sq_util::get_subkey_by_fingerprint(&key, &p, &sig_fp)?
sq_util::get_subkey_by_fingerprint(key, &p, &sig_fp)?
{
println!("Uploading {} as signing key", sig.fingerprint());
admin.upload_key(sig, KeyType::Signing, None)?;
@ -393,7 +391,7 @@ fn key_import_explicit(
if let Some(dec_fp) = dec_fp {
if let Some(dec) =
sq_util::get_subkey_by_fingerprint(&key, &p, &dec_fp)?
sq_util::get_subkey_by_fingerprint(key, &p, &dec_fp)?
{
println!("Uploading {} as decryption key", dec.fingerprint());
admin.upload_key(dec, KeyType::Decryption, None)?;
@ -404,7 +402,7 @@ fn key_import_explicit(
if let Some(auth_fp) = auth_fp {
if let Some(auth) =
sq_util::get_subkey_by_fingerprint(&key, &p, &auth_fp)?
sq_util::get_subkey_by_fingerprint(key, &p, &auth_fp)?
{
println!("Uploading {} as authentication key", auth.fingerprint());
admin.upload_key(auth, KeyType::Authentication, None)?;
@ -478,7 +476,7 @@ fn generate_keys(
// Write armored certificate to the output file (or stdout)
let mut output = util::open_or_stdout(output.as_deref())?;
output.write(armored.as_bytes())?;
output.write_all(armored.as_bytes())?;
Ok(())
}
@ -519,7 +517,7 @@ fn gen_subkeys(
// If none of them work, fail and return all errors
for (n, alg) in algos.iter().enumerate() {
let a = Some(alg.clone());
let a = Some(*alg);
log::info!(" Trying key generation with algo {:?}", alg);

View file

@ -3,16 +3,16 @@
use anyhow::{Context, Result};
use openpgp_card::{CardClientBox, Error};
use openpgp_card::{CardApp, Error};
use openpgp_card_pcsc::PcscClient;
use openpgp_card_sequoia::card::{Admin, Open, Sign, User};
use std::path::Path;
pub(crate) fn cards() -> Result<Vec<CardClientBox>> {
pub(crate) fn cards() -> Result<Vec<CardApp>> {
PcscClient::cards()
}
pub(crate) fn open_card(ident: &str) -> Result<CardClientBox, Error> {
pub(crate) fn open_card(ident: &str) -> Result<CardApp, Error> {
PcscClient::open_by_ident(ident)
}