diff --git a/openpgp-card-sequoia/src/decryptor.rs b/openpgp-card-sequoia/src/decryptor.rs index e1b4215..cea43dc 100644 --- a/openpgp-card-sequoia/src/decryptor.rs +++ b/openpgp-card-sequoia/src/decryptor.rs @@ -22,7 +22,7 @@ use crate::PublicKey; pub(crate) struct CardDecryptor<'a> { /// The OpenPGP card (authenticated to allow decryption operations) - ocu: &'a CardUser, + ocu: &'a mut CardUser, /// The matching public key for the card's decryption key public: PublicKey, @@ -34,7 +34,7 @@ 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( - ocu: &'a CardUser, + ocu: &'a mut CardUser, cert: &Cert, policy: &dyn Policy, ) -> Result, OpenpgpCardError> { diff --git a/openpgp-card-sequoia/src/lib.rs b/openpgp-card-sequoia/src/lib.rs index f3681e1..6cfcfde 100644 --- a/openpgp-card-sequoia/src/lib.rs +++ b/openpgp-card-sequoia/src/lib.rs @@ -216,7 +216,7 @@ impl EccKey for SqEccKey { /// FIXME: picking the (sub)key to upload should probably done with /// more intent. pub fn upload_from_cert_yolo( - oca: &CardAdmin, + oca: &mut CardAdmin, cert: &sequoia_openpgp::Cert, key_type: KeyType, password: Option, @@ -249,7 +249,7 @@ pub fn upload_from_cert_yolo( /// /// The caller needs to make sure that `vka` is suitable for `key_type`. pub fn upload_key( - oca: &CardAdmin, + oca: &mut CardAdmin, vka: ValidErasedKeyAmalgamation, key_type: KeyType, password: Option, @@ -260,7 +260,7 @@ pub fn upload_key( } pub fn decrypt( - ocu: &CardUser, + ocu: &mut CardUser, cert: &sequoia_openpgp::Cert, msg: Vec, ) -> Result> { @@ -282,7 +282,7 @@ pub fn decrypt( } pub fn sign( - ocu: &CardSign, + ocu: &mut CardSign, cert: &sequoia_openpgp::Cert, input: &mut dyn io::Read, ) -> Result { diff --git a/openpgp-card-sequoia/src/main.rs b/openpgp-card-sequoia/src/main.rs index fa031e4..47da491 100644 --- a/openpgp-card-sequoia/src/main.rs +++ b/openpgp-card-sequoia/src/main.rs @@ -29,7 +29,7 @@ fn main() -> Result<(), Box> { if let Ok(test_card_ident) = test_card_ident { println!("** get card"); - let oc = CardBase::open_by_ident(&test_card_ident)?; + let mut oc = CardBase::open_by_ident(&test_card_ident)?; // card metadata @@ -86,7 +86,7 @@ fn main() -> Result<(), Box> { oc.factory_reset()?; match oc.verify_pw3("12345678") { - Ok(oc_admin) => { + Ok(mut oc_admin) => { println!("pw3 verify ok"); let check = oc_admin.check_pw3(); @@ -112,14 +112,14 @@ fn main() -> Result<(), Box> { let cert = Cert::from_file(TEST_KEY_PATH)?; openpgp_card_sequoia::upload_from_cert_yolo( - &oc_admin, + &mut oc_admin, &cert, KeyType::Decryption, None, )?; openpgp_card_sequoia::upload_from_cert_yolo( - &oc_admin, + &mut oc_admin, &cert, KeyType::Signing, None, @@ -140,7 +140,7 @@ fn main() -> Result<(), Box> { // Open fresh Card for decrypt // ----------------------------- - let oc = CardBase::open_by_ident(&test_card_ident)?; + let mut oc = CardBase::open_by_ident(&test_card_ident)?; let app_id = oc.get_aid()?; // Check that we're still using the expected card @@ -150,7 +150,7 @@ fn main() -> Result<(), Box> { println!("has pw1/82 been verified yet? {:x?}", check); match oc.verify_pw1("123456") { - Ok(oc_user) => { + Ok(mut oc_user) => { println!("pw1 82 verify ok"); let check = oc_user.check_pw1(); @@ -163,7 +163,7 @@ fn main() -> Result<(), Box> { println!("{:?}", msg); let res = openpgp_card_sequoia::decrypt( - &oc_user, + &mut oc_user, &cert, msg.into_bytes(), )?; @@ -183,14 +183,14 @@ fn main() -> Result<(), Box> { // Sign match oc.verify_pw1_for_signing("123456") { - Ok(oc_user) => { + Ok(mut oc_user) => { println!("pw1 81 verify ok"); let cert = Cert::from_file(TEST_KEY_PATH)?; let text = "Hello world, I am signed."; let res = openpgp_card_sequoia::sign( - &oc_user, + &mut oc_user, &cert, &mut text.as_bytes(), ); diff --git a/openpgp-card-sequoia/src/signer.rs b/openpgp-card-sequoia/src/signer.rs index a7a7e63..3939480 100644 --- a/openpgp-card-sequoia/src/signer.rs +++ b/openpgp-card-sequoia/src/signer.rs @@ -18,7 +18,7 @@ use crate::PublicKey; pub(crate) struct CardSigner<'a> { /// The OpenPGP card (authenticated to allow signing operations) - ocu: &'a CardSign, + ocu: &'a mut CardSign, /// The matching public key for the card's signing key public: PublicKey, @@ -30,7 +30,7 @@ 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( - ocs: &'a CardSign, + ocs: &'a mut CardSign, cert: &openpgp::Cert, policy: &dyn Policy, ) -> Result, OpenpgpCardError> { diff --git a/openpgp-card/src/apdu/mod.rs b/openpgp-card/src/apdu/mod.rs index d169540..c10f432 100644 --- a/openpgp-card/src/apdu/mod.rs +++ b/openpgp-card/src/apdu/mod.rs @@ -5,6 +5,7 @@ pub mod command; pub mod commands; pub mod response; +use anyhow::Result; use pcsc::Card; use std::convert::TryFrom; @@ -25,13 +26,13 @@ pub(crate) enum Le { /// If the reply is truncated, this fn assembles all the parts and returns /// them as one aggregated Response. pub(crate) fn send_command( - card: &Card, + card_client: &mut Box, cmd: Command, expect_reply: bool, card_caps: Option<&CardCaps>, ) -> Result { let mut resp = Response::try_from(send_command_low_level( - &card, + card_client, cmd, expect_reply, card_caps, @@ -44,7 +45,7 @@ pub(crate) fn send_command( // Get additional data let next = Response::try_from(send_command_low_level( - &card, + card_client, commands::get_response(), expect_reply, card_caps, @@ -69,7 +70,7 @@ pub(crate) fn send_command( /// If the response is chained, this fn only returns one chunk, the caller /// needs take care of chained responses fn send_command_low_level( - card: &Card, + card_client: &mut Box, cmd: Command, expect_reply: bool, card_caps: Option<&CardCaps>, @@ -116,8 +117,6 @@ fn send_command_low_level( pcsc::MAX_BUFFER_SIZE_EXTENDED }; - let mut resp_buffer = vec![0; buf_size]; - if chaining_support && !cmd.data.is_empty() { // Send command in chained mode @@ -139,12 +138,7 @@ fn send_command_low_level( .map_err(OpenpgpCardError::InternalError)?; log::trace!(" -> chunked APDU command: {:x?}", &serialized); - let resp = - card.transmit(&serialized, &mut resp_buffer).map_err(|e| { - OpenpgpCardError::Smartcard(SmartcardError::Error( - format!("Transmit failed: {:?}", e), - )) - })?; + let resp = card_client.transmit(&serialized, buf_size)?; log::trace!(" <- APDU chunk response: {:x?}", &resp); @@ -170,20 +164,45 @@ fn send_command_low_level( // chaining is not supported." } else { // this is the last Response in the chain -> return - return Ok(resp.to_vec()); + return Ok(resp); } } unreachable!("This state should be unreachable"); } else { let serialized = cmd.serialize(ext)?; - let resp = - card.transmit(&serialized, &mut resp_buffer).map_err(|e| { - OpenpgpCardError::Smartcard(SmartcardError::Error(format!( - "Transmit failed: {:?}", - e - ))) - })?; + let resp = card_client.transmit(&serialized, buf_size)?; + + log::trace!(" <- APDU response: {:x?}", resp); + + Ok(resp) + } +} + +pub trait CardClient { + fn transmit(&mut self, cmd: &[u8], buf_size: usize) -> Result>; +} + +pub struct PcscClient { + card: Card, +} + +impl PcscClient { + pub fn new(card: Card) -> Self { + Self { card } + } +} + +impl CardClient for PcscClient { + fn transmit(&mut self, cmd: &[u8], buf_size: usize) -> Result> { + let mut resp_buffer = vec![0; buf_size]; + + let resp = self.card.transmit(cmd, &mut resp_buffer).map_err(|e| { + OpenpgpCardError::Smartcard(SmartcardError::Error(format!( + "Transmit failed: {:?}", + e + ))) + })?; log::trace!(" <- APDU response: {:x?}", resp); diff --git a/openpgp-card/src/card_app.rs b/openpgp-card/src/card_app.rs index e250665..85675ee 100644 --- a/openpgp-card/src/card_app.rs +++ b/openpgp-card/src/card_app.rs @@ -9,6 +9,7 @@ //! Also, no caching of data is done here. If necessary, caching should //! be done on a higher layer. +use std::borrow::BorrowMut; use std::convert::TryFrom; use anyhow::{anyhow, Result}; @@ -27,6 +28,7 @@ use crate::errors::OpenpgpCardError; use crate::tlv::tag::Tag; use crate::tlv::TlvEntry; +use crate::apdu::CardClient; use crate::Hash; use crate::{ apdu, key_upload, parse, tlv, CardCaps, CardUploadableKey, DecryptMe, @@ -34,27 +36,27 @@ use crate::{ }; pub(crate) struct CardApp { - card: Card, + card_client: Box, card_caps: Option, } impl CardApp { - pub fn new(card: Card) -> Self { + pub fn new(card_client: Box) -> Self { Self { - card, + card_client, card_caps: None, } } pub fn set_caps(self, card_caps: CardCaps) -> Self { Self { - card: self.card, + card_client: self.card_client, card_caps: Some(card_caps), } } - pub fn card(&self) -> &Card { - &self.card + pub fn card(&mut self) -> &mut Box { + &mut self.card_client } pub fn card_caps(&self) -> Option<&CardCaps> { @@ -67,9 +69,9 @@ impl CardApp { /// /// This is done once, after opening the OpenPGP card applet /// (the data is stored in the OpenPGPCard object). - pub fn get_app_data(&self) -> Result { + pub fn get_app_data(&mut self) -> Result { let ad = commands::get_application_data(); - let resp = apdu::send_command(&self.card, ad, true, None)?; + let resp = apdu::send_command(&mut self.card_client, ad, true, None)?; let entry = TlvEntry::from(resp.data()?, true)?; log::trace!(" App data TlvEntry: {:x?}", entry); @@ -225,9 +227,9 @@ impl CardApp { // --- URL (5f50) --- - pub fn get_url(&self) -> Result { + pub fn get_url(&mut self) -> Result { let resp = apdu::send_command( - &self.card, + &mut self.card_client, commands::get_url(), true, self.card_caps.as_ref(), @@ -237,10 +239,10 @@ impl CardApp { } // --- cardholder related data (65) --- - pub fn get_cardholder_related_data(&self) -> Result { + pub fn get_cardholder_related_data(&mut self) -> Result { let crd = commands::cardholder_related_data(); let resp = apdu::send_command( - &self.card, + &mut self.card_client, crd, true, self.card_caps.as_ref(), @@ -251,10 +253,10 @@ impl CardApp { } // --- security support template (7a) --- - pub fn get_security_support_template(&self) -> Result { + pub fn get_security_support_template(&mut self) -> Result { let sst = commands::get_security_support_template(); let resp = apdu::send_command( - &self.card, + &mut self.card_client, sst, true, self.card_caps.as_ref(), @@ -265,9 +267,9 @@ impl CardApp { } // DO "Algorithm Information" (0xFA) - pub fn list_supported_algo(&self) -> Result> { + pub fn list_supported_algo(&mut self) -> Result> { let resp = apdu::send_command( - &self.card, + &mut self.card_client, commands::get_algo_list(), true, self.card_caps.as_ref(), @@ -281,13 +283,13 @@ impl CardApp { // ---------- /// Delete all state on this OpenPGP card - pub fn factory_reset(&self) -> Result<()> { + pub fn factory_reset(&mut self) -> 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, + &mut self.card_client, verify, false, self.card_caps.as_ref(), @@ -304,7 +306,7 @@ impl CardApp { for _ in 0..4 { let verify = commands::verify_pw3([0x40; 8].to_vec()); let resp = apdu::send_command( - &self.card, + &mut self.card_client, verify, false, self.card_caps.as_ref(), @@ -320,7 +322,7 @@ impl CardApp { // terminate_df [apdu 00 e6 00 00] let term = commands::terminate_df(); let resp = apdu::send_command( - &self.card, + &mut self.card_client, term, false, self.card_caps.as_ref(), @@ -330,7 +332,7 @@ impl CardApp { // activate_file [apdu 00 44 00 00] let act = commands::activate_file(); let resp = apdu::send_command( - &self.card, + &mut self.card_client, act, false, self.card_caps.as_ref(), @@ -344,43 +346,77 @@ impl CardApp { } pub fn verify_pw1_for_signing( - &self, + &mut self, pin: &str, ) -> Result { assert!(pin.len() >= 6); // FIXME: Err let verify = commands::verify_pw1_81(pin.as_bytes().to_vec()); - apdu::send_command(&self.card, verify, false, self.card_caps.as_ref()) + apdu::send_command( + &mut self.card_client, + verify, + false, + self.card_caps.as_ref(), + ) } - pub fn check_pw1(&self) -> Result { + pub fn check_pw1(&mut self) -> Result { let verify = commands::verify_pw1_82(vec![]); - apdu::send_command(&self.card, verify, false, self.card_caps.as_ref()) + apdu::send_command( + &mut self.card_client, + verify, + false, + self.card_caps.as_ref(), + ) } - pub fn verify_pw1(&self, pin: &str) -> Result { + pub fn verify_pw1( + &mut self, + pin: &str, + ) -> Result { assert!(pin.len() >= 6); // FIXME: Err let verify = commands::verify_pw1_82(pin.as_bytes().to_vec()); - apdu::send_command(&self.card, verify, false, self.card_caps.as_ref()) + apdu::send_command( + &mut self.card_client, + verify, + false, + self.card_caps.as_ref(), + ) } - pub fn check_pw3(&self) -> Result { + pub fn check_pw3(&mut self) -> Result { let verify = commands::verify_pw3(vec![]); - apdu::send_command(&self.card, verify, false, self.card_caps.as_ref()) + apdu::send_command( + &mut self.card_client, + verify, + false, + self.card_caps.as_ref(), + ) } - pub fn verify_pw3(&self, pin: &str) -> Result { + pub fn verify_pw3( + &mut self, + pin: &str, + ) -> Result { assert!(pin.len() >= 8); // FIXME: Err let verify = commands::verify_pw3(pin.as_bytes().to_vec()); - apdu::send_command(&self.card, verify, false, self.card_caps.as_ref()) + apdu::send_command( + &mut self.card_client, + verify, + false, + self.card_caps.as_ref(), + ) } // --- decrypt --- /// Decrypt the ciphertext in `dm`, on the card. - pub fn decrypt(&self, dm: DecryptMe) -> Result, OpenpgpCardError> { + pub fn decrypt( + &mut self, + dm: DecryptMe, + ) -> Result, OpenpgpCardError> { match dm { DecryptMe::RSA(message) => { let mut data = vec![0x0]; @@ -407,13 +443,13 @@ impl CardApp { /// Run decryption operation on the smartcard /// (7.2.11 PSO: DECIPHER) pub(crate) fn pso_decipher( - &self, + &mut self, data: Vec, ) -> Result, OpenpgpCardError> { // 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, + &mut self.card_client, dec_cmd, true, self.card_caps.as_ref(), @@ -427,7 +463,7 @@ impl CardApp { /// Sign the message in `hash`, on the card. pub fn signature_for_hash( - &self, + &mut self, hash: Hash, ) -> Result, OpenpgpCardError> { let data = match hash { @@ -464,13 +500,13 @@ impl CardApp { /// Run signing operation on the smartcard /// (7.2.10 PSO: COMPUTE DIGITAL SIGNATURE) pub(crate) fn compute_digital_signature( - &self, + &mut self, data: Vec, ) -> Result, OpenpgpCardError> { let dec_cmd = commands::signature(data); let resp = apdu::send_command( - &self.card, + &mut self.card_client, dec_cmd, true, self.card_caps.as_ref(), @@ -481,43 +517,62 @@ impl CardApp { // --- admin --- - pub fn set_name(&self, name: &str) -> Result { + pub fn set_name( + &mut self, + name: &str, + ) -> Result { let put_name = commands::put_name(name.as_bytes().to_vec()); apdu::send_command( - &self.card, + &mut self.card_client, put_name, false, self.card_caps.as_ref(), ) } - pub fn set_lang(&self, lang: &str) -> Result { + pub fn set_lang( + &mut self, + lang: &str, + ) -> Result { let put_lang = commands::put_lang(lang.as_bytes().to_vec()); apdu::send_command( - &self.card, + self.card_client.borrow_mut(), put_lang, false, self.card_caps.as_ref(), ) } - pub fn set_sex(&self, sex: Sex) -> Result { + pub fn set_sex(&mut self, sex: Sex) -> Result { let put_sex = commands::put_sex(sex.as_u8()); - apdu::send_command(&self.card, put_sex, false, self.card_caps.as_ref()) + apdu::send_command( + self.card_client.borrow_mut(), + put_sex, + false, + self.card_caps.as_ref(), + ) } - pub fn set_url(&self, url: &str) -> Result { + pub fn set_url( + &mut self, + url: &str, + ) -> Result { let put_url = commands::put_url(url.as_bytes().to_vec()); - apdu::send_command(&self.card, put_url, false, self.card_caps.as_ref()) + apdu::send_command( + &mut self.card_client, + put_url, + false, + self.card_caps.as_ref(), + ) } pub fn upload_key( - &self, + &mut self, key: Box, key_type: KeyType, ) -> Result<(), OpenpgpCardError> { let algo_list = self.list_supported_algo()?; - key_upload::upload_key(&self, key, key_type, algo_list) + key_upload::upload_key(self, key, key_type, algo_list) } } diff --git a/openpgp-card/src/key_upload.rs b/openpgp-card/src/key_upload.rs index 863e12f..edc9832 100644 --- a/openpgp-card/src/key_upload.rs +++ b/openpgp-card/src/key_upload.rs @@ -4,7 +4,7 @@ use anyhow::{anyhow, Result}; use crate::apdu::command::Command; -use crate::apdu::commands; +use crate::apdu::{commands, CardClient}; use crate::card_app::CardApp; use crate::errors::OpenpgpCardError; use crate::parse::algo_attrs::{Algo, RsaAttrs}; @@ -21,7 +21,7 @@ use pcsc::Card; /// /// The client needs to make sure that the key is suitable for `key_type`. pub(crate) fn upload_key( - card_app: &CardApp, + card_app: &mut CardApp, key: Box, key_type: KeyType, algo_list: Option, @@ -68,6 +68,8 @@ pub(crate) fn upload_key( } }; + let caps: Option = card_app.card_caps().map(|c| c.clone()); + copy_key_to_card( card_app.card(), key_type, @@ -75,7 +77,7 @@ pub(crate) fn upload_key( key.get_fp(), algo_cmd, key_cmd, - card_app.card_caps(), + caps.as_ref(), )?; Ok(()) @@ -368,7 +370,7 @@ fn ecc_algo_attrs_cmd( } fn copy_key_to_card( - card: &Card, + card_client: &mut Box, key_type: KeyType, ts: u64, fp: Vec, @@ -393,11 +395,11 @@ fn copy_key_to_card( // FIXME: Only write algo attributes to the card if "extended // capabilities" show that they are changeable! - apdu::send_command(card, algo_cmd, false, card_caps)?.check_ok()?; + apdu::send_command(card_client, algo_cmd, false, card_caps)?.check_ok()?; - apdu::send_command(card, key_cmd, false, card_caps)?.check_ok()?; - apdu::send_command(card, fp_cmd, false, card_caps)?.check_ok()?; - apdu::send_command(card, time_cmd, false, card_caps)?.check_ok()?; + apdu::send_command(card_client, key_cmd, false, card_caps)?.check_ok()?; + apdu::send_command(card_client, fp_cmd, false, card_caps)?.check_ok()?; + apdu::send_command(card_client, time_cmd, false, card_caps)?.check_ok()?; Ok(()) } diff --git a/openpgp-card/src/lib.rs b/openpgp-card/src/lib.rs index d3e269f..0098aca 100644 --- a/openpgp-card/src/lib.rs +++ b/openpgp-card/src/lib.rs @@ -13,9 +13,10 @@ use parse::{ }; use tlv::Tlv; +use crate::apdu::{CardClient, PcscClient}; use crate::card_app::CardApp; use crate::errors::{OpenpgpCardError, SmartcardError}; -use std::ops::Deref; +use std::ops::{Deref, DerefMut}; mod apdu; mod card; @@ -27,6 +28,7 @@ mod tlv; /// Information about the capabilities of the card. /// (feature configuration from card metadata) +#[derive(Clone, Copy)] pub(crate) struct CardCaps { pub(crate) ext_support: bool, pub(crate) chaining_support: bool, @@ -286,11 +288,16 @@ impl CardBase { /// Open connection to a specific card and select the openpgp applet fn open_card(card: Card) -> Result { let select_openpgp = commands::select_openpgp(); - let resp = apdu::send_command(&card, select_openpgp, false, None)?; + + let card_client = PcscClient::new(card); + let mut ccb = + Box::new(card_client) as Box; + + let resp = apdu::send_command(&mut ccb, select_openpgp, false, None)?; if resp.is_ok() { // read and cache "application related data" - let card_app = CardApp::new(card); + let mut card_app = CardApp::new(ccb); let ard = card_app.get_app_data()?; // Determine chaining/extended length support from card @@ -334,7 +341,7 @@ impl CardBase { /// /// This is done once, after opening the OpenPGP card applet /// (the data is stored in the OpenPGPCard object). - fn get_app_data(&self) -> Result { + fn get_app_data(&mut self) -> Result { self.card_app.get_app_data() } @@ -414,22 +421,22 @@ impl CardBase { // --- URL (5f50) --- - pub fn get_url(&self) -> Result { + pub fn get_url(&mut self) -> Result { self.card_app.get_url() } // --- cardholder related data (65) --- - pub fn get_cardholder_related_data(&self) -> Result { + pub fn get_cardholder_related_data(&mut self) -> Result { self.card_app.get_cardholder_related_data() } // --- security support template (7a) --- - pub fn get_security_support_template(&self) -> Result { + pub fn get_security_support_template(&mut self) -> Result { self.card_app.get_security_support_template() } // DO "Algorithm Information" (0xFA) - pub fn list_supported_algo(&self) -> Result> { + pub fn list_supported_algo(&mut self) -> Result> { // The DO "Algorithm Information" (Tag FA) shall be present if // Algorithm attributes can be changed let ec = self.get_extended_capabilities()?; @@ -445,12 +452,12 @@ impl CardBase { // ---------- /// Delete all state on this OpenPGP card - pub fn factory_reset(&self) -> Result<()> { + pub fn factory_reset(&mut self) -> Result<()> { self.card_app.factory_reset() } pub fn verify_pw1_for_signing( - self, + mut self, pin: &str, ) -> Result { assert!(pin.len() >= 6); // FIXME: Err @@ -466,11 +473,11 @@ impl CardBase { Err(self) } - pub fn check_pw1(&self) -> Result { + pub fn check_pw1(&mut self) -> Result { self.card_app.check_pw1() } - pub fn verify_pw1(self, pin: &str) -> Result { + pub fn verify_pw1(mut self, pin: &str) -> Result { assert!(pin.len() >= 6); // FIXME: Err let res = self.card_app.verify_pw1(pin); @@ -484,11 +491,11 @@ impl CardBase { Err(self) } - pub fn check_pw3(&self) -> Result { + pub fn check_pw3(&mut self) -> Result { self.card_app.check_pw3() } - pub fn verify_pw3(self, pin: &str) -> Result { + pub fn verify_pw3(mut self, pin: &str) -> Result { assert!(pin.len() >= 8); // FIXME: Err let res = self.card_app.verify_pw3(pin); @@ -518,16 +525,26 @@ impl Deref for CardUser { } } +/// Allow access to fn of CardBase, through CardUser. +impl DerefMut for CardUser { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.oc + } +} + impl CardUser { /// Decrypt the ciphertext in `dm`, on the card. - pub fn decrypt(&self, dm: DecryptMe) -> Result, OpenpgpCardError> { + pub fn decrypt( + &mut self, + dm: DecryptMe, + ) -> Result, OpenpgpCardError> { self.card_app.decrypt(dm) } /// Run decryption operation on the smartcard /// (7.2.11 PSO: DECIPHER) pub(crate) fn pso_decipher( - &self, + &mut self, data: Vec, ) -> Result, OpenpgpCardError> { self.card_app.pso_decipher(data) @@ -540,7 +557,7 @@ pub struct CardSign { oc: CardBase, } -/// Allow access to fn of OpenPGPCard, through OpenPGPCardUser. +/// Allow access to fn of CardBase, through CardSign. impl Deref for CardSign { type Target = CardBase; @@ -549,12 +566,19 @@ impl Deref for CardSign { } } +/// Allow access to fn of CardBase, through CardSign. +impl DerefMut for CardSign { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.oc + } +} + // FIXME: depending on the setting in "PW1 Status byte", only one // signature can be made after verification for signing impl CardSign { /// Sign the message in `hash`, on the card. pub fn signature_for_hash( - &self, + &mut self, hash: Hash, ) -> Result, OpenpgpCardError> { self.card_app.signature_for_hash(hash) @@ -563,7 +587,7 @@ impl CardSign { /// Run signing operation on the smartcard /// (7.2.10 PSO: COMPUTE DIGITAL SIGNATURE) pub(crate) fn compute_digital_signature( - &self, + &mut self, data: Vec, ) -> Result, OpenpgpCardError> { self.card_app.compute_digital_signature(data) @@ -584,8 +608,18 @@ impl Deref for CardAdmin { } } +/// Allow access to fn of OpenPGPCard, through OpenPGPCardAdmin. +impl DerefMut for CardAdmin { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.oc + } +} + impl CardAdmin { - pub fn set_name(&self, name: &str) -> Result { + pub fn set_name( + &mut self, + name: &str, + ) -> Result { if name.len() >= 40 { return Err(anyhow!("name too long").into()); } @@ -598,7 +632,10 @@ impl CardAdmin { self.card_app.set_name(name) } - pub fn set_lang(&self, lang: &str) -> Result { + pub fn set_lang( + &mut self, + lang: &str, + ) -> Result { if lang.len() > 8 { return Err(anyhow!("lang too long").into()); } @@ -606,11 +643,14 @@ impl CardAdmin { self.card_app.set_lang(lang) } - pub fn set_sex(&self, sex: Sex) -> Result { + pub fn set_sex(&mut self, sex: Sex) -> Result { self.card_app.set_sex(sex) } - pub fn set_url(&self, url: &str) -> Result { + pub fn set_url( + &mut self, + url: &str, + ) -> Result { if url.chars().any(|c| !c.is_ascii()) { return Err(anyhow!("Invalid char in url").into()); } @@ -626,13 +666,13 @@ impl CardAdmin { } pub fn upload_key( - &self, + &mut self, key: Box, key_type: KeyType, ) -> Result<(), OpenpgpCardError> { let algo_list = self.list_supported_algo()?; - key_upload::upload_key(&self.card_app, key, key_type, algo_list) + key_upload::upload_key(&mut self.card_app, key, key_type, algo_list) } }