diff options
author | Neal H. Walfield <neal@pep.foundation> | 2019-03-14 09:20:10 +0100 |
---|---|---|
committer | Neal H. Walfield <neal@pep.foundation> | 2019-03-14 14:56:47 +0100 |
commit | 1434843469109127f41c5dbd8aacf5400c537759 (patch) | |
tree | 0ca324cad8a486def769000eb460a13bd51473c4 /openpgp-ffi | |
parent | 6bea117391c1813e956e384c6638b7b0311d8d7c (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.h | 103 | ||||
-rw-r--r-- | openpgp-ffi/src/tpk.rs | 186 |
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 { |