Don't use Cert to build signer and decryptor.

Rename decryptor/signer/authenticator getters.
Add alternatives that don't require PublicKey parameter.
This commit is contained in:
Heiko Schaefer 2022-07-25 16:18:48 +02:00
parent f3ac66cef5
commit 6e630254fa
No known key found for this signature in database
GPG key ID: 4A849A1904CCBD7D
6 changed files with 63 additions and 125 deletions

View file

@ -163,15 +163,13 @@ fn main() -> Result<(), Box<dyn Error>> {
.user_card() .user_card()
.expect("We just validated, this should not fail"); .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"); let msg = std::fs::read_to_string(TEST_ENC_MSG).expect("Unable to read file");
println!("Encrypted message:\n{}", msg); println!("Encrypted message:\n{}", msg);
let sp = StandardPolicy::new(); let sp = StandardPolicy::new();
let d = user.decryptor(&cert, &|| { let d = user.decryptor(&|| println!("Touch confirmation needed for decryption"))?;
println!("Touch confirmation needed for decryption")
})?;
let res = sq_util::decryption_helper(d, msg.into_bytes(), &sp)?; let res = sq_util::decryption_helper(d, msg.into_bytes(), &sp)?;
let plain = String::from_utf8_lossy(&res); let plain = String::from_utf8_lossy(&res);
@ -194,11 +192,11 @@ fn main() -> Result<(), Box<dyn Error>> {
// Use Sign access to card // Use Sign access to card
let mut sign = open.signing_card().expect("just verified"); 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 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())?; let sig = sq_util::sign_helper(signer, &mut text.as_bytes())?;
println!("Signature from card:\n{}", sig) println!("Signature from card:\n{}", sig)

View file

@ -7,7 +7,6 @@
use sequoia_openpgp::cert::amalgamation::key::ValidErasedKeyAmalgamation; use sequoia_openpgp::cert::amalgamation::key::ValidErasedKeyAmalgamation;
use sequoia_openpgp::packet::key::SecretParts; use sequoia_openpgp::packet::key::SecretParts;
use sequoia_openpgp::types::{HashAlgorithm, SymmetricAlgorithm}; use sequoia_openpgp::types::{HashAlgorithm, SymmetricAlgorithm};
use sequoia_openpgp::Cert;
use openpgp_card::algorithm::{Algo, AlgoInfo, AlgoSimple}; use openpgp_card::algorithm::{Algo, AlgoInfo, AlgoSimple};
use openpgp_card::card_do::{ use openpgp_card::card_do::{
@ -15,13 +14,13 @@ use openpgp_card::card_do::{
ExtendedLengthInfo, Fingerprint, HistoricalBytes, KeyGenerationTime, Lang, PWStatusBytes, ExtendedLengthInfo, Fingerprint, HistoricalBytes, KeyGenerationTime, Lang, PWStatusBytes,
SecuritySupportTemplate, Sex, TouchPolicy, SecuritySupportTemplate, Sex, TouchPolicy,
}; };
use openpgp_card::crypto_data::PublicKeyMaterial;
use openpgp_card::{Error, KeySet, KeyType, OpenPgpTransaction}; use openpgp_card::{Error, KeySet, KeyType, OpenPgpTransaction};
use crate::decryptor::CardDecryptor; use crate::decryptor::CardDecryptor;
use crate::signer::CardSigner; 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;
use openpgp_card::crypto_data::PublicKeyMaterial;
/// Representation of an opened OpenPGP card in its base state (i.e. no /// Representation of an opened OpenPGP card in its base state (i.e. no
/// passwords have been verified, default authorization applies). /// passwords have been verified, default authorization applies).
@ -340,13 +339,40 @@ pub struct User<'app, 'open> {
impl<'app, 'open> User<'app, 'open> { impl<'app, 'open> User<'app, 'open> {
pub fn decryptor( pub fn decryptor(
&mut self, &mut self,
cert: &Cert,
touch_prompt: &'open (dyn Fn() + Send + Sync), touch_prompt: &'open (dyn Fn() + Send + Sync),
) -> Result<CardDecryptor<'_, 'app>, Error> { ) -> Result<CardDecryptor<'_, 'app>, 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( pub fn authenticator(
&mut self,
touch_prompt: &'open (dyn Fn() + Send + Sync),
) -> Result<CardSigner<'_, 'app>, 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, &mut self,
pubkey: PublicKey, pubkey: PublicKey,
touch_prompt: &'open (dyn Fn() + Send + Sync), touch_prompt: &'open (dyn Fn() + Send + Sync),
@ -364,16 +390,18 @@ pub struct Sign<'app, 'open> {
impl<'app, 'open> Sign<'app, 'open> { impl<'app, 'open> Sign<'app, 'open> {
pub fn signer( pub fn signer(
&mut self, &mut self,
cert: &Cert,
touch_prompt: &'open (dyn Fn() + Send + Sync), touch_prompt: &'open (dyn Fn() + Send + Sync),
) -> std::result::Result<CardSigner<'_, 'app>, Error> { ) -> Result<CardSigner<'_, 'app>, Error> {
// 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_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, &mut self,
pubkey: PublicKey, pubkey: PublicKey,
touch_prompt: &'open (dyn Fn() + Send + Sync), touch_prompt: &'open (dyn Fn() + Send + Sync),

View file

@ -9,13 +9,11 @@ use openpgp::crypto::SessionKey;
use openpgp::packet; use openpgp::packet;
use openpgp::parse::stream::{DecryptionHelper, MessageStructure, VerificationHelper}; use openpgp::parse::stream::{DecryptionHelper, MessageStructure, VerificationHelper};
use openpgp::types::{Curve, SymmetricAlgorithm}; use openpgp::types::{Curve, SymmetricAlgorithm};
use openpgp::Cert;
use sequoia_openpgp as openpgp; use sequoia_openpgp as openpgp;
use openpgp_card::crypto_data::Cryptogram; use openpgp_card::crypto_data::Cryptogram;
use openpgp_card::{Error, OpenPgpTransaction}; use openpgp_card::OpenPgpTransaction;
use crate::sq_util;
use crate::PublicKey; use crate::PublicKey;
pub struct CardDecryptor<'a, 'app> { pub struct CardDecryptor<'a, 'app> {
@ -30,41 +28,15 @@ pub struct CardDecryptor<'a, 'app> {
} }
impl<'a, 'app> CardDecryptor<'a, 'app> { impl<'a, 'app> CardDecryptor<'a, 'app> {
/// Try to create a CardDecryptor. pub(crate) fn with_pubkey(
///
/// 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(
ca: &'a mut OpenPgpTransaction<'app>, ca: &'a mut OpenPgpTransaction<'app>,
cert: &Cert, public: PublicKey,
touch_prompt: &'a (dyn Fn() + Send + Sync), touch_prompt: &'a (dyn Fn() + Send + Sync),
) -> Result<CardDecryptor<'a, 'app>, Error> { ) -> CardDecryptor<'a, 'app> {
// Get the fingerprint for the decryption key from the card. Self {
let ard = ca.application_related_data()?; ca,
let fps = ard.fingerprints()?; public,
let fp = fps.decryption(); touch_prompt,
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(),
))
} }
} }
} }

View file

@ -67,13 +67,8 @@
//! open.verify_user(b"123456")?; //! open.verify_user(b"123456")?;
//! let mut user = open.user_card().expect("This should not fail"); //! let mut user = open.user_card().expect("This should not fail");
//! //!
//! // Get decryptor (`cert` must contain a public key that corresponds //! // Get decryptor
//! // to the key material on the card) //! let decryptor = user.decryptor(&|| { println!("Touch confirmation needed for decryption") });
//! # 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") });
//! //!
//! // Perform decryption operation(s) //! // Perform decryption operation(s)
//! // .. //! // ..
@ -110,13 +105,8 @@
//! open.verify_user_for_signing(b"123456")?; //! open.verify_user_for_signing(b"123456")?;
//! let mut user = open.signing_card().expect("This should not fail"); //! let mut user = open.signing_card().expect("This should not fail");
//! //!
//! // Get signer (`cert` must contain a public key that corresponds //! // Get signer
//! // to the key material on the card) //! let signer = user.signer(&|| println!("Touch confirmation needed for signing"));
//! # 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"));
//! //!
//! // Perform signing operation(s) //! // Perform signing operation(s)
//! // .. //! // ..

View file

@ -11,9 +11,8 @@ use openpgp::types::{Curve, PublicKeyAlgorithm};
use sequoia_openpgp as openpgp; use sequoia_openpgp as openpgp;
use openpgp_card::crypto_data::Hash; use openpgp_card::crypto_data::Hash;
use openpgp_card::{Error, OpenPgpTransaction}; use openpgp_card::OpenPgpTransaction;
use crate::sq_util;
use crate::PublicKey; use crate::PublicKey;
pub struct CardSigner<'a, 'app> { pub struct CardSigner<'a, 'app> {
@ -31,40 +30,6 @@ pub struct CardSigner<'a, 'app> {
} }
impl<'a, 'app> 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<CardSigner<'a, 'app>, 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( pub(crate) fn with_pubkey(
ca: &'a mut OpenPgpTransaction<'app>, ca: &'a mut OpenPgpTransaction<'app>,
public: PublicKey, public: PublicKey,

View file

@ -29,11 +29,13 @@ use sequoia_openpgp::types::{HashAlgorithm, SymmetricAlgorithm};
use openpgp_card::algorithm::{Algo, Curve}; use openpgp_card::algorithm::{Algo, Curve};
use openpgp_card::card_do::{Fingerprint, KeyGenerationTime}; 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, OpenPgpTransaction}; use openpgp_card::{Error, KeyType};
use crate::card::Open; use crate::card::Open;
use crate::decryptor::CardDecryptor;
use crate::privkey::SequoiaKey; 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. /// Create a Cert from the three subkeys on a card.
/// (Calling this multiple times will result in different Certs!) /// (Calling this multiple times will result in different Certs!)
@ -85,7 +87,7 @@ pub fn make_cert<'app>(
} }
if let Some(mut sign) = open.signing_card() { if let Some(mut sign) = open.signing_card() {
// Card-backed signer for bindings // 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 let signing_bsig: Packet = sub_dec
.bind(&mut card_signer, &cert, signing_builder)? .bind(&mut card_signer, &cert, signing_builder)?
@ -116,7 +118,7 @@ pub fn make_cert<'app>(
} }
if let Some(mut sign) = open.signing_card() { if let Some(mut sign) = open.signing_card() {
// Card-backed signer for bindings // 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 // Temporary version of the cert
let cert = Cert::try_from(pp.clone())?; let cert = Cert::try_from(pp.clone())?;
@ -159,7 +161,7 @@ pub fn make_cert<'app>(
if let Some(mut sign) = open.signing_card() { if let Some(mut sign) = open.signing_card() {
// Card-backed signer for bindings // 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 // Temporary version of the cert
let cert = Cert::try_from(pp.clone())?; 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 /// Get a PublicKey representation for a key slot on the card
pub fn key_slot(open: &mut Open, kt: KeyType) -> Result<Option<PublicKey>> { pub fn key_slot(open: &mut Open, 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()?;
@ -425,17 +427,9 @@ pub fn vka_as_uploadable_key(
Box::new(sqk) Box::new(sqk)
} }
/// FIXME: this fn is used in card_functionality, but should be removed pub fn sign(s: CardSigner, input: &mut dyn io::Read) -> Result<String> {
pub fn sign(
card_tx: &'_ mut OpenPgpTransaction<'_>,
cert: &Cert,
input: &mut dyn io::Read,
touch_prompt: &(dyn Fn() + Send + Sync),
) -> Result<String> {
let mut armorer = armor::Writer::new(vec![], armor::Kind::Signature)?; 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 message = Message::new(&mut armorer);
let mut message = Signer::new(message, s).detached().build()?; 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") 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(d: CardDecryptor, msg: Vec<u8>, p: &dyn Policy) -> Result<Vec<u8>> {
pub fn decrypt(
card_tx: &'_ mut OpenPgpTransaction<'_>,
cert: &Cert,
msg: Vec<u8>,
touch_prompt: &(dyn Fn() + Send + Sync),
p: &dyn Policy,
) -> Result<Vec<u8>> {
let mut decrypted = Vec::new(); let mut decrypted = Vec::new();
{ {
let reader = io::BufReader::new(&msg[..]); let reader = io::BufReader::new(&msg[..]);
let d = decryptor::CardDecryptor::new(card_tx, cert, touch_prompt)?;
let db = DecryptorBuilder::from_reader(reader)?; let db = DecryptorBuilder::from_reader(reader)?;
let mut decryptor = db.with_policy(p, None, d)?; let mut decryptor = db.with_policy(p, None, d)?;