From 7e78e716610ac3a9bff86035c52b344b437951a2 Mon Sep 17 00:00:00 2001 From: "Neal H. Walfield" Date: Mon, 6 Jan 2020 10:29:13 +0100 Subject: openpgp: Pass a timestamp to the KeyIter instead of each filter. - KeyIter::revoked and KeyIter::key_flags (and its variants) didn't take a time stamp so they could only be used for filtering keys based on their current state, not their state at some time in the past. Adding a time stamp to each of the filters would have fixed the problem, but it would have made the interface ugly: callers always want the same time stamp for all filters. - Split KeyIter into two structures: a KeyIter and a ValidKeyIter. - Add KeyIter::policy. It takes a time stamp, which is then used for filters like `alive` and `revoked`, and it returns a ValidKeyIter, which exposes filters that require a time stamp. --- guide/src/chapter_01.md | 8 +- guide/src/chapter_02.md | 8 +- ipc/examples/gpg-agent-decrypt.rs | 2 +- ipc/examples/gpg-agent-sign.rs | 7 +- ipc/tests/gpg-agent.rs | 8 +- net/src/lib.rs | 4 +- openpgp-ffi/examples/decrypt-with.c | 2 +- openpgp-ffi/examples/encrypt-for.c | 12 +- openpgp-ffi/include/sequoia/openpgp.h | 84 ++++-- openpgp-ffi/include/sequoia/openpgp/serialize.h | 8 + openpgp-ffi/include/sequoia/openpgp/types.h | 5 + openpgp-ffi/src/cert.rs | 230 ++++++++++---- openpgp-ffi/src/serialize.rs | 32 ++ openpgp/examples/decrypt-with.rs | 2 +- openpgp/examples/encrypt-for.rs | 3 +- openpgp/examples/generate-encrypt-decrypt.rs | 4 +- openpgp/examples/generate-sign-verify.rs | 4 +- openpgp/examples/notarize.rs | 5 +- openpgp/examples/pad.rs | 7 +- openpgp/examples/sign-detached.rs | 5 +- openpgp/examples/sign.rs | 5 +- openpgp/src/cert/bindings.rs | 4 +- openpgp/src/cert/builder.rs | 10 +- openpgp/src/cert/keyiter.rs | 386 ++++++++++++++++++------ openpgp/src/cert/mod.rs | 2 +- openpgp/src/crypto/keygrip.rs | 2 +- openpgp/src/crypto/mpis.rs | 2 +- openpgp/src/packet/signature/mod.rs | 2 +- openpgp/src/parse/stream.rs | 6 +- openpgp/src/serialize/cert.rs | 4 +- openpgp/src/serialize/stream.rs | 19 +- sqv/src/sqv.rs | 4 +- store/src/backend/mod.rs | 2 +- tool/src/commands/mod.rs | 10 +- tool/tests/sq-sign.rs | 2 +- 35 files changed, 638 insertions(+), 262 deletions(-) diff --git a/guide/src/chapter_01.md b/guide/src/chapter_01.md index 56c131fb..78978161 100644 --- a/guide/src/chapter_01.md +++ b/guide/src/chapter_01.md @@ -51,7 +51,7 @@ fn main() { # fn sign(sink: &mut Write, plaintext: &str, tsk: &openpgp::Cert) # -> openpgp::Result<()> { # // Get the keypair to do the signing from the Cert. -# let keypair = tsk.keys().alive().revoked(false).for_signing().nth(0).unwrap(). +# let keypair = tsk.keys().policy(None).alive().revoked(false).for_signing().nth(0).unwrap(). # key().clone().mark_parts_secret().unwrap().into_keypair()?; # # // Start streaming an OpenPGP message. @@ -196,7 +196,7 @@ fn generate() -> openpgp::Result { # fn sign(sink: &mut Write, plaintext: &str, tsk: &openpgp::Cert) # -> openpgp::Result<()> { # // Get the keypair to do the signing from the Cert. -# let keypair = tsk.keys().alive().revoked(false).for_signing().nth(0).unwrap(). +# let keypair = tsk.keys().policy(None).alive().revoked(false).for_signing().nth(0).unwrap(). # key().clone().mark_parts_secret().unwrap().into_keypair()?; # # // Start streaming an OpenPGP message. @@ -341,7 +341,7 @@ implements [`io::Write`], and we simply write the plaintext to it. fn sign(sink: &mut Write, plaintext: &str, tsk: &openpgp::Cert) -> openpgp::Result<()> { // Get the keypair to do the signing from the Cert. - let keypair = tsk.keys().alive().revoked(false).for_signing().nth(0).unwrap(). + let keypair = tsk.keys().policy(None).alive().revoked(false).for_signing().nth(0).unwrap(). key().clone().mark_parts_secret().unwrap().into_keypair()?; // Start streaming an OpenPGP message. @@ -497,7 +497,7 @@ Verified data can be read from this using [`io::Read`]. # fn sign(sink: &mut Write, plaintext: &str, tsk: &openpgp::Cert) # -> openpgp::Result<()> { # // Get the keypair to do the signing from the Cert. -# let keypair = tsk.keys().alive().revoked(false).for_signing().nth(0).unwrap(). +# let keypair = tsk.keys().policy(None).alive().revoked(false).for_signing().nth(0).unwrap(). # key().clone().mark_parts_secret().unwrap().into_keypair()?; # # // Start streaming an OpenPGP message. diff --git a/guide/src/chapter_02.md b/guide/src/chapter_02.md index 9f4c3a0a..f6cb4b48 100644 --- a/guide/src/chapter_02.md +++ b/guide/src/chapter_02.md @@ -51,7 +51,7 @@ fn main() { # -> openpgp::Result<()> { # // Build a vector of recipients to hand to Encryptor. # let mut recipients = -# recipient.keys().alive().revoked(false) +# recipient.keys().policy(None).alive().revoked(false) # .for_transport_encryption() # .map(|ka| ka.key().into()) # .collect::>(); @@ -192,7 +192,7 @@ fn generate() -> openpgp::Result { # -> openpgp::Result<()> { # // Build a vector of recipients to hand to Encryptor. # let mut recipients = -# recipient.keys().alive().revoked(false) +# recipient.keys().policy(None).alive().revoked(false) # .for_transport_encryption() # .map(|ka| ka.key().into()) # .collect::>(); @@ -333,7 +333,7 @@ fn encrypt(sink: &mut Write, plaintext: &str, recipient: &openpgp::Cert) -> openpgp::Result<()> { // Build a vector of recipients to hand to Encryptor. let mut recipients = - recipient.keys().alive().revoked(false) + recipient.keys().policy(None).alive().revoked(false) .for_transport_encryption() .map(|ka| ka.key().into()) .collect::>(); @@ -488,7 +488,7 @@ Decrypted data can be read from this using [`io::Read`]. # -> openpgp::Result<()> { # // Build a vector of recipients to hand to Encryptor. # let mut recipients = -# recipient.keys().alive().revoked(false) +# recipient.keys().policy(None).alive().revoked(false) # .for_transport_encryption() # .map(|ka| ka.key().into()) # .collect::>(); diff --git a/ipc/examples/gpg-agent-decrypt.rs b/ipc/examples/gpg-agent-decrypt.rs index 2b9252cc..0f824d60 100644 --- a/ipc/examples/gpg-agent-decrypt.rs +++ b/ipc/examples/gpg-agent-decrypt.rs @@ -74,7 +74,7 @@ impl<'a> Helper<'a> { // Map (sub)KeyIDs to secrets. let mut keys = HashMap::new(); for cert in certs { - for ka in cert.keys() { + for ka in cert.keys().policy(None) { if ka.binding_signature(None) .map(|s| (s.key_flags().for_storage_encryption() || s.key_flags().for_transport_encryption())) diff --git a/ipc/examples/gpg-agent-sign.rs b/ipc/examples/gpg-agent-sign.rs index b5f32a9c..a80f3935 100644 --- a/ipc/examples/gpg-agent-sign.rs +++ b/ipc/examples/gpg-agent-sign.rs @@ -39,9 +39,10 @@ fn main() { // Construct a KeyPair for every signing-capable (sub)key. let mut signers = certs.iter().flat_map(|cert| { - cert.keys().alive().revoked(false).for_signing().filter_map(|ka| { - KeyPair::new(&ctx, ka.key()).ok() - }) + cert.keys().policy(None).alive().revoked(false).for_signing() + .filter_map(|ka| { + KeyPair::new(&ctx, ka.key()).ok() + }) }).collect::>(); // Compose a writer stack corresponding to the output format and diff --git a/ipc/tests/gpg-agent.rs b/ipc/tests/gpg-agent.rs index 889402b5..b76a24d9 100644 --- a/ipc/tests/gpg-agent.rs +++ b/ipc/tests/gpg-agent.rs @@ -96,7 +96,7 @@ fn sign() { let keypair = KeyPair::new( &ctx, - cert.keys().alive().revoked(false) + cert.keys().policy(None).alive().revoked(false) .for_signing().take(1).next().unwrap().key()) .unwrap(); @@ -210,7 +210,7 @@ fn decrypt() { let mut message = Vec::new(); { let recipient = - cert.keys().alive().revoked(false) + cert.keys().policy(None).alive().revoked(false) .key_flags( KeyFlags::default().set_transport_encryption(true)) .map(|ka| ka.key().into()) @@ -278,8 +278,8 @@ fn decrypt() { { let mut keypair = KeyPair::new( self.ctx, - self.cert.keys().alive().revoked(false). - key_flags( + self.cert.keys().policy(None).alive().revoked(false) + .key_flags( KeyFlags::default().set_transport_encryption(true)) .take(1).next().unwrap().key()) .unwrap(); diff --git a/net/src/lib.rs b/net/src/lib.rs index f7add939..048031fe 100644 --- a/net/src/lib.rs +++ b/net/src/lib.rs @@ -182,8 +182,8 @@ impl KeyServer { Some(armor::Kind::PublicKey))); match Cert::from_reader(r) { Ok(cert) => { - if cert.keys().any(|ka| { - KeyID::from(ka.key().fingerprint()) + if cert.keys().any(|key| { + KeyID::from(key.fingerprint()) == keyid_want }) { future::done(Ok(cert)) diff --git a/openpgp-ffi/examples/decrypt-with.c b/openpgp-ffi/examples/decrypt-with.c index c85b96f8..d395abd9 100644 --- a/openpgp-ffi/examples/decrypt-with.c +++ b/openpgp-ffi/examples/decrypt-with.c @@ -157,7 +157,7 @@ decrypt_cb (void *cookie_opaque, pgp_cert_key_iter_t key_iter = pgp_cert_key_iter (cookie->key); pgp_key_t key; - while ((key = pgp_cert_key_iter_next (key_iter, NULL, NULL))) { + while ((key = pgp_cert_key_iter_next (key_iter))) { pgp_keyid_t this_keyid = pgp_key_keyid (key); int match = pgp_keyid_equal (this_keyid, keyid); pgp_keyid_free (this_keyid); diff --git a/openpgp-ffi/examples/encrypt-for.c b/openpgp-ffi/examples/encrypt-for.c index 65bd8a45..aeb4dea4 100644 --- a/openpgp-ffi/examples/encrypt-for.c +++ b/openpgp-ffi/examples/encrypt-for.c @@ -36,14 +36,14 @@ main (int argc, char **argv) if (cert == NULL) error (1, 0, "pgp_cert_from_file: %s", pgp_error_to_string (err)); - pgp_cert_key_iter_t iter = pgp_cert_key_iter (cert); - pgp_cert_key_iter_alive (iter); - pgp_cert_key_iter_revoked (iter, false); - pgp_cert_key_iter_for_storage_encryption (iter); - pgp_cert_key_iter_for_transport_encryption (iter); + pgp_cert_valid_key_iter_t iter = pgp_cert_valid_key_iter (cert, 0); + pgp_cert_valid_key_iter_alive (iter); + pgp_cert_valid_key_iter_revoked (iter, false); + pgp_cert_valid_key_iter_for_storage_encryption (iter); + pgp_cert_valid_key_iter_for_transport_encryption (iter); size_t recipients_len; pgp_recipient_t *recipients = - pgp_recipients_from_key_iter (iter, &recipients_len); + pgp_recipients_from_valid_key_iter (iter, &recipients_len); sink = pgp_writer_from_fd (STDOUT_FILENO); diff --git a/openpgp-ffi/include/sequoia/openpgp.h b/openpgp-ffi/include/sequoia/openpgp.h index 4468ccb5..1a27fad9 100644 --- a/openpgp-ffi/include/sequoia/openpgp.h +++ b/openpgp-ffi/include/sequoia/openpgp.h @@ -606,6 +606,41 @@ void pgp_user_id_binding_iter_free (pgp_user_id_binding_iter_t iter); /* openpgp::cert::KeyIter. */ +/*/ +/// Changes the iterator to only return keys that have secret keys. +/// +/// Note: you may not call this function after starting to iterate. +/*/ +void pgp_cert_key_iter_secret (pgp_cert_key_iter_t iter); + +/*/ +/// Changes the iterator to only return keys that have unencrypted +/// secret keys. +/// +/// Note: you may not call this function after starting to iterate. +/*/ +void pgp_cert_key_iter_unencrypted_secret (pgp_cert_key_iter_t iter); + +/*/ +/// Changes the iterator to only return keys that have unencrypted +/// secret keys. +/// +/// Note: you may not call this function after starting to iterate. +/*/ +pgp_cert_valid_key_iter_t pgp_cert_key_iter_policy + (pgp_cert_key_iter_t iter, time_t when); + +/*/ +/// Returns a reference to the next key. Returns NULL if there are no +/// more elements. +/*/ +pgp_key_t pgp_cert_key_iter_next (pgp_cert_key_iter_t iter); + +/*/ +/// Frees an pgp_cert_key_iter_t. +/*/ +void pgp_cert_key_iter_free (pgp_cert_key_iter_t iter); + /*/ /// Changes the iterator to only return keys that are certification /// capable. @@ -617,7 +652,7 @@ void pgp_user_id_binding_iter_free (pgp_user_id_binding_iter_t iter); /// /// Note: you may not call this function after starting to iterate. /*/ -void pgp_cert_key_iter_for_certification (pgp_cert_key_iter_t iter); +void pgp_cert_valid_key_iter_for_certification (pgp_cert_valid_key_iter_t iter); /*/ /// Changes the iterator to only return keys that are certification @@ -630,7 +665,7 @@ void pgp_cert_key_iter_for_certification (pgp_cert_key_iter_t iter); /// /// Note: you may not call this function after starting to iterate. /*/ -void pgp_cert_key_iter_for_signing (pgp_cert_key_iter_t iter); +void pgp_cert_valid_key_iter_for_signing (pgp_cert_valid_key_iter_t iter); /*/ /// Changes the iterator to only return keys that are capable of @@ -643,7 +678,7 @@ void pgp_cert_key_iter_for_signing (pgp_cert_key_iter_t iter); /// /// Note: you may not call this function after starting to iterate. /*/ -void pgp_cert_key_iter_for_storage_encryption (pgp_cert_key_iter_t); +void pgp_cert_valid_key_iter_for_storage_encryption (pgp_cert_valid_key_iter_t); /*/ /// Changes the iterator to only return keys that are capable of @@ -656,28 +691,16 @@ void pgp_cert_key_iter_for_storage_encryption (pgp_cert_key_iter_t); /// /// Note: you may not call this function after starting to iterate. /*/ -void pgp_cert_key_iter_for_transport_encryption (pgp_cert_key_iter_t); +void pgp_cert_valid_key_iter_for_transport_encryption (pgp_cert_valid_key_iter_t); /*/ /// Changes the iterator to only return keys that are alive. /// -/// If you call this function (or `pgp_cert_key_iter_alive_at`), only -/// the last value is used. +/// If you call this function, only the last value is used. /// /// Note: you may not call this function after starting to iterate. /*/ -void pgp_cert_key_iter_alive (pgp_cert_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_cert_key_iter_alive`), only the -/// last value is used. -/// -/// Note: you may not call this function after starting to iterate. -/*/ -void pgp_cert_key_iter_alive_at (pgp_cert_key_iter_t iter, time_t when); +void pgp_cert_valid_key_iter_alive (pgp_cert_valid_key_iter_t iter); /*/ /// Changes the iterator to only return keys whose revocation status @@ -685,14 +708,14 @@ void pgp_cert_key_iter_alive_at (pgp_cert_key_iter_t iter, time_t when); /// /// Note: you may not call this function after starting to iterate. /*/ -void pgp_cert_key_iter_revoked (pgp_cert_key_iter_t iter, bool revoked); +void pgp_cert_valid_key_iter_revoked (pgp_cert_valid_key_iter_t iter, bool revoked); /*/ /// Changes the iterator to only return keys that have secret keys. /// /// Note: you may not call this function after starting to iterate. /*/ -void pgp_cert_key_iter_secret (pgp_cert_key_iter_t iter); +void pgp_cert_valid_key_iter_secret (pgp_cert_valid_key_iter_t iter); /*/ /// Changes the iterator to only return keys that have unencrypted @@ -700,7 +723,7 @@ void pgp_cert_key_iter_secret (pgp_cert_key_iter_t iter); /// /// Note: you may not call this function after starting to iterate. /*/ -void pgp_cert_key_iter_unencrypted_secret (pgp_cert_key_iter_t iter); +void pgp_cert_valid_key_iter_unencrypted_secret (pgp_cert_valid_key_iter_t iter); /*/ /// Returns a reference to the next key. Returns NULL if there are no @@ -714,14 +737,14 @@ void pgp_cert_key_iter_unencrypted_secret (pgp_cert_key_iter_t iter); /// If rev is not NULL, this stores the key's revocation status in /// *rev. /*/ -pgp_key_t pgp_cert_key_iter_next (pgp_cert_key_iter_t iter, - pgp_signature_t *signature, - pgp_revocation_status_t *rev); +pgp_key_t pgp_cert_valid_key_iter_next (pgp_cert_valid_key_iter_t iter, + pgp_signature_t *signature, + pgp_revocation_status_t *rev); /*/ -/// Frees an pgp_cert_key_iter_t. +/// Frees an pgp_cert_valid_key_iter_t. /*/ -void pgp_cert_key_iter_free (pgp_cert_key_iter_t iter); +void pgp_cert_valid_key_iter_free (pgp_cert_valid_key_iter_t iter); /* openpgp::cert. */ @@ -916,6 +939,15 @@ pgp_user_id_binding_iter_t pgp_cert_user_id_binding_iter (pgp_cert_t cert); /*/ pgp_cert_key_iter_t pgp_cert_key_iter (pgp_cert_t cert); +/*/ +/// Returns an iterator over all valid `Key`s in a Cert. +/// +/// That is, this returns an iterator over the primary key and any +/// subkeys that are valid (i.e., have a self-signature at time +/// `when`). +/*/ +pgp_cert_valid_key_iter_t pgp_cert_valid_key_iter (pgp_cert_t cert, time_t when); + /*/ /// Returns the Cert's primary user id (if any). /*/ diff --git a/openpgp-ffi/include/sequoia/openpgp/serialize.h b/openpgp-ffi/include/sequoia/openpgp/serialize.h index 09d62c95..5f9239b5 100644 --- a/openpgp-ffi/include/sequoia/openpgp/serialize.h +++ b/openpgp-ffi/include/sequoia/openpgp/serialize.h @@ -37,4 +37,12 @@ void pgp_recipient_set_keyid (pgp_recipient_t, pgp_keyid_t); /*/ pgp_recipient_t *pgp_recipients_from_key_iter (pgp_cert_key_iter_t, size_t *); +/*/ +/// Collects recipients from a `pgp_cert_valid_key_iter_t`. +/// +/// Consumes the iterator. The returned buffer must be freed using +/// libc's allocator. +/*/ +pgp_recipient_t *pgp_recipients_from_valid_key_iter (pgp_cert_valid_key_iter_t, size_t *); + #endif diff --git a/openpgp-ffi/include/sequoia/openpgp/types.h b/openpgp-ffi/include/sequoia/openpgp/types.h index c0b3bbd7..e85916f3 100644 --- a/openpgp-ffi/include/sequoia/openpgp/types.h +++ b/openpgp-ffi/include/sequoia/openpgp/types.h @@ -378,6 +378,11 @@ typedef struct pgp_user_id_binding_iter *pgp_user_id_binding_iter_t; /*/ typedef struct pgp_cert_key_iter *pgp_cert_key_iter_t; +/*/ +/// An iterator over valid keys in a Cert. +/*/ +typedef struct pgp_cert_valid_key_iter *pgp_cert_valid_key_iter_t; + /*/ /// An OpenPGP Certificate. /// diff --git a/openpgp-ffi/src/cert.rs b/openpgp-ffi/src/cert.rs index 0c91dd88..90aac1ea 100644 --- a/openpgp-ffi/src/cert.rs +++ b/openpgp-ffi/src/cert.rs @@ -26,6 +26,7 @@ use self::openpgp::{ CertRevocationBuilder, UserIDBinding, UserIDBindingIter, + ValidKeyIter, }, }; @@ -459,17 +460,11 @@ pub extern "C" fn pgp_cert_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 `for_signing` -/// function, the *union* of the values is used. That is, the -/// iterator will return keys that are certification capable *or* -/// signing capable. +/// Changes the iterator to only return keys that have secret keys. /// /// Note: you may not call this function after starting to iterate. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] -pub extern "C" fn pgp_cert_key_iter_for_certification<'a>( +pub extern "C" fn pgp_cert_key_iter_secret<'a>( iter_wrapper: *mut KeyIterWrapper<'a>) { let iter_wrapper = ffi_param_ref_mut!(iter_wrapper); @@ -479,20 +474,15 @@ pub extern "C" fn pgp_cert_key_iter_for_certification<'a>( use std::mem; let tmp = mem::replace(&mut iter_wrapper.iter, unsafe { mem::zeroed() }); - iter_wrapper.iter = tmp.for_certification(); + iter_wrapper.iter = unsafe { std::mem::transmute(tmp.secret()) }; } -/// Changes the iterator to only return keys that are certification -/// capable. -/// -/// If you call this function and, e.g., the `for_signing` -/// function, the *union* of the values is used. That is, the -/// iterator will return keys that are certification capable *or* -/// signing capable. +/// Changes the iterator to only return keys that have unencrypted +/// secret keys. /// /// Note: you may not call this function after starting to iterate. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] -pub extern "C" fn pgp_cert_key_iter_for_signing<'a>( +pub extern "C" fn pgp_cert_key_iter_unencrypted_secret<'a>( iter_wrapper: *mut KeyIterWrapper<'a>) { let iter_wrapper = ffi_param_ref_mut!(iter_wrapper); @@ -502,21 +492,19 @@ pub extern "C" fn pgp_cert_key_iter_for_signing<'a>( use std::mem; let tmp = mem::replace(&mut iter_wrapper.iter, unsafe { mem::zeroed() }); - iter_wrapper.iter = tmp.for_signing(); + iter_wrapper.iter = + unsafe { std::mem::transmute(tmp.unencrypted_secret()) }; } -/// Changes the iterator to only return keys that are capable of -/// encrypting data at rest. -/// -/// If you call this function and, e.g., the `for_signing` -/// function, the *union* of the values is used. That is, the -/// iterator will return keys that are certification capable *or* -/// signing capable. +/// Changes the iterator to only return keys that are valid at time +/// `t`. /// /// Note: you may not call this function after starting to iterate. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] -pub extern "C" fn pgp_cert_key_iter_for_storage_encryption<'a>( - iter_wrapper: *mut KeyIterWrapper<'a>) +pub extern "C" fn pgp_cert_key_iter_policy<'a>( + iter_wrapper: *mut KeyIterWrapper<'a>, + when: time_t) + -> *mut ValidKeyIterWrapper<'static> { let iter_wrapper = ffi_param_ref_mut!(iter_wrapper); if iter_wrapper.next_called { @@ -525,11 +513,111 @@ pub extern "C" fn pgp_cert_key_iter_for_storage_encryption<'a>( use std::mem; let tmp = mem::replace(&mut iter_wrapper.iter, unsafe { mem::zeroed() }); - iter_wrapper.iter = tmp.for_storage_encryption(); + + box_raw!(ValidKeyIterWrapper { + iter: unsafe { std::mem::transmute(tmp.policy(maybe_time(when))) }, + next_called: false, + }) } -/// Changes the iterator to only return keys that are capable of -/// encrypting data for transport. +/// 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 +/// *sigo. (Note: subkeys always have signatures, but a primary key +/// may not have a direct signature, and there might not be any user +/// ids.) +/// +/// If rso is not NULL, this stores the key's revocation status in +/// *rso. +#[::sequoia_ffi_macros::extern_fn] #[no_mangle] +pub extern "C" fn pgp_cert_key_iter_next<'a>( + iter_wrapper: *mut KeyIterWrapper<'a>) + -> Maybe +{ + let iter_wrapper = ffi_param_ref_mut!(iter_wrapper); + iter_wrapper.next_called = true; + + if let Some(key) = iter_wrapper.iter.next() { + Some(key.mark_parts_unspecified_ref().mark_role_unspecified_ref()) + .move_into_raw() + } else { + None + } +} + +/// Wraps a ValidKeyIter for export via the FFI. +pub struct ValidKeyIterWrapper<'a> { + pub(crate) // For serialize.rs. + iter: ValidKeyIter<'a, openpgp::packet::key::PublicParts, + openpgp::packet::key::UnspecifiedRole>, + // Whether next has been called. + next_called: bool, +} + +/// Returns an iterator over all valid `Key`s in a Cert. +/// +/// That is, this returns an iterator over the primary key and any +/// subkeys that are valid (i.e., have a self-signature at time +/// `when`). +#[::sequoia_ffi_macros::extern_fn] #[no_mangle] +pub extern "C" fn pgp_cert_valid_key_iter(cert: *const Cert, when: time_t) + -> *mut ValidKeyIterWrapper<'static> +{ + let cert = cert.ref_raw(); + let iter = box_raw!(KeyIterWrapper { + iter: cert.keys(), + next_called: false, + }); + + pgp_cert_key_iter_policy(iter, when) +} + +/// Frees a pgp_cert_key_iter_t. +#[::sequoia_ffi_macros::extern_fn] #[no_mangle] +pub extern "C" fn pgp_cert_valid_key_iter_free( + iter: Option<&mut ValidKeyIterWrapper>) +{ + ffi_free!(iter) +} + +/// Changes the iterator to only return keys that have secret keys. +/// +/// Note: you may not call this function after starting to iterate. +#[::sequoia_ffi_macros::extern_fn] #[no_mangle] +pub extern "C" fn pgp_cert_valid_key_iter_secret<'a>( + iter_wrapper: *mut ValidKeyIterWrapper<'a>) +{ + let iter_wrapper = ffi_param_ref_mut!(iter_wrapper); + if iter_wrapper.next_called { + panic!("Can't change ValidKeyIter filter after iterating."); + } + + use std::mem; + let tmp = mem::replace(&mut iter_wrapper.iter, unsafe { mem::zeroed() }); + iter_wrapper.iter = unsafe { std::mem::transmute(tmp.secret()) }; +} + +/// Changes the iterator to only return keys that have unencrypted +/// secret keys. +/// +/// Note: you may not call this function after starting to iterate. +#[::sequoia_ffi_macros::extern_fn] #[no_mangle] +pub extern "C" fn pgp_cert_valid_key_iter_unencrypted_secret<'a>( + iter_wrapper: *mut ValidKeyIterWrapper<'a>) +{ + let iter_wrapper = ffi_param_ref_mut!(iter_wrapper); + if iter_wrapper.next_called { + panic!("Can't change ValidKeyIter filter after iterating."); + } + + use std::mem; + let tmp = mem::replace(&mut iter_wrapper.iter, unsafe { mem::zeroed() }); + iter_wrapper.iter = + unsafe { std::mem::transmute(tmp.unencrypted_secret()) }; +} + +/// Changes the iterator to only return keys that are certification +/// capable. /// /// If you call this function and, e.g., the `for_signing` /// function, the *union* of the values is used. That is, the @@ -538,8 +626,8 @@ pub extern "C" fn pgp_cert_key_iter_for_storage_encryption<'a>( /// /// Note: you may not call this function after starting to iterate. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] -pub extern "C" fn pgp_cert_key_iter_for_transport_encryption<'a>( - iter_wrapper: *mut KeyIterWrapper<'a>) +pub extern "C" fn pgp_cert_valid_key_iter_for_certification<'a>( + iter_wrapper: *mut ValidKeyIterWrapper<'a>) { let iter_wrapper = ffi_param_ref_mut!(iter_wrapper); if iter_wrapper.next_called { @@ -548,18 +636,21 @@ pub extern "C" fn pgp_cert_key_iter_for_transport_encryption<'a>( use std::mem; let tmp = mem::replace(&mut iter_wrapper.iter, unsafe { mem::zeroed() }); - iter_wrapper.iter = tmp.for_transport_encryption(); + iter_wrapper.iter = tmp.for_certification(); } -/// Changes the iterator to only return keys that are alive. +/// Changes the iterator to only return keys that are certification +/// capable. /// -/// If you call this function (or `pgp_cert_key_iter_alive_at`), only -/// the last value is used. +/// If you call this function and, e.g., the `for_signing` +/// 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 "C" fn pgp_cert_key_iter_alive<'a>( - iter_wrapper: *mut KeyIterWrapper<'a>) +pub extern "C" fn pgp_cert_valid_key_iter_for_signing<'a>( + iter_wrapper: *mut ValidKeyIterWrapper<'a>) { let iter_wrapper = ffi_param_ref_mut!(iter_wrapper); if iter_wrapper.next_called { @@ -568,20 +659,21 @@ pub extern "C" fn pgp_cert_key_iter_alive<'a>( use std::mem; let tmp = mem::replace(&mut iter_wrapper.iter, unsafe { mem::zeroed() }); - iter_wrapper.iter = tmp.alive(); + iter_wrapper.iter = tmp.for_signing(); } -/// Changes the iterator to only return keys that are alive at the -/// specified time. +/// Changes the iterator to only return keys that are capable of +/// encrypting data at rest. /// -/// If you call this function (or `pgp_cert_key_iter_alive`), only the -/// last value is used. +/// If you call this function and, e.g., the `for_signing` +/// 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 "C" fn pgp_cert_key_iter_alive_at<'a>( - iter_wrapper: *mut KeyIterWrapper<'a>, - when: time_t) +pub extern "C" fn pgp_cert_valid_key_iter_for_storage_encryption<'a>( + iter_wrapper: *mut ValidKeyIterWrapper<'a>) { let iter_wrapper = ffi_param_ref_mut!(iter_wrapper); if iter_wrapper.next_called { @@ -590,18 +682,21 @@ pub extern "C" fn pgp_cert_key_iter_alive_at<'a>( use std::mem; let tmp = mem::replace(&mut iter_wrapper.iter, unsafe { mem::zeroed() }); - iter_wrapper.iter = - tmp.alive_at(maybe_time(when).unwrap_or(std::time::UNIX_EPOCH)); + iter_wrapper.iter = tmp.for_storage_encryption(); } -/// Changes the iterator to only return keys whose revocation status -/// matches `revoked`. +/// Changes the iterator to only return keys that are capable of +/// encrypting data for transport. +/// +/// If you call this function and, e.g., the `for_signing` +/// 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 "C" fn pgp_cert_key_iter_revoked<'a>( - iter_wrapper: *mut KeyIterWrapper<'a>, - revoked: bool) +pub extern "C" fn pgp_cert_valid_key_iter_for_transport_encryption<'a>( + iter_wrapper: *mut ValidKeyIterWrapper<'a>) { let iter_wrapper = ffi_param_ref_mut!(iter_wrapper); if iter_wrapper.next_called { @@ -610,15 +705,18 @@ pub extern "C" fn pgp_cert_key_iter_revoked<'a>( use std::mem; let tmp = mem::replace(&mut iter_wrapper.iter, unsafe { mem::zeroed() }); - iter_wrapper.iter = tmp.revoked(Some(revoked)); + iter_wrapper.iter = tmp.for_transport_encryption(); } -/// Changes the iterator to only return keys that have secret keys. +/// Changes the iterator to only return keys that are alive. +/// +/// If you call this function (or `pgp_cert_valid_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 "C" fn pgp_cert_key_iter_secret<'a>( - iter_wrapper: *mut KeyIterWrapper<'a>) +pub extern "C" fn pgp_cert_valid_key_iter_alive<'a>( + iter_wrapper: *mut ValidKeyIterWrapper<'a>) { let iter_wrapper = ffi_param_ref_mut!(iter_wrapper); if iter_wrapper.next_called { @@ -627,16 +725,17 @@ pub extern "C" fn pgp_cert_key_iter_secret<'a>( use std::mem; let tmp = mem::replace(&mut iter_wrapper.iter, unsafe { mem::zeroed() }); - iter_wrapper.iter = unsafe { std::mem::transmute(tmp.secret()) }; + iter_wrapper.iter = tmp.alive(); } -/// Changes the iterator to only return keys that have unencrypted -/// secret keys. +/// 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 "C" fn pgp_cert_key_iter_unencrypted_secret<'a>( - iter_wrapper: *mut KeyIterWrapper<'a>) +pub extern "C" fn pgp_cert_valid_key_iter_revoked<'a>( + iter_wrapper: *mut ValidKeyIterWrapper<'a>, + revoked: bool) { let iter_wrapper = ffi_param_ref_mut!(iter_wrapper); if iter_wrapper.next_called { @@ -645,8 +744,7 @@ pub extern "C" fn pgp_cert_key_iter_unencrypted_secret<'a>( use std::mem; let tmp = mem::replace(&mut iter_wrapper.iter, unsafe { mem::zeroed() }); - iter_wrapper.iter = - unsafe { std::mem::transmute(tmp.unencrypted_secret()) }; + iter_wrapper.iter = tmp.revoked(Some(revoked)); } /// Returns the next key. Returns NULL if there are no more elements. @@ -659,8 +757,8 @@ pub extern "C" fn pgp_cert_key_iter_unencrypted_secret<'a>( /// If rso is not NULL, this stores the key's revocation status in /// *rso. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] -pub extern "C" fn pgp_cert_key_iter_next<'a>( - iter_wrapper: *mut KeyIterWrapper<'a>, +pub extern "C" fn pgp_cert_valid_key_iter_next<'a>( + iter_wrapper: *mut ValidKeyIterWrapper<'a>, sigo: Option<&mut Maybe>, rso: Option<&mut *mut RevocationStatus<'a>>) -> Maybe diff --git a/openpgp-ffi/src/serialize.rs b/openpgp-ffi/src/serialize.rs index 0a6435a0..d6a7695b 100644 --- a/openpgp-ffi/src/serialize.rs +++ b/openpgp-ffi/src/serialize.rs @@ -38,6 +38,7 @@ use self::openpgp::serialize::{ use super::keyid::KeyID; use super::packet::key::Key; use super::cert::KeyIterWrapper; +use super::cert::ValidKeyIterWrapper; /// Streams an OpenPGP message. #[::sequoia_ffi_macros::extern_fn] #[no_mangle] @@ -277,6 +278,37 @@ fn pgp_recipients_from_key_iter<'a>( iter_wrapper: *mut KeyIterWrapper<'a>, result_len: *mut size_t) -> *mut *mut Recipient<'a> +{ + let iter_wrapper = ffi_param_move!(iter_wrapper); + let result_len = ffi_param_ref_mut!(result_len); + let recipients = + iter_wrapper.iter + .map(|key| key.into()) + .collect::>(); + + let result = unsafe { + libc::calloc(recipients.len(), std::mem::size_of::<* mut Recipient>()) + as *mut *mut Recipient + }; + let r = unsafe { + slice::from_raw_parts_mut(result, + recipients.len()) + }; + *result_len = recipients.len(); + r.iter_mut().zip(recipients.into_iter()) + .for_each(|(r, recipient)| *r = recipient.move_into_raw()); + result +} + +/// Collects recipients from a `pgp_cert_valid_key_iter_t`. +/// +/// Consumes the iterator. The returned buffer must be freed using +/// libc's allocator. +#[::sequoia_ffi_macros::extern_fn] #[no_mangle] pub extern "C" +fn pgp_recipients_from_valid_key_iter<'a>( + iter_wrapper: *mut ValidKeyIterWrapper<'a>, + result_len: *mut size_t) + -> *mut *mut Recipient<'a> { let iter_wrapper = ffi_param_move!(iter_wrapper); let result_len = ffi_param_ref_mut!(result_len); diff --git a/openpgp/examples/decrypt-with.rs b/openpgp/examples/decrypt-with.rs index 27977048..b3feceb6 100644 --- a/openpgp/examples/decrypt-with.rs +++ b/openpgp/examples/decrypt-with.rs @@ -58,7 +58,7 @@ impl Helper { // Map (sub)KeyIDs to secrets. let mut keys = HashMap::new(); for cert in certs { - for ka in cert.keys() { + for ka in cert.keys().policy(None) { if ka.binding_signature(None) .map(|s| (s.key_flags().for_storage_encryption() || s.key_flags().for_transport_encryption())) diff --git a/openpgp/examples/encrypt-for.rs b/openpgp/examples/encrypt-for.rs index c76c7a1b..63e0e071 100644 --- a/openpgp/examples/encrypt-for.rs +++ b/openpgp/examples/encrypt-for.rs @@ -38,7 +38,8 @@ fn main() { let mut recipients = certs.iter() .flat_map(|cert| { - cert.keys().alive().revoked(false).key_flags(&mode) + cert.keys() + .policy(None).alive().revoked(false).key_flags(&mode) }) .map(|ka| ka.key().into()) .collect::>(); diff --git a/openpgp/examples/generate-encrypt-decrypt.rs b/openpgp/examples/generate-encrypt-decrypt.rs index 416a4b73..d431e99c 100644 --- a/openpgp/examples/generate-encrypt-decrypt.rs +++ b/openpgp/examples/generate-encrypt-decrypt.rs @@ -41,8 +41,8 @@ fn generate() -> openpgp::Result { fn encrypt(sink: &mut dyn Write, plaintext: &str, recipient: &openpgp::Cert) -> openpgp::Result<()> { // Build a vector of recipients to hand to Encryptor. - let mut recipients = - recipient.keys().alive().revoked(false) + let mut recipients = recipient + .keys().policy(None).alive().revoked(false) .for_transport_encryption() .map(|ka| ka.key().into()) .collect::>(); diff --git a/openpgp/examples/generate-sign-verify.rs b/openpgp/examples/generate-sign-verify.rs index a51ff031..f238d368 100644 --- a/openpgp/examples/generate-sign-verify.rs +++ b/openpgp/examples/generate-sign-verify.rs @@ -40,7 +40,9 @@ fn generate() -> openpgp::Result { fn sign(sink: &mut dyn Write, plaintext: &str, tsk: &openpgp::Cert) -> openpgp::Result<()> { // Get the keypair to do the signing from the Cert. - let keypair = tsk.keys().alive().revoked(false).for_signing().nth(0).unwrap() + let keypair = tsk + .keys().policy(None).alive().revoked(false).for_signing() + .nth(0).unwrap() .key().clone().mark_parts_secret().unwrap().into_keypair()?; // Start streaming an OpenPGP message. diff --git a/openpgp/examples/notarize.rs b/openpgp/examples/notarize.rs index fec7419b..5d14ff9e 100644 --- a/openpgp/examples/notarize.rs +++ b/openpgp/examples/notarize.rs @@ -28,8 +28,9 @@ fn main() { .expect("Failed to read key"); let mut n = 0; - for key in tsk.keys().alive().revoked(false).for_signing().secret() - .map(|ka| ka.key()) + for key in tsk.keys() + .policy(None).alive().revoked(false).for_signing().secret() + .map(|ka| ka.key()) { keys.push({ let mut key = key.clone(); diff --git a/openpgp/examples/pad.rs b/openpgp/examples/pad.rs index 95625f51..f0792d4e 100644 --- a/openpgp/examples/pad.rs +++ b/openpgp/examples/pad.rs @@ -37,10 +37,11 @@ fn main() { }).collect(); // Build a vector of recipients to hand to Encryptor. - let mut recipients = - certs.iter() + let mut recipients = certs + .iter() .flat_map(|cert| { - cert.keys().alive().revoked(false).key_flags(mode.clone()) + cert.keys() + .policy(None).alive().revoked(false).key_flags(&mode) }) .map(|ka| Recipient::new(KeyID::wildcard(), ka.key())) .collect::>(); diff --git a/openpgp/examples/sign-detached.rs b/openpgp/examples/sign-detached.rs index eea08f08..4d228f34 100644 --- a/openpgp/examples/sign-detached.rs +++ b/openpgp/examples/sign-detached.rs @@ -24,8 +24,9 @@ fn main() { .expect("Failed to read key"); let mut n = 0; - for key in tsk.keys().alive().revoked(false).for_signing().secret() - .map(|ka| ka.key()) + for key in tsk + .keys().policy(None).alive().revoked(false).for_signing().secret() + .map(|ka| ka.key()) { keys.push({ let mut key = key.clone(); diff --git a/openpgp/examples/sign.rs b/openpgp/examples/sign.rs index d8054fac..b6bedeb4 100644 --- a/openpgp/examples/sign.rs +++ b/openpgp/examples/sign.rs @@ -23,8 +23,9 @@ fn main() { .expect("Failed to read key"); let mut n = 0; - for key in tsk.keys().alive().revoked(false).for_signing().secret() - .map(|ka| ka.key()) + for key in tsk.keys() + .policy(None).alive().revoked(false).for_signing().secret() + .map(|ka| ka.key()) { keys.push({ let mut key = key.clone(); diff --git a/openpgp/src/cert/bindings.rs b/openpgp/src/cert/bindings.rs index 52cc9527..6e0932ff 100644 --- a/openpgp/src/cert/bindings.rs +++ b/openpgp/src/cert/bindings.rs @@ -36,7 +36,7 @@ impl Key { /// /// // Let's add an encryption subkey. /// let flags = KeyFlags::default().set_storage_encryption(true); - /// assert_eq!(cert.keys().alive().revoked(false) + /// assert_eq!(cert.keys().policy(None).alive().revoked(false) /// .key_flags(&flags).count(), /// 0); /// @@ -53,7 +53,7 @@ impl Key { /// binding.into()])?; /// /// // Check that we have an encryption subkey. - /// assert_eq!(cert.keys().alive().revoked(false) + /// assert_eq!(cert.keys().policy(None).alive().revoked(false) /// .key_flags(flags).count(), /// 1); /// # Ok(()) } diff --git a/openpgp/src/cert/builder.rs b/openpgp/src/cert/builder.rs index 511ddd2d..89853794 100644 --- a/openpgp/src/cert/builder.rs +++ b/openpgp/src/cert/builder.rs @@ -655,17 +655,19 @@ mod tests { assert!(sig.key_alive(key, now + 590 * s).is_ok()); assert!(! sig.key_alive(key, now + 610 * s).is_ok()); - let (sig, key) = cert.keys().alive().revoked(false).for_signing() + let (sig, key) = cert.keys().policy(now).alive().revoked(false) + .for_signing() .nth(0).map(|ka| { - (ka.binding_signature(None).unwrap(), ka.key()) + (ka.binding_signature(now).unwrap(), ka.key()) }).unwrap(); assert!(sig.key_alive(key, now).is_ok()); assert!(sig.key_alive(key, now + 290 * s).is_ok()); assert!(! sig.key_alive(key, now + 310 * s).is_ok()); - let (sig, key) = cert.keys().alive().revoked(false).for_authentication() + let (sig, key) = cert.keys().policy(now).alive().revoked(false) + .for_authentication() .nth(0).map(|ka| { - (ka.binding_signature(None).unwrap(), ka.key()) + (ka.binding_signature(now).unwrap(), ka.key()) }).unwrap(); assert!(sig.key_alive(key, now).is_ok()); assert!(sig.key_alive(key, now + 590 * s).is_ok()); diff --git a/openpgp/src/cert/keyiter.rs b/openpgp/src/cert/keyiter.rs index 7bb59153..f235ec89 100644 --- a/openpgp/src/cert/keyiter.rs +++ b/openpgp/src/cert/keyiter.rs @@ -1,5 +1,6 @@ use std::fmt; use std::convert::TryInto; +use std::time::SystemTime; use std::borrow::Borrow; use crate::{ @@ -36,16 +37,6 @@ pub struct KeyIter<'a, P: key::KeyParts, R: key::KeyRole> { key::PublicParts, key::SubordinateRole>, - // If not None, only returns keys with the specified flags. - flags: Option, - - // If not None, only returns keys that are live at the specified - // time. - alive_at: Option, - - // If not None, filters by revocation status. - revoked: Option, - // If not None, filters by whether a key has a secret. secret: Option, @@ -62,9 +53,6 @@ impl<'a, P: key::KeyParts, R: key::KeyRole> fmt::Debug { 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() @@ -80,6 +68,244 @@ macro_rules! impl_iterator { impl<'a, R: 'a + key::KeyRole> Iterator for KeyIter<'a, $parts, R> where &'a Key<$parts, R>: From<&'a Key> + { + type Item = &'a Key<$parts, R>; + + fn next(&mut self) -> Option { + self.next_common().map(|k| k.into()) + } + } + } +} +impl_iterator!(key::PublicParts); +impl_iterator!(key::UnspecifiedParts); + +impl<'a, R: 'a + key::KeyRole> Iterator for KeyIter<'a, key::SecretParts, R> + where &'a Key: From<&'a Key> +{ + type Item = &'a Key; + + fn next(&mut self) -> Option { + self.next_common().map(|k| k.try_into().expect("has secret parts")) + } +} + +impl<'a, P: 'a + key::KeyParts, R: 'a + key::KeyRole> KeyIter<'a, P, R> +{ + fn next_common(&mut self) -> Option<&'a Key> + { + tracer!(false, "KeyIter::next", 0); + t!("KeyIter: {:?}", self); + + if self.cert.is_none() { + return None; + } + let cert = self.cert.unwrap(); + + loop { + let key : &Key + = if ! self.primary { + self.primary = true; + cert.primary.key().into() + } else { + self.subkey_iter.next()?.key().into() + }; + + t!("Considering key: {:?}", key); + + if let Some(want_secret) = self.secret { + if key.secret().is_some() { + // We have a 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.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 { + // No secret. + t!("No secret... skipping."); + continue; + } + } + + return Some(key); + } + } +} + +impl<'a, P: 'a + key::KeyParts, R: 'a + key::KeyRole> KeyIter<'a, P, R> +{ + /// Returns a new `KeyIter` instance. + pub(crate) fn new(cert: &'a Cert) -> Self where Self: 'a { + KeyIter { + cert: Some(cert), + primary: false, + subkey_iter: cert.subkeys(), + + // The filters. + secret: None, + unencrypted_secret: None, + + _p: std::marker::PhantomData, + _r: std::marker::PhantomData, + } + } + + /// Changes the filter to only return keys with secret key material. + pub fn secret(self) -> KeyIter<'a, key::SecretParts, R> { + KeyIter { + cert: self.cert, + primary: self.primary, + subkey_iter: self.subkey_iter, + + // The filters. + secret: Some(true), + unencrypted_secret: self.unencrypted_secret, + + _p: std::marker::PhantomData, + _r: std::marker::PhantomData, + } + } + + /// Changes the filter to only return keys with unencrypted secret + /// key material. + pub fn unencrypted_secret(self) -> KeyIter<'a, key::SecretParts, R> { + KeyIter { + cert: self.cert, + primary: self.primary, + subkey_iter: self.subkey_iter, + + // The filters. + secret: self.secret, + unencrypted_secret: Some(true), + + _p: std::marker::PhantomData, + _r: std::marker::PhantomData, + } + } + + /// Changes the iterator to only return keys that are valid at + /// time `time`. + /// + /// If `time` is None, then the current time is used. + /// + /// See `ValidKeyIter` for the definition of a valid key. + /// + /// As a general rule of thumb, when encrypting or signing a + /// message, you want keys that are valid now. When decrypting a + /// message, you want keys that were valid when the message was + /// encrypted, because these are the only keys that the encryptor + /// could have used. The same holds when verifying a message. + pub fn policy(self, time: T) -> ValidKeyIter<'a, P, R> + where T: Into> + { + ValidKeyIter { + cert: self.cert, + primary: self.primary, + subkey_iter: self.subkey_iter, + + // The filters. + secret: self.secret, + unencrypted_secret: self.unencrypted_secret, + time: time.into().unwrap_or_else(SystemTime::now), + flags: None, + alive: None, + revoked: None, + + _p: self._p, + _r: self._r, + } + } +} + +/// An iterator over all valid `Key`s in a certificate. +/// +/// A key is valid at time `t` if it was not created after `t` and it +/// has a live self-signature at time `t`. Note: this does not mean +/// that the key is also live at time `t`; the key may be expired, but +/// the self-signature is still valid. +/// +/// `ValidKeyIter` follows the builder pattern. There is no need to +/// explicitly finalize it, however: it already implements the +/// `Iterator` trait. +pub struct ValidKeyIter<'a, P: key::KeyParts, R: key::KeyRole> { + // This is an option to make it easier to create an empty ValidKeyIter. + cert: Option<&'a Cert>, + primary: bool, + subkey_iter: KeyBindingIter<'a, + key::PublicParts, + key::SubordinateRole>, + + // If not None, filters by whether a key has a secret. + secret: Option, + + // If not None, filters by whether a key has an unencrypted + // secret. + unencrypted_secret: Option, + + // The time. + time: SystemTime, + + // If not None, only returns keys with the specified flags. + flags: Option, + + // If not None, filters by whether a key is alive at time `t`. + alive: Option<()>, + + // If not None, filters by whether the key is revoked or not at + // time `t`. + revoked: Option, + + _p: std::marker::PhantomData

