sequoia_openpgp/cert/
amalgamation.rs

1//! Components, their associated signatures, and some useful methods.
2//!
3//! Whereas a [`ComponentBundle`] owns a `Component` and its
4//! associated [`Signature`]s, a [`ComponentAmalgamation`] references
5//! a `ComponentBundle` and its containing [`Cert`].  This additional
6//! context means that a `ComponentAmalgamation` can implement more of
7//! OpenPGP's high-level semantics than a `ComponentBundle` can.  For
8//! instance, most of the information about a primary key, such as its
9//! capabilities, is on the primary User ID's binding signature.  A
10//! `ComponentAmalgamation` can find the certificate's primary User
11//! ID; a `ComponentBundle` can't.  Similarly, when looking up a
12//! subpacket, if it isn't present in the component's binding
13//! signature, then an OpenPGP implementation [is supposed to] consult
14//! the certificate's direct key signatures.  A
15//! `ComponentAmalgamation` has access to this information; a
16//! `ComponentBundle` doesn't.
17//!
18//! Given the limitations of a `ComponentBundle`, it would seem more
19//! useful to just change it to include a reference to its containing
20//! certificate.  That change would make `ComponentAmalgamation`s
21//! redundant.  Unfortunately, this isn't possible, because it would
22//! result in a self-referential data structure, which Rust doesn't
23//! allow.  To understand how this arises, consider a certificate `C`,
24//! which contains a `ComponentBundle` `B`.  If `B` contains a
25//! reference to `C`, then `C` references itself, because `C` contains
26//! `B`!
27//!
28//! ```text
29//! Cert:[ Bundle:[ &Cert ] ]
30//!      ^            |
31//!      `------------'
32//! ```
33//!
34//! # Policy
35//!
36//! Although a `ComponentAmalgamation` contains the information
37//! necessary to realize high-level OpenPGP functionality, components
38//! can have multiple self signatures, and functions that consult the
39//! binding signature need to determine the best one to use.  There
40//! are two main concerns here.
41//!
42//! First, we need to protect the user from forgeries.  As attacks
43//! improve, cryptographic algorithms that were once considered secure
44//! now provide insufficient security margins.  For instance, in 2007
45//! it was possible to find [MD5 collisions] using just a few seconds
46//! of computing time on a desktop computer.  Sequoia provides a
47//! flexible mechanism, called [`Policy`] objects, that allow users to
48//! implement this type of filtering: before a self signature is used,
49//! a policy object is queried to determine whether the `Signature`
50//! should be rejected.  If so, then it is skipped.
51//!
52//! Second, we need an algorithm to determine the most appropriate
53//! self signature.  Obvious non-candidate self signatures are self
54//! signatures whose creation time is in the future.  We don't assume
55//! that these self signatures are bad per se, but that they represent
56//! a policy that should go into effect some time in the future.
57//!
58//! We extend this idea of a self signature representing a policy for
59//! a certain period of time to all self signatures.  In particular,
60//! Sequoia takes the view that *a binding signature represents a
61//! policy that is valid from its creation time until its expiry*.
62//! Thus, when considering what self signature to use, we need a
63//! reference time.  Given the reference time, we then use the self
64//! signature that was in effect at that time, i.e., the most recent,
65//! non-expired, non-revoked self signature that was created at or
66//! prior to the reference time.  In other words, we ignore self
67//! signatures created after the reference time.  We take the position
68//! that if the certificate holder wants a new policy to apply to
69//! existing signatures, then the new self signature should be
70//! backdated, and existing self signatures revoked, if necessary.
71//!
72//! Consider evaluating a signature over a document.  Sequoia's
73//! [streaming verifier] uses the signature's creation time as the
74//! reference time.  Thus, if the signature was created on June 9th,
75//! 2011, then, when evaluating that signature, the streaming verifier
76//! uses a self signature that was live at that time, since that was
77//! the self signature that represented the signer's policy at the
78//! time the signature over the document was created.
79//!
80//! A consequence of this approach is that even if the self signature
81//! were considered expired at the time the signature was evaluated
82//! (e.g., "now"), this fact doesn't invalidate the signature.  That
83//! is, a self signature's lifetime does not impact a signature's
84//! lifetime; a signature's lifetime is defined by its own creation
85//! time and expiry.  Similarly, a key's lifetime is defined by its
86//! own creation time and expiry.
87//!
88//! This interpretation of lifetimes removes a major disadvantage that
89//! comes with fast rotation of subkeys: if an implementation binds
90//! the lifetime of signatures to the signing key, and the key
91//! expires, then old signatures are considered invalid.  Consider a
92//! user who generates a new signature subkey each week, and sets it
93//! to expire after exactly one week.  If we use the policy that the
94//! signature is only valid while the key *and* the self signature are
95//! live, then if someone checks the signature a week after receiving
96//! it, the signature will be considered invalid, because the key has
97//! expired.  The practical result is that all old messages from this
98//! user will be considered invalid!  Unfortunately, this will result
99//! in users becoming accustomed to seeing invalid signatures, and
100//! cause them to be less suspcious of them.
101//!
102//! Sequoia's low-level mechanisms support this interpretation of self
103//! signatures, but they do *not* enforce it.  It is still possible to
104//! realize other policies using this low-level API.
105//!
106//! The possibility of abuse of this interpretation of signature
107//! lifetimes is limited.  If a key has been compromised, then the
108//! right thing to do is to revoke it.  Expiry doesn't help: the
109//! attacker can simply create self-signatures that say whatever she
110//! wants.  Assuming the secret key material has not been compromised,
111//! then an attacker could still reuse a message that would otherwise
112//! be considered expired.  However, the attacker will not be able to
113//! change the signature's creation time, so, assuming a mail context
114//! and MUAs that check that the time in the message's headers matches
115//! the signature's creation time, the mails will appear old.
116//! Further, this type of attack will be mitigated by the proposed
117//! "[Intended Recipients]" subpacket, which more tightly binds the
118//! message to its context.
119//!
120//! # [`ValidComponentAmalgamation`]
121//!
122//! Most operations need to query a `ComponentAmalgamation` for
123//! multiple pieces of information.  Accidentally using a different
124//! `Policy` or a different reference time for one of the queries is
125//! easy, especially when the queries are spread across multiple
126//! functions.  Further, using `None` for the reference time can
127//! result in subtle timing bugs as each function translates it to the
128//! current time on demand.  In these cases, the correct approach
129//! would be for the user of the library to get the current time at
130//! the start of the operation.  But, this is less convenient.
131//! Finally, passing a `Policy` and a reference time to most function
132//! calls clutters the code.
133//!
134//! To mitigate these issues, we have a separate data structure,
135//! `ValidComponentAmalgamation`, which combines a
136//! `ComponetAmalgamation`, a `Policy` and a reference time.  It
137//! implements methods that require a `Policy` and reference time, but
138//! instead of requiring the caller to pass them in, it uses the ones
139//! embedded in the data structure.  Further, when the
140//! `ValidComponentAmalgamation` constructor is passed `None` for the
141//! reference time, it eagerly stores the current time, and uses that
142//! for all operations.  This approach elegantly solves all the
143//! aforementioned problems.
144//!
145//! [`ComponentBundle`]: super::bundle
146//! [`Signature`]: crate::packet::signature
147//! [`Cert`]: super
148//! [is supposed to]: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.10
149//! [`std::iter::map`]: std::iter::Map
150//! [MD5 collisions]: https://en.wikipedia.org/wiki/MD5
151//! [`Policy`]: crate::policy::Policy
152//! [streaming verifier]: crate::parse::stream
153//! [Intended Recipients]: https://www.rfc-editor.org/rfc/rfc9580.html#intended-recipient-fingerprint
154//! [signature expirations]: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.18
155use std::time;
156use std::time::{
157    Duration,
158    SystemTime,
159};
160use std::clone::Clone;
161use std::borrow::Borrow;
162
163use crate::{
164    cert::prelude::*,
165    crypto::{Signer, hash::Hash},
166    Error,
167    KeyHandle,
168    packet,
169    packet::{
170        Key,
171        Signature,
172        Unknown,
173        UserAttribute,
174        UserID,
175        key::{PrimaryRole, PublicParts},
176    },
177    Result,
178    policy::{
179        HashAlgoSecurity,
180        Policy,
181    },
182    seal,
183    types::{
184        AEADAlgorithm,
185        CompressionAlgorithm,
186        Features,
187        HashAlgorithm,
188        KeyServerPreferences,
189        RevocationKey,
190        RevocationStatus,
191        RevocationType,
192        SignatureType,
193        SymmetricAlgorithm,
194    },
195};
196
197mod iter;
198pub use iter::{
199    ComponentAmalgamationIter,
200    UnknownComponentAmalgamationIter,
201    UserAttributeAmalgamationIter,
202    UserIDAmalgamationIter,
203    ValidComponentAmalgamationIter,
204    ValidUserAttributeAmalgamationIter,
205    ValidUserIDAmalgamationIter,
206};
207
208pub mod key;
209
210/// Embeds a policy and a reference time in an amalgamation.
211///
212/// This is used to turn a [`ComponentAmalgamation`] into a
213/// [`ValidComponentAmalgamation`], and a [`KeyAmalgamation`] into a
214/// [`ValidKeyAmalgamation`].
215///
216/// A certificate or a component is considered valid if:
217///
218///   - It has a self signature that is live at time `t`.
219///
220///   - The policy considers it acceptable.
221///
222///   - The certificate is valid.
223///
224/// # Sealed trait
225///
226/// This trait is [sealed] and cannot be implemented for types outside this crate.
227/// Therefore it can be extended in a non-breaking way.
228/// If you want to implement the trait inside the crate
229/// you also need to implement the `seal::Sealed` marker trait.
230///
231/// [sealed]: https://rust-lang.github.io/api-guidelines/future-proofing.html#sealed-traits-protect-against-downstream-implementations-c-sealed
232///
233/// # Examples
234///
235/// ```
236/// # use sequoia_openpgp as openpgp;
237/// use openpgp::cert::prelude::*;
238/// use openpgp::policy::{Policy, StandardPolicy};
239///
240/// const POLICY: &dyn Policy = &StandardPolicy::new();
241///
242/// fn f(ua: UserIDAmalgamation) -> openpgp::Result<()> {
243///     let ua = ua.with_policy(POLICY, None)?;
244///     // ...
245/// #   Ok(())
246/// }
247/// # fn main() -> openpgp::Result<()> {
248/// #     let (cert, _) =
249/// #         CertBuilder::general_purpose(Some("alice@example.org"))
250/// #         .generate()?;
251/// #     let ua = cert.userids().nth(0).expect("User IDs");
252/// #     f(ua);
253/// #     Ok(())
254/// # }
255/// ```
256///
257pub trait ValidateAmalgamation<'a, C: 'a>: seal::Sealed {
258    /// The type returned by `with_policy`.
259    ///
260    /// This is either a [`ValidComponentAmalgamation`] or
261    /// a [`ValidKeyAmalgamation`].
262    ///
263    type V;
264
265    /// Uses the specified `Policy` and reference time with the amalgamation.
266    ///
267    /// If `time` is `None`, the current time is used.
268    fn with_policy<T>(&self, policy: &'a dyn Policy, time: T) -> Result<Self::V>
269        where T: Into<Option<time::SystemTime>>,
270              Self: Sized;
271}
272
273/// Applies a policy to an amalgamation.
274///
275/// This is an internal variant of `ValidateAmalgamation`, which
276/// allows validating a component for an otherwise invalid
277/// certificate.  See `ValidComponentAmalgamation::primary` for an
278/// explanation.
279trait ValidateAmalgamationRelaxed<'a, C: 'a> {
280    /// The type returned by `with_policy`.
281    type V;
282
283    /// Changes the amalgamation's policy.
284    ///
285    /// If `time` is `None`, the current time is used.
286    ///
287    /// If `valid_cert` is `false`, then this does not also check
288    /// whether the certificate is valid; it only checks whether the
289    /// component is valid.  Normally, this should be `true`.  This
290    /// option is only expose to allow breaking an infinite recursion:
291    ///
292    ///   - To check if a certificate is valid, we check if the
293    ///     primary key is valid.
294    ///
295    ///   - To check if the primary key is valid, we need the primary
296    ///     key's self signature
297    ///
298    ///   - To find the primary key's self signature, we need to find
299    ///     the primary user id
300    ///
301    ///   - To find the primary user id, we need to check if the user
302    ///     id is valid.
303    ///
304    ///   - To check if the user id is valid, we need to check that
305    ///     the corresponding certificate is valid.
306    fn with_policy_relaxed<T>(&self, policy: &'a dyn Policy, time: T,
307                              valid_cert: bool) -> Result<Self::V>
308        where T: Into<Option<time::SystemTime>>,
309              Self: Sized;
310}
311
312/// Methods for valid amalgamations.
313///
314/// The methods exposed by a `ValidComponentAmalgamation` are similar
315/// to those exposed by a `ComponentAmalgamation`, but the policy and
316/// reference time are included in the `ValidComponentAmalgamation`.
317/// This helps prevent using different policies or different reference
318/// times when using a component, which can easily happen when the
319/// checks span multiple functions.
320///
321/// # Sealed trait
322///
323/// This trait is [sealed] and cannot be implemented for types outside this crate.
324/// Therefore it can be extended in a non-breaking way.
325/// If you want to implement the trait inside the crate
326/// you also need to implement the `seal::Sealed` marker trait.
327///
328/// [sealed]: https://rust-lang.github.io/api-guidelines/future-proofing.html#sealed-traits-protect-against-downstream-implementations-c-sealed
329pub trait ValidAmalgamation<'a, C: 'a>: seal::Sealed
330{
331    /// Returns the valid amalgamation's associated certificate.
332    ///
333    /// # Examples
334    ///
335    /// ```
336    /// # use sequoia_openpgp as openpgp;
337    /// # use openpgp::cert::prelude::*;
338    /// # use openpgp::policy::StandardPolicy;
339    /// #
340    /// fn f(ua: &ValidUserIDAmalgamation) {
341    ///     let vcert = ua.valid_cert();
342    ///     // ...
343    /// }
344    /// # fn main() -> openpgp::Result<()> {
345    /// #     let p = &StandardPolicy::new();
346    /// #     let (cert, _) =
347    /// #         CertBuilder::general_purpose(Some("alice@example.org"))
348    /// #         .generate()?;
349    /// #     let fpr = cert.fingerprint();
350    /// #     let ua = cert.userids().nth(0).expect("User IDs");
351    /// #     assert_eq!(ua.cert().fingerprint(), fpr);
352    /// #     f(&ua.with_policy(p, None)?);
353    /// #     Ok(())
354    /// # }
355    /// ```
356    fn valid_cert(&self) -> &ValidCert<'a>;
357
358    /// Returns the amalgamation's reference time.
359    ///
360    /// # Examples
361    ///
362    /// ```
363    /// # use std::time::{SystemTime, Duration, UNIX_EPOCH};
364    /// #
365    /// # use sequoia_openpgp as openpgp;
366    /// # use openpgp::cert::prelude::*;
367    /// # use openpgp::policy::StandardPolicy;
368    /// fn f(ua: &ValidUserIDAmalgamation) {
369    ///     let t = ua.time();
370    ///     // ...
371    /// }
372    /// # fn main() -> openpgp::Result<()> {
373    /// #     let p = &StandardPolicy::new();
374    /// #     let t = UNIX_EPOCH + Duration::from_secs(1554542220);
375    /// #     let (cert, _) =
376    /// #         CertBuilder::general_purpose(Some("alice@example.org"))
377    /// #         .set_creation_time(t)
378    /// #         .generate()?;
379    /// #     let ua = cert.userids().nth(0).expect("User IDs");
380    /// #     let ua = ua.with_policy(p, t)?;
381    /// #     assert_eq!(t, ua.time());
382    /// #     f(&ua);
383    /// #     Ok(())
384    /// # }
385    /// ```
386    fn time(&self) -> SystemTime;
387
388    /// Returns the amalgamation's policy.
389    ///
390    /// # Examples
391    ///
392    /// ```
393    /// # use sequoia_openpgp as openpgp;
394    /// # use openpgp::cert::prelude::*;
395    /// # use openpgp::policy::{Policy, StandardPolicy};
396    /// #
397    /// fn f(ua: &ValidUserIDAmalgamation) {
398    ///     let policy = ua.policy();
399    ///     // ...
400    /// }
401    /// # fn main() -> openpgp::Result<()> {
402    /// #     let p: &dyn Policy = &StandardPolicy::new();
403    /// #     let (cert, _) =
404    /// #         CertBuilder::general_purpose(Some("alice@example.org"))
405    /// #         .generate()?;
406    /// #     let ua = cert.userids().nth(0).expect("User IDs");
407    /// #     let ua = ua.with_policy(p, None)?;
408    /// #     assert!(std::ptr::eq(p, ua.policy()));
409    /// #     f(&ua);
410    /// #     Ok(())
411    /// # }
412    /// ```
413    fn policy(&self) -> &'a dyn Policy;
414
415    /// Returns the component's binding signature as of the reference time.
416    ///
417    /// # Examples
418    ///
419    /// ```
420    /// # use sequoia_openpgp as openpgp;
421    /// # use openpgp::cert::prelude::*;
422    /// # use openpgp::policy::{Policy, StandardPolicy};
423    /// #
424    /// fn f(ua: &ValidUserIDAmalgamation) {
425    ///     let sig = ua.binding_signature();
426    ///     // ...
427    /// }
428    /// # fn main() -> openpgp::Result<()> {
429    /// #     let p: &dyn Policy = &StandardPolicy::new();
430    /// #     let (cert, _) =
431    /// #         CertBuilder::general_purpose(Some("alice@example.org"))
432    /// #         .generate()?;
433    /// #     let ua = cert.userids().nth(0).expect("User IDs");
434    /// #     let ua = ua.with_policy(p, None)?;
435    /// #     f(&ua);
436    /// #     Ok(())
437    /// # }
438    /// ```
439    fn binding_signature(&self) -> &'a Signature;
440
441    /// Returns the certificate's direct key signature as of the
442    /// reference time, if any.
443    ///
444    /// Subpackets on direct key signatures apply to all components of
445    /// the certificate, cf. [Section 5.2.3.10 of RFC 9580].
446    ///
447    /// [Section 5.2.3.10 of RFC 9580]: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.10
448    ///
449    /// # Examples
450    ///
451    /// ```
452    /// # use sequoia_openpgp as openpgp;
453    /// # use openpgp::cert::prelude::*;
454    /// # use openpgp::policy::{Policy, StandardPolicy};
455    /// #
456    /// fn f(ua: &ValidUserIDAmalgamation) {
457    ///     let sig = ua.direct_key_signature();
458    ///     // ...
459    /// }
460    /// # fn main() -> openpgp::Result<()> {
461    /// #     let p: &dyn Policy = &StandardPolicy::new();
462    /// #     let (cert, _) =
463    /// #         CertBuilder::general_purpose(Some("alice@example.org"))
464    /// #         .generate()?;
465    /// #     let cert = cert.with_policy(p, None)?;
466    /// #     let ua = cert.userids().nth(0).expect("User IDs");
467    /// #     assert!(std::ptr::eq(ua.direct_key_signature().unwrap(),
468    /// #                          cert.direct_key_signature().unwrap()));
469    /// #     f(&ua);
470    /// #     Ok(())
471    /// # }
472    /// ```
473    fn direct_key_signature(&self) -> Result<&'a Signature> {
474        self.valid_cert().cert().primary_key()
475            .binding_signature(self.policy(), self.time())
476    }
477
478    /// Returns the component's revocation status as of the amalgamation's
479    /// reference time.
480    ///
481    /// This does *not* check whether the certificate has been
482    /// revoked.  For that, use `Cert::revocation_status()`.
483    ///
484    /// Note, as per [Section 5.2.3.31 of RFC 9580], a key is considered to be revoked at
485    /// some time if there were no soft revocations created as of that
486    /// time, and no hard revocations:
487    ///
488    /// > If a key has been revoked because of a compromise, all signatures
489    /// > created by that key are suspect.  However, if it was merely
490    /// > superseded or retired, old signatures are still valid.
491    ///
492    /// [Section 5.2.3.31 of RFC 9580]: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.31
493    ///
494    /// # Examples
495    ///
496    /// ```
497    /// # use sequoia_openpgp as openpgp;
498    /// use openpgp::cert::prelude::*;
499    /// # use openpgp::policy::StandardPolicy;
500    /// use openpgp::types::RevocationStatus;
501    ///
502    /// # fn main() -> openpgp::Result<()> {
503    /// #     let p = &StandardPolicy::new();
504    /// #     let (cert, _) =
505    /// #         CertBuilder::general_purpose(Some("alice@example.org"))
506    /// #         .generate()?;
507    /// #     let cert = cert.with_policy(p, None)?;
508    /// #     let ua = cert.userids().nth(0).expect("User IDs");
509    /// match ua.revocation_status() {
510    ///     RevocationStatus::Revoked(revs) => {
511    ///         // The certificate holder revoked the User ID.
512    /// #       unreachable!();
513    ///     }
514    ///     RevocationStatus::CouldBe(revs) => {
515    ///         // There are third-party revocations.  You still need
516    ///         // to check that they are valid (this is necessary,
517    ///         // because without the Certificates are not normally
518    ///         // available to Sequoia).
519    /// #       unreachable!();
520    ///     }
521    ///     RevocationStatus::NotAsFarAsWeKnow => {
522    ///         // We have no evidence that the User ID is revoked.
523    ///     }
524    /// }
525    /// #     Ok(())
526    /// # }
527    /// ```
528    fn revocation_status(&self) -> RevocationStatus<'a>;
529
530    /// Returns a list of any designated revokers for this component.
531    ///
532    /// This function returns the designated revokers listed on the
533    /// components' binding signatures and the certificate's direct
534    /// key signatures.
535    ///
536    /// Note: the returned list is deduplicated.
537    ///
538    /// # Examples
539    ///
540    /// ```
541    /// use sequoia_openpgp as openpgp;
542    /// # use openpgp::Result;
543    /// use openpgp::cert::prelude::*;
544    /// use openpgp::policy::StandardPolicy;
545    /// use openpgp::types::RevocationKey;
546    ///
547    /// # fn main() -> Result<()> {
548    /// let p = &StandardPolicy::new();
549    ///
550    /// let (alice, _) =
551    ///     CertBuilder::general_purpose(Some("alice@example.org"))
552    ///     .generate()?;
553    /// // Make Alice a designated revoker for Bob.
554    /// let (bob, _) =
555    ///     CertBuilder::general_purpose(Some("bob@example.org"))
556    ///     .set_revocation_keys(vec![(&alice).into()])
557    ///     .generate()?;
558    ///
559    /// // Make sure Alice is listed as a designated revoker for Bob's
560    /// // primary user id.
561    /// assert_eq!(bob.with_policy(p, None)?.primary_userid()?
562    ///            .revocation_keys().collect::<Vec<&RevocationKey>>(),
563    ///            vec![&(&alice).into()]);
564    ///
565    /// // Make sure Alice is listed as a designated revoker for Bob's
566    /// // encryption subkey.
567    /// assert_eq!(bob.with_policy(p, None)?
568    ///            .keys().for_transport_encryption().next().unwrap()
569    ///            .revocation_keys().collect::<Vec<&RevocationKey>>(),
570    ///            vec![&(&alice).into()]);
571    /// # Ok(()) }
572    /// ```
573    fn revocation_keys(&self)
574                       -> Box<dyn Iterator<Item = &'a RevocationKey> + 'a>;
575}
576
577#[test]
578fn valid_amalgamation_is_dyn_compatible() {
579    let _t: Option<Box<dyn ValidAmalgamation<()>>> = None;
580}
581
582/// Locates information on the active binding signature or direct key
583/// signature.
584///
585/// # Sealed trait
586///
587/// This trait is [sealed] and cannot be implemented for types outside
588/// this crate.  Therefore it can be extended in a non-breaking way.
589/// If you want to implement the trait inside the crate you also need
590/// to implement the `seal::Sealed` marker trait.
591///
592/// [sealed]: https://rust-lang.github.io/api-guidelines/future-proofing.html#sealed-traits-protect-against-downstream-implementations-c-sealed
593pub trait ValidBindingSignature<'a, C: 'a>: ValidAmalgamation<'a, C> + seal::Sealed
594{
595    /// Maps the given function over binding and direct key signature.
596    ///
597    /// Makes `f` consider both the binding signature and the direct
598    /// key signature.  Information in the binding signature takes
599    /// precedence over the direct key signature.  See also [Section
600    /// 5.2.3.10 of RFC 9580].
601    ///
602    ///   [Section 5.2.3.10 of RFC 9580]: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.10
603    fn map<F: Fn(&'a Signature) -> Option<T>, T>(&self, f: F) -> Option<T> {
604        f(self.binding_signature())
605            .or_else(|| self.direct_key_signature().ok().and_then(f))
606    }
607}
608
609/// A certificate component, its associated data, and useful methods.
610///
611/// [`Cert::userids`], [`ValidCert::primary_userid`], [`Cert::user_attributes`], and
612/// [`Cert::unknowns`] return `ComponentAmalgamation`s.
613///
614/// `ComponentAmalgamation` implements [`ValidateAmalgamation`], which
615/// allows you to turn a `ComponentAmalgamation` into a
616/// [`ValidComponentAmalgamation`] using
617/// [`ComponentAmalgamation::with_policy`].
618///
619/// [See the module's documentation] for more details.
620///
621/// # Examples
622///
623/// ```
624/// # use sequoia_openpgp as openpgp;
625/// # use openpgp::cert::prelude::*;
626/// # use openpgp::policy::StandardPolicy;
627/// #
628/// # fn main() -> openpgp::Result<()> {
629/// #     let p = &StandardPolicy::new();
630/// #     let (cert, _) =
631/// #         CertBuilder::general_purpose(Some("alice@example.org"))
632/// #         .generate()?;
633/// #     let fpr = cert.fingerprint();
634/// // Iterate over all User IDs.
635/// for ua in cert.userids() {
636///     // ua is a `ComponentAmalgamation`, specifically, a `UserIDAmalgamation`.
637/// }
638/// #     Ok(())
639/// # }
640/// ```
641///
642/// [`Cert`]: super::Cert
643/// [`Cert::userids`]: super::Cert::userids()
644/// [`ValidCert::primary_userid`]: super::ValidCert::primary_userid()
645/// [`Cert::user_attributes`]: super::Cert::user_attributes()
646/// [`Cert::unknowns`]: super::Cert::unknowns()
647/// [`ComponentAmalgamation::with_policy`]: ValidateAmalgamation::with_policy()
648/// [See the module's documentation]: self
649#[derive(Debug, PartialEq)]
650pub struct ComponentAmalgamation<'a, C> {
651    cert: &'a Cert,
652    bundle: &'a ComponentBundle<C>,
653}
654assert_send_and_sync!(ComponentAmalgamation<'_, C> where C);
655
656/// A User ID and its associated data.
657///
658/// A specialized version of [`ComponentAmalgamation`].
659///
660pub type UserIDAmalgamation<'a> = ComponentAmalgamation<'a, UserID>;
661
662/// A User Attribute and its associated data.
663///
664/// A specialized version of [`ComponentAmalgamation`].
665///
666pub type UserAttributeAmalgamation<'a>
667    = ComponentAmalgamation<'a, UserAttribute>;
668
669/// An Unknown component and its associated data.
670///
671/// A specialized version of [`ComponentAmalgamation`].
672///
673pub type UnknownComponentAmalgamation<'a>
674    = ComponentAmalgamation<'a, Unknown>;
675
676// derive(Clone) doesn't work with generic parameters that don't
677// implement clone.  But, we don't need to require that C implements
678// Clone, because we're not cloning C, just the reference.
679//
680// See: https://github.com/rust-lang/rust/issues/26925
681impl<'a, C> Clone for ComponentAmalgamation<'a, C> {
682    fn clone(&self) -> Self {
683        Self {
684            cert: self.cert,
685            bundle: self.bundle,
686        }
687    }
688}
689
690impl<'a, C> ComponentAmalgamation<'a, C> {
691    /// Creates a new amalgamation.
692    pub(crate) fn new(cert: &'a Cert, bundle: &'a ComponentBundle<C>) -> Self
693    {
694        Self {
695            cert,
696            bundle,
697        }
698    }
699
700    /// Returns the amalgamations's associated certificate.
701    ///
702    /// ```
703    /// # use sequoia_openpgp as openpgp;
704    /// # use openpgp::cert::prelude::*;
705    /// #
706    /// # fn main() -> openpgp::Result<()> {
707    /// # let (cert, _) =
708    /// #     CertBuilder::general_purpose(Some("alice@example.org"))
709    /// #     .generate()?;
710    /// for u in cert.userids() {
711    ///     // It's not only an identical `Cert`, it's the same one.
712    ///     assert!(std::ptr::eq(u.cert(), &cert));
713    /// }
714    /// # Ok(()) }
715    /// ```
716    pub fn cert(&self) -> &'a Cert {
717        self.cert
718    }
719
720    /// Returns the active binding signature at time `t`.
721    ///
722    /// The active binding signature is the most recent, non-revoked
723    /// self-signature that is valid according to the `policy` and
724    /// alive at time `t` (`creation time <= t`, `t < expiry`).  If
725    /// there are multiple such signatures then the signatures are
726    /// ordered by their MPIs interpreted as byte strings.
727    ///
728    /// # Examples
729    ///
730    /// ```
731    /// # use sequoia_openpgp as openpgp;
732    /// # use openpgp::cert::prelude::*;
733    /// use openpgp::policy::StandardPolicy;
734    /// #
735    /// # fn main() -> openpgp::Result<()> {
736    /// let p = &StandardPolicy::new();
737    ///
738    /// # let (cert, _) =
739    /// #     CertBuilder::general_purpose(Some("alice@example.org"))
740    /// #     .generate()?;
741    /// // Display information about each User ID's current active
742    /// // binding signature (the `time` parameter is `None`), if any.
743    /// for ua in cert.userids() {
744    ///     eprintln!("{:?}", ua.binding_signature(p, None));
745    /// }
746    /// # Ok(()) }
747    /// ```
748    pub fn binding_signature<T>(&self, policy: &dyn Policy, time: T)
749                                -> Result<&'a Signature>
750        where T: Into<Option<time::SystemTime>>
751    {
752        let time = time.into().unwrap_or_else(crate::now);
753        self.bundle().binding_signature(policy, time)
754    }
755
756    /// Returns this amalgamation's bundle.
757    ///
758    /// # Examples
759    ///
760    /// ```
761    /// # fn main() -> sequoia_openpgp::Result<()> {
762    /// # use sequoia_openpgp as openpgp;
763    /// use openpgp::cert::prelude::*;
764    /// use openpgp::packet::prelude::*;
765    ///
766    /// # let (cert, _) = CertBuilder::new()
767    /// #     .add_userid("Alice")
768    /// #     .add_signing_subkey()
769    /// #     .add_transport_encryption_subkey()
770    /// #     .generate()?;
771    /// cert.userids()
772    ///     .map(|ua| ua.bundle())
773    ///     .collect::<Vec<&ComponentBundle<_>>>();
774    /// # Ok(()) }
775    /// ```
776    pub fn bundle(&self) -> &'a ComponentBundle<C> {
777        self.bundle
778    }
779
780    /// Returns this amalgamation's component.
781    ///
782    /// # Examples
783    ///
784    /// ```
785    /// # use sequoia_openpgp as openpgp;
786    /// # use openpgp::cert::prelude::*;
787    /// #
788    /// # fn main() -> openpgp::Result<()> {
789    /// # let (cert, _) =
790    /// #     CertBuilder::general_purpose(Some("alice@example.org"))
791    /// #     .generate()?;
792    /// // Display some information about any unknown components.
793    /// for u in cert.unknowns() {
794    ///     eprintln!(" - {:?}", u.component());
795    /// }
796    /// # Ok(()) }
797    /// ```
798    pub fn component(&self) -> &'a C {
799        self.bundle().component()
800    }
801
802    /// Returns the component's self-signatures.
803    ///
804    /// The signatures are validated, and they are sorted by their
805    /// creation time, most recent first.
806    ///
807    /// # Examples
808    ///
809    /// ```
810    /// # use sequoia_openpgp as openpgp;
811    /// # use openpgp::cert::prelude::*;
812    /// use openpgp::policy::StandardPolicy;
813    /// #
814    /// # fn main() -> openpgp::Result<()> {
815    /// let p = &StandardPolicy::new();
816    ///
817    /// # let (cert, _) =
818    /// #     CertBuilder::general_purpose(Some("alice@example.org"))
819    /// #     .generate()?;
820    /// for (i, ka) in cert.keys().enumerate() {
821    ///     eprintln!("Key #{} ({}) has {:?} self signatures",
822    ///               i, ka.key().fingerprint(),
823    ///               ka.self_signatures().count());
824    /// }
825    /// # Ok(()) }
826    /// ```
827    pub fn self_signatures(&self) -> impl Iterator<Item=&'a Signature> + Send + Sync {
828        self.bundle().self_signatures()
829    }
830
831    /// Returns the component's third-party certifications.
832    ///
833    /// The signatures are *not* validated.  They are sorted by their
834    /// creation time, most recent first.
835    ///
836    /// # Examples
837    ///
838    /// ```
839    /// # use sequoia_openpgp as openpgp;
840    /// # use openpgp::cert::prelude::*;
841    /// use openpgp::policy::StandardPolicy;
842    /// #
843    /// # fn main() -> openpgp::Result<()> {
844    /// let p = &StandardPolicy::new();
845    ///
846    /// # let (cert, _) =
847    /// #     CertBuilder::general_purpose(Some("alice@example.org"))
848    /// #     .generate()?;
849    /// for ua in cert.userids() {
850    ///     eprintln!("User ID {} has {:?} unverified, third-party certifications",
851    ///               String::from_utf8_lossy(ua.userid().value()),
852    ///               ua.certifications().count());
853    /// }
854    /// # Ok(()) }
855    /// ```
856    pub fn certifications(&self) -> impl Iterator<Item=&'a Signature> + Send + Sync {
857        self.bundle().certifications()
858    }
859
860    /// Returns third-party certifications that appear to issued by
861    /// any of the specified keys.
862    ///
863    /// A certification is returned if one of the provided key handles
864    /// matches an [Issuer subpacket] or [Issuer Fingerprint
865    /// subpacket] in the certification.
866    ///
867    ///   [Issuer subpacket]: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.12
868    ///   [Issuer Fingerprint subpacket]: https://www.rfc-editor.org/rfc/rfc9580.html#name-intended-recipient-fingerpr
869    ///
870    /// This function does not check that a certification is valid.
871    /// It can't.  To check that a certification was actually issued
872    /// by a specific key, we also need a policy and the public key,
873    /// which we don't have.  To only get valid certifications, use
874    /// [`UserIDAmalgamation::valid_certifications_by_key`] or
875    /// [`UserIDAmalgamation::active_certifications_by_key`] instead
876    /// of this function.
877    pub fn certifications_by_key<'b>(&'b self, issuers: &'b [ KeyHandle ])
878        -> impl Iterator<Item=&'a Signature> + Send + Sync + 'b
879    {
880        self.certifications().filter(|certification| {
881            certification.get_issuers().into_iter().any(|certification_issuer| {
882                issuers.iter().any(|issuer| {
883                    certification_issuer.aliases(issuer)
884                })
885            })
886        })
887    }
888
889    /// Returns the component's revocations that were issued by the
890    /// certificate holder.
891    ///
892    /// The revocations are validated, and they are sorted by their
893    /// creation time, most recent first.
894    ///
895    /// # Examples
896    ///
897    /// ```
898    /// # use sequoia_openpgp as openpgp;
899    /// # use openpgp::cert::prelude::*;
900    /// use openpgp::policy::StandardPolicy;
901    /// #
902    /// # fn main() -> openpgp::Result<()> {
903    /// let p = &StandardPolicy::new();
904    ///
905    /// # let (cert, _) =
906    /// #     CertBuilder::general_purpose(Some("alice@example.org"))
907    /// #     .generate()?;
908    /// for u in cert.userids() {
909    ///     eprintln!("User ID {} has {:?} revocation certificates.",
910    ///               String::from_utf8_lossy(u.userid().value()),
911    ///               u.self_revocations().count());
912    /// }
913    /// # Ok(()) }
914    /// ```
915    pub fn self_revocations(&self) -> impl Iterator<Item=&'a Signature> + Send + Sync {
916        self.bundle().self_revocations()
917    }
918
919    /// Returns the component's revocations that were issued by other
920    /// certificates.
921    ///
922    /// The revocations are *not* validated.  They are sorted by their
923    /// creation time, most recent first.
924    ///
925    /// # Examples
926    ///
927    /// ```
928    /// # use sequoia_openpgp as openpgp;
929    /// # use openpgp::cert::prelude::*;
930    /// use openpgp::policy::StandardPolicy;
931    /// #
932    /// # fn main() -> openpgp::Result<()> {
933    /// let p = &StandardPolicy::new();
934    ///
935    /// # let (cert, _) =
936    /// #     CertBuilder::general_purpose(Some("alice@example.org"))
937    /// #     .generate()?;
938    /// for u in cert.userids() {
939    ///     eprintln!("User ID {} has {:?} unverified, third-party revocation certificates.",
940    ///               String::from_utf8_lossy(u.userid().value()),
941    ///               u.other_revocations().count());
942    /// }
943    /// # Ok(()) }
944    /// ```
945    pub fn other_revocations(&self) -> impl Iterator<Item=&'a Signature> + Send + Sync {
946        self.bundle().other_revocations()
947    }
948
949    /// Returns all the component's Certification Approval Key
950    /// Signatures.
951    ///
952    /// This feature is [experimental](crate#experimental-features).
953    ///
954    /// The signatures are validated, and they are sorted by their
955    /// creation time, most recent first.
956    ///
957    /// A certificate owner can use Certification Approval Key
958    /// Signatures to approve of third party certifications.
959    /// Currently, only userid and user attribute certifications can
960    /// be approved of.  See [Approved Certifications subpacket] for
961    /// details.
962    ///
963    ///   [Approved Certifications subpacket]: https://www.ietf.org/archive/id/draft-dkg-openpgp-1pa3pc-02.html#approved-certifications-subpacket
964    ///
965    /// # Examples
966    ///
967    /// ```
968    /// # use sequoia_openpgp as openpgp;
969    /// # fn main() -> openpgp::Result<()> {
970    /// # use openpgp::cert::prelude::*;
971    /// use openpgp::policy::StandardPolicy;
972    /// let p = &StandardPolicy::new();
973    ///
974    /// # let (cert, _) =
975    /// #     CertBuilder::general_purpose(Some("alice@example.org"))
976    /// #     .generate()?;
977    /// for (i, uid) in cert.userids().enumerate() {
978    ///     eprintln!("UserID #{} ({:?}) has {:?} certification approval key signatures",
979    ///               i, uid.userid().email(),
980    ///               uid.approvals().count());
981    /// }
982    /// # Ok(()) }
983    /// ```
984    pub fn approvals(&self)
985                     -> impl Iterator<Item=&'a Signature> + Send + Sync + 'a
986    {
987        self.bundle().approvals()
988    }
989
990    /// Returns all the component's signatures.
991    ///
992    /// Only the self-signatures are validated.  The signatures are
993    /// sorted first by type, then by creation time.  The self
994    /// revocations come first, then the self signatures,
995    /// then any certification approval key  signatures,
996    /// certifications, and third-party revocations coming last.  This
997    /// function may return additional types of signatures that could
998    /// be associated to this component.
999    ///
1000    /// # Examples
1001    ///
1002    /// ```
1003    /// # use sequoia_openpgp as openpgp;
1004    /// # use openpgp::cert::prelude::*;
1005    /// use openpgp::policy::StandardPolicy;
1006    /// #
1007    /// # fn main() -> openpgp::Result<()> {
1008    /// let p = &StandardPolicy::new();
1009    ///
1010    /// # let (cert, _) =
1011    /// #     CertBuilder::general_purpose(Some("alice@example.org"))
1012    /// #     .generate()?;
1013    /// for (i, ka) in cert.keys().enumerate() {
1014    ///     eprintln!("Key #{} ({}) has {:?} signatures",
1015    ///               i, ka.key().fingerprint(),
1016    ///               ka.signatures().count());
1017    /// }
1018    /// # Ok(()) }
1019    /// ```
1020    pub fn signatures(&self)
1021                      -> impl Iterator<Item = &'a Signature> + Send + Sync {
1022        self.bundle().signatures()
1023    }
1024
1025    // Used to implement
1026    // [`UserIDAmalgamation::valid_certifications_by_key`],
1027    // [`KeyAmalgamation::valid_certifications_by_key`],
1028    // [`UserIDAmalgamation::active_certifications_by_key`], and
1029    // [`KeyAmalgamation::active_certifications_by_key`].
1030    fn valid_certifications_by_key_<'b, F>(
1031        &self,
1032        policy: &'a dyn Policy,
1033        reference_time: Option<time::SystemTime>,
1034        issuer: &'a packet::Key<packet::key::PublicParts,
1035                                packet::key::UnspecifiedRole>,
1036        only_active: bool,
1037        certifications: impl Iterator<Item=&'b Signature> + Send + Sync,
1038        verify_certification: F)
1039        -> impl Iterator<Item=&'b Signature> + Send + Sync
1040    where
1041        F: Fn(&Signature) -> Result<()>
1042    {
1043        let reference_time = reference_time.unwrap_or_else(crate::now);
1044        let issuer_handle = issuer.key_handle();
1045        let issuer_handle = &issuer_handle;
1046
1047        let mut certifications: Vec<(&Signature, _)> = certifications
1048            .filter_map(|certification| {
1049                // Extract the signature's creation time.  Ignore
1050                // certifications without a creation time: those are
1051                // malformed.
1052                certification
1053                    .signature_creation_time()
1054                    .map(|ct| (certification, ct))
1055            })
1056            .filter(|(certification, _ct)| {
1057                // Filter out certifications that definitely aren't
1058                // from `issuer`.
1059                certification.get_issuers().into_iter().any(|sig_issuer| {
1060                    sig_issuer.aliases(issuer_handle)
1061                })
1062            })
1063            .map(|(certification, ct)| {
1064                let hard = if matches!(certification.typ(),
1065                                       SignatureType::KeyRevocation
1066                                       | SignatureType::SubkeyRevocation
1067                                       | SignatureType::CertificationRevocation)
1068                {
1069                    certification.reason_for_revocation()
1070                        .map(|(reason, _text)| {
1071                            reason.revocation_type() == RevocationType::Hard
1072                        })
1073                        // Interpret an unspecified reason as a hard
1074                        // revocation.
1075                        .unwrap_or(true)
1076                } else {
1077                    false
1078                };
1079
1080                (certification, ct, hard)
1081            })
1082            .filter(|(_certification, ct, hard)| {
1083                // Skip certifications created after the reference
1084                // time, unless they are hard revocations.
1085                *ct <= reference_time || *hard
1086            })
1087            .filter(|(certification, ct, hard)| {
1088                // Check that the certification is not expired as of
1089                // the reference time.
1090                if *hard {
1091                    // Hard revocations don't expire.
1092                    true
1093                } else if let Some(validity)
1094                    = certification.signature_validity_period()
1095                {
1096                    if validity == Duration::new(0, 0) {
1097                        // "If this is not present or has a value of
1098                        // zero, it never expires."
1099                        //
1100                        // https://www.rfc-editor.org/rfc/rfc9580.html#name-key-expiration-time
1101                        true
1102                    } else {
1103                        // "the number of seconds after the signature
1104                        // creation time that the signature expires"
1105                        //
1106                        // Assume validity = 1 second, then:
1107                        //
1108                        //  expiry time   reference time    status
1109                        //  -----------   --------------    ------
1110                        //              >     ct            live
1111                        //  ct + 1      =     ct + 1        expired
1112                        //              <     ct + 2        expired
1113                        *ct + validity > reference_time
1114                    }
1115                } else {
1116                    true
1117                }
1118            })
1119            .filter(|(_certification, ct, hard)| {
1120                // Make sure the certification was created after the
1121                // certificate, unless they are hard revocations.
1122                self.cert.primary_key().key().creation_time() <= *ct || *hard
1123            })
1124            .filter(|(certification, _ct, _hard)| {
1125                // Make sure the certification conforms to the policy.
1126                policy
1127                    .signature(certification,
1128                               HashAlgoSecurity::CollisionResistance)
1129                    .is_ok()
1130            })
1131            .map(|(certification, ct, _hard)| (certification, ct))
1132            .collect();
1133
1134        // Sort the certifications by creation time so that the newest
1135        // certifications come first.
1136        certifications.sort_unstable_by(|(_, a), (_, b)| {
1137            a.cmp(b).reverse()
1138        });
1139
1140        // Check that the issuer actually made the signatures, and
1141        // collect the most recent certifications.
1142        let mut valid = Vec::new();
1143        for (certification, ct) in certifications.into_iter() {
1144            if only_active {
1145                if let Some((_active, active_ct)) = valid.get(0) {
1146                    if *active_ct != ct {
1147                        // This certification is further in the past.
1148                        // We're done.
1149                        break;
1150                    }
1151                }
1152            }
1153
1154            if let Ok(()) = verify_certification(certification) {
1155                valid.push((certification, ct));
1156            }
1157        }
1158
1159        valid.into_iter()
1160            .map(|(certification, _creation_time)| certification)
1161            .collect::<Vec<&Signature>>()
1162            .into_iter()
1163    }
1164}
1165
1166macro_rules! impl_with_policy {
1167    ($func:ident, $value:ident $(, $arg:ident: $type:ty )*) => {
1168        fn $func<T>(&self, policy: &'a dyn Policy, time: T, $($arg: $type, )*)
1169            -> Result<Self::V>
1170            where T: Into<Option<time::SystemTime>>,
1171                  Self: Sized
1172        {
1173            let time = time.into().unwrap_or_else(crate::now);
1174
1175            if $value {
1176                self.cert.with_policy(policy, time)?;
1177            }
1178
1179            let binding_signature = self.binding_signature(policy, time)?;
1180            let cert = self.cert;
1181            // We can't do `Cert::with_policy` as that would
1182            // result in infinite recursion.  But at this point,
1183            // we know the certificate is valid (unless the caller
1184            // doesn't care).
1185            Ok(ValidComponentAmalgamation {
1186                ca: self.clone(),
1187                cert: ValidCert {
1188                    cert,
1189                    policy,
1190                    time,
1191                },
1192                binding_signature,
1193            })
1194        }
1195    }
1196}
1197
1198impl<'a, C> seal::Sealed for ComponentAmalgamation<'a, C> {}
1199impl<'a, C> ValidateAmalgamation<'a, C> for ComponentAmalgamation<'a, C> {
1200    type V = ValidComponentAmalgamation<'a, C>;
1201
1202    impl_with_policy!(with_policy, true);
1203}
1204
1205impl<'a, C> ValidateAmalgamationRelaxed<'a, C> for ComponentAmalgamation<'a, C> {
1206    type V = ValidComponentAmalgamation<'a, C>;
1207
1208    impl_with_policy!(with_policy_relaxed, valid_cert, valid_cert: bool);
1209}
1210
1211impl<'a> UserIDAmalgamation<'a> {
1212    /// Returns a reference to the User ID.
1213    ///
1214    /// This is just a type-specific alias for
1215    /// [`ComponentAmalgamation::component`].
1216    ///
1217    /// # Examples
1218    ///
1219    /// ```
1220    /// # use sequoia_openpgp as openpgp;
1221    /// # use openpgp::cert::prelude::*;
1222    /// #
1223    /// # fn main() -> openpgp::Result<()> {
1224    /// # let (cert, _) =
1225    /// #     CertBuilder::general_purpose(Some("alice@example.org"))
1226    /// #     .generate()?;
1227    /// // Display some information about the User IDs.
1228    /// for ua in cert.userids() {
1229    ///     eprintln!(" - {:?}", ua.userid());
1230    /// }
1231    /// # Ok(()) }
1232    /// ```
1233    pub fn userid(&self) -> &'a UserID {
1234        self.component()
1235    }
1236
1237    /// Returns the User ID's revocation status at time `t`.<a
1238    /// name="userid_revocation_status"></a>
1239    ///
1240    /// <!-- Why we have the above anchor:
1241    ///      https://github.com/rust-lang/rust/issues/71912 -->
1242    ///
1243    /// A User ID is revoked at time `t` if:
1244    ///
1245    ///   - There is a live revocation at time `t` that is newer than
1246    ///     all live self signatures at time `t`.
1247    ///
1248    /// Note: Certs and subkeys have different criteria from User IDs
1249    /// and User Attributes.
1250    ///
1251    /// Note: this only returns whether this User ID is revoked; it
1252    /// does not imply anything about the Cert or other components.
1253    //
1254    /// # Examples
1255    ///
1256    /// ```
1257    /// # use sequoia_openpgp as openpgp;
1258    /// # use openpgp::cert::prelude::*;
1259    /// use openpgp::policy::StandardPolicy;
1260    /// #
1261    /// # fn main() -> openpgp::Result<()> {
1262    /// let p = &StandardPolicy::new();
1263    ///
1264    /// # let (cert, _) =
1265    /// #     CertBuilder::general_purpose(Some("alice@example.org"))
1266    /// #     .generate()?;
1267    /// // Display the User IDs' revocation status.
1268    /// for ua in cert.userids() {
1269    ///     eprintln!(" Revocation status of {}: {:?}",
1270    ///               String::from_utf8_lossy(ua.userid().value()),
1271    ///               ua.revocation_status(p, None));
1272    /// }
1273    /// # Ok(()) }
1274    /// ```
1275    pub fn revocation_status<T>(&self, policy: &dyn Policy, t: T)
1276                                -> RevocationStatus
1277    where
1278        T: Into<Option<time::SystemTime>>,
1279    {
1280        let t = t.into();
1281        self.bundle().revocation_status(policy, t)
1282    }
1283
1284    /// Returns the third-party certifications issued by the specified
1285    /// key, and valid at the specified time.
1286    ///
1287    /// This function returns the certifications issued by the
1288    /// specified key.  Specifically, it returns a certification if:
1289    ///
1290    ///   - it is well-formed,
1291    ///   - it is live with respect to the reference time,
1292    ///   - it conforms to the policy, and
1293    ///   - the signature is cryptographically valid.
1294    ///
1295    /// This method is implemented on a [`UserIDAmalgamation`] and not
1296    /// a [`ValidUserIDAmalgamation`], because a third-party
1297    /// certification does not require the user ID to be self-signed.
1298    ///
1299    /// # Examples
1300    ///
1301    /// Alice has certified that a certificate belongs to Bob on two
1302    /// occasions.  Whereas
1303    /// [`UserIDAmalgamation::valid_certifications_by_key`] returns
1304    /// both certifications,
1305    /// [`UserIDAmalgamation::active_certifications_by_key`] only
1306    /// returns the most recent certification.
1307    ///
1308    /// ```rust
1309    /// use sequoia_openpgp as openpgp;
1310    /// use openpgp::cert::prelude::*;
1311    /// # use openpgp::packet::signature::SignatureBuilder;
1312    /// # use openpgp::packet::UserID;
1313    /// use openpgp::policy::StandardPolicy;
1314    /// # use openpgp::types::SignatureType;
1315    ///
1316    /// const P: &StandardPolicy = &StandardPolicy::new();
1317    ///
1318    /// # fn main() -> openpgp::Result<()> {
1319    /// # let epoch = std::time::SystemTime::now()
1320    /// #     - std::time::Duration::new(100, 0);
1321    /// # let t0 = epoch;
1322    /// #
1323    /// # let (alice, _) = CertBuilder::new()
1324    /// #     .set_creation_time(t0)
1325    /// #     .add_userid("<alice@example.org>")
1326    /// #     .generate()
1327    /// #     .unwrap();
1328    /// let alice: Cert = // ...
1329    /// # alice;
1330    /// #
1331    /// # let bob_userid = "<bob@example.org>";
1332    /// # let (bob, _) = CertBuilder::new()
1333    /// #     .set_creation_time(t0)
1334    /// #     .add_userid(bob_userid)
1335    /// #     .generate()
1336    /// #     .unwrap();
1337    /// let bob: Cert = // ...
1338    /// # bob;
1339    ///
1340    /// # // Alice has not certified Bob's User ID.
1341    /// # let ua = bob.userids().next().expect("have a user id");
1342    /// # assert_eq!(
1343    /// #     ua.active_certifications_by_key(
1344    /// #         P, t0, alice.primary_key().key()).count(),
1345    /// #     0);
1346    /// #
1347    /// # // Have Alice certify Bob's certificate.
1348    /// # let mut alice_signer = alice
1349    /// #     .keys()
1350    /// #     .with_policy(P, None)
1351    /// #     .for_certification()
1352    /// #     .next().expect("have a certification-capable key")
1353    /// #     .key()
1354    /// #     .clone()
1355    /// #     .parts_into_secret().expect("have unencrypted key material")
1356    /// #     .into_keypair().expect("have unencrypted key material");
1357    /// #
1358    /// # let mut bob = bob;
1359    /// # for i in 1..=2usize {
1360    /// #     let ti = t0 + std::time::Duration::new(i as u64, 0);
1361    /// #
1362    /// #     let certification = SignatureBuilder::new(SignatureType::GenericCertification)
1363    /// #         .set_signature_creation_time(ti)?
1364    /// #         .sign_userid_binding(
1365    /// #             &mut alice_signer,
1366    /// #             bob.primary_key().key(),
1367    /// #             &UserID::from(bob_userid))?;
1368    /// #     bob = bob.insert_packets(certification)?.0;
1369    /// #
1370    /// #     let ua = bob.userids().next().expect("have a user id");
1371    /// #     assert_eq!(
1372    /// #         ua.valid_certifications_by_key(
1373    /// #             P, ti, alice.primary_key().key()).count(),
1374    /// #         i);
1375    /// #
1376    /// #     assert_eq!(
1377    /// #         ua.active_certifications_by_key(
1378    /// #             P, ti, alice.primary_key().key()).count(),
1379    /// #         1);
1380    /// # }
1381    /// let ua = bob.userids().next().expect("have user id");
1382    ///
1383    /// let valid_certifications = ua.valid_certifications_by_key(
1384    ///     P, None, alice.primary_key().key());
1385    /// // Alice certified Bob's certificate twice.
1386    /// assert_eq!(valid_certifications.count(), 2);
1387    ///
1388    /// let active_certifications = ua.active_certifications_by_key(
1389    ///     P, None, alice.primary_key().key());
1390    /// // But only the most recent one is active.
1391    /// assert_eq!(active_certifications.count(), 1);
1392    /// # Ok(()) }
1393    /// ```
1394    pub fn valid_certifications_by_key<T, PK>(&self,
1395                                              policy: &'a dyn Policy,
1396                                              reference_time: T,
1397                                              issuer: PK)
1398        -> impl Iterator<Item=&Signature> + Send + Sync
1399    where
1400        T: Into<Option<time::SystemTime>>,
1401        PK: Into<&'a packet::Key<packet::key::PublicParts,
1402                                 packet::key::UnspecifiedRole>>,
1403    {
1404        let reference_time = reference_time.into();
1405        let issuer = issuer.into();
1406
1407        self.valid_certifications_by_key_(
1408            policy, reference_time, issuer, false,
1409            self.certifications(),
1410            |sig| {
1411                sig.clone().verify_userid_binding(
1412                    issuer,
1413                    self.cert.primary_key().key(),
1414                    self.userid())
1415            })
1416    }
1417
1418    /// Returns any active third-party certifications issued by the
1419    /// specified key.
1420    ///
1421    /// This function is like
1422    /// [`UserIDAmalgamation::valid_certifications_by_key`], but it
1423    /// only returns active certifications.  Active certifications are
1424    /// the most recent valid certifications with respect to the
1425    /// reference time.
1426    ///
1427    /// Although there is normally only a single active certification,
1428    /// there can be multiple certifications with the same timestamp.
1429    /// In this case, all of them are returned.
1430    ///
1431    /// Unlike self-signatures, multiple third-party certifications
1432    /// issued by the same key at the same time can be sensible.  For
1433    /// instance, Alice may fully trust a CA for user IDs in a
1434    /// particular domain, and partially trust it for everything else.
1435    /// This can only be expressed using multiple certifications.
1436    ///
1437    /// This method is implemented on a [`UserIDAmalgamation`] and not
1438    /// a [`ValidUserIDAmalgamation`], because a third-party
1439    /// certification does not require the user ID to be self-signed.
1440    ///
1441    /// # Examples
1442    ///
1443    /// See the examples for
1444    /// [`UserIDAmalgamation::valid_certifications_by_key`].
1445    pub fn active_certifications_by_key<T, PK>(&self,
1446                                               policy: &'a dyn Policy,
1447                                               reference_time: T,
1448                                               issuer: PK)
1449        -> impl Iterator<Item=&Signature> + Send + Sync
1450    where
1451        T: Into<Option<time::SystemTime>>,
1452        PK: Into<&'a packet::Key<packet::key::PublicParts,
1453                                 packet::key::UnspecifiedRole>>,
1454    {
1455        let reference_time = reference_time.into();
1456        let issuer = issuer.into();
1457
1458        self.valid_certifications_by_key_(
1459            policy, reference_time, issuer, true,
1460            self.certifications(),
1461            |sig| {
1462                sig.clone().verify_userid_binding(
1463                    issuer,
1464                    self.cert.primary_key().key(),
1465                    self.userid())
1466            })
1467    }
1468
1469    /// Returns the third-party revocations issued by the specified
1470    /// key, and valid at the specified time.
1471    ///
1472    /// This function returns the revocations issued by the specified
1473    /// key.  Specifically, it returns a revocation if:
1474    ///
1475    ///   - it is well-formed,
1476    ///   - it is live with respect to the reference time,
1477    ///   - it conforms to the policy, and
1478    ///   - the signature is cryptographically valid.
1479    ///
1480    /// This method is implemented on a [`UserIDAmalgamation`] and not
1481    /// a [`ValidUserIDAmalgamation`], because a third-party
1482    /// revocation does not require the user ID to be self-signed.
1483    ///
1484    /// # Examples
1485    ///
1486    /// Alice revokes a user ID on Bob's certificate.
1487    ///
1488    /// ```rust
1489    /// use sequoia_openpgp as openpgp;
1490    /// use openpgp::cert::prelude::*;
1491    /// # use openpgp::Packet;
1492    /// # use openpgp::packet::signature::SignatureBuilder;
1493    /// # use openpgp::packet::UserID;
1494    /// use openpgp::policy::StandardPolicy;
1495    /// # use openpgp::types::ReasonForRevocation;
1496    /// # use openpgp::types::SignatureType;
1497    ///
1498    /// const P: &StandardPolicy = &StandardPolicy::new();
1499    ///
1500    /// # fn main() -> openpgp::Result<()> {
1501    /// # let epoch = std::time::SystemTime::now()
1502    /// #     - std::time::Duration::new(100, 0);
1503    /// # let t0 = epoch;
1504    /// # let t1 = epoch + std::time::Duration::new(1, 0);
1505    /// #
1506    /// # let (alice, _) = CertBuilder::new()
1507    /// #     .set_creation_time(t0)
1508    /// #     .add_userid("<alice@example.org>")
1509    /// #     .generate()
1510    /// #     .unwrap();
1511    /// let alice: Cert = // ...
1512    /// # alice;
1513    /// #
1514    /// # let bob_userid = "<bob@example.org>";
1515    /// # let (bob, _) = CertBuilder::new()
1516    /// #     .set_creation_time(t0)
1517    /// #     .add_userid(bob_userid)
1518    /// #     .generate()
1519    /// #     .unwrap();
1520    /// let bob: Cert = // ...
1521    /// # bob;
1522    ///
1523    /// # // Alice has not certified Bob's User ID.
1524    /// # let ua = bob.userids().next().expect("have a user id");
1525    /// # assert_eq!(
1526    /// #     ua.active_certifications_by_key(
1527    /// #         P, t0, alice.primary_key().key()).count(),
1528    /// #     0);
1529    /// #
1530    /// # // Have Alice certify Bob's certificate.
1531    /// # let mut alice_signer = alice
1532    /// #     .keys()
1533    /// #     .with_policy(P, None)
1534    /// #     .for_certification()
1535    /// #     .next().expect("have a certification-capable key")
1536    /// #     .key()
1537    /// #     .clone()
1538    /// #     .parts_into_secret().expect("have unencrypted key material")
1539    /// #     .into_keypair().expect("have unencrypted key material");
1540    /// #
1541    /// # let certification = SignatureBuilder::new(SignatureType::CertificationRevocation)
1542    /// #     .set_signature_creation_time(t1)?
1543    /// #     .set_reason_for_revocation(
1544    /// #         ReasonForRevocation::UIDRetired, b"")?
1545    /// #     .sign_userid_binding(
1546    /// #         &mut alice_signer,
1547    /// #         bob.primary_key().key(),
1548    /// #         &UserID::from(bob_userid))?;
1549    /// # let bob = bob.insert_packets([
1550    /// #     Packet::from(UserID::from(bob_userid)),
1551    /// #     Packet::from(certification),
1552    /// # ])?.0;
1553    /// let ua = bob.userids().next().expect("have user id");
1554    ///
1555    /// let revs = ua.valid_third_party_revocations_by_key(
1556    ///     P, None, alice.primary_key().key());
1557    /// // Alice revoked the User ID.
1558    /// assert_eq!(revs.count(), 1);
1559    /// # Ok(()) }
1560    /// ```
1561    pub fn valid_third_party_revocations_by_key<T, PK>(&self,
1562                                                       policy: &'a dyn Policy,
1563                                                       reference_time: T,
1564                                                       issuer: PK)
1565        -> impl Iterator<Item=&Signature> + Send + Sync
1566    where
1567        T: Into<Option<time::SystemTime>>,
1568        PK: Into<&'a packet::Key<packet::key::PublicParts,
1569                                 packet::key::UnspecifiedRole>>,
1570    {
1571        let reference_time = reference_time.into();
1572        let issuer = issuer.into();
1573
1574        self.valid_certifications_by_key_(
1575            policy, reference_time, issuer, false,
1576            self.other_revocations(),
1577            |sig| {
1578                sig.clone().verify_userid_revocation(
1579                    issuer,
1580                    self.cert.primary_key().key(),
1581                    self.userid())
1582            })
1583    }
1584
1585    /// Approves of third-party certifications.
1586    ///
1587    /// This feature is [experimental](crate#experimental-features).
1588    ///
1589    /// Allows the certificate owner to approve of third party
1590    /// certifications. See [Approved Certifications subpacket] for
1591    /// details.  This can be used to address certificate flooding
1592    /// concerns.
1593    ///
1594    ///   [Approved Certifications subpacket]: https://www.ietf.org/archive/id/draft-dkg-openpgp-1pa3pc-02.html#approved-certifications-subpacket
1595    ///
1596    /// A policy is needed, because the expiration is updated by
1597    /// updating the current binding signatures.
1598    ///
1599    /// # Examples
1600    ///
1601    /// ```
1602    /// # use sequoia_openpgp as openpgp;
1603    /// # fn main() -> openpgp::Result<()> {
1604    /// # use openpgp::cert::prelude::*;
1605    /// # use openpgp::packet::signature::SignatureBuilder;
1606    /// # use openpgp::types::*;
1607    /// # let policy = &openpgp::policy::StandardPolicy::new();
1608    /// let (alice, _) = CertBuilder::new()
1609    ///     .add_userid("alice@example.org")
1610    ///     .generate()?;
1611    /// let mut alice_signer =
1612    ///     alice.primary_key().key().clone().parts_into_secret()?
1613    ///     .into_keypair()?;
1614    ///
1615    /// let (bob, _) = CertBuilder::new()
1616    ///     .add_userid("bob@example.org")
1617    ///     .generate()?;
1618    /// let mut bob_signer =
1619    ///     bob.primary_key().key().clone().parts_into_secret()?
1620    ///     .into_keypair()?;
1621    /// let bob_pristine = bob.clone();
1622    ///
1623    /// // Have Alice certify the binding between "bob@example.org" and
1624    /// // Bob's key.
1625    /// let alice_certifies_bob
1626    ///     = bob.userids().next().unwrap().userid().bind(
1627    ///         &mut alice_signer, &bob,
1628    ///         SignatureBuilder::new(SignatureType::GenericCertification))?;
1629    /// let bob = bob.insert_packets(vec![alice_certifies_bob.clone()])?.0;
1630    ///
1631    /// // Have Bob approve of that certification.
1632    /// let bobs_uid = bob.userids().next().unwrap();
1633    /// let approvals =
1634    ///     bobs_uid.approve_of_certifications(
1635    ///         policy,
1636    ///         None,
1637    ///         &mut bob_signer,
1638    ///         bobs_uid.certifications())?;
1639    /// let bob = bob.insert_packets(approvals)?.0;
1640    ///
1641    /// assert_eq!(bob.bad_signatures().count(), 0);
1642    /// assert_eq!(bob.userids().next().unwrap().certifications().next(),
1643    ///            Some(&alice_certifies_bob));
1644    /// # Ok(()) }
1645    /// ```
1646    pub fn approve_of_certifications<T, C, S>(&self,
1647                                              policy: &dyn Policy,
1648                                              time: T,
1649                                              primary_signer: &mut dyn Signer,
1650                                              certifications: C)
1651        -> Result<Vec<Signature>>
1652    where T: Into<Option<time::SystemTime>>,
1653          C: IntoIterator<Item = S>,
1654          S: Borrow<Signature>,
1655    {
1656        let time = time.into();
1657        let certifications = certifications.into_iter()
1658            .collect::<Vec<_>>();
1659
1660        // Check if there is a previous attestation.  If so, we need
1661        // that to robustly override it.
1662        let old = self.clone()
1663            .with_policy(policy, time)
1664            .ok()
1665            .and_then(
1666                |v| v.certification_approval_key_signatures().next().cloned());
1667
1668        approve_of_certifications_common(self.cert().primary_key().key(),
1669                                         self.userid(),
1670                                         old, time, primary_signer,
1671                                         &certifications)
1672    }
1673}
1674
1675impl<'a> UserAttributeAmalgamation<'a> {
1676    /// Returns a reference to the User Attribute.
1677    ///
1678    /// This is just a type-specific alias for
1679    /// [`ComponentAmalgamation::component`].
1680    ///
1681    /// # Examples
1682    ///
1683    /// ```
1684    /// # use sequoia_openpgp as openpgp;
1685    /// # use openpgp::cert::prelude::*;
1686    /// #
1687    /// # fn main() -> openpgp::Result<()> {
1688    /// # let (cert, _) =
1689    /// #     CertBuilder::general_purpose(Some("alice@example.org"))
1690    /// #     .generate()?;
1691    /// // Display some information about the User Attributes
1692    /// for ua in cert.user_attributes() {
1693    ///     eprintln!(" - {:?}", ua.user_attribute());
1694    /// }
1695    /// # Ok(()) }
1696    /// ```
1697    pub fn user_attribute(&self) -> &'a UserAttribute {
1698        self.component()
1699    }
1700
1701    /// Returns the User Attribute's revocation status at time `t`.
1702    ///
1703    /// A User Attribute is revoked at time `t` if:
1704    ///
1705    ///   - There is a live revocation at time `t` that is newer than
1706    ///     all live self signatures at time `t`.
1707    ///
1708    /// Note: Certs and subkeys have different criteria from User IDs
1709    /// and User Attributes.
1710    ///
1711    /// Note: this only returns whether this User Attribute is revoked;
1712    /// it does not imply anything about the Cert or other components.
1713    //
1714    /// # Examples
1715    ///
1716    /// ```
1717    /// # use sequoia_openpgp as openpgp;
1718    /// # use openpgp::cert::prelude::*;
1719    /// use openpgp::policy::StandardPolicy;
1720    /// #
1721    /// # fn main() -> openpgp::Result<()> {
1722    /// let p = &StandardPolicy::new();
1723    ///
1724    /// # let (cert, _) =
1725    /// #     CertBuilder::general_purpose(Some("alice@example.org"))
1726    /// #     .generate()?;
1727    /// // Display the User Attributes' revocation status.
1728    /// for (i, ua) in cert.user_attributes().enumerate() {
1729    ///     eprintln!(" Revocation status of User Attribute #{}: {:?}",
1730    ///               i, ua.revocation_status(p, None));
1731    /// }
1732    /// # Ok(()) }
1733    /// ```
1734    pub fn revocation_status<T>(&self, policy: &dyn Policy, t: T)
1735                                -> RevocationStatus
1736    where
1737        T: Into<Option<time::SystemTime>>,
1738    {
1739        let t = t.into();
1740        self.bundle().revocation_status(policy, t)
1741    }
1742
1743    /// Approves of third-party certifications.
1744    ///
1745    /// This feature is [experimental](crate#experimental-features).
1746    ///
1747    /// Allows the certificate owner to approve of third party
1748    /// certifications. See [Approved Certifications subpacket] for
1749    /// details.  This can be used to address certificate flooding
1750    /// concerns.
1751    ///
1752    /// A policy is needed, because the expiration is updated by
1753    /// updating the current binding signatures.
1754    ///
1755    ///   [Approved Certifications subpacket]: https://www.ietf.org/archive/id/draft-dkg-openpgp-1pa3pc-02.html#approved-certifications-subpacket
1756    ///
1757    /// # Examples
1758    ///
1759    /// See [`UserIDAmalgamation::approve_of_certifications#examples`].
1760    ///
1761    ///   [`UserIDAmalgamation::approve_of_certifications#examples`]: UserIDAmalgamation#examples
1762    // The explicit link works around a bug in rustdoc.
1763    pub fn approve_of_certifications<T, C, S>(&self,
1764                                              policy: &dyn Policy,
1765                                              time: T,
1766                                              primary_signer: &mut dyn Signer,
1767                                              certifications: C)
1768        -> Result<Vec<Signature>>
1769    where T: Into<Option<time::SystemTime>>,
1770          C: IntoIterator<Item = S>,
1771          S: Borrow<Signature>,
1772    {
1773        let time = time.into();
1774        let certifications = certifications.into_iter()
1775            .collect::<Vec<_>>();
1776
1777        // Check if there is a previous attestation.  If so, we need
1778        // that to robustly override it.
1779        let old = self.clone()
1780            .with_policy(policy, time)
1781            .ok()
1782            .and_then(
1783                |v| v.certification_approval_key_signatures().next().cloned());
1784
1785        approve_of_certifications_common(self.cert().primary_key().key(),
1786                                         self.user_attribute(),
1787                                         old, time, primary_signer,
1788                                         &certifications)
1789    }
1790}
1791
1792/// Approves of third-party certifications.
1793fn approve_of_certifications_common<S>(key: &Key<PublicParts, PrimaryRole>,
1794                                          component: &dyn Hash,
1795                                          old_attestation: Option<Signature>,
1796                                          time: Option<SystemTime>,
1797                                          primary_signer: &mut dyn Signer,
1798                                          certifications: &[S])
1799                                          -> Result<Vec<Signature>>
1800where
1801    S: Borrow<Signature>,
1802{
1803    use crate::{
1804        packet::signature::{SignatureBuilder, subpacket::SubpacketArea},
1805        serialize::MarshalInto,
1806    };
1807
1808    // Fix the time.
1809    let now = time.unwrap_or_else(crate::now);
1810
1811    // Fix the algorithm.
1812    let hash_algo = HashAlgorithm::default();
1813    let digest_size = hash_algo.digest_size()?;
1814
1815    let mut attestations = Vec::new();
1816    for certification in certifications {
1817        let mut h = hash_algo.context()?
1818            .for_signature(primary_signer.public().version());
1819        certification.borrow().hash_for_confirmation(&mut h)?;
1820        attestations.push(h.into_digest()?);
1821    }
1822
1823    // Hashes SHOULD be sorted.
1824    attestations.sort();
1825
1826    // All attestation signatures we generate for this component
1827    // should have the same creation time.  Fix it now.  We also like
1828    // our signatures to be newer than any existing signatures.  Do so
1829    // by using the old attestation as template.
1830    let template = if let Some(old) = old_attestation {
1831        let mut s = SignatureBuilder::from(old)
1832            .set_reference_time(now)?;
1833        s.hashed_area_mut().clear();
1834        s.unhashed_area_mut().clear();
1835        s
1836    } else {
1837        // Backdate the signature a little so that we can immediately
1838        // override it.
1839        use crate::packet::signature::SIG_BACKDATE_BY;
1840
1841        let mut creation_time =
1842            now - time::Duration::new(SIG_BACKDATE_BY, 0);
1843
1844        // ... but don't backdate it further than the key's creation
1845        // time, which would make it invalid.
1846        let key_creation_time = primary_signer.public().creation_time();
1847        if creation_time < key_creation_time {
1848            // ... unless that would make it is later than now.
1849            creation_time = key_creation_time.min(now);
1850        }
1851
1852        let template = SignatureBuilder::new(SignatureType::CertificationApproval)
1853            .set_signature_creation_time(creation_time)?;
1854        template
1855
1856    };
1857
1858    let template = template
1859        .set_hash_algo(hash_algo);
1860
1861    // Compute the available space in the hashed area.  For this,
1862    // it is important that template.pre_sign has been called.
1863    let available_space = {
1864        // But, we do it on a clone, so that `template` is still not
1865        // initialized.
1866        let t = template.clone().pre_sign(primary_signer)?;
1867
1868        SubpacketArea::MAX_SIZE - t.hashed_area().serialized_len()
1869    };
1870
1871    // Reserve space for the subpacket header, length and tag.
1872    const SUBPACKET_HEADER_MAX_LEN: usize = 5 + 1;
1873
1874    // Compute the chunk size for each signature.
1875    let digests_per_sig =
1876        (available_space - SUBPACKET_HEADER_MAX_LEN) / digest_size;
1877
1878    // Now create the signatures.
1879    let mut sigs = Vec::new();
1880    for digests in attestations.chunks(digests_per_sig) {
1881        // Hash the components.  First, initialize the salt.
1882        let t = template.clone().pre_sign(primary_signer)?;
1883
1884        let mut hash = hash_algo.context()?
1885            .for_signature(primary_signer.public().version());
1886
1887        if let Some(salt) = t.sb_version.salt() {
1888            hash.update(salt);
1889        }
1890        key.hash(&mut hash)?;
1891        component.hash(&mut hash)?;
1892
1893        sigs.push(t
1894                  .set_approved_certifications(digests)?
1895                  .sign_hash(primary_signer, hash)?);
1896    }
1897
1898    if attestations.is_empty() {
1899        // The certificate owner can withdraw attestations by issuing
1900        // an empty attestation key signature.
1901        assert!(sigs.is_empty());
1902
1903        // Hash the components.  First, initialize the salt.
1904        let t = template.clone().pre_sign(primary_signer)?;
1905
1906        let mut hash = hash_algo.context()?
1907            .for_signature(primary_signer.public().version());
1908
1909        if let Some(salt) = t.sb_version.salt() {
1910            hash.update(salt);
1911        }
1912        key.hash(&mut hash)?;
1913        component.hash(&mut hash)?;
1914
1915        sigs.push(t
1916                  .set_approved_certifications(Option::<&[u8]>::None)?
1917                  .sign_hash(primary_signer, hash.clone())?);
1918    }
1919
1920    Ok(sigs)
1921}
1922
1923impl<'a> UnknownComponentAmalgamation<'a> {
1924    /// Returns a reference to the Unknown packet.
1925    ///
1926    /// This is just a type-specific alias for
1927    /// [`ComponentAmalgamation::component`].
1928    ///
1929    /// # Examples
1930    ///
1931    /// ```
1932    /// # use sequoia_openpgp as openpgp;
1933    /// # use openpgp::cert::prelude::*;
1934    /// #
1935    /// # fn main() -> openpgp::Result<()> {
1936    /// # let (cert, _) =
1937    /// #     CertBuilder::general_purpose(Some("alice@example.org"))
1938    /// #     .generate()?;
1939    /// // Display some information about the Unknown components.
1940    /// for u in cert.unknowns() {
1941    ///     eprintln!(" - {:?}", u.unknown());
1942    /// }
1943    /// # Ok(()) }
1944    /// ```
1945    pub fn unknown(&self) -> &'a Unknown {
1946        self.component()
1947    }
1948}
1949
1950/// A `ComponentAmalgamation` plus a `Policy` and a reference time.
1951///
1952/// A `ValidComponentAmalgamation` combines a
1953/// [`ComponentAmalgamation`] with a [`Policy`] and a reference time.
1954/// This allows it to implement the [`ValidAmalgamation`] trait, which
1955/// provides methods that require a [`Policy`] and a reference time.
1956/// Although `ComponentAmalgamation` could implement these methods by
1957/// requiring that the caller explicitly pass them in, embedding them
1958/// in the `ValidComponentAmalgamation` helps ensure that multipart
1959/// operations, even those that span multiple functions, use the same
1960/// `Policy` and reference time.
1961///
1962/// A `ValidComponentAmalgamation` is typically obtained by
1963/// transforming a `ComponentAmalgamation` using
1964/// [`ValidateAmalgamation::with_policy`].  A
1965/// [`ComponentAmalgamationIter`] can also be changed to yield
1966/// `ValidComponentAmalgamation`s.
1967///
1968/// A `ValidComponentAmalgamation` is guaranteed to come from a valid
1969/// certificate, and have a valid and live binding signature at the
1970/// specified reference time.  Note: this only means that the binding
1971/// signatures are live; it says nothing about whether the
1972/// *certificate* is live.  If you care about that, then you need to
1973/// check it separately.
1974///
1975/// # Examples
1976///
1977/// Print out information about all non-revoked User IDs.
1978///
1979/// ```
1980/// # use sequoia_openpgp as openpgp;
1981/// use openpgp::cert::prelude::*;
1982/// use openpgp::packet::prelude::*;
1983/// use openpgp::policy::StandardPolicy;
1984/// use openpgp::types::RevocationStatus;
1985///
1986/// # fn main() -> openpgp::Result<()> {
1987/// let p = &StandardPolicy::new();
1988/// # let (cert, _) = CertBuilder::new()
1989/// #     .add_userid("Alice")
1990/// #     .add_signing_subkey()
1991/// #     .add_transport_encryption_subkey()
1992/// #     .generate()?;
1993/// for u in cert.userids() {
1994///     // Create a `ValidComponentAmalgamation`.  This may fail if
1995///     // there are no binding signatures that are accepted by the
1996///     // policy and that are live right now.
1997///     let u = u.with_policy(p, None)?;
1998///
1999///     // Before using the User ID, we still need to check that it is
2000///     // not revoked; `ComponentAmalgamation::with_policy` ensures
2001///     // that there is a valid *binding signature*, not that the
2002///     // `ComponentAmalgamation` is valid.
2003///     //
2004///     // Note: `ValidComponentAmalgamation::revocation_status` and
2005///     // `Preferences::preferred_symmetric_algorithms` use the
2006///     // embedded policy and timestamp.  Even though we used `None` for
2007///     // the timestamp (i.e., now), they are guaranteed to use the same
2008///     // timestamp, because `with_policy` eagerly transforms it into
2009///     // the current time.
2010///     //
2011///     // Note: we only check whether the User ID is not revoked.  If
2012///     // we were using a key, we'd also want to check that it is alive.
2013///     // (Keys can expire, but User IDs cannot.)
2014///     if let RevocationStatus::Revoked(_revs) = u.revocation_status() {
2015///         // Revoked by the key owner.  (If we care about
2016///         // designated revokers, then we need to check those
2017///         // ourselves.)
2018///     } else {
2019///         // Print information about the User ID.
2020///         eprintln!("{}: preferred symmetric algorithms: {:?}",
2021///                   String::from_utf8_lossy(u.userid().value()),
2022///                   u.preferred_symmetric_algorithms());
2023///     }
2024/// }
2025/// # Ok(()) }
2026/// ```
2027///
2028/// [`Policy`]: crate::policy::Policy
2029#[derive(Debug)]
2030pub struct ValidComponentAmalgamation<'a, C> {
2031    ca: ComponentAmalgamation<'a, C>,
2032    cert: ValidCert<'a>,
2033    // The binding signature at time `time`.  (This is just a cache.)
2034    binding_signature: &'a Signature,
2035}
2036assert_send_and_sync!(ValidComponentAmalgamation<'_, C> where C);
2037
2038impl<'a, C> ValidComponentAmalgamation<'a, C> {
2039    /// Returns the valid amalgamation's associated certificate.
2040    ///
2041    /// ```
2042    /// # use sequoia_openpgp as openpgp;
2043    /// # use openpgp::cert::prelude::*;
2044    /// #
2045    /// # fn main() -> openpgp::Result<()> {
2046    /// # let (cert, _) =
2047    /// #     CertBuilder::general_purpose(Some("alice@example.org"))
2048    /// #     .generate()?;
2049    /// for u in cert.userids() {
2050    ///     // It's not only an identical `Cert`, it's the same one.
2051    ///     assert!(std::ptr::eq(u.cert(), &cert));
2052    /// }
2053    /// # Ok(()) }
2054    /// ```
2055    pub fn cert(&self) -> &'a Cert {
2056        self.ca.cert()
2057    }
2058
2059    /// Returns the valid amalgamation's active binding signature.
2060    ///
2061    /// The active binding signature is the most recent, non-revoked
2062    /// self-signature that is valid according to the `policy` and
2063    /// alive at time `t` (`creation time <= t`, `t < expiry`).  If
2064    /// there are multiple such signatures then the signatures are
2065    /// ordered by their MPIs interpreted as byte strings.
2066    ///
2067    /// # Examples
2068    ///
2069    /// ```
2070    /// # use sequoia_openpgp as openpgp;
2071    /// # use openpgp::cert::prelude::*;
2072    /// use openpgp::policy::StandardPolicy;
2073    /// #
2074    /// # fn main() -> openpgp::Result<()> {
2075    /// let p = &StandardPolicy::new();
2076    ///
2077    /// # let (cert, _) =
2078    /// #     CertBuilder::general_purpose(Some("alice@example.org"))
2079    /// #     .generate()?;
2080    /// // Display information about each User ID's current active
2081    /// // binding signature (the `time` parameter is `None`), if any.
2082    /// for ua in cert.with_policy(p, None)?.userids() {
2083    ///     eprintln!("{:?}", ua.binding_signature());
2084    /// }
2085    /// # Ok(()) }
2086    /// ```
2087    pub fn binding_signature(&self) -> &'a Signature {
2088        self.binding_signature
2089    }
2090
2091    /// Returns the valid amalgamation's amalgamation.
2092    ///
2093    /// # Examples
2094    ///
2095    /// ```
2096    /// # use sequoia_openpgp as openpgp;
2097    /// # use openpgp::cert::prelude::*;
2098    /// use openpgp::policy::StandardPolicy;
2099    ///
2100    /// # fn main() -> openpgp::Result<()> {
2101    /// let p = &StandardPolicy::new();
2102    ///
2103    /// # let (cert, _) = CertBuilder::new()
2104    /// #     .add_userid("Alice")
2105    /// #     .add_signing_subkey()
2106    /// #     .add_transport_encryption_subkey()
2107    /// #     .generate()?;
2108    /// // Get a user ID amalgamation.
2109    /// let ua = cert.userids().next().expect("added one");
2110    ///
2111    /// // Validate it, yielding a valid component amalgamation.
2112    /// let vua = ua.with_policy(p, None)?;
2113    ///
2114    /// // And here we get the amalgamation back.
2115    /// let ua2 = vua.amalgamation();
2116    /// assert_eq!(&ua, ua2);
2117    /// # Ok(()) }
2118    /// ```
2119    pub fn amalgamation(&self) -> &ComponentAmalgamation<'a, C> {
2120        &self.ca
2121    }
2122
2123    /// Returns this valid amalgamation's bundle.
2124    ///
2125    /// # Examples
2126    ///
2127    /// ```
2128    /// # fn main() -> sequoia_openpgp::Result<()> {
2129    /// # use sequoia_openpgp as openpgp;
2130    /// use openpgp::cert::prelude::*;
2131    /// use openpgp::packet::prelude::*;
2132    /// let p = &openpgp::policy::StandardPolicy::new();
2133    ///
2134    /// # let (cert, _) = CertBuilder::new()
2135    /// #     .add_userid("Alice")
2136    /// #     .add_signing_subkey()
2137    /// #     .add_transport_encryption_subkey()
2138    /// #     .generate()?;
2139    /// cert.with_policy(p, None)?.userids()
2140    ///     .map(|ua| ua.bundle())
2141    ///     .collect::<Vec<&ComponentBundle<_>>>();
2142    /// # Ok(()) }
2143    /// ```
2144    pub fn bundle(&self) -> &'a ComponentBundle<C> {
2145        self.ca.bundle()
2146    }
2147
2148    /// Returns this valid amalgamation's component.
2149    ///
2150    /// # Examples
2151    ///
2152    /// ```
2153    /// # use sequoia_openpgp as openpgp;
2154    /// # use openpgp::cert::prelude::*;
2155    /// # fn main() -> openpgp::Result<()> {
2156    /// # let (cert, _) =
2157    /// #     CertBuilder::general_purpose(Some("alice@example.org"))
2158    /// #     .generate()?;
2159    /// let p = &openpgp::policy::StandardPolicy::new();
2160    ///
2161    /// // Display some information about any userid components.
2162    /// for u in cert.with_policy(p, None)?.userids() {
2163    ///     eprintln!(" - {:?}", u.component());
2164    /// }
2165    /// # Ok(()) }
2166    /// ```
2167    pub fn component(&self) -> &'a C {
2168        self.bundle().component()
2169    }
2170}
2171
2172impl<'a, C> ValidComponentAmalgamation<'a, C>
2173where
2174    C: Send + Sync,
2175{
2176    /// Returns the valid amalgamation's self-signatures.
2177    ///
2178    /// The signatures are validated, and they are sorted by their
2179    /// creation time, most recent first.  This method only returns
2180    /// signatures that are valid under the current policy.
2181    ///
2182    /// # Examples
2183    ///
2184    /// ```
2185    /// # use sequoia_openpgp as openpgp;
2186    /// # use openpgp::cert::prelude::*;
2187    /// use openpgp::policy::StandardPolicy;
2188    /// #
2189    /// # fn main() -> openpgp::Result<()> {
2190    /// let p = &StandardPolicy::new();
2191    ///
2192    /// # let (cert, _) =
2193    /// #     CertBuilder::general_purpose(Some("alice@example.org"))
2194    /// #     .generate()?;
2195    /// for (i, ka) in cert.with_policy(p, None)?.keys().enumerate() {
2196    ///     eprintln!("Key #{} ({}) has {:?} self signatures",
2197    ///               i, ka.key().fingerprint(),
2198    ///               ka.self_signatures().count());
2199    /// }
2200    /// # Ok(()) }
2201    /// ```
2202    pub fn self_signatures(&self) -> impl Iterator<Item=&'a Signature> + Send + Sync + 'a {
2203        let policy = self.cert.policy();
2204        let has = self.ca.bundle().hash_algo_security;
2205
2206        self.ca.self_signatures()
2207          .filter(move |sig| policy.signature(sig, has).is_ok())
2208    }
2209
2210    /// Returns the component's third-party certifications.
2211    ///
2212    /// The signatures are *not* validated.  They are sorted by their
2213    /// creation time, most recent first.  This method only returns
2214    /// signatures that are valid under the current policy.
2215    ///
2216    /// # Examples
2217    ///
2218    /// ```
2219    /// # use sequoia_openpgp as openpgp;
2220    /// # use openpgp::cert::prelude::*;
2221    /// use openpgp::policy::StandardPolicy;
2222    /// #
2223    /// # fn main() -> openpgp::Result<()> {
2224    /// let p = &StandardPolicy::new();
2225    ///
2226    /// # let (cert, _) =
2227    /// #     CertBuilder::general_purpose(Some("alice@example.org"))
2228    /// #     .generate()?;
2229    /// for ua in cert.with_policy(p, None)?.userids() {
2230    ///     eprintln!("User ID {} has {:?} unverified, third-party certifications",
2231    ///               String::from_utf8_lossy(ua.userid().value()),
2232    ///               ua.certifications().count());
2233    /// }
2234    /// # Ok(()) }
2235    /// ```
2236    pub fn certifications(&self) -> impl Iterator<Item=&'a Signature> + Send + Sync + 'a {
2237        let policy = self.cert.policy();
2238
2239        self.ca.certifications()
2240          .filter(move |sig| policy.signature(sig,
2241            HashAlgoSecurity::CollisionResistance).is_ok())
2242    }
2243
2244    /// Returns the valid amalgamation's revocations that were issued
2245    /// by the certificate holder.
2246    ///
2247    /// The revocations are validated, and they are sorted by their
2248    /// creation time, most recent first.  This method only returns
2249    /// signatures that are valid under the current policy.
2250    ///
2251    /// # Examples
2252    ///
2253    /// ```
2254    /// # use sequoia_openpgp as openpgp;
2255    /// # use openpgp::cert::prelude::*;
2256    /// use openpgp::policy::StandardPolicy;
2257    /// #
2258    /// # fn main() -> openpgp::Result<()> {
2259    /// let p = &StandardPolicy::new();
2260    ///
2261    /// # let (cert, _) =
2262    /// #     CertBuilder::general_purpose(Some("alice@example.org"))
2263    /// #     .generate()?;
2264    /// for u in cert.with_policy(p, None)?.userids() {
2265    ///     eprintln!("User ID {} has {:?} revocation certificates.",
2266    ///               String::from_utf8_lossy(u.userid().value()),
2267    ///               u.self_revocations().count());
2268    /// }
2269    /// # Ok(()) }
2270    /// ```
2271    pub fn self_revocations(&self) -> impl Iterator<Item=&'a Signature> + Send + Sync + 'a  {
2272        let policy = self.cert.policy();
2273        let has = self.ca.bundle().hash_algo_security;
2274
2275        self.ca.self_revocations()
2276          .filter(move |sig| policy.signature(sig, has).is_ok())
2277    }
2278
2279    /// Returns the valid amalgamation's revocations that were issued
2280    /// by other certificates.
2281    ///
2282    /// The revocations are *not* validated.  They are sorted by their
2283    /// creation time, most recent first.  This method only returns
2284    /// signatures that are valid under the current policy.
2285    ///
2286    /// # Examples
2287    ///
2288    /// ```
2289    /// # use sequoia_openpgp as openpgp;
2290    /// # use openpgp::cert::prelude::*;
2291    /// use openpgp::policy::StandardPolicy;
2292    /// #
2293    /// # fn main() -> openpgp::Result<()> {
2294    /// let p = &StandardPolicy::new();
2295    ///
2296    /// # let (cert, _) =
2297    /// #     CertBuilder::general_purpose(Some("alice@example.org"))
2298    /// #     .generate()?;
2299    /// for u in cert.with_policy(p, None)?.userids() {
2300    ///     eprintln!("User ID {} has {:?} unverified, third-party revocation certificates.",
2301    ///               String::from_utf8_lossy(u.userid().value()),
2302    ///               u.other_revocations().count());
2303    /// }
2304    /// # Ok(()) }
2305    /// ```
2306    pub fn other_revocations(&self) -> impl Iterator<Item=&'a Signature> + Send + Sync + 'a {
2307        let policy = self.cert.policy();
2308
2309        self.ca.other_revocations()
2310          .filter(move |sig| policy.signature(sig,
2311            HashAlgoSecurity::CollisionResistance).is_ok())
2312    }
2313
2314    /// Returns all of the valid amalgamation's Certification Approval
2315    /// Key Signatures.
2316    ///
2317    /// This feature is [experimental](crate#experimental-features).
2318    ///
2319    /// The signatures are validated, and they are sorted by their
2320    /// creation time, most recent first.
2321    ///
2322    /// A certificate owner can use Certification Approval Key
2323    /// Signatures to approve of third party certifications.
2324    /// Currently, only userid and user attribute certifications can
2325    /// be approved.  See [Approved Certifications subpacket] for
2326    /// details.
2327    ///
2328    ///   [Approved Certifications subpacket]: https://www.ietf.org/archive/id/draft-dkg-openpgp-1pa3pc-02.html#approved-certifications-subpacket
2329    ///
2330    /// # Examples
2331    ///
2332    /// ```
2333    /// # use sequoia_openpgp as openpgp;
2334    /// # fn main() -> openpgp::Result<()> {
2335    /// # use openpgp::cert::prelude::*;
2336    /// use openpgp::policy::StandardPolicy;
2337    /// let p = &StandardPolicy::new();
2338    ///
2339    /// # let (cert, _) =
2340    /// #     CertBuilder::general_purpose(Some("alice@example.org"))
2341    /// #     .generate()?;
2342    /// for (i, uid) in cert.with_policy(p, None)?.userids().enumerate() {
2343    ///     eprintln!("UserID #{} ({:?}) has {:?} certification approval key signatures",
2344    ///               i, uid.userid().email(),
2345    ///               uid.approvals().count());
2346    /// }
2347    /// # Ok(()) }
2348    /// ```
2349    pub fn approvals(&self)
2350                     -> impl Iterator<Item = &'a Signature> + Send + Sync + 'a
2351    {
2352        let policy = self.cert.policy();
2353        let has = self.ca.bundle().hash_algo_security;
2354
2355        self.ca.approvals()
2356          .filter(move |sig| policy.signature(sig, has).is_ok())
2357    }
2358
2359    /// Returns all of the valid amalgamations's signatures.
2360    ///
2361    /// Only the self-signatures are validated.  The signatures are
2362    /// sorted first by type, then by creation time.  The self
2363    /// revocations come first, then the self signatures,
2364    /// then any certification approval key signatures,
2365    /// certifications, and third-party revocations coming last.  This
2366    /// function may return additional types of signatures that could
2367    /// be associated to this component.
2368    ///
2369    /// This method only returns signatures that are valid under the
2370    /// current policy.
2371    ///
2372    /// # Examples
2373    ///
2374    /// ```
2375    /// # use sequoia_openpgp as openpgp;
2376    /// # use openpgp::cert::prelude::*;
2377    /// use openpgp::policy::StandardPolicy;
2378    /// #
2379    /// # fn main() -> openpgp::Result<()> {
2380    /// let p = &StandardPolicy::new();
2381    ///
2382    /// # let (cert, _) =
2383    /// #     CertBuilder::general_purpose(Some("alice@example.org"))
2384    /// #     .generate()?;
2385    /// for (i, ka) in cert.with_policy(p, None)?.keys().enumerate() {
2386    ///     eprintln!("Key #{} ({}) has {:?} signatures",
2387    ///               i, ka.key().fingerprint(),
2388    ///               ka.signatures().count());
2389    /// }
2390    /// # Ok(()) }
2391    /// ```
2392    pub fn signatures(&self)
2393                      -> impl Iterator<Item = &'a Signature> + Send + Sync + 'a {
2394        let policy = self.cert.policy();
2395
2396        self.ca.signatures()
2397          .filter(move |sig| policy.signature(sig,
2398            HashAlgoSecurity::CollisionResistance).is_ok())
2399    }
2400}
2401
2402/// A Valid User ID and its associated data.
2403///
2404/// A specialized version of [`ValidComponentAmalgamation`].
2405///
2406pub type ValidUserIDAmalgamation<'a> = ValidComponentAmalgamation<'a, UserID>;
2407
2408impl<'a> ValidUserIDAmalgamation<'a> {
2409    /// Returns a reference to the User ID.
2410    ///
2411    /// This is just a type-specific alias for
2412    /// [`ValidComponentAmalgamation::component`].
2413    ///
2414    /// # Examples
2415    ///
2416    /// ```
2417    /// # use sequoia_openpgp as openpgp;
2418    /// # use openpgp::cert::prelude::*;
2419    /// #
2420    /// # fn main() -> openpgp::Result<()> {
2421    /// # let (cert, _) =
2422    /// #     CertBuilder::general_purpose(Some("alice@example.org"))
2423    /// #     .generate()?;
2424    /// // Display some information about the User IDs.
2425    /// for ua in cert.userids() {
2426    ///     eprintln!(" - {:?}", ua.userid());
2427    /// }
2428    /// # Ok(()) }
2429    /// ```
2430    pub fn userid(&self) -> &'a UserID {
2431        self.component()
2432    }
2433
2434    /// Returns the user ID's approved third-party certifications.
2435    ///
2436    /// This feature is [experimental](crate#experimental-features).
2437    ///
2438    /// Allows the certificate owner to approve of third party
2439    /// certifications. See [Approved Certification subpacket] for
2440    /// details.  This can be used to address certificate flooding
2441    /// concerns.
2442    ///
2443    /// This method only returns signatures that are valid under the
2444    /// current policy and are approved by the certificate holder.
2445    ///
2446    ///   [Approved Certification subpacket]: https://www.ietf.org/archive/id/draft-dkg-openpgp-1pa3pc-02.html#approved-certifications-subpacket
2447    pub fn approved_certifications(&self)
2448        -> impl Iterator<Item=&Signature> + Send + Sync
2449    {
2450        let mut hash_algo = None;
2451        let digests: std::collections::HashSet<_> =
2452            self.certification_approval_key_signatures()
2453            .filter_map(|sig| {
2454                sig.approved_certifications().ok()
2455                    .map(|digest_iter| (sig, digest_iter))
2456            })
2457            .flat_map(|(sig, digest_iter)| {
2458                hash_algo = Some(sig.hash_algo());
2459                digest_iter
2460            })
2461            .collect();
2462
2463        self.certifications()
2464            .filter_map(move |sig| {
2465                let mut hash = hash_algo.and_then(|a| a.context().ok())?
2466                    .for_signature(sig.version());
2467                sig.hash_for_confirmation(&mut hash).ok()?;
2468                let digest = hash.into_digest().ok()?;
2469                if digests.contains(&digest[..]) {
2470                    Some(sig)
2471                } else {
2472                    None
2473                }
2474            })
2475    }
2476
2477    /// Returns set of active certification approval key signatures.
2478    ///
2479    /// This feature is [experimental](crate#experimental-features).
2480    ///
2481    /// Returns the set of signatures with the newest valid signature
2482    /// creation time.  Older signatures are not returned.  The sum of
2483    /// all digests in these signatures are the set of approved
2484    /// third-party certifications.
2485    ///
2486    /// This interface is useful for pruning old certification
2487    /// approval key signatures when filtering a certificate.
2488    ///
2489    /// Note: This is a low-level interface.  Consider using
2490    /// [`ValidUserIDAmalgamation::approved_certifications`] to
2491    /// iterate over all approved certifications.
2492    ///
2493    ///   [`ValidUserIDAmalgamation::approved_certifications`]: ValidUserIDAmalgamation#method.approved_certifications
2494    // The explicit link works around a bug in rustdoc.
2495    pub fn certification_approval_key_signatures(&'a self)
2496        -> impl Iterator<Item=&'a Signature> + Send + Sync
2497    {
2498        let mut first = None;
2499
2500        // The newest valid signature will be returned first.
2501        self.ca.approvals()
2502        // First, filter out any invalid (e.g. too new) signatures.
2503            .filter(move |sig| self.cert.policy().signature(
2504                sig,
2505                HashAlgoSecurity::CollisionResistance).is_ok())
2506            .take_while(move |sig| {
2507                let time_hash = (
2508                    if let Some(t) = sig.signature_creation_time() {
2509                        (t, sig.hash_algo())
2510                    } else {
2511                        // Something is off.  Just stop.
2512                        return false;
2513                    },
2514                    sig.hash_algo());
2515
2516                if let Some(reference) = first {
2517                    // Stop looking once we see an older signature or one
2518                    // with a different hash algo.
2519                    reference == time_hash
2520                } else {
2521                    first = Some(time_hash);
2522                    true
2523                }
2524            })
2525    }
2526
2527    /// Approves of third-party certifications.
2528    ///
2529    /// This feature is [experimental](crate#experimental-features).
2530    ///
2531    /// Allows the certificate owner to approve of third party
2532    /// certifications. See [Approved Certifications subpacket] for
2533    /// details.  This can be used to address certificate flooding
2534    /// concerns.
2535    ///
2536    ///   [Approved Certifications subpacket]: https://www.ietf.org/archive/id/draft-dkg-openpgp-1pa3pc-02.html#approved-certifications-subpacket
2537    ///
2538    /// # Examples
2539    ///
2540    /// ```
2541    /// # use sequoia_openpgp as openpgp;
2542    /// # fn main() -> openpgp::Result<()> {
2543    /// # use openpgp::cert::prelude::*;
2544    /// # use openpgp::packet::signature::SignatureBuilder;
2545    /// # use openpgp::types::*;
2546    /// # let policy = &openpgp::policy::StandardPolicy::new();
2547    /// let (alice, _) = CertBuilder::new()
2548    ///     .add_userid("alice@example.org")
2549    ///     .generate()?;
2550    /// let mut alice_signer =
2551    ///     alice.primary_key().key().clone().parts_into_secret()?
2552    ///     .into_keypair()?;
2553    ///
2554    /// let (bob, _) = CertBuilder::new()
2555    ///     .add_userid("bob@example.org")
2556    ///     .generate()?;
2557    /// let mut bob_signer =
2558    ///     bob.primary_key().key().clone().parts_into_secret()?
2559    ///     .into_keypair()?;
2560    /// let bob_pristine = bob.clone();
2561    ///
2562    /// // Have Alice certify the binding between "bob@example.org" and
2563    /// // Bob's key.
2564    /// let alice_certifies_bob
2565    ///     = bob.userids().next().unwrap().userid().bind(
2566    ///         &mut alice_signer, &bob,
2567    ///         SignatureBuilder::new(SignatureType::GenericCertification))?;
2568    /// let bob = bob.insert_packets(vec![alice_certifies_bob.clone()])?.0;
2569    ///
2570    /// // Have Bob approve of that certification.
2571    /// let bobs_uid = bob.with_policy(policy, None)?.userids().next().unwrap();
2572    /// let approvals =
2573    ///     bobs_uid.approve_of_certifications(
2574    ///         &mut bob_signer,
2575    ///         bobs_uid.certifications())?;
2576    /// let bob = bob.insert_packets(approvals)?.0;
2577    ///
2578    /// assert_eq!(bob.bad_signatures().count(), 0);
2579    /// assert_eq!(bob.userids().next().unwrap().certifications().next(),
2580    ///            Some(&alice_certifies_bob));
2581    /// # Ok(()) }
2582    /// ```
2583    pub fn approve_of_certifications<C, S>(&self,
2584                                           primary_signer: &mut dyn Signer,
2585                                           certifications: C)
2586                                           -> Result<Vec<Signature>>
2587    where C: IntoIterator<Item = S>,
2588          S: Borrow<Signature>,
2589    {
2590        self.ca
2591            .approve_of_certifications(self.policy(),
2592                                       self.time(),
2593                                       primary_signer,
2594                                       certifications)
2595    }
2596}
2597
2598/// A Valid User Attribute and its associated data.
2599///
2600/// A specialized version of [`ValidComponentAmalgamation`].
2601///
2602pub type ValidUserAttributeAmalgamation<'a>
2603    = ValidComponentAmalgamation<'a, UserAttribute>;
2604
2605impl<'a> ValidUserAttributeAmalgamation<'a> {
2606    /// Returns a reference to the User Attribute.
2607    ///
2608    /// This is just a type-specific alias for
2609    /// [`ValidComponentAmalgamation::component`].
2610    ///
2611    /// # Examples
2612    ///
2613    /// ```
2614    /// # use sequoia_openpgp as openpgp;
2615    /// # use openpgp::cert::prelude::*;
2616    /// #
2617    /// # fn main() -> openpgp::Result<()> {
2618    /// # let (cert, _) =
2619    /// #     CertBuilder::general_purpose(Some("alice@example.org"))
2620    /// #     .generate()?;
2621    /// // Display some information about the User IDs.
2622    /// for ua in cert.user_attributes() {
2623    ///     eprintln!(" - {:?}", ua.user_attribute());
2624    /// }
2625    /// # Ok(()) }
2626    /// ```
2627    pub fn user_attribute(&self) -> &'a UserAttribute {
2628        self.component()
2629    }
2630
2631    /// Returns the user attributes' approved third-party certifications.
2632    ///
2633    /// This feature is [experimental](crate#experimental-features).
2634    ///
2635    /// Allows the certificate owner to approve of third party
2636    /// certifications. See [Approved Certifications subpacket] for
2637    /// details.  This can be used to address certificate flooding
2638    /// concerns.
2639    ///
2640    /// This method only returns signatures that are valid under the
2641    /// current policy and are approved by the certificate holder.
2642    ///
2643    ///   [Approved Certifications subpacket]: https://www.ietf.org/archive/id/draft-dkg-openpgp-1pa3pc-02.html#approved-certifications-subpacket
2644    pub fn approved_certifications(&self)
2645        -> impl Iterator<Item=&Signature> + Send + Sync
2646    {
2647        let mut hash_algo = None;
2648        let digests: std::collections::HashSet<_> =
2649            self.certification_approval_key_signatures()
2650            .filter_map(|sig| {
2651                sig.approved_certifications().ok()
2652                    .map(|digest_iter| (sig, digest_iter))
2653            })
2654            .flat_map(|(sig, digest_iter)| {
2655                hash_algo = Some(sig.hash_algo());
2656                digest_iter
2657            })
2658            .collect();
2659
2660        self.certifications()
2661            .filter_map(move |sig| {
2662                let mut hash = hash_algo.and_then(|a| a.context().ok())?
2663                    .for_signature(sig.version());
2664                sig.hash_for_confirmation(&mut hash).ok()?;
2665                let digest = hash.into_digest().ok()?;
2666                if digests.contains(&digest[..]) {
2667                    Some(sig)
2668                } else {
2669                    None
2670                }
2671            })
2672    }
2673
2674    /// Returns set of active certification approval key signatures.
2675    ///
2676    /// This feature is [experimental](crate#experimental-features).
2677    ///
2678    /// Returns the set of signatures with the newest valid signature
2679    /// creation time.  Older signatures are not returned.  The sum of
2680    /// all digests in these signatures are the set of approved
2681    /// third-party certifications.
2682    ///
2683    /// This interface is useful for pruning old certification
2684    /// approval key signatures when filtering a certificate.
2685    ///
2686    /// Note: This is a low-level interface.  Consider using
2687    /// [`ValidUserAttributeAmalgamation::approved_certifications`] to
2688    /// iterate over all approved certifications.
2689    ///
2690    ///   [`ValidUserAttributeAmalgamation::approved_certifications`]: ValidUserAttributeAmalgamation#method.approved_certifications
2691    // The explicit link works around a bug in rustdoc.
2692    pub fn certification_approval_key_signatures(&'a self)
2693        -> impl Iterator<Item=&'a Signature> + Send + Sync
2694    {
2695        let mut first = None;
2696
2697        // The newest valid signature will be returned first.
2698        self.ca.approvals()
2699        // First, filter out any invalid (e.g. too new) signatures.
2700            .filter(move |sig| self.cert.policy().signature(
2701                sig,
2702                HashAlgoSecurity::CollisionResistance).is_ok())
2703            .take_while(move |sig| {
2704                let time_hash = (
2705                    if let Some(t) = sig.signature_creation_time() {
2706                        (t, sig.hash_algo())
2707                    } else {
2708                        // Something is off.  Just stop.
2709                        return false;
2710                    },
2711                    sig.hash_algo());
2712
2713                if let Some(reference) = first {
2714                    // Stop looking once we see an older signature or one
2715                    // with a different hash algo.
2716                    reference == time_hash
2717                } else {
2718                    first = Some(time_hash);
2719                    true
2720                }
2721            })
2722    }
2723
2724    /// Approves of third-party certifications.
2725    ///
2726    /// This feature is [experimental](crate#experimental-features).
2727    ///
2728    /// Allows the certificate owner to approve of third party
2729    /// certifications. See [Approved Certifications subpacket] for
2730    /// details.  This can be used to address certificate flooding
2731    /// concerns.
2732    ///
2733    ///   [Approved Certifications subpacket]: https://www.ietf.org/archive/id/draft-dkg-openpgp-1pa3pc-02.html#approved-certifications-subpacket
2734    ///
2735    /// # Examples
2736    ///
2737    /// See [`ValidUserIDAmalgamation::approve_of_certifications#examples`].
2738    ///
2739    ///   [`ValidUserIDAmalgamation::approve_of_certifications#examples`]: ValidUserIDAmalgamation#examples
2740    // The explicit link works around a bug in rustdoc.
2741    pub fn approve_of_certifications<C, S>(&self,
2742                                           primary_signer: &mut dyn Signer,
2743                                           certifications: C)
2744                                           -> Result<Vec<Signature>>
2745    where C: IntoIterator<Item = S>,
2746          S: Borrow<Signature>,
2747    {
2748        self.ca
2749            .approve_of_certifications(self.policy(),
2750                                       self.time(),
2751                                       primary_signer,
2752                                       certifications)
2753    }
2754}
2755
2756// derive(Clone) doesn't work with generic parameters that don't
2757// implement clone.  But, we don't need to require that C implements
2758// Clone, because we're not cloning C, just the reference.
2759//
2760// See: https://github.com/rust-lang/rust/issues/26925
2761impl<'a, C> Clone for ValidComponentAmalgamation<'a, C> {
2762    fn clone(&self) -> Self {
2763        Self {
2764            ca: self.ca.clone(),
2765            cert: self.cert.clone(),
2766            binding_signature: self.binding_signature,
2767        }
2768    }
2769}
2770
2771impl<'a, C: 'a> From<ValidComponentAmalgamation<'a, C>>
2772    for ComponentAmalgamation<'a, C>
2773{
2774    fn from(vca: ValidComponentAmalgamation<'a, C>) -> Self {
2775        assert!(std::ptr::eq(vca.ca.cert(), vca.cert.cert()));
2776        vca.ca
2777    }
2778}
2779
2780impl<'a, C> ValidComponentAmalgamation<'a, C>
2781    where C: Ord + Send + Sync
2782{
2783    /// Returns the amalgamated primary component at time `time`
2784    ///
2785    /// If `time` is None, then the current time is used.
2786    /// `ValidComponentAmalgamationIter` for the definition of a valid component.
2787    ///
2788    /// The primary component is determined by taking the components that
2789    /// are alive at time `t`, and sorting them as follows:
2790    ///
2791    ///   - non-revoked first
2792    ///   - primary first
2793    ///   - signature creation first
2794    ///
2795    /// If there is more than one, then one is selected in a
2796    /// deterministic, but undefined manner.
2797    ///
2798    /// If `valid_cert` is `false`, then this does not also check
2799    /// whether the certificate is valid; it only checks whether the
2800    /// component is valid.  Normally, this should be `true`.  This
2801    /// option is only exposed to allow breaking an infinite recursion:
2802    ///
2803    ///   - To check if a certificate is valid, we check if the
2804    ///     primary key is valid.
2805    ///
2806    ///   - To check if the primary key is valid, we need the primary
2807    ///     key's self signature
2808    ///
2809    ///   - To find the primary key's self signature, we need to find
2810    ///     the primary user id
2811    ///
2812    ///   - To find the primary user id, we need to check if the user
2813    ///     id is valid.
2814    ///
2815    ///   - To check if the user id is valid, we need to check that
2816    ///     the corresponding certificate is valid.
2817    pub(super) fn primary(cert: &'a Cert,
2818                          iter: std::slice::Iter<'a, ComponentBundle<C>>,
2819                          policy: &'a dyn Policy, t: SystemTime,
2820                          valid_cert: bool)
2821        -> Result<ValidComponentAmalgamation<'a, C>>
2822    {
2823        use std::cmp::Ordering;
2824
2825        let mut error = None;
2826
2827        // Filter out components that are not alive at time `t`.
2828        //
2829        // While we have the binding signature, extract a few
2830        // properties to avoid recomputing the same thing multiple
2831        // times.
2832        iter.filter_map(|c| {
2833            // No binding signature at time `t` => not alive.
2834            let sig = match c.binding_signature(policy, t) {
2835                Ok(sig) => Some(sig),
2836                Err(e) => {
2837                    error = Some(e);
2838                    None
2839                },
2840            }?;
2841
2842            let revoked = c._revocation_status(policy, t, false, Some(sig));
2843            let primary = sig.primary_userid().unwrap_or(false);
2844            let signature_creation_time = match sig.signature_creation_time() {
2845                Some(time) => Some(time),
2846                None => {
2847                    error = Some(Error::MalformedPacket(
2848                        "Signature has no creation time".into()).into());
2849                    None
2850                },
2851            }?;
2852
2853            Some(((c, sig, revoked), primary, signature_creation_time))
2854        })
2855            .max_by(|(a, a_primary, a_signature_creation_time),
2856                    (b, b_primary, b_signature_creation_time)| {
2857                match (matches!(&a.2, RevocationStatus::Revoked(_)),
2858                       matches!(&b.2, RevocationStatus::Revoked(_))) {
2859                    (true, false) => return Ordering::Less,
2860                    (false, true) => return Ordering::Greater,
2861                    _ => (),
2862                }
2863                match (a_primary, b_primary) {
2864                    (true, false) => return Ordering::Greater,
2865                    (false, true) => return Ordering::Less,
2866                    _ => (),
2867                }
2868                match a_signature_creation_time.cmp(b_signature_creation_time)
2869                {
2870                    Ordering::Less => return Ordering::Less,
2871                    Ordering::Greater => return Ordering::Greater,
2872                    Ordering::Equal => (),
2873                }
2874
2875                // Fallback to a lexographical comparison.  Prefer
2876                // the "smaller" one.
2877                match a.0.component().cmp(b.0.component()) {
2878                    Ordering::Less => Ordering::Greater,
2879                    Ordering::Greater => Ordering::Less,
2880                    Ordering::Equal =>
2881                        panic!("non-canonicalized Cert (duplicate components)"),
2882                }
2883            })
2884            .ok_or_else(|| {
2885                error.map(|e| e.context(format!(
2886                    "No binding signature at time {}", crate::fmt::time(&t))))
2887                    .unwrap_or_else(|| Error::NoBindingSignature(t).into())
2888            })
2889            .and_then(|c| ComponentAmalgamation::new(cert, (c.0).0)
2890                      .with_policy_relaxed(policy, t, valid_cert))
2891    }
2892}
2893
2894impl<'a, C> seal::Sealed for ValidComponentAmalgamation<'a, C> {}
2895impl<'a, C> ValidateAmalgamation<'a, C> for ValidComponentAmalgamation<'a, C> {
2896    type V = Self;
2897
2898    fn with_policy<T>(&self, policy: &'a dyn Policy, time: T) -> Result<Self::V>
2899        where T: Into<Option<time::SystemTime>>,
2900              Self: Sized,
2901    {
2902        assert!(std::ptr::eq(self.ca.cert(), self.cert.cert()));
2903
2904        let time = time.into().unwrap_or_else(crate::now);
2905        self.ca.with_policy(policy, time)
2906    }
2907}
2908
2909impl<'a, C> ValidAmalgamation<'a, C> for ValidComponentAmalgamation<'a, C>
2910where
2911    C: Send + Sync,
2912{
2913    fn valid_cert(&self) -> &ValidCert<'a> {
2914        assert!(std::ptr::eq(self.ca.cert(), self.cert.cert()));
2915        &self.cert
2916    }
2917
2918    fn time(&self) -> SystemTime {
2919        assert!(std::ptr::eq(self.ca.cert(), self.cert.cert()));
2920        self.cert.time
2921    }
2922
2923    fn policy(&self) -> &'a dyn Policy
2924    {
2925        assert!(std::ptr::eq(self.ca.cert(), self.cert.cert()));
2926        self.cert.policy
2927    }
2928
2929    fn binding_signature(&self) -> &'a Signature {
2930        assert!(std::ptr::eq(self.ca.cert(), self.cert.cert()));
2931        self.binding_signature
2932    }
2933
2934    fn revocation_status(&self) -> RevocationStatus<'a> {
2935        self.bundle()._revocation_status(self.policy(), self.cert.time,
2936                                         false, Some(self.binding_signature))
2937    }
2938
2939    fn revocation_keys(&self)
2940                       -> Box<dyn Iterator<Item = &'a RevocationKey> + 'a>
2941    {
2942        let mut keys = std::collections::HashSet::new();
2943
2944        let policy = self.policy();
2945        let pk_sec = self.cert().primary_key().key().hash_algo_security();
2946
2947        // All valid self-signatures.
2948        let sec = self.bundle().hash_algo_security;
2949        self.self_signatures()
2950            .filter(move |sig| {
2951                policy.signature(sig, sec).is_ok()
2952            })
2953        // All direct-key signatures.
2954            .chain(self.cert().primary_key()
2955                   .self_signatures()
2956                   .filter(|sig| {
2957                       policy.signature(sig, pk_sec).is_ok()
2958                   }))
2959            .flat_map(|sig| sig.revocation_keys())
2960            .for_each(|rk| { keys.insert(rk); });
2961
2962        Box::new(keys.into_iter())
2963    }
2964}
2965
2966impl<'a, C> ValidBindingSignature<'a, C> for ValidComponentAmalgamation<'a, C>
2967where
2968    C: Send + Sync,
2969{}
2970
2971impl<'a, C> crate::cert::Preferences<'a>
2972    for ValidComponentAmalgamation<'a, C>
2973where
2974    C: Send + Sync,
2975{
2976    fn preferred_symmetric_algorithms(&self)
2977                                      -> Option<&'a [SymmetricAlgorithm]> {
2978        self.map(|s| s.preferred_symmetric_algorithms())
2979    }
2980
2981    fn preferred_hash_algorithms(&self) -> Option<&'a [HashAlgorithm]> {
2982        self.map(|s| s.preferred_hash_algorithms())
2983    }
2984
2985    fn preferred_compression_algorithms(&self)
2986                                        -> Option<&'a [CompressionAlgorithm]> {
2987        self.map(|s| s.preferred_compression_algorithms())
2988    }
2989
2990    fn preferred_aead_ciphersuites(
2991        &self)
2992        -> Option<&'a [(SymmetricAlgorithm, AEADAlgorithm)]>
2993    {
2994        self.map(|s| s.preferred_aead_ciphersuites())
2995    }
2996
2997    fn key_server_preferences(&self) -> Option<KeyServerPreferences> {
2998        self.map(|s| s.key_server_preferences())
2999    }
3000
3001    fn preferred_key_server(&self) -> Option<&'a [u8]> {
3002        self.map(|s| s.preferred_key_server())
3003    }
3004
3005    fn policy_uri(&self) -> Option<&'a [u8]> {
3006        self.map(|s| s.policy_uri())
3007    }
3008
3009    fn features(&self) -> Option<Features> {
3010        self.map(|s| s.features())
3011    }
3012}
3013
3014#[cfg(test)]
3015mod test {
3016    use super::*;
3017
3018    use std::time::UNIX_EPOCH;
3019
3020    use crate::policy::StandardPolicy as P;
3021    use crate::Packet;
3022    use crate::packet::signature::SignatureBuilder;
3023    use crate::packet::UserID;
3024    use crate::types::SignatureType;
3025    use crate::types::ReasonForRevocation;
3026
3027    // derive(Clone) doesn't work with generic parameters that don't
3028    // implement clone.  Make sure that our custom implementations
3029    // work.
3030    //
3031    // See: https://github.com/rust-lang/rust/issues/26925
3032    #[test]
3033    fn clone() {
3034        let p = &P::new();
3035
3036        let (cert, _) = CertBuilder::new()
3037            .add_userid("test@example.example")
3038            .generate()
3039            .unwrap();
3040
3041        let userid : UserIDAmalgamation = cert.userids().next().unwrap();
3042        assert_eq!(userid.userid(), userid.clone().userid());
3043
3044        let userid : ValidUserIDAmalgamation
3045            = userid.with_policy(p, None).unwrap();
3046        let c = userid.clone();
3047        assert_eq!(userid.userid(), c.userid());
3048        assert_eq!(userid.time(), c.time());
3049    }
3050
3051    #[test]
3052    fn map() {
3053        // The reference returned by `ComponentAmalgamation::userid`
3054        // and `ComponentAmalgamation::user_attribute` is bound by the
3055        // reference to the `Component` in the
3056        // `ComponentAmalgamation`, not the `ComponentAmalgamation`
3057        // itself.
3058        let (cert, _) = CertBuilder::new()
3059            .add_userid("test@example.example")
3060            .generate()
3061            .unwrap();
3062
3063        let _ = cert.userids().map(|ua| ua.userid())
3064            .collect::<Vec<_>>();
3065
3066        let _ = cert.user_attributes().map(|ua| ua.user_attribute())
3067            .collect::<Vec<_>>();
3068    }
3069
3070    #[test]
3071    fn component_amalgamation_certifications_by_key() -> Result<()> {
3072        // Alice and Bob certify Carol's certificate.  We then check
3073        // that certifications_by_key returns them.
3074        let (alice, _) = CertBuilder::new()
3075            .add_userid("<alice@example.example>")
3076            .generate()
3077            .unwrap();
3078
3079        let (bob, _) = CertBuilder::new()
3080            .add_userid("<bob@example.example>")
3081            .generate()
3082            .unwrap();
3083
3084        let carol_userid = "<carol@example.example>";
3085        let (carol, _) = CertBuilder::new()
3086            .add_userid(carol_userid)
3087            .generate()
3088            .unwrap();
3089
3090        let ua = alice.userids().next().expect("have a user id");
3091        assert_eq!(ua.certifications_by_key(&[ alice.key_handle() ]).count(), 0);
3092
3093        // Alice has not certified Bob's User ID.
3094        let ua = bob.userids().next().expect("have a user id");
3095        assert_eq!(ua.certifications_by_key(&[ alice.key_handle() ]).count(), 0);
3096
3097        // Alice has not certified Carol's User ID.
3098        let ua = carol.userids().next().expect("have a user id");
3099        assert_eq!(ua.certifications_by_key(&[ alice.key_handle() ]).count(), 0);
3100
3101
3102        // Have Alice certify Carol's certificate.
3103        let mut alice_signer = alice.primary_key()
3104            .key()
3105            .clone()
3106            .parts_into_secret().expect("have unencrypted key material")
3107            .into_keypair().expect("have unencrypted key material");
3108        let certification = SignatureBuilder::new(SignatureType::GenericCertification)
3109            .sign_userid_binding(
3110                &mut alice_signer,
3111                carol.primary_key().key(),
3112                &UserID::from(carol_userid))?;
3113        let carol = carol.insert_packets(certification)?.0;
3114
3115        // Check that it is returned.
3116        let ua = carol.userids().next().expect("have a user id");
3117        assert_eq!(ua.certifications().count(), 1);
3118        assert_eq!(ua.certifications_by_key(&[ alice.key_handle() ]).count(), 1);
3119        assert_eq!(ua.certifications_by_key(&[ bob.key_handle() ]).count(), 0);
3120
3121
3122        // Have Bob certify Carol's certificate.
3123        let mut bob_signer = bob.primary_key()
3124            .key()
3125            .clone()
3126            .parts_into_secret().expect("have unencrypted key material")
3127            .into_keypair().expect("have unencrypted key material");
3128        let certification = SignatureBuilder::new(SignatureType::GenericCertification)
3129            .sign_userid_binding(
3130                &mut bob_signer,
3131                carol.primary_key().key(),
3132                &UserID::from(carol_userid))?;
3133        let carol = carol.insert_packets(certification)?.0;
3134
3135        // Check that it is returned.
3136        let ua = carol.userids().next().expect("have a user id");
3137        assert_eq!(ua.certifications().count(), 2);
3138        assert_eq!(ua.certifications_by_key(&[ alice.key_handle() ]).count(), 1);
3139        assert_eq!(ua.certifications_by_key(&[ bob.key_handle() ]).count(), 1);
3140
3141        // Again.
3142        let certification = SignatureBuilder::new(SignatureType::GenericCertification)
3143            .sign_userid_binding(
3144                &mut bob_signer,
3145                carol.primary_key().key(),
3146                &UserID::from(carol_userid))?;
3147        let carol = carol.insert_packets(certification)?.0;
3148
3149        // Check that it is returned.
3150        let ua = carol.userids().next().expect("have a user id");
3151        assert_eq!(ua.certifications().count(), 3);
3152        assert_eq!(ua.certifications_by_key(&[ alice.key_handle() ]).count(), 1);
3153        assert_eq!(ua.certifications_by_key(&[ bob.key_handle() ]).count(), 2);
3154
3155        Ok(())
3156    }
3157
3158    #[test]
3159    fn user_id_amalgamation_certifications_by_key() -> Result<()> {
3160        // Alice and Bob certify Carol's certificate.  We then check
3161        // that valid_certifications_by_key and
3162        // active_certifications_by_key return them.
3163        let p = &crate::policy::StandardPolicy::new();
3164
3165        // $ date -u -d '2024-01-02 13:00' +%s
3166        let t0 = UNIX_EPOCH + Duration::new(1704200400, 0);
3167        // $ date -u -d '2024-01-02 14:00' +%s
3168        let t1 = UNIX_EPOCH + Duration::new(1704204000, 0);
3169        // $ date -u -d '2024-01-02 15:00' +%s
3170        let t2 = UNIX_EPOCH + Duration::new(1704207600, 0);
3171
3172        let (alice, _) = CertBuilder::new()
3173            .set_creation_time(t0)
3174            .add_userid("<alice@example.example>")
3175            .generate()
3176            .unwrap();
3177        let alice_primary = alice.primary_key().key();
3178
3179        let (bob, _) = CertBuilder::new()
3180            .set_creation_time(t0)
3181            .add_userid("<bob@example.example>")
3182            .generate()
3183            .unwrap();
3184        let bob_primary = bob.primary_key().key();
3185
3186        let carol_userid = "<carol@example.example>";
3187        let (carol, _) = CertBuilder::new()
3188            .set_creation_time(t0)
3189            .add_userid(carol_userid)
3190            .generate()
3191            .unwrap();
3192
3193        let ua = alice.userids().next().expect("have a user id");
3194        assert_eq!(ua.valid_certifications_by_key(p, None, alice_primary).count(), 0);
3195        assert_eq!(ua.active_certifications_by_key(p, None, alice_primary).count(), 0);
3196
3197        // Alice has not certified Bob's User ID.
3198        let ua = bob.userids().next().expect("have a user id");
3199        assert_eq!(ua.valid_certifications_by_key(p, None, alice_primary).count(), 0);
3200        assert_eq!(ua.active_certifications_by_key(p, None, alice_primary).count(), 0);
3201
3202        // Alice has not certified Carol's User ID.
3203        let ua = carol.userids().next().expect("have a user id");
3204        assert_eq!(ua.valid_certifications_by_key(p, None, alice_primary).count(), 0);
3205        assert_eq!(ua.active_certifications_by_key(p, None, alice_primary).count(), 0);
3206
3207
3208        // Have Alice certify Carol's certificate at t1.
3209        let mut alice_signer = alice_primary
3210            .clone()
3211            .parts_into_secret().expect("have unencrypted key material")
3212            .into_keypair().expect("have unencrypted key material");
3213        let certification = SignatureBuilder::new(SignatureType::GenericCertification)
3214            .set_signature_creation_time(t1)?
3215            .sign_userid_binding(
3216                &mut alice_signer,
3217                carol.primary_key().key(),
3218                &UserID::from(carol_userid))?;
3219        let carol = carol.insert_packets(certification.clone())?.0;
3220
3221        // Check that it is returned.
3222        let ua = carol.userids().next().expect("have a user id");
3223        assert_eq!(ua.certifications().count(), 1);
3224
3225        assert_eq!(ua.valid_certifications_by_key(p, t0, alice_primary).count(), 0);
3226        assert_eq!(ua.active_certifications_by_key(p, t0, alice_primary).count(), 0);
3227
3228        assert_eq!(ua.valid_certifications_by_key(p, t1, alice_primary).count(), 1);
3229        assert_eq!(ua.active_certifications_by_key(p, t1, alice_primary).count(), 1);
3230
3231        assert_eq!(ua.valid_certifications_by_key(p, t1, bob_primary).count(), 0);
3232        assert_eq!(ua.active_certifications_by_key(p, t1, bob_primary).count(), 0);
3233
3234
3235        // Have Alice certify Carol's certificate at t1 (again).
3236        // Since both certifications were created at t1, they should
3237        // both be returned.
3238        let mut alice_signer = alice_primary
3239            .clone()
3240            .parts_into_secret().expect("have unencrypted key material")
3241            .into_keypair().expect("have unencrypted key material");
3242        let certification = SignatureBuilder::new(SignatureType::GenericCertification)
3243            .set_signature_creation_time(t1)?
3244            .sign_userid_binding(
3245                &mut alice_signer,
3246                carol.primary_key().key(),
3247                &UserID::from(carol_userid))?;
3248        let carol = carol.insert_packets(certification.clone())?.0;
3249
3250        // Check that it is returned.
3251        let ua = carol.userids().next().expect("have a user id");
3252        assert_eq!(ua.certifications().count(), 2);
3253        assert_eq!(ua.valid_certifications_by_key(p, t0, alice_primary).count(), 0);
3254        assert_eq!(ua.active_certifications_by_key(p, t0, alice_primary).count(), 0);
3255
3256        assert_eq!(ua.valid_certifications_by_key(p, t1, alice_primary).count(), 2);
3257        assert_eq!(ua.active_certifications_by_key(p, t1, alice_primary).count(), 2);
3258
3259        assert_eq!(ua.valid_certifications_by_key(p, t2, alice_primary).count(), 2);
3260        assert_eq!(ua.active_certifications_by_key(p, t2, alice_primary).count(), 2);
3261
3262        assert_eq!(ua.valid_certifications_by_key(p, t0, bob_primary).count(), 0);
3263        assert_eq!(ua.active_certifications_by_key(p, t0, bob_primary).count(), 0);
3264
3265
3266        // Have Alice certify Carol's certificate at t2.  Now we only
3267        // have one active certification.
3268        let mut alice_signer = alice_primary
3269            .clone()
3270            .parts_into_secret().expect("have unencrypted key material")
3271            .into_keypair().expect("have unencrypted key material");
3272        let certification = SignatureBuilder::new(SignatureType::GenericCertification)
3273            .set_signature_creation_time(t2)?
3274            .sign_userid_binding(
3275                &mut alice_signer,
3276                carol.primary_key().key(),
3277                &UserID::from(carol_userid))?;
3278        let carol = carol.insert_packets(certification.clone())?.0;
3279
3280        // Check that it is returned.
3281        let ua = carol.userids().next().expect("have a user id");
3282        assert_eq!(ua.certifications().count(), 3);
3283        assert_eq!(ua.valid_certifications_by_key(p, t0, alice_primary).count(), 0);
3284        assert_eq!(ua.active_certifications_by_key(p, t0, alice_primary).count(), 0);
3285
3286        assert_eq!(ua.valid_certifications_by_key(p, t1, alice_primary).count(), 2);
3287        assert_eq!(ua.active_certifications_by_key(p, t1, alice_primary).count(), 2);
3288
3289        assert_eq!(ua.valid_certifications_by_key(p, t2, alice_primary).count(), 3);
3290        assert_eq!(ua.active_certifications_by_key(p, t2, alice_primary).count(), 1);
3291
3292        assert_eq!(ua.valid_certifications_by_key(p, t0, bob_primary).count(), 0);
3293        assert_eq!(ua.active_certifications_by_key(p, t0, bob_primary).count(), 0);
3294
3295
3296        // Have Bob certify Carol's certificate at t1 and have it expire at t2.
3297        let mut bob_signer = bob.primary_key()
3298            .key()
3299            .clone()
3300            .parts_into_secret().expect("have unencrypted key material")
3301            .into_keypair().expect("have unencrypted key material");
3302        let certification = SignatureBuilder::new(SignatureType::GenericCertification)
3303            .set_signature_creation_time(t1)?
3304            .set_signature_validity_period(t2.duration_since(t1)?)?
3305            .sign_userid_binding(
3306                &mut bob_signer,
3307                carol.primary_key().key(),
3308                &UserID::from(carol_userid))?;
3309        let carol = carol.insert_packets(certification.clone())?.0;
3310
3311        // Check that it is returned.
3312        let ua = carol.userids().next().expect("have a user id");
3313        assert_eq!(ua.certifications().count(), 4);
3314
3315        assert_eq!(ua.valid_certifications_by_key(p, t0, alice_primary).count(), 0);
3316        assert_eq!(ua.active_certifications_by_key(p, t0, alice_primary).count(), 0);
3317
3318        assert_eq!(ua.valid_certifications_by_key(p, t1, alice_primary).count(), 2);
3319        assert_eq!(ua.active_certifications_by_key(p, t1, alice_primary).count(), 2);
3320
3321        assert_eq!(ua.valid_certifications_by_key(p, t2, alice_primary).count(), 3);
3322        assert_eq!(ua.active_certifications_by_key(p, t2, alice_primary).count(), 1);
3323
3324        assert_eq!(ua.valid_certifications_by_key(p, t0, bob_primary).count(), 0);
3325        assert_eq!(ua.active_certifications_by_key(p, t0, bob_primary).count(), 0);
3326
3327        assert_eq!(ua.valid_certifications_by_key(p, t1, bob_primary).count(), 1);
3328        assert_eq!(ua.active_certifications_by_key(p, t1, bob_primary).count(), 1);
3329
3330        // It expired.
3331        assert_eq!(ua.valid_certifications_by_key(p, t2, bob_primary).count(), 0);
3332        assert_eq!(ua.active_certifications_by_key(p, t2, bob_primary).count(), 0);
3333
3334
3335        // Have Bob certify Carol's certificate at t1 again.  This
3336        // time don't have it expire.
3337        let mut bob_signer = bob.primary_key()
3338            .key()
3339            .clone()
3340            .parts_into_secret().expect("have unencrypted key material")
3341            .into_keypair().expect("have unencrypted key material");
3342        let certification = SignatureBuilder::new(SignatureType::GenericCertification)
3343            .set_signature_creation_time(t1)?
3344            .sign_userid_binding(
3345                &mut bob_signer,
3346                carol.primary_key().key(),
3347                &UserID::from(carol_userid))?;
3348        let carol = carol.insert_packets(certification.clone())?.0;
3349
3350        // Check that it is returned.
3351        let ua = carol.userids().next().expect("have a user id");
3352        assert_eq!(ua.certifications().count(), 5);
3353        assert_eq!(ua.valid_certifications_by_key(p, t0, alice_primary).count(), 0);
3354        assert_eq!(ua.active_certifications_by_key(p, t0, alice_primary).count(), 0);
3355
3356        assert_eq!(ua.valid_certifications_by_key(p, t1, alice_primary).count(), 2);
3357        assert_eq!(ua.active_certifications_by_key(p, t1, alice_primary).count(), 2);
3358
3359        assert_eq!(ua.valid_certifications_by_key(p, t2, alice_primary).count(), 3);
3360        assert_eq!(ua.active_certifications_by_key(p, t2, alice_primary).count(), 1);
3361
3362        assert_eq!(ua.valid_certifications_by_key(p, t0, bob_primary).count(), 0);
3363        assert_eq!(ua.active_certifications_by_key(p, t0, bob_primary).count(), 0);
3364
3365        assert_eq!(ua.valid_certifications_by_key(p, t1, bob_primary).count(), 2);
3366        assert_eq!(ua.active_certifications_by_key(p, t1, bob_primary).count(), 2);
3367
3368        // One of the certifications expired.
3369        assert_eq!(ua.valid_certifications_by_key(p, t2, bob_primary).count(), 1);
3370        assert_eq!(ua.active_certifications_by_key(p, t2, bob_primary).count(), 1);
3371
3372        Ok(())
3373    }
3374
3375    #[test]
3376    fn user_id_amalgamation_third_party_revocations_by_key() -> Result<()> {
3377        // Alice and Bob revoke Carol's User ID.  We then check
3378        // that valid_third_party_revocations_by_key returns them.
3379        let p = &crate::policy::StandardPolicy::new();
3380
3381        // $ date -u -d '2024-01-02 13:00' +%s
3382        let t0 = UNIX_EPOCH + Duration::new(1704200400, 0);
3383        // $ date -u -d '2024-01-02 14:00' +%s
3384        let t1 = UNIX_EPOCH + Duration::new(1704204000, 0);
3385        // $ date -u -d '2024-01-02 15:00' +%s
3386        let t2 = UNIX_EPOCH + Duration::new(1704207600, 0);
3387
3388        let (alice, _) = CertBuilder::new()
3389            .set_creation_time(t0)
3390            .add_userid("<alice@example.example>")
3391            .generate()
3392            .unwrap();
3393        let alice_primary = alice.primary_key().key();
3394
3395        let (bob, _) = CertBuilder::new()
3396            .set_creation_time(t0)
3397            .add_userid("<bob@example.example>")
3398            .generate()
3399            .unwrap();
3400        let bob_primary = bob.primary_key().key();
3401
3402        let carol_userid = "<carol@example.example>";
3403        let (carol, _) = CertBuilder::new()
3404            .set_creation_time(t0)
3405            .add_userid(carol_userid)
3406            .generate()
3407            .unwrap();
3408        let carol_userid = UserID::from(carol_userid);
3409
3410        let ua = alice.userids().next().expect("have a user id");
3411        assert_eq!(ua.valid_third_party_revocations_by_key(p, None, alice_primary).count(), 0);
3412
3413        // Alice has not certified Bob's User ID.
3414        let ua = bob.userids().next().expect("have a user id");
3415        assert_eq!(ua.valid_third_party_revocations_by_key(p, None, alice_primary).count(), 0);
3416
3417        // Alice has not certified Carol's User ID.
3418        let ua = carol.userids().next().expect("have a user id");
3419        assert_eq!(ua.valid_third_party_revocations_by_key(p, None, alice_primary).count(), 0);
3420
3421
3422        // Have Alice revoke Carol's certificate at t1.
3423        let mut alice_signer = alice_primary
3424            .clone()
3425            .parts_into_secret().expect("have unencrypted key material")
3426            .into_keypair().expect("have unencrypted key material");
3427        let certification = SignatureBuilder::new(SignatureType::CertificationRevocation)
3428            .set_signature_creation_time(t1)?
3429            .set_reason_for_revocation(
3430                ReasonForRevocation::UIDRetired, b"")?
3431            .sign_userid_binding(
3432                &mut alice_signer,
3433                carol.primary_key().key(),
3434                &carol_userid)?;
3435        let carol = carol.insert_packets([
3436            Packet::from(carol_userid.clone()),
3437            Packet::from(certification.clone()),
3438        ])?.0;
3439
3440        // Check that it is returned.
3441        let ua = carol.userids().next().expect("have a user id");
3442        assert_eq!(ua.other_revocations().count(), 1);
3443
3444        assert_eq!(ua.valid_third_party_revocations_by_key(p, t0, alice_primary).count(), 0);
3445        assert_eq!(ua.valid_third_party_revocations_by_key(p, t1, alice_primary).count(), 1);
3446        assert_eq!(ua.valid_third_party_revocations_by_key(p, t1, bob_primary).count(), 0);
3447
3448
3449        // Have Alice certify Carol's certificate at t1 (again).
3450        // Since both certifications were created at t1, they should
3451        // both be returned.
3452        let mut alice_signer = alice_primary
3453            .clone()
3454            .parts_into_secret().expect("have unencrypted key material")
3455            .into_keypair().expect("have unencrypted key material");
3456        let certification = SignatureBuilder::new(SignatureType::CertificationRevocation)
3457            .set_signature_creation_time(t1)?
3458            .set_reason_for_revocation(ReasonForRevocation::UIDRetired, b"")?
3459            .sign_userid_binding(
3460                &mut alice_signer,
3461                carol.primary_key().key(),
3462                &carol_userid)?;
3463        let carol = carol.insert_packets([
3464            Packet::from(carol_userid.clone()),
3465            Packet::from(certification.clone()),
3466        ])?.0;
3467
3468        // Check that it is returned.
3469        let ua = carol.userids().next().expect("have a user id");
3470        assert_eq!(ua.other_revocations().count(), 2);
3471        assert_eq!(ua.valid_third_party_revocations_by_key(p, t0, alice_primary).count(), 0);
3472        assert_eq!(ua.valid_third_party_revocations_by_key(p, t1, alice_primary).count(), 2);
3473        assert_eq!(ua.valid_third_party_revocations_by_key(p, t2, alice_primary).count(), 2);
3474        assert_eq!(ua.valid_third_party_revocations_by_key(p, t0, bob_primary).count(), 0);
3475
3476
3477        // Have Alice certify Carol's certificate at t2.  Now we only
3478        // have one active certification.
3479        let mut alice_signer = alice_primary
3480            .clone()
3481            .parts_into_secret().expect("have unencrypted key material")
3482            .into_keypair().expect("have unencrypted key material");
3483        let certification = SignatureBuilder::new(SignatureType::CertificationRevocation)
3484            .set_signature_creation_time(t2)?
3485            .set_reason_for_revocation(ReasonForRevocation::UIDRetired, b"")?
3486            .sign_userid_binding(
3487                &mut alice_signer,
3488                carol.primary_key().key(),
3489                &carol_userid)?;
3490        let carol = carol.insert_packets([
3491            Packet::from(carol_userid.clone()),
3492            Packet::from(certification.clone()),
3493        ])?.0;
3494
3495        // Check that it is returned.
3496        let ua = carol.userids().next().expect("have a user id");
3497        assert_eq!(ua.other_revocations().count(), 3);
3498        assert_eq!(ua.valid_third_party_revocations_by_key(p, t0, alice_primary).count(), 0);
3499        assert_eq!(ua.valid_third_party_revocations_by_key(p, t1, alice_primary).count(), 2);
3500        assert_eq!(ua.valid_third_party_revocations_by_key(p, t2, alice_primary).count(), 3);
3501        assert_eq!(ua.valid_third_party_revocations_by_key(p, t0, bob_primary).count(), 0);
3502
3503
3504        // Have Bob certify Carol's certificate at t1 and have it expire at t2.
3505        let mut bob_signer = bob.primary_key()
3506            .key()
3507            .clone()
3508            .parts_into_secret().expect("have unencrypted key material")
3509            .into_keypair().expect("have unencrypted key material");
3510        let certification = SignatureBuilder::new(SignatureType::CertificationRevocation)
3511            .set_signature_creation_time(t1)?
3512            .set_signature_validity_period(t2.duration_since(t1)?)?
3513            .set_reason_for_revocation(ReasonForRevocation::UIDRetired, b"")?
3514            .sign_userid_binding(
3515                &mut bob_signer,
3516                carol.primary_key().key(),
3517                &carol_userid)?;
3518        let carol = carol.insert_packets([
3519            Packet::from(carol_userid.clone()),
3520            Packet::from(certification.clone()),
3521        ])?.0;
3522
3523        // Check that it is returned.
3524        let ua = carol.userids().next().expect("have a user id");
3525        assert_eq!(ua.other_revocations().count(), 4);
3526
3527        assert_eq!(ua.valid_third_party_revocations_by_key(p, t0, alice_primary).count(), 0);
3528        assert_eq!(ua.valid_third_party_revocations_by_key(p, t1, alice_primary).count(), 2);
3529        assert_eq!(ua.valid_third_party_revocations_by_key(p, t2, alice_primary).count(), 3);
3530        assert_eq!(ua.valid_third_party_revocations_by_key(p, t0, bob_primary).count(), 0);
3531        assert_eq!(ua.valid_third_party_revocations_by_key(p, t1, bob_primary).count(), 1);
3532        // It expired.
3533        assert_eq!(ua.valid_third_party_revocations_by_key(p, t2, bob_primary).count(), 0);
3534
3535
3536        // Have Bob certify Carol's certificate at t1 again.  This
3537        // time don't have it expire.
3538        let mut bob_signer = bob.primary_key()
3539            .key()
3540            .clone()
3541            .parts_into_secret().expect("have unencrypted key material")
3542            .into_keypair().expect("have unencrypted key material");
3543        let certification = SignatureBuilder::new(SignatureType::CertificationRevocation)
3544            .set_signature_creation_time(t1)?
3545            .set_reason_for_revocation(ReasonForRevocation::UIDRetired, b"")?
3546            .sign_userid_binding(
3547                &mut bob_signer,
3548                carol.primary_key().key(),
3549                &carol_userid)?;
3550        let carol = carol.insert_packets([
3551            Packet::from(carol_userid.clone()),
3552            Packet::from(certification.clone()),
3553        ])?.0;
3554
3555        // Check that it is returned.
3556        let ua = carol.userids().next().expect("have a user id");
3557        assert_eq!(ua.other_revocations().count(), 5);
3558        assert_eq!(ua.valid_third_party_revocations_by_key(p, t0, alice_primary).count(), 0);
3559        assert_eq!(ua.valid_third_party_revocations_by_key(p, t1, alice_primary).count(), 2);
3560        assert_eq!(ua.valid_third_party_revocations_by_key(p, t2, alice_primary).count(), 3);
3561        assert_eq!(ua.valid_third_party_revocations_by_key(p, t0, bob_primary).count(), 0);
3562        assert_eq!(ua.valid_third_party_revocations_by_key(p, t1, bob_primary).count(), 2);
3563        // One of the certifications expired.
3564        assert_eq!(ua.valid_third_party_revocations_by_key(p, t2, bob_primary).count(), 1);
3565
3566        Ok(())
3567    }
3568}