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:
parent
288a2a8325
commit
d55985807c
14 changed files with 147 additions and 173 deletions
|
@ -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()?;
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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)?;
|
||||
|
|
|
@ -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)?;
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)?;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue