Merge branch 'ocs-card-state' into 'main'

Refactor openpgp-card-state to use Card<State> types

See merge request openpgp-card/openpgp-card!20
This commit is contained in:
Nora Widdecke 2022-10-27 12:46:28 +00:00
commit 46b5f59d0f
21 changed files with 446 additions and 402 deletions

View file

@ -4,15 +4,14 @@
use anyhow::Result; use anyhow::Result;
use openpgp_card_pcsc::PcscBackend; use openpgp_card_pcsc::PcscBackend;
use openpgp_card_sequoia::card::Card; use openpgp_card_sequoia::card::{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 backend in PcscBackend::cards(None)? { for backend in PcscBackend::cards(None)? {
let mut card = Card::new(backend); let mut card: Card<Open> = backend.into();
let open = card.transaction()?; println!(" {}", card.transaction()?.application_identifier()?.ident());
println!(" {}", open.application_identifier()?.ident());
} }
Ok(()) Ok(())

View file

@ -16,7 +16,7 @@ use sequoia_openpgp::Cert;
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::{Error, KeyType, OpenPgp, OpenPgpTransaction, StatusBytes}; 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::{ use openpgp_card_sequoia::util::{
make_cert, public_key_material_and_fp_to_key, public_key_material_to_key, 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<TestOutput, Tes
let p = StandardPolicy::new(); let p = StandardPolicy::new();
let mut open = Open::new(pgpt)?; let mut transaction = Card::<Transaction>::new(pgpt)?;
let mut user = open.user_card().unwrap(); let mut user = transaction.user_card().unwrap();
let d = user.decryptor(&|| {})?; let d = user.decryptor(&|| {})?;
let res = openpgp_card_sequoia::util::decrypt(d, msg.into_bytes(), &p)?; 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<TestOutput, TestEr
let cert = Cert::from_str(param[0])?; let cert = Cert::from_str(param[0])?;
let mut open = Open::new(pgpt)?; let mut transaction = Card::<Transaction>::new(pgpt)?;
let mut sign = open.signing_card().unwrap(); let mut sign = transaction.signing_card().unwrap();
let s = sign.signer(&|| {})?; let s = sign.signer(&|| {})?;
let msg = "Hello world, I am signed."; let msg = "Hello world, I am signed.";
@ -216,9 +216,9 @@ pub fn test_upload_keys(pgp: &mut OpenPgp, param: &[&str]) -> Result<TestOutput,
pub fn test_keygen(pgp: &mut OpenPgp, param: &[&str]) -> Result<TestOutput, TestError> { pub fn test_keygen(pgp: &mut OpenPgp, param: &[&str]) -> Result<TestOutput, TestError> {
let pgpt = pgp.transaction()?; let pgpt = pgp.transaction()?;
let mut open = Open::new(pgpt)?; let mut transaction = Card::<Transaction>::new(pgpt)?;
open.verify_admin(b"12345678")?; transaction.verify_admin(b"12345678")?;
let mut admin = open.admin_card().expect("Couldn't get Admin card"); let mut admin = transaction.admin_card().expect("Couldn't get Admin card");
// Generate all three subkeys on card // Generate all three subkeys on card
let algo = param[0]; let algo = param[0];
@ -245,7 +245,7 @@ pub fn test_keygen(pgp: &mut OpenPgp, param: &[&str]) -> Result<TestOutput, Test
// Generate a Cert for this set of generated keys // Generate a Cert for this set of generated keys
let cert = make_cert( let cert = make_cert(
&mut open, &mut transaction,
key_sig, key_sig,
Some(key_dec), Some(key_dec),
Some(key_aut), Some(key_aut),

View file

@ -2,7 +2,7 @@
// SPDX-License-Identifier: MIT OR Apache-2.0 // SPDX-License-Identifier: MIT OR Apache-2.0
use openpgp_card_pcsc::PcscBackend; use openpgp_card_pcsc::PcscBackend;
use openpgp_card_sequoia::card::Card; use openpgp_card_sequoia::card::{Card, Open};
use openpgp::parse::{stream::DecryptorBuilder, Parse}; use openpgp::parse::{stream::DecryptorBuilder, Parse};
use openpgp::policy::StandardPolicy; use openpgp::policy::StandardPolicy;
@ -19,16 +19,16 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let card_ident = &args[0]; let card_ident = &args[0];
let pin_file = &args[1]; 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 card: Card<Open> = backend.into();
let mut open = card.transaction()?; let mut transaction = card.transaction()?;
let pin = std::fs::read(pin_file)?; 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(); let p = StandardPolicy::new();

View file

@ -2,7 +2,7 @@
// SPDX-License-Identifier: MIT OR Apache-2.0 // SPDX-License-Identifier: MIT OR Apache-2.0
use openpgp_card_pcsc::PcscBackend; 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 openpgp::serialize::stream::{Armorer, Message, Signer};
use sequoia_openpgp as openpgp; use sequoia_openpgp as openpgp;
@ -18,16 +18,16 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let card_ident = &args[0]; let card_ident = &args[0];
let pin_file = &args[1]; 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 card: Card<Open> = backend.into();
let mut open = card.transaction()?; let mut transaction = card.transaction()?;
let pin = std::fs::read(pin_file)?; 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 s = sign.signer(&|| println!("Touch confirmation needed for signing"))?;
let stdout = std::io::stdout(); let stdout = std::io::stdout();

View file

@ -10,10 +10,10 @@ use sequoia_openpgp::policy::StandardPolicy;
use sequoia_openpgp::Cert; use sequoia_openpgp::Cert;
use openpgp_card::card_do::Sex; use openpgp_card::card_do::Sex;
use openpgp_card::{KeyType, OpenPgp}; use openpgp_card::KeyType;
use openpgp_card_pcsc::PcscBackend; use openpgp_card_pcsc::PcscBackend;
use openpgp_card_sequoia::card::Open; use openpgp_card_sequoia::card::{Card, Open};
use openpgp_card_sequoia::sq_util; use openpgp_card_sequoia::sq_util;
// Filename of test key and test message to use // Filename of test key and test message to use
@ -36,47 +36,47 @@ fn main() -> Result<(), Box<dyn Error>> {
if let Ok(test_card_ident) = test_card_ident { if let Ok(test_card_ident) = test_card_ident {
let backend = PcscBackend::open_by_ident(&test_card_ident, None)?; 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<Open> = backend.into();
let mut transaction = card.transaction()?;
// card metadata // card metadata
let app_id = open.application_identifier()?; let app_id = transaction.application_identifier()?;
println!("{:x?}\n", app_id); println!("{:x?}\n", app_id);
let eli = open.extended_length_information()?; let eli = transaction.extended_length_information()?;
println!("extended_length_info: {:?}\n", eli); println!("extended_length_info: {:?}\n", eli);
let hist = open.historical_bytes()?; let hist = transaction.historical_bytes()?;
println!("{:#x?}\n", hist); println!("{:#x?}\n", hist);
let ext = open.extended_capabilities()?; let ext = transaction.extended_capabilities()?;
println!("{:#x?}\n", ext); println!("{:#x?}\n", ext);
let pws = open.pw_status_bytes()?; let pws = transaction.pw_status_bytes()?;
println!("{:#x?}\n", pws); println!("{:#x?}\n", pws);
// cardholder // cardholder
let ch = open.cardholder_related_data()?; let ch = transaction.cardholder_related_data()?;
println!("{:#x?}\n", ch); println!("{:#x?}\n", ch);
// crypto-ish metadata // crypto-ish metadata
let fp = open.fingerprints()?; let fp = transaction.fingerprints()?;
println!("Fingerprint {:#x?}\n", fp); println!("Fingerprint {:#x?}\n", fp);
match open.algorithm_information() { match transaction.algorithm_information() {
Ok(Some(ai)) => println!("Algorithm information:\n{}", ai), Ok(Some(ai)) => println!("Algorithm information:\n{}", ai),
Ok(None) => println!("No Algorithm information found"), Ok(None) => println!("No Algorithm information found"),
Err(e) => println!("Error getting Algorithm information: {:?}", e), Err(e) => println!("Error getting Algorithm information: {:?}", e),
} }
println!("Current algorithm attributes on card:"); println!("Current algorithm attributes on card:");
let algo = open.algorithm_attributes(KeyType::Signing)?; let algo = transaction.algorithm_attributes(KeyType::Signing)?;
println!("Sig: {}", algo); println!("Sig: {}", algo);
let algo = open.algorithm_attributes(KeyType::Decryption)?; let algo = transaction.algorithm_attributes(KeyType::Decryption)?;
println!("Dec: {}", algo); println!("Dec: {}", algo);
let algo = open.algorithm_attributes(KeyType::Authentication)?; let algo = transaction.algorithm_attributes(KeyType::Authentication)?;
println!("Aut: {}", algo); println!("Aut: {}", algo);
println!(); println!();
@ -88,20 +88,20 @@ fn main() -> Result<(), Box<dyn Error>> {
assert_eq!(app_id.ident(), test_card_ident.to_ascii_uppercase()); 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!("has admin (pw3) been verified yet?\n{:x?}\n", check);
println!("factory reset\n"); 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"); 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); println!("has user (pw1/82) been verified yet? {:x?}", check);
// Use Admin access to card // Use Admin access to card
let mut admin = open.admin_card().expect("just verified"); let mut admin = transaction.admin_card().expect("just verified");
println!(); println!();
@ -141,25 +141,25 @@ fn main() -> Result<(), Box<dyn Error>> {
// Open fresh Card for decrypt // Open fresh Card for decrypt
// ----------------------------- // -----------------------------
let backend = PcscBackend::open_by_ident(&test_card_ident, None)?; 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<Open> = backend.into();
let mut transaction = card.transaction()?;
// 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 = transaction.application_identifier()?;
assert_eq!(app_id.ident(), test_card_ident.to_ascii_uppercase()); 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); 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"); 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); println!("has user (pw1/82) been verified yet?\n{:x?}\n", check);
// Use User access to card // Use User access to card
let mut user = open let mut user = transaction
.user_card() .user_card()
.expect("We just validated, this should not fail"); .expect("We just validated, this should not fail");
@ -181,16 +181,16 @@ fn main() -> Result<(), Box<dyn Error>> {
// Open fresh Card for signing // Open fresh Card for signing
// ----------------------------- // -----------------------------
let backend = PcscBackend::open_by_ident(&test_card_ident, None)?; 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<Open> = backend.into();
let mut transaction = card.transaction()?;
// Sign // Sign
open.verify_user_for_signing(b"123456")?; transaction.verify_user_for_signing(b"123456")?;
println!("verify for sign (pw1/81) ok\n"); println!("verify for sign (pw1/81) ok\n");
// Use Sign access to card // 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)?; let _cert = Cert::from_file(TEST_KEY_PATH)?;
@ -213,9 +213,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 backend in PcscBackend::cards(None)? { for backend in PcscBackend::cards(None)? {
let mut pgp = OpenPgp::new(backend); let mut card: Card<Open> = backend.into();
let open = card.transaction()?;
let open = Open::new(pgp.transaction()?)?;
println!(" {}", open.application_identifier()?.ident()); println!(" {}", open.application_identifier()?.ident());
} }

View file

@ -22,39 +22,33 @@ use crate::signer::CardSigner;
use crate::util::{public_to_fingerprint, vka_as_uploadable_key}; use crate::util::{public_to_fingerprint, vka_as_uploadable_key};
use crate::PublicKey; 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 /// 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).
/// No transaction has been started. /// No transaction has been started.
pub struct Card { pub struct Open {
pgp: OpenPgp, pgp: OpenPgp,
} }
impl Card {
pub fn new<B>(backend: B) -> Self
where
B: Into<Box<dyn CardBackend + Send + Sync>>,
{
let pgp = OpenPgp::new(backend.into());
Self { pgp }
}
pub fn transaction(&mut self) -> Result<Open, Error> {
let t = self.pgp.transaction()?;
Open::new(t)
}
}
/// 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).
/// A transaction has been started. /// A transaction has been started.
pub struct Open<'a> { pub struct Transaction<'a> {
opt: OpenPgpTransaction<'a>, opt: OpenPgpTransaction<'a>,
// Cache of "application related data". // Cache of "application related data".
// //
// FIXME: Should be invalidated when changing data on the card! // FIXME: Should be invalidated when changing data on the card!
// (e.g. uploading keys, etc) // (e.g. uploading keys, etc)
//
// This field should probably be an Option<> that gets invalidated when appropriate and
// re-fetched lazily.
ard: ApplicationRelatedData, ard: ApplicationRelatedData,
// verify status of pw1 // verify status of pw1
@ -67,16 +61,67 @@ pub struct Open<'a> {
pw3: bool, pw3: bool,
} }
impl<'a> Open<'a> { /// An OpenPGP card after successfully verifying PW1 in mode 82
pub fn new(mut ca: OpenPgpTransaction<'a>) -> Result<Self, Error> { /// (verification for user operations other than signing)
let ard = ca.application_related_data()?; pub struct User<'app, 'open> {
tx: &'open mut Card<Transaction<'app>>,
}
/// An OpenPGP card after successfully verifying PW1 in mode 81
/// (verification for signing)
pub struct Sign<'app, 'open> {
tx: &'open mut Card<Transaction<'app>>,
}
/// An OpenPGP card after successful verification of PW3 ("Admin privileges")
pub struct Admin<'app, 'open> {
tx: &'open mut Card<Transaction<'app>>,
}
pub struct Card<S>
where
S: State,
{
state: S,
}
impl<B> From<B> for Card<Open>
where
B: Into<Box<dyn CardBackend + Send + Sync>>,
{
fn from(backend: B) -> Self {
let pgp = OpenPgp::new(backend.into());
Card::<Open> {
state: Open { pgp },
}
}
}
impl Card<Open> {
pub fn transaction(&mut self) -> Result<Card<Transaction>, Error> {
let opt = self.state.pgp.transaction()?;
Card::<Transaction>::new(opt)
}
}
impl<'a> Card<Transaction<'a>> {
/// 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<Self, Error> {
let ard = opt.application_related_data()?;
Ok(Self { Ok(Self {
opt: ca, state: Transaction {
opt,
ard, ard,
pw1: false, pw1: false,
pw1_sign: false, pw1_sign: false,
pw3: 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 /// This is needed e.g. after importing or generating keys on a card, to
/// see these changes reflected in `self.ard`. /// see these changes reflected in `self.ard`.
pub fn reload_ard(&mut self) -> Result<(), Error> { 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(()) Ok(())
} }
pub fn feature_pinpad_verify(&mut self) -> bool { 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 { 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> { pub fn verify_user(&mut self, pin: &[u8]) -> Result<(), Error> {
self.opt.verify_pw1_user(pin)?; self.state.opt.verify_pw1_user(pin)?;
self.pw1 = true; self.state.pw1 = true;
Ok(()) Ok(())
} }
pub fn verify_user_pinpad(&mut self, pinpad_prompt: &dyn Fn()) -> Result<(), Error> { pub fn verify_user_pinpad(&mut self, pinpad_prompt: &dyn Fn()) -> Result<(), Error> {
pinpad_prompt(); pinpad_prompt();
self.opt.verify_pw1_user_pinpad()?; self.state.opt.verify_pw1_user_pinpad()?;
self.pw1 = true; self.state.pw1 = true;
Ok(()) Ok(())
} }
pub fn verify_user_for_signing(&mut self, pin: &[u8]) -> Result<(), Error> { 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 // FIXME: depending on card mode, pw1_sign is only usable once
self.pw1_sign = true; self.state.pw1_sign = true;
Ok(()) Ok(())
} }
@ -127,25 +173,25 @@ impl<'a> Open<'a> {
) -> Result<(), Error> { ) -> Result<(), Error> {
pinpad_prompt(); 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 // FIXME: depending on card mode, pw1_sign is only usable once
self.pw1_sign = true; self.state.pw1_sign = true;
Ok(()) Ok(())
} }
pub fn verify_admin(&mut self, pin: &[u8]) -> Result<(), Error> { pub fn verify_admin(&mut self, pin: &[u8]) -> Result<(), Error> {
self.opt.verify_pw3(pin)?; self.state.opt.verify_pw3(pin)?;
self.pw3 = true; self.state.pw3 = true;
Ok(()) Ok(())
} }
pub fn verify_admin_pinpad(&mut self, pinpad_prompt: &dyn Fn()) -> Result<(), Error> { pub fn verify_admin_pinpad(&mut self, pinpad_prompt: &dyn Fn()) -> Result<(), Error> {
pinpad_prompt(); pinpad_prompt();
self.opt.verify_pw3_pinpad()?; self.state.opt.verify_pw3_pinpad()?;
self.pw3 = true; self.state.pw3 = true;
Ok(()) Ok(())
} }
@ -153,65 +199,71 @@ impl<'a> Open<'a> {
/// ///
/// NOTE: on some cards this functionality seems broken. /// NOTE: on some cards this functionality seems broken.
pub fn check_user_verified(&mut self) -> Result<(), Error> { 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. /// Ask the card if the admin password has been successfully verified.
/// ///
/// NOTE: on some cards this functionality seems broken. /// NOTE: on some cards this functionality seems broken.
pub fn check_admin_verified(&mut self) -> Result<(), Error> { 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> { 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> { pub fn change_user_pin_pinpad(&mut self, pinpad_prompt: &dyn Fn()) -> Result<(), Error> {
pinpad_prompt(); 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> { 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> { 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> { pub fn change_admin_pin_pinpad(&mut self, pinpad_prompt: &dyn Fn()) -> Result<(), Error> {
pinpad_prompt(); pinpad_prompt();
self.opt.change_pw3_pinpad() self.state.opt.change_pw3_pinpad()
} }
/// Get a view of the card authenticated for "User" commands. /// Get a view of the card authenticated for "User" commands.
pub fn user_card<'b>(&'b mut self) -> Option<User<'a, 'b>> { pub fn user_card<'b>(&'b mut self) -> Option<Card<User<'a, 'b>>> {
Some(User { oc: self }) Some(Card::<User> {
state: User { tx: self },
})
} }
/// Get a view of the card authenticated for Signing. /// Get a view of the card authenticated for Signing.
pub fn signing_card<'b>(&'b mut self) -> Option<Sign<'a, 'b>> { pub fn signing_card<'b>(&'b mut self) -> Option<Card<Sign<'a, 'b>>> {
Some(Sign { oc: self }) Some(Card::<Sign> {
state: Sign { tx: self },
})
} }
/// Get a view of the card authenticated for "Admin" commands. /// Get a view of the card authenticated for "Admin" commands.
pub fn admin_card<'b>(&'b mut self) -> Option<Admin<'a, 'b>> { pub fn admin_card<'b>(&'b mut self) -> Option<Card<Admin<'a, 'b>>> {
Some(Admin { oc: self }) Some(Card::<Admin> {
state: Admin { tx: self },
})
} }
// --- application data --- // --- application data ---
pub fn application_identifier(&self) -> Result<ApplicationIdentifier, Error> { pub fn application_identifier(&self) -> Result<ApplicationIdentifier, Error> {
self.ard.application_id() self.state.ard.application_id()
} }
pub fn historical_bytes(&self) -> Result<HistoricalBytes, Error> { pub fn historical_bytes(&self) -> Result<HistoricalBytes, Error> {
self.ard.historical_bytes() self.state.ard.historical_bytes()
} }
pub fn extended_length_information(&self) -> Result<Option<ExtendedLengthInfo>, Error> { pub fn extended_length_information(&self) -> Result<Option<ExtendedLengthInfo>, Error> {
self.ard.extended_length_information() self.state.ard.extended_length_information()
} }
#[allow(dead_code)] #[allow(dead_code)]
@ -225,48 +277,48 @@ impl<'a> Open<'a> {
} }
pub fn extended_capabilities(&self) -> Result<ExtendedCapabilities, Error> { pub fn extended_capabilities(&self) -> Result<ExtendedCapabilities, Error> {
self.ard.extended_capabilities() self.state.ard.extended_capabilities()
} }
pub fn algorithm_attributes(&self, key_type: KeyType) -> Result<Algo, Error> { pub fn algorithm_attributes(&self, key_type: KeyType) -> Result<Algo, Error> {
self.ard.algorithm_attributes(key_type) self.state.ard.algorithm_attributes(key_type)
} }
/// PW status Bytes /// PW status Bytes
pub fn pw_status_bytes(&self) -> Result<PWStatusBytes, Error> { pub fn pw_status_bytes(&self) -> Result<PWStatusBytes, Error> {
self.ard.pw_status_bytes() self.state.ard.pw_status_bytes()
} }
pub fn fingerprints(&self) -> Result<KeySet<Fingerprint>, Error> { pub fn fingerprints(&self) -> Result<KeySet<Fingerprint>, Error> {
self.ard.fingerprints() self.state.ard.fingerprints()
} }
pub fn ca_fingerprints(&self) -> Result<[Option<Fingerprint>; 3], Error> { pub fn ca_fingerprints(&self) -> Result<[Option<Fingerprint>; 3], Error> {
self.ard.ca_fingerprints() self.state.ard.ca_fingerprints()
} }
pub fn key_generation_times(&self) -> Result<KeySet<KeyGenerationTime>, Error> { pub fn key_generation_times(&self) -> Result<KeySet<KeyGenerationTime>, Error> {
self.ard.key_generation_times() self.state.ard.key_generation_times()
} }
pub fn key_information(&self) -> Result<Option<KeyInformation>, Error> { pub fn key_information(&self) -> Result<Option<KeyInformation>, Error> {
self.ard.key_information() self.state.ard.key_information()
} }
pub fn uif_signing(&self) -> Result<Option<UIF>, Error> { pub fn uif_signing(&self) -> Result<Option<UIF>, Error> {
self.ard.uif_pso_cds() self.state.ard.uif_pso_cds()
} }
pub fn uif_decryption(&self) -> Result<Option<UIF>, Error> { pub fn uif_decryption(&self) -> Result<Option<UIF>, Error> {
self.ard.uif_pso_dec() self.state.ard.uif_pso_dec()
} }
pub fn uif_authentication(&self) -> Result<Option<UIF>, Error> { pub fn uif_authentication(&self) -> Result<Option<UIF>, Error> {
self.ard.uif_pso_aut() self.state.ard.uif_pso_aut()
} }
pub fn uif_attestation(&self) -> Result<Option<UIF>, Error> { pub fn uif_attestation(&self) -> Result<Option<UIF>, Error> {
self.ard.uif_attestation() self.state.ard.uif_attestation()
} }
// --- optional private DOs (0101 - 0104) --- // --- optional private DOs (0101 - 0104) ---
@ -276,17 +328,17 @@ impl<'a> Open<'a> {
// --- URL (5f50) --- // --- URL (5f50) ---
pub fn url(&mut self) -> Result<String, Error> { pub fn url(&mut self) -> Result<String, Error> {
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) --- // --- cardholder related data (65) ---
pub fn cardholder_related_data(&mut self) -> Result<CardholderRelatedData, Error> { pub fn cardholder_related_data(&mut self) -> Result<CardholderRelatedData, Error> {
self.opt.cardholder_related_data() self.state.opt.cardholder_related_data()
} }
/// Get cardholder name as a String (this also normalizes the "<" and "<<" filler chars) /// Get cardholder name as a String (this also normalizes the "<" and "<<" filler chars)
pub fn cardholder_name(&mut self) -> Result<String, Error> { pub fn cardholder_name(&mut self) -> Result<String, Error> {
let crd = self.opt.cardholder_related_data()?; let crd = self.state.opt.cardholder_related_data()?;
if let Some(name) = crd.name() { if let Some(name) = crd.name() {
let name = String::from_utf8_lossy(name).to_string(); let name = String::from_utf8_lossy(name).to_string();
@ -305,12 +357,12 @@ impl<'a> Open<'a> {
// --- security support template (7a) --- // --- security support template (7a) ---
pub fn security_support_template(&mut self) -> Result<SecuritySupportTemplate, Error> { pub fn security_support_template(&mut self) -> Result<SecuritySupportTemplate, Error> {
self.opt.security_support_template() self.state.opt.security_support_template()
} }
/// SELECT DATA ("select a DO in the current 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> { 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. /// Get cardholder certificate.
@ -318,7 +370,7 @@ impl<'a> Open<'a> {
/// Call select_data() before calling this fn to select a particular /// Call select_data() before calling this fn to select a particular
/// certificate (if the card supports multiple certificates). /// certificate (if the card supports multiple certificates).
pub fn cardholder_certificate(&mut self) -> Result<Vec<u8>, Error> { pub fn cardholder_certificate(&mut self) -> Result<Vec<u8>, Error> {
self.opt.cardholder_certificate() self.state.opt.cardholder_certificate()
} }
/// "GET NEXT DATA" for the DO 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 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(). /// cardholder_certificate(), followed by up to two calls to next_cardholder_certificate().
pub fn next_cardholder_certificate(&mut self) -> Result<Vec<u8>, Error> { pub fn next_cardholder_certificate(&mut self) -> Result<Vec<u8>, Error> {
self.opt.next_cardholder_certificate() self.state.opt.next_cardholder_certificate()
} }
// DO "Algorithm Information" (0xFA) // DO "Algorithm Information" (0xFA)
@ -340,7 +392,7 @@ impl<'a> Open<'a> {
return Ok(None); return Ok(None);
} }
self.opt.algorithm_information() self.state.opt.algorithm_information()
} }
/// "MANAGE SECURITY ENVIRONMENT" /// "MANAGE SECURITY ENVIRONMENT"
@ -350,19 +402,21 @@ impl<'a> Open<'a> {
for_operation: KeyType, for_operation: KeyType,
key_ref: KeyType, key_ref: KeyType,
) -> Result<(), Error> { ) -> 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)" /// Get "Attestation Certificate (Yubico)"
pub fn attestation_certificate(&mut self) -> Result<Vec<u8>, Error> { pub fn attestation_certificate(&mut self) -> Result<Vec<u8>, Error> {
self.opt.attestation_certificate() self.state.opt.attestation_certificate()
} }
/// Firmware Version, YubiKey specific (?) /// Firmware Version, YubiKey specific (?)
pub fn firmware_version(&mut self) -> Result<Vec<u8>, Error> { pub fn firmware_version(&mut self) -> Result<Vec<u8>, Error> {
self.opt.firmware_version() self.state.opt.firmware_version()
} }
/// Set "identity", Nitrokey Start specific (possible values: 0, 1, 2). /// 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. /// Each virtual card identity behaves like a separate, independent OpenPGP card.
pub fn set_identity(&mut self, id: u8) -> Result<(), Error> { pub fn set_identity(&mut self, id: u8) -> Result<(), Error> {
// FIXME: what is in the returned data - is it ever useful? // 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(()) Ok(())
} }
@ -382,36 +436,31 @@ impl<'a> Open<'a> {
// ---------- // ----------
pub fn public_key(&mut self, key_type: KeyType) -> Result<PublicKeyMaterial, Error> { pub fn public_key(&mut self, key_type: KeyType) -> Result<PublicKeyMaterial, Error> {
self.opt.public_key(key_type) self.state.opt.public_key(key_type)
} }
// ---------- // ----------
/// Delete all state on this OpenPGP card /// Delete all state on this OpenPGP card
pub fn factory_reset(&mut self) -> Result<(), Error> { 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 impl<'app, 'open> Card<User<'app, 'open>> {
/// (verification for user operations other than signing) /// Helper fn to easily access underlying openpgp_card object
pub struct User<'app, 'open> { fn card(&mut self) -> &mut OpenPgpTransaction<'app> {
oc: &'open mut Open<'app>, &mut self.state.tx.state.opt
} }
impl<'app, 'open> User<'app, 'open> {
pub fn decryptor( pub fn decryptor(
&mut self, &mut self,
touch_prompt: &'open (dyn Fn() + Send + Sync), touch_prompt: &'open (dyn Fn() + Send + Sync),
) -> Result<CardDecryptor<'_, 'app>, Error> { ) -> Result<CardDecryptor<'_, 'app>, 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"); .expect("Couldn't get decryption pubkey from card");
Ok(CardDecryptor::with_pubkey( Ok(CardDecryptor::with_pubkey(self.card(), pk, touch_prompt))
&mut self.oc.opt,
pk,
touch_prompt,
))
} }
pub fn decryptor_from_public( pub fn decryptor_from_public(
@ -419,18 +468,18 @@ impl<'app, 'open> User<'app, 'open> {
pubkey: PublicKey, pubkey: PublicKey,
touch_prompt: &'open (dyn Fn() + Send + Sync), touch_prompt: &'open (dyn Fn() + Send + Sync),
) -> CardDecryptor<'_, 'app> { ) -> CardDecryptor<'_, 'app> {
CardDecryptor::with_pubkey(&mut self.oc.opt, pubkey, touch_prompt) CardDecryptor::with_pubkey(self.card(), pubkey, touch_prompt)
} }
pub fn authenticator( pub fn authenticator(
&mut self, &mut self,
touch_prompt: &'open (dyn Fn() + Send + Sync), touch_prompt: &'open (dyn Fn() + Send + Sync),
) -> Result<CardSigner<'_, 'app>, Error> { ) -> Result<CardSigner<'_, 'app>, 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"); .expect("Couldn't get authentication pubkey from card");
Ok(CardSigner::with_pubkey_for_auth( Ok(CardSigner::with_pubkey_for_auth(
&mut self.oc.opt, self.card(),
pk, pk,
touch_prompt, touch_prompt,
)) ))
@ -440,17 +489,16 @@ impl<'app, 'open> User<'app, 'open> {
pubkey: PublicKey, pubkey: PublicKey,
touch_prompt: &'open (dyn Fn() + Send + Sync), touch_prompt: &'open (dyn Fn() + Send + Sync),
) -> CardSigner<'_, 'app> { ) -> 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 impl<'app, 'open> Card<Sign<'app, 'open>> {
/// (verification for signing) /// Helper fn to easily access underlying openpgp_card object
pub struct Sign<'app, 'open> { fn card(&mut self) -> &mut OpenPgpTransaction<'app> {
oc: &'open mut Open<'app>, &mut self.state.tx.state.opt
} }
impl<'app, 'open> Sign<'app, 'open> {
pub fn signer( pub fn signer(
&mut self, &mut self,
touch_prompt: &'open (dyn Fn() + Send + Sync), 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 // FIXME: depending on the setting in "PW1 Status byte", only one
// signature can be made after verification for signing // signature can be made after verification for signing
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"); .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( 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 // FIXME: depending on the setting in "PW1 Status byte", only one
// signature can be made after verification for signing // signature can be made after verification for signing
CardSigner::with_pubkey(&mut self.oc.opt, pubkey, touch_prompt) CardSigner::with_pubkey(self.card(), pubkey, touch_prompt)
} }
/// Generate Attestation (Yubico) /// Generate Attestation (Yubico)
@ -484,28 +532,28 @@ impl<'app, 'open> Sign<'app, 'open> {
// Touch is required if: // Touch is required if:
// - the card supports the feature // - the card supports the feature
// - and the policy is set to a value other than 'Off' // - 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() { if uif.touch_policy().touch_required() {
(touch_prompt)(); (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") impl<'app, 'open> Card<Admin<'app, 'open>> {
pub struct Admin<'app, 'open> { pub fn as_open(&'_ mut self) -> &mut Card<Transaction<'app>> {
oc: &'open mut Open<'app>, self.state.tx
} }
impl<'app, 'open> Admin<'app, 'open> { /// Helper fn to easily access underlying openpgp_card object
pub fn as_open(&'_ mut self) -> &mut Open<'app> { fn card(&mut self) -> &mut OpenPgpTransaction<'app> {
self.oc &mut self.state.tx.state.opt
} }
} }
impl Admin<'_, '_> { impl Card<Admin<'_, '_>> {
pub fn set_name(&mut self, name: &str) -> Result<(), Error> { pub fn set_name(&mut self, name: &str) -> Result<(), Error> {
if name.len() >= 40 { if name.len() >= 40 {
return Err(Error::InternalError("name too long".into())); return Err(Error::InternalError("name too long".into()));
@ -516,7 +564,7 @@ impl Admin<'_, '_> {
return Err(Error::InternalError("Invalid char in name".into())); 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> { pub fn set_lang(&mut self, lang: &[Lang]) -> Result<(), Error> {
@ -524,11 +572,11 @@ impl Admin<'_, '_> {
return Err(Error::InternalError("lang too long".into())); 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> { 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> { pub fn set_url(&mut self, url: &str) -> Result<(), Error> {
@ -537,7 +585,7 @@ impl Admin<'_, '_> {
} }
// Check for max len // 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 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: // or if it's within the acceptable length:
// send the url update to the card. // send the url update to the card.
self.oc.opt.set_url(url.as_bytes()) self.card().set_url(url.as_bytes())
} else { } else {
Err(Error::InternalError("URL too long".into())) 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> { pub fn set_uif(&mut self, key: KeyType, policy: TouchPolicy) -> Result<(), Error> {
let uif = match key { let uif = match key {
KeyType::Signing => self.oc.ard.uif_pso_cds()?, KeyType::Signing => self.state.tx.state.ard.uif_pso_cds()?,
KeyType::Decryption => self.oc.ard.uif_pso_dec()?, KeyType::Decryption => self.state.tx.state.ard.uif_pso_dec()?,
KeyType::Authentication => self.oc.ard.uif_pso_aut()?, KeyType::Authentication => self.state.tx.state.ard.uif_pso_aut()?,
KeyType::Attestation => self.oc.ard.uif_attestation()?, KeyType::Attestation => self.state.tx.state.ard.uif_attestation()?,
_ => unimplemented!(), _ => unimplemented!(),
}; };
@ -564,10 +612,10 @@ impl Admin<'_, '_> {
uif.set_touch_policy(policy); uif.set_touch_policy(policy);
match key { match key {
KeyType::Signing => self.oc.opt.set_uif_pso_cds(&uif)?, KeyType::Signing => self.card().set_uif_pso_cds(&uif)?,
KeyType::Decryption => self.oc.opt.set_uif_pso_dec(&uif)?, KeyType::Decryption => self.card().set_uif_pso_dec(&uif)?,
KeyType::Authentication => self.oc.opt.set_uif_pso_aut(&uif)?, KeyType::Authentication => self.card().set_uif_pso_aut(&uif)?,
KeyType::Attestation => self.oc.opt.set_uif_attestation(&uif)?, KeyType::Attestation => self.card().set_uif_attestation(&uif)?,
_ => unimplemented!(), _ => unimplemented!(),
} }
} else { } else {
@ -580,15 +628,15 @@ impl Admin<'_, '_> {
} }
pub fn set_resetting_code(&mut self, pin: &[u8]) -> Result<(), Error> { 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> { 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> { 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. /// Upload a ValidErasedKeyAmalgamation to the card as a specific KeyType.
@ -601,7 +649,7 @@ impl Admin<'_, '_> {
password: Option<String>, password: Option<String>,
) -> Result<(), Error> { ) -> Result<(), Error> {
let key = vka_as_uploadable_key(vka, password); let key = vka_as_uploadable_key(vka, password);
self.oc.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. /// Wrapper fn for `public_to_fingerprint` that uses SHA256/AES128 as default parameters.
@ -628,8 +676,8 @@ impl Admin<'_, '_> {
algo: Option<AlgoSimple>, algo: Option<AlgoSimple>,
) -> Result<(PublicKeyMaterial, KeyGenerationTime), Error> { ) -> Result<(PublicKeyMaterial, KeyGenerationTime), Error> {
match algo { match algo {
Some(algo) => self.oc.opt.generate_key_simple(Self::ptf, key_type, algo), Some(algo) => self.card().generate_key_simple(Self::ptf, key_type, algo),
None => self.oc.opt.generate_key(Self::ptf, key_type, None), None => self.card().generate_key(Self::ptf, key_type, None),
} }
} }
} }

View file

@ -13,14 +13,14 @@
//! //!
//! ```no_run //! ```no_run
//! use openpgp_card_pcsc::PcscBackend; //! use openpgp_card_pcsc::PcscBackend;
//! use openpgp_card_sequoia::card::Card; //! use openpgp_card_sequoia::card::{Card, Open};
//! //!
//! # fn main() -> Result<(), Box<dyn std::error::Error>> { //! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! for backend in PcscBackend::cards(None)? { //! for backend in PcscBackend::cards(None)? {
//! let mut card = Card::new(backend); //! let mut card: Card<Open> = backend.into();
//! let mut open = card.transaction()?; //! let mut transaction = card.transaction()?;
//! println!("Found OpenPGP card with ident '{}'", //! println!("Found OpenPGP card with ident '{}'",
//! open.application_identifier()?.ident()); //! transaction.application_identifier()?.ident());
//! } //! }
//! # Ok(()) //! # Ok(())
//! # } //! # }
@ -30,12 +30,12 @@
//! //!
//! ```no_run //! ```no_run
//! use openpgp_card_pcsc::PcscBackend; //! use openpgp_card_pcsc::PcscBackend;
//! use openpgp_card_sequoia::card::Card; //! use openpgp_card_sequoia::card::{Card, Open};
//! //!
//! # fn main() -> Result<(), Box<dyn std::error::Error>> { //! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! let backend = PcscBackend::open_by_ident("abcd:12345678", None)?; //! let backend = PcscBackend::open_by_ident("abcd:12345678", None)?;
//! let mut card = Card::new(backend); //! let mut card: Card<Open> = backend.into();
//! let mut open = card.transaction()?; //! let mut transaction = card.transaction()?;
//! # Ok(()) //! # Ok(())
//! # } //! # }
//! ``` //! ```
@ -51,18 +51,18 @@
//! //!
//! ```no_run //! ```no_run
//! use openpgp_card_pcsc::PcscBackend; //! use openpgp_card_pcsc::PcscBackend;
//! use openpgp_card_sequoia::card::Card; //! use openpgp_card_sequoia::card::{Card, Open};
//! //!
//! # 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 backend = PcscBackend::open_by_ident("abcd:12345678", None)?; //! let backend = PcscBackend::open_by_ident("abcd:12345678", None)?;
//! let mut card = Card::new(backend); //! let mut card: Card<Open> = backend.into();
//! let mut open = card.transaction()?; //! let mut transaction = card.transaction()?;
//! //!
//! // Get authorization for user access to the card with password //! // Get authorization for user access to the card with password
//! open.verify_user(b"123456")?; //! transaction.verify_user(b"123456")?;
//! let mut user = open.user_card().expect("This should not fail"); //! let mut user = transaction.user_card().expect("This should not fail");
//! //!
//! // Get decryptor //! // Get decryptor
//! let decryptor = user.decryptor(&|| { println!("Touch confirmation needed for decryption") }); //! let decryptor = user.decryptor(&|| { println!("Touch confirmation needed for decryption") });
@ -88,17 +88,17 @@
//! //!
//! ```no_run //! ```no_run
//! use openpgp_card_pcsc::PcscBackend; //! use openpgp_card_pcsc::PcscBackend;
//! use openpgp_card_sequoia::card::Card; //! use openpgp_card_sequoia::card::{Card, Open};
//! //!
//! # 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 backend = PcscBackend::open_by_ident("abcd:12345678", None)?; //! let backend = PcscBackend::open_by_ident("abcd:12345678", None)?;
//! let mut card = Card::new(backend); //! let mut card: Card<Open> = backend.into();
//! let mut open = card.transaction()?; //! let mut transaction = card.transaction()?;
//! //!
//! // 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(b"123456")?; //! transaction.verify_user_for_signing(b"123456")?;
//! let mut user = open.signing_card().expect("This should not fail"); //! let mut user = transaction.signing_card().expect("This should not fail");
//! //!
//! // Get signer //! // Get signer
//! let signer = user.signer(&|| println!("Touch confirmation needed for signing")); //! let signer = user.signer(&|| println!("Touch confirmation needed for signing"));
@ -114,17 +114,17 @@
//! //!
//! ```no_run //! ```no_run
//! use openpgp_card_pcsc::PcscBackend; //! use openpgp_card_pcsc::PcscBackend;
//! use openpgp_card_sequoia::card::Card; //! use openpgp_card_sequoia::card::{Card, Open};
//! //!
//! # 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 backend = PcscBackend::open_by_ident("abcd:12345678", None)?; //! let backend = PcscBackend::open_by_ident("abcd:12345678", None)?;
//! let mut card = Card::new(backend); //! let mut card: Card<Open> = backend.into();
//! let mut open = card.transaction()?; //! let mut transaction = card.transaction()?;
//! //!
//! // Get authorization for admin access to the card with password //! // Get authorization for admin access to the card with password
//! open.verify_admin(b"12345678")?; //! transaction.verify_admin(b"12345678")?;
//! let mut admin = open.admin_card().expect("This should not fail"); //! let mut admin = transaction.admin_card().expect("This should not fail");
//! //!
//! // Set the Name and URL fields on the card //! // Set the Name and URL fields on the card
//! admin.set_name("Bar<<Foo")?; //! admin.set_name("Bar<<Foo")?;

View file

@ -32,7 +32,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::{Error, KeyType}; use openpgp_card::{Error, KeyType};
use crate::card::Open; use crate::card::{Card, Transaction};
use crate::decryptor::CardDecryptor; use crate::decryptor::CardDecryptor;
use crate::privkey::SequoiaKey; use crate::privkey::SequoiaKey;
use crate::signer::CardSigner; use crate::signer::CardSigner;
@ -48,7 +48,7 @@ use crate::PublicKey;
/// FIXME: accept optional metadata for user_id(s)? /// FIXME: accept optional metadata for user_id(s)?
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
pub fn make_cert<'app>( pub fn make_cert<'app>(
open: &mut Open<'app>, open: &mut Card<Transaction<'app>>,
key_sig: PublicKey, key_sig: PublicKey,
key_dec: Option<PublicKey>, key_dec: Option<PublicKey>,
key_aut: Option<PublicKey>, key_aut: Option<PublicKey>,
@ -226,7 +226,7 @@ pub fn public_key_material_and_fp_to_key(
} }
/// Get a PublicKey representation for a key slot on the card /// Get a PublicKey representation for a key slot on the card
pub fn key_slot(open: &mut Open, kt: KeyType) -> Result<Option<PublicKey>, Error> { pub fn key_slot(open: &mut Card<Transaction>, kt: KeyType) -> Result<Option<PublicKey>, Error> {
// FIXME: only read these once, if multiple subkeys are retrieved from the card // FIXME: only read these once, if multiple subkeys are retrieved from the card
let times = open.key_generation_times()?; let times = open.key_generation_times()?;
let fps = open.fingerprints()?; let fps = open.fingerprints()?;

View file

@ -5,7 +5,7 @@
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use clap::{Parser, ValueEnum}; 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 openpgp_card_sequoia::util::public_key_material_to_key;
use sequoia_openpgp::types::{HashAlgorithm, SymmetricAlgorithm}; use sequoia_openpgp::types::{HashAlgorithm, SymmetricAlgorithm};
@ -114,7 +114,7 @@ pub enum BasePlusAttKeySlot {
Att, Att,
} }
impl From<BasePlusAttKeySlot> for openpgp_card_sequoia::types::KeyType { impl From<BasePlusAttKeySlot> for KeyType {
fn from(ks: BasePlusAttKeySlot) -> Self { fn from(ks: BasePlusAttKeySlot) -> Self {
match ks { match ks {
BasePlusAttKeySlot::Sig => KeyType::Signing, BasePlusAttKeySlot::Sig => KeyType::Signing,
@ -164,7 +164,7 @@ pub enum Algo {
Curve25519, Curve25519,
} }
impl From<Algo> for openpgp_card_sequoia::types::AlgoSimple { impl From<Algo> for AlgoSimple {
fn from(a: Algo) -> Self { fn from(a: Algo) -> Self {
match a { match a {
Algo::Rsa2048 => AlgoSimple::RSA2k, Algo::Rsa2048 => AlgoSimple::RSA2k,
@ -184,17 +184,17 @@ pub fn admin(
command: AdminCommand, command: AdminCommand,
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
let backend = util::open_card(&command.ident)?; let backend = util::open_card(&command.ident)?;
let mut card = Card::new(backend); let mut open: Card<Open> = backend.into();
let mut open = card.transaction()?; 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 { match command.cmd {
AdminSubCommand::Name { name } => { AdminSubCommand::Name { name } => {
name_command(&name, open, admin_pin.as_deref())?; name_command(&name, card, admin_pin.as_deref())?;
} }
AdminSubCommand::Url { url } => { AdminSubCommand::Url { url } => {
url_command(&url, open, admin_pin.as_deref())?; url_command(&url, card, admin_pin.as_deref())?;
} }
AdminSubCommand::Import { AdminSubCommand::Import {
keyfile, keyfile,
@ -202,19 +202,19 @@ pub fn admin(
dec_fp, dec_fp,
auth_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) => { AdminSubCommand::Generate(cmd) => {
generate_command( generate_command(
output_format, output_format,
output_version, output_version,
open, card,
admin_pin.as_deref(), admin_pin.as_deref(),
cmd, cmd,
)?; )?;
} }
AdminSubCommand::Touch { key, policy } => { AdminSubCommand::Touch { key, policy } => {
touch_command(open, admin_pin.as_deref(), key, policy)?; touch_command(card, admin_pin.as_deref(), key, policy)?;
} }
} }
Ok(()) Ok(())
@ -249,7 +249,7 @@ fn keys_pick_explicit<'a>(
} }
fn gen_subkeys( fn gen_subkeys(
admin: &mut Admin, admin: &mut Card<Admin>,
decrypt: bool, decrypt: bool,
auth: bool, auth: bool,
algo: Option<AlgoSimple>, algo: Option<AlgoSimple>,
@ -297,10 +297,10 @@ fn gen_subkeys(
fn name_command( fn name_command(
name: &str, name: &str,
mut open: Open, mut card: Card<Transaction>,
admin_pin: Option<&[u8]>, admin_pin: Option<&[u8]>,
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
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)?; admin.set_name(name)?;
Ok(()) Ok(())
@ -308,10 +308,10 @@ fn name_command(
fn url_command( fn url_command(
url: &str, url: &str,
mut open: Open, mut card: Card<Transaction>,
admin_pin: Option<&[u8]>, admin_pin: Option<&[u8]>,
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
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)?; admin.set_url(url)?;
Ok(()) Ok(())
@ -322,7 +322,7 @@ fn import_command(
sig_fp: Option<String>, sig_fp: Option<String>,
dec_fp: Option<String>, dec_fp: Option<String>,
auth_fp: Option<String>, auth_fp: Option<String>,
mut open: Open, mut card: Card<Transaction>,
admin_pin: Option<&[u8]>, admin_pin: Option<&[u8]>,
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
let key = Cert::from_file(keyfile)?; let key = Cert::from_file(keyfile)?;
@ -410,7 +410,7 @@ fn import_command(
let auth_p = get_pw_for_key(&auth, "authentication")?; let auth_p = get_pw_for_key(&auth, "authentication")?;
// upload keys to card // 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 { if let Some(sig) = sig {
println!("Uploading {} as signing key", sig.fingerprint()); println!("Uploading {} as signing key", sig.fingerprint());
@ -430,16 +430,16 @@ fn import_command(
fn generate_command( fn generate_command(
output_format: OutputFormat, output_format: OutputFormat,
output_version: OutputVersion, output_version: OutputVersion,
mut open: Open, mut card: Card<Transaction>,
admin_pin: Option<&[u8]>, admin_pin: Option<&[u8]>,
cmd: AdminGenerateCommand, cmd: AdminGenerateCommand,
) -> Result<()> { ) -> 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(); 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. // 1) Interpret the user's choice of algorithm.
// //
@ -461,7 +461,7 @@ fn generate_command(
// 2) Then, generate keys on the card. // 2) Then, generate keys on the card.
// We need "admin" access to the card for this). // We need "admin" access to the card for this).
let (key_sig, key_dec, key_aut) = { 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)? gen_subkeys(&mut admin, cmd.decrypt, cmd.auth, algo)?
} else { } else {
return Err(anyhow!("Failed to open card in admin mode.")); 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 // need "signing" access to the card (to make binding signatures within
// the Cert). // the Cert).
let cert = crate::get_cert( let cert = crate::get_cert(
&mut open, &mut card,
key_sig, key_sig,
key_dec, key_dec,
key_aut, key_aut,
@ -493,7 +493,7 @@ fn generate_command(
} }
fn touch_command( fn touch_command(
mut open: Open, mut card: Card<Transaction>,
admin_pin: Option<&[u8]>, admin_pin: Option<&[u8]>,
key: BasePlusAttKeySlot, key: BasePlusAttKeySlot,
policy: TouchPolicy, policy: TouchPolicy,
@ -502,7 +502,7 @@ fn touch_command(
let pol = openpgp_card_sequoia::types::TouchPolicy::from(policy); 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)?; admin.set_uif(kt, pol)?;
Ok(()) Ok(())

View file

@ -7,8 +7,8 @@ use std::path::PathBuf;
use anyhow::Result; use anyhow::Result;
use clap::{Parser, ValueEnum}; use clap::{Parser, ValueEnum};
use openpgp_card_sequoia::card::{Card, Open};
use openpgp_card_sequoia::card::Card;
use openpgp_card_sequoia::types::KeyType; use openpgp_card_sequoia::types::KeyType;
use crate::versioned_output::{OutputBuilder, OutputFormat, OutputVersion}; use crate::versioned_output::{OutputBuilder, OutputFormat, OutputVersion};
@ -60,7 +60,7 @@ pub enum BaseKeySlot {
Aut, Aut,
} }
impl From<BaseKeySlot> for openpgp_card_sequoia::types::KeyType { impl From<BaseKeySlot> for KeyType {
fn from(ks: BaseKeySlot) -> Self { fn from(ks: BaseKeySlot) -> Self {
match ks { match ks {
BaseKeySlot::Sig => KeyType::Signing, BaseKeySlot::Sig => KeyType::Signing,
@ -94,12 +94,12 @@ fn cert(
let mut output = output::AttestationCert::default(); let mut output = output::AttestationCert::default();
let backend = pick_card_for_reading(ident)?; let backend = pick_card_for_reading(ident)?;
let mut card = Card::new(backend); let mut open: Card<Open> = backend.into();
let mut open = card.transaction()?; 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); let pem = util::pem_encode(ac);
output.attestation_cert(pem); output.attestation_cert(pem);
} }
@ -114,12 +114,12 @@ fn generate(
user_pin: Option<PathBuf>, user_pin: Option<PathBuf>,
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
let backend = util::open_card(ident)?; let backend = util::open_card(ident)?;
let mut card = Card::new(backend); let mut open: Card<Open> = backend.into();
let mut open = card.transaction()?; 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); let kt = KeyType::from(key);
sign.generate_attestation(kt, &|| { sign.generate_attestation(kt, &|| {
@ -130,15 +130,15 @@ fn generate(
fn statement(ident: Option<String>, key: BaseKeySlot) -> Result<(), Box<dyn std::error::Error>> { fn statement(ident: Option<String>, key: BaseKeySlot) -> Result<(), Box<dyn std::error::Error>> {
let backend = pick_card_for_reading(ident)?; let backend = pick_card_for_reading(ident)?;
let mut card = Card::new(backend); let mut open: Card<Open> = backend.into();
let mut open = card.transaction()?; let mut card = open.transaction()?;
// Get cardholder certificate from card. // Get cardholder certificate from card.
let mut select_data_workaround = false; let mut select_data_workaround = false;
// Use "select data" workaround if the card reports a // Use "select data" workaround if the card reports a
// yk firmware version number >= 5 and <= 5.4.3 // 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 if version.len() == 3
&& version[0] == 5 && version[0] == 5
&& (version[1] < 4 || (version[1] == 4 && version[2] <= 3)) && (version[1] < 4 || (version[1] == 4 && version[2] <= 3))
@ -149,13 +149,13 @@ fn statement(ident: Option<String>, key: BaseKeySlot) -> Result<(), Box<dyn std:
// Select cardholder certificate // Select cardholder certificate
match key { match key {
BaseKeySlot::Aut => open.select_data(0, &[0x7F, 0x21], select_data_workaround)?, BaseKeySlot::Aut => card.select_data(0, &[0x7F, 0x21], select_data_workaround)?,
BaseKeySlot::Dec => open.select_data(1, &[0x7F, 0x21], select_data_workaround)?, BaseKeySlot::Dec => card.select_data(1, &[0x7F, 0x21], select_data_workaround)?,
BaseKeySlot::Sig => open.select_data(2, &[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) // 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() { if !cert.is_empty() {
let pem = util::pem_encode(cert); let pem = util::pem_encode(cert);

View file

@ -7,13 +7,12 @@ use clap::Parser;
use std::path::PathBuf; use std::path::PathBuf;
use openpgp_card_sequoia::card::{Card, Open};
use sequoia_openpgp::{ use sequoia_openpgp::{
parse::{stream::DecryptorBuilder, Parse}, parse::{stream::DecryptorBuilder, Parse},
policy::StandardPolicy, policy::StandardPolicy,
}; };
use openpgp_card_sequoia::card::Card;
use crate::util; use crate::util;
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
@ -35,16 +34,16 @@ pub fn decrypt(command: DecryptCommand) -> Result<(), Box<dyn std::error::Error>
let input = util::open_or_stdin(command.input.as_deref())?; let input = util::open_or_stdin(command.input.as_deref())?;
let backend = util::open_card(&command.ident)?; let backend = util::open_card(&command.ident)?;
let mut card = Card::new(backend); let mut open: Card<Open> = backend.into();
let mut open = card.transaction()?; 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()); 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 d = user.decryptor(&|| println!("Touch confirmation needed for decryption"))?;
let db = DecryptorBuilder::from_reader(input)?; let db = DecryptorBuilder::from_reader(input)?;

View file

@ -4,8 +4,7 @@
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use clap::Parser; use clap::Parser;
use openpgp_card_sequoia::card::{Card, Open};
use openpgp_card_sequoia::card::Card;
use crate::util; use crate::util;
@ -17,9 +16,9 @@ pub struct FactoryResetCommand {
pub fn factory_reset(command: FactoryResetCommand) -> Result<()> { pub fn factory_reset(command: FactoryResetCommand) -> Result<()> {
println!("Resetting Card {}", command.ident); println!("Resetting Card {}", command.ident);
let card = util::open_card(&command.ident)?; let backend = util::open_card(&command.ident)?;
let mut card = Card::new(card); let mut open: Card<Open> = backend.into();
let mut open = card.transaction()?; let mut card = open.transaction()?;
open.factory_reset().map_err(|e| anyhow!(e)) card.factory_reset().map_err(|e| anyhow!(e))
} }

View file

@ -5,8 +5,7 @@
use anyhow::Result; use anyhow::Result;
use clap::Parser; use clap::Parser;
use openpgp_card_sequoia::card::{Card, Open};
use openpgp_card_sequoia::card::Card;
use crate::output; use crate::output;
use crate::pick_card_for_reading; use crate::pick_card_for_reading;
@ -27,10 +26,10 @@ pub fn print_info(
let mut output = output::Info::default(); let mut output = output::Info::default();
let backend = pick_card_for_reading(command.ident)?; let backend = pick_card_for_reading(command.ident)?;
let mut card = Card::new(backend); let mut open: Card<Open> = backend.into();
let mut open = card.transaction()?; let mut card = open.transaction()?;
let ai = open.application_identifier()?; let ai = card.application_identifier()?;
output.ident(ai.ident()); output.ident(ai.ident());
@ -41,34 +40,34 @@ pub fn print_info(
output.manufacturer_id(format!("{:04X}", ai.manufacturer())); output.manufacturer_id(format!("{:04X}", ai.manufacturer()));
output.manufacturer_name(ai.manufacturer_name().to_string()); 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() { for line in cc.to_string().lines() {
let line = line.strip_prefix("- ").unwrap_or(line); let line = line.strip_prefix("- ").unwrap_or(line);
output.card_capability(line.to_string()); 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() { for line in csd.to_string().lines() {
let line = line.strip_prefix("- ").unwrap_or(line); let line = line.strip_prefix("- ").unwrap_or(line);
output.card_service_data(line.to_string()); 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() { for line in eli.to_string().lines() {
let line = line.strip_prefix("- ").unwrap_or(line); let line = line.strip_prefix("- ").unwrap_or(line);
output.extended_length_info(line.to_string()); output.extended_length_info(line.to_string());
} }
} }
let ec = open.extended_capabilities()?; let ec = card.extended_capabilities()?;
for line in ec.to_string().lines() { for line in ec.to_string().lines() {
let line = line.strip_prefix("- ").unwrap_or(line); let line = line.strip_prefix("- ").unwrap_or(line);
output.extended_capability(line.to_string()); output.extended_capability(line.to_string());
} }
// Algorithm information (list of supported algorithms) // 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() { for line in ai.to_string().lines() {
let line = line.strip_prefix("- ").unwrap_or(line); let line = line.strip_prefix("- ").unwrap_or(line);
output.algorithm(line.to_string()); output.algorithm(line.to_string());
@ -78,7 +77,7 @@ pub fn print_info(
// FIXME: print KDF info // FIXME: print KDF info
// YubiKey specific (?) firmware version // 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::<Vec<_>>().join("."); let ver = ver.iter().map(u8::to_string).collect::<Vec<_>>().join(".");
output.firmware_version(ver); output.firmware_version(ver);
} }

View file

@ -7,7 +7,7 @@ use std::path::PathBuf;
use anyhow::Result; use anyhow::Result;
use clap::Parser; use clap::Parser;
use openpgp_card_sequoia::card::{Card, Open}; use openpgp_card_sequoia::card::{Card, Open, Transaction};
use crate::util; use crate::util;
use crate::util::{load_pin, print_gnuk_note}; use crate::util::{load_pin, print_gnuk_note};
@ -72,51 +72,51 @@ pub enum PinSubCommand {
pub fn pin(ident: &str, cmd: PinSubCommand) -> Result<()> { pub fn pin(ident: &str, cmd: PinSubCommand) -> Result<()> {
let backend = util::open_card(ident)?; let backend = util::open_card(ident)?;
let mut card = Card::new(backend); let mut open: Card<Open> = backend.into();
let open = card.transaction()?; let card = open.transaction()?;
match cmd { match cmd {
PinSubCommand::SetUser { PinSubCommand::SetUser {
user_pin_old, user_pin_old,
user_pin_new, user_pin_new,
} => set_user(user_pin_old, user_pin_new, open), } => set_user(user_pin_old, user_pin_new, card),
PinSubCommand::SetAdmin { PinSubCommand::SetAdmin {
admin_pin_old, admin_pin_old,
admin_pin_new, admin_pin_new,
} => set_admin(admin_pin_old, admin_pin_new, open), } => set_admin(admin_pin_old, admin_pin_new, card),
PinSubCommand::ResetUser { PinSubCommand::ResetUser {
admin_pin, admin_pin,
user_pin_new, user_pin_new,
} => reset_user(admin_pin, user_pin_new, open), } => reset_user(admin_pin, user_pin_new, card),
PinSubCommand::SetReset { PinSubCommand::SetReset {
admin_pin, admin_pin,
reset_code, reset_code,
} => set_reset(admin_pin, reset_code, open), } => set_reset(admin_pin, reset_code, card),
PinSubCommand::ResetUserRc { PinSubCommand::ResetUserRc {
reset_code, reset_code,
user_pin_new, user_pin_new,
} => reset_user_rc(reset_code, user_pin_new, open), } => reset_user_rc(reset_code, user_pin_new, card),
} }
} }
fn set_user( fn set_user(
user_pin_old: Option<PathBuf>, user_pin_old: Option<PathBuf>,
user_pin_new: Option<PathBuf>, user_pin_new: Option<PathBuf>,
mut open: Open, mut card: Card<Transaction>,
) -> Result<()> { ) -> Result<()> {
let pinpad_modify = open.feature_pinpad_modify(); let pinpad_modify = card.feature_pinpad_modify();
let res = if !pinpad_modify { let res = if !pinpad_modify {
// get current user pin // 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"); .expect("this should never be None");
// verify pin // verify pin
open.verify_user(&user_pin1)?; card.verify_user(&user_pin1)?;
println!("PIN was accepted by the card.\n"); println!("PIN was accepted by the card.\n");
let pin_new = match user_pin_new { let pin_new = match user_pin_new {
@ -128,10 +128,10 @@ fn set_user(
}; };
// set new user pin // set new user pin
open.change_user_pin(&user_pin1, &pin_new) card.change_user_pin(&user_pin1, &pin_new)
} else { } else {
// set new user pin via pinpad // 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).") println!("Enter old User PIN on card reader pinpad, then new User PIN (twice).")
}) })
}; };
@ -140,7 +140,7 @@ fn set_user(
Err(err) => { Err(err) => {
println!("\nFailed to change the User PIN!"); println!("\nFailed to change the User PIN!");
println!("{:?}", err); println!("{:?}", err);
print_gnuk_note(err, &open)?; print_gnuk_note(err, &card)?;
} }
Ok(_) => println!("\nUser PIN has been set."), Ok(_) => println!("\nUser PIN has been set."),
} }
@ -150,17 +150,17 @@ fn set_user(
fn set_admin( fn set_admin(
admin_pin_old: Option<PathBuf>, admin_pin_old: Option<PathBuf>,
admin_pin_new: Option<PathBuf>, admin_pin_new: Option<PathBuf>,
mut open: Open, mut card: Card<Transaction>,
) -> Result<()> { ) -> Result<()> {
let pinpad_modify = open.feature_pinpad_modify(); let pinpad_modify = card.feature_pinpad_modify();
if !pinpad_modify { if !pinpad_modify {
// get current admin pin // 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"); .expect("this should never be None");
// verify pin // verify pin
open.verify_admin(&admin_pin1)?; card.verify_admin(&admin_pin1)?;
// (Verifying the PIN here fixes this class of problems: // (Verifying the PIN here fixes this class of problems:
// https://developers.yubico.com/PGP/PGP_PIN_Change_Behavior.html // https://developers.yubico.com/PGP/PGP_PIN_Change_Behavior.html
// It is also just generally more user friendly than failing later) // It is also just generally more user friendly than failing later)
@ -175,10 +175,10 @@ fn set_admin(
}; };
// set new admin pin // set new admin pin
open.change_admin_pin(&admin_pin1, &pin_new)?; card.change_admin_pin(&admin_pin1, &pin_new)?;
} else { } else {
// set new admin pin via pinpad // 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).") println!("Enter old Admin PIN on card reader pinpad, then new Admin PIN (twice).")
})?; })?;
}; };
@ -190,16 +190,16 @@ fn set_admin(
fn reset_user( fn reset_user(
admin_pin: Option<PathBuf>, admin_pin: Option<PathBuf>,
user_pin_new: Option<PathBuf>, user_pin_new: Option<PathBuf>,
mut open: Open, mut card: Card<Transaction>,
) -> Result<()> { ) -> Result<()> {
// verify admin pin // 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) => { Some(admin_pin) => {
// verify pin // verify pin
open.verify_admin(&admin_pin)?; card.verify_admin(&admin_pin)?;
} }
None => { 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"); println!("PIN was accepted by the card.\n");
@ -210,7 +210,7 @@ fn reset_user(
Some(path) => load_pin(&path)?, 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) admin.reset_user_pin(&pin)
} else { } else {
return Err(anyhow::anyhow!("Failed to use card in admin-mode.")); return Err(anyhow::anyhow!("Failed to use card in admin-mode."));
@ -219,7 +219,7 @@ fn reset_user(
match res { match res {
Err(err) => { Err(err) => {
println!("\nFailed to change the User PIN!"); println!("\nFailed to change the User PIN!");
print_gnuk_note(err, &open)?; print_gnuk_note(err, &card)?;
} }
Ok(_) => println!("\nUser PIN has been set."), Ok(_) => println!("\nUser PIN has been set."),
} }
@ -229,16 +229,16 @@ fn reset_user(
fn set_reset( fn set_reset(
admin_pin: Option<PathBuf>, admin_pin: Option<PathBuf>,
reset_code: Option<PathBuf>, reset_code: Option<PathBuf>,
mut open: Open, mut card: Card<Transaction>,
) -> Result<()> { ) -> Result<()> {
// verify admin pin // 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) => { Some(admin_pin) => {
// verify pin // verify pin
open.verify_admin(&admin_pin)?; card.verify_admin(&admin_pin)?;
} }
None => { 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"); println!("PIN was accepted by the card.\n");
@ -252,7 +252,7 @@ fn set_reset(
Some(path) => load_pin(&path)?, 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)?; admin.set_resetting_code(&code)?;
println!("\nResetting code has been set."); println!("\nResetting code has been set.");
Ok(()) Ok(())
@ -264,7 +264,7 @@ fn set_reset(
fn reset_user_rc( fn reset_user_rc(
reset_code: Option<PathBuf>, reset_code: Option<PathBuf>,
user_pin_new: Option<PathBuf>, user_pin_new: Option<PathBuf>,
mut open: Open, mut card: Card<Transaction>,
) -> Result<()> { ) -> Result<()> {
// reset by presenting resetting code // reset by presenting resetting code
@ -285,10 +285,10 @@ fn reset_user_rc(
}; };
// reset to new user pin // reset to new user pin
match open.reset_user_pin(&rst, &pin) { match card.reset_user_pin(&rst, &pin) {
Err(err) => { Err(err) => {
println!("\nFailed to change the User PIN!"); println!("\nFailed to change the User PIN!");
print_gnuk_note(err, &open) print_gnuk_note(err, &card)
} }
Ok(_) => { Ok(_) => {
println!("\nUser PIN has been set."); println!("\nUser PIN has been set.");

View file

@ -8,9 +8,9 @@ use clap::Parser;
use std::path::PathBuf; use std::path::PathBuf;
use openpgp_card_sequoia::card::{Card, Open};
use sequoia_openpgp::serialize::SerializeInto; use sequoia_openpgp::serialize::SerializeInto;
use openpgp_card_sequoia::card::Card;
use openpgp_card_sequoia::types::KeyType; use openpgp_card_sequoia::types::KeyType;
use openpgp_card_sequoia::util::public_key_material_and_fp_to_key; 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 mut output = output::PublicKey::default();
let backend = pick_card_for_reading(command.ident)?; let backend = pick_card_for_reading(command.ident)?;
let mut card = Card::new(backend); let mut open: Card<Open> = backend.into();
let mut open = card.transaction()?; let mut card = open.transaction()?;
let ident = open.application_identifier()?.ident(); let ident = card.application_identifier()?.ident();
output.ident(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 pkm = card.public_key(KeyType::Signing)?;
let times = open.key_generation_times()?; let times = card.key_generation_times()?;
let fps = open.fingerprints()?; let fps = card.fingerprints()?;
let key_sig = public_key_material_and_fp_to_key( let key_sig = public_key_material_and_fp_to_key(
&pkm, &pkm,
@ -60,7 +60,7 @@ pub fn print_pubkey(
)?; )?;
let mut key_dec = None; 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() { if let Some(ts) = times.decryption() {
key_dec = Some(public_key_material_and_fp_to_key( key_dec = Some(public_key_material_and_fp_to_key(
&pkm, &pkm,
@ -72,7 +72,7 @@ pub fn print_pubkey(
} }
let mut key_aut = None; 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() { if let Some(ts) = times.authentication() {
key_aut = Some(public_key_material_and_fp_to_key( key_aut = Some(public_key_material_and_fp_to_key(
&pkm, &pkm,
@ -85,7 +85,7 @@ pub fn print_pubkey(
} }
let cert = crate::get_cert( let cert = crate::get_cert(
&mut open, &mut card,
key_sig, key_sig,
key_dec, key_dec,
key_aut, key_aut,

View file

@ -4,8 +4,7 @@
use anyhow::Result; use anyhow::Result;
use clap::{Parser, ValueEnum}; use clap::{Parser, ValueEnum};
use openpgp_card_sequoia::card::{Card, Open};
use openpgp_card_sequoia::card::Card;
use crate::util; use crate::util;
@ -40,9 +39,9 @@ impl From<SetIdentityId> for u8 {
pub fn set_identity(command: SetIdentityCommand) -> Result<(), Box<dyn std::error::Error>> { pub fn set_identity(command: SetIdentityCommand) -> Result<(), Box<dyn std::error::Error>> {
let backend = util::open_card(&command.ident)?; let backend = util::open_card(&command.ident)?;
let mut card = Card::new(backend); let mut open: Card<Open> = backend.into();
let mut open = card.transaction()?; let mut card = open.transaction()?;
open.set_identity(u8::from(command.id))?; card.set_identity(u8::from(command.id))?;
Ok(()) Ok(())
} }

View file

@ -7,10 +7,9 @@ use clap::Parser;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use openpgp_card_sequoia::card::{Card, Open};
use sequoia_openpgp::serialize::stream::{Armorer, Message, Signer}; use sequoia_openpgp::serialize::stream::{Armorer, Message, Signer};
use openpgp_card_sequoia::card::Card;
use crate::util; use crate::util;
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
@ -46,16 +45,16 @@ pub fn sign_detached(
let mut input = util::open_or_stdin(input)?; let mut input = util::open_or_stdin(input)?;
let backend = util::open_card(ident)?; let backend = util::open_card(ident)?;
let mut card = Card::new(backend); let mut open: Card<Open> = backend.into();
let mut open = card.transaction()?; 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()); 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 s = sign.signer(&|| println!("Touch confirmation needed for signing"))?;
let message = Armorer::new(Message::new(std::io::stdout())).build()?; let message = Armorer::new(Message::new(std::io::stdout())).build()?;

View file

@ -5,8 +5,8 @@
use anyhow::Result; use anyhow::Result;
use clap::Parser; use clap::Parser;
use openpgp_card_sequoia::card::{Card, Open};
use openpgp_card_sequoia::card::Card;
use openpgp_card_sequoia::types::KeyType; use openpgp_card_sequoia::types::KeyType;
use crate::output; use crate::output;
@ -30,21 +30,21 @@ pub fn print_ssh(
let ident = command.ident; let ident = command.ident;
let backend = pick_card_for_reading(ident)?; let backend = pick_card_for_reading(ident)?;
let mut card = Card::new(backend); let mut open: Card<Open> = backend.into();
let mut open = card.transaction()?; let mut card = open.transaction()?;
let ident = open.application_identifier()?.ident(); let ident = card.application_identifier()?.ident();
output.ident(ident.clone()); output.ident(ident.clone());
// Print fingerprint of authentication subkey // Print fingerprint of authentication subkey
let fps = open.fingerprints()?; let fps = card.fingerprints()?;
if let Some(fp) = fps.authentication() { if let Some(fp) = fps.authentication() {
output.authentication_key_fingerprint(fp.to_string()); output.authentication_key_fingerprint(fp.to_string());
} }
// Show authentication subkey as openssh public key 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) { if let Ok(ssh) = util::get_ssh_pubkey_string(&pkm, ident) {
output.ssh_public_key(ssh); output.ssh_public_key(ssh);
} }

View file

@ -5,8 +5,8 @@
use anyhow::Result; use anyhow::Result;
use clap::Parser; use clap::Parser;
use openpgp_card_sequoia::card::{Card, Open};
use openpgp_card_sequoia::card::Card;
use openpgp_card_sequoia::types::KeyType; use openpgp_card_sequoia::types::KeyType;
use crate::output; use crate::output;
@ -35,17 +35,17 @@ pub fn print_status(
output.verbose(command.verbose); output.verbose(command.verbose);
let backend = pick_card_for_reading(command.ident)?; let backend = pick_card_for_reading(command.ident)?;
let mut card = Card::new(backend); let mut open: Card<Open> = backend.into();
let mut open = card.transaction()?; 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(); let version = ai.version().to_be_bytes();
output.card_version(format!("{}.{}", version[0], version[1])); output.card_version(format!("{}.{}", version[0], version[1]));
// card / cardholder metadata // card / cardholder metadata
let crd = open.cardholder_related_data()?; let crd = card.cardholder_related_data()?;
if let Some(name) = crd.name() { if let Some(name) = crd.name() {
// FIXME: decoding as utf8 is wrong (the spec defines this field as latin1 encoded) // 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); output.card_holder(name);
} }
let url = open.url()?; let url = card.url()?;
if !url.is_empty() { if !url.is_empty() {
output.url(url); output.url(url);
} }
@ -79,24 +79,24 @@ pub fn print_status(
} }
// key information (imported vs. generated on card) // 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 // information about subkeys
let fps = open.fingerprints()?; let fps = card.fingerprints()?;
let kgt = open.key_generation_times()?; let kgt = card.key_generation_times()?;
let mut signature_key = output::KeySlotInfo::default(); let mut signature_key = output::KeySlotInfo::default();
if let Some(fp) = fps.signature() { if let Some(fp) = fps.signature() {
signature_key.fingerprint(fp.to_spaced_hex()); 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() { if let Some(kgt) = kgt.signature() {
signature_key.created(format!("{}", kgt.to_datetime())); 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_policy(format!("{}", uif.touch_policy()));
signature_key.touch_features(format!("{}", uif.features())); signature_key.touch_features(format!("{}", uif.features()));
} }
@ -109,14 +109,14 @@ pub fn print_status(
} }
if command.pkm { 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()); signature_key.public_key_material(pkm.to_string());
} }
} }
output.signature_key(signature_key); output.signature_key(signature_key);
let sst = open.security_support_template()?; let sst = card.security_support_template()?;
output.signature_count(sst.signature_count()); output.signature_count(sst.signature_count());
let mut decryption_key = output::KeySlotInfo::default(); let mut decryption_key = output::KeySlotInfo::default();
@ -125,12 +125,12 @@ pub fn print_status(
} }
decryption_key.algorithm(format!( decryption_key.algorithm(format!(
"{}", "{}",
open.algorithm_attributes(KeyType::Decryption)? card.algorithm_attributes(KeyType::Decryption)?
)); ));
if let Some(kgt) = kgt.decryption() { if let Some(kgt) = kgt.decryption() {
decryption_key.created(format!("{}", kgt.to_datetime())); 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_policy(format!("{}", uif.touch_policy()));
decryption_key.touch_features(format!("{}", uif.features())); decryption_key.touch_features(format!("{}", uif.features()));
} }
@ -138,7 +138,7 @@ pub fn print_status(
decryption_key.status(format!("{}", ks)); decryption_key.status(format!("{}", ks));
} }
if command.pkm { 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()); decryption_key.public_key_material(pkm.to_string());
} }
} }
@ -150,12 +150,12 @@ pub fn print_status(
} }
authentication_key.algorithm(format!( authentication_key.algorithm(format!(
"{}", "{}",
open.algorithm_attributes(KeyType::Authentication)? card.algorithm_attributes(KeyType::Authentication)?
)); ));
if let Some(kgt) = kgt.authentication() { if let Some(kgt) = kgt.authentication() {
authentication_key.created(format!("{}", kgt.to_datetime())); 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_policy(format!("{}", uif.touch_policy()));
authentication_key.touch_features(format!("{}", uif.features())); authentication_key.touch_features(format!("{}", uif.features()));
} }
@ -163,7 +163,7 @@ pub fn print_status(
authentication_key.status(format!("{}", ks)); authentication_key.status(format!("{}", ks));
} }
if command.pkm { 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()); authentication_key.public_key_material(pkm.to_string());
} }
} }
@ -180,7 +180,7 @@ pub fn print_status(
// own `Option<KeySlotInfo>`, and (if any information about the // own `Option<KeySlotInfo>`, and (if any information about the
// attestation key exists at all, which is not the case for most // attestation key exists at all, which is not the case for most
// cards) it should be printed as a fourth KeySlot block. // 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_policy(uif.touch_policy().to_string());
output.card_touch_features(uif.features().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() { for fp in fps.iter().flatten() {
output.ca_fingerprint(fp.to_string()); output.ca_fingerprint(fp.to_string());
} }

View file

@ -8,7 +8,7 @@ use clap::Parser;
use sequoia_openpgp::Cert; 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::types::CardBackend;
use openpgp_card_sequoia::util::make_cert; use openpgp_card_sequoia::util::make_cert;
use openpgp_card_sequoia::PublicKey; use openpgp_card_sequoia::PublicKey;
@ -90,10 +90,9 @@ fn list_cards(format: OutputFormat, output_version: OutputVersion) -> Result<()>
let mut output = output::List::default(); let mut output = output::List::default();
if !cards.is_empty() { if !cards.is_empty() {
for backend in cards { for backend in cards {
let mut card = Card::new(backend); let mut open: Card<Open> = backend.into();
let open = card.transaction()?;
output.push(open.application_identifier()?.ident()); output.push(open.transaction()?.application_identifier()?.ident());
} }
} }
println!("{}", output.print(format, output_version)?); println!("{}", output.print(format, output_version)?);
@ -123,7 +122,7 @@ fn pick_card_for_reading(ident: Option<String>) -> Result<Box<dyn CardBackend +
} }
fn get_cert( fn get_cert(
open: &mut Open, card: &mut Card<Transaction>,
key_sig: PublicKey, key_sig: PublicKey,
key_dec: Option<PublicKey>, key_dec: Option<PublicKey>,
key_aut: Option<PublicKey>, key_aut: Option<PublicKey>,
@ -131,7 +130,7 @@ fn get_cert(
user_ids: &[String], user_ids: &[String],
prompt: &dyn Fn(), prompt: &dyn Fn(),
) -> Result<Cert> { ) -> Result<Cert> {
if user_pin.is_none() && open.feature_pinpad_verify() { if user_pin.is_none() && card.feature_pinpad_verify() {
println!( println!(
"The public cert will now be generated.\n\n\ "The public cert will now be generated.\n\n\
You will need to enter your User PIN multiple times during this process.\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( make_cert(
open, card,
key_sig, key_sig,
key_dec, key_dec,
key_aut, key_aut,

View file

@ -5,7 +5,7 @@ use anyhow::{anyhow, Context, Result};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use openpgp_card_pcsc::PcscBackend; 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::{ use openpgp_card_sequoia::types::{
Algo, CardBackend, Curve, EccType, Error, PublicKeyMaterial, StatusBytes, Algo, CardBackend, Curve, EccType, Error, PublicKeyMaterial, StatusBytes,
}; };
@ -23,11 +23,15 @@ pub(crate) fn open_card(ident: &str) -> Result<Box<dyn CardBackend + Send + Sync
/// If a pinpad is available, return Null (the pinpad will be used to get access to the card). /// If a pinpad is available, return Null (the pinpad will be used to get access to the card).
/// ///
/// `msg` is the message to show when asking the user to enter a PIN. /// `msg` is the message to show when asking the user to enter a PIN.
pub(crate) fn get_pin(open: &mut Open, pin_file: Option<PathBuf>, msg: &str) -> Option<Vec<u8>> { pub(crate) fn get_pin(
card: &mut Card<Transaction<'_>>,
pin_file: Option<PathBuf>,
msg: &str,
) -> Option<Vec<u8>> {
if let Some(path) = pin_file { if let Some(path) = pin_file {
// we have a pin file // we have a pin file
Some(load_pin(&path).ok()?) 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 // we have no pin file and no pinpad
let pin = rpassword::prompt_password(msg).ok()?; let pin = rpassword::prompt_password(msg).ok()?;
Some(pin.into_bytes()) Some(pin.into_bytes())
@ -51,53 +55,53 @@ pub(crate) fn input_pin_twice(msg1: &str, msg2: &str) -> Result<Vec<u8>> {
} }
pub(crate) fn verify_to_user<'app, 'open>( pub(crate) fn verify_to_user<'app, 'open>(
open: &'open mut Open<'app>, card: &'open mut Card<Transaction<'app>>,
pin: Option<&[u8]>, pin: Option<&[u8]>,
) -> Result<User<'app, 'open>, Box<dyn std::error::Error>> { ) -> Result<Card<User<'app, 'open>>, Box<dyn std::error::Error>> {
if let Some(pin) = pin { if let Some(pin) = pin {
open.verify_user(pin)?; card.verify_user(pin)?;
} else { } else {
if !open.feature_pinpad_verify() { if !card.feature_pinpad_verify() {
return Err(anyhow!("No user PIN file provided, and no pinpad found").into()); 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()) .ok_or_else(|| anyhow!("Couldn't get user access").into())
} }
pub(crate) fn verify_to_sign<'app, 'open>( pub(crate) fn verify_to_sign<'app, 'open>(
open: &'open mut Open<'app>, card: &'open mut Card<Transaction<'app>>,
pin: Option<&[u8]>, pin: Option<&[u8]>,
) -> Result<Sign<'app, 'open>, Box<dyn std::error::Error>> { ) -> Result<Card<Sign<'app, 'open>>, Box<dyn std::error::Error>> {
if let Some(pin) = pin { if let Some(pin) = pin {
open.verify_user_for_signing(pin)?; card.verify_user_for_signing(pin)?;
} else { } else {
if !open.feature_pinpad_verify() { if !card.feature_pinpad_verify() {
return Err(anyhow!("No user PIN file provided, and no pinpad found").into()); 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()) .ok_or_else(|| anyhow!("Couldn't get sign access").into())
} }
pub(crate) fn verify_to_admin<'app, 'open>( pub(crate) fn verify_to_admin<'app, 'open>(
open: &'open mut Open<'app>, card: &'open mut Card<Transaction<'app>>,
pin: Option<&[u8]>, pin: Option<&[u8]>,
) -> Result<Admin<'app, 'open>, Box<dyn std::error::Error>> { ) -> Result<Card<Admin<'app, 'open>>, Box<dyn std::error::Error>> {
if let Some(pin) = pin { if let Some(pin) = pin {
open.verify_admin(pin)?; card.verify_admin(pin)?;
} else { } else {
if !open.feature_pinpad_verify() { if !card.feature_pinpad_verify() {
return Err(anyhow!("No admin PIN file provided, and no pinpad found").into()); 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()) .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 /// 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.
pub(crate) fn print_gnuk_note(err: Error, card: &Open) -> Result<()> { pub(crate) fn print_gnuk_note(err: Error, card: &Card<Transaction>) -> Result<()> {
if matches!( if matches!(
err, err,
Error::CardStatus(StatusBytes::ConditionOfUseNotSatisfied) Error::CardStatus(StatusBytes::ConditionOfUseNotSatisfied)