use std::{
cmp::Ordering,
mem,
sync::{Arc, Mutex},
};
use crate::{
Error,
Result,
packet::{
Key,
Signature,
key,
signature::subpacket::{SubpacketTag, SubpacketValue},
},
};
#[derive(Debug)]
pub struct LazySignatures {
primary_key: Arc<Key<key::PublicParts, key::PrimaryRole>>,
sigs: Vec<Signature>,
states: Mutex<Vec<SigState>>,
}
impl PartialEq for LazySignatures {
fn eq(&self, other: &Self) -> bool {
self.assert_invariant();
other.assert_invariant();
self.primary_key == other.primary_key
&& self.sigs == other.sigs
}
}
impl Clone for LazySignatures {
fn clone(&self) -> Self {
self.assert_invariant();
LazySignatures {
primary_key: self.primary_key.clone(),
sigs: self.sigs.clone(),
states: if let Ok(states) = self.states.try_lock() {
states.clone()
} else {
vec![SigState::Unverified; self.sigs.len()]
}.into(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum SigState {
Unverified,
Good,
Bad,
}
impl LazySignatures {
fn assert_invariant(&self) {
debug_assert_eq!(self.sigs.len(), self.states.lock().unwrap().len());
}
pub fn new(primary_key: Arc<Key<key::PublicParts, key::PrimaryRole>>)
-> Self
{
LazySignatures {
primary_key,
sigs: Default::default(),
states: Default::default(),
}
}
pub fn is_empty(&self) -> bool {
self.assert_invariant();
self.sigs.is_empty()
}
pub fn take(&mut self) -> Vec<Signature> {
self.assert_invariant();
self.states.lock().unwrap().clear();
let r = mem::replace(&mut self.sigs, Vec::new());
self.assert_invariant();
r
}
pub fn push(&mut self, s: Signature) {
self.assert_invariant();
self.sigs.push(s);
self.states.lock().unwrap().push(SigState::Unverified);
self.assert_invariant();
}
pub fn append(&mut self, other: &mut LazySignatures) {
self.assert_invariant();
other.assert_invariant();
self.sigs.append(&mut other.sigs);
self.states.lock().unwrap().append(&mut other.states.lock().unwrap());
self.assert_invariant();
}
pub fn sort_by<F>(&mut self, compare: F)
where
F: FnMut(&Signature, &Signature) -> Ordering,
{
self.assert_invariant();
self.sigs.sort_by(compare);
self.states.lock().unwrap().iter_mut().for_each(|p| *p = SigState::Unverified);
self.assert_invariant();
}
pub fn dedup_by<F>(&mut self, same_bucket: F)
where
F: FnMut(&mut Signature, &mut Signature) -> bool,
{
self.assert_invariant();
self.sigs.dedup_by(same_bucket);
{
let mut states = self.states.lock().unwrap();
states.truncate(self.sigs.len());
states.iter_mut().for_each(|p| *p = SigState::Unverified);
}
self.assert_invariant();
}
pub fn iter_mut_unverified(&mut self) -> impl Iterator<Item = &mut Signature> {
self.assert_invariant();
self.sigs.iter_mut()
}
pub fn into_unverified(self) -> impl Iterator<Item = Signature> {
self.assert_invariant();
self.sigs.into_iter()
}
pub fn as_slice_unverified(&self) -> &[Signature] {
self.sigs.as_slice()
}
pub fn iter_verified<'a>(&'a self,
subkey: Option<&'a Key<key::PublicParts, key::SubordinateRole>>)
-> impl Iterator<Item = &'a Signature> + 'a
{
self.iter_intern(subkey)
.filter_map(|(state, s)| match state {
SigState::Good => Some(s),
SigState::Bad => None,
SigState::Unverified => unreachable!(),
})
}
pub fn iter_bad<'a>(&'a self,
subkey: Option<&'a Key<key::PublicParts, key::SubordinateRole>>)
-> impl Iterator<Item = &'a Signature> + 'a
{
self.iter_intern(subkey)
.filter_map(|(state, s)| match state {
SigState::Good => None,
SigState::Bad => Some(s),
SigState::Unverified => unreachable!(),
})
}
fn iter_intern<'a>(&'a self,
subkey: Option<&'a Key<key::PublicParts, key::SubordinateRole>>)
-> impl Iterator<Item = (SigState, &'a Signature)> + 'a
{
self.assert_invariant();
self.sigs.iter().enumerate()
.map(move |(i, s)| (self.verify_sig(i, subkey).expect("in bounds"), s))
}
pub fn verify_sig(&self, i: usize,
subkey: Option<&Key<key::PublicParts, key::SubordinateRole>>)
-> Result<SigState>
{
self.assert_invariant();
if ! i < self.sigs.len() {
return Err(Error::InvalidArgument(format!(
"signature {} out of bound 0..{}", i, self.sigs.len())).into());
}
let state = self.states.lock().unwrap().get(i).cloned();
match state {
None => unreachable!("LazySignatures invariant violated"),
Some(SigState::Unverified) => {
let s = &self.sigs[i];
let mut r = s.verify_signature(&self.primary_key);
if r.is_ok() && subkey.is_some() &&
s.key_flags().map(|kf| kf.for_signing())
.unwrap_or(false)
{
let mut any_backsig = Err(Error::BadSignature(
"Primary key binding signature missing".into()).into());
for backsig in s.subpackets(SubpacketTag::EmbeddedSignature)
{
let result =
if let SubpacketValue::EmbeddedSignature(sig) =
backsig.value()
{
sig.verify_primary_key_binding(
&self.primary_key, subkey.unwrap())
} else {
unreachable!("subpackets(EmbeddedSignature) \
returns EmbeddedSignatures");
};
if result.is_ok() {
backsig.set_authenticated(true);
}
if any_backsig.is_err() {
any_backsig = result;
}
}
r = any_backsig;
}
let state = if r.is_ok() {
SigState::Good
} else {
SigState::Bad
};
self.states.lock().unwrap()[i] = state.clone();
Ok(state)
},
Some(state) => Ok(state),
}
}
}