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