use std::time;
use std::time::SystemTime;
use std::convert::TryInto;
use std::convert::TryFrom;
use std::ops::Deref;
use crate::{
Cert,
cert::components::{
Amalgamation,
KeyBundle,
},
Error,
packet::key,
packet::key::SecretKeyMaterial,
packet::Key,
packet::Signature,
policy::Policy,
Result,
RevocationStatus,
};
#[derive(Debug, Clone)]
enum KeyAmalgamationBundle<'a, P: key::KeyParts> {
Primary(),
Subordinate(&'a KeyBundle<P, key::SubordinateRole>),
}
#[derive(Debug, Clone)]
pub struct KeyAmalgamation<'a, P: key::KeyParts> {
cert: &'a Cert,
bundle: KeyAmalgamationBundle<'a, P>,
}
impl<'a, P: key::KeyParts> Deref for KeyAmalgamation<'a, P>
where &'a Key<P, key::UnspecifiedRole>: From<&'a key::PublicKey>
{
type Target = Key<P, key::UnspecifiedRole>;
fn deref(&self) -> &Self::Target {
self.key()
}
}
impl<'a> From<KeyAmalgamation<'a, key::PublicParts>>
for KeyAmalgamation<'a, key::UnspecifiedParts>
{
fn from(ka: KeyAmalgamation<'a, key::PublicParts>) -> Self {
match ka {
KeyAmalgamation {
cert,
bundle: KeyAmalgamationBundle::Primary(),
} =>
KeyAmalgamation {
cert,
bundle: KeyAmalgamationBundle::Primary(),
},
KeyAmalgamation {
cert,
bundle: KeyAmalgamationBundle::Subordinate(bundle),
} =>
KeyAmalgamation {
cert,
bundle: KeyAmalgamationBundle::Subordinate(bundle.into()),
},
}
}
}
impl<'a> From<KeyAmalgamation<'a, key::SecretParts>>
for KeyAmalgamation<'a, key::PublicParts>
{
fn from(ka: KeyAmalgamation<'a, key::SecretParts>) -> Self {
match ka {
KeyAmalgamation {
cert,
bundle: KeyAmalgamationBundle::Primary(),
} =>
KeyAmalgamation {
cert,
bundle: KeyAmalgamationBundle::Primary(),
},
KeyAmalgamation {
cert,
bundle: KeyAmalgamationBundle::Subordinate(bundle),
} =>
KeyAmalgamation {
cert,
bundle: KeyAmalgamationBundle::Subordinate(bundle.into()),
},
}
}
}
impl<'a> TryFrom<KeyAmalgamation<'a, key::PublicParts>>
for KeyAmalgamation<'a, key::SecretParts>
{
type Error = failure::Error;
fn try_from(ka: KeyAmalgamation<'a, key::PublicParts>) -> Result<Self> {
Ok(match ka {
KeyAmalgamation {
cert,
bundle: KeyAmalgamationBundle::Primary(),
} => {
let _ : &KeyBundle<key::SecretParts, key::PrimaryRole>
= (&cert.primary).try_into()?;
KeyAmalgamation {
cert,
bundle: KeyAmalgamationBundle::Primary(),
}
}
KeyAmalgamation {
cert,
bundle: KeyAmalgamationBundle::Subordinate(bundle),
} =>
KeyAmalgamation {
cert,
bundle: KeyAmalgamationBundle::Subordinate(bundle.try_into()?),
},
})
}
}
impl<'a, P: 'a + key::KeyParts> KeyAmalgamation<'a, P> {
pub(crate) fn new_primary(cert: &'a Cert) -> Self {
KeyAmalgamation {
cert: cert,
bundle: KeyAmalgamationBundle::Primary(),
}
}
pub(crate) fn new_subordinate(
cert: &'a Cert, bundle: &'a KeyBundle<P, key::SubordinateRole>)
-> Self
{
KeyAmalgamation {
cert: cert,
bundle: KeyAmalgamationBundle::Subordinate(bundle),
}
}
pub fn key(&self) -> &'a Key<P, key::UnspecifiedRole>
where &'a Key<P, key::UnspecifiedRole>: From<&'a key::PublicKey>
{
match self {
KeyAmalgamation { bundle: KeyAmalgamationBundle::Primary(), .. } =>
self.cert.primary.key().into(),
KeyAmalgamation { bundle: KeyAmalgamationBundle::Subordinate(bundle), .. } =>
bundle.key().into(),
}
}
fn generic_key(&self)
-> &'a Key<key::UnspecifiedParts, key::UnspecifiedRole> {
match self {
KeyAmalgamation { bundle: KeyAmalgamationBundle::Primary(), .. } =>
self.cert.primary.key().into(),
KeyAmalgamation { bundle: KeyAmalgamationBundle::Subordinate(bundle), .. } =>
bundle.key().mark_parts_unspecified_ref().into(),
}
}
pub fn cert(&self) -> &'a Cert
{
self.cert
}
pub fn has_secret(&self) -> bool
{
self.generic_key().secret().is_some()
}
pub fn has_unencrypted_secret(&self) -> bool
{
if let Some(secret) = self.generic_key().secret() {
if let SecretKeyMaterial::Unencrypted { .. } = secret {
true
} else {
false
}
} else {
false
}
}
pub fn bundle(&self) -> &'a KeyBundle<P, key::UnspecifiedRole>
where &'a KeyBundle<P, key::UnspecifiedRole>:
From<&'a KeyBundle<key::PublicParts, key::PrimaryRole>>
{
match self {
KeyAmalgamation { bundle: KeyAmalgamationBundle::Primary(), .. } =>
(&self.cert.primary).into(),
KeyAmalgamation { bundle: KeyAmalgamationBundle::Subordinate(bundle), .. } =>
(*bundle).into(),
}
}
fn binding_signature<T>(&self, policy: &'a dyn Policy, time: T)
-> Option<&'a Signature>
where T: Into<Option<time::SystemTime>>
{
let time = time.into().unwrap_or_else(SystemTime::now);
match self {
KeyAmalgamation {
bundle: KeyAmalgamationBundle::Primary(),
..
} => {
self.cert.primary_userid(policy, time)
.map(|u| u.binding_signature())
.or_else(|| self.cert.primary_key().bundle()
.binding_signature(policy, time))
},
KeyAmalgamation {
bundle: KeyAmalgamationBundle::Subordinate(bundle),
..
} =>
bundle.binding_signature(policy, time),
}
}
pub fn with_policy<T>(self, policy: &'a dyn Policy, time: T)
-> Result<ValidKeyAmalgamation<'a, P>>
where T: Into<Option<time::SystemTime>>
{
let time = time.into().unwrap_or_else(SystemTime::now);
if let Some(binding_signature) = self.binding_signature(policy, time) {
Ok(ValidKeyAmalgamation {
a: self,
policy: policy,
time: time,
binding_signature: binding_signature,
})
} else {
Err(Error::NoBindingSignature(time).into())
}
}
}
#[derive(Debug, Clone)]
pub struct PrimaryKeyAmalgamation<'a, P: key::KeyParts> {
a: KeyAmalgamation<'a, P>,
}
impl<'a, P> From<PrimaryKeyAmalgamation<'a, P>>
for KeyAmalgamation<'a, P>
where P: key::KeyParts
{
fn from(a: PrimaryKeyAmalgamation<'a, P>) -> Self {
a.a
}
}
impl<'a, P: key::KeyParts> Deref for PrimaryKeyAmalgamation<'a, P>
where &'a Key<P, key::PrimaryRole>: From<&'a key::PublicKey>
{
type Target = KeyAmalgamation<'a, P>;
fn deref(&self) -> &Self::Target {
&self.a
}
}
impl<'a, P: key::KeyParts> PrimaryKeyAmalgamation<'a, P> {
pub(super) fn new(a: KeyAmalgamation<'a, P>) -> Self {
assert_match!(
&KeyAmalgamation {
bundle: KeyAmalgamationBundle::Primary(),
..
} = &a);
PrimaryKeyAmalgamation {
a
}
}
pub fn key(&self) -> &'a Key<P, key::PrimaryRole>
where &'a Key<P, key::UnspecifiedRole>:
From<&'a Key<key::PublicParts, key::PrimaryRole>>
{
self.a.key().into()
}
pub fn with_policy<T>(self, policy: &'a dyn Policy, time: T)
-> Result<ValidPrimaryKeyAmalgamation<'a, P>>
where T: Into<Option<time::SystemTime>>
{
Ok(ValidPrimaryKeyAmalgamation::new(self.a.with_policy(policy, time)?))
}
}
#[derive(Debug, Clone)]
pub struct ValidKeyAmalgamation<'a, P: key::KeyParts> {
a: KeyAmalgamation<'a, P>,
policy: &'a dyn Policy,
time: SystemTime,
binding_signature: &'a Signature,
}
impl<'a, P: key::KeyParts> Deref for ValidKeyAmalgamation<'a, P> {
type Target = KeyAmalgamation<'a, P>;
fn deref(&self) -> &Self::Target {
&self.a
}
}
impl<'a, P: key::KeyParts> From<ValidKeyAmalgamation<'a, P>>
for KeyAmalgamation<'a, P>
{
fn from(vka: ValidKeyAmalgamation<'a, P>) -> Self {
vka.a
}
}
impl<'a> From<ValidKeyAmalgamation<'a, key::PublicParts>>
for ValidKeyAmalgamation<'a, key::UnspecifiedParts>
{
fn from(ka: ValidKeyAmalgamation<'a, key::PublicParts>) -> Self {
ValidKeyAmalgamation {
a: ka.a.into(),
policy: ka.policy,
time: ka.time,
binding_signature: ka.binding_signature,
}
}
}
impl<'a> From<ValidKeyAmalgamation<'a, key::SecretParts>>
for ValidKeyAmalgamation<'a, key::PublicParts>
{
fn from(ka: ValidKeyAmalgamation<'a, key::SecretParts>) -> Self {
ValidKeyAmalgamation {
a: ka.a.into(),
policy: ka.policy,
time: ka.time,
binding_signature: ka.binding_signature,
}
}
}
impl<'a> TryFrom<ValidKeyAmalgamation<'a, key::PublicParts>>
for ValidKeyAmalgamation<'a, key::SecretParts>
{
type Error = failure::Error;
fn try_from(ka: ValidKeyAmalgamation<'a, key::PublicParts>) -> Result<Self> {
Ok(ValidKeyAmalgamation {
a: ka.a.try_into()?,
policy: ka.policy,
time: ka.time,
binding_signature: ka.binding_signature,
})
}
}
impl<'a, P: 'a + key::KeyParts> Amalgamation<'a> for ValidKeyAmalgamation<'a, P>
{
fn cert(&self) -> &'a Cert {
self.cert
}
fn time(&self) -> SystemTime {
self.time
}
fn policy(&self) -> &'a dyn Policy
{
self.policy
}
fn with_policy<T>(self, policy: &'a dyn Policy, time: T) -> Result<Self>
where T: Into<Option<time::SystemTime>>
{
let time = time.into().unwrap_or_else(SystemTime::now);
self.a.with_policy(policy, time)
}
fn binding_signature(&self) -> &'a Signature {
self.binding_signature
}
fn direct_key_signature(&self) -> Option<&'a Signature> {
self.cert.primary.binding_signature(self.policy, self.time())
}
fn revoked(&self) -> RevocationStatus<'a> {
match self.a.bundle {
KeyAmalgamationBundle::Primary() =>
self.cert.revoked(self.policy, self.time()),
KeyAmalgamationBundle::Subordinate(bundle) =>
bundle.revoked(self.policy, self.time()),
}
}
}
impl<'a, P: 'a + key::KeyParts> ValidKeyAmalgamation<'a, P> {
pub fn bundle(&self) -> &'a KeyBundle<P, key::UnspecifiedRole>
where &'a KeyBundle<P, key::UnspecifiedRole>:
From<&'a KeyBundle<key::PublicParts, key::PrimaryRole>>
{
match self {
ValidKeyAmalgamation {
a: KeyAmalgamation {
bundle: KeyAmalgamationBundle::Primary(), ..
},
..
} =>
(&self.cert.primary).into(),
ValidKeyAmalgamation {
a: KeyAmalgamation {
bundle: KeyAmalgamationBundle::Subordinate(bundle),
..
},
..
} =>
(*bundle).into(),
}
}
pub fn alive(&self) -> Result<()>
{
let sig = {
let binding = self.binding_signature();
if binding.key_expiration_time().is_some() {
Some(binding)
} else {
self.direct_key_signature()
}
};
if let Some(sig) = sig {
sig.key_alive(self.generic_key(), self.time())
} else {
Ok(())
}
}
pub fn has_secret(&self) -> bool
{
self.generic_key().secret().is_some()
}
pub fn has_unencrypted_secret(&self) -> bool
{
if let Some(secret) = self.generic_key().secret() {
if let SecretKeyMaterial::Unencrypted { .. } = secret {
true
} else {
false
}
} else {
false
}
}
}
#[derive(Debug, Clone)]
pub struct ValidPrimaryKeyAmalgamation<'a, P: key::KeyParts> {
a: ValidKeyAmalgamation<'a, P>,
}
impl<'a, P> From<ValidPrimaryKeyAmalgamation<'a, P>>
for ValidKeyAmalgamation<'a, P>
where P: key::KeyParts
{
fn from(a: ValidPrimaryKeyAmalgamation<'a, P>) -> Self {
a.a
}
}
impl<'a, P: key::KeyParts> Deref for ValidPrimaryKeyAmalgamation<'a, P>
where &'a Key<P, key::PrimaryRole>: From<&'a key::PublicKey>
{
type Target = ValidKeyAmalgamation<'a, P>;
fn deref(&self) -> &Self::Target {
&self.a
}
}
impl<'a, P: key::KeyParts> ValidPrimaryKeyAmalgamation<'a, P> {
pub(super) fn new(a: ValidKeyAmalgamation<'a, P>) -> Self {
assert_match!(
&ValidKeyAmalgamation {
a: KeyAmalgamation {
bundle: KeyAmalgamationBundle::Primary(),
..
},
..
} = &a);
ValidPrimaryKeyAmalgamation {
a
}
}
pub fn key(&self) -> &'a Key<P, key::PrimaryRole>
where &'a Key<P, key::UnspecifiedRole>:
From<&'a Key<key::PublicParts, key::PrimaryRole>>
{
self.a.key().into()
}
pub fn with_policy<T>(self, policy: &'a dyn Policy, time: T) -> Result<Self>
where T: Into<Option<time::SystemTime>>
{
Ok(Self::new(self.a.with_policy(policy, time)?))
}
}
impl<'a, P: 'a + key::KeyParts> Amalgamation<'a>
for ValidPrimaryKeyAmalgamation<'a, P>
{
fn cert(&self) -> &'a Cert {
self.a.cert()
}
fn time(&self) -> SystemTime {
self.a.time()
}
fn policy(&self) -> &'a dyn Policy {
self.a.policy()
}
fn with_policy<T>(self, policy: &'a dyn Policy, time: T) -> Result<Self>
where T: Into<Option<time::SystemTime>>
{
let time = time.into().unwrap_or_else(SystemTime::now);
Ok(ValidPrimaryKeyAmalgamation {
a: self.a.with_policy(policy, time)?,
})
}
fn binding_signature(&self) -> &'a Signature {
self.a.binding_signature()
}
fn direct_key_signature(&self) -> Option<&'a Signature> {
self.a.direct_key_signature()
}
fn revoked(&self) -> RevocationStatus<'a> {
self.a.revoked()
}
}
impl<'a, P: key::KeyParts> crate::cert::Preferences<'a>
for ValidPrimaryKeyAmalgamation<'a, P> {}