119 lines
3.6 KiB
Rust
119 lines
3.6 KiB
Rust
use crate::openpgp::{
|
|
self,
|
|
cert::Cert,
|
|
packet::{PKESK, SKESK},
|
|
parse::stream::{DecryptionHelper, VerificationHelper, MessageStructure},
|
|
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(),
|
|
}
|
|
}
|
|
|
|
// 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 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>> {
|
|
// TODO: no verification logic until we mark a cert as "root"
|
|
// this is the first cert in the metadata list
|
|
Ok(Vec::new())
|
|
}
|
|
fn check(&mut self, _structure: MessageStructure) -> openpgp::Result<()> {
|
|
// TODO: ensure that we have a "root" cert and assign it
|
|
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,
|
|
{
|
|
// optimized 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()));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// smartcard route: plug in smartcard, attempt decrypt, fail and bail
|
|
|
|
Err(KeyringFailure::SecretKeyNotFound.into())
|
|
}
|
|
}
|