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:
commit
46b5f59d0f
21 changed files with 446 additions and 402 deletions
|
@ -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(())
|
||||||
|
|
|
@ -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),
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
|
@ -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),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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")?;
|
||||||
|
|
|
@ -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()?;
|
||||||
|
|
|
@ -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(())
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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)?;
|
||||||
|
|
|
@ -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))
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.");
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()?;
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in a new issue