, + _r: std::marker::PhantomData, +} + +impl<'a, P: key::KeyParts, R: key::KeyRole> fmt::Debug + for ValidKeyIter<'a, P, R> +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("ValidKeyIter") + .field("secret", &self.secret) + .field("unencrypted_secret", &self.unencrypted_secret) + .field("time", &self.time) + .field("flags", &self.flags) + .field("alive", &self.alive) + .field("revoked", &self.revoked) + .finish() + } +} + +// Very carefully implement Iterator for +// Key<{PublicParts,UnspecifiedParts}, _>. We cannot just abstract +// over the parts, because then we cannot specialize the +// implementation for Key below. +macro_rules! impl_iterator { + ($parts:path) => { + impl<'a, R: 'a + key::KeyRole> Iterator for ValidKeyIter<'a, $parts, R> + where &'a Key<$parts, R>: From<&'a Key> { type Item = KeyAmalgamation<'a, $parts>; @@ -92,7 +318,7 @@ macro_rules! impl_iterator { impl_iterator!(key::PublicParts); impl_iterator!(key::UnspecifiedParts); -impl<'a, R: 'a + key::KeyRole> Iterator for KeyIter<'a, key::SecretParts, R> +impl<'a, R: 'a + key::KeyRole> Iterator for ValidKeyIter<'a, key::SecretParts, R> where &'a Key: From<&'a Key> { @@ -103,11 +329,11 @@ impl<'a, R: 'a + key::KeyRole> Iterator for KeyIter<'a, key::SecretParts, R> } } -impl <'a, P: 'a + key::KeyParts, R: 'a + key::KeyRole> KeyIter<'a, P, R> { +impl<'a, P: 'a + key::KeyParts, R: 'a + key::KeyRole> ValidKeyIter<'a, P, R> { fn next_common(&mut self) -> Option> { - tracer!(false, "KeyIter::next", 0); - t!("KeyIter: {:?}", self); + tracer!(false, "ValidKeyIter::next", 0); + t!("ValidKeyIter: {:?}", self); if self.cert.is_none() { return None; @@ -131,41 +357,33 @@ impl <'a, P: 'a + key::KeyParts, R: 'a + key::KeyRole> KeyIter<'a, P, R> { }; let key = ka.key(); + t!("Considering key: {:?}", key); - t!("Considering key: {:?}", ka); + let binding_signature + = if let Some(binding_signature) = ka.binding_signature(self.time) { + binding_signature + } else { + t!("No self-signature at time {:?}", self.time); + continue + }; if let Some(flags) = self.flags.as_ref() { - // XXX: Shouldn't assume the current time. - if let Some(sig) = ka.binding_signature(None) { - if (&sig.key_flags() & &flags).is_empty() { - t!("Have flags: {:?}, want flags: {:?}... skipping.", - sig.key_flags(), flags); - continue; - } - } else { - // No self-signature, skip it. - t!("No self-signature... skipping."); + if (&binding_signature.key_flags() & &flags).is_empty() { + t!("Have flags: {:?}, want flags: {:?}... skipping.", + binding_signature.key_flags(), flags); continue; } } - if let Some(alive_at) = self.alive_at { - // XXX: Shouldn't assume the current time. - if let Some(sig) = ka.binding_signature(None) { - if ! sig.key_alive(key, alive_at).is_ok() { - t!("Key not alive... skipping."); - continue; - } - } else { - // No self-signature, skip it. - t!("No self-signature... skipping."); + if let Some(()) = self.alive { + if let Err(err) = binding_signature.key_alive(key, self.time) { + t!("Key not alive: {:?}", err); continue; } } if let Some(want_revoked) = self.revoked { - // XXX: Shouldn't assume the current time. - if let RevocationStatus::Revoked(_) = ka.revoked(None) { + if let RevocationStatus::Revoked(_) = ka.revoked(self.time) { // The key is definitely revoked. if ! want_revoked { t!("Key revoked... skipping."); @@ -220,27 +438,8 @@ impl <'a, P: 'a + key::KeyParts, R: 'a + key::KeyRole> KeyIter<'a, P, R> { } } -impl<'a, P: 'a + key::KeyParts, R: 'a + key::KeyRole> KeyIter<'a, P, R> +impl<'a, P: 'a + key::KeyParts, R: 'a + key::KeyRole> ValidKeyIter<'a, P, R> { - /// Returns a new `KeyIter` instance. - pub(crate) fn new(cert: &'a Cert) -> Self where Self: 'a { - KeyIter { - cert: Some(cert), - primary: false, - subkey_iter: cert.subkeys(), - - // The filters. - flags: None, - alive_at: None, - revoked: None, - secret: None, - unencrypted_secret: None, - - _p: std::marker::PhantomData, - _r: std::marker::PhantomData, - } - } - /// Returns keys that have the at least one of the flags specified /// in `flags`. /// @@ -302,26 +501,10 @@ impl<'a, P: 'a + key::KeyParts, R: 'a + key::KeyRole> KeyIter<'a, P, R> self.key_flags(KeyFlags::default().set_transport_encryption(true)) } - /// Only returns keys that are live as of `now`. - /// - /// A value of None disables this filter. - /// - /// If you call this function (or `alive`) multiple times, only - /// the last value is used. - pub fn alive_at(mut self, alive_at: T) -> Self - where T: Into> - { - self.alive_at = alive_at.into(); - self - } - - /// Only returns keys that are alive right now. - /// - /// If you call this function (or `alive_at`) multiple times, only - /// the last value is used. + /// Only returns keys that are alive. pub fn alive(mut self) -> Self { - self.alive_at = Some(std::time::SystemTime::now()); + self.alive = Some(()); self } @@ -349,6 +532,7 @@ impl<'a, P: 'a + key::KeyParts, R: 'a + key::KeyRole> KeyIter<'a, P, R> /// # .generate()?; /// let non_revoked_keys = cert /// .keys() + /// .policy(None) /// .filter(|ka| { /// match ka.revoked(None) { /// RevocationStatus::Revoked(_) => @@ -385,18 +569,20 @@ impl<'a, P: 'a + key::KeyParts, R: 'a + key::KeyRole> KeyIter<'a, P, R> } /// Changes the filter to only return keys with secret key material. - pub fn secret(self) -> KeyIter<'a, key::SecretParts, R> { - KeyIter { + pub fn secret(self) -> ValidKeyIter<'a, key::SecretParts, R> { + ValidKeyIter { cert: self.cert, primary: self.primary, subkey_iter: self.subkey_iter, + time: self.time, + // The filters. - flags: self.flags, - alive_at: self.alive_at, - revoked: self.revoked, secret: Some(true), unencrypted_secret: self.unencrypted_secret, + flags: self.flags, + alive: self.alive, + revoked: self.revoked, _p: std::marker::PhantomData, _r: std::marker::PhantomData, @@ -405,18 +591,20 @@ impl<'a, P: 'a + key::KeyParts, R: 'a + key::KeyRole> KeyIter<'a, P, R> /// Changes the filter to only return keys with unencrypted secret /// key material. - pub fn unencrypted_secret(self) -> KeyIter<'a, key::SecretParts, R> { - KeyIter { + pub fn unencrypted_secret(self) -> ValidKeyIter<'a, key::SecretParts, R> { + ValidKeyIter { cert: self.cert, primary: self.primary, subkey_iter: self.subkey_iter, + time: self.time, + // The filters. - flags: self.flags, - alive_at: self.alive_at, - revoked: self.revoked, secret: self.secret, unencrypted_secret: Some(true), + flags: self.flags, + alive: self.alive, + revoked: self.revoked, _p: std::marker::PhantomData, _r: std::marker::PhantomData, @@ -445,7 +633,7 @@ mod test { .generate().unwrap(); let flags = KeyFlags::default().set_transport_encryption(true); - assert_eq!(cert.keys().key_flags(flags).count(), 0); + assert_eq!(cert.keys().policy(None).key_flags(flags).count(), 0); } #[test] @@ -455,7 +643,7 @@ mod test { .generate().unwrap(); let flags = KeyFlags::default().set_transport_encryption(true); - assert_eq!(cert.keys().key_flags(flags).count(), 1); + assert_eq!(cert.keys().policy(None).key_flags(flags).count(), 1); } #[test] @@ -466,7 +654,7 @@ mod test { .generate().unwrap(); let flags = KeyFlags::default().set_transport_encryption(true); - assert_eq!(cert.keys().key_flags(flags).count(), 1); + assert_eq!(cert.keys().policy(None).key_flags(flags).count(), 1); } #[test] @@ -476,9 +664,9 @@ mod test { .generate().unwrap(); let flags = KeyFlags::default().set_transport_encryption(true); - let now = std::time::SystemTime::now() + let now = SystemTime::now() - std::time::Duration::new(52 * 7 * 24 * 60 * 60, 0); - assert_eq!(cert.keys().key_flags(flags).alive_at(now).count(), 0); + assert_eq!(cert.keys().policy(now).key_flags(flags).alive().count(), 0); } #[test] @@ -488,7 +676,7 @@ mod test { .generate().unwrap(); let flags = KeyFlags::default().set_certification(true); - assert_eq!(cert.keys().key_flags(flags).count(), 2); + assert_eq!(cert.keys().policy(None).key_flags(flags).count(), 2); } #[test] @@ -500,20 +688,20 @@ mod test { .add_storage_encryption_subkey() .add_authentication_subkey() .generate().unwrap(); - assert_eq!(cert.keys().alive().revoked(false) + assert_eq!(cert.keys().policy(None).alive().revoked(false) .for_certification().count(), 2); - assert_eq!(cert.keys().alive().revoked(false) + assert_eq!(cert.keys().policy(None).alive().revoked(false) .for_transport_encryption().count(), 1); - assert_eq!(cert.keys().alive().revoked(false) + assert_eq!(cert.keys().policy(None).alive().revoked(false) .for_storage_encryption().count(), 1); - assert_eq!(cert.keys().alive().revoked(false) + assert_eq!(cert.keys().policy(None).alive().revoked(false) .for_signing().count(), 1); - assert_eq!(cert.keys().alive().revoked(false) + assert_eq!(cert.keys().policy(None).alive().revoked(false) .key_flags(KeyFlags::default().set_authentication(true)) .count(), 1); diff --git a/openpgp/src/cert/mod.rs b/openpgp/src/cert/mod.rs index 8ab9aa9d..8cb4651c 100644 --- a/openpgp/src/cert/mod.rs +++ b/openpgp/src/cert/mod.rs @@ -45,7 +45,7 @@ mod revoke; pub use self::builder::{CertBuilder, CipherSuite}; -pub use keyiter::KeyIter; +pub use keyiter::{KeyIter, ValidKeyIter}; pub use key_amalgamation::KeyAmalgamation; pub use parser::{ diff --git a/openpgp/src/crypto/keygrip.rs b/openpgp/src/crypto/keygrip.rs index cff25e6f..a6095ef4 100644 --- a/openpgp/src/crypto/keygrip.rs +++ b/openpgp/src/crypto/keygrip.rs @@ -340,7 +340,7 @@ mod tests { .iter().map(|n| (n, crate::Cert::from_bytes(crate::tests::key(n)).unwrap())) { eprintln!("{}", name); - for key in cert.keys().map(|ka| ka.key()) { + for key in cert.keys() { let fp = key.fingerprint(); eprintln!("(sub)key: {}", fp); assert_eq!(&key.mpis().keygrip().unwrap(), diff --git a/openpgp/src/crypto/mpis.rs b/openpgp/src/crypto/mpis.rs index 4460cc58..84aa21f5 100644 --- a/openpgp/src/crypto/mpis.rs +++ b/openpgp/src/crypto/mpis.rs @@ -1061,7 +1061,7 @@ mod tests { ("erika-corinna-daniela-simone-antonia-nistp521.pgp", 0, 521), ] { let cert = crate::Cert::from_bytes(crate::tests::key(name)).unwrap(); - let key = cert.keys().nth(*key_no).unwrap().key(); + let key = cert.keys().nth(*key_no).unwrap(); assert_eq!(key.mpis().bits().unwrap(), *bits, "Cert {}, key no {}", name, *key_no); } diff --git a/openpgp/src/packet/signature/mod.rs b/openpgp/src/packet/signature/m