use super::openpgp::{ self, cert::Cert, packet::{PKESK, SKESK}, parse::stream::{DecryptionHelper, MessageLayer, MessageStructure, VerificationHelper}, KeyHandle, KeyID, }; #[derive(Clone, Debug)] pub enum KeyringFailure { SecretKeyNotFound, #[allow(dead_code)] SmartcardDecrypt, } impl std::fmt::Display for KeyringFailure { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { KeyringFailure::SecretKeyNotFound => f.write_str("Secret key was not found"), KeyringFailure::SmartcardDecrypt => { f.write_str("Smartcard could not decrypt any PKESKs") } } } } impl std::error::Error for KeyringFailure {} #[derive(Clone, Debug)] pub struct Keyring { full_certs: Vec<Cert>, root: Option<Cert>, } impl Keyring { pub fn new(certs: impl AsRef<[Cert]>) -> Self { Self { full_certs: certs.as_ref().to_vec(), root: Default::default(), } } pub fn is_empty(&self) -> bool { self.full_certs.is_empty() } // Sets the root cert, returning the old cert pub fn set_root_cert(&mut self, cert: impl Into<Option<Cert>>) -> Option<Cert> { let mut cert = cert.into(); std::mem::swap(&mut self.root, &mut cert); cert } pub fn root_cert(&self) -> Option<&Cert> { self.root.as_ref() } pub fn get_cert_for_primary_keyid<'a>(&'a self, keyid: &KeyID) -> Option<&'a Cert> { self.full_certs.iter().find(|cert| &cert.keyid() == keyid) } // NOTE: This can't return an iterator because iterators are all different types // and returning different types is naughty fn get_certs_for_pkesk<'a>(&'a self, pkesk: &'a PKESK) -> impl Iterator<Item = &Cert> + 'a { self.full_certs.iter().filter(move |cert| { pkesk.recipient().is_wildcard() || cert.keys().any(|k| &k.keyid() == pkesk.recipient()) }) } } impl VerificationHelper for &mut Keyring { fn get_certs(&mut self, ids: &[KeyHandle]) -> openpgp::Result<Vec<Cert>> { Ok(ids .iter() .flat_map(|kh| { self.root .iter() .filter(move |cert| &cert.key_handle() == kh) }) .cloned() .collect()) } fn check(&mut self, structure: MessageStructure) -> openpgp::Result<()> { for layer in structure.into_iter() { #[allow(unused_variables)] match layer { MessageLayer::Compression { algo } => {} MessageLayer::Encryption { sym_algo, aead_algo, } => {} MessageLayer::SignatureGroup { results } => { for result in results { if let Err(e) = result { // FIXME: anyhow leak return Err(anyhow::anyhow!(e.to_string())); } } } } } Ok(()) } } impl DecryptionHelper for &mut Keyring { fn decrypt<D>( &mut self, pkesks: &[PKESK], _skesks: &[SKESK], sym_algo: Option<openpgp::types::SymmetricAlgorithm>, mut decrypt: D, ) -> openpgp::Result<Option<openpgp::Fingerprint>> where D: FnMut(openpgp::types::SymmetricAlgorithm, &openpgp::crypto::SessionKey) -> bool, { // unoptimized route: use all locally stored certs for pkesk in pkesks { for cert in self.get_certs_for_pkesk(pkesk) { for key in cert.keys().secret() { let secret_key = key.key().clone(); // NOTE: Returns an error if using an encrypted secret key. // TODO: support skipping or validating encrypted secret keys. let mut keypair = secret_key.into_keypair()?; if pkesk .decrypt(&mut keypair, sym_algo) .map(|(algo, sk)| decrypt(algo, &sk)) .unwrap_or(false) { return Ok(Some(key.fingerprint())); } } } } Err(KeyringFailure::SecretKeyNotFound.into()) } }