Don't apply Policy when picking (sub)key from Cert for sign/decrypt.

This commit is contained in:
Heiko Schaefer 2021-12-11 23:35:58 +01:00
parent b04295543e
commit 383f592865
No known key found for this signature in database
GPG key ID: 4A849A1904CCBD7D
10 changed files with 25 additions and 99 deletions

View file

@ -93,15 +93,9 @@ pub fn test_sign(
let cert = Cert::from_str(param[0])?; let cert = Cert::from_str(param[0])?;
let p = StandardPolicy::new();
let msg = "Hello world, I am signed."; let msg = "Hello world, I am signed.";
let sig = openpgp_card_sequoia::util::sign( let sig =
&mut ca, openpgp_card_sequoia::util::sign(&mut ca, &cert, &mut msg.as_bytes())?;
&cert,
&mut msg.as_bytes(),
&p,
)?;
// validate sig // validate sig
assert!(util::verify_sig(&cert, msg.as_bytes(), sig.as_bytes())?); assert!(util::verify_sig(&cert, msg.as_bytes(), sig.as_bytes())?);

View file

@ -33,7 +33,7 @@ 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, &p)?; let d = user.decryptor(&cert)?;
let stdin = std::io::stdin(); let stdin = std::io::stdin();
let mut stdout = std::io::stdout(); let mut stdout = std::io::stdout();

View file

@ -6,7 +6,6 @@ use openpgp_card_pcsc::PcscClient;
use openpgp_card_sequoia::card::Open; use openpgp_card_sequoia::card::Open;
use openpgp::parse::Parse; use openpgp::parse::Parse;
use openpgp::policy::StandardPolicy;
use openpgp::serialize::stream::{Armorer, Message, Signer}; use openpgp::serialize::stream::{Armorer, Message, Signer};
use openpgp::Cert; use openpgp::Cert;
use sequoia_openpgp as openpgp; use sequoia_openpgp as openpgp;
@ -32,9 +31,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut user = open.signing_card().unwrap(); let mut user = open.signing_card().unwrap();
let p = StandardPolicy::new();
let cert = Cert::from_file(cert_file)?; let cert = Cert::from_file(cert_file)?;
let s = user.signer(&cert, &p)?; let s = user.signer(&cert)?;
let stdout = std::io::stdout(); let stdout = std::io::stdout();

View file

