Implement signing for auth slot

This commit is contained in:
Heiko Schaefer 2022-06-20 19:59:12 +02:00
parent 141fe3d136
commit 43a9abdabd
No known key found for this signature in database
GPG key ID: 4A849A1904CCBD7D
3 changed files with 47 additions and 8 deletions

View file

@ -357,6 +357,14 @@ impl<'app, 'open> User<'app, 'open> {
) -> Result<CardDecryptor<'_, 'app>, Error> { ) -> Result<CardDecryptor<'_, 'app>, Error> {
CardDecryptor::new(&mut self.oc.opt, cert, touch_prompt) CardDecryptor::new(&mut self.oc.opt, cert, touch_prompt)
} }
pub fn authenticator(
&mut self,
pubkey: PublicKey,
touch_prompt: &'open (dyn Fn() + Send + Sync),
) -> CardSigner<'_, 'app> {
CardSigner::with_pubkey_for_auth(&mut self.oc.opt, pubkey, touch_prompt)
}
} }
/// An OpenPGP card after successfully verifying PW1 in mode 81 /// An OpenPGP card after successfully verifying PW1 in mode 81
@ -374,7 +382,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::new(&mut self.oc.opt, cert, touch_prompt) CardSigner::with_cert(&mut self.oc.opt, cert, touch_prompt)
} }
pub fn signer_from_pubkey( pub fn signer_from_pubkey(

View file

@ -25,6 +25,9 @@ pub struct CardSigner<'a, 'app> {
/// Callback function to signal if touch confirmation is needed /// Callback function to signal if touch confirmation is needed
touch_prompt: &'a (dyn Fn() + Send + Sync), touch_prompt: &'a (dyn Fn() + Send + Sync),
/// sign or auth? (true = auth)
auth: bool,
} }
impl<'a, 'app> CardSigner<'a, 'app> { impl<'a, 'app> CardSigner<'a, 'app> {
@ -32,7 +35,7 @@ impl<'a, 'app> CardSigner<'a, 'app> {
/// ///
/// An Error is returned if no match between the card's signing /// An Error is returned if no match between the card's signing
/// key and a (sub)key of `cert` can be made. /// key and a (sub)key of `cert` can be made.
pub(crate) fn new( pub(crate) fn with_cert(
ca: &'a mut OpenPgpTransaction<'app>, ca: &'a mut OpenPgpTransaction<'app>,
cert: &openpgp::Cert, cert: &openpgp::Cert,
touch_prompt: &'a (dyn Fn() + Send + Sync), touch_prompt: &'a (dyn Fn() + Send + Sync),
@ -71,6 +74,20 @@ impl<'a, 'app> CardSigner<'a, 'app> {
ca, ca,
public, public,
touch_prompt, touch_prompt,
auth: false,
}
}
pub(crate) fn with_pubkey_for_auth(
ca: &'a mut OpenPgpTransaction<'app>,
public: PublicKey,
touch_prompt: &'a (dyn Fn() + Send + Sync),
) -> CardSigner<'a, 'app> {
CardSigner {
ca,
public,
touch_prompt,
auth: true,
} }
} }
} }
@ -88,21 +105,35 @@ impl<'a, 'app> crypto::Signer for CardSigner<'a, 'app> {
// FIXME: use cached ARD value from caller? // FIXME: use cached ARD value from caller?
let ard = self.ca.application_related_data()?; let ard = self.ca.application_related_data()?;
// Get UIF setting for the sign or auth slot
let uif = if !self.auth {
ard.uif_pso_cds()?
} else {
ard.uif_pso_aut()?
};
// 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'
let touch_required = if let Some(uif) = ard.uif_pso_cds()? { let touch_required = if let Some(uif) = uif {
uif.touch_policy().touch_required() uif.touch_policy().touch_required()
} else { } else {
false false
}; };
// Delegate a signing operation to the OpenPGP card. let sig_fn = if !self.auth {
OpenPgpTransaction::signature_for_hash
} else {
OpenPgpTransaction::authenticate_for_hash
};
// Delegate a signing (or auth) 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
// perform the signing operation. // perform the signing operation.
// //
// (7.2.10 PSO: COMPUTE DIGITAL SIGNATURE) // (7.2.10 PSO: COMPUTE DIGITAL SIGNATURE)
// or (7.2.13 INTERNAL AUTHENTICATE)
match (self.public.pk_algo(), self.public.mpis()) { match (self.public.pk_algo(), self.public.mpis()) {
#[allow(deprecated)] #[allow(deprecated)]
@ -136,7 +167,7 @@ impl<'a, 'app> crypto::Signer for CardSigner<'a, 'app> {
(self.touch_prompt)(); (self.touch_prompt)();
} }
let sig = self.ca.signature_for_hash(hash)?; let sig = sig_fn(self.ca, hash)?;
let mpi = mpi::MPI::new(&sig[..]); let mpi = mpi::MPI::new(&sig[..]);
Ok(mpi::Signature::RSA { s: mpi }) Ok(mpi::Signature::RSA { s: mpi })
@ -148,7 +179,7 @@ impl<'a, 'app> crypto::Signer for CardSigner<'a, 'app> {
(self.touch_prompt)(); (self.touch_prompt)();
} }
let sig = self.ca.signature_for_hash(hash)?; let sig = sig_fn(self.ca, hash)?;
let r = mpi::MPI::new(&sig[..32]); let r = mpi::MPI::new(&sig[..32]);
let s = mpi::MPI::new(&sig[32..]); let s = mpi::MPI::new(&sig[32..]);
@ -167,7 +198,7 @@ impl<'a, 'app> crypto::Signer for CardSigner<'a, 'app> {
(self.touch_prompt)(); (self.touch_prompt)();
} }
let sig = self.ca.signature_for_hash(hash)?; let sig = sig_fn(self.ca, hash)?;
let len_2 = sig.len() / 2; let len_2 = sig.len() / 2;
let r = mpi::MPI::new(&sig[..len_2]); let r = mpi::MPI::new(&sig[..len_2]);

View file

@ -434,7 +434,7 @@ pub fn sign(
) -> Result<String> { ) -> 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::new(card_tx, cert, touch_prompt)?; 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()?;