Change the API for interactions between openpgp-card and backends.
The goal of this change is a cleaner structure, and in particular to make it the default for client-code to obtain a CardApp with pre-initialized "capabilities" (that is, init_caps() gets called implicitely).
This commit is contained in:
parent
288a2a8325
commit
d55985807c
14 changed files with 147 additions and 173 deletions
|
@ -97,16 +97,12 @@ 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);
|
||||||
|
|
||||||
for card_client in PcscClient::cards()? {
|
for mut ca in PcscClient::cards()? {
|
||||||
let mut ca = CardApp::from(card_client);
|
|
||||||
|
|
||||||
// Set Card Capabilities (chaining, command length, ..)
|
// Set Card Capabilities (chaining, command length, ..)
|
||||||
let ard = ca.get_application_related_data()?;
|
let ard = ca.get_application_related_data()?;
|
||||||
let app_id = ard.get_application_id()?;
|
let app_id = ard.get_application_id()?;
|
||||||
|
|
||||||
if app_id.ident().as_str() == ident.to_uppercase() {
|
if app_id.ident().as_str() == ident.to_uppercase() {
|
||||||
ca.init_caps(&ard)?;
|
|
||||||
|
|
||||||
// println!("opened pcsc card {}", ident);
|
// println!("opened pcsc card {}", ident);
|
||||||
|
|
||||||
return Ok(ca);
|
return Ok(ca);
|
||||||
|
@ -116,8 +112,7 @@ impl TestCard {
|
||||||
Err(anyhow!("Pcsc card {} not found", ident))
|
Err(anyhow!("Pcsc card {} not found", ident))
|
||||||
}
|
}
|
||||||
Self::Scdc(serial) => {
|
Self::Scdc(serial) => {
|
||||||
let card_client = ScdClient::open_by_serial(None, serial)?;
|
let mut ca = ScdClient::open_by_serial(None, serial)?;
|
||||||
let mut ca = CardApp::from(card_client);
|
|
||||||
|
|
||||||
// Set Card Capabilities (chaining, command length, ..)
|
// Set Card Capabilities (chaining, command length, ..)
|
||||||
let ard = ca.get_application_related_data()?;
|
let ard = ca.get_application_related_data()?;
|
||||||
|
|
|
@ -9,8 +9,7 @@ use openpgp_card_sequoia::card::Open;
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
println!("The following OpenPGP cards are connected to your system:");
|
println!("The following OpenPGP cards are connected to your system:");
|
||||||
|
|
||||||
for ccb in PcscClient::cards()? {
|
for mut ca in PcscClient::cards()? {
|
||||||
let mut ca = ccb.into();
|
|
||||||
let open = Open::open(&mut ca)?;
|
let open = Open::open(&mut ca)?;
|
||||||
println!(" {}", open.application_identifier()?.ident());
|
println!(" {}", open.application_identifier()?.ident());
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let pin_file = &args[1];
|
let pin_file = &args[1];
|
||||||
let cert_file = &args[2];
|
let cert_file = &args[2];
|
||||||
|
|
||||||
let mut ca = PcscClient::open_by_ident(&card_ident)?.into();
|
let mut ca = PcscClient::open_by_ident(card_ident)?;
|
||||||
let mut open = Open::open(&mut ca)?;
|
let mut open = Open::open(&mut ca)?;
|
||||||
|
|
||||||
let pin = std::fs::read_to_string(pin_file)?;
|
let pin = std::fs::read_to_string(pin_file)?;
|
||||||
|
|
|
@ -23,7 +23,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let pin_file = &args[1];
|
let pin_file = &args[1];
|
||||||
let cert_file = &args[2];
|
let cert_file = &args[2];
|
||||||
|
|
||||||
let mut ca = PcscClient::open_by_ident(&card_ident)?.into();
|
let mut ca = PcscClient::open_by_ident(card_ident)?;
|
||||||
let mut open = Open::open(&mut ca)?;
|
let mut open = Open::open(&mut ca)?;
|
||||||
|
|
||||||
let pin = std::fs::read_to_string(pin_file)?;
|
let pin = std::fs::read_to_string(pin_file)?;
|
||||||
|
|
|
@ -35,7 +35,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||||
let test_card_ident = env::var("TEST_CARD_IDENT");
|
let test_card_ident = env::var("TEST_CARD_IDENT");
|
||||||
|
|
||||||
if let Ok(test_card_ident) = test_card_ident {
|
if let Ok(test_card_ident) = test_card_ident {
|
||||||
let mut card = PcscClient::open_by_ident(&test_card_ident)?.into();
|
let mut card = PcscClient::open_by_ident(&test_card_ident)?;
|
||||||
let mut open = Open::open(&mut card)?;
|
let mut open = Open::open(&mut card)?;
|
||||||
|
|
||||||
// card metadata
|
// card metadata
|
||||||
|
@ -150,7 +150,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
// Open fresh Card for decrypt
|
// Open fresh Card for decrypt
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
let mut card = PcscClient::open_by_ident(&test_card_ident)?.into();
|
let mut card = PcscClient::open_by_ident(&test_card_ident)?;
|
||||||
let mut open = Open::open(&mut card)?;
|
let mut open = Open::open(&mut card)?;
|
||||||
|
|
||||||
// Check that we're still using the expected card
|
// Check that we're still using the expected card
|
||||||
|
@ -189,7 +189,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
// Open fresh Card for signing
|
// Open fresh Card for signing
|
||||||
// -----------------------------
|
// -----------------------------
|
||||||
let mut card = PcscClient::open_by_ident(&test_card_ident)?.into();
|
let mut card = PcscClient::open_by_ident(&test_card_ident)?;
|
||||||
let mut open = Open::open(&mut card)?;
|
let mut open = Open::open(&mut card)?;
|
||||||
|
|
||||||
// Sign
|
// Sign
|
||||||
|
@ -219,8 +219,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||||
|
|
||||||
println!("The following OpenPGP cards are connected to your system:");
|
println!("The following OpenPGP cards are connected to your system:");
|
||||||
|
|
||||||
for card in PcscClient::cards()? {
|
for mut card in PcscClient::cards()? {
|
||||||
let mut card = card.into();
|
|
||||||
let open = Open::open(&mut card)?;
|
let open = Open::open(&mut card)?;
|
||||||
println!(" {}", open.application_identifier()?.ident());
|
println!(" {}", open.application_identifier()?.ident());
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ use std::convert::TryFrom;
|
||||||
|
|
||||||
use crate::apdu::command::Expect;
|
use crate::apdu::command::Expect;
|
||||||
use crate::apdu::{command::Command, response::RawResponse};
|
use crate::apdu::{command::Command, response::RawResponse};
|
||||||
use crate::{CardClientBox, Error, StatusBytes};
|
use crate::{CardClient, Error, StatusBytes};
|
||||||
|
|
||||||
/// "Maximum amount of bytes in a short APDU command or response" (from pcsc)
|
/// "Maximum amount of bytes in a short APDU command or response" (from pcsc)
|
||||||
const MAX_BUFFER_SIZE: usize = 264;
|
const MAX_BUFFER_SIZE: usize = 264;
|
||||||
|
@ -23,7 +23,7 @@ const MAX_BUFFER_SIZE: usize = 264;
|
||||||
/// If the reply is truncated, this fn assembles all the parts and returns
|
/// If the reply is truncated, this fn assembles all the parts and returns
|
||||||
/// them as one aggregated Response.
|
/// them as one aggregated Response.
|
||||||
pub(crate) fn send_command(
|
pub(crate) fn send_command(
|
||||||
card_client: &mut CardClientBox,
|
card_client: &mut dyn CardClient,
|
||||||
cmd: Command,
|
cmd: Command,
|
||||||
expect_reply: bool,
|
expect_reply: bool,
|
||||||
) -> Result<RawResponse, Error> {
|
) -> Result<RawResponse, Error> {
|
||||||
|
@ -82,7 +82,7 @@ pub(crate) fn send_command(
|
||||||
/// If the response is chained, this fn only returns one chunk, the caller
|
/// If the response is chained, this fn only returns one chunk, the caller
|
||||||
/// needs to re-assemble the chained response-parts.
|
/// needs to re-assemble the chained response-parts.
|
||||||
fn send_command_low_level(
|
fn send_command_low_level(
|
||||||
card_client: &mut CardClientBox,
|
card_client: &mut dyn CardClient,
|
||||||
cmd: Command,
|
cmd: Command,
|
||||||
expect_response: Expect,
|
expect_response: Expect,
|
||||||
) -> Result<Vec<u8>, Error> {
|
) -> Result<Vec<u8>, Error> {
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
|
|
||||||
//! CardApp exposes functionality of the "OpenPGP card" application.
|
//! CardApp exposes functionality of the "OpenPGP card" application.
|
||||||
|
|
||||||
use std::borrow::BorrowMut;
|
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
|
|
||||||
|
@ -19,7 +18,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::{apdu, keys, CardCaps, CardClientBox, KeyType};
|
use crate::{apdu, keys, CardCaps, CardClient, CardClientBox, KeyType};
|
||||||
use crate::{Error, StatusBytes};
|
use crate::{Error, StatusBytes};
|
||||||
|
|
||||||
/// Low-level access to OpenPGP card functionality.
|
/// Low-level access to OpenPGP card functionality.
|
||||||
|
@ -33,22 +32,26 @@ pub struct CardApp {
|
||||||
card_client: CardClientBox,
|
card_client: CardClientBox,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<CardClientBox> for CardApp {
|
|
||||||
fn from(card_client: CardClientBox) -> Self {
|
|
||||||
Self { card_client }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<CardApp> for CardClientBox {
|
|
||||||
fn from(card_app: CardApp) -> CardClientBox {
|
|
||||||
card_app.card_client
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CardApp {
|
impl CardApp {
|
||||||
|
/// Get a CardApp based on a CardClient.
|
||||||
|
///
|
||||||
|
/// It is expected that SELECT has already been performed on the card.
|
||||||
|
///
|
||||||
|
/// This fn calls CardClient::init_caps(). It should probably only be used
|
||||||
|
/// by backend implementations, not by user code. User Code should get
|
||||||
|
/// a fully initialized CardApp from their backend implementation.
|
||||||
|
pub fn initialize(card_client: CardClientBox) -> Result<Self> {
|
||||||
|
let mut ca = Self { card_client };
|
||||||
|
|
||||||
|
let ard = ca.get_application_related_data()?;
|
||||||
|
ca.init_caps(&ard)?;
|
||||||
|
|
||||||
|
Ok(ca)
|
||||||
|
}
|
||||||
|
|
||||||
/// Get the CardClient for this CardApp
|
/// Get the CardClient for this CardApp
|
||||||
pub(crate) fn get_card_client(&mut self) -> &mut CardClientBox {
|
pub(crate) fn card_client(&mut self) -> &mut dyn CardClient {
|
||||||
&mut self.card_client
|
&mut *self.card_client
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initialize the CardCaps settings in the underlying CardClient
|
/// Initialize the CardCaps settings in the underlying CardClient
|
||||||
|
@ -95,15 +98,6 @@ impl CardApp {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- select ---
|
|
||||||
|
|
||||||
/// Select the OpenPGP card application
|
|
||||||
pub fn select(&mut self) -> Result<Response, Error> {
|
|
||||||
let select_openpgp = commands::select_openpgp();
|
|
||||||
apdu::send_command(&mut self.card_client, select_openpgp, false)?
|
|
||||||
.try_into()
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- get data ---
|
// --- get data ---
|
||||||
|
|
||||||
/// Get the "application related data" from the card.
|
/// Get the "application related data" from the card.
|
||||||
|
@ -115,7 +109,7 @@ impl CardApp {
|
||||||
&mut self,
|
&mut self,
|
||||||
) -> Result<ApplicationRelatedData> {
|
) -> Result<ApplicationRelatedData> {
|
||||||
let ad = commands::get_application_data();
|
let ad = commands::get_application_data();
|
||||||
let resp = apdu::send_command(&mut self.card_client, ad, true)?;
|
let resp = apdu::send_command(self.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);
|
||||||
|
@ -130,7 +124,7 @@ impl CardApp {
|
||||||
assert!((1..=4).contains(&num));
|
assert!((1..=4).contains(&num));
|
||||||
|
|
||||||
let cmd = commands::get_private_do(num);
|
let cmd = commands::get_private_do(num);
|
||||||
let resp = apdu::send_command(&mut self.card_client, cmd, true)?;
|
let resp = apdu::send_command(self.card_client(), cmd, true)?;
|
||||||
|
|
||||||
Ok(resp.data()?.to_vec())
|
Ok(resp.data()?.to_vec())
|
||||||
}
|
}
|
||||||
|
@ -166,11 +160,8 @@ impl CardApp {
|
||||||
// --- URL (5f50) ---
|
// --- URL (5f50) ---
|
||||||
|
|
||||||
pub fn get_url(&mut self) -> Result<String> {
|
pub fn get_url(&mut self) -> Result<String> {
|
||||||
let resp = apdu::send_command(
|
let resp =
|
||||||
&mut self.card_client,
|
apdu::send_command(self.card_client(), commands::get_url(), true)?;
|
||||||
commands::get_url(),
|
|
||||||
true,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(String::from_utf8_lossy(resp.data()?).to_string())
|
Ok(String::from_utf8_lossy(resp.data()?).to_string())
|
||||||
}
|
}
|
||||||
|
@ -180,7 +171,7 @@ impl CardApp {
|
||||||
&mut self,
|
&mut self,
|
||||||
) -> Result<CardholderRelatedData> {
|
) -> Result<CardholderRelatedData> {
|
||||||
let crd = commands::cardholder_related_data();
|
let crd = commands::cardholder_related_data();
|
||||||
let resp = apdu::send_command(&mut self.card_client, crd, true)?;
|
let resp = apdu::send_command(self.card_client(), crd, true)?;
|
||||||
resp.check_ok()?;
|
resp.check_ok()?;
|
||||||
|
|
||||||
CardholderRelatedData::try_from(resp.data()?)
|
CardholderRelatedData::try_from(resp.data()?)
|
||||||
|
@ -191,7 +182,7 @@ impl CardApp {
|
||||||
&mut self,
|
&mut self,
|
||||||
) -> Result<SecuritySupportTemplate> {
|
) -> Result<SecuritySupportTemplate> {
|
||||||
let sst = commands::get_security_support_template();
|
let sst = commands::get_security_support_template();
|
||||||
let resp = apdu::send_command(&mut self.card_client, sst, true)?;
|
let resp = apdu::send_command(self.card_client(), sst, true)?;
|
||||||
resp.check_ok()?;
|
resp.check_ok()?;
|
||||||
|
|
||||||
let tlv = Tlv::try_from(resp.data()?)?;
|
let tlv = Tlv::try_from(resp.data()?)?;
|
||||||
|
@ -219,13 +210,13 @@ impl CardApp {
|
||||||
/// certificate (if the card supports multiple certificates).
|
/// certificate (if the card supports multiple certificates).
|
||||||
pub fn get_cardholder_certificate(&mut self) -> Result<Response, Error> {
|
pub fn get_cardholder_certificate(&mut self) -> Result<Response, Error> {
|
||||||
let cmd = commands::get_cardholder_certificate();
|
let cmd = commands::get_cardholder_certificate();
|
||||||
apdu::send_command(&mut self.card_client, cmd, true)?.try_into()
|
apdu::send_command(self.card_client(), cmd, true)?.try_into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// DO "Algorithm Information"
|
/// DO "Algorithm Information"
|
||||||
pub fn get_algo_info(&mut self) -> Result<Option<AlgoInfo>> {
|
pub fn get_algo_info(&mut self) -> Result<Option<AlgoInfo>> {
|
||||||
let resp = apdu::send_command(
|
let resp = apdu::send_command(
|
||||||
&mut self.card_client,
|
self.card_client(),
|
||||||
commands::get_algo_list(),
|
commands::get_algo_list(),
|
||||||
true,
|
true,
|
||||||
)?;
|
)?;
|
||||||
|
@ -250,7 +241,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(&mut self.card_client, cmd, true)?.try_into()
|
apdu::send_command(self.card_client(), cmd, true)?.try_into()
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------
|
// ----------
|
||||||
|
@ -268,8 +259,7 @@ impl CardApp {
|
||||||
// [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 =
|
let resp = apdu::send_command(self.card_client(), verify, false)?;
|
||||||
apdu::send_command(&mut self.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(_)))
|
||||||
|
@ -282,8 +272,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 =
|
let resp = apdu::send_command(self.card_client(), verify, false)?;
|
||||||
apdu::send_command(&mut self.card_client, verify, false)?;
|
|
||||||
|
|
||||||
if !(resp.status() == StatusBytes::SecurityStatusNotSatisfied
|
if !(resp.status() == StatusBytes::SecurityStatusNotSatisfied
|
||||||
|| resp.status() == StatusBytes::AuthenticationMethodBlocked
|
|| resp.status() == StatusBytes::AuthenticationMethodBlocked
|
||||||
|
@ -295,12 +284,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(&mut self.card_client, term, false)?;
|
let resp = apdu::send_command(self.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(&mut self.card_client, act, false)?;
|
let resp = apdu::send_command(self.card_client(), act, false)?;
|
||||||
resp.check_ok()?;
|
resp.check_ok()?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -317,7 +306,7 @@ impl CardApp {
|
||||||
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(&mut self.card_client, verify, false)?.try_into()
|
apdu::send_command(self.card_client(), verify, false)?.try_into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check the current access of PW1 for signing (mode 81).
|
/// Check the current access of PW1 for signing (mode 81).
|
||||||
|
@ -328,14 +317,14 @@ impl CardApp {
|
||||||
/// 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(&mut self) -> Result<Response, Error> {
|
||||||
let verify = commands::verify_pw1_81(vec![]);
|
let verify = commands::verify_pw1_81(vec![]);
|
||||||
apdu::send_command(&mut self.card_client, verify, false)?.try_into()
|
apdu::send_command(self.card_client(), verify, false)?.try_into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Verify PW1 (user) and set an appropriate access status.
|
/// Verify PW1 (user) and set an appropriate access status.
|
||||||
/// (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(&mut self, 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(&mut self.card_client, verify, false)?.try_into()
|
apdu::send_command(self.card_client(), verify, false)?.try_into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check the current access of PW1.
|
/// Check the current access of PW1.
|
||||||
|
@ -347,13 +336,13 @@ impl CardApp {
|
||||||
/// e.g. yubikey 5)
|
/// e.g. yubikey 5)
|
||||||
pub fn check_pw1(&mut self) -> Result<Response, Error> {
|
pub fn check_pw1(&mut self) -> Result<Response, Error> {
|
||||||
let verify = commands::verify_pw1_82(vec![]);
|
let verify = commands::verify_pw1_82(vec![]);
|
||||||
apdu::send_command(&mut self.card_client, verify, false)?.try_into()
|
apdu::send_command(self.card_client(), verify, false)?.try_into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Verify PW3 (admin) and set an appropriate access status.
|
/// Verify PW3 (admin) and set an appropriate access status.
|
||||||
pub fn verify_pw3(&mut self, pin: &str) -> Result<Response, Error> {
|
pub fn verify_pw3(&mut self, 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(&mut self.card_client, verify, false)?.try_into()
|
apdu::send_command(self.card_client(), verify, false)?.try_into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check the current access of PW3 (admin).
|
/// Check the current access of PW3 (admin).
|
||||||
|
@ -364,7 +353,7 @@ impl CardApp {
|
||||||
/// e.g. yubikey 5)
|
/// e.g. yubikey 5)
|
||||||
pub fn check_pw3(&mut self) -> Result<Response, Error> {
|
pub fn check_pw3(&mut self) -> Result<Response, Error> {
|
||||||
let verify = commands::verify_pw3(vec![]);
|
let verify = commands::verify_pw3(vec![]);
|
||||||
apdu::send_command(&mut self.card_client, verify, false)?.try_into()
|
apdu::send_command(self.card_client(), verify, false)?.try_into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Change the value of PW1 (user password).
|
/// Change the value of PW1 (user password).
|
||||||
|
@ -380,7 +369,7 @@ 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(&mut self.card_client, change, false)?.try_into()
|
apdu::send_command(self.card_client(), change, false)?.try_into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Change the value of PW3 (admin password).
|
/// Change the value of PW3 (admin password).
|
||||||
|
@ -396,7 +385,7 @@ 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(&mut self.card_client, change, false)?.try_into()
|
apdu::send_command(self.card_client(), change, false)?.try_into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reset the error counter for PW1 (user password) and set a new value
|
/// Reset the error counter for PW1 (user password) and set a new value
|
||||||
|
@ -412,7 +401,7 @@ impl CardApp {
|
||||||
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(&mut self.card_client, reset, false)?.try_into()
|
apdu::send_command(self.card_client(), reset, false)?.try_into()
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- decrypt ---
|
// --- decrypt ---
|
||||||
|
@ -460,7 +449,7 @@ impl CardApp {
|
||||||
fn pso_decipher(&mut self, data: Vec<u8>) -> Result<Vec<u8>, Error> {
|
fn pso_decipher(&mut self, 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(&mut self.card_client, dec_cmd, true)?;
|
let resp = apdu::send_command(self.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())?)
|
||||||
|
@ -522,7 +511,7 @@ impl CardApp {
|
||||||
) -> 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(&mut self.card_client, cds_cmd, true)?;
|
let resp = apdu::send_command(self.card_client(), cds_cmd, true)?;
|
||||||
|
|
||||||
Ok(resp.data().map(|d| d.to_vec())?)
|
Ok(resp.data().map(|d| d.to_vec())?)
|
||||||
}
|
}
|
||||||
|
@ -553,7 +542,7 @@ impl CardApp {
|
||||||
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(&mut self.card_client, ia_cmd, true)?;
|
let resp = apdu::send_command(self.card_client(), ia_cmd, true)?;
|
||||||
|
|
||||||
Ok(resp.data().map(|d| d.to_vec())?)
|
Ok(resp.data().map(|d| d.to_vec())?)
|
||||||
}
|
}
|
||||||
|
@ -571,31 +560,29 @@ impl CardApp {
|
||||||
assert!((1..=4).contains(&num));
|
assert!((1..=4).contains(&num));
|
||||||
|
|
||||||
let cmd = commands::put_private_do(num, data);
|
let cmd = commands::put_private_do(num, data);
|
||||||
let resp = apdu::send_command(&mut self.card_client, cmd, true)?;
|
let resp = apdu::send_command(self.card_client(), cmd, true)?;
|
||||||
|
|
||||||
Ok(resp.data()?.to_vec())
|
Ok(resp.data()?.to_vec())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_name(&mut self, name: &str) -> Result<Response, Error> {
|
pub fn set_name(&mut self, 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(&mut self.card_client, put_name, false)?.try_into()
|
apdu::send_command(self.card_client(), put_name, false)?.try_into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_lang(&mut self, lang: &str) -> Result<Response, Error> {
|
pub fn set_lang(&mut self, 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.borrow_mut(), put_lang, false)?
|
apdu::send_command(self.card_client(), put_lang, false)?.try_into()
|
||||||
.try_into()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_sex(&mut self, sex: Sex) -> Result<Response, Error> {
|
pub fn set_sex(&mut self, 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.borrow_mut(), put_sex, false)?
|
apdu::send_command(self.card_client(), put_sex, false)?.try_into()
|
||||||
.try_into()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_url(&mut self, url: &str) -> Result<Response, Error> {
|
pub fn set_url(&mut self, 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(&mut self.card_client, put_url, false)?.try_into()
|
apdu::send_command(self.card_client(), put_url, false)?.try_into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_creation_time(
|
pub fn set_creation_time(
|
||||||
|
@ -617,7 +604,7 @@ impl CardApp {
|
||||||
time_value,
|
time_value,
|
||||||
);
|
);
|
||||||
|
|
||||||
apdu::send_command(&mut self.card_client, time_cmd, false)?.try_into()
|
apdu::send_command(self.card_client(), time_cmd, false)?.try_into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_fingerprint(
|
pub fn set_fingerprint(
|
||||||
|
@ -630,7 +617,7 @@ impl CardApp {
|
||||||
fp.as_bytes().to_vec(),
|
fp.as_bytes().to_vec(),
|
||||||
);
|
);
|
||||||
|
|
||||||
apdu::send_command(self.get_card_client(), fp_cmd, false)?.try_into()
|
apdu::send_command(self.card_client(), fp_cmd, false)?.try_into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set PW Status Bytes.
|
/// Set PW Status Bytes.
|
||||||
|
@ -652,7 +639,7 @@ impl CardApp {
|
||||||
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.get_card_client(), cmd, false)?.try_into()
|
apdu::send_command(self.card_client(), cmd, false)?.try_into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set cardholder certificate (for AUT, DEC or SIG).
|
/// Set cardholder certificate (for AUT, DEC or SIG).
|
||||||
|
@ -664,7 +651,7 @@ impl CardApp {
|
||||||
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(&mut self.card_client, cmd, false)?.try_into()
|
apdu::send_command(self.card_client(), cmd, false)?.try_into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set algorithm attributes
|
/// Set algorithm attributes
|
||||||
|
@ -680,7 +667,7 @@ impl CardApp {
|
||||||
algo.get_data()?,
|
algo.get_data()?,
|
||||||
);
|
);
|
||||||
|
|
||||||
apdu::send_command(&mut self.card_client, cmd, false)?.try_into()
|
apdu::send_command(self.card_client(), cmd, false)?.try_into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set resetting code
|
/// Set resetting code
|
||||||
|
@ -690,7 +677,7 @@ impl CardApp {
|
||||||
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(&mut self.card_client, cmd, false)?.try_into()
|
apdu::send_command(self.card_client(), cmd, false)?.try_into()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Import an existing private key to the card.
|
/// Import an existing private key to the card.
|
||||||
|
|
|
@ -135,9 +135,7 @@ pub(crate) fn generate_asymmetric_key_pair(
|
||||||
let crt = get_crt(key_type)?;
|
let crt = get_crt(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 card_client = card_app.get_card_client();
|
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()?)?;
|
||||||
|
@ -164,7 +162,7 @@ pub(crate) fn get_pub_key(
|
||||||
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_app.get_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()?)?;
|
||||||
|
@ -216,8 +214,7 @@ pub(crate) fn key_import(
|
||||||
card_app.set_algorithm_attributes(key_type, &algo)?;
|
card_app.set_algorithm_attributes(key_type, &algo)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
apdu::send_command(card_app.get_card_client(), key_cmd, false)?
|
apdu::send_command(card_app.card_client(), key_cmd, false)?.check_ok()?;
|
||||||
.check_ok()?;
|
|
||||||
card_app.set_fingerprint(fp, key_type)?;
|
card_app.set_fingerprint(fp, key_type)?;
|
||||||
card_app.set_creation_time(key.get_ts(), key_type)?;
|
card_app.set_creation_time(key.get_ts(), key_type)?;
|
||||||
|
|
||||||
|
|
|
@ -25,10 +25,8 @@
|
||||||
//! crate offers a higher level wrapper based on the
|
//! crate offers a higher level wrapper based on the
|
||||||
//! [Sequoia PGP](https://sequoia-pgp.org/) implementation.
|
//! [Sequoia PGP](https://sequoia-pgp.org/) implementation.
|
||||||
|
|
||||||
use anyhow::Result;
|
|
||||||
|
|
||||||
pub mod algorithm;
|
pub mod algorithm;
|
||||||
mod apdu;
|
pub(crate) mod apdu;
|
||||||
mod card_app;
|
mod card_app;
|
||||||
pub mod card_do;
|
pub mod card_do;
|
||||||
pub mod crypto_data;
|
pub mod crypto_data;
|
||||||
|
@ -40,6 +38,11 @@ pub use crate::apdu::response::Response;
|
||||||
pub use crate::card_app::CardApp;
|
pub use crate::card_app::CardApp;
|
||||||
pub use crate::errors::{Error, SmartcardError, StatusBytes};
|
pub use crate::errors::{Error, SmartcardError, StatusBytes};
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
use std::convert::TryInto;
|
||||||
|
|
||||||
|
use crate::apdu::commands;
|
||||||
|
|
||||||
/// The CardClient trait defines communication with an OpenPGP card via a
|
/// The CardClient trait defines communication with an OpenPGP card via a
|
||||||
/// backend implementation (e.g. the pcsc backend in the crate
|
/// backend implementation (e.g. the pcsc backend in the crate
|
||||||
/// [openpgp-card-pcsc](https://crates.io/crates/openpgp-card-pcsc)).
|
/// [openpgp-card-pcsc](https://crates.io/crates/openpgp-card-pcsc)).
|
||||||
|
@ -75,6 +78,14 @@ pub trait CardClient {
|
||||||
/// A boxed CardClient (which is Send+Sync).
|
/// A boxed CardClient (which is Send+Sync).
|
||||||
pub type CardClientBox = Box<dyn CardClient + Send + Sync>;
|
pub type CardClientBox = Box<dyn CardClient + Send + Sync>;
|
||||||
|
|
||||||
|
impl dyn CardClient {
|
||||||
|
/// Select the OpenPGP card application
|
||||||
|
pub fn select(&mut self) -> Result<Response, Error> {
|
||||||
|
let select_openpgp = commands::select_openpgp();
|
||||||
|
apdu::send_command(self, select_openpgp, false)?.try_into()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Configuration of the capabilities of the card.
|
/// Configuration of the capabilities of the card.
|
||||||
///
|
///
|
||||||
/// This configuration is used to determine e.g. if chaining or extended
|
/// This configuration is used to determine e.g. if chaining or extended
|
||||||
|
|
|
@ -4,9 +4,7 @@
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use pcsc::{Card, Context, Protocols, Scope, ShareMode};
|
use pcsc::{Card, Context, Protocols, Scope, ShareMode};
|
||||||
|
|
||||||
use openpgp_card::{
|
use openpgp_card::{CardApp, CardCaps, CardClient, Error, SmartcardError};
|
||||||
CardApp, CardCaps, CardClient, CardClientBox, Error, SmartcardError,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct PcscClient {
|
pub struct PcscClient {
|
||||||
card: Card,
|
card: Card,
|
||||||
|
@ -21,6 +19,11 @@ impl PcscClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get an initialized CardApp from a card
|
||||||
|
fn into_card_app(self) -> Result<CardApp> {
|
||||||
|
CardApp::initialize(Box::new(self))
|
||||||
|
}
|
||||||
|
|
||||||
/// Opened PCSC Cards without selecting the OpenPGP card application
|
/// Opened PCSC Cards without selecting the OpenPGP card application
|
||||||
fn pcsc_cards() -> Result<Vec<Card>, SmartcardError> {
|
fn pcsc_cards() -> Result<Vec<Card>, SmartcardError> {
|
||||||
let ctx = match Context::establish(Scope::User) {
|
let ctx = match Context::establish(Scope::User) {
|
||||||
|
@ -84,56 +87,43 @@ impl PcscClient {
|
||||||
/// Return all cards on which the OpenPGP application could be selected.
|
/// Return all cards on which the OpenPGP application could be selected.
|
||||||
///
|
///
|
||||||
/// Each card is opened and has the OpenPGP application selected.
|
/// Each card is opened and has the OpenPGP application selected.
|
||||||
pub fn cards() -> Result<Vec<CardClientBox>> {
|
/// Cards are initialized via init_caps().
|
||||||
let cards = Self::unopened_cards()?
|
pub fn cards() -> Result<Vec<CardApp>> {
|
||||||
.into_iter()
|
let mut cards = vec![];
|
||||||
.map(Self::select)
|
|
||||||
.map(|res| res.ok())
|
for mut card in Self::unopened_cards()? {
|
||||||
.flatten()
|
if Self::select(&mut card).is_ok() {
|
||||||
.map(|ca| ca.into())
|
if let Ok(ca) = card.into_card_app() {
|
||||||
.collect();
|
cards.push(ca);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(cards)
|
Ok(cards)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Try to select the OpenPGP application on a card
|
/// Try to select the OpenPGP application on a card
|
||||||
fn select(card_client: PcscClient) -> Result<CardApp, Error> {
|
fn select(card_client: &mut PcscClient) -> Result<(), Error> {
|
||||||
let ccb = Box::new(card_client) as CardClientBox;
|
if <dyn CardClient>::select(card_client).is_ok() {
|
||||||
|
Ok(())
|
||||||
let mut ca = CardApp::from(ccb);
|
|
||||||
if ca.select().is_ok() {
|
|
||||||
Ok(ca)
|
|
||||||
} else {
|
} else {
|
||||||
Err(Error::Smartcard(SmartcardError::SelectOpenPGPCardFailed))
|
Err(Error::Smartcard(SmartcardError::SelectOpenPGPCardFailed))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get application related data from the card and check if 'ident'
|
|
||||||
/// matches
|
|
||||||
fn match_by_ident(
|
|
||||||
mut ca: CardApp,
|
|
||||||
ident: &str,
|
|
||||||
) -> Result<Option<CardClientBox>, Error> {
|
|
||||||
let ard = ca.get_application_related_data()?;
|
|
||||||
let aid = ard.get_application_id()?;
|
|
||||||
|
|
||||||
if aid.ident() == ident {
|
|
||||||
Ok(Some(ca.into()))
|
|
||||||
} else {
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the OpenPGP card that matches `ident`, if it is available.
|
/// Returns the OpenPGP card that matches `ident`, if it is available.
|
||||||
/// The OpenPGP application of the `CardClientBox` has been selected.
|
/// A fully initialized CardApp is returned: application has been
|
||||||
pub fn open_by_ident(ident: &str) -> Result<CardClientBox, Error> {
|
/// selected, init_caps() has been performed.
|
||||||
for card in Self::unopened_cards()? {
|
pub fn open_by_ident(ident: &str) -> Result<CardApp, Error> {
|
||||||
if let Ok(ca) = Self::select(card) {
|
for mut card in Self::unopened_cards()? {
|
||||||
if let Some(matched_card) =
|
Self::select(&mut card)?;
|
||||||
PcscClient::match_by_ident(ca, ident)?
|
let mut ca = card.into_card_app()?;
|
||||||
{
|
|
||||||
return Ok(matched_card);
|
let ard = ca.get_application_related_data()?;
|
||||||
}
|
let aid = ard.get_application_id()?;
|
||||||
|
|
||||||
|
if aid.ident() == ident {
|
||||||
|
return Ok(ca);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ use sequoia_ipc::gnupg::{Agent, Context};
|
||||||
use std::sync::Mutex;
|
use std::sync::Mutex;
|
||||||
use tokio::runtime::Runtime;
|
use tokio::runtime::Runtime;
|
||||||
|
|
||||||
use openpgp_card::Error;
|
use openpgp_card::{CardApp, Error};
|
||||||
use openpgp_card::{CardCaps, CardClient, CardClientBox};
|
use openpgp_card::{CardCaps, CardClient, CardClientBox};
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
|
@ -118,11 +118,11 @@ impl ScdClient {
|
||||||
pub fn open_by_serial(
|
pub fn open_by_serial(
|
||||||
agent: Option<Agent>,
|
agent: Option<Agent>,
|
||||||
serial: &str,
|
serial: &str,
|
||||||
) -> Result<CardClientBox, Error> {
|
) -> Result<CardApp, Error> {
|
||||||
let mut card = ScdClient::new(agent, true)?;
|
let mut card = ScdClient::new(agent, true)?;
|
||||||
card.select_card(serial)?;
|
card.select_card(serial)?;
|
||||||
|
|
||||||
Ok(Box::new(card) as CardClientBox)
|
Ok(CardApp::initialize(Box::new(card))?)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ask scdameon to switch to using a specific OpenPGP card, based on
|
/// Ask scdameon to switch to using a specific OpenPGP card, based on
|
||||||
|
|
|
@ -13,7 +13,7 @@ mod cli;
|
||||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let cli = cli::Cli::from_args();
|
let cli = cli::Cli::from_args();
|
||||||
|
|
||||||
let mut card = PcscClient::open_by_ident(&cli.ident)?.into();
|
let mut card = PcscClient::open_by_ident(&cli.ident)?;
|
||||||
let mut open = Open::open(&mut card)?;
|
let mut open = Open::open(&mut card)?;
|
||||||
|
|
||||||
match cli.cmd {
|
match cli.cmd {
|
||||||
|
@ -145,15 +145,13 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
let res = if let Some(rst) = rst {
|
let res = if let Some(rst) = rst {
|
||||||
// reset to new user pin
|
// reset to new user pin
|
||||||
open.reset_user_pin(&rst, &newpin1)
|
open.reset_user_pin(&rst, &newpin1)
|
||||||
|
} else if let Some(mut admin) = open.admin_card() {
|
||||||
|
admin.reset_user_pin(&newpin1)
|
||||||
} else {
|
} else {
|
||||||
if let Some(mut admin) = open.admin_card() {
|
return Err(anyhow::anyhow!(
|
||||||
admin.reset_user_pin(&newpin1)
|
"Failed to use card in admin-mode."
|
||||||
} else {
|
)
|
||||||
return Err(anyhow::anyhow!(
|
.into());
|
||||||
"Failed to use card in admin-mode."
|
|
||||||
)
|
|
||||||
.into());
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if res.is_err() {
|
if res.is_err() {
|
||||||
|
|
|
@ -71,7 +71,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
admin_pin,
|
admin_pin,
|
||||||
cmd,
|
cmd,
|
||||||
} => {
|
} => {
|
||||||
let mut card = util::open_card(&ident)?.into();
|
let mut card = util::open_card(&ident)?;
|
||||||
let mut open = Open::open(&mut card)?;
|
let mut open = Open::open(&mut card)?;
|
||||||
|
|
||||||
match cmd {
|
match cmd {
|
||||||
|
@ -137,8 +137,7 @@ fn list_cards() -> Result<()> {
|
||||||
if !cards.is_empty() {
|
if !cards.is_empty() {
|
||||||
println!("Available OpenPGP cards:");
|
println!("Available OpenPGP cards:");
|
||||||
|
|
||||||
for card in cards {
|
for mut card in cards {
|
||||||
let mut card = card.into();
|
|
||||||
let open = Open::open(&mut card)?;
|
let open = Open::open(&mut card)?;
|
||||||
println!(" {}", open.application_identifier()?.ident());
|
println!(" {}", open.application_identifier()?.ident());
|
||||||
}
|
}
|
||||||
|
@ -149,18 +148,17 @@ fn list_cards() -> Result<()> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn print_status(ident: Option<String>, verbose: bool) -> Result<()> {
|
fn print_status(ident: Option<String>, verbose: bool) -> Result<()> {
|
||||||
let ccb = if let Some(ident) = ident {
|
let mut ca = if let Some(ident) = ident {
|
||||||
util::open_card(&ident)?
|
util::open_card(&ident)?
|
||||||
} else {
|
} else {
|
||||||
let mut cards = util::cards()?;
|
let mut cards = util::cards()?;
|
||||||
if cards.len() == 1 {
|
if cards.len() == 1 {
|
||||||
cards.pop().unwrap()
|
cards.pop().unwrap()
|
||||||
} else {
|
} else {
|
||||||
return Err(anyhow::anyhow!("Found {} cards", cards.len()).into());
|
return Err(anyhow::anyhow!("Found {} cards", cards.len()));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let mut card = ccb.into();
|
let mut open = Open::open(&mut ca)?;
|
||||||
let mut open = Open::open(&mut card)?;
|
|
||||||
|
|
||||||
print!("OpenPGP card {}", open.application_identifier()?.ident());
|
print!("OpenPGP card {}", open.application_identifier()?.ident());
|
||||||
|
|
||||||
|
@ -291,10 +289,10 @@ fn decrypt(
|
||||||
|
|
||||||
let input = util::open_or_stdin(input.as_deref())?;
|
let input = util::open_or_stdin(input.as_deref())?;
|
||||||
|
|
||||||
let mut card = util::open_card(&ident)?.into();
|
let mut card = util::open_card(ident)?;
|
||||||
let mut open = Open::open(&mut card)?;
|
let mut open = Open::open(&mut card)?;
|
||||||
|
|
||||||
let mut user = util::get_user(&mut open, &pin_file)?;
|
let mut user = util::get_user(&mut open, pin_file)?;
|
||||||
let d = user.decryptor(&cert, &p)?;
|
let d = user.decryptor(&cert, &p)?;
|
||||||
|
|
||||||
let db = DecryptorBuilder::from_reader(input)?;
|
let db = DecryptorBuilder::from_reader(input)?;
|
||||||
|
@ -316,10 +314,10 @@ fn sign_detached(
|
||||||
|
|
||||||
let mut input = util::open_or_stdin(input.as_deref())?;
|
let mut input = util::open_or_stdin(input.as_deref())?;
|
||||||
|
|
||||||
let mut card = util::open_card(&ident)?.into();
|
let mut card = util::open_card(ident)?;
|
||||||
let mut open = Open::open(&mut card)?;
|
let mut open = Open::open(&mut card)?;
|
||||||
|
|
||||||
let mut sign = util::get_sign(&mut open, &pin_file)?;
|
let mut sign = util::get_sign(&mut open, pin_file)?;
|
||||||
let s = sign.signer(&cert, &p)?;
|
let s = sign.signer(&cert, &p)?;
|
||||||
|
|
||||||
let message = Armorer::new(Message::new(std::io::stdout())).build()?;
|
let message = Armorer::new(Message::new(std::io::stdout())).build()?;
|
||||||
|
@ -333,7 +331,7 @@ fn sign_detached(
|
||||||
|
|
||||||
fn factory_reset(ident: &str) -> Result<()> {
|
fn factory_reset(ident: &str) -> Result<()> {
|
||||||
println!("Resetting Card {}", ident);
|
println!("Resetting Card {}", ident);
|
||||||
let mut card = util::open_card(ident)?.into();
|
let mut card = util::open_card(ident)?;
|
||||||
Open::open(&mut card)?.factory_reset()
|
Open::open(&mut card)?.factory_reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -341,16 +339,16 @@ fn key_import_yolo(mut admin: Admin, key: &Cert) -> Result<()> {
|
||||||
let p = StandardPolicy::new();
|
let p = StandardPolicy::new();
|
||||||
|
|
||||||
let sig =
|
let sig =
|
||||||
openpgp_card_sequoia::sq_util::get_subkey(&key, &p, KeyType::Signing)?;
|
openpgp_card_sequoia::sq_util::get_subkey(key, &p, KeyType::Signing)?;
|
||||||
|
|
||||||
let dec = openpgp_card_sequoia::sq_util::get_subkey(
|
let dec = openpgp_card_sequoia::sq_util::get_subkey(
|
||||||
&key,
|
key,
|
||||||
&p,
|
&p,
|
||||||
KeyType::Decryption,
|
KeyType::Decryption,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let auth = openpgp_card_sequoia::sq_util::get_subkey(
|
let auth = openpgp_card_sequoia::sq_util::get_subkey(
|
||||||
&key,
|
key,
|
||||||
&p,
|
&p,
|
||||||
KeyType::Authentication,
|
KeyType::Authentication,
|
||||||
)?;
|
)?;
|
||||||
|
@ -382,7 +380,7 @@ fn key_import_explicit(
|
||||||
|
|
||||||
if let Some(sig_fp) = sig_fp {
|
if let Some(sig_fp) = sig_fp {
|
||||||
if let Some(sig) =
|
if let Some(sig) =
|
||||||
sq_util::get_subkey_by_fingerprint(&key, &p, &sig_fp)?
|
sq_util::get_subkey_by_fingerprint(key, &p, &sig_fp)?
|
||||||
{
|
{
|
||||||
println!("Uploading {} as signing key", sig.fingerprint());
|
println!("Uploading {} as signing key", sig.fingerprint());
|
||||||
admin.upload_key(sig, KeyType::Signing, None)?;
|
admin.upload_key(sig, KeyType::Signing, None)?;
|
||||||
|
@ -393,7 +391,7 @@ fn key_import_explicit(
|
||||||
|
|
||||||
if let Some(dec_fp) = dec_fp {
|
if let Some(dec_fp) = dec_fp {
|
||||||
if let Some(dec) =
|
if let Some(dec) =
|
||||||
sq_util::get_subkey_by_fingerprint(&key, &p, &dec_fp)?
|
sq_util::get_subkey_by_fingerprint(key, &p, &dec_fp)?
|
||||||
{
|
{
|
||||||
println!("Uploading {} as decryption key", dec.fingerprint());
|
println!("Uploading {} as decryption key", dec.fingerprint());
|
||||||
admin.upload_key(dec, KeyType::Decryption, None)?;
|
admin.upload_key(dec, KeyType::Decryption, None)?;
|
||||||
|
@ -404,7 +402,7 @@ fn key_import_explicit(
|
||||||
|
|
||||||
if let Some(auth_fp) = auth_fp {
|
if let Some(auth_fp) = auth_fp {
|
||||||
if let Some(auth) =
|
if let Some(auth) =
|
||||||
sq_util::get_subkey_by_fingerprint(&key, &p, &auth_fp)?
|
sq_util::get_subkey_by_fingerprint(key, &p, &auth_fp)?
|
||||||
{
|
{
|
||||||
println!("Uploading {} as authentication key", auth.fingerprint());
|
println!("Uploading {} as authentication key", auth.fingerprint());
|
||||||
admin.upload_key(auth, KeyType::Authentication, None)?;
|
admin.upload_key(auth, KeyType::Authentication, None)?;
|
||||||
|
@ -478,7 +476,7 @@ fn generate_keys(
|
||||||
|
|
||||||
// Write armored certificate to the output file (or stdout)
|
// Write armored certificate to the output file (or stdout)
|
||||||
let mut output = util::open_or_stdout(output.as_deref())?;
|
let mut output = util::open_or_stdout(output.as_deref())?;
|
||||||
output.write(armored.as_bytes())?;
|
output.write_all(armored.as_bytes())?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -519,7 +517,7 @@ fn gen_subkeys(
|
||||||
// If none of them work, fail and return all errors
|
// If none of them work, fail and return all errors
|
||||||
|
|
||||||
for (n, alg) in algos.iter().enumerate() {
|
for (n, alg) in algos.iter().enumerate() {
|
||||||
let a = Some(alg.clone());
|
let a = Some(*alg);
|
||||||
|
|
||||||
log::info!(" Trying key generation with algo {:?}", alg);
|
log::info!(" Trying key generation with algo {:?}", alg);
|
||||||
|
|
||||||
|
|
|
@ -3,16 +3,16 @@
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
|
|
||||||
use openpgp_card::{CardClientBox, Error};
|
use openpgp_card::{CardApp, Error};
|
||||||
use openpgp_card_pcsc::PcscClient;
|
use openpgp_card_pcsc::PcscClient;
|
||||||
use openpgp_card_sequoia::card::{Admin, Open, Sign, User};
|
use openpgp_card_sequoia::card::{Admin, Open, Sign, User};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
pub(crate) fn cards() -> Result<Vec<CardClientBox>> {
|
pub(crate) fn cards() -> Result<Vec<CardApp>> {
|
||||||
PcscClient::cards()
|
PcscClient::cards()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn open_card(ident: &str) -> Result<CardClientBox, Error> {
|
pub(crate) fn open_card(ident: &str) -> Result<CardApp, Error> {
|
||||||
PcscClient::open_by_ident(ident)
|
PcscClient::open_by_ident(ident)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue