summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeal H. Walfield <neal@pep.foundation>2019-03-14 09:20:10 +0100
committerNeal H. Walfield <neal@pep.foundation>2019-03-14 14:56:47 +0100
commit1434843469109127f41c5dbd8aacf5400c537759 (patch)
tree0ca324cad8a486def769000eb460a13bd51473c4
parent6bea117391c1813e956e384c6638b7b0311d8d7c (diff)
openpgp: Replace TPK::select_keys with an iterator.
- TPK::select_keys mixes iterating and filtering. - Make KeyIter an implicit builder, which supports convenient filtering. - Provide a convenience function to key an iterator with a reasonable filter default.
-rw-r--r--openpgp-ffi/include/sequoia/openpgp.h103
-rw-r--r--openpgp-ffi/src/tpk.rs186
-rw-r--r--openpgp/examples/decrypt-with.rs2
-rw-r--r--openpgp/examples/notarize.rs2
-rw-r--r--openpgp/examples/sign-detached.rs2
-rw-r--r--openpgp/examples/sign.rs2
-rw-r--r--openpgp/src/crypto/keygrip.rs2
-rw-r--r--openpgp/src/packet/key_flags.rs10
-rw-r--r--openpgp/src/packet/signature/mod.rs9
-rw-r--r--openpgp/src/parse/stream.rs12
-rw-r--r--openpgp/src/serialize/stream.rs8
-rw-r--r--openpgp/src/tpk/mod.rs417
-rw-r--r--openpgp/src/tsk.rs50
-rw-r--r--sqv/src/sqv.rs16
-rw-r--r--store/src/backend/mod.rs2
-rw-r--r--tool/src/commands/mod.rs9
-rw-r--r--tool/tests/sq-sign.rs2
17 files changed, 682 insertions, 152 deletions
diff --git a/openpgp-ffi/include/sequoia/openpgp.h b/openpgp-ffi/include/sequoia/openpgp.h
index 1efd7d8a..b4115388 100644
--- a/openpgp-ffi/include/sequoia/openpgp.h
+++ b/openpgp-ffi/include/sequoia/openpgp.h
@@ -503,12 +503,86 @@ pgp_signature_t pgp_user_id_binding_selfsig(pgp_user_id_binding_t binding);
/*/
pgp_user_id_binding_t pgp_user_id_binding_iter_next (pgp_user_id_binding_iter_t iter);
+/*/
/// Frees an pgp_user_id_binding_iter_t.
+/*/
void pgp_user_id_binding_iter_free (pgp_user_id_binding_iter_t iter);
/* openpgp::tpk::KeyIter. */
/*/
+/// Changes the iterator to only return keys that are certification
+/// capable.
+///
+/// If you call this function and, e.g., the `signing_capable`
+/// function, the *union* of the values is used. That is, the
+/// iterator will return keys that are certification capable *or*
+/// signing capable.
+///
+/// Note: you may not call this function after starting to iterate.
+/*/
+void pgp_tpk_key_iter_certification_capable (pgp_tpk_key_iter_t iter);
+
+/*/
+/// Changes the iterator to only return keys that are certification
+/// capable.
+///
+/// If you call this function and, e.g., the `signing_capable`
+/// function, the *union* of the values is used. That is, the
+/// iterator will return keys that are certification capable *or*
+/// signing capable.
+///
+/// Note: you may not call this function after starting to iterate.
+/*/
+void pgp_tpk_key_iter_signing_capable (pgp_tpk_key_iter_t iter);
+
+/*/
+/// Changes the iterator to only return keys that are alive.
+///
+/// If you call this function (or `pgp_tpk_key_iter_alive_at`), only
+/// the last value is used.
+///
+/// Note: you may not call this function after starting to iterate.
+/*/
+void pgp_tpk_key_iter_alive (pgp_tpk_key_iter_t iter);
+
+/*/
+/// Changes the iterator to only return keys that are alive at the
+/// specified time.
+///
+/// If you call this function (or `pgp_tpk_key_iter_alive`), only the
+/// last value is used.
+///
+/// Note: you may not call this function after starting to iterate.
+/*/
+void pgp_tpk_key_iter_alive_at (pgp_tpk_key_iter_t iter, time_t when);
+
+/*/
+/// Changes the iterator to only return keys whose revocation status
+/// matches `revoked`.
+///
+/// Note: you may not call this function after starting to iterate.
+/*/
+void pgp_tpk_key_iter_revoked (pgp_tpk_key_iter_t iter, bool revoked);
+
+/*/
+/// Changes the iterator to only return keys that have secret keys (or
+/// not).
+///
+/// Note: you may not call this function after starting to iterate.
+/*/
+void pgp_tpk_key_iter_secret (pgp_tpk_key_iter_t iter, bool secret);
+
+/*/
+/// Changes the iterator to only return keys that have unencrypted
+/// secret keys (or not).
+///
+/// Note: you may not call this function after starting to iterate.
+/*/
+void pgp_tpk_key_iter_unencrypted_secret (pgp_tpk_key_iter_t iter,
+ bool unencrypted_secret);
+
+/*/
/// Returns the next key. Returns NULL if there are no more elements.
///
/// If sigo is not NULL, stores the current self-signature (if any) in
@@ -718,10 +792,33 @@ int pgp_tpk_is_tsk(pgp_tpk_t tpk);
pgp_user_id_binding_iter_t pgp_tpk_user_id_binding_iter (pgp_tpk_t tpk);
/*/
-/// Returns an iterator over all `Key`s (both the primary key and any
-/// subkeys) in a TPK.
+/// Returns an iterator over the live and unrevoked `Key`s in a TPK.
+///
+/// Compare with `pgp_tpk_keys_iter_valid`, which doesn'filters out
+/// expired and revoked keys by default.
+/*/
+pgp_tpk_key_iter_t pgp_tpk_keys_iter_all (pgp_tpk_t tpk);
+
+/*/
+/// Returns an iterator over all `Key`s in a TPK.
+///
+/// That is, this returns an iterator over the primary key and any
+/// subkeys, along with the corresponding signatures.
+///
+/// Note: since a primary key is different from a subkey, the iterator
+/// is over `Key`s and not `SubkeyBindings`. Since the primary key
+/// has no binding signature, the signature carrying the primary key's
+/// key flags is returned (either a direct key signature, or the
+/// self-signature on the primary User ID). There are corner cases
+/// where no such signature exists (e.g. partial TPKs), therefore this
+/// iterator may return `None` for the primary key's signature.
+///
+/// A valid `Key` has at least one good self-signature.
+///
+/// Compare with `pgp_tpk_keys_iter_all`, which doesn't filter out
+/// expired and revoked keys.
/*/
-pgp_tpk_key_iter_t pgp_tpk_key_iter (pgp_tpk_t tpk);
+pgp_tpk_key_iter_t pgp_tpk_keys_iter_valid (pgp_tpk_t tpk);
/*/
/// Returns the TPK's primary user id (if any).
diff --git a/openpgp-ffi/src/tpk.rs b/openpgp-ffi/src/tpk.rs
index 1483c71c..39315565 100644
--- a/openpgp-ffi/src/tpk.rs
+++ b/openpgp-ffi/src/tpk.rs
@@ -437,19 +437,51 @@ pub extern "system" fn pgp_user_id_binding_iter_next<'a>(
pub struct KeyIterWrapper<'a> {
iter: KeyIter<'a>,
rso: Option<RevocationStatus<'a>>,
+ // Whether next has been called.
+ next_called: bool,
}
-/// Returns an iterator over the TPK's keys.
+/// Returns an iterator over the TPK's live, non-revoked keys.
///
-/// This iterates over both the primary key and any subkeys.
+/// That is, this returns an iterator over the primary key and any
+/// subkeys, along with the corresponding signatures.
+///
+/// Note: since a primary key is different from a subkey, the iterator
+/// is over `Key`s and not `SubkeyBindings`. Since the primary key
+/// has no binding signature, the signature carrying the primary key's
+/// key flags is returned (either a direct key signature, or the
+/// self-signature on the primary User ID). There are corner cases
+/// where no such signature exists (e.g. partial TPKs), therefore this
+/// iterator may return `None` for the primary key's signature.
+///
+/// A valid `Key` has at least one good self-signature.
+///
+/// To return all keys, use `pgp_tpk_keys_all_iter()`.
+#[::sequoia_ffi_macros::extern_fn] #[no_mangle]
+pub extern "system" fn pgp_tpk_keys_iter_valid(tpk: *const TPK)
+ -> *mut KeyIterWrapper<'static>
+{
+ let tpk = tpk.ref_raw();
+ box_raw!(KeyIterWrapper {
+ iter: tpk.keys_valid(),
+ rso: None,
+ next_called: false,
+ })
+}
+
+/// Returns an iterator over all `Key`s in a TPK.
+///
+/// Compare with `pgp_tpk_keys_iter_all`, which doesn't filter out
+/// expired and revoked keys by default.
#[::sequoia_ffi_macros::extern_fn] #[no_mangle]
-pub extern "system" fn pgp_tpk_key_iter(tpk: *const TPK)
+pub extern "system" fn pgp_tpk_keys_iter_all(tpk: *const TPK)
-> *mut KeyIterWrapper<'static>
{
let tpk = tpk.ref_raw();
box_raw!(KeyIterWrapper {
- iter: tpk.keys(),
+ iter: tpk.keys_all(),
rso: None,
+ next_called: false,
})
}
@@ -461,6 +493,151 @@ pub extern "system" fn pgp_tpk_key_iter_free(
ffi_free!(iter)
}
+/// Changes the iterator to only return keys that are certification
+/// capable.
+///
+/// If you call this function and, e.g., the `signing_capable`
+/// function, the *union* of the values is used. That is, the
+/// iterator will return keys that are certification capable *or*
+/// signing capable.
+///
+/// Note: you may not call this function after starting to iterate.
+#[::sequoia_ffi_macros::extern_fn] #[no_mangle]
+pub extern "system" fn pgp_tpk_key_iter_certification_capable<'a>(
+ iter_wrapper: *mut KeyIterWrapper<'a>)
+{
+ let iter_wrapper = ffi_param_ref_mut!(iter_wrapper);
+ if iter_wrapper.next_called {
+ panic!("Can't change KeyIter filter after iterating.");
+ }
+
+ use std::mem;
+ let tmp = mem::replace(&mut iter_wrapper.iter, KeyIter::empty());
+ iter_wrapper.iter = tmp.certification_capable();
+}
+
+/// Changes the iterator to only return keys that are certification
+/// capable.
+///
+/// If you call this function and, e.g., the `signing_capable`
+/// function, the *union* of the values is used. That is, the
+/// iterator will return keys that are certification capable *or*
+/// signing capable.
+///
+/// Note: you may not call this function after starting to iterate.
+#[::sequoia_ffi_macros::extern_fn] #[no_mangle]
+pub extern "system" fn pgp_tpk_key_iter_signing_capable<'a>(
+ iter_wrapper: *mut KeyIterWrapper<'a>)
+{
+ let iter_wrapper = ffi_param_ref_mut!(iter_wrapper);
+ if iter_wrapper.next_called {
+ panic!("Can't change KeyIter filter after iterating.");
+ }
+
+ use std::mem;
+ let tmp = mem::replace(&mut iter_wrapper.iter, KeyIter::empty());
+ iter_wrapper.iter = tmp.signing_capable();
+}
+
+/// Changes the iterator to only return keys that are alive.
+///
+/// If you call this function (or `pgp_tpk_key_iter_alive_at`), only
+/// the last value is used.
+///
+/// Note: you may not call this function after starting to iterate.
+#[::sequoia_ffi_macros::extern_fn] #[no_mangle]
+pub extern "system" fn pgp_tpk_key_iter_alive<'a>(
+ iter_wrapper: *mut KeyIterWrapper<'a>)
+{
+ let iter_wrapper = ffi_param_ref_mut!(iter_wrapper);
+ if iter_wrapper.next_called {
+ panic!("Can't change KeyIter filter after iterating.");
+ }
+
+ use std::mem;
+ let tmp = mem::replace(&mut iter_wrapper.iter, KeyIter::empty());
+ iter_wrapper.iter = tmp.alive();
+}
+
+/// Changes the iterator to only return keys that are alive at the
+/// specified time.
+///
+/// If you call this function (or `pgp_tpk_key_iter_alive`), only the
+/// last value is used.
+///
+/// Note: you may not call this function after starting to iterate.
+#[::sequoia_ffi_macros::extern_fn] #[no_mangle]
+pub extern "system" fn pgp_tpk_key_iter_alive_at<'a>(
+ iter_wrapper: *mut KeyIterWrapper<'a>,
+ when: time_t)
+{
+ let iter_wrapper = ffi_param_ref_mut!(iter_wrapper);
+ if iter_wrapper.next_called {
+ panic!("Can't change KeyIter filter after iterating.");
+ }
+
+ use std::mem;
+ let tmp = mem::replace(&mut iter_wrapper.iter, KeyIter::empty());
+ iter_wrapper.iter = tmp.alive_at(time::at(time::Timespec::new(when as i64, 0)));
+}
+
+/// Changes the iterator to only return keys whose revocation status
+/// matches `revoked`.
+///
+/// Note: you may not call this function after starting to iterate.
+#[::sequoia_ffi_macros::extern_fn] #[no_mangle]
+pub extern "system" fn pgp_tpk_key_iter_revoked<'a>(
+ iter_wrapper: *mut KeyIterWrapper<'a>,
+ revoked: bool)
+{
+ let iter_wrapper = ffi_param_ref_mut!(iter_wrapper);
+ if iter_wrapper.next_called {
+ panic!("Can't change KeyIter filter after iterating.");
+ }
+
+ use std::mem;
+ let tmp = mem::replace(&mut iter_wrapper.iter, KeyIter::empty());
+ iter_wrapper.iter = tmp.revoked(Some(revoked));
+}
+
+/// Changes the iterator to only return keys that have secret keys (or
+/// not).
+///
+/// Note: you may not call this function after starting to iterate.
+#[::sequoia_ffi_macros::extern_fn] #[no_mangle]
+pub extern "system" fn pgp_tpk_key_iter_secret<'a>(
+ iter_wrapper: *mut KeyIterWrapper<'a>,
+ secret: bool)
+{
+ let iter_wrapper = ffi_param_ref_mut!(iter_wrapper);
+ if iter_wrapper.next_called {
+ panic!("Can't change KeyIter filter after iterating.");
+ }
+
+ use std::mem;
+ let tmp = mem::replace(&mut iter_wrapper.iter, KeyIter::empty());
+ iter_wrapper.iter = tmp.secret(Some(secret));
+}
+
+/// Changes the iterator to only return keys that have unencrypted
+/// secret keys (or not).
+///
+/// Note: you may not call this function after starting to iterate.
+#[::sequoia_ffi_macros::extern_fn] #[no_mangle]
+pub extern "system" fn pgp_tpk_key_iter_unencrypted_secret<'a>(
+ iter_wrapper: *mut KeyIterWrapper<'a>,
+ unencrypted_secret: bool)
+{
+ let iter_wrapper = ffi_param_ref_mut!(iter_wrapper);
+ if iter_wrapper.next_called {
+ panic!("Can't change KeyIter filter after iterating.");
+ }
+
+ use std::mem;
+ let tmp = mem::replace(&mut iter_wrapper.iter, KeyIter::empty());
+ iter_wrapper.iter = tmp.unencrypted_secret(Some(unencrypted_secret));
+}
+
/// Returns the next key. Returns NULL if there are no more elements.
///
/// If sigo is not NULL, stores the current self-signature (if any) in
@@ -479,6 +656,7 @@ pub extern "system" fn pgp_tpk_key_iter_next<'a>(
{
let iter_wrapper = ffi_param_ref_mut!(iter_wrapper);
iter_wrapper.rso = None;
+ iter_wrapper.next_called = true;
if let Some((sig, rs, key)) = iter_wrapper.iter.next() {
if let Some(ptr) = sigo {
diff --git a/openpgp/examples/decrypt-with.rs b/openpgp/examples/decrypt-with.rs
index 176e03de..a5b26baa 100644
--- a/openpgp/examples/decrypt-with.rs
+++ b/openpgp/examples/decrypt-with.rs
@@ -57,7 +57,7 @@ impl Helper {
// Map (sub)KeyIDs to secrets.
let mut keys = HashMap::new();
for tpk in tpks {
- for (sig, _, key) in tpk.keys() {
+ for (sig, _, key) in tpk.keys_all() {
if sig.map(|s| (s.key_flags().can_encrypt_at_rest()
|| s.key_flags().can_encrypt_for_transport()))
.unwrap_or(false)
diff --git a/openpgp/examples/notarize.rs b/openpgp/examples/notarize.rs
index 5214ad9e..1b849376 100644
--- a/openpgp/examples/notarize.rs
+++ b/openpgp/examples/notarize.rs
@@ -30,7 +30,7 @@ fn main() {
let tsk = openpgp::TPK::from_file(filename)
.expect("Failed to read key");
- for key in tsk.select_signing_keys(None) {
+ for key in tsk.keys_valid().signing_capable().map(|k| k.2) {
if let Some(mut secret) = key.secret() {
let secret_mpis = match secret {
SecretKey::Encrypted { .. } => {
diff --git a/openpgp/examples/sign-detached.rs b/openpgp/examples/sign-detached.rs
index 19dc771f..e558aa5e 100644
--- a/openpgp/examples/sign-detached.rs
+++ b/openpgp/examples/sign-detached.rs
@@ -25,7 +25,7 @@ fn main() {
let tsk = openpgp::TPK::from_file(filename)
.expect("Failed to read key");
- for key in tsk.select_signing_keys(None) {
+ for key in tsk.keys_valid().signing_capable().map(|k| k.2) {
if let Some(mut secret) = key.secret() {
let secret_mpis = match secret {
SecretKey::Encrypted { .. } => {
diff --git a/openpgp/examples/sign.rs b/openpgp/examples/sign.rs
index c3ee0728..33e7625e 100644
--- a/openpgp/examples/sign.rs
+++ b/openpgp/examples/sign.rs
@@ -25,7 +25,7 @@ fn main() {
let tsk = openpgp::TPK::from_file(filename)
.expect("Failed to read key");
- for key in tsk.select_signing_keys(None) {
+ for key in tsk.keys_valid().signing_capable().map(|k| k.2) {
if let Some(mut secret) = key.secret() {
let secret_mpis = match secret {
SecretKey::Encrypted { .. } => {
diff --git a/openpgp/src/crypto/keygrip.rs b/openpgp/src/crypto/keygrip.rs
index 50a2448c..3d1a84bd 100644
--- a/openpgp/src/crypto/keygrip.rs
+++ b/openpgp/src/crypto/keygrip.rs
@@ -340,7 +340,7 @@ mod tests {
.iter().map(|n| (n, ::TPK::from_file(path_to(n)).unwrap()))
{
eprintln!("{}", name);
- for key in tpk.keys() {
+ for key in tpk.keys_all() {
let fp = key.2.fingerprint();
eprintln!("(sub)key: {}", fp);
assert_eq!(&key.2.mpis().keygrip().unwrap(),
diff --git a/openpgp/src/packet/key_flags.rs b/openpgp/src/packet/key_flags.rs
index 92dac82f..51f9e00d 100644
--- a/openpgp/src/packet/key_flags.rs
+++ b/openpgp/src/packet/key_flags.rs
@@ -156,6 +156,11 @@ impl KeyFlags {
}
}
+ /// Returns a new `KeyFlags` with all capabilities disabled.
+ pub fn empty() -> Self {
+ KeyFlags::default()
+ }
+
/// Returns a slice referencing the raw values.
pub(crate) fn as_vec(&self) -> Vec<u8> {
let mut ret = if self.unknown.is_empty() {
@@ -249,6 +254,11 @@ impl KeyFlags {
self.is_group_key = v;
self
}
+
+ /// Returns whether no flags are set.
+ pub fn is_empty(&self) -> bool {
+ self.as_vec().into_iter().all(|b| b == 0)
+ }
}
// Numeric key capability flags.
diff --git a/openpgp/src/packet/signature/mod.rs b/openpgp/src/packet/signature/mod.rs
index 2d877c56..8097d149 100644
--- a/openpgp/src/packet/signature/mod.rs
+++ b/openpgp/src/packet/signature/mod.rs
@@ -1094,12 +1094,15 @@ mod test {
#[test]
fn verify_gpg_3rd_party_cert() {
- use {packet::KeyFlags, TPK};
+ use TPK;
- let cert_kf = KeyFlags::default().set_certify(true);
let test1 = TPK::from_file(
path_to("keys/test1-certification-key.pgp")).unwrap();
- let cert_key1 = test1.select_keys(cert_kf, None)[0];
+ let cert_key1 = test1.keys_all()
+ .certification_capable()
+ .nth(0)
+ .map(|x| x.2)
+ .unwrap();
let test2 = TPK::from_file(
path_to("keys/test2-signed-by-test1.pgp")).unwrap();
let uid_binding = &test2.primary_key_signature_full().unwrap().0.unwrap();
diff --git a/openpgp/src/parse/stream.rs b/openpgp/src/parse/stream.rs
index a89d61a3..fcea6038 100644
--- a/openpgp/src/parse/stream.rs
+++ b/openpgp/src/parse/stream.rs
@@ -118,7 +118,7 @@ const BUFFER_SIZE: usize = 25 * 1024 * 1024;
pub struct Verifier<'a, H: VerificationHelper> {
helper: H,
tpks: Vec<TPK>,
- /// Maps KeyID to tpks[i].keys().nth(j).
+ /// Maps KeyID to tpks[i].keys_all().nth(j).
keys: HashMap<KeyID, (usize, usize)>,
oppr: Option<PacketParserResult<'a>>,
sigs: Vec<Vec<VerificationResult>>,
@@ -350,7 +350,8 @@ impl<'a, H: VerificationHelper> Verifier<'a, H> {
if let Some(issuer) = sig.get_issuer() {
if let Some((i, j)) = self.keys.get(&issuer) {
- let (_, _, key) = self.tpks[*i].keys().nth(*j).unwrap();
+ let (_, _, key)
+ = self.tpks[*i].keys_all().nth(*j).unwrap();
if sig.verify(key).unwrap_or(false) {
self.sigs.iter_mut().last()
.expect("sigs is never empty").push(
@@ -808,7 +809,7 @@ impl DetachedVerifier {
pub struct Decryptor<'a, H: VerificationHelper + DecryptionHelper> {
helper: H,
tpks: Vec<TPK>,
- /// Maps KeyID to tpks[i].keys().nth(j).
+ /// Maps KeyID to tpks[i].keys_all().nth(j).
keys: HashMap<KeyID, (usize, usize)>,
oppr: Option<PacketParserResult<'a>>,
identity: Option<Fingerprint>,
@@ -1167,7 +1168,8 @@ impl<'a, H: VerificationHelper + DecryptionHelper> Decryptor<'a, H> {
if let Some(issuer) = sig.get_issuer() {
if let Some((i, j)) = self.keys.get(&issuer) {
- let (_, _, key) = self.tpks[*i].keys().nth(*j).unwrap();
+ let (_, _, key)
+ = self.tpks[*i].keys_all().nth(*j).unwrap();
if sig.verify(key).unwrap_or(false) {
self.sigs.iter_mut().last()
.expect("sigs is never empty").push(
@@ -1488,7 +1490,7 @@ mod test {
// sign 30MiB message
let mut buf = vec![];
{
- let key = tpk.select_signing_keys(None)[0];
+ let key = tpk.keys_all().signing_capable().nth(0).unwrap().2;
let sec = match key.secret() {
Some(SecretKey::Unencrypted { ref mpis }) => mpis,
_ => unreachable!(),
diff --git a/openpgp/src/serialize/stream.rs b/openpgp/src/serialize/stream.rs
index 5e88db65..1d3c79e1 100644
--- a/openpgp/src/serialize/stream.rs
+++ b/openpgp/src/serialize/stream.rs
@@ -228,7 +228,7 @@ impl<'a> Signer<'a> {
/// # let tsk = TPK::from_bytes(include_bytes!(
/// # "../../tests/data/keys/testy-new-private.pgp"))
/// # .unwrap();
- /// # let key = tsk.select_signing_keys(None)[0];
+ /// # let key = tsk.keys_valid().signing_capable().nth(0).unwrap().2;
/// # let sec = match key.secret() {
/// # Some(SecretKey::Unencrypted { ref mpis }) => mpis,
/// # _ => unreachable!(),
@@ -284,7 +284,7 @@ impl<'a> Signer<'a> {
/// # let tsk = TPK::from_bytes(include_bytes!(
/// # "../../tests/data/keys/testy-new-private.pgp"))
/// # .unwrap();
- /// # let key = tsk.select_signing_keys(None)[0];
+ /// # let key = tsk.keys_valid().signing_capable().nth(0).unwrap().2;
/// # let sec = match key.secret() {
/// # Some(SecretKey::Unencrypted { ref mpis }) => mpis,
/// # _ => unreachable!(),
@@ -1282,7 +1282,6 @@ mod test {
#[test]
fn signature() {
use crypto::KeyPair;
- use packet::KeyFlags;
use packet::key::SecretKey;
use std::collections::HashMap;
use Fingerprint;
@@ -1292,8 +1291,7 @@ mod test {
TPK::from_bytes(bytes!("keys/testy-private.pgp")).unwrap(),
TPK::from_bytes(bytes!("keys/testy-new-private.pgp")).unwrap(),
] {
- for key in tsk.select_keys(
- KeyFlags::default().set_sign(true), None)
+ for key in tsk.keys_all().signing_capable().map(|x| x.2)
{
keys.insert(key.fingerprint(), key.clone());
}
diff --git a/openpgp/src/tpk/mod.rs b/openpgp/src/tpk/mod.rs
index eca1448b..394f9922 100644
--- a/openpgp/src/tpk/mod.rs
+++ b/openpgp/src/tpk/mod.rs
@@ -20,6 +20,7 @@ use {
packet::Tag,
packet::signature::{self, Signature},
packet::Key,
+ packet::key::SecretKey,
packet::UserID,
packet::UserAttribute,
packet::Unknown,
@@ -861,32 +862,312 @@ pub struct UnknownBinding {
/// in a TPK.
///
/// Returned by TPK::keys().
+///
+/// `KeyIter` follows the builder pattern. There is no need to
+/// explicitly finalize it, however: it already implements the
+/// `Iterator` interface.
+///
+/// By default, `KeyIter` will only return live, non-revoked keys. It
+/// is possible to control how `KeyIter` filters using, for instance,
+/// `KeyIter::flags` to only return keys with particular flags set.
pub struct KeyIter<'a> {
- tpk: &'a TPK,
+ // This is an option to make it easier to create an empty KeyIter.
+ tpk: Option<&'a TPK>,
primary: bool,
subkey_iter: SubkeyBindingIter<'a>,
+
+ // If not None, only returns keys with the specified flags.
+ flags: Option<KeyFlags>,
+
+ // If not None, only returns keys that are live at the specified
+ // time.
+ alive_at: Option<time::Tm>,
+
+ // If not None, filters by revocation status.
+ revoked: Option<bool>,
+
+ // If not None, filters by whether a key has a secret.
+ secret: Option<bool>,
+
+ // If not None, filters by whether a key has an unencrypted
+ // secret.
+ unencrypted_secret: Option<bool>,
+}
+
+impl<'a> fmt::Debug for KeyIter<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("KeyIter")
+ .field("flags", &self.flags)
+ .field("alive_at", &self.alive_at)
+ .field("revoked", &self.revoked)
+ .field("secret", &self.secret)
+ .field("unencrypted_secret", &self.unencrypted_secret)
+ .finish()
+ }
}
impl<'a> Iterator for KeyIter<'a> {
type Item = (Option<&'a Signature>, RevocationStatus<'a>, &'a Key);
fn next(&m