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

139 lines
4.3 KiB
Rust

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())
}
}