keyfork/crates/keyfork-shard/src/openpgp.rs

726 lines
24 KiB
Rust
Raw Normal View History

2024-01-16 02:44:48 +00:00
//! OpenPGP Shard functionality.
#![allow(clippy::expect_fun_call)]
use std::{
2024-02-19 10:49:43 +00:00
collections::HashMap,
io::{Read, Write},
marker::PhantomData,
path::Path,
str::FromStr,
sync::{Arc, Mutex},
};
use keyfork_bug::bug;
use keyfork_derive_openpgp::{
2024-02-19 10:49:43 +00:00
derive_util::{DerivationPath, VariableLengthSeed},
XPrv,
};
use keyfork_prompt::PromptHandler;
use openpgp::{
armor::{Kind, Writer},
cert::{Cert, CertParser, ValidCert},
packet::{Packet, Tag, UserID, PKESK, SEIP},
parse::{
stream::{DecryptionHelper, DecryptorBuilder, VerificationHelper},
Parse,
},
policy::{NullPolicy, Policy},
serialize::{
2023-11-05 05:45:47 +00:00
stream::{ArbitraryWriter, Encryptor2, LiteralWriter, Message, Recipient, Signer},
Marshal,
},
types::KeyFlags,
2024-02-19 10:49:43 +00:00
KeyID, PacketPile,
};
pub use sequoia_openpgp as openpgp;
2024-02-19 10:49:43 +00:00
use sharks::Share;
mod keyring;
use keyring::Keyring;
mod smartcard;
use smartcard::SmartcardManager;
/// Shard metadata verson 1:
/// 1 byte: Version
/// 1 byte: Threshold
2024-01-07 04:23:03 +00:00
/// Packet Pile of Certs
const SHARD_METADATA_VERSION: u8 = 1;
const SHARD_METADATA_OFFSET: usize = 2;
2024-02-19 10:49:43 +00:00
use super::{Format, KeyDiscovery, SharksError};
2024-01-16 02:44:48 +00:00
/// Errors encountered while performing operations using OpenPGP.
#[derive(Debug, thiserror::Error)]
pub enum Error {
2024-01-16 02:44:48 +00:00
/// Errors encountered while creating or combining shares.
#[error("{0}")]
Sharks(#[from] SharksError),
2024-01-16 02:44:48 +00:00
/// An error occurred while performing an OpenPGP operation.
#[error("OpenPGP error: {0}")]
Sequoia(#[source] anyhow::Error),
2024-01-16 02:44:48 +00:00
/// An IO error occurred while performing an OpenPGP operation.
#[error("OpenPGP IO error: {0}")]
SequoiaIo(#[source] std::io::Error),
2024-01-16 02:44:48 +00:00
/// An error occurred while using a keyring.
#[error("Keyring error: {0}")]
Keyring(#[from] keyring::Error),
2024-01-16 02:44:48 +00:00
/// An error occurred while using a smartcard.
#[error("Smartcard error: {0}")]
Smartcard(#[from] smartcard::Error),
2024-01-16 02:44:48 +00:00
/// An IO error occurred.
#[error("IO error: {0}")]
Io(#[source] std::io::Error),
}
2024-01-16 02:44:48 +00:00
#[allow(missing_docs)]
pub type Result<T, E = Error> = std::result::Result<T, E>;
2024-01-16 02:44:48 +00:00
/// An OpenPGP encrypted message and public-key-encrypted-secret-key packets.
#[derive(Debug, Clone)]
pub struct EncryptedMessage {
pkesks: Vec<PKESK>,
message: SEIP,
}
impl EncryptedMessage {
2024-01-16 02:44:48 +00:00
/// Create a new EncryptedMessage from known parts.
2023-12-19 14:55:22 +00:00
pub fn new(pkesks: &mut Vec<PKESK>, seip: SEIP) -> Self {
Self {
pkesks: std::mem::take(pkesks),
message: seip,
}
}
2024-02-15 08:01:23 +00:00
/// Parse OpenPGP packets for encrypted messages.
2024-02-19 10:49:43 +00:00
///
/// # Errors
/// The function may return an error if Sequoia is unable to parse packets.
///
/// # Panics
/// The function may panic if an unexpected packet is encountered.
2024-02-15 08:01:23 +00:00
pub fn from_reader(input: impl Read + Send + Sync) -> openpgp::Result<Vec<Self>> {
let mut pkesks = Vec::new();
let mut encrypted_messages = vec![];
for packet in PacketPile::from_reader(input)
.map_err(Error::Sequoia)?
.into_children()
{
match packet {
Packet::PKESK(p) => pkesks.push(p),
Packet::SEIP(s) => {
encrypted_messages.push(EncryptedMessage::new(&mut pkesks, s));
}
s => {
panic!("Invalid variant found: {}", s.tag());
}
}
}
Ok(encrypted_messages)
}
2024-01-20 06:20:04 +00:00
/// Serialize all contents of the message to a writer.
///
/// # Errors
/// The function may error for any condition in Sequoia's Serialize trait.
2024-02-15 08:01:23 +00:00
fn serialize(&self, mut o: impl std::io::Write + Send + Sync) -> openpgp::Result<()> {
2024-01-20 06:20:04 +00:00
for pkesk in &self.pkesks {
2024-02-15 08:01:23 +00:00
let mut packet = vec![];
pkesk.serialize(&mut packet).map_err(Error::Sequoia)?;
let message = Message::new(&mut o);
let mut message = ArbitraryWriter::new(message, Tag::PKESK).map_err(Error::Sequoia)?;
message.write_all(&packet).map_err(Error::SequoiaIo)?;
message.finalize().map_err(Error::Sequoia)?;
2024-01-20 06:20:04 +00:00
}
2024-02-15 08:01:23 +00:00
let mut packet = vec![];
self.message
.serialize(&mut packet)
.map_err(Error::Sequoia)?;
let message = Message::new(&mut o);
let mut message = ArbitraryWriter::new(message, Tag::SEIP).map_err(Error::Sequoia)?;
message.write_all(&packet).map_err(Error::SequoiaIo)?;
message.finalize().map_err(Error::Sequoia)?;
2024-01-20 06:20:04 +00:00
Ok(())
}
2024-01-16 02:44:48 +00:00
/// Decrypt the message with a Sequoia policy and decryptor.
///
/// This method creates a container containing the packets and passes the serialized container
/// to a DecryptorBuilder, which is used to decrypt the message.
///
/// # Errors
/// The method may return an error if it is unable to rebuild the message to decrypt or if it
/// is unable to decrypt the message.
pub fn decrypt_with<H>(&self, policy: &'_ dyn Policy, decryptor: H) -> Result<Vec<u8>>
where
H: VerificationHelper + DecryptionHelper,
{
let mut packets = vec![];
2024-02-19 10:49:43 +00:00
self.serialize(&mut packets).map_err(Error::Sequoia)?;
let mut decryptor = DecryptorBuilder::from_bytes(&packets)
.map_err(Error::Sequoia)?
.with_policy(policy, None, decryptor)
.map_err(Error::Sequoia)?;
let mut content = vec![];
decryptor
.read_to_end(&mut content)
.map_err(Error::SequoiaIo)?;
Ok(content)
}
}
2024-01-20 06:20:04 +00:00
///
pub struct OpenPGP<P: PromptHandler> {
p: PhantomData<P>,
}
impl<P: PromptHandler> OpenPGP<P> {
#[allow(clippy::new_without_default, missing_docs)]
pub fn new() -> Self {
Self { p: PhantomData }
}
}
2024-01-20 06:20:04 +00:00
impl<P: PromptHandler> OpenPGP<P> {
/// Read all OpenPGP certificates in a path and return a [`Vec`] of them.
///
/// Certificates are read from a file, or from files one level deep in a directory.
/// Certificates with duplicated fingerprints will be discarded.
2024-01-20 06:20:04 +00:00
///
/// # Errors
/// The function may return an error if it is unable to read the directory or if Sequoia is
/// unable to load certificates from the file.
2024-01-20 06:20:04 +00:00
pub fn discover_certs(path: impl AsRef<Path>) -> Result<Vec<Cert>> {
let path = path.as_ref();
let mut pubkeys = std::collections::HashSet::new();
let mut certs = HashMap::new();
2024-01-20 06:20:04 +00:00
if path.is_file() {
for maybe_cert in CertParser::from_file(path).map_err(Error::Sequoia)? {
let cert = maybe_cert.map_err(Error::Sequoia)?;
let certfp = cert.fingerprint();
for key in cert.keys() {
let fp = key.fingerprint();
if pubkeys.contains(&fp) {
eprintln!("Received duplicate key: {fp} in public key: {certfp}");
}
pubkeys.insert(fp);
}
certs.insert(certfp, cert);
2024-01-20 06:20:04 +00:00
}
} else {
for entry in path
.read_dir()
.map_err(Error::Io)?
.filter_map(Result::ok)
.filter(|p| p.path().is_file())
{
let cert = Cert::from_file(entry.path()).map_err(Error::Sequoia)?;
let certfp = cert.fingerprint();
for key in cert.keys() {
let fp = key.fingerprint();
if pubkeys.contains(&fp) {
eprintln!("Received duplicate key: {fp} in public key: {certfp}");
}
pubkeys.insert(fp);
}
certs.insert(certfp, cert);
2024-01-20 06:20:04 +00:00
}
}
Ok(certs.into_values().collect())
2024-01-20 06:20:04 +00:00
}
}
const METADATA_MESSAGE_MISSING: &str = "Metadata message was not found in parsed packets";
impl<P: PromptHandler> Format for OpenPGP<P> {
2024-01-20 06:20:04 +00:00
type Error = Error;
type PublicKey = Cert;
2024-01-20 06:20:04 +00:00
type PrivateKeyData = Vec<Cert>;
type SigningKey = Cert;
2024-02-15 08:01:23 +00:00
type EncryptedData = EncryptedMessage;
2024-01-20 06:20:04 +00:00
/// Derive an OpenPGP Shard certificate from the given seed.
fn derive_signing_key(&self, seed: &[u8]) -> Self::SigningKey {
let seed = VariableLengthSeed::new(seed);
// build cert to sign encrypted shares
let userid = UserID::from("keyfork-sss");
let path = DerivationPath::from_str("m/7366512'/0'").expect(bug!("valid derivation path"));
let xprv = XPrv::new(seed)
.expect(bug!("could not create XPrv from key"))
.derive_path(&path)
.expect(bug!("valid derivation"));
keyfork_derive_openpgp::derive(
xprv,
&[KeyFlags::empty().set_certification().set_signing()],
&userid,
)
.expect(bug!("valid cert creation"))
}
fn format_encrypted_header(
&self,
signing_key: &Self::SigningKey,
2024-02-15 08:01:23 +00:00
key_data: &[Self::PublicKey],
threshold: u8,
2024-02-15 08:01:23 +00:00
) -> Result<Self::EncryptedData, Self::Error> {
let policy = NullPolicy::new();
let mut pp = vec![SHARD_METADATA_VERSION, threshold];
// Note: Sequoia does not export private keys on a Cert, only on a TSK
signing_key
.serialize(&mut pp)
.expect(bug!("serialize cert into bytes"));
for cert in key_data {
cert.serialize(&mut pp)
.expect(bug!("serialize pubkey into bytes"));
}
// verify packet pile
let mut iter = openpgp::cert::CertParser::from_bytes(&pp[SHARD_METADATA_OFFSET..])
.expect(bug!("should have certs"));
let first_cert = iter
.next()
.transpose()
.ok()
.flatten()
.expect(bug!("first cert"));
assert_eq!(signing_key, &first_cert);
for (packet_cert, cert) in iter.zip(key_data) {
assert_eq!(
&packet_cert.expect(bug!("parsed packet cert")),
cert,
"packet pile could not recreate cert: {}",
cert.fingerprint(),
);
}
let valid_certs = key_data
.iter()
.map(|c| c.with_policy(&policy, None))
.collect::<openpgp::Result<Vec<_>>>()
.map_err(Error::Sequoia)?;
let recipients = valid_certs.iter().flat_map(|vc| {
get_encryption_keys(vc).map(|key| Recipient::new(KeyID::wildcard(), key.key()))
});
// Process is as follows:
// * Any OpenPGP message
// * An encrypted message
// * A literal message
// * The packet pile
//
// When decrypting, OpenPGP will see:
// * A message, and parse it
// * An encrypted message, and decrypt it
// * A literal message, and extract it
// * The packet pile
let mut output = vec![];
let message = Message::new(&mut output);
let encrypted_message = Encryptor2::for_recipients(message, recipients)
.build()
.map_err(Error::Sequoia)?;
let mut literal_message = LiteralWriter::new(encrypted_message)
.build()
.map_err(Error::Sequoia)?;
literal_message.write_all(&pp).map_err(Error::SequoiaIo)?;
literal_message.finalize().map_err(Error::Sequoia)?;
2024-02-15 08:01:23 +00:00
// Parse it into an EncryptedMessage. Yes, this takes a serialized message
// and deserializes it. Don't think about it too hard. It's easier this way.
let mut pkesks = vec![];
for packet in PacketPile::from_reader(output.as_slice())
.map_err(Error::Sequoia)?
.into_children()
{
match packet {
Packet::PKESK(p) => pkesks.push(p),
Packet::SEIP(s) => return Ok(EncryptedMessage::new(&mut pkesks, s)),
s => panic!("Invalid variant found: {}", s.tag()),
}
}
panic!("Unable to build EncryptedMessage from PacketPile");
}
fn encrypt_shard(
&self,
shard: &[u8],
public_key: &Cert,
signing_key: &mut Self::SigningKey,
2024-02-15 08:01:23 +00:00
) -> Result<EncryptedMessage> {
let policy = NullPolicy::new();
let valid_cert = public_key
.with_policy(&policy, None)
.map_err(Error::Sequoia)?;
let encryption_keys = get_encryption_keys(&valid_cert).collect::<Vec<_>>();
let signing_key = signing_key
.primary_key()
.parts_into_secret()
.map_err(Error::Sequoia)?
.key()
.clone()
.into_keypair()
.map_err(Error::Sequoia)?;
// Process is as follows:
// * Any OpenPGP message
// * An encrypted message
// * A signed message
// * A literal message
// * The shard itself
//
// When decrypting, OpenPGP will see:
// * A message, and parse it
// * An encrypted message, and decrypt it
// * A signed message, and verify it
// * A literal message, and extract it
// * The shard itself
let mut message_output = vec![];
let message = Message::new(&mut message_output);
let encrypted_message = Encryptor2::for_recipients(
message,
encryption_keys
.iter()
.map(|k| Recipient::new(KeyID::wildcard(), k.key())),
)
.build()
.map_err(Error::Sequoia)?;
let signed_message = Signer::new(encrypted_message, signing_key)
.build()
.map_err(Error::Sequoia)?;
let mut message = LiteralWriter::new(signed_message)
.build()
.map_err(Error::Sequoia)?;
message.write_all(shard).map_err(Error::SequoiaIo)?;
message.finalize().map_err(Error::Sequoia)?;
2024-02-15 08:01:23 +00:00
let message = EncryptedMessage::from_reader(message_output.as_slice())
.map_err(Error::Sequoia)?
.into_iter()
.next()
.expect(bug!("serialized message should be parseable"));
2024-02-15 08:01:23 +00:00
Ok(message)
}
2024-01-20 06:20:04 +00:00
fn parse_shard_file(
&self,
shard_file: impl Read + Send + Sync,
2024-02-15 08:01:23 +00:00
) -> Result<Vec<Self::EncryptedData>, Self::Error> {
EncryptedMessage::from_reader(shard_file).map_err(Error::Sequoia)
2024-01-20 06:20:04 +00:00
}
fn format_shard_file(
&self,
2024-02-15 08:01:23 +00:00
encrypted_data: &[Self::EncryptedData],
shard_file: impl Write + Send + Sync,
2024-01-20 06:20:04 +00:00
) -> Result<(), Self::Error> {
let mut writer = Writer::new(shard_file, Kind::Message).map_err(Error::SequoiaIo)?;
2024-02-15 08:01:23 +00:00
for message in encrypted_data {
2024-01-20 06:20:04 +00:00
message.serialize(&mut writer).map_err(Error::Sequoia)?;
}
writer.finalize().map_err(Error::SequoiaIo)?;
Ok(())
}
fn decrypt_all_shards(
&self,
private_keys: Option<Self::PrivateKeyData>,
2024-02-15 08:01:23 +00:00
encrypted_data: &[Self::EncryptedData],
prompt: Arc<Mutex<impl PromptHandler>>,
2024-01-20 06:20:04 +00:00
) -> std::result::Result<(Vec<Share>, u8), Self::Error> {
// Be as liberal as possible when decrypting.
// We don't want to invalidate someone's keys just because the old sig expired.
let policy = NullPolicy::new();
let mut keyring = Keyring::new(private_keys.unwrap_or_default(), prompt.clone())?;
let mut manager = SmartcardManager::new(prompt.clone())?;
2024-01-20 06:20:04 +00:00
2024-02-15 08:01:23 +00:00
let mut encrypted_messages = encrypted_data.iter();
let metadata = encrypted_messages
.next()
.expect(bug!(METADATA_MESSAGE_MISSING));
2024-02-15 08:01:23 +00:00
let metadata_content = decrypt_metadata(metadata, &policy, &mut keyring, &mut manager)?;
2024-01-20 06:20:04 +00:00
let (threshold, root_cert, certs) = decode_metadata_v1(&metadata_content)?;
keyring.set_root_cert(root_cert.clone());
manager.set_root_cert(root_cert.clone());
// Generate a controlled binding from certificates to encrypted messages. This is stable
// because we control the order packets are encrypted and certificates are stored.
// TODO: remove alloc, convert EncryptedMessage to &EncryptedMessage
2024-02-15 08:01:23 +00:00
let mut messages: HashMap<KeyID, EncryptedMessage> = certs
.iter()
.map(Cert::keyid)
.zip(encrypted_messages.cloned())
.collect();
2024-01-20 06:20:04 +00:00
let mut decrypted_messages =
decrypt_with_keyring(&mut messages, &certs, &policy, &mut keyring)?;
// clean decrypted messages from encrypted messages
messages.retain(|k, _v| !decrypted_messages.contains_key(k));
let left_from_threshold = threshold as usize - decrypted_messages.len();
if left_from_threshold > 0 {
#[allow(clippy::cast_possible_truncation)]
let new_messages = decrypt_with_manager(
left_from_threshold as u8,
&mut messages,
&certs,
&policy,
&mut manager,
)?;
decrypted_messages.extend(new_messages);
}
let shares = decrypted_messages
.values()
.map(|message| Share::try_from(message.as_slice()))
.collect::<Result<Vec<_>, &str>>()
.map_err(|e| SharksError::Share(e.to_string()))?;
Ok((shares, threshold))
}
fn decrypt_one_shard(
&self,
private_keys: Option<Self::PrivateKeyData>,
2024-02-15 08:01:23 +00:00
encrypted_data: &[Self::EncryptedData],
prompt: Arc<Mutex<impl PromptHandler>>,
2024-01-20 06:20:04 +00:00
) -> std::result::Result<(Share, u8), Self::Error> {
let policy = NullPolicy::new();
let mut keyring = Keyring::new(private_keys.unwrap_or_default(), prompt.clone())?;
let mut manager = SmartcardManager::new(prompt.clone())?;
2024-01-20 06:20:04 +00:00
2024-02-15 08:01:23 +00:00
let mut encrypted_messages = encrypted_data.iter();
let metadata = encrypted_messages
.next()
.expect(bug!(METADATA_MESSAGE_MISSING));
2024-02-15 08:01:23 +00:00
let metadata_content = decrypt_metadata(metadata, &policy, &mut keyring, &mut manager)?;
2024-01-20 06:20:04 +00:00
let (threshold, root_cert, certs) = decode_metadata_v1(&metadata_content)?;
keyring.set_root_cert(root_cert.clone());
manager.set_root_cert(root_cert.clone());
2024-02-15 08:01:23 +00:00
let mut messages: HashMap<KeyID, EncryptedMessage> = certs
.iter()
.map(Cert::keyid)
.zip(encrypted_messages.cloned())
.collect();
2024-01-20 06:20:04 +00:00
let decrypted_messages =
decrypt_with_keyring(&mut messages, &certs, &policy, &mut keyring)?;
if let Some(message) = decrypted_messages.into_values().next() {
let share = Share::try_from(message.as_slice())
.map_err(|e| SharksError::Share(e.to_string()))?;
2024-01-20 06:20:04 +00:00
return Ok((share, threshold));
}
let decrypted_messages =
decrypt_with_manager(1, &mut messages, &certs, &policy, &mut manager)?;
if let Some(message) = decrypted_messages.into_values().next() {
let share = Share::try_from(message.as_slice())
.map_err(|e| SharksError::Share(e.to_string()))?;
2024-01-20 06:20:04 +00:00
return Ok((share, threshold));
}
panic!("unable to decrypt shard");
}
}
impl<P: PromptHandler> KeyDiscovery<OpenPGP<P>> for &Path {
fn discover_public_keys(&self) -> Result<Vec<<OpenPGP<P> as Format>::PublicKey>> {
OpenPGP::<P>::discover_certs(self)
}
fn discover_private_keys(&self) -> Result<<OpenPGP<P> as Format>::PrivateKeyData> {
OpenPGP::<P>::discover_certs(self)
}
}
impl<P: PromptHandler> KeyDiscovery<OpenPGP<P>> for &[Cert] {
fn discover_public_keys(&self) -> Result<Vec<<OpenPGP<P> as Format>::PublicKey>> {
Ok(self.to_vec())
}
fn discover_private_keys(&self) -> Result<<OpenPGP<P> as Format>::PrivateKeyData> {
Ok(self.to_vec())
}
}
fn get_encryption_keys<'a>(
cert: &'a ValidCert,
) -> openpgp::cert::prelude::ValidKeyAmalgamationIter<
'a,
openpgp::packet::key::PublicParts,
openpgp::packet::key::UnspecifiedRole,
> {
cert.keys()
// NOTE: this causes complications on Airgap systems
// .alive()
.revoked(false)
.supported()
.for_storage_encryption()
}
fn get_decryption_keys<'a>(
cert: &'a ValidCert,
) -> openpgp::cert::prelude::ValidKeyAmalgamationIter<
'a,
openpgp::packet::key::SecretParts,
openpgp::packet::key::UnspecifiedRole,
> {
cert.keys()
/*
.alive()
.revoked(false)
.supported()
*/
.for_storage_encryption()
.secret()
}
fn decode_metadata_v1(buf: &[u8]) -> Result<(u8, Cert, Vec<Cert>)> {
assert_eq!(
SHARD_METADATA_VERSION, buf[0],
"Incompatible metadata version"
);
let threshold = buf[1];
let mut cert_parser =
CertParser::from_bytes(&buf[SHARD_METADATA_OFFSET..]).map_err(Error::Sequoia)?;
let root_cert = match cert_parser.next() {
Some(Ok(c)) => c,
Some(Err(e)) => return Err(Error::Sequoia(e)),
None => panic!("No data found"),
};
let certs = cert_parser
.collect::<openpgp::Result<Vec<_>>>()
.map_err(Error::Sequoia)?;
Ok((threshold, root_cert, certs))
}
// NOTE: When using single-decryptor mechanism, use this method with `threshold = 1` to return a
// single message.
fn decrypt_with_manager<P: PromptHandler>(
threshold: u8,
messages: &mut HashMap<KeyID, EncryptedMessage>,
certs: &[Cert],
2024-01-07 04:23:03 +00:00
policy: &dyn Policy,
manager: &mut SmartcardManager<P>,
) -> Result<HashMap<KeyID, Vec<u8>>> {
let mut decrypted_messages = HashMap::new();
while threshold as usize - decrypted_messages.len() > 0 {
// Build list of fingerprints that haven't yet been used for decrypting
let mut cert_by_fingerprint = HashMap::new();
let mut unused_fingerprints = vec![];
for valid_cert in certs
.iter()
.filter(|cert| !decrypted_messages.contains_key(&cert.keyid()))
2024-01-07 04:23:03 +00:00
.map(|cert| cert.with_policy(policy, None))
{
let valid_cert = valid_cert.map_err(Error::Sequoia)?;
let fp = valid_cert
.keys()
.for_storage_encryption()
.map(|k| k.fingerprint())
.collect::<Vec<_>>();
for fp in &fp {
cert_by_fingerprint.insert(fp.clone(), valid_cert.keyid());
}
unused_fingerprints.extend(fp.into_iter());
}
// Iterate over all fingerprints and use key_by_fingerprints to assoc with Enc. Message
if let Some(fp) = manager.load_any_fingerprint(unused_fingerprints)? {
let cert_keyid = cert_by_fingerprint
.get(&fp)
.expect(bug!(
"manager loaded fingerprint not from unused_fingerprints"
))
.clone();
if let Some(message) = messages.remove(&cert_keyid) {
2024-01-07 04:23:03 +00:00
let message = message.decrypt_with(policy, &mut *manager)?;
decrypted_messages.insert(cert_keyid, message);
}
}
}
Ok(decrypted_messages)
}
// NOTE: When using single-decryptor mechanism, only a single key should be provided in Keyring to
// decrypt messages with.
fn decrypt_with_keyring<P: PromptHandler>(
messages: &mut HashMap<KeyID, EncryptedMessage>,
certs: &[Cert],
policy: &NullPolicy,
keyring: &mut Keyring<P>,
) -> Result<HashMap<KeyID, Vec<u8>>, Error> {
let mut decrypted_messages = HashMap::new();
for valid_cert in certs.iter().map(|cert| cert.with_policy(policy, None)) {
let valid_cert = valid_cert.map_err(Error::Sequoia)?;
let Some(secret_cert) = keyring.get_cert_for_primary_keyid(&valid_cert.keyid()) else {
continue;
};
let secret_cert = secret_cert
.with_policy(policy, None)
.map_err(Error::Sequoia)?;
let keys = get_decryption_keys(&secret_cert).collect::<Vec<_>>();
if !keys.is_empty() {
if let Some(message) = messages.get_mut(&valid_cert.keyid()) {
for (pkesk, key) in message.pkesks.iter_mut().zip(keys) {
pkesk.set_recipient(key.keyid());
}
// we have a pkesk, decrypt via keyring
2023-11-05 22:26:19 +00:00
decrypted_messages.insert(
valid_cert.keyid(),
message.decrypt_with(policy, &mut *keyring)?,
2023-11-05 22:26:19 +00:00
);
}
}
}
Ok(decrypted_messages)
}
fn decrypt_metadata<P: PromptHandler>(
message: &EncryptedMessage,
policy: &NullPolicy,
keyring: &mut Keyring<P>,
manager: &mut SmartcardManager<P>,
) -> Result<Vec<u8>> {
Ok(if keyring.is_empty() {
manager.load_any_card()?;
message.decrypt_with(policy, manager)?
} else {
message.decrypt_with(policy, keyring)?
})
}