diff --git a/card-functionality/src/cards.rs b/card-functionality/src/cards.rs index 489a79d..198d2b3 100644 --- a/card-functionality/src/cards.rs +++ b/card-functionality/src/cards.rs @@ -8,7 +8,7 @@ use anyhow::Result; use serde_derive::Deserialize; use std::collections::BTreeMap; -use openpgp_card::CardApp; +use openpgp_card::CardClient; use openpgp_card_pcsc::PcscClient; use openpgp_card_scdc::ScdClient; @@ -38,7 +38,9 @@ pub struct TestCardApp { } impl TestCardApp { - pub(crate) fn get_card_app(&self) -> Result { + pub(crate) fn get_card_client( + &self, + ) -> Result> { self.tc.open() } @@ -89,7 +91,7 @@ pub enum TestCard { } impl TestCard { - pub fn open(&self) -> Result { + pub fn open(&self) -> Result> { match self { Self::Pcsc(ident) => { // Attempt to shutdown SCD, if it is running. @@ -97,11 +99,11 @@ impl TestCard { let res = ScdClient::shutdown_scd(None); log::trace!(" Attempt to shutdown scd: {:?}", res); - Ok(PcscClient::open_by_ident(ident)?) + Ok(Box::new(PcscClient::open_by_ident(ident)?)) } Self::Scdc(serial) => { // println!("open scdc card {}", serial); - Ok(ScdClient::open_by_serial(None, serial)?) + Ok(Box::new(ScdClient::open_by_serial(None, serial)?)) } } } diff --git a/card-functionality/src/tests.rs b/card-functionality/src/tests.rs index c927a75..9e5ee12 100644 --- a/card-functionality/src/tests.rs +++ b/card-functionality/src/tests.rs @@ -15,7 +15,7 @@ use sequoia_openpgp::Cert; use openpgp_card; use openpgp_card::algorithm::AlgoSimple; use openpgp_card::card_do::{KeyGenerationTime, Sex}; -use openpgp_card::{CardApp, Error, KeyType, StatusBytes}; +use openpgp_card::{CardApp, CardClient, Error, KeyType, StatusBytes}; use openpgp_card_sequoia::card::Open; use openpgp_card_sequoia::util::{ make_cert, public_key_material_to_key, public_to_fingerprint, @@ -53,7 +53,7 @@ pub enum TestError { /// Run after each "upload keys", if key *was* uploaded (?) pub fn test_decrypt( - mut ca: &mut CardApp, + card_client: &mut (dyn CardClient + Send + Sync), param: &[&str], ) -> Result { assert_eq!( @@ -65,12 +65,12 @@ pub fn test_decrypt( let cert = Cert::from_str(param[0])?; let msg = param[1].to_string(); - ca.verify_pw1("123456")?; + CardApp::verify_pw1(card_client, "123456")?; let p = StandardPolicy::new(); let res = openpgp_card_sequoia::util::decrypt( - &mut ca, + card_client, &cert, msg.into_bytes(), &p, @@ -84,18 +84,21 @@ pub fn test_decrypt( /// Run after each "upload keys", if key *was* uploaded (?) pub fn test_sign( - mut ca: &mut CardApp, + card_client: &mut (dyn CardClient + Send + Sync), param: &[&str], ) -> Result { assert_eq!(param.len(), 1, "test_sign needs a filename for 'cert'"); - ca.verify_pw1_for_signing("123456")?; + CardApp::verify_pw1_for_signing(card_client, "123456")?; let cert = Cert::from_str(param[0])?; let msg = "Hello world, I am signed."; - let sig = - openpgp_card_sequoia::util::sign(&mut ca, &cert, &mut msg.as_bytes())?; + let sig = openpgp_card_sequoia::util::sign( + card_client, + &cert, + &mut msg.as_bytes(), + )?; // validate sig assert!(util::verify_sig(&cert, msg.as_bytes(), sig.as_bytes())?); @@ -104,10 +107,10 @@ pub fn test_sign( } fn check_key_upload_metadata( - ca: &mut CardApp, + card_client: &mut (dyn CardClient + Send + Sync), meta: &[(String, KeyGenerationTime)], ) -> Result<()> { - let ard = ca.application_related_data()?; + let ard = CardApp::application_related_data(card_client)?; // check fingerprints let card_fp = ard.fingerprints()?; @@ -148,10 +151,10 @@ fn check_key_upload_algo_attrs() -> Result<()> { } pub fn test_print_caps( - ca: &mut CardApp, + card_client: &mut (dyn CardClient + Send + Sync), _param: &[&str], ) -> Result { - let ard = ca.application_related_data()?; + let ard = CardApp::application_related_data(card_client)?; let aid = ard.application_id()?; println!("aid: {:#x?}", aid); @@ -169,17 +172,17 @@ pub fn test_print_caps( } pub fn test_print_algo_info( - ca: &mut CardApp, + card_client: &mut (dyn CardClient + Send + Sync), _param: &[&str], ) -> Result { - let ard = ca.application_related_data()?; + let ard = CardApp::application_related_data(card_client)?; let dec = ard.algorithm_attributes(KeyType::Decryption)?; println!("Current algorithm for the decrypt slot: {}", dec); println!(); - let algo = ca.algorithm_information(); + let algo = CardApp::algorithm_information(card_client); if let Ok(Some(algo)) = algo { println!("Card algorithm list:\n{}", algo); } @@ -188,7 +191,7 @@ pub fn test_print_algo_info( } pub fn test_upload_keys( - ca: &mut CardApp, + card_client: &mut (dyn CardClient + Send + Sync), param: &[&str], ) -> Result { assert_eq!( @@ -197,16 +200,16 @@ pub fn test_upload_keys( "test_upload_keys needs a filename for 'cert'" ); - ca.verify_pw3("12345678")?; + CardApp::verify_pw3(card_client, "12345678")?; let cert = Cert::from_file(param[0])?; let p = StandardPolicy::new(); - let meta = util::upload_subkeys(ca, &cert, &p) + let meta = util::upload_subkeys(card_client, &cert, &p) .map_err(|e| TestError::KeyUploadError(param[0].to_string(), e))?; - check_key_upload_metadata(ca, &meta)?; + check_key_upload_metadata(card_client, &meta)?; // FIXME: implement check_key_upload_algo_attrs()?; @@ -216,10 +219,10 @@ pub fn test_upload_keys( /// Generate keys for each of the three KeyTypes pub fn test_keygen( - mut ca: &mut CardApp, + card_client: &mut (dyn CardClient + Send + Sync), param: &[&str], ) -> Result { - ca.verify_pw3("12345678")?; + CardApp::verify_pw3(card_client, "12345678")?; // Generate all three subkeys on card let algo = param[0]; @@ -227,12 +230,17 @@ pub fn test_keygen( let alg = AlgoSimple::try_from(algo)?; println!(" Generate subkey for Signing"); - let (pkm, ts) = - ca.generate_key_simple(public_to_fingerprint, KeyType::Signing, alg)?; + let (pkm, ts) = CardApp::generate_key_simple( + card_client, + public_to_fingerprint, + KeyType::Signing, + alg, + )?; let key_sig = public_key_material_to_key(&pkm, KeyType::Signing, ts)?; println!(" Generate subkey for Decryption"); - let (pkm, ts) = ca.generate_key_simple( + let (pkm, ts) = CardApp::generate_key_simple( + card_client, public_to_fingerprint, KeyType::Decryption, alg, @@ -240,7 +248,8 @@ pub fn test_keygen( let key_dec = public_key_material_to_key(&pkm, KeyType::Decryption, ts)?; println!(" Generate subkey for Authentication"); - let (pkm, ts) = ca.generate_key_simple( + let (pkm, ts) = CardApp::generate_key_simple( + card_client, public_to_fingerprint, KeyType::Authentication, alg, @@ -249,7 +258,7 @@ pub fn test_keygen( public_key_material_to_key(&pkm, KeyType::Authentication, ts)?; // Generate a Cert for this set of generated keys - let mut open = Open::new(&mut ca)?; + let mut open = Open::new(card_client)?; let cert = make_cert( &mut open, key_sig, @@ -267,15 +276,15 @@ pub fn test_keygen( /// Construct public key based on data from the card pub fn test_get_pub( - ca: &mut CardApp, + card_client: &mut (dyn CardClient + Send + Sync), _param: &[&str], ) -> Result { - let ard = ca.application_related_data()?; + let ard = CardApp::application_related_data(card_client)?; let key_gen = ard.key_generation_times()?; // -- - let sig = ca.public_key(KeyType::Signing)?; + let sig = CardApp::public_key(card_client, KeyType::Signing)?; let ts = key_gen.signature().unwrap().get().into(); let key = public_key_material_to_key(&sig, KeyType::Signing, ts)?; @@ -283,7 +292,7 @@ pub fn test_get_pub( // -- - let dec = ca.public_key(KeyType::Decryption)?; + let dec = CardApp::public_key(card_client, KeyType::Decryption)?; let ts = key_gen.decryption().unwrap().get().into(); let key = public_key_material_to_key(&dec, KeyType::Decryption, ts)?; @@ -291,7 +300,7 @@ pub fn test_get_pub( // -- - let auth = ca.public_key(KeyType::Authentication)?; + let auth = CardApp::public_key(card_client, KeyType::Authentication)?; let ts = key_gen.authentication().unwrap().get().into(); let key = public_key_material_to_key(&auth, KeyType::Authentication, ts)?; @@ -306,10 +315,10 @@ pub fn test_get_pub( } pub fn test_reset( - ca: &mut CardApp, + card_client: &mut (dyn CardClient + Send + Sync), _param: &[&str], ) -> Result { - let _res = ca.factory_reset()?; + let _res = CardApp::factory_reset(card_client)?; Ok(vec![]) } @@ -319,25 +328,25 @@ pub fn test_reset( /// Returns an empty TestOutput, throws errors for unexpected Status codes /// and for unequal field values. pub fn test_set_user_data( - ca: &mut CardApp, + card_client: &mut (dyn CardClient + Send + Sync), _param: &[&str], ) -> Result { - ca.verify_pw3("12345678")?; + CardApp::verify_pw3(card_client, "12345678")?; // name - ca.set_name("Bar< Result { let out = vec![]; println!(); - let d = ca.private_use_do(1)?; + let d = CardApp::private_use_do(card_client, 1)?; println!("data 1 {:?}", d); - ca.verify_pw1("123456")?; + CardApp::verify_pw1(card_client, "123456")?; - ca.set_private_use_do(1, "Foo bar1!".as_bytes().to_vec())?; - ca.set_private_use_do(3, "Foo bar3!".as_bytes().to_vec())?; + CardApp::set_private_use_do( + card_client, + 1, + "Foo bar1!".as_bytes().to_vec(), + )?; + CardApp::set_private_use_do( + card_client, + 3, + "Foo bar3!".as_bytes().to_vec(), + )?; - ca.verify_pw3("12345678")?; + CardApp::verify_pw3(card_client, "12345678")?; - ca.set_private_use_do(2, "Foo bar2!".as_bytes().to_vec())?; - ca.set_private_use_do(4, "Foo bar4!".as_bytes().to_vec())?; + CardApp::set_private_use_do( + card_client, + 2, + "Foo bar2!".as_bytes().to_vec(), + )?; + CardApp::set_private_use_do( + card_client, + 4, + "Foo bar4!".as_bytes().to_vec(), + )?; - let d = ca.private_use_do(1)?; + let d = CardApp::private_use_do(card_client, 1)?; println!("data 1 {:?}", d); - let d = ca.private_use_do(2)?; + let d = CardApp::private_use_do(card_client, 2)?; println!("data 2 {:?}", d); - let d = ca.private_use_do(3)?; + let d = CardApp::private_use_do(card_client, 3)?; println!("data 3 {:?}", d); - let d = ca.private_use_do(4)?; + let d = CardApp::private_use_do(card_client, 4)?; println!("data 4 {:?}", d); Ok(out) } pub fn test_cardholder_cert( - ca: &mut CardApp, + card_client: &mut (dyn CardClient + Send + Sync), _param: &[&str], ) -> Result { let mut out = vec![]; println!(); - match ca.cardholder_certificate() { + match CardApp::cardholder_certificate(card_client) { Ok(res) => { out.push(TestResult::Text(format!("got cert {:x?}", res.data()))) } @@ -406,11 +431,11 @@ pub fn test_cardholder_cert( } }; - ca.verify_pw3("12345678")?; + CardApp::verify_pw3(card_client, "12345678")?; let data = "Foo bar baz!".as_bytes(); - match ca.set_cardholder_certificate(data.to_vec()) { + match CardApp::set_cardholder_certificate(card_client, data.to_vec()) { Ok(_resp) => out.push(TestResult::Text("set cert ok".to_string())), Err(e) => { out.push(TestResult::Text(format!( @@ -421,7 +446,7 @@ pub fn test_cardholder_cert( } } - let res = ca.cardholder_certificate()?; + let res = CardApp::cardholder_certificate(card_client)?; out.push(TestResult::Text("get cert ok".to_string())); if res.data() != data { @@ -434,7 +459,7 @@ pub fn test_cardholder_cert( // try using slot 2 - match ca.select_data(2, &[0x7F, 0x21]) { + match CardApp::select_data(card_client, 2, &[0x7F, 0x21]) { Ok(_res) => out.push(TestResult::Text("select_data ok".to_string())), Err(e) => { out.push(TestResult::Text(format!("select_data: {:?}", e))); @@ -446,24 +471,24 @@ pub fn test_cardholder_cert( } pub fn test_pw_status( - ca: &mut CardApp, + card_client: &mut (dyn CardClient + Send + Sync), _param: &[&str], ) -> Result { let out = vec![]; - let ard = ca.application_related_data()?; + let ard = CardApp::application_related_data(card_client)?; let mut pws = ard.pw_status_bytes()?; println!("pws {:?}", pws); - ca.verify_pw3("12345678")?; + CardApp::verify_pw3(card_client, "12345678")?; pws.set_pw1_cds_valid_once(false); pws.set_pw1_pin_block(true); - ca.set_pw_status_bytes(&pws, false)?; + CardApp::set_pw_status_bytes(card_client, &pws, false)?; - let ard = ca.application_related_data()?; + let ard = CardApp::application_related_data(card_client)?; let pws = ard.pw_status_bytes()?; println!("pws {:?}", pws); @@ -474,7 +499,7 @@ pub fn test_pw_status( /// - verify pw3 (check) -> Status /// - verify pw1 (check) -> Status pub fn test_verify( - ca: &mut CardApp, + card_client: &mut (dyn CardClient + Send + Sync), _param: &[&str], ) -> Result { // Steps: @@ -492,7 +517,7 @@ pub fn test_verify( let mut out = vec![]; // try to set name without verify, assert result is not ok! - let res = ca.set_name("Notverified< { // e.g. yubikey5 returns an error status! out.push(TestResult::Status(s)); @@ -513,14 +538,14 @@ pub fn test_verify( Ok(_) => out.push(TestResult::StatusOk), } - ca.set_name("Admin< { // e.g. yubikey5 returns an error status! out.push(TestResult::Status(s)); @@ -531,16 +556,16 @@ pub fn test_verify( Ok(_) => out.push(TestResult::StatusOk), } - ca.set_name("There< Result { let out = vec![]; @@ -548,20 +573,20 @@ pub fn test_change_pw( // first do admin-less pw1 on gnuk // (NOTE: Gnuk requires a key to be loaded before allowing pw changes!) println!("change pw1"); - ca.change_pw1("123456", "abcdef00")?; + CardApp::change_pw1(card_client, "123456", "abcdef00")?; // also set admin pw, which means pw1 is now only user-pw again, on gnuk println!("change pw3"); // ca.change_pw3("abcdef00", "abcdefgh")?; // gnuk - ca.change_pw3("12345678", "abcdefgh")?; + CardApp::change_pw3(card_client, "12345678", "abcdefgh")?; println!("change pw1"); - ca.change_pw1("abcdef00", "abcdef")?; // gnuk + CardApp::change_pw1(card_client, "abcdef00", "abcdef")?; // gnuk // ca.change_pw1("123456", "abcdef")?; println!("verify bad pw1"); - match ca.verify_pw1("123456ab") { + match CardApp::verify_pw1(card_client, "123456ab") { Err(Error::CardStatus(StatusBytes::SecurityStatusNotSatisfied)) => { // this is expected } @@ -572,10 +597,10 @@ pub fn test_change_pw( } println!("verify good pw1"); - ca.verify_pw1("abcdef")?; + CardApp::verify_pw1(card_client, "abcdef")?; println!("verify bad pw3"); - match ca.verify_pw3("00000000") { + match CardApp::verify_pw3(card_client, "00000000") { Err(Error::CardStatus(StatusBytes::SecurityStatusNotSatisfied)) => { // this is expected } @@ -586,34 +611,34 @@ pub fn test_change_pw( } println!("verify good pw3"); - ca.verify_pw3("abcdefgh")?; + CardApp::verify_pw3(card_client, "abcdefgh")?; println!("change pw3 back to default"); - ca.change_pw3("abcdefgh", "12345678")?; + CardApp::change_pw3(card_client, "abcdefgh", "12345678")?; println!("change pw1 back to default"); - ca.change_pw1("abcdef", "123456")?; + CardApp::change_pw1(card_client, "abcdef", "123456")?; Ok(out) } pub fn test_reset_retry_counter( - ca: &mut CardApp, + card_client: &mut (dyn CardClient + Send + Sync), _param: &[&str], ) -> Result { let out = vec![]; // set pw3, then pw1 (to bring gnuk into non-admin mode) println!("set pw3"); - ca.change_pw3("12345678", "12345678")?; + CardApp::change_pw3(card_client, "12345678", "12345678")?; println!("set pw1"); - ca.change_pw1("123456", "123456")?; + CardApp::change_pw1(card_client, "123456", "123456")?; println!("break pw1"); - let _ = ca.verify_pw1("wrong0"); - let _ = ca.verify_pw1("wrong0"); - let _ = ca.verify_pw1("wrong0"); - let res = ca.verify_pw1("wrong0"); + let _ = CardApp::verify_pw1(card_client, "wrong0"); + let _ = CardApp::verify_pw1(card_client, "wrong0"); + let _ = CardApp::verify_pw1(card_client, "wrong0"); + let res = CardApp::verify_pw1(card_client, "wrong0"); match res { Err(Error::CardStatus(StatusBytes::AuthenticationMethodBlocked)) => { @@ -634,23 +659,24 @@ pub fn test_reset_retry_counter( } println!("verify pw3"); - ca.verify_pw3("12345678")?; + CardApp::verify_pw3(card_client, "12345678")?; println!("set resetting code"); - ca.set_resetting_code("abcdefgh".as_bytes().to_vec())?; + CardApp::set_resetting_code(card_client, "abcdefgh".as_bytes().to_vec())?; println!("reset retry counter"); // ca.reset_retry_counter_pw1("abcdef".as_bytes().to_vec(), None)?; - let _res = ca.reset_retry_counter_pw1( + let _res = CardApp::reset_retry_counter_pw1( + card_client, "abcdef".as_bytes().to_vec(), Some("abcdefgh".as_bytes().to_vec()), ); println!("verify good pw1"); - ca.verify_pw1("abcdef")?; + CardApp::verify_pw1(card_client, "abcdef")?; println!("verify bad pw1"); - match ca.verify_pw1("00000000") { + match CardApp::verify_pw1(card_client, "00000000") { Err(Error::CardStatus(StatusBytes::SecurityStatusNotSatisfied)) => { // this is expected } @@ -665,12 +691,15 @@ pub fn test_reset_retry_counter( pub fn run_test( card: &mut TestCardApp, - t: fn(&mut CardApp, &[&str]) -> Result, + t: fn( + &mut (dyn CardClient + Send + Sync), + &[&str], + ) -> Result, param: &[&str], ) -> Result { - let mut ca = card.get_card_app()?; - let ard = ca.application_related_data()?; + let mut card_client = card.get_card_client()?; + let ard = CardApp::application_related_data(&mut *card_client)?; let _app_id = ard.application_id()?; - t(&mut ca, param) + t(&mut *card_client, param) } diff --git a/card-functionality/src/util.rs b/card-functionality/src/util.rs index 4c1b2ac..0049910 100644 --- a/card-functionality/src/util.rs +++ b/card-functionality/src/util.rs @@ -17,14 +17,14 @@ use sequoia_openpgp::serialize::stream::{ use sequoia_openpgp::Cert; use openpgp_card::card_do::KeyGenerationTime; -use openpgp_card::{CardApp, KeyType}; +use openpgp_card::{CardApp, CardClient, KeyType}; use openpgp_card_sequoia::sq_util; use openpgp_card_sequoia::util::vka_as_uploadable_key; pub const SP: &StandardPolicy = &StandardPolicy::new(); pub(crate) fn upload_subkeys( - ca: &mut CardApp, + card_client: &mut dyn CardClient, cert: &Cert, policy: &dyn Policy, ) -> Result> { @@ -49,7 +49,7 @@ pub(crate) fn upload_subkeys( // upload key let cuk = vka_as_uploadable_key(vka, None); - ca.key_import(cuk, *kt)?; + CardApp::key_import(card_client, cuk, *kt)?; } } diff --git a/openpgp-card-sequoia/src/card.rs b/openpgp-card-sequoia/src/card.rs index adda8f4..cb11936 100644 --- a/openpgp-card-sequoia/src/card.rs +++ b/openpgp-card-sequoia/src/card.rs @@ -16,7 +16,7 @@ use openpgp_card::card_do::{ ExtendedCapabilities, ExtendedLengthInfo, Fingerprint, HistoricalBytes, KeyGenerationTime, PWStatusBytes, SecuritySupportTemplate, Sex, }; -use openpgp_card::{CardApp, Error, KeySet, KeyType, Response}; +use openpgp_card::{CardApp, CardClient, Error, KeySet, KeyType, Response}; use crate::decryptor::CardDecryptor; use crate::signer::CardSigner; @@ -27,7 +27,7 @@ use openpgp_card::crypto_data::PublicKeyMaterial; /// Representation of an opened OpenPGP card in its base state (i.e. no /// passwords have been verified, default authorization applies). pub struct Open<'a> { - card_app: &'a mut CardApp, + card_client: &'a mut (dyn CardClient + Send + Sync), // Cache of "application related data". // @@ -46,27 +46,29 @@ pub struct Open<'a> { } impl<'a> Open<'a> { - pub fn new(card_app: &'a mut CardApp) -> Result { - let ard = card_app.application_related_data()?; + pub fn new( + card_client: &'a mut (dyn CardClient + Send + Sync), + ) -> Result { + let ard = CardApp::application_related_data(card_client)?; Ok(Self { - card_app, + card_client, ard, pw1: false, pw1_sign: false, pw3: false, }) } - pub fn feature_pinpad_verify(&self) -> bool { - self.card_app.feature_pinpad_verify() + pub fn feature_pinpad_verify(&mut self) -> bool { + CardApp::feature_pinpad_verify(self.card_client) } - pub fn feature_pinpad_modify(&self) -> bool { - self.card_app.feature_pinpad_modify() + pub fn feature_pinpad_modify(&mut self) -> bool { + CardApp::feature_pinpad_modify(self.card_client) } pub fn verify_user(&mut self, pin: &str) -> Result<(), Error> { - let _ = self.card_app.verify_pw1(pin)?; + let _ = CardApp::verify_pw1(self.card_client, pin)?; self.pw1 = true; Ok(()) } @@ -77,13 +79,13 @@ impl<'a> Open<'a> { ) -> Result<(), Error> { prompt(); - let _ = self.card_app.verify_pw1_pinpad()?; + let _ = CardApp::verify_pw1_pinpad(self.card_client)?; self.pw1 = true; Ok(()) } pub fn verify_user_for_signing(&mut self, pin: &str) -> Result<(), Error> { - let _ = self.card_app.verify_pw1_for_signing(pin)?; + let _ = CardApp::verify_pw1_for_signing(self.card_client, pin)?; // FIXME: depending on card mode, pw1_sign is only usable once @@ -97,7 +99,7 @@ impl<'a> Open<'a> { ) -> Result<(), Error> { prompt(); - let _ = self.card_app.verify_pw1_for_signing_pinpad()?; + let _ = CardApp::verify_pw1_for_signing_pinpad(self.card_client)?; // FIXME: depending on card mode, pw1_sign is only usable once @@ -106,7 +108,7 @@ impl<'a> Open<'a> { } pub fn verify_admin(&mut self, pin: &str) -> Result<(), Error> { - let _ = self.card_app.verify_pw3(pin)?; + let _ = CardApp::verify_pw3(self.card_client, pin)?; self.pw3 = true; Ok(()) } @@ -117,7 +119,7 @@ impl<'a> Open<'a> { ) -> Result<(), Error> { prompt(); - let _ = self.card_app.verify_pw3_pinpad()?; + let _ = CardApp::verify_pw3_pinpad(self.card_client)?; self.pw3 = true; Ok(()) } @@ -126,14 +128,14 @@ impl<'a> Open<'a> { /// /// NOTE: on some cards this functionality seems broken. pub fn check_user_verified(&mut self) -> Result { - self.card_app.check_pw1() + CardApp::check_pw1(self.card_client) } /// Ask the card if the admin password has been successfully verified. /// /// NOTE: on some cards this functionality seems broken. pub fn check_admin_verified(&mut self) -> Result { - self.card_app.check_pw3() + CardApp::check_pw3(self.card_client) } pub fn change_user_pin( @@ -141,7 +143,7 @@ impl<'a> Open<'a> { old: &str, new: &str, ) -> Result { - self.card_app.change_pw1(old, new) + CardApp::change_pw1(self.card_client, old, new) } pub fn change_user_pin_pinpad( @@ -149,7 +151,7 @@ impl<'a> Open<'a> { prompt: &dyn Fn(), ) -> Result { prompt(); - self.card_app.change_pw1_pinpad() + CardApp::change_pw1_pinpad(self.card_client) } pub fn reset_user_pin( @@ -157,8 +159,11 @@ impl<'a> Open<'a> { rst: &str, new: &str, ) -> Result { - self.card_app - .reset_retry_counter_pw1(new.into(), Some(rst.into())) + CardApp::reset_retry_counter_pw1( + self.card_client, + new.into(), + Some(rst.into()), + ) } pub fn change_admin_pin( @@ -166,7 +171,7 @@ impl<'a> Open<'a> { old: &str, new: &str, ) -> Result { - self.card_app.change_pw3(old, new) + CardApp::change_pw3(self.card_client, old, new) } pub fn change_admin_pin_pinpad( @@ -174,7 +179,7 @@ impl<'a> Open<'a> { prompt: &dyn Fn(), ) -> Result { prompt(); - self.card_app.change_pw3_pinpad() + CardApp::change_pw3_pinpad(self.card_client) } /// Get a view of the card authenticated for "User" commands. @@ -294,21 +299,21 @@ impl<'a> Open<'a> { // --- URL (5f50) --- pub fn url(&mut self) -> Result { - self.card_app.url() + CardApp::url(self.card_client) } // --- cardholder related data (65) --- pub fn cardholder_related_data( &mut self, ) -> Result { - self.card_app.cardholder_related_data() + CardApp::cardholder_related_data(self.card_client) } // --- security support template (7a) --- pub fn security_support_template( &mut self, ) -> Result { - self.card_app.security_support_template() + CardApp::security_support_template(self.card_client) } // DO "Algorithm Information" (0xFA) @@ -322,12 +327,12 @@ impl<'a> Open<'a> { return Ok(None); } - self.card_app.algorithm_information() + CardApp::algorithm_information(self.card_client) } /// Firmware Version, YubiKey specific (?) pub fn firmware_version(&mut self) -> Result> { - self.card_app.firmware_version() + CardApp::firmware_version(self.card_client) } // ---------- @@ -336,14 +341,14 @@ impl<'a> Open<'a> { &mut self, key_type: KeyType, ) -> Result { - self.card_app.public_key(key_type).map_err(|e| e.into()) + CardApp::public_key(self.card_client, key_type).map_err(|e| e.into()) } // ---------- /// Delete all state on this OpenPGP card pub fn factory_reset(&mut self) -> Result<()> { - self.card_app.factory_reset() + CardApp::factory_reset(self.card_client) } } @@ -355,7 +360,7 @@ pub struct User<'app, 'open> { impl User<'_, '_> { pub fn decryptor(&mut self, cert: &Cert) -> Result { - CardDecryptor::new(&mut self.oc.card_app, cert) + CardDecryptor::new(self.oc.card_client, cert) } } @@ -373,14 +378,14 @@ impl Sign<'_, '_> { // FIXME: depending on the setting in "PW1 Status byte", only one // signature can be made after verification for signing - CardSigner::new(&mut self.oc.card_app, cert) + CardSigner::new(self.oc.card_client, cert) } pub fn signer_from_pubkey(&mut self, pubkey: PublicKey) -> CardSigner { // FIXME: depending on the setting in "PW1 Status byte", only one // signature can be made after verification for signing - CardSigner::with_pubkey(&mut self.oc.card_app, pubkey) + CardSigner::with_pubkey(self.oc.card_client, pubkey) } } @@ -406,7 +411,7 @@ impl Admin<'_, '_> { return Err(anyhow!("Invalid char in name").into()); }; - self.oc.card_app.set_name(name) + CardApp::set_name(self.oc.card_client, name) } pub fn set_lang(&mut self, lang: &str) -> Result { @@ -414,11 +419,11 @@ impl Admin<'_, '_> { return Err(anyhow!("lang too long").into()); } - self.oc.card_app.set_lang(lang) + CardApp::set_lang(self.oc.card_client, lang) } pub fn set_sex(&mut self, sex: Sex) -> Result { - self.oc.card_app.set_sex(sex) + CardApp::set_sex(self.oc.card_client, sex) } pub fn set_url(&mut self, url: &str) -> Result { @@ -436,7 +441,7 @@ impl Admin<'_, '_> { // or if it's within the acceptable length: // send the url update to the card. - self.oc.card_app.set_url(url) + CardApp::set_url(self.oc.card_client, url) } else { Err(anyhow!("URL too long").into()) } @@ -446,11 +451,11 @@ impl Admin<'_, '_> { &mut self, pin: &str, ) -> Result { - self.oc.card_app.set_resetting_code(pin.into()) + CardApp::set_resetting_code(self.oc.card_client, pin.into()) } pub fn reset_user_pin(&mut self, new: &str) -> Result { - self.oc.card_app.reset_retry_counter_pw1(new.into(), None) + CardApp::reset_retry_counter_pw1(self.oc.card_client, new.into(), None) } /// Upload a ValidErasedKeyAmalgamation to the card as a specific KeyType. @@ -463,7 +468,7 @@ impl Admin<'_, '_> { password: Option, ) -> Result<(), Error> { let key = vka_as_uploadable_key(vka, password); - self.oc.card_app.key_import(key, key_type) + CardApp::key_import(self.oc.card_client, key, key_type) } pub fn generate_key_simple( @@ -472,12 +477,14 @@ impl Admin<'_, '_> { algo: Option, ) -> Result<(PublicKeyMaterial, KeyGenerationTime), Error> { match algo { - Some(algo) => self.oc.card_app.generate_key_simple( + Some(algo) => CardApp::generate_key_simple( + self.oc.card_client, public_to_fingerprint, key_type, algo, ), - None => self.oc.card_app.generate_key( + None => CardApp::generate_key( + self.oc.card_client, public_to_fingerprint, key_type, None, diff --git a/openpgp-card-sequoia/src/decryptor.rs b/openpgp-card-sequoia/src/decryptor.rs index 6a4f872..1ebcdbf 100644 --- a/openpgp-card-sequoia/src/decryptor.rs +++ b/openpgp-card-sequoia/src/decryptor.rs @@ -15,14 +15,14 @@ use openpgp::Cert; use sequoia_openpgp as openpgp; use openpgp_card::crypto_data::Cryptogram; -use openpgp_card::{CardApp, Error}; +use openpgp_card::{CardApp, CardClient, Error}; use crate::sq_util; use crate::PublicKey; pub struct CardDecryptor<'a> { /// The OpenPGP card (authenticated to allow decryption operations) - ca: &'a mut CardApp, + card_client: &'a mut dyn CardClient, /// The matching public key for the card's decryption key public: PublicKey, @@ -34,11 +34,11 @@ impl<'a> CardDecryptor<'a> { /// An Error is returned if no match between the card's decryption /// key and a (sub)key of `cert` can be made. pub fn new( - ca: &'a mut CardApp, + card_client: &'a mut dyn CardClient, cert: &Cert, ) -> Result, Error> { // Get the fingerprint for the decryption key from the card. - let ard = ca.application_related_data()?; + let ard = CardApp::application_related_data(card_client)?; let fps = ard.fingerprints()?; let fp = fps.decryption(); @@ -48,7 +48,10 @@ impl<'a> CardDecryptor<'a> { if let Some(eka) = sq_util::get_subkey_by_fingerprint(cert, &fp)? { let public = eka.key().clone(); - Ok(Self { ca, public }) + Ok(Self { + card_client, + public, + }) } else { Err(Error::InternalError(anyhow!( "Failed to find (sub)key {} in cert", @@ -82,7 +85,7 @@ impl<'a> crypto::Decryptor for CardDecryptor<'a> { match (ciphertext, self.public.mpis()) { (mpi::Ciphertext::RSA { c: ct }, mpi::PublicKey::RSA { .. }) => { let dm = Cryptogram::RSA(ct.value()); - let dec = self.ca.decipher(dm)?; + let dec = CardApp::decipher(self.card_client, dm)?; let sk = openpgp::crypto::SessionKey::from(&dec[..]); Ok(sk) @@ -106,7 +109,7 @@ impl<'a> crypto::Decryptor for CardDecryptor<'a> { }; // Decryption operation on the card - let mut dec = self.ca.decipher(dm)?; + let mut dec = CardApp::decipher(self.card_client, dm)?; // Specifically handle return value format like Gnuk's // (Gnuk returns a leading '0x04' byte and diff --git a/openpgp-card-sequoia/src/signer.rs b/openpgp-card-sequoia/src/signer.rs index bfda776..69c627f 100644 --- a/openpgp-card-sequoia/src/signer.rs +++ b/openpgp-card-sequoia/src/signer.rs @@ -11,14 +11,14 @@ use openpgp::types::{Curve, PublicKeyAlgorithm}; use sequoia_openpgp as openpgp; use openpgp_card::crypto_data::Hash; -use openpgp_card::{CardApp, Error}; +use openpgp_card::{CardApp, CardClient, Error}; use crate::sq_util; use crate::PublicKey; pub struct CardSigner<'a> { /// The OpenPGP card (authenticated to allow signing operations) - ca: &'a mut CardApp, + card_client: &'a mut (dyn CardClient + Send + Sync), /// The matching public key for the card's signing key public: PublicKey, @@ -30,11 +30,11 @@ impl<'a> CardSigner<'a> { /// An Error is returned if no match between the card's signing /// key and a (sub)key of `cert` can be made. pub fn new( - ca: &'a mut CardApp, + card_client: &'a mut (dyn CardClient + Send + Sync), cert: &openpgp::Cert, ) -> Result, Error> { // Get the fingerprint for the signing key from the card. - let ard = ca.application_related_data()?; + let ard = CardApp::application_related_data(card_client)?; let fps = ard.fingerprints()?; let fp = fps.signature(); @@ -44,7 +44,7 @@ impl<'a> CardSigner<'a> { if let Some(eka) = sq_util::get_subkey_by_fingerprint(cert, &fp)? { let key = eka.key().clone(); - Ok(Self::with_pubkey(ca, key)) + Ok(Self::with_pubkey(card_client, key)) } else { Err(Error::InternalError(anyhow!( "Failed to find (sub)key {} in cert", @@ -59,10 +59,13 @@ impl<'a> CardSigner<'a> { } pub(crate) fn with_pubkey( - ca: &'a mut CardApp, + card_client: &'a mut (dyn CardClient + Send + Sync), public: PublicKey, ) -> CardSigner<'a> { - CardSigner { ca, public } + CardSigner { + card_client, + public, + } } } @@ -114,7 +117,7 @@ impl<'a> crypto::Signer for CardSigner<'a> { } }; - let sig = self.ca.signature_for_hash(hash)?; + let sig = CardApp::signature_for_hash(self.card_client, hash)?; let mpi = mpi::MPI::new(&sig[..]); Ok(mpi::Signature::RSA { s: mpi }) @@ -122,7 +125,7 @@ impl<'a> crypto::Signer for CardSigner<'a> { (PublicKeyAlgorithm::EdDSA, mpi::PublicKey::EdDSA { .. }) => { let hash = Hash::EdDSA(digest); - let sig = self.ca.signature_for_hash(hash)?; + let sig = CardApp::signature_for_hash(self.card_client, hash)?; let r = mpi::MPI::new(&sig[..32]); let s = mpi::MPI::new(&sig[32..]); @@ -140,7 +143,7 @@ impl<'a> crypto::Signer for CardSigner<'a> { _ => Hash::ECDSA(digest), }; - let sig = self.ca.signature_for_hash(hash)?; + let sig = CardApp::signature_for_hash(self.card_client, hash)?; let len_2 = sig.len() / 2; let r = mpi::MPI::new(&sig[..len_2]); diff --git a/openpgp-card-sequoia/src/util.rs b/openpgp-card-sequoia/src/util.rs index e00163d..3623512 100644 --- a/openpgp-card-sequoia/src/util.rs +++ b/openpgp-card-sequoia/src/util.rs @@ -27,7 +27,7 @@ use sequoia_openpgp as openpgp; use openpgp_card::algorithm::{Algo, Curve}; use openpgp_card::card_do::{Fingerprint, KeyGenerationTime}; use openpgp_card::crypto_data::{CardUploadableKey, PublicKeyMaterial}; -use openpgp_card::{CardApp, Error, KeyType}; +use openpgp_card::{CardClient, Error, KeyType}; use crate::card::Open; use crate::privkey::SequoiaKey; @@ -294,13 +294,13 @@ pub fn vka_as_uploadable_key( /// FIXME: this fn is used in card_functionality, but should be removed pub fn sign( - ca: &mut CardApp, + card_client: &mut (dyn CardClient + Send + Sync), cert: &Cert, input: &mut dyn io::Read, ) -> Result { let mut armorer = armor::Writer::new(vec![], armor::Kind::Signature)?; { - let s = signer::CardSigner::new(ca, cert)?; + let s = signer::CardSigner::new(card_client, cert)?; let message = Message::new(&mut armorer); let mut message = Signer::new(message, s).detached().build()?; @@ -318,7 +318,7 @@ pub fn sign( /// FIXME: this fn is used in card_functionality, but should be removed pub fn decrypt( - ca: &mut CardApp, + card_client: &mut dyn CardClient, cert: &Cert, msg: Vec, p: &dyn Policy, @@ -327,7 +327,7 @@ pub fn decrypt( { let reader = io::BufReader::new(&msg[..]); - let d = decryptor::CardDecryptor::new(ca, cert)?; + let d = decryptor::CardDecryptor::new(card_client, cert)?; let db = DecryptorBuilder::from_reader(reader)?; let mut decryptor = db.with_policy(p, None, d)?; diff --git a/openpgp-card/src/card_app.rs b/openpgp-card/src/card_app.rs index a71b734..d7eba3a 100644 --- a/openpgp-card/src/card_app.rs +++ b/openpgp-card/src/card_app.rs @@ -19,9 +19,7 @@ use crate::crypto_data::{ CardUploadableKey, Cryptogram, Hash, PublicKeyMaterial, }; use crate::tlv::{tag::Tag, value::Value, Tlv}; -use crate::{ - apdu, keys, CardCaps, CardClient, CardClientBox, KeyType, SmartcardError, -}; +use crate::{apdu, keys, CardCaps, CardClient, KeyType, SmartcardError}; use crate::{Error, StatusBytes}; /// Low-level access to OpenPGP card functionality. @@ -31,9 +29,7 @@ use crate::{Error, StatusBytes}; /// /// Also, no caching of data is done here. If necessary, caching should /// be done on a higher layer. -pub struct CardApp { - card_client: CardClientBox, -} +pub struct CardApp {} impl CardApp { /// Get a CardApp based on a CardClient. @@ -44,25 +40,21 @@ impl CardApp { /// This fn initializes the CardCaps by requesting /// application_related_data from the card, and setting the /// capabilities accordingly. - pub fn initialize(card_client: CardClientBox) -> Result { - let mut ca = Self { card_client }; + pub fn initialize(card_client: &mut dyn CardClient) -> Result<()> { + let ard = Self::application_related_data(card_client)?; + Self::init_caps(card_client, &ard)?; - let ard = ca.application_related_data()?; - ca.init_caps(&ard)?; - - Ok(ca) - } - - /// Get the CardClient of this CardApp - pub(crate) fn card_client(&mut self) -> &mut dyn CardClient { - &mut *self.card_client + Ok(()) } /// Initialize the CardCaps settings in the underlying CardClient /// from the data in `ard`. /// /// This should be done at an early point, soon after opening the card. - fn init_caps(&mut self, ard: &ApplicationRelatedData) -> Result<()> { + fn init_caps( + card_client: &mut dyn CardClient, + ard: &ApplicationRelatedData, + ) -> Result<()> { // Determine chaining/extended length support from card // metadata and cache this information in CardApp (as a // CardCaps) @@ -107,7 +99,9 @@ impl CardApp { pw3_max_len: pw3_max, }; - self.card_client.init_card_caps(caps); + log::debug!("init_card_caps to: {:x?}", caps); + + card_client.init_card_caps(caps); Ok(()) } @@ -120,10 +114,10 @@ impl CardApp { /// it are needed regularly, and it does not usually change during /// normal use of a card.) pub fn application_related_data( - &mut self, + card_client: &mut dyn CardClient, ) -> Result { let ad = commands::application_related_data(); - let resp = apdu::send_command(self.card_client(), ad, true)?; + let resp = apdu::send_command(card_client, ad, true)?; let value = Value::from(resp.data()?, true)?; log::debug!(" App data Value: {:x?}", value); @@ -164,19 +158,18 @@ impl CardApp { // --- login data (5e) --- /// Get URL (5f50) - pub fn url(&mut self) -> Result { - let resp = - apdu::send_command(self.card_client(), commands::url(), true)?; + pub fn url(card_client: &mut dyn CardClient) -> Result { + let resp = apdu::send_command(card_client, commands::url(), true)?; Ok(String::from_utf8_lossy(resp.data()?).to_string()) } /// Get cardholder related data (65) pub fn cardholder_related_data( - &mut self, + card_client: &mut dyn CardClient, ) -> Result { let crd = commands::cardholder_related_data(); - let resp = apdu::send_command(self.card_client(), crd, true)?; + let resp = apdu::send_command(card_client, crd, true)?; resp.check_ok()?; CardholderRelatedData::try_from(resp.data()?) @@ -184,10 +177,10 @@ impl CardApp { /// Get security support template (7a) pub fn security_support_template( - &mut self, + card_client: &mut dyn CardClient, ) -> Result { let sst = commands::security_support_template(); - let resp = apdu::send_command(self.card_client(), sst, true)?; + let resp = apdu::send_command(card_client, sst, true)?; resp.check_ok()?; let tlv = Tlv::try_from(resp.data()?)?; @@ -213,18 +206,19 @@ impl CardApp { /// /// Call select_data() before calling this fn, to select a particular /// certificate (if the card supports multiple certificates). - pub fn cardholder_certificate(&mut self) -> Result { + pub fn cardholder_certificate( + card_client: &mut dyn CardClient, + ) -> Result { let cmd = commands::cardholder_certificate(); - apdu::send_command(self.card_client(), cmd, true)?.try_into() + apdu::send_command(card_client, cmd, true)?.try_into() } /// Get "Algorithm Information" - pub fn algorithm_information(&mut self) -> Result> { - let resp = apdu::send_command( - self.card_client(), - commands::algo_info(), - true, - )?; + pub fn algorithm_information( + card_client: &mut dyn CardClient, + ) -> Result> { + let resp = + apdu::send_command(card_client, commands::algo_info(), true)?; resp.check_ok()?; let ai = AlgoInfo::try_from(resp.data()?)?; @@ -232,9 +226,11 @@ impl CardApp { } /// Firmware Version (YubiKey specific (?)) - pub fn firmware_version(&mut self) -> Result> { + pub fn firmware_version( + card_client: &mut dyn CardClient, + ) -> Result> { let resp = apdu::send_command( - self.card_client(), + card_client, commands::firmware_version(), true, )?; @@ -246,12 +242,12 @@ impl CardApp { /// [see: /// /// ] - pub fn set_identity(&mut self, id: u8) -> Result> { - let resp = apdu::send_command( - self.card_client(), - commands::set_identity(id), - false, - ); + pub fn set_identity( + card_client: &mut dyn CardClient, + id: u8, + ) -> Result> { + let resp = + apdu::send_command(card_client, commands::set_identity(id), false); // Apparently it's normal to get "NotTransacted" from pcsclite when // the identity switch was successful. @@ -265,7 +261,7 @@ impl CardApp { /// SELECT DATA ("select a DO in the current template", /// e.g. for cardholder certificate) pub fn select_data( - &mut self, + card_client: &mut dyn CardClient, num: u8, tag: &[u8], ) -> Result { @@ -277,7 +273,7 @@ impl CardApp { let data = tlv.serialize(); let cmd = commands::select_data(num, data); - apdu::send_command(self.card_client(), cmd, true)?.try_into() + apdu::send_command(card_client, cmd, true)?.try_into() } // --- optional private DOs (0101 - 0104) --- @@ -285,11 +281,14 @@ impl CardApp { /// Get data from "private use" DO. /// /// `num` must be between 1 and 4. - pub fn private_use_do(&mut self, num: u8) -> Result> { + pub fn private_use_do( + card_client: &mut dyn CardClient, + num: u8, + ) -> Result> { assert!((1..=4).contains(&num)); let cmd = commands::private_use_do(num); - let resp = apdu::send_command(self.card_client(), cmd, true)?; + let resp = apdu::send_command(card_client, cmd, true)?; Ok(resp.data()?.to_vec()) } @@ -302,14 +301,14 @@ impl CardApp { /// - 1/3 need PW1 (82) /// - 2/4 need PW3 pub fn set_private_use_do( - &mut self, + card_client: &mut dyn CardClient, num: u8, data: Vec, ) -> Result> { assert!((1..=4).contains(&num)); let cmd = commands::put_private_use_do(num, data); - let resp = apdu::send_command(self.card_client(), cmd, true)?; + let resp = apdu::send_command(card_client, cmd, true)?; Ok(resp.data()?.to_vec()) } @@ -331,12 +330,12 @@ impl CardApp { /// (However, e.g. vanilla Gnuk doesn't support this functionality. /// Gnuk needs to be built with the `--enable-factory-reset` /// option to the `configure` script to enable this functionality). - pub fn factory_reset(&mut self) -> Result<()> { + pub fn factory_reset(card_client: &mut dyn CardClient) -> Result<()> { // send 4 bad requests to verify pw1 // [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(self.card_client(), verify, false)?; + let resp = apdu::send_command(card_client, verify, false)?; if !(resp.status() == StatusBytes::SecurityStatusNotSatisfied || resp.status() == StatusBytes::AuthenticationMethodBlocked || matches!(resp.status(), StatusBytes::PasswordNotChecked(_))) @@ -349,7 +348,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(self.card_client(), verify, false)?; + let resp = apdu::send_command(card_client, verify, false)?; if !(resp.status() == StatusBytes::SecurityStatusNotSatisfied || resp.status() == StatusBytes::AuthenticationMethodBlocked @@ -361,12 +360,12 @@ impl CardApp { // terminate_df [apdu 00 e6 00 00] let term = commands::terminate_df(); - let resp = apdu::send_command(self.card_client(), term, false)?; + let resp = apdu::send_command(card_client, term, false)?; resp.check_ok()?; // activate_file [apdu 00 44 00 00] let act = commands::activate_file(); - let resp = apdu::send_command(self.card_client(), act, false)?; + let resp = apdu::send_command(card_client, act, false)?; resp.check_ok()?; Ok(()) @@ -375,13 +374,13 @@ impl CardApp { // --- verify/modify --- /// Does the cardreader support direct pinpad verify? - pub fn feature_pinpad_verify(&self) -> bool { - self.card_client.feature_pinpad_verify() + pub fn feature_pinpad_verify(card_client: &mut dyn CardClient) -> bool { + card_client.feature_pinpad_verify() } /// Does the cardreader support direct pinpad modify? - pub fn feature_pinpad_modify(&self) -> bool { - self.card_client.feature_pinpad_modify() + pub fn feature_pinpad_modify(card_client: &mut dyn CardClient) -> bool { + card_client.feature_pinpad_modify() } /// Verify pw1 (user) for signing operation (mode 81). @@ -390,11 +389,11 @@ impl CardApp { /// access condition is only valid for one PSO:CDS command or remains /// valid for several attempts. pub fn verify_pw1_for_signing( - &mut self, + card_client: &mut dyn CardClient, pin: &str, ) -> Result { let verify = commands::verify_pw1_81(pin.as_bytes().to_vec()); - apdu::send_command(self.card_client(), verify, false)?.try_into() + apdu::send_command(card_client, verify, false)?.try_into() } /// Verify pw1 (user) for signing operation (mode 81) using a @@ -405,9 +404,9 @@ impl CardApp { /// access condition is only valid for one PSO:CDS command or remains /// valid for several attempts. pub fn verify_pw1_for_signing_pinpad( - &mut self, + card_client: &mut dyn CardClient, ) -> Result { - let res = self.card_client.pinpad_verify(0x81)?; + let res = card_client.pinpad_verify(0x81)?; RawResponse::try_from(res)?.try_into() } @@ -417,24 +416,31 @@ impl CardApp { /// /// (Note: some cards don't correctly implement this feature, /// e.g. YubiKey 5) - pub fn check_pw1_for_signing(&mut self) -> Result { + pub fn check_pw1_for_signing( + card_client: &mut dyn CardClient, + ) -> Result { let verify = commands::verify_pw1_81(vec![]); - apdu::send_command(self.card_client(), verify, false)?.try_into() + apdu::send_command(card_client, verify, false)?.try_into() } /// Verify PW1 (user). /// (For operations except signing, mode 82). - pub fn verify_pw1(&mut self, pin: &str) -> Result { + pub fn verify_pw1( + card_client: &mut dyn CardClient, + pin: &str, + ) -> Result { let verify = commands::verify_pw1_82(pin.as_bytes().to_vec()); - apdu::send_command(self.card_client(), verify, false)?.try_into() + apdu::send_command(card_client, verify, false)?.try_into() } /// Verify PW1 (user) for operations except signing (mode 82), /// using a pinpad on the card reader. If no usable pinpad is found, /// an error is returned. - pub fn verify_pw1_pinpad(&mut self) -> Result { - let res = self.card_client.pinpad_verify(0x82)?; + pub fn verify_pw1_pinpad( + card_client: &mut dyn CardClient, + ) -> Result { + let res = card_client.pinpad_verify(0x82)?; RawResponse::try_from(res)?.try_into() } @@ -445,21 +451,28 @@ impl CardApp { /// /// (Note: some cards don't correctly implement this feature, /// e.g. YubiKey 5) - pub fn check_pw1(&mut self) -> Result { + pub fn check_pw1( + card_client: &mut dyn CardClient, + ) -> Result { let verify = commands::verify_pw1_82(vec![]); - apdu::send_command(self.card_client(), verify, false)?.try_into() + apdu::send_command(card_client, verify, false)?.try_into() } /// Verify PW3 (admin). - pub fn verify_pw3(&mut self, pin: &str) -> Result { + pub fn verify_pw3( + card_client: &mut dyn CardClient, + pin: &str, + ) -> Result { let verify = commands::verify_pw3(pin.as_bytes().to_vec()); - apdu::send_command(self.card_client(), verify, false)?.try_into() + apdu::send_command(card_client, verify, false)?.try_into() } /// Verify PW3 (admin) using a pinpad on the card reader. If no usable /// pinpad is found, an error is returned. - pub fn verify_pw3_pinpad(&mut self) -> Result { - let res = self.card_client.pinpad_verify(0x83)?; + pub fn verify_pw3_pinpad( + card_client: &mut dyn CardClient, + ) -> Result { + let res = card_client.pinpad_verify(0x83)?; RawResponse::try_from(res)?.try_into() } @@ -469,16 +482,18 @@ impl CardApp { /// /// (Note: some cards don't correctly implement this feature, /// e.g. YubiKey 5) - pub fn check_pw3(&mut self) -> Result { + pub fn check_pw3( + card_client: &mut dyn CardClient, + ) -> Result { let verify = commands::verify_pw3(vec![]); - apdu::send_command(self.card_client(), verify, false)?.try_into() + apdu::send_command(card_client, verify, false)?.try_into() } /// Change the value of PW1 (user password). /// /// The current value of PW1 must be presented in `old` for authorization. pub fn change_pw1( - &mut self, + card_client: &mut dyn CardClient, old: &str, new: &str, ) -> Result { @@ -487,13 +502,15 @@ impl CardApp { data.extend(new.as_bytes()); let change = commands::change_pw1(data); - apdu::send_command(self.card_client(), change, false)?.try_into() + apdu::send_command(card_client, change, false)?.try_into() } /// Change the value of PW1 (user password) using a pinpad on the /// card reader. If no usable pinpad is found, an error is returned. - pub fn change_pw1_pinpad(&mut self) -> Result { - let res = self.card_client.pinpad_modify(0x81)?; + pub fn change_pw1_pinpad( + card_client: &mut dyn CardClient, + ) -> Result { + let res = card_client.pinpad_modify(0x81)?; RawResponse::try_from(res)?.try_into() } @@ -501,7 +518,7 @@ impl CardApp { /// /// The current value of PW3 must be presented in `old` for authorization. pub fn change_pw3( - &mut self, + card_client: &mut dyn CardClient, old: &str, new: &str, ) -> Result { @@ -510,13 +527,15 @@ impl CardApp { data.extend(new.as_bytes()); let change = commands::change_pw3(data); - apdu::send_command(self.card_client(), change, false)?.try_into() + apdu::send_command(card_client, change, false)?.try_into() } /// Change the value of PW3 (admin password) using a pinpad on the /// card reader. If no usable pinpad is found, an error is returned. - pub fn change_pw3_pinpad(&mut self) -> Result { - let res = self.card_client.pinpad_modify(0x83)?; + pub fn change_pw3_pinpad( + card_client: &mut dyn CardClient, + ) -> Result { + let res = card_client.pinpad_modify(0x83)?; RawResponse::try_from(res)?.try_into() } @@ -528,12 +547,12 @@ impl CardApp { /// - secure messaging must be currently used, /// - the resetting_code must be presented. pub fn reset_retry_counter_pw1( - &mut self, + card_client: &mut dyn CardClient, new_pw1: Vec, resetting_code: Option>, ) -> Result { let reset = commands::reset_retry_counter_pw1(resetting_code, new_pw1); - apdu::send_command(self.card_client(), reset, false)?.try_into() + apdu::send_command(card_client, reset, false)?.try_into() } // --- decrypt --- @@ -542,7 +561,10 @@ impl CardApp { /// /// (This is a wrapper around the low-level pso_decipher /// operation, it builds the required `data` field from `dm`) - pub fn decipher(&mut self, dm: Cryptogram) -> Result, Error> { + pub fn decipher( + card_client: &mut dyn CardClient, + dm: Cryptogram, + ) -> Result, Error> { match dm { Cryptogram::RSA(message) => { // "Padding indicator byte (00) for RSA" (pg. 69) @@ -550,7 +572,7 @@ impl CardApp { data.extend_from_slice(message); // Call the card to decrypt `data` - self.pso_decipher(data) + Self::pso_decipher(card_client, data) } Cryptogram::ECDH(eph) => { // "In case of ECDH the card supports a partial decrypt @@ -568,17 +590,20 @@ impl CardApp { // Cipher DO let cdo = Tlv::new([0xa6], Value::C(vec![pkdo])); - self.pso_decipher(cdo.serialize()) + Self::pso_decipher(card_client, cdo.serialize()) } } } /// Run decryption operation on the smartcard (low level operation) /// (7.2.11 PSO: DECIPHER) - fn pso_decipher(&mut self, data: Vec) -> Result, Error> { + fn pso_decipher( + card_client: &mut dyn CardClient, + data: Vec, + ) -> Result, Error> { // The OpenPGP card is already connected and PW1 82 has been verified let dec_cmd = commands::decryption(data); - let resp = apdu::send_command(self.card_client(), dec_cmd, true)?; + let resp = apdu::send_command(card_client, dec_cmd, true)?; resp.check_ok()?; Ok(resp.data().map(|d| d.to_vec())?) @@ -626,21 +651,24 @@ impl CardApp { /// With ECC the hash data is processed as is, using /// pso_compute_digital_signature. pub fn signature_for_hash( - &mut self, + card_client: &mut dyn CardClient, hash: Hash, ) -> Result, Error> { - self.pso_compute_digital_signature(Self::digestinfo(hash)) + Self::pso_compute_digital_signature( + card_client, + Self::digestinfo(hash), + ) } /// Run signing operation on the smartcard (low level operation) /// (7.2.10 PSO: COMPUTE DIGITAL SIGNATURE) pub fn pso_compute_digital_signature( - &mut self, + card_client: &mut dyn CardClient, data: Vec, ) -> Result, Error> { let cds_cmd = commands::signature(data); - let resp = apdu::send_command(self.card_client(), cds_cmd, true)?; + let resp = apdu::send_command(card_client, cds_cmd, true)?; Ok(resp.data().map(|d| d.to_vec())?) } @@ -658,48 +686,60 @@ impl CardApp { /// /// With ECC the hash data is processed as is. pub fn authenticate_for_hash( - &mut self, + card_client: &mut dyn CardClient, hash: Hash, ) -> Result, Error> { - self.internal_authenticate(Self::digestinfo(hash)) + Self::internal_authenticate(card_client, Self::digestinfo(hash)) } /// Run signing operation on the smartcard (low level operation) /// (7.2.13 INTERNAL AUTHENTICATE) pub fn internal_authenticate( - &mut self, + card_client: &mut dyn CardClient, data: Vec, ) -> Result, Error> { let ia_cmd = commands::internal_authenticate(data); - let resp = apdu::send_command(self.card_client(), ia_cmd, true)?; + let resp = apdu::send_command(card_client, ia_cmd, true)?; Ok(resp.data().map(|d| d.to_vec())?) } // --- admin --- - pub fn set_name(&mut self, name: &str) -> Result { + pub fn set_name( + card_client: &mut dyn CardClient, + name: &str, + ) -> Result { let put_name = commands::put_name(name.as_bytes().to_vec()); - apdu::send_command(self.card_client(), put_name, false)?.try_into() + apdu::send_command(card_client, put_name, false)?.try_into() } - pub fn set_lang(&mut self, lang: &str) -> Result { + pub fn set_lang( + card_client: &mut dyn CardClient, + lang: &str, + ) -> Result { let put_lang = commands::put_lang(lang.as_bytes().to_vec()); - apdu::send_command(self.card_client(), put_lang, false)?.try_into() + apdu::send_command(card_client, put_lang, false)?.try_into() } - pub fn set_sex(&mut self, sex: Sex) -> Result { + pub fn set_sex( + card_client: &mut dyn CardClient, + sex: Sex, + ) -> Result { let put_sex = commands::put_sex((&sex).into()); - apdu::send_command(self.card_client(), put_sex, false)?.try_into() + apdu::send_command(card_client, put_sex, false)?.try_into() } - pub fn set_url(&mut self, url: &str) -> Result { + pub fn set_url( + card_client: &mut dyn CardClient, + url: &str, + ) -> Result { let put_url = commands::put_url(url.as_bytes().to_vec()); - apdu::send_command(self.card_client(), put_url, false)?.try_into() + apdu::send_command(card_client, put_url, false)?.try_into() } pub fn set_creation_time( - &mut self, + card_client: &mut dyn CardClient, time: KeyGenerationTime, key_type: KeyType, ) -> Result { @@ -715,11 +755,11 @@ impl CardApp { let time_cmd = commands::put_data(&[key_type.timestamp_put_tag()], time_value); - apdu::send_command(self.card_client(), time_cmd, false)?.try_into() + apdu::send_command(card_client, time_cmd, false)?.try_into() } pub fn set_fingerprint( - &mut self, + card_client: &mut dyn CardClient, fp: Fingerprint, key_type: KeyType, ) -> Result { @@ -728,7 +768,7 @@ impl CardApp { fp.as_bytes().to_vec(), ); - apdu::send_command(self.card_client(), fp_cmd, false)?.try_into() + apdu::send_command(card_client, fp_cmd, false)?.try_into() } /// Set PW Status Bytes. @@ -743,14 +783,14 @@ impl CardApp { /// /// (See OpenPGP card spec, pg. 28) pub fn set_pw_status_bytes( - &mut self, + card_client: &mut dyn CardClient, pw_status: &PWStatusBytes, long: bool, ) -> Result { let data = pw_status.serialize_for_put(long); let cmd = commands::put_pw_status(data); - apdu::send_command(self.card_client(), cmd, false)?.try_into() + apdu::send_command(card_client, cmd, false)?.try_into() } /// Set cardholder certificate (for AUT, DEC or SIG). @@ -758,17 +798,17 @@ impl CardApp { /// Call select_data() before calling this fn, to select a particular /// certificate (if the card supports multiple certificates). pub fn set_cardholder_certificate( - &mut self, + card_client: &mut dyn CardClient, data: Vec, ) -> Result { let cmd = commands::put_cardholder_certificate(data); - apdu::send_command(self.card_client(), cmd, false)?.try_into() + apdu::send_command(card_client, cmd, false)?.try_into() } /// Set algorithm attributes /// (4.4.3.9 Algorithm Attributes) pub fn set_algorithm_attributes( - &mut self, + card_client: &mut dyn CardClient, key_type: KeyType, algo: &Algo, ) -> Result { @@ -778,33 +818,33 @@ impl CardApp { algo.to_data_object()?, ); - apdu::send_command(self.card_client(), cmd, false)?.try_into() + apdu::send_command(card_client, cmd, false)?.try_into() } /// Set resetting code /// (4.3.4 Resetting Code) pub fn set_resetting_code( - &mut self, + card_client: &mut dyn CardClient, resetting_code: Vec, ) -> Result { let cmd = commands::put_data(&[0xd3], resetting_code); - apdu::send_command(self.card_client(), cmd, false)?.try_into() + apdu::send_command(card_client, cmd, false)?.try_into() } /// Import an existing private key to the card. /// (This implicitly sets the algorithm info, fingerprint and timestamp) pub fn key_import( - &mut self, + card_client: &mut dyn CardClient, key: Box, key_type: KeyType, ) -> Result<(), Error> { - let algo_info = self.algorithm_information(); + let algo_info = Self::algorithm_information(card_client); // An error is ok - it's fine if a card doesn't offer a list of // supported algorithms let algo_info = algo_info.unwrap_or(None); - keys::key_import(self, key, key_type, algo_info) + keys::key_import(card_client, key, key_type, algo_info) } /// Generate a key on the card. @@ -817,7 +857,7 @@ impl CardApp { /// applicable), and import format, with values that the current card /// supports. pub fn generate_key( - &mut self, + card_client: &mut dyn CardClient, fp_from_pub: fn( &PublicKeyMaterial, KeyGenerationTime, @@ -826,7 +866,7 @@ impl CardApp { key_type: KeyType, algo: Option<&Algo>, ) -> Result<(PublicKeyMaterial, KeyGenerationTime), Error> { - keys::gen_key_with_metadata(self, fp_from_pub, key_type, algo) + keys::gen_key_with_metadata(card_client, fp_from_pub, key_type, algo) } /// Generate a key on the card. @@ -839,7 +879,7 @@ impl CardApp { /// bitsize of e for RSA, and import format). This function determines /// these values based on information from the card. pub fn generate_key_simple( - &mut self, + card_client: &mut dyn CardClient, fp_from_pub: fn( &PublicKeyMaterial, KeyGenerationTime, @@ -848,16 +888,17 @@ impl CardApp { key_type: KeyType, simple: AlgoSimple, ) -> Result<(PublicKeyMaterial, KeyGenerationTime), Error> { - let ard = self.application_related_data()?; - let algo_info = if let Ok(ai) = self.algorithm_information() { - ai - } else { - None - }; + let ard = Self::application_related_data(card_client)?; + let algo_info = + if let Ok(ai) = Self::algorithm_information(card_client) { + ai + } else { + None + }; let algo = simple.determine_algo(key_type, &ard, algo_info)?; - self.generate_key(fp_from_pub, key_type, Some(&algo)) + Self::generate_key(card_client, fp_from_pub, key_type, Some(&algo)) } /// Get public key material from the card. @@ -869,9 +910,9 @@ impl CardApp { /// reconstruct a pre-existing OpenPGP public key that corresponds to /// the private key on the card. pub fn public_key( - &mut self, + card_client: &mut dyn CardClient, key_type: KeyType, ) -> Result { - keys::public_key(self, key_type) + keys::public_key(card_client, key_type) } } diff --git a/openpgp-card/src/keys.rs b/openpgp-card/src/keys.rs index 08c6dec..01a7b7d 100644 --- a/openpgp-card/src/keys.rs +++ b/openpgp-card/src/keys.rs @@ -17,8 +17,8 @@ use crate::crypto_data::{ PublicKeyMaterial, RSAKey, RSAPub, }; use crate::tlv::{length::tlv_encode_length, value::Value, Tlv}; -use crate::Error; use crate::{apdu, KeyType}; +use crate::{CardClient, Error}; /// Generate asymmetric key pair on the card. /// @@ -31,7 +31,7 @@ use crate::{apdu, KeyType}; /// `fp_from_pub` calculates the fingerprint for a public key data object and /// creation timestamp pub(crate) fn gen_key_with_metadata( - card_app: &mut CardApp, + card_client: &mut dyn CardClient, fp_from_pub: fn( &PublicKeyMaterial, KeyGenerationTime, @@ -43,12 +43,16 @@ pub(crate) fn gen_key_with_metadata( // Set algo on card if it's Some if let Some(target_algo) = algo { // FIXME: caching - let ard = card_app.application_related_data()?; // no caching, here! + let ard = CardApp::application_related_data(card_client)?; // no caching, here! let ecap = ard.extended_capabilities()?; // Only set algo if card supports setting of algo attr if ecap.algo_attrs_changeable() { - card_app.set_algorithm_attributes(key_type, target_algo)?; + CardApp::set_algorithm_attributes( + card_client, + key_type, + target_algo, + )?; } else { // Check if the current algo on the card is the one we want, if // not we return an error. @@ -65,11 +69,11 @@ pub(crate) fn gen_key_with_metadata( } // get current (possibly updated) state of algo - let ard = card_app.application_related_data()?; // no caching, here! + let ard = CardApp::application_related_data(card_client)?; // no caching, here! let cur_algo = ard.algorithm_attributes(key_type)?; // generate key - let tlv = generate_asymmetric_key_pair(card_app, key_type)?; + let tlv = generate_asymmetric_key_pair(card_client, key_type)?; // derive pubkey let pubkey = tlv_to_pubkey(&tlv, &cur_algo)?; @@ -87,11 +91,11 @@ pub(crate) fn gen_key_with_metadata( let ts = ts.into(); - card_app.set_creation_time(ts, key_type)?; + CardApp::set_creation_time(card_client, ts, key_type)?; // calculate/store fingerprint let fp = fp_from_pub(&pubkey, ts, key_type)?; - card_app.set_fingerprint(fp, key_type)?; + CardApp::set_fingerprint(card_client, fp, key_type)?; Ok((pubkey, ts)) } @@ -128,14 +132,14 @@ fn tlv_to_pubkey(tlv: &Tlv, algo: &Algo) -> Result { /// This runs the low level key generation primitive on the card. /// (This does not set algorithm attributes, creation time or fingerprint) pub(crate) fn generate_asymmetric_key_pair( - card_app: &mut CardApp, + card_client: &mut dyn CardClient, key_type: KeyType, ) -> Result { // generate key let crt = control_reference_template(key_type)?; let gen_key_cmd = commands::gen_key(crt.serialize().to_vec()); - let resp = apdu::send_command(card_app.card_client(), gen_key_cmd, true)?; + let resp = apdu::send_command(card_client, gen_key_cmd, true)?; resp.check_ok()?; let tlv = Tlv::try_from(resp.data()?)?; @@ -150,19 +154,18 @@ pub(crate) fn generate_asymmetric_key_pair( /// /// (See 7.2.14 GENERATE ASYMMETRIC KEY PAIR) pub(crate) fn public_key( - card_app: &mut CardApp, + card_client: &mut dyn CardClient, key_type: KeyType, ) -> Result { // get current algo - let ard = card_app.application_related_data()?; // FIXME: caching + let ard = CardApp::application_related_data(card_client)?; // FIXME: caching let algo = ard.algorithm_attributes(key_type)?; // get public key let crt = control_reference_template(key_type)?; let get_pub_key_cmd = commands::get_pub_key(crt.serialize().to_vec()); - let resp = - apdu::send_command(card_app.card_client(), get_pub_key_cmd, true)?; + let resp = apdu::send_command(card_client, get_pub_key_cmd, true)?; resp.check_ok()?; let tlv = Tlv::try_from(resp.data()?)?; @@ -177,13 +180,13 @@ pub(crate) fn public_key( /// caused by checks before attempting to upload the key to the card, or by /// an error that the card reports during an attempt to upload the key). pub(crate) fn key_import( - card_app: &mut CardApp, + card_client: &mut dyn CardClient, key: Box, key_type: KeyType, algo_info: Option, ) -> Result<(), Error> { // FIXME: caching? - let ard = card_app.application_related_data()?; + let ard = CardApp::application_related_data(card_client)?; let (algo, key_cmd) = match key.private_key()? { PrivateKeyMaterial::R(rsa_key) => { @@ -219,12 +222,12 @@ pub(crate) fn key_import( // Only set algo attrs if "Extended Capabilities" lists the feature if ard.extended_capabilities()?.algo_attrs_changeable() { - card_app.set_algorithm_attributes(key_type, &algo)?; + CardApp::set_algorithm_attributes(card_client, key_type, &algo)?; } - 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.timestamp(), key_type)?; + apdu::send_command(card_client, key_cmd, false)?.check_ok()?; + CardApp::set_fingerprint(card_client, fp, key_type)?; + CardApp::set_creation_time(card_client, key.timestamp(), key_type)?; Ok(()) } diff --git a/pcsc/src/lib.rs b/pcsc/src/lib.rs index 0081f7f..147456b 100644 --- a/pcsc/src/lib.rs +++ b/pcsc/src/lib.rs @@ -236,8 +236,8 @@ impl PcscClient { } } - fn cards_filter(ident: Option<&str>) -> Result, Error> { - let mut cas: Vec = vec![]; + fn cards_filter(ident: Option<&str>) -> Result, Error> { + let mut cas: Vec = vec![]; for mut card in Self::raw_pcsc_cards().map_err(|sce| Error::Smartcard(sce))? @@ -316,14 +316,14 @@ impl PcscClient { /// /// Each card has the OpenPGP application selected, CardCaps have been /// initialized. - pub fn cards() -> Result, Error> { + pub fn cards() -> Result, Error> { Self::cards_filter(None) } /// Returns the OpenPGP card that matches `ident`, if it is available. /// A fully initialized CardApp is returned: the OpenPGP application has /// been selected, CardCaps have been set. - pub fn open_by_ident(ident: &str) -> Result { + pub fn open_by_ident(ident: &str) -> Result { log::debug!("open_by_ident for {:?}", ident); let mut cards = Self::cards_filter(Some(ident))?; @@ -349,7 +349,7 @@ impl PcscClient { /// Make an initialized CardApp from a PcscClient. /// Obtain and store feature lists from reader (pinpad functionality). - fn into_card_app(mut self) -> Result { + fn into_card_app(mut self) -> Result { // Get Features from reader (pinpad verify/modify) if let Ok(feat) = self.features() { for tlv in feat { @@ -359,7 +359,9 @@ impl PcscClient { } // Get initalized CardApp - CardApp::initialize(Box::new(self)) + CardApp::initialize(&mut self)?; + + Ok(self) } /// Get the minimum pin length for pin_id. diff --git a/scdc/src/lib.rs b/scdc/src/lib.rs index 1eba7d8..82481ee 100644 --- a/scdc/src/lib.rs +++ b/scdc/src/lib.rs @@ -62,11 +62,13 @@ impl ScdClient { pub fn open_by_serial( agent: Option, serial: &str, - ) -> Result { + ) -> Result { let mut card = ScdClient::new(agent, true)?; card.select_card(serial)?; - Ok(CardApp::initialize(Box::new(card))?) + CardApp::initialize(&mut card)?; + + Ok(card) } /// Open a CardApp that uses an scdaemon instance as its backend. @@ -75,10 +77,12 @@ impl ScdClient { /// /// (NOTE: implicitly picking an unspecified card might be a bad idea. /// You might want to avoid using this function.) - pub fn open_yolo(agent: Option) -> Result { - let card = ScdClient::new(agent, true)?; + pub fn open_yolo(agent: Option) -> Result { + let mut card = ScdClient::new(agent, true)?; - Ok(CardApp::initialize(Box::new(card))?) + CardApp::initialize(&mut card)?; + + Ok(card) } /// Helper fn that shuts down scdaemon via GnuPG Agent.