@ -8,7 +8,6 @@ use anyhow::{anyhow, Result};
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::policy::Policy;
use sequoia_openpgp::Cert; use sequoia_openpgp::Cert;
use openpgp_card::algorithm::{Algo, AlgoInfo, AlgoSimple}; use openpgp_card::algorithm::{Algo, AlgoInfo, AlgoSimple};
@ -355,12 +354,8 @@ pub struct User<'app, 'open> {
} }
impl User<'_, '_> { impl User<'_, '_> {
pub fn decryptor( pub fn decryptor(&mut self, cert: &Cert) -> Result<CardDecryptor, Error> {
&mut self, CardDecryptor::new(&mut self.oc.card_app, cert)
cert: &Cert,
policy: &dyn Policy,
) -> Result<CardDecryptor, Error> {
CardDecryptor::new(&mut self.oc.card_app, cert, policy)
} }
} }
@ -374,12 +369,11 @@ impl Sign<'_, '_> {
pub fn signer( pub fn signer(
&mut self, &mut self,
cert: &Cert, cert: &Cert,
policy: &dyn Policy,
) -> std::result::Result<CardSigner, Error> { ) -> std::result::Result<CardSigner, 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::new(&mut self.oc.card_app, cert, policy) CardSigner::new(&mut self.oc.card_app, cert)
} }
pub fn signer_from_pubkey(&mut self, pubkey: PublicKey) -> CardSigner { pub fn signer_from_pubkey(&mut self, pubkey: PublicKey) -> CardSigner {

View file

@ -10,7 +10,6 @@ use openpgp::packet;
use openpgp::parse::stream::{ use openpgp::parse::stream::{
DecryptionHelper, MessageStructure, VerificationHelper, DecryptionHelper, MessageStructure, VerificationHelper,
}; };
use openpgp::policy::Policy;
use openpgp::types::{Curve, SymmetricAlgorithm}; use openpgp::types::{Curve, SymmetricAlgorithm};
use openpgp::Cert; use openpgp::Cert;
use sequoia_openpgp as openpgp; use sequoia_openpgp as openpgp;
@ -37,7 +36,6 @@ impl<'a> CardDecryptor<'a> {
pub fn new( pub fn new(
ca: &'a mut CardApp, ca: &'a mut CardApp,
cert: &Cert, cert: &Cert,
policy: &dyn Policy,
) -> Result<CardDecryptor<'a>, Error> { ) -> Result<CardDecryptor<'a>, 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()?;
@ -48,19 +46,9 @@ impl<'a> CardDecryptor<'a> {
// Transform into Sequoia Fingerprint // Transform into Sequoia Fingerprint
let fp = openpgp::Fingerprint::from_bytes(fp.as_bytes()); let fp = openpgp::Fingerprint::from_bytes(fp.as_bytes());
if let Some(vk) = if let Some(eka) = sq_util::get_subkey_by_fingerprint(cert, &fp)? {
sq_util::get_subkey_by_fingerprint(cert, policy, &fp, false)? let public = eka.key().clone();
{ Ok(Self { ca, public })
if vk.for_storage_encryption() || vk.for_transport_encryption()
{
let public = vk.key().clone();
Ok(Self { ca, public })
} else {
Err(Error::InternalError(anyhow!(
"(Sub)key {} in the cert isn't encryption capable",
fp
)))
}
} else { } else {
Err(Error::InternalError(anyhow!( Err(Error::InternalError(anyhow!(
"Failed to find (sub)key {} in cert", "Failed to find (sub)key {} in cert",

View file

@ -172,7 +172,7 @@ 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, &sp)?; let d = user.decryptor(&cert)?;
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);
@ -197,7 +197,7 @@ fn main() -> Result<(), Box<dyn Error>> {
let text = "Hello world, I am signed."; let text = "Hello world, I am signed.";
let signer = sign.signer(&cert, &StandardPolicy::new())?; let signer = sign.signer(&cert)?;
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 anyhow::anyhow;
use openpgp::crypto; use openpgp::crypto;
use openpgp::crypto::mpi; use openpgp::crypto::mpi;
use openpgp::policy::Policy;
use openpgp::types::{Curve, PublicKeyAlgorithm}; use openpgp::types::{Curve, PublicKeyAlgorithm};
use sequoia_openpgp as openpgp; use sequoia_openpgp as openpgp;
@ -33,7 +32,6 @@ impl<'a> CardSigner<'a> {
pub fn new( pub fn new(
ca: &'a mut CardApp, ca: &'a mut CardApp,
cert: &openpgp::Cert, cert: &openpgp::Cert,
policy: &dyn Policy,
) -> Result<CardSigner<'a>, Error> { ) -> Result<CardSigner<'a>, Error> {
// Get the fingerprint for the signing key from the card. // Get the fingerprint for the signing key from the card.
let ard = ca.application_related_data()?; let ard = ca.application_related_data()?;
@ -44,18 +42,9 @@ impl<'a> CardSigner<'a> {
// Transform into Sequoia Fingerprint // Transform into Sequoia Fingerprint
let fp = openpgp::Fingerprint::from_bytes(fp.as_bytes()); let fp = openpgp::Fingerprint::from_bytes(fp.as_bytes());
if let Some(vk) = if let Some(eka) = sq_util::get_subkey_by_fingerprint(cert, &fp)? {
sq_util::get_subkey_by_fingerprint(cert, policy, &fp, true)? let key = eka.key().clone();
{ Ok(Self::with_pubkey(ca, key))
if vk.for_signing() {
let key = vk.key().clone();
Ok(Self::with_pubkey(ca, key))
} else {
Err(Error::InternalError(anyhow!(
"(Sub)key {} in the cert isn't signing capable",
fp
)))
}
} else { } else {
Err(Error::InternalError(anyhow!( Err(Error::InternalError(anyhow!(
"Failed to find (sub)key {} in cert", "Failed to find (sub)key {} in cert",

View file

@ -9,9 +9,7 @@ use anyhow::{anyhow, Context, Result};
use std::io; use std::io;
use openpgp::armor; use openpgp::armor;
use openpgp::cert::amalgamation::{ use openpgp::cert::amalgamation::key::ValidErasedKeyAmalgamation;
key::ValidErasedKeyAmalgamation, ValidAmalgamation, ValidateAmalgamation,
};
use openpgp::crypto; use openpgp::crypto;
use openpgp::packet::key::{PublicParts, SecretParts}; use openpgp::packet::key::{PublicParts, SecretParts};
use openpgp::parse::{ use openpgp::parse::{
@ -20,11 +18,11 @@ use openpgp::parse::{
}; };
use openpgp::policy::Policy; use openpgp::policy::Policy;
use openpgp::serialize::stream::{Message, Signer}; use openpgp::serialize::stream::{Message, Signer};
use openpgp::types::RevocationStatus;
use openpgp::{Cert, Fingerprint}; use openpgp::{Cert, Fingerprint};
use sequoia_openpgp as openpgp; use sequoia_openpgp as openpgp;
use openpgp_card::{Error, KeyType}; use openpgp_card::{Error, KeyType};
use sequoia_openpgp::cert::amalgamation::key::ErasedKeyAmalgamation;
/// Retrieve a (sub)key from a Cert, for a given KeyType. /// Retrieve a (sub)key from a Cert, for a given KeyType.
/// ///
@ -96,50 +94,17 @@ pub fn private_subkey_by_fingerprint<'a>(
/// Retrieve a public (sub)key from a Cert, by fingerprint. /// Retrieve a public (sub)key from a Cert, by fingerprint.
pub fn get_subkey_by_fingerprint<'a>( pub fn get_subkey_by_fingerprint<'a>(
cert: &'a Cert, cert: &'a Cert,
policy: &'a dyn Policy,
fp: &Fingerprint, fp: &Fingerprint,
check_revocation: bool, ) -> Result<Option<ErasedKeyAmalgamation<'a, PublicParts>>, Error> {
) -> Result<Option<ValidErasedKeyAmalgamation<'a, PublicParts>>, Error> {
// FIXME: if `test_revocation`, then first check if the primary key is
// revoked?
// Find the (sub)key in `cert` that matches the fingerprint from // Find the (sub)key in `cert` that matches the fingerprint from
// the Card's signing-key slot. // the Card's signing-key slot.
let keys: Vec<_> = let keys: Vec<_> =
cert.keys().filter(|ka| &ka.fingerprint() == fp).collect(); cert.keys().filter(|ka| &ka.fingerprint() == fp).collect();
// Exactly one matching (sub)key should be found. If not, fail! if keys.is_empty() {
if keys.len() == 1 {
// Check if the (sub)key is valid/alive, return error
// otherwise
let validkey = keys[0].clone().with_policy(policy, None)?;
validkey.alive()?;
if check_revocation {
if let RevocationStatus::Revoked(_) = validkey.revocation_status()
{
return Err(Error::InternalError(anyhow!(
"(Sub)key {} in the cert is revoked",
fp
)));
}
}
Ok(Some(validkey))
} else if keys.is_empty() {
Ok(None) Ok(None)
} else if keys.len() == 2 {
Err(Error::InternalError(anyhow!(
"Found two results for {}, probably the cert has the \
primary as a subkey?",
fp
)))
} else { } else {
Err(Error::InternalError(anyhow!( Ok(Some(keys[0].clone()))
"Found {} results for (sub)key {}, this is unexpected",
keys.len(),
fp
)))
} }
} }

View file

@ -19,7 +19,6 @@ use openpgp::packet::{
Key, UserID, Key, UserID,
}; };
use openpgp::parse::{stream::DecryptorBuilder, Parse}; use openpgp::parse::{stream::DecryptorBuilder, Parse};
use openpgp::policy::Policy;
use openpgp::serialize::stream::{Message, Signer}; use openpgp::serialize::stream::{Message, Signer};
use openpgp::types::{KeyFlags, PublicKeyAlgorithm, SignatureType, Timestamp}; use openpgp::types::{KeyFlags, PublicKeyAlgorithm, SignatureType, Timestamp};
use openpgp::{Cert, Packet}; use openpgp::{Cert, Packet};
@ -33,6 +32,7 @@ use openpgp_card::{CardApp, Error, KeyType};
use crate::card::Open; use crate::card::Open;
use crate::privkey::SequoiaKey; use crate::privkey::SequoiaKey;
use crate::{decryptor, signer, PublicKey}; use crate::{decryptor, signer, PublicKey};
use sequoia_openpgp::policy::Policy;
/// 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!)
@ -294,11 +294,10 @@ pub fn sign(
ca: &mut CardApp, ca: &mut CardApp,
cert: &Cert, cert: &Cert,
input: &mut dyn io::Read, input: &mut dyn io::Read,
p: &dyn Policy,
) -> 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(ca, cert, p)?; let s = signer::CardSigner::new(ca, cert)?;
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()?;
@ -325,7 +324,7 @@ pub fn decrypt(
{ {
let reader = io::BufReader::new(&msg[..]); let reader = io::BufReader::new(&msg[..]);
let d = decryptor::CardDecryptor::new(ca, cert, p)?; let d = decryptor::CardDecryptor::new(ca, cert)?;
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)?;

View file

@ -321,7 +321,7 @@ fn decrypt(
let mut open = Open::new(&mut card)?; let mut open = Open::new(&mut card)?;
let mut user = util::verify_to_user(&mut open, pin_file)?; let mut user = util::verify_to_user(&mut open, pin_file)?;
let d = user.decryptor(&cert, &p)?; let d = user.decryptor(&cert)?;
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)?;
@ -337,7 +337,6 @@ fn sign_detached(
cert_file: &Path, cert_file: &Path,
input: Option<&Path>, input: Option<&Path>,
) -> Result<(), Box<dyn std::error::Error>> { ) -> Result<(), Box<dyn std::error::Error>> {
let p = StandardPolicy::new();
let cert = Cert::from_file(cert_file)?; let cert = Cert::from_file(cert_file)?;
let mut input = util::open_or_stdin(input.as_deref())?; let mut input = util::open_or_stdin(input.as_deref())?;
@ -346,7 +345,7 @@ fn sign_detached(
let mut open = Open::new(&mut card)?; let mut open = Open::new(&mut card)?;
let mut sign = util::verify_to_sign(&mut open, pin_file)?; let mut sign = util::verify_to_sign(&mut open, pin_file)?;
let s = sign.signer(&cert, &p)?; let s = sign.signer(&cert)?;
let message = Armorer::new(Message::new(std::io::stdout())).build()?; let message = Armorer::new(Message::new(std::io::stdout())).build()?;
let mut signer = Signer::new(message, s).detached().build()?; let mut signer = Signer::new(message, s).detached().build()?;