use std::time;
use std::ops::Deref;
use crate::{
Error,
packet::Signature,
packet::Key,
packet::key,
packet::UserID,
packet::UserAttribute,
packet::Unknown,
Packet,
policy::HashAlgoSecurity,
policy::Policy,
Result,
};
use crate::types::{
RevocationType,
RevocationStatus,
};
use super::{
sig_cmp,
canonical_signature_order,
};
#[derive(Debug, Clone, PartialEq)]
pub struct ComponentBundle<C> {
pub(crate) component: C,
pub(crate) hash_algo_security: HashAlgoSecurity,
pub(crate) self_signatures: Vec<Signature>,
pub(crate) certifications: Vec<Signature>,
pub(crate) attestations: Vec<Signature>,
pub(crate) self_revocations: Vec<Signature>,
pub(crate) other_revocations: Vec<Signature>,
}
assert_send_and_sync!(ComponentBundle<C> where C);
pub type KeyBundle<KeyPart, KeyRole> = ComponentBundle<Key<KeyPart, KeyRole>>;
pub type PrimaryKeyBundle<KeyPart> =
KeyBundle<KeyPart, key::PrimaryRole>;
pub type SubkeyBundle<KeyPart>
= KeyBundle<KeyPart, key::SubordinateRole>;
pub type UserIDBundle = ComponentBundle<UserID>;
pub type UserAttributeBundle = ComponentBundle<UserAttribute>;
pub type UnknownBundle = ComponentBundle<Unknown>;
impl<C> Deref for ComponentBundle<C>
{
type Target = C;
fn deref(&self) -> &Self::Target {
&self.component
}
}
impl<C> ComponentBundle<C> {
pub fn component(&self) -> &C {
&self.component
}
fn component_mut(&mut self) -> &mut C {
&mut self.component
}
pub fn binding_signature<T>(&self, policy: &dyn Policy, t: T)
-> Result<&Signature>
where T: Into<Option<time::SystemTime>>
{
let t = t.into().unwrap_or_else(time::SystemTime::now);
let i =
if Some(t) >= self.self_signatures.get(0)
.and_then(|s| s.signature_creation_time())
{
0
} else {
match self.self_signatures.binary_search_by(
|s| canonical_signature_order(
s.signature_creation_time(), Some(t)))
{
Ok(mut i) => {
while i > 0
&& self.self_signatures[i - 1].signature_creation_time()
== Some(t)
{
i -= 1;
}
i
}
Err(i) => i,
}
};
let mut sig = None;
let mut error = None;
'next_sig: for s in self.self_signatures[i..].iter() {
if let Err(e) = s.signature_alive(t, time::Duration::new(0, 0)) {
if error.is_none() {
error = Some(e);
}
continue;
}
if let Err(e) = policy.signature(s, self.hash_algo_security)
{
if error.is_none() {
error = Some(e);
}
continue;
}
if s.typ() == crate::types::SignatureType::SubkeyBinding &&
s.key_flags().map(|kf| kf.for_signing()).unwrap_or(false)
{
let mut n = 0;
let mut one_good_backsig = false;
'next_backsig: for backsig in s.embedded_signatures() {
n += 1;
if let Err(e) = backsig.signature_alive(
t, time::Duration::new(0, 0))
{
if error.is_none() {
error = Some(e);
}
continue 'next_backsig;
}
if let Err(e) = policy
.signature(backsig, self.hash_algo_security)
{
if error.is_none() {
error = Some(e);
}
continue 'next_backsig;
}
one_good_backsig = true;
}
if n == 0 {
if error.is_none() {
error = Some(Error::BadSignature(
"Primary key binding signature missing".into())
.into());
}
continue 'next_sig;
}
if ! one_good_backsig {
continue 'next_sig;
}
}
sig = Some(s);
break;
}
if let Some(sig) = sig {
Ok(sig)
} else if let Some(err) = error {
Err(err)
} else {
Err(Error::NoBindingSignature(t).into())
}
}
pub fn self_signatures(&self) -> &[Signature] {
&self.self_signatures
}
pub fn certifications(&self) -> &[Signature] {
&self.certifications
}
pub fn self_revocations(&self) -> &[Signature] {
&self.self_revocations
}
pub fn other_revocations(&self) -> &[Signature] {
&self.other_revocations
}
pub fn signatures(&self)
-> impl Iterator<Item = &Signature> + Send + Sync
{
self.self_revocations.iter()
.chain(self.self_signatures.iter())
.chain(self.attestations.iter())
.chain(self.certifications.iter())
.chain(self.other_revocations.iter())
}
pub(crate) fn _revocation_status<'a, T>(&'a self, policy: &dyn Policy, t: T,
hard_revocations_are_final: bool,
selfsig: Option<&Signature>)
-> RevocationStatus<'a>
where T: Into<Option<time::SystemTime>>
{
let time_zero = || time::UNIX_EPOCH;
let t = t.into().unwrap_or_else(time::SystemTime::now);
let selfsig_creation_time
= selfsig.and_then(|s| s.signature_creation_time())
.unwrap_or_else(time_zero);
tracer!(super::TRACE, "ComponentBundle::_revocation_status", 0);
t!("hard_revocations_are_final: {}, selfsig: {:?}, t: {:?}",
hard_revocations_are_final,
selfsig_creation_time,
t);
if let Some(selfsig) = selfsig {
assert!(
selfsig.signature_alive(t, time::Duration::new(0, 0)).is_ok());
}
let check = |revs: &'a [Signature], sec: HashAlgoSecurity|
-> Option<Vec<&'a Signature>>
{
let revs = revs.iter().filter_map(|rev| {
if let Err(err) = policy.signature(rev, sec) {
t!(" revocation rejected by caller policy: {}", err);
None
} else if hard_revocations_are_final
&& rev.reason_for_revocation()
.map(|(r, _)| {
r.revocation_type() == RevocationType::Hard
})
.unwrap_or(true)
{
t!(" got a hard revocation: {:?}, {:?}",
rev.signature_creation_time()
.unwrap_or_else(time_zero),
rev.reason_for_revocation()
.map(|r| (r.0, String::from_utf8_lossy(r.1))));
Some(rev)
} else if selfsig_creation_time
> rev.signature_creation_time().unwrap_or_else(time_zero)
{
t!(" newer binding signature trumps soft revocation ({:?} > {:?})",
selfsig_creation_time,
rev.signature_creation_time().unwrap_or_else(time_zero));
None
} else if let Err(err)
= rev.signature_alive(t, time::Duration::new(0, 0))
{
t!(" revocation not alive ({:?} - {:?}): {}",
rev.signature_creation_time().unwrap_or_else(time_zero),
rev.signature_validity_period()
.unwrap_or_else(|| time::Duration::new(0, 0)),
err);
None
} else {
t!(" got a revocation: {:?} ({:?})",
rev.signature_creation_time().unwrap_or_else(time_zero),
rev.reason_for_revocation()
.map(|r| (r.0, String::from_utf8_lossy(r.1))));
Some(rev)
}
}).collect::<Vec<&Signature>>();
if revs.len() == 0 {
None
} else {
Some(revs)
}
};
if let Some(revs)
= check(&self.self_revocations, self.hash_algo_security)
{
RevocationStatus::Revoked(revs)
} else if let Some(revs)
= check(&self.other_revocations, Default::default())
{
RevocationStatus::CouldBe(revs)
} else {
RevocationStatus::NotAsFarAsWeKnow
}
}
pub(crate) fn into_packets<'a>(self)
-> impl Iterator<Item=Packet> + Send + Sync
where Packet: From<C>
{
let p : Packet = self.component.into();
std::iter::once(p)
.chain(self.self_revocations.into_iter().map(|s| s.into()))
.chain(self.self_signatures.into_iter().map(|s| s.into()))
.chain(self.attestations.into_iter().map(|s| s.into()))
.chain(self.certifications.into_iter().map(|s| s.into()))
.chain(self.other_revocations.into_iter().map(|s| s.into()))
}
pub(crate) fn sort_and_dedup(&mut self)
{
fn sig_merge(a: &mut Signature, b: &mut Signature) -> bool {
if a.normalized_eq(b) {
b.merge_internal(a)
.expect("checked for equality above");
true
} else {
false
}
}
fn sig_fixup(sig: &mut Signature) {
let _ = sig.add_missing_issuers();
sig.unhashed_area_mut().sort();
}
self.self_signatures.sort_by(Signature::normalized_cmp);
self.self_signatures.dedup_by(sig_merge);
self.self_signatures.sort_by(sig_cmp);
self.self_signatures.iter_mut().for_each(sig_fixup);
self.attestations.sort_by(Signature::normalized_cmp);
self.attestations.dedup_by(sig_merge);
self.attestations.sort_by(sig_cmp);
self.attestations.iter_mut().for_each(sig_fixup);
self.certifications.sort_by(Signature::normalized_cmp);
self.certifications.dedup_by(sig_merge);
self.certifications.sort_by(sig_cmp);
self.certifications.iter_mut().for_each(sig_fixup);
self.self_revocations.sort_by(Signature::normalized_cmp);
self.self_revocations.dedup_by(sig_merge);
self.self_revocations.sort_by(sig_cmp);
self.self_revocations.iter_mut().for_each(sig_fixup);
self.other_revocations.sort_by(Signature::normalized_cmp);
self.other_revocations.dedup_by(sig_merge);
self.other_revocations.sort_by(sig_cmp);
self.other_revocations.iter_mut().for_each(sig_fixup);
}
}
impl<P: key::KeyParts, R: key::KeyRole> ComponentBundle<Key<P, R>> {
pub fn key(&self) -> &Key<P, R> {
self.component()
}
pub(crate) fn key_mut(&mut self) -> &mut Key<P, R> {
self.component_mut()
}
}
impl<P: key::KeyParts> ComponentBundle<Key<P, key::SubordinateRole>> {
pub fn revocation_status<T>(&self, policy: &dyn Policy, t: T)
-> RevocationStatus
where T: Into<Option<time::SystemTime>>
{
let t = t.into();
self._revocation_status(policy, t, true,
self.binding_signature(policy, t).ok())
}
}
impl ComponentBundle<UserID> {
pub fn userid(&self) -> &UserID {
self.component()
}
pub fn revocation_status<T>(&self, policy: &dyn Policy, t: T)
-> RevocationStatus
where T: Into<Option<time::SystemTime>>
{
let t = t.into();
self._revocation_status(policy, t, false, self.binding_signature(policy, t).ok())
}
}
impl ComponentBundle<UserAttribute> {
pub fn user_attribute(&self) -> &UserAttribute {
self.component()
}
pub fn revocation_status<T>(&self, policy: &dyn Policy, t: T)
-> RevocationStatus
where T: Into<Option<time::SystemTime>>
{
let t = t.into();
self._revocation_status(policy, t, false,
self.binding_signature(policy, t).ok())
}
}
impl ComponentBundle<Unknown> {
pub fn unknown(&self) -> &Unknown {
self.component()
}
}