use std::time;
use std::time::SystemTime;
use std::clone::Clone;
use crate::{
cert::prelude::*,
Error,
packet::{
Signature,
Unknown,
UserAttribute,
UserID,
},
Result,
policy::{
HashAlgoSecurity,
Policy,
},
seal,
types::{
AEADAlgorithm,
CompressionAlgorithm,
Features,
HashAlgorithm,
KeyServerPreferences,
RevocationStatus,
SymmetricAlgorithm,
},
};
mod iter;
pub use iter::{
ComponentAmalgamationIter,
UnknownComponentAmalgamationIter,
UserAttributeAmalgamationIter,
UserIDAmalgamationIter,
ValidComponentAmalgamationIter,
ValidUserAttributeAmalgamationIter,
ValidUserIDAmalgamationIter,
};
pub mod key;
pub trait ValidateAmalgamation<'a, C: 'a>: seal::Sealed {
type V;
fn with_policy<T>(self, policy: &'a dyn Policy, time: T) -> Result<Self::V>
where T: Into<Option<time::SystemTime>>,
Self: Sized;
}
trait ValidateAmalgamationRelaxed<'a, C: 'a> {
type V;
fn with_policy_relaxed<T>(self, policy: &'a dyn Policy, time: T,
valid_cert: bool) -> Result<Self::V>
where T: Into<Option<time::SystemTime>>,
Self: Sized;
}
pub trait ValidAmalgamation<'a, C: 'a>: seal::Sealed
{
fn map<F: Fn(&'a Signature) -> Option<T>, T>(&self, f: F) -> Option<T> {
f(self.binding_signature())
.or_else(|| self.direct_key_signature().ok().and_then(f))
}
fn cert(&self) -> &ValidCert<'a>;
fn time(&self) -> SystemTime;
fn policy(&self) -> &'a dyn Policy;
fn binding_signature(&self) -> &'a Signature;
fn direct_key_signature(&self) -> Result<&'a Signature> {
self.cert().cert.primary.binding_signature(self.policy(), self.time())
}
fn revocation_status(&self) -> RevocationStatus<'a>;
}
#[derive(Debug, PartialEq)]
pub struct ComponentAmalgamation<'a, C> {
cert: &'a Cert,
bundle: &'a ComponentBundle<C>,
}
assert_send_and_sync!(ComponentAmalgamation<'_, C> where C);
pub type UserIDAmalgamation<'a> = ComponentAmalgamation<'a, UserID>;
pub type UserAttributeAmalgamation<'a>
= ComponentAmalgamation<'a, UserAttribute>;
pub type UnknownComponentAmalgamation<'a>
= ComponentAmalgamation<'a, Unknown>;
impl<'a, C> Clone for ComponentAmalgamation<'a, C> {
fn clone(&self) -> Self {
Self {
cert: self.cert,
bundle: self.bundle,
}
}
}
impl<'a, C> std::ops::Deref for ComponentAmalgamation<'a, C> {
type Target = ComponentBundle<C>;
fn deref(&self) -> &Self::Target {
self.bundle
}
}
impl<'a, C> ComponentAmalgamation<'a, C> {
pub(crate) fn new(cert: &'a Cert, bundle: &'a ComponentBundle<C>) -> Self
{
Self {
cert,
bundle,
}
}
pub fn cert(&self) -> &'a Cert {
&self.cert
}
fn binding_signature<T>(&self, policy: &dyn Policy, time: T)
-> Result<&'a Signature>
where T: Into<Option<time::SystemTime>>
{
let time = time.into().unwrap_or_else(SystemTime::now);
self.bundle.binding_signature(policy, time)
}
pub fn bundle(&self) -> &'a ComponentBundle<C> {
&self.bundle
}
pub fn component(&self) -> &'a C {
self.bundle().component()
}
pub fn self_signatures(&self) -> impl Iterator<Item=&'a Signature> + Send + Sync {
self.bundle().self_signatures().iter()
}
pub fn certifications(&self) -> impl Iterator<Item=&'a Signature> + Send + Sync {
self.bundle().certifications().iter()
}
pub fn self_revocations(&self) -> impl Iterator<Item=&'a Signature> + Send + Sync {
self.bundle().self_revocations().iter()
}
pub fn other_revocations(&self) -> impl Iterator<Item=&'a Signature> + Send + Sync {
self.bundle().other_revocations().iter()
}
}
macro_rules! impl_with_policy {
($func:ident, $value:ident $(, $arg:ident: $type:ty )*) => {
fn $func<T>(self, policy: &'a dyn Policy, time: T, $($arg: $type, )*)
-> Result<Self::V>
where T: Into<Option<time::SystemTime>>,
Self: Sized
{
let time = time.into().unwrap_or_else(SystemTime::now);
if $value {
self.cert.with_policy(policy, time)?;
}
let binding_signature = self.binding_signature(policy, time)?;
let cert = self.cert;
Ok(ValidComponentAmalgamation {
ca: self,
cert: ValidCert {
cert: cert,
policy: policy,
time: time,
},
binding_signature: binding_signature,
})
}
}
}
impl<'a, C> seal::Sealed for ComponentAmalgamation<'a, C> {}
impl<'a, C> ValidateAmalgamation<'a, C> for ComponentAmalgamation<'a, C> {
type V = ValidComponentAmalgamation<'a, C>;
impl_with_policy!(with_policy, true);
}
impl<'a, C> ValidateAmalgamationRelaxed<'a, C> for ComponentAmalgamation<'a, C> {
type V = ValidComponentAmalgamation<'a, C>;
impl_with_policy!(with_policy_relaxed, valid_cert, valid_cert: bool);
}
impl<'a> UserIDAmalgamation<'a> {
pub fn userid(&self) -> &'a UserID {
self.component()
}
}
impl<'a> UserAttributeAmalgamation<'a> {
pub fn user_attribute(&self) -> &'a UserAttribute {
self.component()
}
}
#[derive(Debug)]
pub struct ValidComponentAmalgamation<'a, C> {
ca: ComponentAmalgamation<'a, C>,
cert: ValidCert<'a>,
binding_signature: &'a Signature,
}
assert_send_and_sync!(ValidComponentAmalgamation<'_, C> where C);
pub type ValidUserIDAmalgamation<'a> = ValidComponentAmalgamation<'a, UserID>;
pub type ValidUserAttributeAmalgamation<'a>
= ValidComponentAmalgamation<'a, UserAttribute>;
impl<'a, C> Clone for ValidComponentAmalgamation<'a, C> {
fn clone(&self) -> Self {
Self {
ca: self.ca.clone(),
cert: self.cert.clone(),
binding_signature: self.binding_signature,
}
}
}
impl<'a, C> std::ops::Deref for ValidComponentAmalgamation<'a, C> {
type Target = ComponentAmalgamation<'a, C>;
fn deref(&self) -> &Self::Target {
assert!(std::ptr::eq(self.ca.cert(), self.cert.cert()));
&self.ca
}
}
impl<'a, C: 'a> From<ValidComponentAmalgamation<'a, C>>
for ComponentAmalgamation<'a, C>
{
fn from(vca: ValidComponentAmalgamation<'a, C>) -> Self {
assert!(std::ptr::eq(vca.ca.cert(), vca.cert.cert()));
vca.ca
}
}
impl<'a, C> ValidComponentAmalgamation<'a, C>
where C: Ord + Send + Sync
{
pub(super) fn primary(cert: &'a Cert,
iter: std::slice::Iter<'a, ComponentBundle<C>>,
policy: &'a dyn Policy, t: SystemTime,
valid_cert: bool)
-> Result<ValidComponentAmalgamation<'a, C>>
{
use std::cmp::Ordering;
let mut error = None;
iter.filter_map(|c| {
let sig = match c.binding_signature(policy, t) {
Ok(sig) => Some(sig),
Err(e) => {
error = Some(e);
None
},
}?;
let revoked = c._revocation_status(policy, t, false, Some(sig));
let primary = sig.primary_userid().unwrap_or(false);
let signature_creation_time = match sig.signature_creation_time() {
Some(time) => Some(time),
None => {
error = Some(Error::MalformedPacket(
"Signature has no creation time".into()).into());
None
},
}?;
Some(((c, sig, revoked), primary, signature_creation_time))
})
.max_by(|(a, a_primary, a_signature_creation_time),
(b, b_primary, b_signature_creation_time)| {
match (matches!(&a.2, RevocationStatus::Revoked(_)),
matches!(&b.2, RevocationStatus::Revoked(_))) {
(true, false) => return Ordering::Less,
(false, true) => return Ordering::Greater,
_ => (),
}
match (a_primary, b_primary) {
(true, false) => return Ordering::Greater,
(false, true) => return Ordering::Less,
_ => (),
}
match a_signature_creation_time.cmp(&b_signature_creation_time)
{
Ordering::Less => return Ordering::Less,
Ordering::Greater => return Ordering::Greater,
Ordering::Equal => (),
}
match a.0.component().cmp(&b.0.component()) {
Ordering::Less => return Ordering::Greater,
Ordering::Greater => return Ordering::Less,
Ordering::Equal =>
panic!("non-canonicalized Cert (duplicate components)"),
}
})
.ok_or_else(|| {
error.map(|e| e.context(format!(
"No binding signature at time {}", crate::fmt::time(&t))))
.unwrap_or(Error::NoBindingSignature(t).into())
})
.and_then(|c| ComponentAmalgamation::new(cert, (c.0).0)
.with_policy_relaxed(policy, t, valid_cert))
}
pub fn self_signatures(&self) -> impl Iterator<Item=&Signature> + Send + Sync {
std::ops::Deref::deref(self).self_signatures()
.filter(move |sig| self.cert.policy().signature(sig,
self.hash_algo_security).is_ok())
}
pub fn certifications(&self) -> impl Iterator<Item=&Signature> + Send + Sync {
std::ops::Deref::deref(self).certifications()
.filter(move |sig| self.cert.policy().signature(sig,
HashAlgoSecurity::CollisionResistance).is_ok())
}
pub fn self_revocations(&self) -> impl Iterator<Item=&Signature> + Send + Sync {
std::ops::Deref::deref(self).self_revocations()
.filter(move |sig|self.cert.policy().signature(sig,
self.hash_algo_security).is_ok())
}
pub fn other_revocations(&self) -> impl Iterator<Item=&Signature> + Send + Sync {
std::ops::Deref::deref(self).other_revocations()
.filter(move |sig| self.cert.policy().signature(sig,
HashAlgoSecurity::CollisionResistance).is_ok())
}
}
impl<'a, C> seal::Sealed for ValidComponentAmalgamation<'a, C> {}
impl<'a, C> ValidateAmalgamation<'a, C> for ValidComponentAmalgamation<'a, C> {
type V = Self;
fn with_policy<T>(self, policy: &'a dyn Policy, time: T) -> Result<Self::V>
where T: Into<Option<time::SystemTime>>,
Self: Sized,
{
assert!(std::ptr::eq(self.ca.cert(), self.cert.cert()));
let time = time.into().unwrap_or_else(SystemTime::now);
self.ca.with_policy(policy, time)
}
}
impl<'a, C> ValidAmalgamation<'a, C> for ValidComponentAmalgamation<'a, C> {
fn cert(&self) -> &ValidCert<'a> {
assert!(std::ptr::eq(self.ca.cert(), self.cert.cert()));
&self.cert
}
fn time(&self) -> SystemTime {
assert!(std::ptr::eq(self.ca.cert(), self.cert.cert()));
self.cert.time
}
fn policy(&self) -> &'a dyn Policy
{
assert!(std::ptr::eq(self.ca.cert(), self.cert.cert()));
self.cert.policy
}
fn binding_signature(&self) -> &'a Signature {
assert!(std::ptr::eq(self.ca.cert(), self.cert.cert()));
self.binding_signature
}
fn revocation_status(&self) -> RevocationStatus<'a> {
self.bundle._revocation_status(self.policy(), self.cert.time,
false, Some(self.binding_signature))
}
}
impl<'a, C> crate::cert::Preferences<'a>
for ValidComponentAmalgamation<'a, C>
{
fn preferred_symmetric_algorithms(&self)
-> Option<&'a [SymmetricAlgorithm]> {
self.map(|s| s.preferred_symmetric_algorithms())
}
fn preferred_hash_algorithms(&self) -> Option<&'a [HashAlgorithm]> {
self.map(|s| s.preferred_hash_algorithms())
}
fn preferred_compression_algorithms(&self)
-> Option<&'a [CompressionAlgorithm]> {
self.map(|s| s.preferred_compression_algorithms())
}
fn preferred_aead_algorithms(&self) -> Option<&'a [AEADAlgorithm]> {
self.map(|s| s.preferred_aead_algorithms())
}
fn key_server_preferences(&self) -> Option<KeyServerPreferences> {
self.map(|s| s.key_server_preferences())
}
fn preferred_key_server(&self) -> Option<&'a [u8]> {
self.map(|s| s.preferred_key_server())
}
fn features(&self) -> Option<Features> {
self.map(|s| s.features())
}
}
#[cfg(test)]
mod test {
use crate::policy::StandardPolicy as P;
use crate::cert::prelude::*;
#[test]
fn clone() {
let p = &P::new();
let (cert, _) = CertBuilder::new()
.add_userid("test@example.example")
.generate()
.unwrap();
let userid : UserIDAmalgamation = cert.userids().nth(0).unwrap();
assert_eq!(userid.userid(), userid.clone().userid());
let userid : ValidUserIDAmalgamation
= userid.with_policy(p, None).unwrap();
let c = userid.clone();
assert_eq!(userid.userid(), c.userid());
assert_eq!(userid.time(), c.time());
}
#[test]
fn map() {
let (cert, _) = CertBuilder::new()
.add_userid("test@example.example")
.generate()
.unwrap();
let _ = cert.userids().map(|ua| ua.userid())
.collect::<Vec<_>>();
let _ = cert.user_attributes().map(|ua| ua.user_attribute())
.collect::<Vec<_>>();
}
}