Add callback Fn for touch confirmation prompt for decryption operations.
This commit is contained in:
parent
079cc32427
commit
374f9eec89
8 changed files with 49 additions and 9 deletions
|
@ -72,7 +72,7 @@ pub fn test_decrypt(
|
||||||
|
|
||||||
let p = StandardPolicy::new();
|
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);
|
let plain = String::from_utf8_lossy(&res);
|
||||||
|
|
||||||
assert_eq!(plain, "Hello world!\n");
|
assert_eq!(plain, "Hello world!\n");
|
||||||
|
|
|
@ -35,7 +35,9 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
|
||||||
let p = StandardPolicy::new();
|
let p = StandardPolicy::new();
|
||||||
let cert = Cert::from_file(cert_file)?;
|
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 stdin = std::io::stdin();
|
||||||
|
|
||||||
let mut stdout = std::io::stdout();
|
let mut stdout = std::io::stdout();
|
||||||
|
|
|
@ -169,7 +169,9 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||||
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(&cert, &|| {
|
||||||
|
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);
|
||||||
|
|
|
@ -340,8 +340,12 @@ pub struct User<'app, 'open> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'app, 'open> User<'app, 'open> {
|
impl<'app, 'open> User<'app, 'open> {
|
||||||
pub fn decryptor(&mut self, cert: &Cert) -> Result<CardDecryptor<'_, 'app>, Error> {
|
pub fn decryptor(
|
||||||
CardDecryptor::new(&mut self.oc.opt, cert)
|
&mut self,
|
||||||
|
cert: &Cert,
|
||||||
|
touch_prompt: &'open (dyn Fn() + Send + Sync),
|
||||||
|
) -> Result<CardDecryptor<'_, 'app>, Error> {
|
||||||
|
CardDecryptor::new(&mut self.oc.opt, cert, touch_prompt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,9 @@ pub struct CardDecryptor<'a, 'app> {
|
||||||
|
|
||||||
/// The matching public key for the card's decryption key
|
/// The matching public key for the card's decryption key
|
||||||
public: PublicKey,
|
public: PublicKey,
|
||||||
|
|
||||||
|
/// Callback function to signal if touch confirmation is needed
|
||||||
|
touch_prompt: &'a (dyn Fn() + Send + Sync),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'app> CardDecryptor<'a, 'app> {
|
impl<'a, 'app> CardDecryptor<'a, 'app> {
|
||||||
|
@ -34,6 +37,7 @@ impl<'a, 'app> CardDecryptor<'a, 'app> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
ca: &'a mut OpenPgpTransaction<'app>,
|
ca: &'a mut OpenPgpTransaction<'app>,
|
||||||
cert: &Cert,
|
cert: &Cert,
|
||||||
|
touch_prompt: &'a (dyn Fn() + Send + Sync),
|
||||||
) -> Result<CardDecryptor<'a, 'app>, Error> {
|
) -> Result<CardDecryptor<'a, 'app>, Error> {
|
||||||
// Get the fingerprint for the decryption key from the card.
|
// Get the fingerprint for the decryption key from the card.
|
||||||
let ard = ca.application_related_data()?;
|
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)? {
|
if let Some(eka) = sq_util::get_subkey_by_fingerprint(cert, &fp)? {
|
||||||
let public = eka.key().clone();
|
let public = eka.key().clone();
|
||||||
Ok(Self { ca, public })
|
Ok(Self {
|
||||||
|
ca,
|
||||||
|
public,
|
||||||
|
touch_prompt,
|
||||||
|
})
|
||||||
} else {
|
} else {
|
||||||
Err(Error::InternalError(format!(
|
Err(Error::InternalError(format!(
|
||||||
"Failed to find (sub)key {} in cert",
|
"Failed to find (sub)key {} in cert",
|
||||||
|
@ -71,6 +79,18 @@ impl<'a, 'app> crypto::Decryptor for CardDecryptor<'a, 'app> {
|
||||||
ciphertext: &mpi::Ciphertext,
|
ciphertext: &mpi::Ciphertext,
|
||||||
_plaintext_len: Option<usize>,
|
_plaintext_len: Option<usize>,
|
||||||
) -> openpgp::Result<crypto::SessionKey> {
|
) -> 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.
|
// Delegate a decryption operation to the OpenPGP card.
|
||||||
//
|
//
|
||||||
// This fn prepares the data structures that openpgp-card needs to
|
// 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()) {
|
match (ciphertext, self.public.mpis()) {
|
||||||
(mpi::Ciphertext::RSA { c: ct }, mpi::PublicKey::RSA { .. }) => {
|
(mpi::Ciphertext::RSA { c: ct }, mpi::PublicKey::RSA { .. }) => {
|
||||||
let dm = Cryptogram::RSA(ct.value());
|
let dm = Cryptogram::RSA(ct.value());
|
||||||
|
|
||||||
|
if touch_required {
|
||||||
|
(self.touch_prompt)();
|
||||||
|
}
|
||||||
|
|
||||||
let dec = self.ca.decipher(dm)?;
|
let dec = self.ca.decipher(dm)?;
|
||||||
|
|
||||||
let sk = openpgp::crypto::SessionKey::from(&dec[..]);
|
let sk = openpgp::crypto::SessionKey::from(&dec[..]);
|
||||||
|
@ -100,6 +125,10 @@ impl<'a, 'app> crypto::Decryptor for CardDecryptor<'a, 'app> {
|
||||||
Cryptogram::ECDH(e.value())
|
Cryptogram::ECDH(e.value())
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if touch_required {
|
||||||
|
(self.touch_prompt)();
|
||||||
|
}
|
||||||
|
|
||||||
// Decryption operation on the card
|
// Decryption operation on the card
|
||||||
let mut dec = self.ca.decipher(dm)?;
|
let mut dec = self.ca.decipher(dm)?;
|
||||||
|
|
||||||
|
|
|
@ -73,7 +73,7 @@
|
||||||
//! # let (cert, _) =
|
//! # let (cert, _) =
|
||||||
//! # CertBuilder::general_purpose(None, Some("alice@example.org"))
|
//! # CertBuilder::general_purpose(None, Some("alice@example.org"))
|
||||||
//! # .generate()?;
|
//! # .generate()?;
|
||||||
//! let decryptor = user.decryptor(&cert);
|
//! let decryptor = user.decryptor(&cert, &|| { println!("Touch confirmation needed for decryption") });
|
||||||
//!
|
//!
|
||||||
//! // Perform decryption operation(s)
|
//! // Perform decryption operation(s)
|
||||||
//! // ..
|
//! // ..
|
||||||
|
|
|
@ -404,13 +404,14 @@ pub fn decrypt(
|
||||||
card_tx: &'_ mut OpenPgpTransaction<'_>,
|
card_tx: &'_ mut OpenPgpTransaction<'_>,
|
||||||
cert: &Cert,
|
cert: &Cert,
|
||||||
msg: Vec<u8>,
|
msg: Vec<u8>,
|
||||||
|
touch_prompt: &(dyn Fn() + Send + Sync),
|
||||||
p: &dyn Policy,
|
p: &dyn Policy,
|
||||||
) -> Result<Vec<u8>> {
|
) -> 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)?;
|
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)?;
|
||||||
|
|
|
@ -892,7 +892,9 @@ fn decrypt(
|
||||||
let user_pin = util::get_pin(&mut open, pin_file, ENTER_USER_PIN);
|
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 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 db = DecryptorBuilder::from_reader(input)?;
|
||||||
let mut decryptor = db.with_policy(&p, None, d)?;
|
let mut decryptor = db.with_policy(&p, None, d)?;
|
||||||
|
|
Loading…
Reference in a new issue