Add an abstraction layer (CardClient) for access to the card, in preparation for scdaemon client mode.

This commit is contained in:
Heiko Schaefer 2021-07-09 20:37:52 +02:00
parent efe88e3582
commit 8e3c6c0046
8 changed files with 233 additions and 117 deletions

View file

@ -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<CardDecryptor<'a>, OpenpgpCardError> {

View file

@ -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<String>,
@ -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<SecretParts>,
key_type: KeyType,
password: Option<String>,
@ -260,7 +260,7 @@ pub fn upload_key(
}
pub fn decrypt(
ocu: &CardUser,
ocu: &mut CardUser,
cert: &sequoia_openpgp::Cert,
msg: Vec<u8>,
) -> Result<Vec<u8>> {
@ -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<String> {

View file

@ -29,7 +29,7 @@ fn main() -> Result<(), Box<dyn Error>> {
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<dyn Error>> {
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<dyn Error>> {
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<dyn Error>> {
// 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<dyn Error>> {
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<dyn Error>> {
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<dyn Error>> {
// 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(),
);

View file

@ -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<CardSigner<'a>, OpenpgpCardError> {

View file

@ -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<dyn CardClient + Send + Sync>,
cmd: Command,
expect_reply: bool,
card_caps: Option<&CardCaps>,
) -> Result<Response, OpenpgpCardError> {
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<dyn CardClient + Send + Sync>,
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<Vec<u8>>;
}
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<Vec<u8>> {
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);

View file

@ -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<dyn CardClient + Send + Sync>,
card_caps: Option<CardCaps>,
}
impl CardApp {
pub fn new(card: Card) -> Self {
pub fn new(card_client: Box<dyn CardClient + Send + Sync>) -> 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<dyn CardClient + Send + Sync> {
&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<Tlv> {
pub fn get_app_data(&mut self) -> Result<Tlv> {
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<String> {
pub fn get_url(&mut self) -> Result<String> {
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<CardHolder> {
pub fn get_cardholder_related_data(&mut self) -> Result<CardHolder> {
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<Tlv> {
pub fn get_security_support_template(&mut self) -> Result<Tlv> {
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<Option<AlgoInfo>> {
pub fn list_supported_algo(&mut self) -> Result<Option<AlgoInfo>> {
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<Response, OpenpgpCardError> {
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<Response, OpenpgpCardError> {
pub fn check_pw1(&mut self) -> Result<Response, OpenpgpCardError> {
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<Response, OpenpgpCardError> {
pub fn verify_pw1(
&mut self,
pin: &str,
) -> Result<Response, OpenpgpCardError> {
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<Response, OpenpgpCardError> {
pub fn check_pw3(&mut self) -> Result<Response, OpenpgpCardError> {
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<Response, OpenpgpCardError> {
pub fn verify_pw3(
&mut self,
pin: &str,
) -> Result<Response, OpenpgpCardError> {
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<Vec<u8>, OpenpgpCardError> {
pub fn decrypt(
&mut self,
dm: DecryptMe,
) -> Result<Vec<u8>, 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<u8>,
) -> Result<Vec<u8>, 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<Vec<u8>, 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<u8>,
) -> Result<Vec<u8>, 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<Response, OpenpgpCardError> {
pub fn set_name(
&mut self,
name: &str,
) -> Result<Response, OpenpgpCardError> {
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<Response, OpenpgpCardError> {
pub fn set_lang(
&mut self,
lang: &str,
) -> Result<Response, OpenpgpCardError> {
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<Response, OpenpgpCardError> {
pub fn set_sex(&mut self, sex: Sex) -> Result<Response, OpenpgpCardError> {
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<Response, OpenpgpCardError> {
pub fn set_url(
&mut self,
url: &str,
) -> Result<Response, OpenpgpCardError> {
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<dyn CardUploadableKey>,
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)
}
}

View file

@ -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<dyn CardUploadableKey>,
key_type: KeyType,
algo_list: Option<AlgoInfo>,
@ -68,6 +68,8 @@ pub(crate) fn upload_key(
}
};
let caps: Option<CardCaps> = 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<dyn CardClient + Send + Sync>,
key_type: KeyType,
ts: u64,
fp: Vec<u8>,
@ -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(())
}

View file

@ -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<Self, OpenpgpCardError> {
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<dyn CardClient + Send + Sync>;
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<Tlv> {
fn get_app_data(&mut self) -> Result<Tlv> {
self.card_app.get_app_data()
}
@ -414,22 +421,22 @@ impl CardBase {
// --- URL (5f50) ---
pub fn get_url(&self) -> Result<String> {
pub fn get_url(&mut self) -> Result<String> {
self.card_app.get_url()
}
// --- cardholder related data (65) ---
pub fn get_cardholder_related_data(&self) -> Result<CardHolder> {
pub fn get_cardholder_related_data(&mut self) -> Result<CardHolder> {
self.card_app.get_cardholder_related_data()
}
// --- security support template (7a) ---
pub fn get_security_support_template(&self) -> Result<Tlv> {
pub fn get_security_support_template(&mut self) -> Result<Tlv> {
self.card_app.get_security_support_template()
}
// DO "Algorithm Information" (0xFA)
pub fn list_supported_algo(&self) -> Result<Option<AlgoInfo>> {
pub fn list_supported_algo(&mut self) -> Result<Option<AlgoInfo>> {
// 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<CardSign, CardBase> {
assert!(pin.len() >= 6); // FIXME: Err
@ -466,11 +473,11 @@ impl CardBase {
Err(self)
}
pub fn check_pw1(&self) -> Result<Response, OpenpgpCardError> {
pub fn check_pw1(&mut self) -> Result<Response, OpenpgpCardError> {
self.card_app.check_pw1()
}
pub fn verify_pw1(self, pin: &str) -> Result<CardUser, CardBase> {
pub fn verify_pw1(mut self, pin: &str) -> Result<CardUser, CardBase> {
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<Response, OpenpgpCardError> {
pub fn check_pw3(&mut self) -> Result<Response, OpenpgpCardError> {
self.card_app.check_pw3()
}
pub fn verify_pw3(self, pin: &str) -> Result<CardAdmin, CardBase> {
pub fn verify_pw3(mut self, pin: &str) -> Result<CardAdmin, CardBase> {
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<Vec<u8>, OpenpgpCardError> {
pub fn decrypt(
&mut self,
dm: DecryptMe,
) -> Result<Vec<u8>, 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<u8>,
) -> Result<Vec<u8>, 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<Vec<u8>, 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<u8>,
) -> Result<Vec<u8>, 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<Response, OpenpgpCardError> {
pub fn set_name(
&mut self,
name: &str,
) -> Result<Response, OpenpgpCardError> {
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<Response, OpenpgpCardError> {
pub fn set_lang(
&mut self,
lang: &str,
) -> Result<Response, OpenpgpCardError> {
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<Response, OpenpgpCardError> {
pub fn set_sex(&mut self, sex: Sex) -> Result<Response, OpenpgpCardError> {
self.card_app.set_sex(sex)
}
pub fn set_url(&self, url: &str) -> Result<Response, OpenpgpCardError> {
pub fn set_url(
&mut self,
url: &str,
) -> Result<Response, OpenpgpCardError> {
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<dyn CardUploadableKey>,
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)
}
}