summaryrefslogtreecommitdiffstats
path: root/openpgp-ffi
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 /openpgp-ffi
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.
Diffstat (limited to 'openpgp-ffi')
-rw-r--r--openpgp-ffi/include/sequoia/openpgp.h103
-rw-r--r--openpgp-ffi/src/tpk.rs186
2 files changed, 282 insertions, 7 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 {