From 6e630254fa017062d1a861ece687066d2a4c2745 Mon Sep 17 00:00:00 2001 From: Heiko Schaefer Date: Mon, 25 Jul 2022 16:18:48 +0200 Subject: [PATCH] Don't use `Cert` to build signer and decryptor. Rename decryptor/signer/authenticator getters. Add alternatives that don't require PublicKey parameter. --- openpgp-card-sequoia/examples/test.rs | 10 +++--- openpgp-card-sequoia/src/card.rs | 44 ++++++++++++++++++++++----- openpgp-card-sequoia/src/decryptor.rs | 44 +++++---------------------- openpgp-card-sequoia/src/lib.rs | 18 +++-------- openpgp-card-sequoia/src/signer.rs | 37 +--------------------- openpgp-card-sequoia/src/util.rs | 35 ++++++--------------- 6 files changed, 63 insertions(+), 125 deletions(-) diff --git a/openpgp-card-sequoia/examples/test.rs b/openpgp-card-sequoia/examples/test.rs index 75a5822..98dfb12 100644 --- a/openpgp-card-sequoia/examples/test.rs +++ b/openpgp-card-sequoia/examples/test.rs @@ -163,15 +163,13 @@ fn main() -> Result<(), Box> { .user_card() .expect("We just validated, this should not fail"); - let cert = Cert::from_file(TEST_KEY_PATH)?; + let _cert = Cert::from_file(TEST_KEY_PATH)?; let msg = std::fs::read_to_string(TEST_ENC_MSG).expect("Unable to read file"); println!("Encrypted message:\n{}", msg); let sp = StandardPolicy::new(); - let d = user.decryptor(&cert, &|| { - println!("Touch confirmation needed for decryption") - })?; + let d = user.decryptor(&|| println!("Touch confirmation needed for decryption"))?; let res = sq_util::decryption_helper(d, msg.into_bytes(), &sp)?; let plain = String::from_utf8_lossy(&res); @@ -194,11 +192,11 @@ fn main() -> Result<(), Box> { // Use Sign access to card let mut sign = open.signing_card().expect("just verified"); - let cert = Cert::from_file(TEST_KEY_PATH)?; + let _cert = Cert::from_file(TEST_KEY_PATH)?; let text = "Hello world, I am signed."; - let signer = sign.signer(&cert, &|| {})?; + let signer = sign.signer(&|| {})?; let sig = sq_util::sign_helper(signer, &mut text.as_bytes())?; println!("Signature from card:\n{}", sig) diff --git a/openpgp-card-sequoia/src/card.rs b/openpgp-card-sequoia/src/card.rs index d08d779..fc6cad9 100644 --- a/openpgp-card-sequoia/src/card.rs +++ b/openpgp-card-sequoia/src/card.rs @@ -7,7 +7,6 @@ use sequoia_openpgp::cert::amalgamation::key::ValidErasedKeyAmalgamation; use sequoia_openpgp::packet::key::SecretParts; use sequoia_openpgp::types::{HashAlgorithm, SymmetricAlgorithm}; -use sequoia_openpgp::Cert; use openpgp_card::algorithm::{Algo, AlgoInfo, AlgoSimple}; use openpgp_card::card_do::{ @@ -15,13 +14,13 @@ use openpgp_card::card_do::{ ExtendedLengthInfo, Fingerprint, HistoricalBytes, KeyGenerationTime, Lang, PWStatusBytes, SecuritySupportTemplate, Sex, TouchPolicy, }; +use openpgp_card::crypto_data::PublicKeyMaterial; use openpgp_card::{Error, KeySet, KeyType, OpenPgpTransaction}; use crate::decryptor::CardDecryptor; use crate::signer::CardSigner; use crate::util::{public_to_fingerprint, vka_as_uploadable_key}; use crate::PublicKey; -use openpgp_card::crypto_data::PublicKeyMaterial; /// Representation of an opened OpenPGP card in its base state (i.e. no /// passwords have been verified, default authorization applies). @@ -340,13 +339,40 @@ pub struct User<'app, 'open> { impl<'app, 'open> User<'app, 'open> { pub fn decryptor( &mut self, - cert: &Cert, touch_prompt: &'open (dyn Fn() + Send + Sync), ) -> Result, Error> { - CardDecryptor::new(&mut self.oc.opt, cert, touch_prompt) + let pk = crate::util::key_slot(self.oc, KeyType::Decryption)? + .expect("Couldn't get decryption pubkey from card"); + + Ok(CardDecryptor::with_pubkey( + &mut self.oc.opt, + pk, + touch_prompt, + )) + } + + pub fn decryptor_from_public( + &mut self, + pubkey: PublicKey, + touch_prompt: &'open (dyn Fn() + Send + Sync), + ) -> CardDecryptor<'_, 'app> { + CardDecryptor::with_pubkey(&mut self.oc.opt, pubkey, touch_prompt) } pub fn authenticator( + &mut self, + touch_prompt: &'open (dyn Fn() + Send + Sync), + ) -> Result, Error> { + let pk = crate::util::key_slot(self.oc, KeyType::Authentication)? + .expect("Couldn't get authentication pubkey from card"); + + Ok(CardSigner::with_pubkey_for_auth( + &mut self.oc.opt, + pk, + touch_prompt, + )) + } + pub fn authenticator_from_public( &mut self, pubkey: PublicKey, touch_prompt: &'open (dyn Fn() + Send + Sync), @@ -364,16 +390,18 @@ pub struct Sign<'app, 'open> { impl<'app, 'open> Sign<'app, 'open> { pub fn signer( &mut self, - cert: &Cert, touch_prompt: &'open (dyn Fn() + Send + Sync), - ) -> std::result::Result, Error> { + ) -> Result, Error> { // FIXME: depending on the setting in "PW1 Status byte", only one // signature can be made after verification for signing - CardSigner::with_cert(&mut self.oc.opt, cert, touch_prompt) + let pk = crate::util::key_slot(self.oc, KeyType::Signing)? + .expect("Couldn't get signing pubkey from card"); + + Ok(CardSigner::with_pubkey(&mut self.oc.opt, pk, touch_prompt)) } - pub fn signer_from_pubkey( + pub fn signer_from_public( &mut self, pubkey: PublicKey, touch_prompt: &'open (dyn Fn() + Send + Sync), diff --git a/openpgp-card-sequoia/src/decryptor.rs b/openpgp-card-sequoia/src/decryptor.rs index b1099ad..c7dc22d 100644 --- a/openpgp-card-sequoia/src/decryptor.rs +++ b/openpgp-card-sequoia/src/decryptor.rs @@ -9,13 +9,11 @@ use openpgp::crypto::SessionKey; use openpgp::packet; use openpgp::parse::stream::{DecryptionHelper, MessageStructure, VerificationHelper}; use openpgp::types::{Curve, SymmetricAlgorithm}; -use openpgp::Cert; use sequoia_openpgp as openpgp; use openpgp_card::crypto_data::Cryptogram; -use openpgp_card::{Error, OpenPgpTransaction}; +use openpgp_card::OpenPgpTransaction; -use crate::sq_util; use crate::PublicKey; pub struct CardDecryptor<'a, 'app> { @@ -30,41 +28,15 @@ pub struct CardDecryptor<'a, 'app> { } impl<'a, 'app> CardDecryptor<'a, 'app> { - /// Try to create a CardDecryptor. - /// - /// An Error is returned if no match between the card's decryption - /// key and a (sub)key of `cert` can be made. - pub fn new( + pub(crate) fn with_pubkey( ca: &'a mut OpenPgpTransaction<'app>, - cert: &Cert, + public: PublicKey, touch_prompt: &'a (dyn Fn() + Send + Sync), - ) -> Result, Error> { - // Get the fingerprint for the decryption key from the card. - let ard = ca.application_related_data()?; - let fps = ard.fingerprints()?; - let fp = fps.decryption(); - - if let Some(fp) = fp { - // Transform into Sequoia Fingerprint - let fp = openpgp::Fingerprint::from_bytes(fp.as_bytes()); - - if let Some(eka) = sq_util::get_subkey_by_fingerprint(cert, &fp)? { - let public = eka.key().clone(); - Ok(Self { - ca, - public, - touch_prompt, - }) - } else { - Err(Error::InternalError(format!( - "Failed to find (sub)key {} in cert", - fp - ))) - } - } else { - Err(Error::InternalError( - "Failed to get the decryption key's Fingerprint from the card".to_string(), - )) + ) -> CardDecryptor<'a, 'app> { + Self { + ca, + public, + touch_prompt, } } } diff --git a/openpgp-card-sequoia/src/lib.rs b/openpgp-card-sequoia/src/lib.rs index 58a6bf3..2a42d32 100644 --- a/openpgp-card-sequoia/src/lib.rs +++ b/openpgp-card-sequoia/src/lib.rs @@ -67,13 +67,8 @@ //! open.verify_user(b"123456")?; //! let mut user = open.user_card().expect("This should not fail"); //! -//! // Get decryptor (`cert` must contain a public key that corresponds -//! // to the key material on the card) -//! # use sequoia_openpgp::cert::CertBuilder; -//! # let (cert, _) = -//! # CertBuilder::general_purpose(None, Some("alice@example.org")) -//! # .generate()?; -//! let decryptor = user.decryptor(&cert, &|| { println!("Touch confirmation needed for decryption") }); +//! // Get decryptor +//! let decryptor = user.decryptor(&|| { println!("Touch confirmation needed for decryption") }); //! //! // Perform decryption operation(s) //! // .. @@ -110,13 +105,8 @@ //! open.verify_user_for_signing(b"123456")?; //! let mut user = open.signing_card().expect("This should not fail"); //! -//! // Get signer (`cert` must contain a public key that corresponds -//! // to the key material on the card) -//! # use sequoia_openpgp::cert::CertBuilder; -//! # let (cert, _) = -//! # CertBuilder::general_purpose(None, Some("alice@example.org")) -//! # .generate()?; -//! let signer = user.signer(&cert, &|| println!("Touch confirmation needed for signing")); +//! // Get signer +//! let signer = user.signer(&|| println!("Touch confirmation needed for signing")); //! //! // Perform signing operation(s) //! // .. diff --git a/openpgp-card-sequoia/src/signer.rs b/openpgp-card-sequoia/src/signer.rs index ae09140..651aa1f 100644 --- a/openpgp-card-sequoia/src/signer.rs +++ b/openpgp-card-sequoia/src/signer.rs @@ -11,9 +11,8 @@ use openpgp::types::{Curve, PublicKeyAlgorithm}; use sequoia_openpgp as openpgp; use openpgp_card::crypto_data::Hash; -use openpgp_card::{Error, OpenPgpTransaction}; +use openpgp_card::OpenPgpTransaction; -use crate::sq_util; use crate::PublicKey; pub struct CardSigner<'a, 'app> { @@ -31,40 +30,6 @@ pub struct CardSigner<'a, 'app> { } impl<'a, 'app> CardSigner<'a, 'app> { - /// Try to create a CardSigner. - /// - /// An Error is returned if no match between the card's signing - /// key and a (sub)key of `cert` can be made. - pub(crate) fn with_cert( - ca: &'a mut OpenPgpTransaction<'app>, - cert: &openpgp::Cert, - touch_prompt: &'a (dyn Fn() + Send + Sync), - ) -> Result, Error> { - // Get the fingerprint for the signing key from the card. - let ard = ca.application_related_data()?; - let fps = ard.fingerprints()?; - let fp = fps.signature(); - - if let Some(fp) = fp { - // Transform into Sequoia Fingerprint - let fp = openpgp::Fingerprint::from_bytes(fp.as_bytes()); - - if let Some(eka) = sq_util::get_subkey_by_fingerprint(cert, &fp)? { - let key = eka.key().clone(); - Ok(Self::with_pubkey(ca, key, touch_prompt)) - } else { - Err(Error::InternalError(format!( - "Failed to find (sub)key {} in cert", - fp - ))) - } - } else { - Err(Error::InternalError( - "Failed to get the signing key's Fingerprint from the card".to_string(), - )) - } - } - pub(crate) fn with_pubkey( ca: &'a mut OpenPgpTransaction<'app>, public: PublicKey, diff --git a/openpgp-card-sequoia/src/util.rs b/openpgp-card-sequoia/src/util.rs index 9165bb7..3c59e65 100644 --- a/openpgp-card-sequoia/src/util.rs +++ b/openpgp-card-sequoia/src/util.rs @@ -29,11 +29,13 @@ use sequoia_openpgp::types::{HashAlgorithm, SymmetricAlgorithm}; use openpgp_card::algorithm::{Algo, Curve}; use openpgp_card::card_do::{Fingerprint, KeyGenerationTime}; use openpgp_card::crypto_data::{CardUploadableKey, PublicKeyMaterial}; -use openpgp_card::{Error, KeyType, OpenPgpTransaction}; +use openpgp_card::{Error, KeyType}; use crate::card::Open; +use crate::decryptor::CardDecryptor; use crate::privkey::SequoiaKey; -use crate::{decryptor, signer, PublicKey}; +use crate::signer::CardSigner; +use crate::PublicKey; /// Create a Cert from the three subkeys on a card. /// (Calling this multiple times will result in different Certs!) @@ -85,7 +87,7 @@ pub fn make_cert<'app>( } if let Some(mut sign) = open.signing_card() { // Card-backed signer for bindings - let mut card_signer = sign.signer_from_pubkey(key_sig.clone(), touch_prompt); + let mut card_signer = sign.signer_from_public(key_sig.clone(), touch_prompt); let signing_bsig: Packet = sub_dec .bind(&mut card_signer, &cert, signing_builder)? @@ -116,7 +118,7 @@ pub fn make_cert<'app>( } if let Some(mut sign) = open.signing_card() { // Card-backed signer for bindings - let mut card_signer = sign.signer_from_pubkey(key_sig.clone(), touch_prompt); + let mut card_signer = sign.signer_from_public(key_sig.clone(), touch_prompt); // Temporary version of the cert let cert = Cert::try_from(pp.clone())?; @@ -159,7 +161,7 @@ pub fn make_cert<'app>( if let Some(mut sign) = open.signing_card() { // Card-backed signer for bindings - let mut card_signer = sign.signer_from_pubkey(key_sig, touch_prompt); + let mut card_signer = sign.signer_from_public(key_sig, touch_prompt); // Temporary version of the cert let cert = Cert::try_from(pp.clone())?; @@ -238,7 +240,7 @@ pub fn public_key_material_and_fp_to_key( } /// Get a PublicKey representation for a key slot on the card -pub fn key_slot(open: &mut Open, kt: KeyType) -> Result> { +pub fn key_slot(open: &mut Open, kt: KeyType) -> Result, Error> { // FIXME: only read these once, if multiple subkeys are retrieved from the card let times = open.key_generation_times()?; let fps = open.fingerprints()?; @@ -425,17 +427,9 @@ pub fn vka_as_uploadable_key( Box::new(sqk) } -/// FIXME: this fn is used in card_functionality, but should be removed -pub fn sign( - card_tx: &'_ mut OpenPgpTransaction<'_>, - cert: &Cert, - input: &mut dyn io::Read, - touch_prompt: &(dyn Fn() + Send + Sync), -) -> Result { +pub fn sign(s: CardSigner, input: &mut dyn io::Read) -> Result { let mut armorer = armor::Writer::new(vec![], armor::Kind::Signature)?; { - let s = signer::CardSigner::with_cert(card_tx, cert, touch_prompt)?; - let message = Message::new(&mut armorer); let mut message = Signer::new(message, s).detached().build()?; @@ -450,20 +444,11 @@ pub fn sign( String::from_utf8(buffer).context("Failed to convert signature to utf8") } -/// FIXME: this fn is used in card_functionality, but should be removed -pub fn decrypt( - card_tx: &'_ mut OpenPgpTransaction<'_>, - cert: &Cert, - msg: Vec, - touch_prompt: &(dyn Fn() + Send + Sync), - p: &dyn Policy, -) -> Result> { +pub fn decrypt(d: CardDecryptor, msg: Vec, p: &dyn Policy) -> Result> { let mut decrypted = Vec::new(); { let reader = io::BufReader::new(&msg[..]); - let d = decryptor::CardDecryptor::new(card_tx, cert, touch_prompt)?; - let db = DecryptorBuilder::from_reader(reader)?; let mut decryptor = db.with_policy(p, None, d)?;