use std::fmt;
use std::convert::TryInto;
use std::time::SystemTime;
use std::borrow::Borrow;
use std::slice;
use crate::{
KeyHandle,
types::RevocationStatus,
packet::key,
packet::key::SecretKeyMaterial,
types::KeyFlags,
cert::prelude::*,
policy::Policy,
};
pub struct KeyAmalgamationIter<'a, P, R>
where P: key::KeyParts,
R: key::KeyRole,
{
cert: Option<&'a Cert>,
primary: bool,
subkey_iter: slice::Iter<'a, KeyBundle<key::PublicParts,
key::SubordinateRole>>,
secret: Option<bool>,
unencrypted_secret: Option<bool>,
key_handles: Vec<KeyHandle>,
_p: std::marker::PhantomData<P>,
_r: std::marker::PhantomData<R>,
}
impl<'a, P, R> fmt::Debug for KeyAmalgamationIter<'a, P, R>
where P: key::KeyParts,
R: key::KeyRole,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("KeyAmalgamationIter")
.field("secret", &self.secret)
.field("unencrypted_secret", &self.unencrypted_secret)
.field("key_handles", &self.key_handles)
.finish()
}
}
macro_rules! impl_iterator {
($parts:path, $role:path, $item:ty) => {
impl<'a> Iterator for KeyAmalgamationIter<'a, $parts, $role>
{
type Item = $item;
fn next(&mut self) -> Option<Self::Item> {
self.next_common().map(|k| k.try_into().expect("filtered"))
}
}
}
}
impl_iterator!(key::PublicParts, key::PrimaryRole,
PrimaryKeyAmalgamation<'a, key::PublicParts>);
impl_iterator!(key::SecretParts, key::PrimaryRole,
PrimaryKeyAmalgamation<'a, key::SecretParts>);
impl_iterator!(key::UnspecifiedParts, key::PrimaryRole,
PrimaryKeyAmalgamation<'a, key::UnspecifiedParts>);
impl_iterator!(key::PublicParts, key::SubordinateRole,
SubordinateKeyAmalgamation<'a, key::PublicParts>);
impl_iterator!(key::SecretParts, key::SubordinateRole,
SubordinateKeyAmalgamation<'a, key::SecretParts>);
impl_iterator!(key::UnspecifiedParts, key::SubordinateRole,
SubordinateKeyAmalgamation<'a, key::UnspecifiedParts>);
impl_iterator!(key::PublicParts, key::UnspecifiedRole,
ErasedKeyAmalgamation<'a, key::PublicParts>);
impl_iterator!(key::SecretParts, key::UnspecifiedRole,
ErasedKeyAmalgamation<'a, key::SecretParts>);
impl_iterator!(key::UnspecifiedParts, key::UnspecifiedRole,
ErasedKeyAmalgamation<'a, key::UnspecifiedParts>);
impl<'a, P, R> KeyAmalgamationIter<'a, P, R>
where P: key::KeyParts,
R: key::KeyRole,
{
fn next_common(&mut self) -> Option<ErasedKeyAmalgamation<'a, key::PublicParts>>
{
tracer!(false, "KeyAmalgamationIter::next", 0);
t!("KeyAmalgamationIter: {:?}", self);
if self.cert.is_none() {
return None;
}
let cert = self.cert.unwrap();
loop {
let ka : ErasedKeyAmalgamation<key::PublicParts>
= if ! self.primary {
self.primary = true;
PrimaryKeyAmalgamation::new(cert).into()
} else {
SubordinateKeyAmalgamation::new(
cert, self.subkey_iter.next()?).into()
};
t!("Considering key: {:?}", ka.key());
if self.key_handles.len() > 0 {
if !self.key_handles
.iter()
.any(|h| h.aliases(ka.key().key_handle()))
{
t!("{} is not one of the keys that we are looking for ({:?})",
ka.key().fingerprint(), self.key_handles);
continue;
}
}
if let Some(want_secret) = self.secret {
if ka.key().has_secret() {
if ! want_secret {
t!("Have a secret... skipping.");
continue;
}
} else {
if want_secret {
t!("No secret... skipping.");
continue;
}
}
}
if let Some(want_unencrypted_secret) = self.unencrypted_secret {
if let Some(secret) = ka.key().optional_secret() {
if let SecretKeyMaterial::Unencrypted { .. } = secret {
if ! want_unencrypted_secret {
t!("Unencrypted secret... skipping.");
continue;
}
} else {
if want_unencrypted_secret {
t!("Encrypted secret... skipping.");
continue;
}
}
} else {
t!("No secret... skipping.");
continue;
}
}
return Some(ka);
}
}
}
impl<'a, P, R> KeyAmalgamationIter<'a, P, R>
where P: key::KeyParts,
R: key::KeyRole,
{
pub(crate) fn new(cert: &'a Cert) -> Self where Self: 'a {
KeyAmalgamationIter {
cert: Some(cert),
primary: false,
subkey_iter: cert.subkeys.iter(),
secret: None,
unencrypted_secret: None,
key_handles: Vec::with_capacity(0),
_p: std::marker::PhantomData,
_r: std::marker::PhantomData,
}
}
pub fn secret(self) -> KeyAmalgamationIter<'a, key::SecretParts, R> {
KeyAmalgamationIter {
cert: self.cert,
primary: self.primary,
subkey_iter: self.subkey_iter,
secret: Some(true),
unencrypted_secret: self.unencrypted_secret,
key_handles: self.key_handles,
_p: std::marker::PhantomData,
_r: std::marker::PhantomData,
}
}
pub fn unencrypted_secret(self) -> KeyAmalgamationIter<'a, key::SecretParts, R> {
KeyAmalgamationIter {
cert: self.cert,
primary: self.primary,
subkey_iter: self.subkey_iter,
secret: self.secret,
unencrypted_secret: Some(true),
key_handles: self.key_handles,
_p: std::marker::PhantomData,
_r: std::marker::PhantomData,
}
}
pub fn key_handle<H>(mut self, h: H) -> Self
where H: Into<KeyHandle>
{
self.key_handles.push(h.into());
self
}
pub fn key_handles<'b>(mut self, h: impl Iterator<Item=&'b KeyHandle>)
-> Self
where 'a: 'b
{
self.key_handles.extend(h.map(|h| h.clone()));
self
}
pub fn subkeys(self) -> KeyAmalgamationIter<'a, P, key::SubordinateRole> {
KeyAmalgamationIter {
cert: self.cert,
primary: true,
subkey_iter: self.subkey_iter,
secret: self.secret,
unencrypted_secret: self.unencrypted_secret,
key_handles: self.key_handles,
_p: std::marker::PhantomData,
_r: std::marker::PhantomData,
}
}
pub fn with_policy<T>(self, policy: &'a dyn Policy, time: T)
-> ValidKeyAmalgamationIter<'a, P, R>
where T: Into<Option<SystemTime>>
{
ValidKeyAmalgamationIter {
cert: self.cert,
primary: self.primary,
subkey_iter: self.subkey_iter,
policy,
time: time.into().unwrap_or_else(SystemTime::now),
secret: self.secret,
unencrypted_secret: self.unencrypted_secret,
key_handles: self.key_handles,
flags: None,
alive: None,
revoked: None,
_p: self._p,
_r: self._r,
}
}
}
pub struct ValidKeyAmalgamationIter<'a, P, R>
where P: key::KeyParts,
R: key::KeyRole,
{
cert: Option<&'a Cert>,
primary: bool,
subkey_iter: slice::Iter<'a, KeyBundle<key::PublicParts,
key::SubordinateRole>>,
policy: &'a dyn Policy,
time: SystemTime,
secret: Option<bool>,
unencrypted_secret: Option<bool>,
key_handles: Vec<KeyHandle>,
flags: Option<KeyFlags>,
alive: Option<()>,
revoked: Option<bool>,
_p: std::marker::PhantomData<P>,
_r: std::marker::PhantomData<R>,
}
impl<'a, P, R> fmt::Debug for ValidKeyAmalgamationIter<'a, P, R>
where P: key::KeyParts,
R: key::KeyRole,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("ValidKeyAmalgamationIter")
.field("policy", &self.policy)
.field("time", &self.time)
.field("secret", &self.secret)
.field("unencrypted_secret", &self.unencrypted_secret)
.field("key_handles", &self.key_handles)
.field("flags", &self.flags)
.field("alive", &self.alive)
.field("revoked", &self.revoked)
.finish()
}
}
macro_rules! impl_iterator {
($parts:path, $role:path, $item:ty) => {
impl<'a> Iterator for ValidKeyAmalgamationIter<'a, $parts, $role>
{
type Item = $item;
fn next(&mut self) -> Option<Self::Item> {
self.next_common().map(|k| k.try_into().expect("filtered"))
}
}
}
}
impl_iterator!(key::PublicParts, key::PrimaryRole,
ValidPrimaryKeyAmalgamation<'a, key::PublicParts>);
impl_iterator!(key::SecretParts, key::PrimaryRole,
ValidPrimaryKeyAmalgamation<'a, key::SecretParts>);
impl_iterator!(key::UnspecifiedParts, key::PrimaryRole,
ValidPrimaryKeyAmalgamation<'a, key::UnspecifiedParts>);
impl_iterator!(key::PublicParts, key::SubordinateRole,
ValidSubordinateKeyAmalgamation<'a, key::PublicParts>);
impl_iterator!(key::SecretParts, key::SubordinateRole,
ValidSubordinateKeyAmalgamation<'a, key::SecretParts>);
impl_iterator!(key::UnspecifiedParts, key::SubordinateRole,
ValidSubordinateKeyAmalgamation<'a, key::UnspecifiedParts>);
impl_iterator!(key::PublicParts, key::UnspecifiedRole,
ValidErasedKeyAmalgamation<'a, key::PublicParts>);
impl_iterator!(key::SecretParts, key::UnspecifiedRole,
ValidErasedKeyAmalgamation<'a, key::SecretParts>);
impl_iterator!(key::UnspecifiedParts, key::UnspecifiedRole,
ValidErasedKeyAmalgamation<'a, key::UnspecifiedParts>);
impl<'a, P, R> ValidKeyAmalgamationIter<'a, P, R>
where P: key::KeyParts,
R: key::KeyRole,
{
fn next_common(&mut self)
-> Option<ValidErasedKeyAmalgamation<'a, key::PublicParts>>
{
tracer!(false, "ValidKeyAmalgamationIter::next", 0);
t!("ValidKeyAmalgamationIter: {:?}", self);
if self.cert.is_none() {
return None;
}
let cert = self.cert.unwrap();
if let Some(flags) = self.flags.as_ref() {
if flags.is_empty() {
t!("short circuiting: flags is empty");
return None;
}
}
loop {
let ka = if ! self.primary {
self.primary = true;
let ka : ErasedKeyAmalgamation<'a, key::PublicParts>
= PrimaryKeyAmalgamation::new(cert).into();
match ka.with_policy(self.policy, self.time) {
Ok(ka) => ka,
Err(err) => {
t!("Getting primary key: {:?}", err);
return None;
}
}
} else {
let ka : ErasedKeyAmalgamation<'a, key::PublicParts>
= SubordinateKeyAmalgamation::new(
cert.into(), self.subkey_iter.next()?).into();
match ka.with_policy(self.policy, self.time) {
Ok(ka) => ka,
Err(err) => {
t!("Getting subkey: {:?}", err);
continue;
}
}
};
let key = ka.key();
t!("Considering key: {:?}", key);
if self.key_handles.len() > 0 {
if !self.key_handles
.iter()
.any(|h| h.aliases(key.key_handle()))
{
t!("{} is not one of the keys that we are looking for ({:?})",
key.key_handle(), self.key_handles);
continue;
}
}
if let Some(flags) = self.flags.as_ref() {
if !ka.has_any_key_flag(flags) {
t!("Have flags: {:?}, want flags: {:?}... skipping.",
flags, flags);
continue;
}
}
if let Some(()) = self.alive {
if let Err(err) = ka.alive() {
t!("Key not alive: {:?}", err);
continue;
}
}
if let Some(want_revoked) = self.revoked {
if let RevocationStatus::Revoked(_) = ka.revoked() {
if ! want_revoked {
t!("Key revoked... skipping.");
continue;
}
} else {
if want_revoked {
t!("Key not revoked... skipping.");
continue;
}
}
}
if let Some(want_secret) = self.secret {
if key.has_secret() {
if ! want_secret {
t!("Have a secret... skipping.");
continue;
}
} else {
if want_secret {
t!("No secret... skipping.");
continue;
}
}
}
if let Some(want_unencrypted_secret) = self.unencrypted_secret {
if let Some(secret) = key.optional_secret() {
if let SecretKeyMaterial::Unencrypted { .. } = secret {
if ! want_unencrypted_secret {
t!("Unencrypted secret... skipping.");
continue;
}
} else {
if want_unencrypted_secret {
t!("Encrypted secret... skipping.");
continue;
}
}
} else {
t!("No secret... skipping.");
continue;
}
}
return Some(ka.into());
}
}
}
impl<'a, P, R> ValidKeyAmalgamationIter<'a, P, R>
where P: key::KeyParts,
R: key::KeyRole,
{
pub fn key_flags<F>(mut self, flags: F) -> Self
where F: Borrow<KeyFlags>
{
let flags = flags.borrow();
if let Some(flags_old) = self.flags {
self.flags = Some(flags | &flags_old);
} else {
self.flags = Some(flags.clone());
}
self
}
pub fn for_certification(self) -> Self {
self.key_flags(KeyFlags::default().set_certification(true))
}
pub fn for_signing(self) -> Self {
self.key_flags(KeyFlags::default().set_signing(true))
}
pub fn for_authentication(self) -> Self {
self.key_flags(KeyFlags::default().set_authentication(true))
}
pub fn for_storage_encryption(self) -> Self {
self.key_flags(KeyFlags::default().set_storage_encryption(true))
}
pub fn for_transport_encryption(self) -> Self {
self.key_flags(KeyFlags::default().set_transport_encryption(true))
}
pub fn alive(mut self) -> Self
{
self.alive = Some(());
self
}
pub fn revoked<T>(mut self, revoked: T) -> Self
where T: Into<Option<bool>>
{
self.revoked = revoked.into();
self
}
pub fn secret(self) -> ValidKeyAmalgamationIter<'a, key::SecretParts, R> {
ValidKeyAmalgamationIter {
cert: self.cert,
primary: self.primary,
subkey_iter: self.subkey_iter,
time: self.time,
policy: self.policy,
secret: Some(true),
unencrypted_secret: self.unencrypted_secret,
key_handles: self.key_handles,
flags: self.flags,
alive: self.alive,
revoked: self.revoked,
_p: std::marker::PhantomData,
_r: std::marker::PhantomData,
}
}
pub fn unencrypted_secret(self) -> ValidKeyAmalgamationIter<'a, key::SecretParts, R> {
ValidKeyAmalgamationIter {
cert: self.cert,
primary: self.primary,
subkey_iter: self.subkey_iter,
time: self.time,
policy: self.policy,
secret: self.secret,
unencrypted_secret: Some(true),
key_handles: self.key_handles,
flags: self.flags,
alive: self.alive,
revoked: self.revoked,
_p: std::marker::PhantomData,
_r: std::marker::PhantomData,
}
}
pub fn key_handle<H>(mut self, h: H) -> Self
where H: Into<KeyHandle>
{
self.key_handles.push(h.into());
self
}
pub fn key_handles<'b>(mut self, h: impl Iterator<Item=&'b KeyHandle>)
-> Self
where 'a: 'b
{
self.key_handles.extend(h.map(|h| h.clone()));
self
}
pub fn subkeys(self) -> ValidKeyAmalgamationIter<'a, P, key::SubordinateRole> {
ValidKeyAmalgamationIter {
cert: self.cert,
primary: true,
subkey_iter: self.subkey_iter,
time: self.time,
policy: self.policy,
secret: self.secret,
unencrypted_secret: self.unencrypted_secret,
key_handles: self.key_handles,
flags: self.flags,
alive: self.alive,
revoked: self.revoked,
_p: std::marker::PhantomData,
_r: std::marker::PhantomData,
}
}
}
#[cfg(test)]
mod test {
use super::*;
use crate::{
parse::Parse,
cert::builder::CertBuilder,
};
use crate::policy::StandardPolicy as P;
#[test]
fn key_iter_test() {
let key = Cert::from_bytes(crate::tests::key("neal.pgp")).unwrap();
assert_eq!(1 + key.subkeys().count(),
key.keys().count());
}
#[test]
fn select_no_keys() {
let p = &P::new();
let (cert, _) = CertBuilder::new()
.generate().unwrap();
let flags = KeyFlags::default().set_transport_encryption(true);
assert_eq!(cert.keys().with_policy(p, None).key_flags(flags).count(), 0);
}
#[test]
fn select_valid_and_right_flags() {
let p = &P::new();
let (cert, _) = CertBuilder::new()
.add_transport_encryption_subkey()
.generate().unwrap();
let flags = KeyFlags::default().set_transport_encryption(true);
assert_eq!(cert.keys().with_policy(p, None).key_flags(flags).count(), 1);
}
#[test]
fn select_valid_and_wrong_flags() {
let p = &P::new();
let (cert, _) = CertBuilder::new()
.add_transport_encryption_subkey()
.add_signing_subkey()
.generate().unwrap();
let flags = KeyFlags::default().set_transport_encryption(true);
assert_eq!(cert.keys().with_policy(p, None).key_flags(flags).count(), 1);
}
#[test]
fn select_invalid_and_right_flags() {
let p = &P::new();
let (cert, _) = CertBuilder::new()
.add_transport_encryption_subkey()
.generate().unwrap();
let flags = KeyFlags::default().set_transport_encryption(true);
let now = SystemTime::now()
- std::time::Duration::new(52 * 7 * 24 * 60 * 60, 0);
assert_eq!(cert.keys().with_policy(p, now).key_flags(flags).alive().count(),
0);
}
#[test]
fn select_primary() {
let p = &P::new();
let (cert, _) = CertBuilder::new()
.add_certification_subkey()
.generate().unwrap();
let flags = KeyFlags::default().set_certification(true);
assert_eq!(cert.keys().with_policy(p, None).key_flags(flags).count(),
2);
}
#[test]
fn selectors() {
let p = &P::new();
let (cert, _) = CertBuilder::new()
.add_signing_subkey()
.add_certification_subkey()
.add_transport_encryption_subkey()
.add_storage_encryption_subkey()
.add_authentication_subkey()
.generate().unwrap();
assert_eq!(cert.keys().with_policy(p, None).alive().revoked(false)
.for_certification().count(),
2);
assert_eq!(cert.keys().with_policy(p, None).alive().revoked(false)
.for_transport_encryption().count(),
1);
assert_eq!(cert.keys().with_policy(p, None).alive().revoked(false)
.for_storage_encryption().count(),
1);
assert_eq!(cert.keys().with_policy(p, None).alive().revoked(false)
.for_signing().count(),
1);
assert_eq!(cert.keys().with_policy(p, None).alive().revoked(false)
.key_flags(KeyFlags::default().set_authentication(true))
.count(),
1);
}
#[test]
fn select_key_handle() {
let p = &P::new();
let (cert, _) = CertBuilder::new()
.add_signing_subkey()
.add_certification_subkey()
.add_transport_encryption_subkey()
.add_storage_encryption_subkey()
.add_authentication_subkey()
.generate().unwrap();
let keys = cert.keys().count();
assert_eq!(keys, 6);
let keyids = cert.keys().map(|ka| ka.key().keyid()).collect::<Vec<_>>();
fn check(got: &[KeyHandle], expected: &[KeyHandle]) {
if expected.len() != got.len() {
panic!("Got {}, expected {} handles",
got.len(), expected.len());
}
for (g, e) in got.iter().zip(expected.iter()) {
if !e.aliases(g) {
panic!(" Got: {:?}\nExpected: {:?}",
got, expected);
}
}
}
for i in 1..keys {
for keyids in keyids[..].windows(i) {
let keyids : Vec<KeyHandle>
= keyids.iter().map(Into::into).collect();
assert_eq!(keyids.len(), i);
check(
&cert.keys().key_handles(keyids.iter())
.map(|ka| ka.key().key_handle())
.collect::<Vec<KeyHandle>>(),
&keyids);
check(
&cert.keys().with_policy(p, None).key_handles(keyids.iter())
.map(|ka| ka.key().key_handle())
.collect::<Vec<KeyHandle>>(),
&keyids);
check(
&cert.keys().key_handles(keyids.iter()).with_policy(p, None)
.map(|ka| ka.key().key_handle())
.collect::<Vec<KeyHandle>>(),
&keyids);
}
}
}
}