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,
types::KeyFlags,
cert::prelude::*,
policy::Policy,
};
fn skip_secret(
have_secret_encrypted: Option<bool>,
want_encrypted_key: Option<bool>,
want_unencrypted_secret: Option<bool>,
) -> Option<&'static str> {
match (have_secret_encrypted, want_encrypted_key, want_unencrypted_secret) {
(Some(_), Some(true), Some(true))
| (_, None, None)
| (Some(true), Some(true), _)
| (Some(true), None, Some(false))
| (Some(false), _, Some(true))
| (Some(false), Some(false), None) => None, (Some(true), Some(false), _) | (Some(true), None, Some(true)) => {
Some("Encrypted secret... skipping.")
}
(Some(false), _, Some(false)) | (Some(false), Some(true), None) => {
Some("Unencrypted secret... skipping.")
}
(None, Some(_), None)
| (None, None, Some(_))
| (None, Some(_), Some(_)) => {
Some("No secret... skipping.")
}
}
}
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>>,
encrypted_secret: Option<bool>,
unencrypted_secret: Option<bool>,
key_handles: Vec<KeyHandle>,
supported: Option<bool>,
_p: std::marker::PhantomData<P>,
_r: std::marker::PhantomData<R>,
}
assert_send_and_sync!(KeyAmalgamationIter<'_, P, R>
where P: key::KeyParts,
R: key::KeyRole,
);
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("encrypted_secret", &self.encrypted_secret)
.field("unencrypted_secret", &self.unencrypted_secret)
.field("key_handles", &self.key_handles)
.field("supported", &self.supported)
.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);
let cert = self.cert?;
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.is_empty()
&& ! 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_supported) = self.supported {
if ka.key().pk_algo().is_supported() {
if ! want_supported {
t!("PK algo is supported... skipping.");
continue;
}
} else if want_supported {
t!("PK algo is not supported... skipping.");
continue;
}
}
if let Some(msg) = skip_secret(
ka.key().optional_secret().map(|x| x.is_encrypted()),
self.encrypted_secret,
self.unencrypted_secret,
) {
t!(msg);
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(),
encrypted_secret: None,
unencrypted_secret: None,
key_handles: Default::default(),
supported: None,
_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,
encrypted_secret: Some(true),
unencrypted_secret: Some(true),
key_handles: self.key_handles,
supported: self.supported,
_p: std::marker::PhantomData,
_r: std::marker::PhantomData,
}
}
pub fn encrypted_secret(
self,
) -> KeyAmalgamationIter<'a, key::SecretParts, R> {
KeyAmalgamationIter {
cert: self.cert,
primary: self.primary,
subkey_iter: self.subkey_iter,
encrypted_secret: Some(true),
unencrypted_secret: self.unencrypted_secret,
key_handles: self.key_handles,
supported: self.supported,
_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,
encrypted_secret: self.encrypted_secret,
unencrypted_secret: Some(true),
key_handles: self.key_handles,
supported: self.supported,
_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<H, K>(mut self, handles: H) -> Self
where
H: IntoIterator<Item=K>,
K: Borrow<KeyHandle>,
{
let mut handles = handles.into_iter()
.map(|h| h.borrow().clone())
.collect::<Vec<_>>();
self.key_handles.append(&mut handles);
self
}
pub fn supported(mut self) -> Self {
self.supported = Some(true);
self
}
pub fn subkeys(self) -> KeyAmalgamationIter<'a, P, key::SubordinateRole> {
KeyAmalgamationIter {
cert: self.cert,
primary: true,
subkey_iter: self.subkey_iter,
encrypted_secret: self.encrypted_secret,
unencrypted_secret: self.unencrypted_secret,
key_handles: self.key_handles,
supported: self.supported,
_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(crate::now),
encrypted_secret: self.encrypted_secret,
unencrypted_secret: self.unencrypted_secret,
key_handles: self.key_handles,
supported: self.supported,
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,
encrypted_secret: Option<bool>,
unencrypted_secret: Option<bool>,
key_handles: Vec<KeyHandle>,
supported: Option<bool>,
flags: Option<KeyFlags>,
alive: Option<()>,
revoked: Option<bool>,
_p: std::marker::PhantomData<P>,
_r: std::marker::PhantomData<R>,
}
assert_send_and_sync!(ValidKeyAmalgamationIter<'_, P, R>
where P: key::KeyParts,
R: key::KeyRole,
);
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("encrypted_secret", &self.encrypted_secret)
.field("unencrypted_secret", &self.unencrypted_secret)
.field("key_handles", &self.key_handles)
.field("supported", &self.supported)
.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);
let cert = self.cert?;
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, 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.is_empty()
&& ! 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(want_supported) = self.supported {
if ka.key().pk_algo().is_supported() {
if ! want_supported {
t!("PK algo is supported... skipping.");
continue;
}
} else if want_supported {
t!("PK algo is not supported... skipping.");
continue;
}
}
if let Some(flags) = self.flags.as_ref() {
if !ka.has_any_key_flag(flags) {
t!("Have flags: {:?}, want flags: {:?}... skipping.",
ka.key_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.revocation_status() {
if ! want_revoked {
t!("Key revoked... skipping.");
continue;
}
} else {
if want_revoked {
t!("Key not revoked... skipping.");
continue;
}
}
}
if let Some(msg) = skip_secret(
ka.key().optional_secret().map(|x| x.is_encrypted()),
self.encrypted_secret,
self.unencrypted_secret,
) {
t!(msg);
continue;
}
return Some(ka);
}
}
}
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::empty().set_certification())
}
pub fn for_signing(self) -> Self {
self.key_flags(KeyFlags::empty().set_signing())
}
pub fn for_authentication(self) -> Self {
self.key_flags(KeyFlags::empty().set_authentication())
}
pub fn for_storage_encryption(self) -> Self {
self.key_flags(KeyFlags::empty().set_storage_encryption())
}
pub fn for_transport_encryption(self) -> Self {
self.key_flags(KeyFlags::empty().set_transport_encryption())
}
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,
encrypted_secret: Some(true),
unencrypted_secret: Some(true),
key_handles: self.key_handles,
supported: self.supported,
flags: self.flags,
alive: self.alive,
revoked: self.revoked,
_p: std::marker::PhantomData,
_r: std::marker::PhantomData,
}
}
pub fn encrypted_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,
encrypted_secret: Some(true),
unencrypted_secret: self.unencrypted_secret,
key_handles: self.key_handles,
supported: self.supported,
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,
encrypted_secret: self.encrypted_secret,
unencrypted_secret: Some(true),
key_handles: self.key_handles,
supported: self.supported,
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<H, K>(mut self, handles: H) -> Self
where
H: IntoIterator<Item=K>,
K: Borrow<KeyHandle>,
{
let mut handles = handles.into_iter()
.map(|h| h.borrow().clone())
.collect::<Vec<_>>();
self.key_handles.append(&mut handles);
self
}
pub fn supported(mut self) -> Self {
self.supported = Some(true);
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,
encrypted_secret: self.encrypted_secret,
unencrypted_secret: self.unencrypted_secret,
key_handles: self.key_handles,
supported: self.supported,
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::empty().set_transport_encryption();
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::empty().set_transport_encryption();
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::empty().set_transport_encryption();
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::empty().set_transport_encryption();
let now = crate::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::empty().set_certification();
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::empty().set_authentication())
.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);
}
}
}
#[test]
#[allow(deprecated)]
fn select_supported() -> crate::Result<()> {
use crate::types::PublicKeyAlgorithm;
if ! PublicKeyAlgorithm::DSA.is_supported()
|| PublicKeyAlgorithm::ElGamalEncrypt.is_supported()
{
return Ok(()); }
let cert =
Cert::from_bytes(crate::tests::key("dsa2048-elgamal3072.pgp"))?;
assert_eq!(cert.keys().count(), 2);
assert_eq!(cert.keys().supported().count(), 1);
let p = unsafe { &crate::policy::NullPolicy::new() };
assert_eq!(cert.keys().with_policy(p, None).count(), 2);
assert_eq!(cert.keys().with_policy(p, None).supported().count(), 1);
Ok(())
}
}