diff --git a/card-functionality/src/list-cards.rs b/card-functionality/src/list-cards.rs index 701fe69..9af379d 100644 --- a/card-functionality/src/list-cards.rs +++ b/card-functionality/src/list-cards.rs @@ -4,15 +4,14 @@ use anyhow::Result; use openpgp_card_pcsc::PcscBackend; -use openpgp_card_sequoia::card::Card; +use openpgp_card_sequoia::card::{Card, Open}; fn main() -> Result<()> { println!("The following OpenPGP cards are connected to your system:"); for backend in PcscBackend::cards(None)? { - let mut card = Card::new(backend); - let open = card.transaction()?; - println!(" {}", open.application_identifier()?.ident()); + let mut card: Card = backend.into(); + println!(" {}", card.transaction()?.application_identifier()?.ident()); } Ok(()) diff --git a/card-functionality/src/tests.rs b/card-functionality/src/tests.rs index 4a2929a..d713706 100644 --- a/card-functionality/src/tests.rs +++ b/card-functionality/src/tests.rs @@ -16,7 +16,7 @@ use sequoia_openpgp::Cert; use openpgp_card::algorithm::AlgoSimple; use openpgp_card::card_do::{KeyGenerationTime, Sex}; use openpgp_card::{Error, KeyType, OpenPgp, OpenPgpTransaction, StatusBytes}; -use openpgp_card_sequoia::card::Open; +use openpgp_card_sequoia::card::{Card, Transaction}; use openpgp_card_sequoia::util::{ make_cert, public_key_material_and_fp_to_key, public_key_material_to_key, }; @@ -67,9 +67,9 @@ pub fn test_decrypt(pgp: &mut OpenPgp, param: &[&str]) -> Result::new(pgpt)?; - let mut user = open.user_card().unwrap(); + let mut user = transaction.user_card().unwrap(); let d = user.decryptor(&|| {})?; let res = openpgp_card_sequoia::util::decrypt(d, msg.into_bytes(), &p)?; @@ -90,9 +90,9 @@ pub fn test_sign(pgp: &mut OpenPgp, param: &[&str]) -> Result::new(pgpt)?; - let mut sign = open.signing_card().unwrap(); + let mut sign = transaction.signing_card().unwrap(); let s = sign.signer(&|| {})?; let msg = "Hello world, I am signed."; @@ -216,9 +216,9 @@ pub fn test_upload_keys(pgp: &mut OpenPgp, param: &[&str]) -> Result Result { let pgpt = pgp.transaction()?; - let mut open = Open::new(pgpt)?; - open.verify_admin(b"12345678")?; - let mut admin = open.admin_card().expect("Couldn't get Admin card"); + let mut transaction = Card::::new(pgpt)?; + transaction.verify_admin(b"12345678")?; + let mut admin = transaction.admin_card().expect("Couldn't get Admin card"); // Generate all three subkeys on card let algo = param[0]; @@ -245,7 +245,7 @@ pub fn test_keygen(pgp: &mut OpenPgp, param: &[&str]) -> Result Result<(), Box> { let card_ident = &args[0]; let pin_file = &args[1]; - let card_backend = PcscBackend::open_by_ident(card_ident, None)?; + let backend = PcscBackend::open_by_ident(card_ident, None)?; - let mut card = Card::new(card_backend); - let mut open = card.transaction()?; + let mut card: Card = backend.into(); + let mut transaction = card.transaction()?; let pin = std::fs::read(pin_file)?; - open.verify_user(&pin)?; + transaction.verify_user(&pin)?; - let mut user = open.user_card().unwrap(); + let mut user = transaction.user_card().unwrap(); let p = StandardPolicy::new(); diff --git a/openpgp-card-examples/src/bin/detach-sign.rs b/openpgp-card-examples/src/bin/detach-sign.rs index 7aa36c0..fc64101 100644 --- a/openpgp-card-examples/src/bin/detach-sign.rs +++ b/openpgp-card-examples/src/bin/detach-sign.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: MIT OR Apache-2.0 use openpgp_card_pcsc::PcscBackend; -use openpgp_card_sequoia::card::Card; +use openpgp_card_sequoia::card::{Card, Open}; use openpgp::serialize::stream::{Armorer, Message, Signer}; use sequoia_openpgp as openpgp; @@ -18,16 +18,16 @@ fn main() -> Result<(), Box> { let card_ident = &args[0]; let pin_file = &args[1]; - let card_backend = PcscBackend::open_by_ident(card_ident, None)?; + let backend = PcscBackend::open_by_ident(card_ident, None)?; - let mut card = Card::new(card_backend); - let mut open = card.transaction()?; + let mut card: Card = backend.into(); + let mut transaction = card.transaction()?; let pin = std::fs::read(pin_file)?; - open.verify_user_for_signing(&pin)?; + transaction.verify_user_for_signing(&pin)?; - let mut sign = open.signing_card().unwrap(); + let mut sign = transaction.signing_card().unwrap(); let s = sign.signer(&|| println!("Touch confirmation needed for signing"))?; let stdout = std::io::stdout(); diff --git a/openpgp-card-sequoia/examples/test.rs b/openpgp-card-sequoia/examples/test.rs index 15178ad..fcf4644 100644 --- a/openpgp-card-sequoia/examples/test.rs +++ b/openpgp-card-sequoia/examples/test.rs @@ -10,10 +10,10 @@ use sequoia_openpgp::policy::StandardPolicy; use sequoia_openpgp::Cert; use openpgp_card::card_do::Sex; -use openpgp_card::{KeyType, OpenPgp}; +use openpgp_card::KeyType; use openpgp_card_pcsc::PcscBackend; -use openpgp_card_sequoia::card::Open; +use openpgp_card_sequoia::card::{Card, Open}; use openpgp_card_sequoia::sq_util; // Filename of test key and test message to use @@ -36,47 +36,47 @@ fn main() -> Result<(), Box> { if let Ok(test_card_ident) = test_card_ident { let backend = PcscBackend::open_by_ident(&test_card_ident, None)?; - let mut pgp = OpenPgp::new(backend); - let mut open = Open::new(pgp.transaction()?)?; + let mut card: Card = backend.into(); + let mut transaction = card.transaction()?; // card metadata - let app_id = open.application_identifier()?; + let app_id = transaction.application_identifier()?; println!("{:x?}\n", app_id); - let eli = open.extended_length_information()?; + let eli = transaction.extended_length_information()?; println!("extended_length_info: {:?}\n", eli); - let hist = open.historical_bytes()?; + let hist = transaction.historical_bytes()?; println!("{:#x?}\n", hist); - let ext = open.extended_capabilities()?; + let ext = transaction.extended_capabilities()?; println!("{:#x?}\n", ext); - let pws = open.pw_status_bytes()?; + let pws = transaction.pw_status_bytes()?; println!("{:#x?}\n", pws); // cardholder - let ch = open.cardholder_related_data()?; + let ch = transaction.cardholder_related_data()?; println!("{:#x?}\n", ch); // crypto-ish metadata - let fp = open.fingerprints()?; + let fp = transaction.fingerprints()?; println!("Fingerprint {:#x?}\n", fp); - match open.algorithm_information() { + match transaction.algorithm_information() { Ok(Some(ai)) => println!("Algorithm information:\n{}", ai), Ok(None) => println!("No Algorithm information found"), Err(e) => println!("Error getting Algorithm information: {:?}", e), } println!("Current algorithm attributes on card:"); - let algo = open.algorithm_attributes(KeyType::Signing)?; + let algo = transaction.algorithm_attributes(KeyType::Signing)?; println!("Sig: {}", algo); - let algo = open.algorithm_attributes(KeyType::Decryption)?; + let algo = transaction.algorithm_attributes(KeyType::Decryption)?; println!("Dec: {}", algo); - let algo = open.algorithm_attributes(KeyType::Authentication)?; + let algo = transaction.algorithm_attributes(KeyType::Authentication)?; println!("Aut: {}", algo); println!(); @@ -88,20 +88,20 @@ fn main() -> Result<(), Box> { assert_eq!(app_id.ident(), test_card_ident.to_ascii_uppercase()); - let check = open.check_admin_verified(); + let check = transaction.check_admin_verified(); println!("has admin (pw3) been verified yet?\n{:x?}\n", check); println!("factory reset\n"); - open.factory_reset()?; + transaction.factory_reset()?; - open.verify_admin(b"12345678")?; + transaction.verify_admin(b"12345678")?; println!("verify for admin ok"); - let check = open.check_user_verified(); + let check = transaction.check_user_verified(); println!("has user (pw1/82) been verified yet? {:x?}", check); // Use Admin access to card - let mut admin = open.admin_card().expect("just verified"); + let mut admin = transaction.admin_card().expect("just verified"); println!(); @@ -141,25 +141,25 @@ fn main() -> Result<(), Box> { // Open fresh Card for decrypt // ----------------------------- let backend = PcscBackend::open_by_ident(&test_card_ident, None)?; - let mut pgp = OpenPgp::new(backend); - let mut open = Open::new(pgp.transaction()?)?; + let mut card: Card = backend.into(); + let mut transaction = card.transaction()?; // Check that we're still using the expected card - let app_id = open.application_identifier()?; + let app_id = transaction.application_identifier()?; assert_eq!(app_id.ident(), test_card_ident.to_ascii_uppercase()); - let check = open.check_user_verified(); + let check = transaction.check_user_verified(); println!("has user (pw1/82) been verified yet?\n{:x?}\n", check); - open.verify_user(b"123456")?; + transaction.verify_user(b"123456")?; println!("verify for user (pw1/82) ok"); - let check = open.check_user_verified(); + let check = transaction.check_user_verified(); println!("has user (pw1/82) been verified yet?\n{:x?}\n", check); // Use User access to card - let mut user = open + let mut user = transaction .user_card() .expect("We just validated, this should not fail"); @@ -181,16 +181,16 @@ fn main() -> Result<(), Box> { // Open fresh Card for signing // ----------------------------- let backend = PcscBackend::open_by_ident(&test_card_ident, None)?; - let mut pgp = OpenPgp::new(backend); - let mut open = Open::new(pgp.transaction()?)?; + let mut card: Card = backend.into(); + let mut transaction = card.transaction()?; // Sign - open.verify_user_for_signing(b"123456")?; + transaction.verify_user_for_signing(b"123456")?; println!("verify for sign (pw1/81) ok\n"); // Use Sign access to card - let mut sign = open.signing_card().expect("just verified"); + let mut sign = transaction.signing_card().expect("just verified"); let _cert = Cert::from_file(TEST_KEY_PATH)?; @@ -213,9 +213,8 @@ fn main() -> Result<(), Box> { println!("The following OpenPGP cards are connected to your system:"); for backend in PcscBackend::cards(None)? { - let mut pgp = OpenPgp::new(backend); - - let open = Open::new(pgp.transaction()?)?; + let mut card: Card = backend.into(); + let open = card.transaction()?; println!(" {}", open.application_identifier()?.ident()); } diff --git a/openpgp-card-sequoia/src/card.rs b/openpgp-card-sequoia/src/card.rs index efea4fe..7c6a9b1 100644 --- a/openpgp-card-sequoia/src/card.rs +++ b/openpgp-card-sequoia/src/card.rs @@ -22,39 +22,33 @@ use crate::signer::CardSigner; use crate::util::{public_to_fingerprint, vka_as_uploadable_key}; use crate::PublicKey; +pub trait State {} +impl State for Open {} +impl State for Transaction<'_> {} +impl State for User<'_, '_> {} +impl State for Sign<'_, '_> {} +impl State for Admin<'_, '_> {} + /// Representation of an opened OpenPGP card in its base state (i.e. no /// passwords have been verified, default authorization applies). /// No transaction has been started. -pub struct Card { +pub struct Open { pgp: OpenPgp, } -impl Card { - pub fn new(backend: B) -> Self - where - B: Into>, - { - let pgp = OpenPgp::new(backend.into()); - - Self { pgp } - } - - pub fn transaction(&mut self) -> Result { - let t = self.pgp.transaction()?; - Open::new(t) - } -} - /// Representation of an opened OpenPGP card in its base state (i.e. no /// passwords have been verified, default authorization applies). /// A transaction has been started. -pub struct Open<'a> { +pub struct Transaction<'a> { opt: OpenPgpTransaction<'a>, // Cache of "application related data". // // FIXME: Should be invalidated when changing data on the card! // (e.g. uploading keys, etc) + // + // This field should probably be an Option<> that gets invalidated when appropriate and + // re-fetched lazily. ard: ApplicationRelatedData, // verify status of pw1 @@ -67,16 +61,67 @@ pub struct Open<'a> { pw3: bool, } -impl<'a> Open<'a> { - pub fn new(mut ca: OpenPgpTransaction<'a>) -> Result { - let ard = ca.application_related_data()?; +/// An OpenPGP card after successfully verifying PW1 in mode 82 +/// (verification for user operations other than signing) +pub struct User<'app, 'open> { + tx: &'open mut Card>, +} + +/// An OpenPGP card after successfully verifying PW1 in mode 81 +/// (verification for signing) +pub struct Sign<'app, 'open> { + tx: &'open mut Card>, +} + +/// An OpenPGP card after successful verification of PW3 ("Admin privileges") +pub struct Admin<'app, 'open> { + tx: &'open mut Card>, +} + +pub struct Card +where + S: State, +{ + state: S, +} + +impl From for Card +where + B: Into>, +{ + fn from(backend: B) -> Self { + let pgp = OpenPgp::new(backend.into()); + + Card:: { + state: Open { pgp }, + } + } +} + +impl Card { + pub fn transaction(&mut self) -> Result, Error> { + let opt = self.state.pgp.transaction()?; + + Card::::new(opt) + } +} + +impl<'a> Card> { + /// Do not use! + /// + /// FIXME: this interface is currently used in `card-functionality`, for testing. + /// It will be removed. + pub fn new(mut opt: OpenPgpTransaction<'a>) -> Result { + let ard = opt.application_related_data()?; Ok(Self { - opt: ca, - ard, - pw1: false, - pw1_sign: false, - pw3: false, + state: Transaction { + opt, + ard, + pw1: false, + pw1_sign: false, + pw3: false, + }, }) } @@ -86,38 +131,39 @@ impl<'a> Open<'a> { /// This is needed e.g. after importing or generating keys on a card, to /// see these changes reflected in `self.ard`. pub fn reload_ard(&mut self) -> Result<(), Error> { - self.ard = self.opt.application_related_data()?; + // FIXME: this should be implemented internally, transparent to users + self.state.ard = self.state.opt.application_related_data()?; Ok(()) } pub fn feature_pinpad_verify(&mut self) -> bool { - self.opt.feature_pinpad_verify() + self.state.opt.feature_pinpad_verify() } pub fn feature_pinpad_modify(&mut self) -> bool { - self.opt.feature_pinpad_modify() + self.state.opt.feature_pinpad_modify() } pub fn verify_user(&mut self, pin: &[u8]) -> Result<(), Error> { - self.opt.verify_pw1_user(pin)?; - self.pw1 = true; + self.state.opt.verify_pw1_user(pin)?; + self.state.pw1 = true; Ok(()) } pub fn verify_user_pinpad(&mut self, pinpad_prompt: &dyn Fn()) -> Result<(), Error> { pinpad_prompt(); - self.opt.verify_pw1_user_pinpad()?; - self.pw1 = true; + self.state.opt.verify_pw1_user_pinpad()?; + self.state.pw1 = true; Ok(()) } pub fn verify_user_for_signing(&mut self, pin: &[u8]) -> Result<(), Error> { - self.opt.verify_pw1_sign(pin)?; + self.state.opt.verify_pw1_sign(pin)?; // FIXME: depending on card mode, pw1_sign is only usable once - self.pw1_sign = true; + self.state.pw1_sign = true; Ok(()) } @@ -127,25 +173,25 @@ impl<'a> Open<'a> { ) -> Result<(), Error> { pinpad_prompt(); - self.opt.verify_pw1_sign_pinpad()?; + self.state.opt.verify_pw1_sign_pinpad()?; // FIXME: depending on card mode, pw1_sign is only usable once - self.pw1_sign = true; + self.state.pw1_sign = true; Ok(()) } pub fn verify_admin(&mut self, pin: &[u8]) -> Result<(), Error> { - self.opt.verify_pw3(pin)?; - self.pw3 = true; + self.state.opt.verify_pw3(pin)?; + self.state.pw3 = true; Ok(()) } pub fn verify_admin_pinpad(&mut self, pinpad_prompt: &dyn Fn()) -> Result<(), Error> { pinpad_prompt(); - self.opt.verify_pw3_pinpad()?; - self.pw3 = true; + self.state.opt.verify_pw3_pinpad()?; + self.state.pw3 = true; Ok(()) } @@ -153,65 +199,71 @@ impl<'a> Open<'a> { /// /// NOTE: on some cards this functionality seems broken. pub fn check_user_verified(&mut self) -> Result<(), Error> { - self.opt.check_pw1_user() + self.state.opt.check_pw1_user() } /// Ask the card if the admin password has been successfully verified. /// /// NOTE: on some cards this functionality seems broken. pub fn check_admin_verified(&mut self) -> Result<(), Error> { - self.opt.check_pw3() + self.state.opt.check_pw3() } pub fn change_user_pin(&mut self, old: &[u8], new: &[u8]) -> Result<(), Error> { - self.opt.change_pw1(old, new) + self.state.opt.change_pw1(old, new) } pub fn change_user_pin_pinpad(&mut self, pinpad_prompt: &dyn Fn()) -> Result<(), Error> { pinpad_prompt(); - self.opt.change_pw1_pinpad() + self.state.opt.change_pw1_pinpad() } pub fn reset_user_pin(&mut self, rst: &[u8], new: &[u8]) -> Result<(), Error> { - self.opt.reset_retry_counter_pw1(new, Some(rst)) + self.state.opt.reset_retry_counter_pw1(new, Some(rst)) } pub fn change_admin_pin(&mut self, old: &[u8], new: &[u8]) -> Result<(), Error> { - self.opt.change_pw3(old, new) + self.state.opt.change_pw3(old, new) } pub fn change_admin_pin_pinpad(&mut self, pinpad_prompt: &dyn Fn()) -> Result<(), Error> { pinpad_prompt(); - self.opt.change_pw3_pinpad() + self.state.opt.change_pw3_pinpad() } /// Get a view of the card authenticated for "User" commands. - pub fn user_card<'b>(&'b mut self) -> Option> { - Some(User { oc: self }) + pub fn user_card<'b>(&'b mut self) -> Option>> { + Some(Card:: { + state: User { tx: self }, + }) } /// Get a view of the card authenticated for Signing. - pub fn signing_card<'b>(&'b mut self) -> Option> { - Some(Sign { oc: self }) + pub fn signing_card<'b>(&'b mut self) -> Option>> { + Some(Card:: { + state: Sign { tx: self }, + }) } /// Get a view of the card authenticated for "Admin" commands. - pub fn admin_card<'b>(&'b mut self) -> Option> { - Some(Admin { oc: self }) + pub fn admin_card<'b>(&'b mut self) -> Option>> { + Some(Card:: { + state: Admin { tx: self }, + }) } // --- application data --- pub fn application_identifier(&self) -> Result { - self.ard.application_id() + self.state.ard.application_id() } pub fn historical_bytes(&self) -> Result { - self.ard.historical_bytes() + self.state.ard.historical_bytes() } pub fn extended_length_information(&self) -> Result, Error> { - self.ard.extended_length_information() + self.state.ard.extended_length_information() } #[allow(dead_code)] @@ -225,48 +277,48 @@ impl<'a> Open<'a> { } pub fn extended_capabilities(&self) -> Result { - self.ard.extended_capabilities() + self.state.ard.extended_capabilities() } pub fn algorithm_attributes(&self, key_type: KeyType) -> Result { - self.ard.algorithm_attributes(key_type) + self.state.ard.algorithm_attributes(key_type) } /// PW status Bytes pub fn pw_status_bytes(&self) -> Result { - self.ard.pw_status_bytes() + self.state.ard.pw_status_bytes() } pub fn fingerprints(&self) -> Result, Error> { - self.ard.fingerprints() + self.state.ard.fingerprints() } pub fn ca_fingerprints(&self) -> Result<[Option; 3], Error> { - self.ard.ca_fingerprints() + self.state.ard.ca_fingerprints() } pub fn key_generation_times(&self) -> Result, Error> { - self.ard.key_generation_times() + self.state.ard.key_generation_times() } pub fn key_information(&self) -> Result, Error> { - self.ard.key_information() + self.state.ard.key_information() } pub fn uif_signing(&self) -> Result, Error> { - self.ard.uif_pso_cds() + self.state.ard.uif_pso_cds() } pub fn uif_decryption(&self) -> Result, Error> { - self.ard.uif_pso_dec() + self.state.ard.uif_pso_dec() } pub fn uif_authentication(&self) -> Result, Error> { - self.ard.uif_pso_aut() + self.state.ard.uif_pso_aut() } pub fn uif_attestation(&self) -> Result, Error> { - self.ard.uif_attestation() + self.state.ard.uif_attestation() } // --- optional private DOs (0101 - 0104) --- @@ -276,17 +328,17 @@ impl<'a> Open<'a> { // --- URL (5f50) --- pub fn url(&mut self) -> Result { - Ok(String::from_utf8_lossy(&self.opt.url()?).to_string()) + Ok(String::from_utf8_lossy(&self.state.opt.url()?).to_string()) } // --- cardholder related data (65) --- pub fn cardholder_related_data(&mut self) -> Result { - self.opt.cardholder_related_data() + self.state.opt.cardholder_related_data() } /// Get cardholder name as a String (this also normalizes the "<" and "<<" filler chars) pub fn cardholder_name(&mut self) -> Result { - let crd = self.opt.cardholder_related_data()?; + let crd = self.state.opt.cardholder_related_data()?; if let Some(name) = crd.name() { let name = String::from_utf8_lossy(name).to_string(); @@ -305,12 +357,12 @@ impl<'a> Open<'a> { // --- security support template (7a) --- pub fn security_support_template(&mut self) -> Result { - self.opt.security_support_template() + self.state.opt.security_support_template() } /// SELECT DATA ("select a DO in the current template"). pub fn select_data(&mut self, num: u8, tag: &[u8], yk_workaround: bool) -> Result<(), Error> { - self.opt.select_data(num, tag, yk_workaround) + self.state.opt.select_data(num, tag, yk_workaround) } /// Get cardholder certificate. @@ -318,7 +370,7 @@ impl<'a> Open<'a> { /// Call select_data() before calling this fn to select a particular /// certificate (if the card supports multiple certificates). pub fn cardholder_certificate(&mut self) -> Result, Error> { - self.opt.cardholder_certificate() + self.state.opt.cardholder_certificate() } /// "GET NEXT DATA" for the DO cardholder certificate. @@ -326,7 +378,7 @@ impl<'a> Open<'a> { /// Cardholder certificate data for multiple slots can be read from the card by first calling /// cardholder_certificate(), followed by up to two calls to next_cardholder_certificate(). pub fn next_cardholder_certificate(&mut self) -> Result, Error> { - self.opt.next_cardholder_certificate() + self.state.opt.next_cardholder_certificate() } // DO "Algorithm Information" (0xFA) @@ -340,7 +392,7 @@ impl<'a> Open<'a> { return Ok(None); } - self.opt.algorithm_information() + self.state.opt.algorithm_information() } /// "MANAGE SECURITY ENVIRONMENT" @@ -350,19 +402,21 @@ impl<'a> Open<'a> { for_operation: KeyType, key_ref: KeyType, ) -> Result<(), Error> { - self.opt.manage_security_environment(for_operation, key_ref) + self.state + .opt + .manage_security_environment(for_operation, key_ref) } // ---------- /// Get "Attestation Certificate (Yubico)" pub fn attestation_certificate(&mut self) -> Result, Error> { - self.opt.attestation_certificate() + self.state.opt.attestation_certificate() } /// Firmware Version, YubiKey specific (?) pub fn firmware_version(&mut self) -> Result, Error> { - self.opt.firmware_version() + self.state.opt.firmware_version() } /// Set "identity", Nitrokey Start specific (possible values: 0, 1, 2). @@ -374,7 +428,7 @@ impl<'a> Open<'a> { /// Each virtual card identity behaves like a separate, independent OpenPGP card. pub fn set_identity(&mut self, id: u8) -> Result<(), Error> { // FIXME: what is in the returned data - is it ever useful? - let _ = self.opt.set_identity(id)?; + let _ = self.state.opt.set_identity(id)?; Ok(()) } @@ -382,36 +436,31 @@ impl<'a> Open<'a> { // ---------- pub fn public_key(&mut self, key_type: KeyType) -> Result { - self.opt.public_key(key_type) + self.state.opt.public_key(key_type) } // ---------- /// Delete all state on this OpenPGP card pub fn factory_reset(&mut self) -> Result<(), Error> { - self.opt.factory_reset() + self.state.opt.factory_reset() } } -/// An OpenPGP card after successfully verifying PW1 in mode 82 -/// (verification for user operations other than signing) -pub struct User<'app, 'open> { - oc: &'open mut Open<'app>, -} +impl<'app, 'open> Card> { + /// Helper fn to easily access underlying openpgp_card object + fn card(&mut self) -> &mut OpenPgpTransaction<'app> { + &mut self.state.tx.state.opt + } -impl<'app, 'open> User<'app, 'open> { pub fn decryptor( &mut self, touch_prompt: &'open (dyn Fn() + Send + Sync), ) -> Result, Error> { - let pk = crate::util::key_slot(self.oc, KeyType::Decryption)? + let pk = crate::util::key_slot(self.state.tx, KeyType::Decryption)? .expect("Couldn't get decryption pubkey from card"); - Ok(CardDecryptor::with_pubkey( - &mut self.oc.opt, - pk, - touch_prompt, - )) + Ok(CardDecryptor::with_pubkey(self.card(), pk, touch_prompt)) } pub fn decryptor_from_public( @@ -419,18 +468,18 @@ impl<'app, 'open> User<'app, 'open> { pubkey: PublicKey, touch_prompt: &'open (dyn Fn() + Send + Sync), ) -> CardDecryptor<'_, 'app> { - CardDecryptor::with_pubkey(&mut self.oc.opt, pubkey, touch_prompt) + CardDecryptor::with_pubkey(self.card(), pubkey, touch_prompt) } pub fn authenticator( &mut self, touch_prompt: &'open (dyn Fn() + Send + Sync), ) -> Result, Error> { - let pk = crate::util::key_slot(self.oc, KeyType::Authentication)? + let pk = crate::util::key_slot(self.state.tx, KeyType::Authentication)? .expect("Couldn't get authentication pubkey from card"); Ok(CardSigner::with_pubkey_for_auth( - &mut self.oc.opt, + self.card(), pk, touch_prompt, )) @@ -440,17 +489,16 @@ impl<'app, 'open> User<'app, 'open> { pubkey: PublicKey, touch_prompt: &'open (dyn Fn() + Send + Sync), ) -> CardSigner<'_, 'app> { - CardSigner::with_pubkey_for_auth(&mut self.oc.opt, pubkey, touch_prompt) + CardSigner::with_pubkey_for_auth(self.card(), pubkey, touch_prompt) } } -/// An OpenPGP card after successfully verifying PW1 in mode 81 -/// (verification for signing) -pub struct Sign<'app, 'open> { - oc: &'open mut Open<'app>, -} +impl<'app, 'open> Card> { + /// Helper fn to easily access underlying openpgp_card object + fn card(&mut self) -> &mut OpenPgpTransaction<'app> { + &mut self.state.tx.state.opt + } -impl<'app, 'open> Sign<'app, 'open> { pub fn signer( &mut self, touch_prompt: &'open (dyn Fn() + Send + Sync), @@ -458,10 +506,10 @@ impl<'app, 'open> Sign<'app, 'open> { // FIXME: depending on the setting in "PW1 Status byte", only one // signature can be made after verification for signing - let pk = crate::util::key_slot(self.oc, KeyType::Signing)? + let pk = crate::util::key_slot(self.state.tx, KeyType::Signing)? .expect("Couldn't get signing pubkey from card"); - Ok(CardSigner::with_pubkey(&mut self.oc.opt, pk, touch_prompt)) + Ok(CardSigner::with_pubkey(self.card(), pk, touch_prompt)) } pub fn signer_from_public( @@ -472,7 +520,7 @@ impl<'app, 'open> Sign<'app, 'open> { // 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.opt, pubkey, touch_prompt) + CardSigner::with_pubkey(self.card(), pubkey, touch_prompt) } /// Generate Attestation (Yubico) @@ -484,28 +532,28 @@ impl<'app, 'open> Sign<'app, 'open> { // Touch is required if: // - the card supports the feature // - and the policy is set to a value other than 'Off' - if let Some(uif) = self.oc.ard.uif_attestation()? { + if let Some(uif) = self.state.tx.state.ard.uif_attestation()? { if uif.touch_policy().touch_required() { (touch_prompt)(); } } - self.oc.opt.generate_attestation(key_type) + self.card().generate_attestation(key_type) } } -/// An OpenPGP card after successful verification of PW3 ("Admin privileges") -pub struct Admin<'app, 'open> { - oc: &'open mut Open<'app>, -} +impl<'app, 'open> Card> { + pub fn as_open(&'_ mut self) -> &mut Card> { + self.state.tx + } -impl<'app, 'open> Admin<'app, 'open> { - pub fn as_open(&'_ mut self) -> &mut Open<'app> { - self.oc + /// Helper fn to easily access underlying openpgp_card object + fn card(&mut self) -> &mut OpenPgpTransaction<'app> { + &mut self.state.tx.state.opt } } -impl Admin<'_, '_> { +impl Card> { pub fn set_name(&mut self, name: &str) -> Result<(), Error> { if name.len() >= 40 { return Err(Error::InternalError("name too long".into())); @@ -516,7 +564,7 @@ impl Admin<'_, '_> { return Err(Error::InternalError("Invalid char in name".into())); }; - self.oc.opt.set_name(name.as_bytes()) + self.card().set_name(name.as_bytes()) } pub fn set_lang(&mut self, lang: &[Lang]) -> Result<(), Error> { @@ -524,11 +572,11 @@ impl Admin<'_, '_> { return Err(Error::InternalError("lang too long".into())); } - self.oc.opt.set_lang(lang) + self.card().set_lang(lang) } pub fn set_sex(&mut self, sex: Sex) -> Result<(), Error> { - self.oc.opt.set_sex(sex) + self.card().set_sex(sex) } pub fn set_url(&mut self, url: &str) -> Result<(), Error> { @@ -537,7 +585,7 @@ impl Admin<'_, '_> { } // Check for max len - let ec = self.oc.extended_capabilities()?; + let ec = self.state.tx.extended_capabilities()?; if ec.max_len_special_do() == None || url.len() <= ec.max_len_special_do().unwrap() as usize { @@ -545,7 +593,7 @@ impl Admin<'_, '_> { // or if it's within the acceptable length: // send the url update to the card. - self.oc.opt.set_url(url.as_bytes()) + self.card().set_url(url.as_bytes()) } else { Err(Error::InternalError("URL too long".into())) } @@ -553,10 +601,10 @@ impl Admin<'_, '_> { pub fn set_uif(&mut self, key: KeyType, policy: TouchPolicy) -> Result<(), Error> { let uif = match key { - KeyType::Signing => self.oc.ard.uif_pso_cds()?, - KeyType::Decryption => self.oc.ard.uif_pso_dec()?, - KeyType::Authentication => self.oc.ard.uif_pso_aut()?, - KeyType::Attestation => self.oc.ard.uif_attestation()?, + KeyType::Signing => self.state.tx.state.ard.uif_pso_cds()?, + KeyType::Decryption => self.state.tx.state.ard.uif_pso_dec()?, + KeyType::Authentication => self.state.tx.state.ard.uif_pso_aut()?, + KeyType::Attestation => self.state.tx.state.ard.uif_attestation()?, _ => unimplemented!(), }; @@ -564,10 +612,10 @@ impl Admin<'_, '_> { uif.set_touch_policy(policy); match key { - KeyType::Signing => self.oc.opt.set_uif_pso_cds(&uif)?, - KeyType::Decryption => self.oc.opt.set_uif_pso_dec(&uif)?, - KeyType::Authentication => self.oc.opt.set_uif_pso_aut(&uif)?, - KeyType::Attestation => self.oc.opt.set_uif_attestation(&uif)?, + KeyType::Signing => self.card().set_uif_pso_cds(&uif)?, + KeyType::Decryption => self.card().set_uif_pso_dec(&uif)?, + KeyType::Authentication => self.card().set_uif_pso_aut(&uif)?, + KeyType::Attestation => self.card().set_uif_attestation(&uif)?, _ => unimplemented!(), } } else { @@ -580,15 +628,15 @@ impl Admin<'_, '_> { } pub fn set_resetting_code(&mut self, pin: &[u8]) -> Result<(), Error> { - self.oc.opt.set_resetting_code(pin) + self.card().set_resetting_code(pin) } pub fn set_pso_enc_dec_key(&mut self, key: &[u8]) -> Result<(), Error> { - self.oc.opt.set_pso_enc_dec_key(key) + self.card().set_pso_enc_dec_key(key) } pub fn reset_user_pin(&mut self, new: &[u8]) -> Result<(), Error> { - self.oc.opt.reset_retry_counter_pw1(new, None) + self.card().reset_retry_counter_pw1(new, None) } /// Upload a ValidErasedKeyAmalgamation to the card as a specific KeyType. @@ -601,7 +649,7 @@ impl Admin<'_, '_> { password: Option, ) -> Result<(), Error> { let key = vka_as_uploadable_key(vka, password); - self.oc.opt.key_import(key, key_type) + self.card().key_import(key, key_type) } /// Wrapper fn for `public_to_fingerprint` that uses SHA256/AES128 as default parameters. @@ -628,8 +676,8 @@ impl Admin<'_, '_> { algo: Option, ) -> Result<(PublicKeyMaterial, KeyGenerationTime), Error> { match algo { - Some(algo) => self.oc.opt.generate_key_simple(Self::ptf, key_type, algo), - None => self.oc.opt.generate_key(Self::ptf, key_type, None), + Some(algo) => self.card().generate_key_simple(Self::ptf, key_type, algo), + None => self.card().generate_key(Self::ptf, key_type, None), } } } diff --git a/openpgp-card-sequoia/src/lib.rs b/openpgp-card-sequoia/src/lib.rs index 2fb5f51..7a5f830 100644 --- a/openpgp-card-sequoia/src/lib.rs +++ b/openpgp-card-sequoia/src/lib.rs @@ -13,14 +13,14 @@ //! //! ```no_run //! use openpgp_card_pcsc::PcscBackend; -//! use openpgp_card_sequoia::card::Card; +//! use openpgp_card_sequoia::card::{Card, Open}; //! //! # fn main() -> Result<(), Box> { //! for backend in PcscBackend::cards(None)? { -//! let mut card = Card::new(backend); -//! let mut open = card.transaction()?; +//! let mut card: Card = backend.into(); +//! let mut transaction = card.transaction()?; //! println!("Found OpenPGP card with ident '{}'", -//! open.application_identifier()?.ident()); +//! transaction.application_identifier()?.ident()); //! } //! # Ok(()) //! # } @@ -30,12 +30,12 @@ //! //! ```no_run //! use openpgp_card_pcsc::PcscBackend; -//! use openpgp_card_sequoia::card::Card; +//! use openpgp_card_sequoia::card::{Card, Open}; //! //! # fn main() -> Result<(), Box> { //! let backend = PcscBackend::open_by_ident("abcd:12345678", None)?; -//! let mut card = Card::new(backend); -//! let mut open = card.transaction()?; +//! let mut card: Card = backend.into(); +//! let mut transaction = card.transaction()?; //! # Ok(()) //! # } //! ``` @@ -51,18 +51,18 @@ //! //! ```no_run //! use openpgp_card_pcsc::PcscBackend; -//! use openpgp_card_sequoia::card::Card; +//! use openpgp_card_sequoia::card::{Card, Open}; //! //! # fn main() -> Result<(), Box> { //! // Open card via PCSC //! use sequoia_openpgp::policy::StandardPolicy; //! let backend = PcscBackend::open_by_ident("abcd:12345678", None)?; -//! let mut card = Card::new(backend); -//! let mut open = card.transaction()?; +//! let mut card: Card = backend.into(); +//! let mut transaction = card.transaction()?; //! //! // Get authorization for user access to the card with password -//! open.verify_user(b"123456")?; -//! let mut user = open.user_card().expect("This should not fail"); +//! transaction.verify_user(b"123456")?; +//! let mut user = transaction.user_card().expect("This should not fail"); //! //! // Get decryptor //! let decryptor = user.decryptor(&|| { println!("Touch confirmation needed for decryption") }); @@ -88,17 +88,17 @@ //! //! ```no_run //! use openpgp_card_pcsc::PcscBackend; -//! use openpgp_card_sequoia::card::Card; +//! use openpgp_card_sequoia::card::{Card, Open}; //! //! # fn main() -> Result<(), Box> { //! // Open card via PCSC //! let backend = PcscBackend::open_by_ident("abcd:12345678", None)?; -//! let mut card = Card::new(backend); -//! let mut open = card.transaction()?; +//! let mut card: Card = backend.into(); +//! let mut transaction = card.transaction()?; //! //! // Get authorization for signing access to the card with password -//! open.verify_user_for_signing(b"123456")?; -//! let mut user = open.signing_card().expect("This should not fail"); +//! transaction.verify_user_for_signing(b"123456")?; +//! let mut user = transaction.signing_card().expect("This should not fail"); //! //! // Get signer //! let signer = user.signer(&|| println!("Touch confirmation needed for signing")); @@ -114,17 +114,17 @@ //! //! ```no_run //! use openpgp_card_pcsc::PcscBackend; -//! use openpgp_card_sequoia::card::Card; +//! use openpgp_card_sequoia::card::{Card, Open}; //! //! # fn main() -> Result<(), Box> { //! // Open card via PCSC //! let backend = PcscBackend::open_by_ident("abcd:12345678", None)?; -//! let mut card = Card::new(backend); -//! let mut open = card.transaction()?; +//! let mut card: Card = backend.into(); +//! let mut transaction = card.transaction()?; //! //! // Get authorization for admin access to the card with password -//! open.verify_admin(b"12345678")?; -//! let mut admin = open.admin_card().expect("This should not fail"); +//! transaction.verify_admin(b"12345678")?; +//! let mut admin = transaction.admin_card().expect("This should not fail"); //! //! // Set the Name and URL fields on the card //! admin.set_name("Bar<( - open: &mut Open<'app>, + open: &mut Card>, key_sig: PublicKey, key_dec: Option, key_aut: Option, @@ -226,7 +226,7 @@ pub fn public_key_material_and_fp_to_key( } /// Get a PublicKey representation for a key slot on the card -pub fn key_slot(open: &mut Open, kt: KeyType) -> Result, Error> { +pub fn key_slot(open: &mut Card, kt: KeyType) -> Result, Error> { // FIXME: only read these once, if multiple subkeys are retrieved from the card let times = open.key_generation_times()?; let fps = open.fingerprints()?; diff --git a/tools/src/bin/opgpcard/commands/admin.rs b/tools/src/bin/opgpcard/commands/admin.rs index 6c16b3c..4cbd347 100644 --- a/tools/src/bin/opgpcard/commands/admin.rs +++ b/tools/src/bin/opgpcard/commands/admin.rs @@ -5,7 +5,7 @@ use anyhow::{anyhow, Result}; use clap::{Parser, ValueEnum}; -use openpgp_card_sequoia::card::{Admin, Open}; +use openpgp_card_sequoia::card::{Admin, Open, Transaction}; use openpgp_card_sequoia::util::public_key_material_to_key; use sequoia_openpgp::types::{HashAlgorithm, SymmetricAlgorithm}; @@ -114,7 +114,7 @@ pub enum BasePlusAttKeySlot { Att, } -impl From for openpgp_card_sequoia::types::KeyType { +impl From for KeyType { fn from(ks: BasePlusAttKeySlot) -> Self { match ks { BasePlusAttKeySlot::Sig => KeyType::Signing, @@ -164,7 +164,7 @@ pub enum Algo { Curve25519, } -impl From for openpgp_card_sequoia::types::AlgoSimple { +impl From for AlgoSimple { fn from(a: Algo) -> Self { match a { Algo::Rsa2048 => AlgoSimple::RSA2k, @@ -184,17 +184,17 @@ pub fn admin( command: AdminCommand, ) -> Result<(), Box> { let backend = util::open_card(&command.ident)?; - let mut card = Card::new(backend); - let mut open = card.transaction()?; + let mut open: Card = backend.into(); + let mut card = open.transaction()?; - let admin_pin = util::get_pin(&mut open, command.admin_pin, ENTER_ADMIN_PIN); + let admin_pin = util::get_pin(&mut card, command.admin_pin, ENTER_ADMIN_PIN); match command.cmd { AdminSubCommand::Name { name } => { - name_command(&name, open, admin_pin.as_deref())?; + name_command(&name, card, admin_pin.as_deref())?; } AdminSubCommand::Url { url } => { - url_command(&url, open, admin_pin.as_deref())?; + url_command(&url, card, admin_pin.as_deref())?; } AdminSubCommand::Import { keyfile, @@ -202,19 +202,19 @@ pub fn admin( dec_fp, auth_fp, } => { - import_command(keyfile, sig_fp, dec_fp, auth_fp, open, admin_pin.as_deref())?; + import_command(keyfile, sig_fp, dec_fp, auth_fp, card, admin_pin.as_deref())?; } AdminSubCommand::Generate(cmd) => { generate_command( output_format, output_version, - open, + card, admin_pin.as_deref(), cmd, )?; } AdminSubCommand::Touch { key, policy } => { - touch_command(open, admin_pin.as_deref(), key, policy)?; + touch_command(card, admin_pin.as_deref(), key, policy)?; } } Ok(()) @@ -249,7 +249,7 @@ fn keys_pick_explicit<'a>( } fn gen_subkeys( - admin: &mut Admin, + admin: &mut Card, decrypt: bool, auth: bool, algo: Option, @@ -297,10 +297,10 @@ fn gen_subkeys( fn name_command( name: &str, - mut open: Open, + mut card: Card, admin_pin: Option<&[u8]>, ) -> Result<(), Box> { - let mut admin = util::verify_to_admin(&mut open, admin_pin)?; + let mut admin = util::verify_to_admin(&mut card, admin_pin)?; admin.set_name(name)?; Ok(()) @@ -308,10 +308,10 @@ fn name_command( fn url_command( url: &str, - mut open: Open, + mut card: Card, admin_pin: Option<&[u8]>, ) -> Result<(), Box> { - let mut admin = util::verify_to_admin(&mut open, admin_pin)?; + let mut admin = util::verify_to_admin(&mut card, admin_pin)?; admin.set_url(url)?; Ok(()) @@ -322,7 +322,7 @@ fn import_command( sig_fp: Option, dec_fp: Option, auth_fp: Option, - mut open: Open, + mut card: Card, admin_pin: Option<&[u8]>, ) -> Result<(), Box> { let key = Cert::from_file(keyfile)?; @@ -410,7 +410,7 @@ fn import_command( let auth_p = get_pw_for_key(&auth, "authentication")?; // upload keys to card - let mut admin = util::verify_to_admin(&mut open, admin_pin)?; + let mut admin = util::verify_to_admin(&mut card, admin_pin)?; if let Some(sig) = sig { println!("Uploading {} as signing key", sig.fingerprint()); @@ -430,16 +430,16 @@ fn import_command( fn generate_command( output_format: OutputFormat, output_version: OutputVersion, - mut open: Open, + mut card: Card, admin_pin: Option<&[u8]>, cmd: AdminGenerateCommand, ) -> Result<()> { - let user_pin = util::get_pin(&mut open, cmd.user_pin, ENTER_USER_PIN); + let user_pin = util::get_pin(&mut card, cmd.user_pin, ENTER_USER_PIN); let mut output = output::AdminGenerate::default(); - output.ident(open.application_identifier()?.ident()); + output.ident(card.application_identifier()?.ident()); // 1) Interpret the user's choice of algorithm. // @@ -461,7 +461,7 @@ fn generate_command( // 2) Then, generate keys on the card. // We need "admin" access to the card for this). let (key_sig, key_dec, key_aut) = { - if let Ok(mut admin) = util::verify_to_admin(&mut open, admin_pin) { + if let Ok(mut admin) = util::verify_to_admin(&mut card, admin_pin) { gen_subkeys(&mut admin, cmd.decrypt, cmd.auth, algo)? } else { return Err(anyhow!("Failed to open card in admin mode.")); @@ -472,7 +472,7 @@ fn generate_command( // need "signing" access to the card (to make binding signatures within // the Cert). let cert = crate::get_cert( - &mut open, + &mut card, key_sig, key_dec, key_aut, @@ -493,7 +493,7 @@ fn generate_command( } fn touch_command( - mut open: Open, + mut card: Card, admin_pin: Option<&[u8]>, key: BasePlusAttKeySlot, policy: TouchPolicy, @@ -502,7 +502,7 @@ fn touch_command( let pol = openpgp_card_sequoia::types::TouchPolicy::from(policy); - let mut admin = util::verify_to_admin(&mut open, admin_pin)?; + let mut admin = util::verify_to_admin(&mut card, admin_pin)?; admin.set_uif(kt, pol)?; Ok(()) diff --git a/tools/src/bin/opgpcard/commands/attestation.rs b/tools/src/bin/opgpcard/commands/attestation.rs index a6bae12..2bce249 100644 --- a/tools/src/bin/opgpcard/commands/attestation.rs +++ b/tools/src/bin/opgpcard/commands/attestation.rs @@ -7,8 +7,8 @@ use std::path::PathBuf; use anyhow::Result; use clap::{Parser, ValueEnum}; +use openpgp_card_sequoia::card::{Card, Open}; -use openpgp_card_sequoia::card::Card; use openpgp_card_sequoia::types::KeyType; use crate::versioned_output::{OutputBuilder, OutputFormat, OutputVersion}; @@ -60,7 +60,7 @@ pub enum BaseKeySlot { Aut, } -impl From for openpgp_card_sequoia::types::KeyType { +impl From for KeyType { fn from(ks: BaseKeySlot) -> Self { match ks { BaseKeySlot::Sig => KeyType::Signing, @@ -94,12 +94,12 @@ fn cert( let mut output = output::AttestationCert::default(); let backend = pick_card_for_reading(ident)?; - let mut card = Card::new(backend); - let mut open = card.transaction()?; + let mut open: Card = backend.into(); + let mut card = open.transaction()?; - output.ident(open.application_identifier()?.ident()); + output.ident(card.application_identifier()?.ident()); - if let Ok(ac) = open.attestation_certificate() { + if let Ok(ac) = card.attestation_certificate() { let pem = util::pem_encode(ac); output.attestation_cert(pem); } @@ -114,12 +114,12 @@ fn generate( user_pin: Option, ) -> Result<(), Box> { let backend = util::open_card(ident)?; - let mut card = Card::new(backend); - let mut open = card.transaction()?; + let mut open: Card = backend.into(); + let mut card = open.transaction()?; - let user_pin = util::get_pin(&mut open, user_pin, ENTER_USER_PIN); + let user_pin = util::get_pin(&mut card, user_pin, ENTER_USER_PIN); - let mut sign = util::verify_to_sign(&mut open, user_pin.as_deref())?; + let mut sign = util::verify_to_sign(&mut card, user_pin.as_deref())?; let kt = KeyType::from(key); sign.generate_attestation(kt, &|| { @@ -130,15 +130,15 @@ fn generate( fn statement(ident: Option, key: BaseKeySlot) -> Result<(), Box> { let backend = pick_card_for_reading(ident)?; - let mut card = Card::new(backend); - let mut open = card.transaction()?; + let mut open: Card = backend.into(); + let mut card = open.transaction()?; // Get cardholder certificate from card. let mut select_data_workaround = false; // Use "select data" workaround if the card reports a // yk firmware version number >= 5 and <= 5.4.3 - if let Ok(version) = open.firmware_version() { + if let Ok(version) = card.firmware_version() { if version.len() == 3 && version[0] == 5 && (version[1] < 4 || (version[1] == 4 && version[2] <= 3)) @@ -149,13 +149,13 @@ fn statement(ident: Option, key: BaseKeySlot) -> Result<(), Box open.select_data(0, &[0x7F, 0x21], select_data_workaround)?, - BaseKeySlot::Dec => open.select_data(1, &[0x7F, 0x21], select_data_workaround)?, - BaseKeySlot::Sig => open.select_data(2, &[0x7F, 0x21], select_data_workaround)?, + BaseKeySlot::Aut => card.select_data(0, &[0x7F, 0x21], select_data_workaround)?, + BaseKeySlot::Dec => card.select_data(1, &[0x7F, 0x21], select_data_workaround)?, + BaseKeySlot::Sig => card.select_data(2, &[0x7F, 0x21], select_data_workaround)?, }; // Get DO "cardholder certificate" (returns the slot that was previously selected) - let cert = open.cardholder_certificate()?; + let cert = card.cardholder_certificate()?; if !cert.is_empty() { let pem = util::pem_encode(cert); diff --git a/tools/src/bin/opgpcard/commands/decrypt.rs b/tools/src/bin/opgpcard/commands/decrypt.rs index 34c7d56..7acc0c8 100644 --- a/tools/src/bin/opgpcard/commands/decrypt.rs +++ b/tools/src/bin/opgpcard/commands/decrypt.rs @@ -7,13 +7,12 @@ use clap::Parser; use std::path::PathBuf; +use openpgp_card_sequoia::card::{Card, Open}; use sequoia_openpgp::{ parse::{stream::DecryptorBuilder, Parse}, policy::StandardPolicy, }; -use openpgp_card_sequoia::card::Card; - use crate::util; #[derive(Parser, Debug)] @@ -35,16 +34,16 @@ pub fn decrypt(command: DecryptCommand) -> Result<(), Box let input = util::open_or_stdin(command.input.as_deref())?; let backend = util::open_card(&command.ident)?; - let mut card = Card::new(backend); - let mut open = card.transaction()?; + let mut open: Card = backend.into(); + let mut card = open.transaction()?; - if open.fingerprints()?.decryption().is_none() { + if card.fingerprints()?.decryption().is_none() { return Err(anyhow!("Can't decrypt: this card has no key in the decryption slot.").into()); } - let user_pin = util::get_pin(&mut open, command.pin_file, crate::ENTER_USER_PIN); + let user_pin = util::get_pin(&mut card, command.pin_file, crate::ENTER_USER_PIN); - let mut user = util::verify_to_user(&mut open, user_pin.as_deref())?; + let mut user = util::verify_to_user(&mut card, user_pin.as_deref())?; let d = user.decryptor(&|| println!("Touch confirmation needed for decryption"))?; let db = DecryptorBuilder::from_reader(input)?; diff --git a/tools/src/bin/opgpcard/commands/factory_reset.rs b/tools/src/bin/opgpcard/commands/factory_reset.rs index f472a21..b68ac95 100644 --- a/tools/src/bin/opgpcard/commands/factory_reset.rs +++ b/tools/src/bin/opgpcard/commands/factory_reset.rs @@ -4,8 +4,7 @@ use anyhow::{anyhow, Result}; use clap::Parser; - -use openpgp_card_sequoia::card::Card; +use openpgp_card_sequoia::card::{Card, Open}; use crate::util; @@ -17,9 +16,9 @@ pub struct FactoryResetCommand { pub fn factory_reset(command: FactoryResetCommand) -> Result<()> { println!("Resetting Card {}", command.ident); - let card = util::open_card(&command.ident)?; - let mut card = Card::new(card); + let backend = util::open_card(&command.ident)?; + let mut open: Card = backend.into(); - let mut open = card.transaction()?; - open.factory_reset().map_err(|e| anyhow!(e)) + let mut card = open.transaction()?; + card.factory_reset().map_err(|e| anyhow!(e)) } diff --git a/tools/src/bin/opgpcard/commands/info.rs b/tools/src/bin/opgpcard/commands/info.rs index 635e857..261dbdd 100644 --- a/tools/src/bin/opgpcard/commands/info.rs +++ b/tools/src/bin/opgpcard/commands/info.rs @@ -5,8 +5,7 @@ use anyhow::Result; use clap::Parser; - -use openpgp_card_sequoia::card::Card; +use openpgp_card_sequoia::card::{Card, Open}; use crate::output; use crate::pick_card_for_reading; @@ -27,10 +26,10 @@ pub fn print_info( let mut output = output::Info::default(); let backend = pick_card_for_reading(command.ident)?; - let mut card = Card::new(backend); - let mut open = card.transaction()?; + let mut open: Card = backend.into(); + let mut card = open.transaction()?; - let ai = open.application_identifier()?; + let ai = card.application_identifier()?; output.ident(ai.ident()); @@ -41,34 +40,34 @@ pub fn print_info( output.manufacturer_id(format!("{:04X}", ai.manufacturer())); output.manufacturer_name(ai.manufacturer_name().to_string()); - if let Some(cc) = open.historical_bytes()?.card_capabilities() { + if let Some(cc) = card.historical_bytes()?.card_capabilities() { for line in cc.to_string().lines() { let line = line.strip_prefix("- ").unwrap_or(line); output.card_capability(line.to_string()); } } - if let Some(csd) = open.historical_bytes()?.card_service_data() { + if let Some(csd) = card.historical_bytes()?.card_service_data() { for line in csd.to_string().lines() { let line = line.strip_prefix("- ").unwrap_or(line); output.card_service_data(line.to_string()); } } - if let Some(eli) = open.extended_length_information()? { + if let Some(eli) = card.extended_length_information()? { for line in eli.to_string().lines() { let line = line.strip_prefix("- ").unwrap_or(line); output.extended_length_info(line.to_string()); } } - let ec = open.extended_capabilities()?; + let ec = card.extended_capabilities()?; for line in ec.to_string().lines() { let line = line.strip_prefix("- ").unwrap_or(line); output.extended_capability(line.to_string()); } // Algorithm information (list of supported algorithms) - if let Ok(Some(ai)) = open.algorithm_information() { + if let Ok(Some(ai)) = card.algorithm_information() { for line in ai.to_string().lines() { let line = line.strip_prefix("- ").unwrap_or(line); output.algorithm(line.to_string()); @@ -78,7 +77,7 @@ pub fn print_info( // FIXME: print KDF info // YubiKey specific (?) firmware version - if let Ok(ver) = open.firmware_version() { + if let Ok(ver) = card.firmware_version() { let ver = ver.iter().map(u8::to_string).collect::>().join("."); output.firmware_version(ver); } diff --git a/tools/src/bin/opgpcard/commands/pin.rs b/tools/src/bin/opgpcard/commands/pin.rs index 97dac49..a881f51 100644 --- a/tools/src/bin/opgpcard/commands/pin.rs +++ b/tools/src/bin/opgpcard/commands/pin.rs @@ -7,7 +7,7 @@ use std::path::PathBuf; use anyhow::Result; use clap::Parser; -use openpgp_card_sequoia::card::{Card, Open}; +use openpgp_card_sequoia::card::{Card, Open, Transaction}; use crate::util; use crate::util::{load_pin, print_gnuk_note}; @@ -72,51 +72,51 @@ pub enum PinSubCommand { pub fn pin(ident: &str, cmd: PinSubCommand) -> Result<()> { let backend = util::open_card(ident)?; - let mut card = Card::new(backend); - let open = card.transaction()?; + let mut open: Card = backend.into(); + let card = open.transaction()?; match cmd { PinSubCommand::SetUser { user_pin_old, user_pin_new, - } => set_user(user_pin_old, user_pin_new, open), + } => set_user(user_pin_old, user_pin_new, card), PinSubCommand::SetAdmin { admin_pin_old, admin_pin_new, - } => set_admin(admin_pin_old, admin_pin_new, open), + } => set_admin(admin_pin_old, admin_pin_new, card), PinSubCommand::ResetUser { admin_pin, user_pin_new, - } => reset_user(admin_pin, user_pin_new, open), + } => reset_user(admin_pin, user_pin_new, card), PinSubCommand::SetReset { admin_pin, reset_code, - } => set_reset(admin_pin, reset_code, open), + } => set_reset(admin_pin, reset_code, card), PinSubCommand::ResetUserRc { reset_code, user_pin_new, - } => reset_user_rc(reset_code, user_pin_new, open), + } => reset_user_rc(reset_code, user_pin_new, card), } } fn set_user( user_pin_old: Option, user_pin_new: Option, - mut open: Open, + mut card: Card, ) -> Result<()> { - let pinpad_modify = open.feature_pinpad_modify(); + let pinpad_modify = card.feature_pinpad_modify(); let res = if !pinpad_modify { // get current user pin - let user_pin1 = util::get_pin(&mut open, user_pin_old, ENTER_USER_PIN) + let user_pin1 = util::get_pin(&mut card, user_pin_old, ENTER_USER_PIN) .expect("this should never be None"); // verify pin - open.verify_user(&user_pin1)?; + card.verify_user(&user_pin1)?; println!("PIN was accepted by the card.\n"); let pin_new = match user_pin_new { @@ -128,10 +128,10 @@ fn set_user( }; // set new user pin - open.change_user_pin(&user_pin1, &pin_new) + card.change_user_pin(&user_pin1, &pin_new) } else { // set new user pin via pinpad - open.change_user_pin_pinpad(&|| { + card.change_user_pin_pinpad(&|| { println!("Enter old User PIN on card reader pinpad, then new User PIN (twice).") }) }; @@ -140,7 +140,7 @@ fn set_user( Err(err) => { println!("\nFailed to change the User PIN!"); println!("{:?}", err); - print_gnuk_note(err, &open)?; + print_gnuk_note(err, &card)?; } Ok(_) => println!("\nUser PIN has been set."), } @@ -150,17 +150,17 @@ fn set_user( fn set_admin( admin_pin_old: Option, admin_pin_new: Option, - mut open: Open, + mut card: Card, ) -> Result<()> { - let pinpad_modify = open.feature_pinpad_modify(); + let pinpad_modify = card.feature_pinpad_modify(); if !pinpad_modify { // get current admin pin - let admin_pin1 = util::get_pin(&mut open, admin_pin_old, ENTER_ADMIN_PIN) + let admin_pin1 = util::get_pin(&mut card, admin_pin_old, ENTER_ADMIN_PIN) .expect("this should never be None"); // verify pin - open.verify_admin(&admin_pin1)?; + card.verify_admin(&admin_pin1)?; // (Verifying the PIN here fixes this class of problems: // https://developers.yubico.com/PGP/PGP_PIN_Change_Behavior.html // It is also just generally more user friendly than failing later) @@ -175,10 +175,10 @@ fn set_admin( }; // set new admin pin - open.change_admin_pin(&admin_pin1, &pin_new)?; + card.change_admin_pin(&admin_pin1, &pin_new)?; } else { // set new admin pin via pinpad - open.change_admin_pin_pinpad(&|| { + card.change_admin_pin_pinpad(&|| { println!("Enter old Admin PIN on card reader pinpad, then new Admin PIN (twice).") })?; }; @@ -190,16 +190,16 @@ fn set_admin( fn reset_user( admin_pin: Option, user_pin_new: Option, - mut open: Open, + mut card: Card, ) -> Result<()> { // verify admin pin - match util::get_pin(&mut open, admin_pin, ENTER_ADMIN_PIN) { + match util::get_pin(&mut card, admin_pin, ENTER_ADMIN_PIN) { Some(admin_pin) => { // verify pin - open.verify_admin(&admin_pin)?; + card.verify_admin(&admin_pin)?; } None => { - open.verify_admin_pinpad(&|| println!("Enter Admin PIN on pinpad."))?; + card.verify_admin_pinpad(&|| println!("Enter Admin PIN on pinpad."))?; } } println!("PIN was accepted by the card.\n"); @@ -210,7 +210,7 @@ fn reset_user( Some(path) => load_pin(&path)?, }; - let res = if let Some(mut admin) = open.admin_card() { + let res = if let Some(mut admin) = card.admin_card() { admin.reset_user_pin(&pin) } else { return Err(anyhow::anyhow!("Failed to use card in admin-mode.")); @@ -219,7 +219,7 @@ fn reset_user( match res { Err(err) => { println!("\nFailed to change the User PIN!"); - print_gnuk_note(err, &open)?; + print_gnuk_note(err, &card)?; } Ok(_) => println!("\nUser PIN has been set."), } @@ -229,16 +229,16 @@ fn reset_user( fn set_reset( admin_pin: Option, reset_code: Option, - mut open: Open, + mut card: Card, ) -> Result<()> { // verify admin pin - match util::get_pin(&mut open, admin_pin, ENTER_ADMIN_PIN) { + match util::get_pin(&mut card, admin_pin, ENTER_ADMIN_PIN) { Some(admin_pin) => { // verify pin - open.verify_admin(&admin_pin)?; + card.verify_admin(&admin_pin)?; } None => { - open.verify_admin_pinpad(&|| println!("Enter Admin PIN on pinpad."))?; + card.verify_admin_pinpad(&|| println!("Enter Admin PIN on pinpad."))?; } } println!("PIN was accepted by the card.\n"); @@ -252,7 +252,7 @@ fn set_reset( Some(path) => load_pin(&path)?, }; - if let Some(mut admin) = open.admin_card() { + if let Some(mut admin) = card.admin_card() { admin.set_resetting_code(&code)?; println!("\nResetting code has been set."); Ok(()) @@ -264,7 +264,7 @@ fn set_reset( fn reset_user_rc( reset_code: Option, user_pin_new: Option, - mut open: Open, + mut card: Card, ) -> Result<()> { // reset by presenting resetting code @@ -285,10 +285,10 @@ fn reset_user_rc( }; // reset to new user pin - match open.reset_user_pin(&rst, &pin) { + match card.reset_user_pin(&rst, &pin) { Err(err) => { println!("\nFailed to change the User PIN!"); - print_gnuk_note(err, &open) + print_gnuk_note(err, &card) } Ok(_) => { println!("\nUser PIN has been set."); diff --git a/tools/src/bin/opgpcard/commands/pubkey.rs b/tools/src/bin/opgpcard/commands/pubkey.rs index 9673643..8b93b80 100644 --- a/tools/src/bin/opgpcard/commands/pubkey.rs +++ b/tools/src/bin/opgpcard/commands/pubkey.rs @@ -8,9 +8,9 @@ use clap::Parser; use std::path::PathBuf; +use openpgp_card_sequoia::card::{Card, Open}; use sequoia_openpgp::serialize::SerializeInto; -use openpgp_card_sequoia::card::Card; use openpgp_card_sequoia::types::KeyType; use openpgp_card_sequoia::util::public_key_material_and_fp_to_key; @@ -40,17 +40,17 @@ pub fn print_pubkey( let mut output = output::PublicKey::default(); let backend = pick_card_for_reading(command.ident)?; - let mut card = Card::new(backend); - let mut open = card.transaction()?; + let mut open: Card = backend.into(); + let mut card = open.transaction()?; - let ident = open.application_identifier()?.ident(); + let ident = card.application_identifier()?.ident(); output.ident(ident); - let user_pin = util::get_pin(&mut open, command.user_pin, crate::ENTER_USER_PIN); + let user_pin = util::get_pin(&mut card, command.user_pin, crate::ENTER_USER_PIN); - let pkm = open.public_key(KeyType::Signing)?; - let times = open.key_generation_times()?; - let fps = open.fingerprints()?; + let pkm = card.public_key(KeyType::Signing)?; + let times = card.key_generation_times()?; + let fps = card.fingerprints()?; let key_sig = public_key_material_and_fp_to_key( &pkm, @@ -60,7 +60,7 @@ pub fn print_pubkey( )?; let mut key_dec = None; - if let Ok(pkm) = open.public_key(KeyType::Decryption) { + if let Ok(pkm) = card.public_key(KeyType::Decryption) { if let Some(ts) = times.decryption() { key_dec = Some(public_key_material_and_fp_to_key( &pkm, @@ -72,7 +72,7 @@ pub fn print_pubkey( } let mut key_aut = None; - if let Ok(pkm) = open.public_key(KeyType::Authentication) { + if let Ok(pkm) = card.public_key(KeyType::Authentication) { if let Some(ts) = times.authentication() { key_aut = Some(public_key_material_and_fp_to_key( &pkm, @@ -85,7 +85,7 @@ pub fn print_pubkey( } let cert = crate::get_cert( - &mut open, + &mut card, key_sig, key_dec, key_aut, diff --git a/tools/src/bin/opgpcard/commands/set_identity.rs b/tools/src/bin/opgpcard/commands/set_identity.rs index efb6cef..0eef31c 100644 --- a/tools/src/bin/opgpcard/commands/set_identity.rs +++ b/tools/src/bin/opgpcard/commands/set_identity.rs @@ -4,8 +4,7 @@ use anyhow::Result; use clap::{Parser, ValueEnum}; - -use openpgp_card_sequoia::card::Card; +use openpgp_card_sequoia::card::{Card, Open}; use crate::util; @@ -40,9 +39,9 @@ impl From for u8 { pub fn set_identity(command: SetIdentityCommand) -> Result<(), Box> { let backend = util::open_card(&command.ident)?; - let mut card = Card::new(backend); - let mut open = card.transaction()?; + let mut open: Card = backend.into(); + let mut card = open.transaction()?; - open.set_identity(u8::from(command.id))?; + card.set_identity(u8::from(command.id))?; Ok(()) } diff --git a/tools/src/bin/opgpcard/commands/sign.rs b/tools/src/bin/opgpcard/commands/sign.rs index 807fac9..a2b8315 100644 --- a/tools/src/bin/opgpcard/commands/sign.rs +++ b/tools/src/bin/opgpcard/commands/sign.rs @@ -7,10 +7,9 @@ use clap::Parser; use std::path::{Path, PathBuf}; +use openpgp_card_sequoia::card::{Card, Open}; use sequoia_openpgp::serialize::stream::{Armorer, Message, Signer}; -use openpgp_card_sequoia::card::Card; - use crate::util; #[derive(Parser, Debug)] @@ -46,16 +45,16 @@ pub fn sign_detached( let mut input = util::open_or_stdin(input)?; let backend = util::open_card(ident)?; - let mut card = Card::new(backend); - let mut open = card.transaction()?; + let mut open: Card = backend.into(); + let mut card = open.transaction()?; - if open.fingerprints()?.signature().is_none() { + if card.fingerprints()?.signature().is_none() { return Err(anyhow!("Can't sign: this card has no key in the signing slot.").into()); } - let user_pin = util::get_pin(&mut open, pin_file, crate::ENTER_USER_PIN); + let user_pin = util::get_pin(&mut card, pin_file, crate::ENTER_USER_PIN); - let mut sign = util::verify_to_sign(&mut open, user_pin.as_deref())?; + let mut sign = util::verify_to_sign(&mut card, user_pin.as_deref())?; let s = sign.signer(&|| println!("Touch confirmation needed for signing"))?; let message = Armorer::new(Message::new(std::io::stdout())).build()?; diff --git a/tools/src/bin/opgpcard/commands/ssh.rs b/tools/src/bin/opgpcard/commands/ssh.rs index 8110da7..d7323f2 100644 --- a/tools/src/bin/opgpcard/commands/ssh.rs +++ b/tools/src/bin/opgpcard/commands/ssh.rs @@ -5,8 +5,8 @@ use anyhow::Result; use clap::Parser; +use openpgp_card_sequoia::card::{Card, Open}; -use openpgp_card_sequoia::card::Card; use openpgp_card_sequoia::types::KeyType; use crate::output; @@ -30,21 +30,21 @@ pub fn print_ssh( let ident = command.ident; let backend = pick_card_for_reading(ident)?; - let mut card = Card::new(backend); - let mut open = card.transaction()?; + let mut open: Card = backend.into(); + let mut card = open.transaction()?; - let ident = open.application_identifier()?.ident(); + let ident = card.application_identifier()?.ident(); output.ident(ident.clone()); // Print fingerprint of authentication subkey - let fps = open.fingerprints()?; + let fps = card.fingerprints()?; if let Some(fp) = fps.authentication() { output.authentication_key_fingerprint(fp.to_string()); } // Show authentication subkey as openssh public key string - if let Ok(pkm) = open.public_key(KeyType::Authentication) { + if let Ok(pkm) = card.public_key(KeyType::Authentication) { if let Ok(ssh) = util::get_ssh_pubkey_string(&pkm, ident) { output.ssh_public_key(ssh); } diff --git a/tools/src/bin/opgpcard/commands/status.rs b/tools/src/bin/opgpcard/commands/status.rs index f4b5405..8717b65 100644 --- a/tools/src/bin/opgpcard/commands/status.rs +++ b/tools/src/bin/opgpcard/commands/status.rs @@ -5,8 +5,8 @@ use anyhow::Result; use clap::Parser; +use openpgp_card_sequoia::card::{Card, Open}; -use openpgp_card_sequoia::card::Card; use openpgp_card_sequoia::types::KeyType; use crate::output; @@ -35,17 +35,17 @@ pub fn print_status( output.verbose(command.verbose); let backend = pick_card_for_reading(command.ident)?; - let mut card = Card::new(backend); - let mut open = card.transaction()?; + let mut open: Card = backend.into(); + let mut card = open.transaction()?; - output.ident(open.application_identifier()?.ident()); + output.ident(card.application_identifier()?.ident()); - let ai = open.application_identifier()?; + let ai = card.application_identifier()?; let version = ai.version().to_be_bytes(); output.card_version(format!("{}.{}", version[0], version[1])); // card / cardholder metadata - let crd = open.cardholder_related_data()?; + let crd = card.cardholder_related_data()?; if let Some(name) = crd.name() { // FIXME: decoding as utf8 is wrong (the spec defines this field as latin1 encoded) @@ -67,7 +67,7 @@ pub fn print_status( output.card_holder(name); } - let url = open.url()?; + let url = card.url()?; if !url.is_empty() { output.url(url); } @@ -79,24 +79,24 @@ pub fn print_status( } // key information (imported vs. generated on card) - let ki = open.key_information().ok().flatten(); + let ki = card.key_information().ok().flatten(); - let pws = open.pw_status_bytes()?; + let pws = card.pw_status_bytes()?; // information about subkeys - let fps = open.fingerprints()?; - let kgt = open.key_generation_times()?; + let fps = card.fingerprints()?; + let kgt = card.key_generation_times()?; let mut signature_key = output::KeySlotInfo::default(); if let Some(fp) = fps.signature() { signature_key.fingerprint(fp.to_spaced_hex()); } - signature_key.algorithm(format!("{}", open.algorithm_attributes(KeyType::Signing)?)); + signature_key.algorithm(format!("{}", card.algorithm_attributes(KeyType::Signing)?)); if let Some(kgt) = kgt.signature() { signature_key.created(format!("{}", kgt.to_datetime())); } - if let Some(uif) = open.uif_signing()? { + if let Some(uif) = card.uif_signing()? { signature_key.touch_policy(format!("{}", uif.touch_policy())); signature_key.touch_features(format!("{}", uif.features())); } @@ -109,14 +109,14 @@ pub fn print_status( } if command.pkm { - if let Ok(pkm) = open.public_key(KeyType::Signing) { + if let Ok(pkm) = card.public_key(KeyType::Signing) { signature_key.public_key_material(pkm.to_string()); } } output.signature_key(signature_key); - let sst = open.security_support_template()?; + let sst = card.security_support_template()?; output.signature_count(sst.signature_count()); let mut decryption_key = output::KeySlotInfo::default(); @@ -125,12 +125,12 @@ pub fn print_status( } decryption_key.algorithm(format!( "{}", - open.algorithm_attributes(KeyType::Decryption)? + card.algorithm_attributes(KeyType::Decryption)? )); if let Some(kgt) = kgt.decryption() { decryption_key.created(format!("{}", kgt.to_datetime())); } - if let Some(uif) = open.uif_decryption()? { + if let Some(uif) = card.uif_decryption()? { decryption_key.touch_policy(format!("{}", uif.touch_policy())); decryption_key.touch_features(format!("{}", uif.features())); } @@ -138,7 +138,7 @@ pub fn print_status( decryption_key.status(format!("{}", ks)); } if command.pkm { - if let Ok(pkm) = open.public_key(KeyType::Decryption) { + if let Ok(pkm) = card.public_key(KeyType::Decryption) { decryption_key.public_key_material(pkm.to_string()); } } @@ -150,12 +150,12 @@ pub fn print_status( } authentication_key.algorithm(format!( "{}", - open.algorithm_attributes(KeyType::Authentication)? + card.algorithm_attributes(KeyType::Authentication)? )); if let Some(kgt) = kgt.authentication() { authentication_key.created(format!("{}", kgt.to_datetime())); } - if let Some(uif) = open.uif_authentication()? { + if let Some(uif) = card.uif_authentication()? { authentication_key.touch_policy(format!("{}", uif.touch_policy())); authentication_key.touch_features(format!("{}", uif.features())); } @@ -163,7 +163,7 @@ pub fn print_status( authentication_key.status(format!("{}", ks)); } if command.pkm { - if let Ok(pkm) = open.public_key(KeyType::Authentication) { + if let Ok(pkm) = card.public_key(KeyType::Authentication) { authentication_key.public_key_material(pkm.to_string()); } } @@ -180,7 +180,7 @@ pub fn print_status( // own `Option`, and (if any information about the // attestation key exists at all, which is not the case for most // cards) it should be printed as a fourth KeySlot block. - if let Some(uif) = open.uif_attestation()? { + if let Some(uif) = card.uif_attestation()? { output.card_touch_policy(uif.touch_policy().to_string()); output.card_touch_features(uif.features().to_string()); } @@ -192,7 +192,7 @@ pub fn print_status( } } - if let Ok(fps) = open.ca_fingerprints() { + if let Ok(fps) = card.ca_fingerprints() { for fp in fps.iter().flatten() { output.ca_fingerprint(fp.to_string()); } diff --git a/tools/src/bin/opgpcard/main.rs b/tools/src/bin/opgpcard/main.rs index dbc8af5..742da7d 100644 --- a/tools/src/bin/opgpcard/main.rs +++ b/tools/src/bin/opgpcard/main.rs @@ -8,7 +8,7 @@ use clap::Parser; use sequoia_openpgp::Cert; -use openpgp_card_sequoia::card::{Card, Open}; +use openpgp_card_sequoia::card::{Card, Open, Transaction}; use openpgp_card_sequoia::types::CardBackend; use openpgp_card_sequoia::util::make_cert; use openpgp_card_sequoia::PublicKey; @@ -90,10 +90,9 @@ fn list_cards(format: OutputFormat, output_version: OutputVersion) -> Result<()> let mut output = output::List::default(); if !cards.is_empty() { for backend in cards { - let mut card = Card::new(backend); - let open = card.transaction()?; + let mut open: Card = backend.into(); - output.push(open.application_identifier()?.ident()); + output.push(open.transaction()?.application_identifier()?.ident()); } } println!("{}", output.print(format, output_version)?); @@ -123,7 +122,7 @@ fn pick_card_for_reading(ident: Option) -> Result, key_sig: PublicKey, key_dec: Option, key_aut: Option, @@ -131,7 +130,7 @@ fn get_cert( user_ids: &[String], prompt: &dyn Fn(), ) -> Result { - if user_pin.is_none() && open.feature_pinpad_verify() { + if user_pin.is_none() && card.feature_pinpad_verify() { println!( "The public cert will now be generated.\n\n\ You will need to enter your User PIN multiple times during this process.\n\n" @@ -139,7 +138,7 @@ fn get_cert( } make_cert( - open, + card, key_sig, key_dec, key_aut, diff --git a/tools/src/bin/opgpcard/util.rs b/tools/src/bin/opgpcard/util.rs index 28a462c..a2d7b0c 100644 --- a/tools/src/bin/opgpcard/util.rs +++ b/tools/src/bin/opgpcard/util.rs @@ -5,7 +5,7 @@ use anyhow::{anyhow, Context, Result}; use std::path::{Path, PathBuf}; use openpgp_card_pcsc::PcscBackend; -use openpgp_card_sequoia::card::{Admin, Open, Sign, User}; +use openpgp_card_sequoia::card::{Admin, Card, Sign, Transaction, User}; use openpgp_card_sequoia::types::{ Algo, CardBackend, Curve, EccType, Error, PublicKeyMaterial, StatusBytes, }; @@ -23,11 +23,15 @@ pub(crate) fn open_card(ident: &str) -> Result, msg: &str) -> Option> { +pub(crate) fn get_pin( + card: &mut Card>, + pin_file: Option, + msg: &str, +) -> Option> { if let Some(path) = pin_file { // we have a pin file Some(load_pin(&path).ok()?) - } else if !open.feature_pinpad_verify() { + } else if !card.feature_pinpad_verify() { // we have no pin file and no pinpad let pin = rpassword::prompt_password(msg).ok()?; Some(pin.into_bytes()) @@ -51,53 +55,53 @@ pub(crate) fn input_pin_twice(msg1: &str, msg2: &str) -> Result> { } pub(crate) fn verify_to_user<'app, 'open>( - open: &'open mut Open<'app>, + card: &'open mut Card>, pin: Option<&[u8]>, -) -> Result, Box> { +) -> Result>, Box> { if let Some(pin) = pin { - open.verify_user(pin)?; + card.verify_user(pin)?; } else { - if !open.feature_pinpad_verify() { + if !card.feature_pinpad_verify() { return Err(anyhow!("No user PIN file provided, and no pinpad found").into()); }; - open.verify_user_pinpad(&|| println!("Enter user PIN on card reader pinpad."))?; + card.verify_user_pinpad(&|| println!("Enter user PIN on card reader pinpad."))?; } - open.user_card() + card.user_card() .ok_or_else(|| anyhow!("Couldn't get user access").into()) } pub(crate) fn verify_to_sign<'app, 'open>( - open: &'open mut Open<'app>, + card: &'open mut Card>, pin: Option<&[u8]>, -) -> Result, Box> { +) -> Result>, Box> { if let Some(pin) = pin { - open.verify_user_for_signing(pin)?; + card.verify_user_for_signing(pin)?; } else { - if !open.feature_pinpad_verify() { + if !card.feature_pinpad_verify() { return Err(anyhow!("No user PIN file provided, and no pinpad found").into()); } - open.verify_user_for_signing_pinpad(&|| println!("Enter user PIN on card reader pinpad."))?; + card.verify_user_for_signing_pinpad(&|| println!("Enter user PIN on card reader pinpad."))?; } - open.signing_card() + card.signing_card() .ok_or_else(|| anyhow!("Couldn't get sign access").into()) } pub(crate) fn verify_to_admin<'app, 'open>( - open: &'open mut Open<'app>, + card: &'open mut Card>, pin: Option<&[u8]>, -) -> Result, Box> { +) -> Result>, Box> { if let Some(pin) = pin { - open.verify_admin(pin)?; + card.verify_admin(pin)?; } else { - if !open.feature_pinpad_verify() { + if !card.feature_pinpad_verify() { return Err(anyhow!("No admin PIN file provided, and no pinpad found").into()); } - open.verify_admin_pinpad(&|| println!("Enter admin PIN on card reader pinpad."))?; + card.verify_admin_pinpad(&|| println!("Enter admin PIN on card reader pinpad."))?; } - open.admin_card() + card.admin_card() .ok_or_else(|| anyhow!("Couldn't get admin access").into()) } @@ -215,7 +219,7 @@ pub(crate) fn get_ssh_pubkey_string(pkm: &PublicKeyMaterial, ident: String) -> R /// 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 /// absence of keys on the card might be the reason for the error they get. -pub(crate) fn print_gnuk_note(err: Error, card: &Open) -> Result<()> { +pub(crate) fn print_gnuk_note(err: Error, card: &Card) -> Result<()> { if matches!( err, Error::CardStatus(StatusBytes::ConditionOfUseNotSatisfied)