Add callback Fn for touch confirmation prompt for decryption operations.

This commit is contained in:
Heiko Schaefer 2022-05-31 00:56:45 +02:00
parent 079cc32427
commit 374f9eec89
No known key found for this signature in database
GPG key ID: 4A849A1904CCBD7D
8 changed files with 49 additions and 9 deletions

View file

@ -72,7 +72,7 @@ pub fn test_decrypt(
let p = StandardPolicy::new();
let res = openpgp_card_sequoia::util::decrypt(&mut pgpt, &cert, msg.into_bytes(), &p)?;
let res = openpgp_card_sequoia::util::decrypt(&mut pgpt, &cert, msg.into_bytes(), &|| {}, &p)?;
let plain = String::from_utf8_lossy(&res);
assert_eq!(plain, "Hello world!\n");

View file

@ -35,7 +35,9 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let p = StandardPolicy::new();
let cert = Cert::from_file(cert_file)?;
let d = user.decryptor(&cert)?;
let d = user.decryptor(&cert, &|| {
println!("Touch confirmation needed for decryption")
})?;
let stdin = std::io::stdin();
let mut stdout = std::io::stdout();

View file

@ -169,7 +169,9 @@ fn main() -> Result<(), Box<dyn Error>> {
println!("Encrypted message:\n{}", msg);
let sp = StandardPolicy::new();
let d = user.decryptor(&cert)?;
let d = user.decryptor(&cert, &|| {
println!("Touch confirmation needed for decryption")
})?;
let res = sq_util::decryption_helper(d, msg.into_bytes(), &sp)?;
let plain = String::from_utf8_lossy(&res);

View file

@ -340,8 +340,12 @@ pub struct User<'app, 'open> {
}
impl<'app, 'open> User<'app, 'open> {
pub fn decryptor(&mut self, cert: &Cert) -> Result<CardDecryptor<'_, 'app>, Error> {
CardDecryptor::new(&mut self.oc.opt, cert)
pub fn decryptor(
&mut self,
cert: &Cert,
touch_prompt: &'open (dyn Fn() + Send + Sync),
) -> Result<CardDecryptor<'_, 'app>, Error> {
CardDecryptor::new(&mut self.oc.opt, cert, touch_prompt)
}
}

View file

@ -24,6 +24,9 @@ pub struct CardDecryptor<'a, 'app> {
/// The matching public key for the card's decryption key
public: PublicKey,
/// Callback function to signal if touch confirmation is needed
touch_prompt: &'a (dyn Fn() + Send + Sync),
}
impl<'a, 'app> CardDecryptor<'a, 'app> {
@ -34,6 +37,7 @@ impl<'a, 'app> CardDecryptor<'a, 'app> {
pub fn new(
ca: &'a mut OpenPgpTransaction<'app>,
cert: &Cert,
touch_prompt: &'a (dyn Fn() + Send + Sync),
) -> Result<CardDecryptor<'a, 'app>, Error> {
// Get the fingerprint for the decryption key from the card.
let ard = ca.application_related_data()?;
@ -46,7 +50,11 @@ impl<'a, 'app> CardDecryptor<'a, 'app> {
if let Some(eka) = sq_util::get_subkey_by_fingerprint(cert, &fp)? {
let public = eka.key().clone();
Ok(Self { ca, public })
Ok(Self {
ca,
public,
touch_prompt,
})
} else {
Err(Error::InternalError(format!(
"Failed to find (sub)key {} in cert",
@ -71,6 +79,18 @@ impl<'a, 'app> crypto::Decryptor for CardDecryptor<'a, 'app> {
ciphertext: &mpi::Ciphertext,
_plaintext_len: Option<usize>,
) -> openpgp::Result<crypto::SessionKey> {
// FIXME: use cached ARD value from caller?
let ard = self.ca.application_related_data()?;
// Touch is required if:
// - the card supports the feature
// - and the policy is set to a value other than 'Off'
let touch_required = if let Some(uif) = ard.uif_pso_dec()? {
uif.touch_policy().touch_required()
} else {
false
};
// Delegate a decryption operation to the OpenPGP card.
//
// This fn prepares the data structures that openpgp-card needs to
@ -80,6 +100,11 @@ impl<'a, 'app> crypto::Decryptor for CardDecryptor<'a, 'app> {
match (ciphertext, self.public.mpis()) {
(mpi::Ciphertext::RSA { c: ct }, mpi::PublicKey::RSA { .. }) => {
let dm = Cryptogram::RSA(ct.value());
if touch_required {
(self.touch_prompt)();
}
let dec = self.ca.decipher(dm)?;
let sk = openpgp::crypto::SessionKey::from(&dec[..]);
@ -100,6 +125,10 @@ impl<'a, 'app> crypto::Decryptor for CardDecryptor<'a, 'app> {
Cryptogram::ECDH(e.value())
};
if touch_required {
(self.touch_prompt)();
}
// Decryption operation on the card
let mut dec = self.ca.decipher(dm)?;

View file

@ -73,7 +73,7 @@
//! # let (cert, _) =
//! # CertBuilder::general_purpose(None, Some("alice@example.org"))
//! # .generate()?;
//! let decryptor = user.decryptor(&cert);
//! let decryptor = user.decryptor(&cert, &|| { println!("Touch confirmation needed for decryption") });
//!
//! // Perform decryption operation(s)
//! // ..

View file

@ -404,13 +404,14 @@ 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 reader = io::BufReader::new(&msg[..]);
let d = decryptor::CardDecryptor::new(card_tx, cert)?;
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)?;

View file

@ -892,7 +892,9 @@ fn decrypt(
let user_pin = util::get_pin(&mut open, pin_file, ENTER_USER_PIN);
let mut user = util::verify_to_user(&mut open, user_pin.as_deref())?;
let d = user.decryptor(&cert)?;
let d = user.decryptor(&cert, &|| {
println!("Touch confirmation needed for decryption")
})?;
let db = DecryptorBuilder::from_reader(input)?;
let mut decryptor = db.with_policy(&p, None, d)?;