Refactor "Open" to use a borrowed CardApp (instead of owning the CardApp).

This commit is contained in:
Heiko Schaefer 2021-11-02 21:31:15 +01:00
parent 8dd83b6c55
commit 8674b0e65c
11 changed files with 218 additions and 165 deletions

View file

@ -9,8 +9,9 @@ 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 card in PcscClient::cards()? { for ccb in PcscClient::cards()? {
let open = Open::open_card(card)?; let mut ca = ccb.into();
let open = Open::open(&mut ca)?;
println!(" {}", open.application_identifier()?.ident()); println!(" {}", open.application_identifier()?.ident());
} }

View file

@ -15,6 +15,7 @@ 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, Error, KeyType, StatusBytes};
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,
}; };
@ -220,7 +221,7 @@ 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(
ca: &mut CardApp, mut ca: &mut CardApp,
param: &[&str], param: &[&str],
) -> Result<TestOutput, TestError> { ) -> Result<TestOutput, TestError> {
ca.verify_pw3("12345678")?; ca.verify_pw3("12345678")?;
@ -253,8 +254,9 @@ 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::open(&mut ca)?;
let cert = make_cert(ca, key_sig, key_dec, key_aut)?; let cert =
make_cert(&mut open, key_sig, Some(key_dec), Some(key_aut), "123456")?;
let armored = String::from_utf8(cert.armored().to_vec()?)?; let armored = String::from_utf8(cert.armored().to_vec()?)?;
let res = TestResult::Text(armored); let res = TestResult::Text(armored);

View file

@ -22,7 +22,8 @@ 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 open = Open::open_card(PcscClient::open_by_ident(&card_ident)?)?; let mut ca = PcscClient::open_by_ident(&card_ident)?.into();
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)?;

View file

@ -19,12 +19,12 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
return Ok(()); return Ok(());
} }
let test_card_ident = &args[0]; let card_ident = &args[0];
let pin_file = &args[1]; let pin_file = &args[1];
let cert_file = &args[2]; let cert_file = &args[2];
let mut open = let mut ca = PcscClient::open_by_ident(&card_ident)?.into();
Open::open_card(PcscClient::open_by_ident(&test_card_ident)?)?; 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)?;

View file

