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