@ -11,7 +11,7 @@ use sequoia_openpgp::packet::key::SecretParts;
use sequoia_openpgp::policy::Policy; use sequoia_openpgp::policy::Policy;
use sequoia_openpgp::Cert; use sequoia_openpgp::Cert;
use openpgp_card::algorithm::{Algo, AlgoInfo}; use openpgp_card::algorithm::{Algo, AlgoInfo, AlgoSimple};
use openpgp_card::card_do::{ use openpgp_card::card_do::{
ApplicationIdentifier, ApplicationRelatedData, CardholderRelatedData, ApplicationIdentifier, ApplicationRelatedData, CardholderRelatedData,
ExtendedCapabilities, ExtendedLengthInfo, Fingerprint, HistoricalBytes, ExtendedCapabilities, ExtendedLengthInfo, Fingerprint, HistoricalBytes,
@ -21,12 +21,14 @@ use openpgp_card::{CardApp, CardClientBox, Error, KeySet, KeyType, Response};
use crate::decryptor::CardDecryptor; use crate::decryptor::CardDecryptor;
use crate::signer::CardSigner; use crate::signer::CardSigner;
use crate::util::vka_as_uploadable_key; use crate::util::{public_to_fingerprint, vka_as_uploadable_key};
use crate::PublicKey;
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 { pub struct Open<'a> {
card_app: CardApp, card_app: &'a mut CardApp,
// Cache of "application related data". // Cache of "application related data".
// //
@ -44,8 +46,16 @@ pub struct Open {
pw3: bool, pw3: bool,
} }
impl Open { impl<'a> Open<'a> {
fn new(card_app: CardApp, ard: ApplicationRelatedData) -> Self { pub fn open(card_app: &'a mut CardApp) -> Result<Self, Error> {
let ard = card_app.get_application_related_data()?;
card_app.init_caps(&ard)?;
Ok(Self::new(card_app, ard))
}
fn new(card_app: &'a mut CardApp, ard: ApplicationRelatedData) -> Self {
Self { Self {
card_app, card_app,
ard, ard,
@ -55,21 +65,6 @@ impl Open {
} }
} }
/// Set up connection to a CardClient (read and cache "application
/// related data").
///
/// The OpenPGP applet must already be opened in the CardClient.
pub fn open_card(ccb: CardClientBox) -> Result<Self, Error> {
// read and cache "application related data"
let mut card_app = CardApp::from(ccb);
let ard = card_app.get_application_related_data()?;
card_app.init_caps(&ard)?;
Ok(Self::new(card_app, ard))
}
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 _ = self.card_app.verify_pw1(pin)?;
self.pw1 = true; self.pw1 = true;
@ -131,7 +126,7 @@ impl Open {
} }
/// Get a view of the card authenticated for "User" commands. /// Get a view of the card authenticated for "User" commands.
pub fn user_card(&mut self) -> Option<User> { pub fn user_card<'b>(&'a mut self) -> Option<User<'a, 'b>> {
if self.pw1 { if self.pw1 {
Some(User { oc: self }) Some(User { oc: self })
} else { } else {
@ -140,7 +135,7 @@ impl Open {
} }
/// Get a view of the card authenticated for Signing. /// Get a view of the card authenticated for Signing.
pub fn signing_card(&mut self) -> Option<Sign> { pub fn signing_card<'b>(&'b mut self) -> Option<Sign<'a, 'b>> {
if self.pw1_sign { if self.pw1_sign {
Some(Sign { oc: self }) Some(Sign { oc: self })
} else { } else {
@ -149,7 +144,7 @@ impl Open {
} }
/// Get a view of the card authenticated for "Admin" commands. /// Get a view of the card authenticated for "Admin" commands.
pub fn admin_card(&mut self) -> Option<Admin> { pub fn admin_card<'b>(&'b mut self) -> Option<Admin<'a, 'b>> {
if self.pw3 { if self.pw3 {
Some(Admin { oc: self }) Some(Admin { oc: self })
} else { } else {
@ -288,11 +283,11 @@ impl Open {
/// An OpenPGP card after successfully verifying PW1 in mode 82 /// An OpenPGP card after successfully verifying PW1 in mode 82
/// (verification for user operations other than signing) /// (verification for user operations other than signing)
pub struct User<'a> { pub struct User<'app, 'open> {
oc: &'a mut Open, oc: &'open mut Open<'app>,
} }
impl User<'_> { impl User<'_, '_> {
pub fn decryptor( pub fn decryptor(
&mut self, &mut self,
cert: &Cert, cert: &Cert,
@ -304,11 +299,11 @@ impl User<'_> {
/// An OpenPGP card after successfully verifying PW1 in mode 81 /// An OpenPGP card after successfully verifying PW1 in mode 81
/// (verification for signing) /// (verification for signing)
pub struct Sign<'a> { pub struct Sign<'app, 'open> {
oc: &'a mut Open, oc: &'open mut Open<'app>,
} }
impl Sign<'_> { impl Sign<'_, '_> {
pub fn signer( pub fn signer(
&mut self, &mut self,
cert: &Cert, cert: &Cert,
@ -319,14 +314,27 @@ impl Sign<'_> {
CardSigner::new(&mut self.oc.card_app, cert, policy) CardSigner::new(&mut self.oc.card_app, cert, policy)
} }
pub fn signer_from_pubkey(&mut self, pubkey: PublicKey) -> CardSigner {
// FIXME: depending on the setting in "PW1 Status byte", only one
// signature can be made after verification for signing
CardSigner::with_pubkey(&mut self.oc.card_app, pubkey)
}
} }
/// An OpenPGP card after successful verification of PW3 ("Admin privileges") /// An OpenPGP card after successful verification of PW3 ("Admin privileges")
pub struct Admin<'a> { pub struct Admin<'app, 'open> {
oc: &'a mut Open, oc: &'open mut Open<'app>,
} }
impl Admin<'_> { impl<'app, 'open> Admin<'app, 'open> {
pub fn get_open(&'_ mut self) -> &mut Open<'app> {
self.oc
}
}
impl Admin<'_, '_> {
pub fn set_name(&mut self, name: &str) -> Result<Response, Error> { pub fn set_name(&mut self, name: &str) -> Result<Response, Error> {
if name.len() >= 40 { if name.len() >= 40 {
return Err(anyhow!("name too long").into()); return Err(anyhow!("name too long").into());
@ -396,4 +404,16 @@ impl Admin<'_> {
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) self.oc.card_app.key_import(key, key_type)
} }
pub fn generate_key_simple(
&mut self,
key_type: KeyType,
algo: AlgoSimple,
) -> Result<(PublicKeyMaterial, KeyGenerationTime), Error> {
self.oc.card_app.generate_key_simple(
public_to_fingerprint,
key_type,
algo,
)
}
} }

View file

@ -17,7 +17,8 @@
//! //!
//! # fn main() -> Result<(), Box<dyn std::error::Error>> { //! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! for card in PcscClient::cards()? { //! for card in PcscClient::cards()? {
//! let open = Open::open_card(card)?; //! let mut ca = card.into();
//! let open = Open::open(&mut ca)?;
//! println!("Found OpenPGP card with ident '{}'", //! println!("Found OpenPGP card with ident '{}'",
//! open.application_identifier()?.ident()); //! open.application_identifier()?.ident());
//! } //! }
@ -32,8 +33,8 @@
//! use openpgp_card_sequoia::card::Open; //! use openpgp_card_sequoia::card::Open;
//! //!
//! # fn main() -> Result<(), Box<dyn std::error::Error>> { //! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let card = PcscClient::open_by_ident("abcd:12345678")?; //! let mut ca = PcscClient::open_by_ident("abcd:12345678")?.into();
//! let mut open = Open::open_card(card)?; //! let mut open = Open::open(&mut ca)?;
//! # Ok(()) //! # Ok(())
//! # } //! # }
//! ``` //! ```
@ -54,8 +55,8 @@
//! # fn main() -> Result<(), Box<dyn std::error::Error>> { //! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! // Open card via PCSC //! // Open card via PCSC
//! use sequoia_openpgp::policy::StandardPolicy; //! use sequoia_openpgp::policy::StandardPolicy;
//! let card = PcscClient::open_by_ident("abcd:12345678")?; //! let mut ca = PcscClient::open_by_ident("abcd:12345678")?.into();
//! let mut open = Open::open_card(card)?; //! let mut open = Open::open(&mut ca)?;
//! //!
//! // Get authorization for user access to the card with password //! // Get authorization for user access to the card with password
//! open.verify_user("123456")?; //! open.verify_user("123456")?;
@ -95,8 +96,8 @@
//! # fn main() -> Result<(), Box<dyn std::error::Error>> { //! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! // Open card via PCSC //! // Open card via PCSC
//! use sequoia_openpgp::policy::StandardPolicy; //! use sequoia_openpgp::policy::StandardPolicy;
//! let card = PcscClient::open_by_ident("abcd:12345678")?; //! let mut ca = PcscClient::open_by_ident("abcd:12345678")?.into();
//! let mut open = Open::open_card(card)?; //! let mut open = Open::open(&mut ca)?;
//! //!
//! // Get authorization for signing access to the card with password //! // Get authorization for signing access to the card with password
//! open.verify_user_for_signing("123456")?; //! open.verify_user_for_signing("123456")?;
@ -125,8 +126,8 @@
//! //!
//! # fn main() -> Result<(), Box<dyn std::error::Error>> { //! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! // Open card via PCSC //! // Open card via PCSC
//! let card = PcscClient::open_by_ident("abcd:12345678")?; //! let mut ca = PcscClient::open_by_ident("abcd:12345678")?.into();
//! let mut open = Open::open_card(card)?; //! let mut open = Open::open(&mut ca)?;
//! //!
//! // Get authorization for admin access to the card with password //! // Get authorization for admin access to the card with password
//! open.verify_admin("12345678")?; //! open.verify_admin("12345678")?;

View file

@ -21,6 +21,7 @@ use openpgp_card_sequoia::sq_util::{decryption_helper, sign_helper};
// const TEST_KEY_PATH: &str = "example/test4k.sec"; // const TEST_KEY_PATH: &str = "example/test4k.sec";
// const TEST_ENC_MSG: &str = "example/encrypted_to_rsa4k.asc"; // const TEST_ENC_MSG: &str = "example/encrypted_to_rsa4k.asc";
// const TEST_KEY_PATH: &str = "example/nist521.sec";
// const TEST_KEY_PATH: &str = "example/nist521.sec"; // const TEST_KEY_PATH: &str = "example/nist521.sec";
// const TEST_ENC_MSG: &str = "example/encrypted_to_nist521.asc"; // const TEST_ENC_MSG: &str = "example/encrypted_to_nist521.asc";
@ -34,8 +35,8 @@ 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 open = let mut card = PcscClient::open_by_ident(&test_card_ident)?.into();
Open::open_card(PcscClient::open_by_ident(&test_card_ident)?)?; let mut open = Open::open(&mut card)?;
// card metadata // card metadata
@ -149,9 +150,8 @@ 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 open = let mut open = Open::open(&mut card)?;
Open::open_card(PcscClient::open_by_ident(&test_card_ident)?)?;
// Check that we're still using the expected card // Check that we're still using the expected card
let app_id = open.application_identifier()?; let app_id = open.application_identifier()?;
@ -189,8 +189,8 @@ fn main() -> Result<(), Box<dyn Error>> {
// ----------------------------- // -----------------------------
// Open fresh Card for signing // Open fresh Card for signing
// ----------------------------- // -----------------------------
let mut open = let mut card = PcscClient::open_by_ident(&test_card_ident)?.into();
Open::open_card(PcscClient::open_by_ident(&test_card_ident)?)?; let mut open = Open::open(&mut card)?;
// Sign // Sign
open.verify_user_for_signing("123456")?; open.verify_user_for_signing("123456")?;
@ -220,7 +220,8 @@ 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 card in PcscClient::cards()? {
let open = Open::open_card(card)?; let mut card = card.into();
let open = Open::open(&mut card)?;
println!(" {}", open.application_identifier()?.ident()); println!(" {}", open.application_identifier()?.ident());
} }
} }

View file

@ -30,6 +30,7 @@ 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::{CardApp, Error, KeyType};
use crate::card::Open;
use crate::privkey::SequoiaKey; use crate::privkey::SequoiaKey;
use crate::signer::CardSigner; use crate::signer::CardSigner;
use crate::{decryptor, signer, PublicKey}; use crate::{decryptor, signer, PublicKey};
@ -37,16 +38,13 @@ use crate::{decryptor, signer, PublicKey};
/// Create a Cert from the three subkeys on a card. /// Create a Cert from the three subkeys on a card.
/// (Calling this multiple times will result in different Certs!) /// (Calling this multiple times will result in different Certs!)
/// ///
/// FIXME: contains hardcoded default passwords!
///
/// FIXME: make dec/auth keys optional
///
/// FIXME: accept optional metadata for user_id(s)? /// FIXME: accept optional metadata for user_id(s)?
pub fn make_cert( pub fn make_cert<'a, 'app>(
ca: &mut CardApp, open: &'a mut Open<'app>,
key_sig: PublicKey, key_sig: PublicKey,
key_dec: PublicKey, key_dec: Option<PublicKey>,
key_aut: PublicKey, key_aut: Option<PublicKey>,
pw1: &str,
) -> Result<Cert> { ) -> Result<Cert> {
let mut pp = vec![]; let mut pp = vec![];
@ -54,65 +52,74 @@ pub fn make_cert(
let pri = PrimaryRole::convert_key(key_sig.clone()); let pri = PrimaryRole::convert_key(key_sig.clone());
pp.push(Packet::from(pri)); pp.push(Packet::from(pri));
// 2) add decryption key as subkey if let Some(key_dec) = key_dec {
let sub_dec = SubordinateRole::convert_key(key_dec); // 2) add decryption key as subkey
pp.push(Packet::from(sub_dec.clone())); let sub_dec = SubordinateRole::convert_key(key_dec);
pp.push(Packet::from(sub_dec.clone()));
// Temporary version of the cert // Temporary version of the cert
let cert = Cert::try_from(pp.clone())?; let cert = Cert::try_from(pp.clone())?;
// 3) make binding, sign with card -> add // 3) make binding, sign with card -> add
{ {
let signing_builder = let signing_builder =
SignatureBuilder::new(SignatureType::SubkeyBinding) SignatureBuilder::new(SignatureType::SubkeyBinding)
.set_signature_creation_time(SystemTime::now())? .set_signature_creation_time(SystemTime::now())?
.set_key_validity_period(std::time::Duration::new(0, 0))? .set_key_validity_period(std::time::Duration::new(0, 0))?
.set_key_flags( .set_key_flags(
KeyFlags::empty() KeyFlags::empty()
.set_storage_encryption() .set_storage_encryption()
.set_transport_encryption(), .set_transport_encryption(),
)?; )?;
// Allow signing on the card // Allow signing on the card
ca.verify_pw1_for_signing("123456")?; open.verify_user_for_signing(pw1)?;
if let Some(mut sign) = open.signing_card() {
// Card-backed signer for bindings
let mut card_signer = sign.signer_from_pubkey(key_sig.clone());
// Card-backed signer for bindings let signing_bsig: Packet = sub_dec
let mut card_signer = CardSigner::with_pubkey(ca, key_sig.clone()); .bind(&mut card_signer, &cert, signing_builder)?
.into();
let signing_bsig: Packet = sub_dec pp.push(signing_bsig);
.bind(&mut card_signer, &cert, signing_builder)? }
.into(); }
pp.push(signing_bsig);
} }
// 4) add auth subkey if let Some(key_aut) = key_aut {
let sub_aut = SubordinateRole::convert_key(key_aut); // 4) add auth subkey
pp.push(Packet::from(sub_aut.clone())); let sub_aut = SubordinateRole::convert_key(key_aut);
pp.push(Packet::from(sub_aut.clone()));
// 5) make, sign binding -> add // 5) make, sign binding -> add
{ {
let signing_builder = let signing_builder =
SignatureBuilder::new(SignatureType::SubkeyBinding) SignatureBuilder::new(SignatureType::SubkeyBinding)
.set_signature_creation_time(SystemTime::now())? .set_signature_creation_time(SystemTime::now())?
.set_key_validity_period(std::time::Duration::new(0, 0))? .set_key_validity_period(std::time::Duration::new(0, 0))?
.set_key_flags(KeyFlags::empty().set_authentication())?; .set_key_flags(KeyFlags::empty().set_authentication())?;
// Allow signing on the card // Allow signing on the card
ca.verify_pw1_for_signing("123456")?; open.verify_user_for_signing(pw1)?;
if let Some(mut sign) = open.signing_card() {
// Card-backed signer for bindings
let mut card_signer = sign.signer_from_pubkey(key_sig.clone());
// Card-backed signer for bindings // Temporary version of the cert
let mut card_signer = CardSigner::with_pubkey(ca, key_sig.clone()); let cert = Cert::try_from(pp.clone())?;
let signing_bsig: Packet = sub_aut let signing_bsig: Packet = sub_aut
.bind(&mut card_signer, &cert, signing_builder)? .bind(&mut card_signer, &cert, signing_builder)?
.into(); .into();
pp.push(signing_bsig); pp.push(signing_bsig);
}
}
} }
// 6) add user id from name / email // 6) add user id from name / email
let cardholder = ca.get_cardholder_related_data()?; let cardholder = open.cardholder_related_data()?;
// FIXME: process name field? accept email as argument?! // FIXME: process name field? accept email as argument?!
let uid: UserID = let uid: UserID =
@ -132,15 +139,20 @@ pub fn make_cert(
)?; )?;
// Allow signing on the card // Allow signing on the card
ca.verify_pw1_for_signing("123456")?; open.verify_user_for_signing(pw1)?;
// Card-backed signer for bindings if let Some(mut sign) = open.signing_card() {
let mut card_signer = CardSigner::with_pubkey(ca, key_sig); // Card-backed signer for bindings
let mut card_signer = sign.signer_from_pubkey(key_sig);
let signing_bsig: Packet = // Temporary version of the cert
uid.bind(&mut card_signer, &cert, signing_builder)?.into(); let cert = Cert::try_from(pp.clone())?;
pp.push(signing_bsig); let signing_bsig: Packet =
uid.bind(&mut card_signer, &cert, signing_builder)?.into();
pp.push(signing_bsig);
}
} }
Cert::try_from(pp) Cert::try_from(pp)

View file

@ -4,7 +4,7 @@
use anyhow::Result; use anyhow::Result;
use structopt::StructOpt; use structopt::StructOpt;
use openpgp_card::{Error, Response, StatusBytes}; use openpgp_card::{Error, StatusBytes};
use openpgp_card_pcsc::PcscClient; use openpgp_card_pcsc::PcscClient;
use openpgp_card_sequoia::card::Open; use openpgp_card_sequoia::card::Open;
@ -13,8 +13,8 @@ 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 ccb = PcscClient::open_by_ident(&cli.ident)?; let mut card = PcscClient::open_by_ident(&cli.ident)?.into();
let mut card = Open::open_card(ccb)?; let mut open = Open::open(&mut card)?;
match cli.cmd { match cli.cmd {
cli::Command::SetUserPin {} => { cli::Command::SetUserPin {} => {
@ -23,7 +23,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
rpassword::read_password_from_tty(Some("Enter user PIN: "))?; rpassword::read_password_from_tty(Some("Enter user PIN: "))?;
// verify pin // verify pin
card.verify_user(&pin)?; open.verify_user(&pin)?;
println!("PIN was accepted by the card.\n"); println!("PIN was accepted by the card.\n");
// get new user pin // get new user pin
@ -39,10 +39,12 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
} }
// set new user pin // set new user pin
let res = card.change_user_pin(&pin, &newpin1); let res = open.change_user_pin(&pin, &newpin1);
if res.is_err() { if res.is_err() {
println!("\nFailed to change the user PIN!"); println!("\nFailed to change the user PIN!");
print_gnuk_note(res, card)?; if let Err(err) = res {
print_gnuk_note(err, &open)?;
}
} else { } else {
println!("\nUser PIN has been set."); println!("\nUser PIN has been set.");
} }
@ -53,7 +55,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
rpassword::read_password_from_tty(Some("Enter admin PIN: "))?; rpassword::read_password_from_tty(Some("Enter admin PIN: "))?;
// verify pin // verify pin
card.verify_admin(&pin)?; open.verify_admin(&pin)?;
// get new admin pin // get new admin pin
let newpin1 = rpassword::read_password_from_tty(Some( let newpin1 = rpassword::read_password_from_tty(Some(
@ -68,7 +70,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
} }
// set new user pin // set new user pin
card.change_admin_pin(&pin, &newpin1)?; open.change_admin_pin(&pin, &newpin1)?;
println!("\nAdmin PIN has been set."); println!("\nAdmin PIN has been set.");
} }
@ -78,10 +80,10 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
rpassword::read_password_from_tty(Some("Enter admin PIN: "))?; rpassword::read_password_from_tty(Some("Enter admin PIN: "))?;
// verify admin pin // verify admin pin
card.verify_admin(&pin)?; open.verify_admin(&pin)?;
println!("PIN was accepted by the card.\n"); println!("PIN was accepted by the card.\n");
if let Some(mut admin) = card.admin_card() { if let Some(mut admin) = open.admin_card() {
// ask user for new resetting code // ask user for new resetting code
let newpin1 = rpassword::read_password_from_tty(Some( let newpin1 = rpassword::read_password_from_tty(Some(
"Enter new resetting code: ", "Enter new resetting code: ",
@ -113,7 +115,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
))?; ))?;
// verify pin // verify pin
card.verify_admin(&pin)?; open.verify_admin(&pin)?;
println!("PIN was accepted by the card.\n"); println!("PIN was accepted by the card.\n");
None None
@ -142,9 +144,9 @@ 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
card.reset_user_pin(&rst, &newpin1) open.reset_user_pin(&rst, &newpin1)
} else { } else {
if let Some(mut admin) = card.admin_card() { if let Some(mut admin) = open.admin_card() {
admin.reset_user_pin(&newpin1) admin.reset_user_pin(&newpin1)
} else { } else {
return Err(anyhow::anyhow!( return Err(anyhow::anyhow!(
@ -156,7 +158,9 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
if res.is_err() { if res.is_err() {
println!("\nFailed to change the user PIN!"); println!("\nFailed to change the user PIN!");
print_gnuk_note(res, card)?; if let Err(err) = res {
print_gnuk_note(err, &open)?;
}
} else { } else {
println!("\nUser PIN has been set."); println!("\nUser PIN has been set.");
} }
@ -172,10 +176,11 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
/// This fn checks for Gnuk's Status code and the case that no keys exist /// This fn checks for Gnuk's Status code and the case that no keys exist
/// on the card, and prints a note to the user, pointing out that the /// on the card, and prints a note to the user, pointing out that the
/// absence of keys on the card might be the reason for the error they get. /// absence of keys on the card might be the reason for the error they get.
fn print_gnuk_note(res: Result<Response, Error>, card: Open) -> Result<()> { fn print_gnuk_note(err: Error, card: &Open) -> Result<()> {
if let Err(Error::CardStatus(StatusBytes::ConditionOfUseNotSatisfied)) = if matches!(
res err,
{ Error::CardStatus(StatusBytes::ConditionOfUseNotSatisfied)
) {
// check if no keys exist on the card // check if no keys exist on the card
let fps = card.fingerprints()?; let fps = card.fingerprints()?;
if fps.signature() == None if fps.signature() == None

View file

@ -8,11 +8,14 @@ use structopt::StructOpt;
use sequoia_openpgp::parse::{stream::DecryptorBuilder, Parse}; use sequoia_openpgp::parse::{stream::DecryptorBuilder, Parse};
use sequoia_openpgp::policy::StandardPolicy; use sequoia_openpgp::policy::StandardPolicy;
use sequoia_openpgp::serialize::stream::{Armorer, Message, Signer}; use sequoia_openpgp::serialize::stream::{Armorer, Message, Signer};
use sequoia_openpgp::serialize::SerializeInto;
use sequoia_openpgp::Cert; use sequoia_openpgp::Cert;
use openpgp_card_sequoia::card::Admin; use openpgp_card_sequoia::card::{Admin, Open};
use openpgp_card_sequoia::sq_util; use openpgp_card_sequoia::sq_util;
use openpgp_card_sequoia::util::{make_cert, public_key_material_to_key};
use openpgp_card::algorithm::AlgoSimple;
use openpgp_card::{card_do::Sex, KeyType}; use openpgp_card::{card_do::Sex, KeyType};
mod cli; mod cli;
@ -67,14 +70,18 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
pin_file, pin_file,
cmd, cmd,
} => { } => {
let mut open = util::open_card(&ident)?; let mut card = util::open_card(&ident)?.into();
let mut admin = util::get_admin(&mut open, &pin_file)?; let mut open = Open::open(&mut card)?;
match cmd { match cmd {
cli::AdminCommand::Name { name } => { cli::AdminCommand::Name { name } => {
let mut admin = util::get_admin(&mut open, &pin_file)?;
let _ = admin.set_name(&name)?; let _ = admin.set_name(&name)?;
} }
cli::AdminCommand::Url { url } => { cli::AdminCommand::Url { url } => {
let mut admin = util::get_admin(&mut open, &pin_file)?;
let _ = admin.set_url(&url)?; let _ = admin.set_url(&url)?;
} }
cli::AdminCommand::Import { cli::AdminCommand::Import {
@ -83,6 +90,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
dec_fp, dec_fp,
auth_fp, auth_fp,
} => { } => {
let admin = util::get_admin(&mut open, &pin_file)?;
let key = Cert::from_file(keyfile)?; let key = Cert::from_file(keyfile)?;
if (&sig_fp, &dec_fp, &auth_fp) == (&None, &None, &None) { if (&sig_fp, &dec_fp, &auth_fp) == (&None, &None, &None) {
@ -109,7 +117,9 @@ fn list_cards() -> Result<()> {
println!("Available OpenPGP cards:"); println!("Available OpenPGP cards:");
for card in cards { for card in cards {
println!(" {}", card.application_identifier()?.ident()); let mut card = card.into();
let open = Open::open(&mut card)?;
println!(" {}", open.application_identifier()?.ident());
} }
} else { } else {
println!("No OpenPGP cards found."); println!("No OpenPGP cards found.");
@ -118,7 +128,7 @@ fn list_cards() -> Result<()> {
} }
fn print_status(ident: Option<String>, verbose: bool) -> Result<()> { fn print_status(ident: Option<String>, verbose: bool) -> Result<()> {
let mut open = if let Some(ident) = ident { let ccb = 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()?;
@ -128,6 +138,8 @@ fn print_status(ident: Option<String>, verbose: bool) -> Result<()> {
return Err(anyhow::anyhow!("Found {} cards", cards.len()).into()); return Err(anyhow::anyhow!("Found {} cards", cards.len()).into());
} }
}; };
let mut card = ccb.into();
let mut open = Open::open(&mut card)?;
print!("OpenPGP card {}", open.application_identifier()?.ident()); print!("OpenPGP card {}", open.application_identifier()?.ident());
@ -258,7 +270,9 @@ fn decrypt(
let input = util::open_or_stdin(input.as_deref())?; let input = util::open_or_stdin(input.as_deref())?;
let mut open = util::open_card(&ident)?; let mut card = util::open_card(&ident)?.into();
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)?;
@ -281,7 +295,9 @@ 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 open = util::open_card(&ident)?; let mut card = util::open_card(&ident)?.into();
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)?;
@ -296,7 +312,8 @@ fn sign_detached(
fn factory_reset(ident: &str) -> Result<()> { fn factory_reset(ident: &str) -> Result<()> {
println!("Resetting Card {}", ident); println!("Resetting Card {}", ident);
util::open_card(ident)?.factory_reset() let mut card = util::open_card(ident)?.into();
Open::open(&mut card)?.factory_reset()
} }
fn key_import_yolo(mut admin: Admin, key: &Cert) -> Result<()> { fn key_import_yolo(mut admin: Admin, key: &Cert) -> Result<()> {

View file

@ -3,54 +3,47 @@
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use openpgp_card::Error; use openpgp_card::{CardClientBox, 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<Open>> { pub(crate) fn cards() -> Result<Vec<CardClientBox>> {
let mut cards = vec![]; PcscClient::cards()
for card in PcscClient::cards()? {
cards.push(Open::open_card(card)?);
}
Ok(cards)
} }
pub(crate) fn open_card(ident: &str) -> Result<Open, Error> { pub(crate) fn open_card(ident: &str) -> Result<CardClientBox, Error> {
let ccb = PcscClient::open_by_ident(ident)?; PcscClient::open_by_ident(ident)
Open::open_card(ccb)
} }
pub(crate) fn get_user<'a>( pub(crate) fn get_user<'app, 'open>(
open: &'a mut Open, open: &'app mut Open<'app>,
pin_file: &Path, pin_file: &Path,
) -> Result<User<'a>, Box<dyn std::error::Error>> { ) -> Result<User<'app, 'open>, Box<dyn std::error::Error>> {
open.verify_user(&get_pin(pin_file)?)?; open.verify_user(&get_pin(pin_file)?)?;
open.user_card() open.user_card()
.ok_or_else(|| anyhow::anyhow!("Couldn't get user access").into()) .ok_or_else(|| anyhow::anyhow!("Couldn't get user access").into())
} }
pub(crate) fn get_sign<'a>( pub(crate) fn get_sign<'app, 'open>(
open: &'a mut Open, open: &'app mut Open<'app>,
pin_file: &Path, pin_file: &Path,
) -> Result<Sign<'a>, Box<dyn std::error::Error>> { ) -> Result<Sign<'app, 'open>, Box<dyn std::error::Error>> {
open.verify_user_for_signing(&get_pin(pin_file)?)?; open.verify_user_for_signing(&get_pin(pin_file)?)?;
open.signing_card() open.signing_card()
.ok_or_else(|| anyhow::anyhow!("Couldn't get sign access").into()) .ok_or_else(|| anyhow::anyhow!("Couldn't get sign access").into())
} }
pub(crate) fn get_admin<'a>( pub(crate) fn get_admin<'app, 'open>(
open: &'a mut Open, open: &'app mut Open<'app>,
pin_file: &Path, pin_file: &Path,
) -> Result<Admin<'a>, Box<dyn std::error::Error>> { ) -> Result<Admin<'app, 'open>, Box<dyn std::error::Error>> {
open.verify_admin(&get_pin(pin_file)?)?; open.verify_admin(&get_pin(pin_file)?)?;
open.admin_card() open.admin_card()
.ok_or_else(|| anyhow::anyhow!("Couldn't get admin access").into()) .ok_or_else(|| anyhow::anyhow!("Couldn't get admin access").into())
} }
fn get_pin(pin_file: &Path) -> Result<String> { pub(crate) fn get_pin(pin_file: &Path) -> Result<String> {
let pin = std::fs::read_to_string(pin_file)?; let pin = std::fs::read_to_string(pin_file)?;
Ok(pin.trim().to_string()) Ok(pin.trim().to_string())
} }