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 siganture'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 of the
143 //! aforementioned problems.
144 //!
145 //! # Lifetimes
146 //!
147 //! `ComponentAmalgamation` autoderefs to `ComponentBundle`.
148 //! Unfortunately, due to the definition of the [`Deref` trait],
149 //! `ComponentBundle` is assigned the same lifetime as
150 //! `ComponentAmalgamation`.  However, it's lifetime is actually `'a`.
151 //! Particularly when using combinators like [`std::iter::map`], the
152 //! `ComponentBundle`'s lifetime is longer.  Consider the following
153 //! code, which doesn't compile:
154 //!
155 //! ```compile_fail
156 //! # extern crate sequoia_openpgp as openpgp;
157 //! use openpgp::cert::prelude::*;
158 //! use openpgp::packet::prelude::*;
159 //!
160 //! # let (cert, _) = CertBuilder::new()
161 //! #     .add_userid("Alice")
162 //! #     .add_signing_subkey()
163 //! #     .add_transport_encryption_subkey()
164 //! #     .generate().unwrap();
165 //! cert.userids()
166 //!     .map(|ua| {
167 //!         // Use auto deref to get the containing `&ComponentBundle`.
168 //!         let b: &ComponentBundle<_> = &ua;
169 //!         b
170 //!     })
171 //!     .collect::<Vec<&UserID>>();
172 //! ```
173 //!
174 //! Compiling it results in the following error:
175 //!
176 //! > `b` returns a value referencing data owned by the current
177 //! > function
178 //!
179 //! This error occurs because the `Deref` trait says that the lifetime
180 //! of the target, i.e., `&ComponentBundle`, is bounded by `ua`'s
181 //! lifetime, whose lifetime is indeed limited to the closure.  But,
182 //! `&ComponentBundle` is independent of `ua`; it is a copy of the
183 //! `ComponentAmalgamation`'s reference to the `ComponentBundle` whose
184 //! lifetime is `'a`!  Unfortunately, this can't be expressed using
185 //! `Deref`.  But, it can be done using separate methods as shown
186 //! below for the [`ComponentAmalgamation::component`] method:
187 //!
188 //! ```
189 //! # extern crate sequoia_openpgp as openpgp;
190 //! use openpgp::cert::prelude::*;
191 //! use openpgp::packet::prelude::*;
192 //!
193 //! # let (cert, _) = CertBuilder::new()
194 //! #     .add_userid("Alice")
195 //! #     .add_signing_subkey()
196 //! #     .add_transport_encryption_subkey()
197 //! #     .generate().unwrap();
198 //! cert.userids()
199 //!     .map(|ua| {
200 //!         // ua's lifetime is this closure.  But `component()`
201 //!         // returns a reference whose lifetime is that of
202 //!         // `cert`.
203 //!         ua.component()
204 //!     })
205 //!     .collect::<Vec<&UserID>>();
206 //! ```
207 //!
208 //! [`ComponentBundle`]: ../bundle/index.html
209 //! [`Signature`]: ../../packet/signature/index.html
210 //! [`ComponentAmalgamation`]: struct.ComponentAmalgamation.html
211 //! [`Cert`]: ../index.html
212 //! [is supposed to]: https://tools.ietf.org/html/rfc4880#section-5.2.3.3
213 //! [`ValidComponentAmalgamation`]: struct.ValidComponentAmalgamation.html
214 //! [`std::iter::map`]: https://doc.rust-lang.org/std/iter/struct.Map.html
215 //! [MD5 collisions]: https://en.wikipedia.org/wiki/MD5
216 //! [`Policy`]: ../../policy/index.html
217 //! [streaming verifier]: ../../parse/stream.html
218 //! [Intended Recipients]: https://www.ietf.org/id/draft-ietf-openpgp-rfc4880bis-09.html#name-intended-recipient-fingerpr
219 //! [signature expirations]: https://tools.ietf.org/html/rfc4880#section-5.2.3.10
220 //! [`Deref` trait]: https://doc.rust-lang.org/stable/std/ops/trait.Deref.html
221 //! [`ComponentAmalgamation::component`]: struct.ComponentAmalgamation.html#method.component
222 use std::time;
223 use std::time::SystemTime;
224 use std::clone::Clone;
225 
226 use crate::{
227     cert::prelude::*,
228     Error,
229     packet::{
230         Signature,
231         Unknown,
232         UserAttribute,
233         UserID,
234     },
235     Result,
236     policy::Policy,
237     types::{
238         AEADAlgorithm,
239         CompressionAlgorithm,
240         Features,
241         HashAlgorithm,
242         KeyServerPreferences,
243         RevocationKey,
244         RevocationStatus,
245         SymmetricAlgorithm,
246     },
247 };
248 
249 mod iter;
250 pub use iter::{
251     ComponentAmalgamationIter,
252     UnknownComponentAmalgamationIter,
253     UserAttributeAmalgamationIter,
254     UserIDAmalgamationIter,
255     ValidComponentAmalgamationIter,
256     ValidUserAttributeAmalgamationIter,
257     ValidUserIDAmalgamationIter,
258 };
259 
260 pub mod key;
261 
262 /// Embeds a policy and a reference time in an amalgamation.
263 ///
264 /// This is used to turn a [`ComponentAmalgamation`] into a
265 /// [`ValidComponentAmalgamation`], and a [`KeyAmalgamation`] into a
266 /// [`ValidKeyAmalgamation`].
267 ///
268 /// A certificate or a component is consider valid if:
269 ///
270 ///   - It has a self signature that is live at time `t`.
271 ///
272 ///   - The policy considers it acceptable.
273 ///
274 ///   - The certificate is valid.
275 ///
276 /// # Examples
277 ///
278 /// ```
279 /// # extern crate sequoia_openpgp as openpgp;
280 /// use openpgp::cert::prelude::*;
281 /// use openpgp::policy::{Policy, StandardPolicy};
282 ///
283 /// const POLICY: &dyn Policy = &StandardPolicy::new();
284 ///
285 /// fn f(ua: UserIDAmalgamation) -> openpgp::Result<()> {
286 ///     let ua = ua.with_policy(POLICY, None)?;
287 ///     // ...
288 /// #   Ok(())
289 /// }
290 /// # fn main() -> openpgp::Result<()> {
291 /// #     let (cert, _) =
292 /// #         CertBuilder::general_purpose(None, Some("alice@example.org"))
293 /// #         .generate()?;
294 /// #     let ua = cert.userids().nth(0).expect("User IDs");
295 /// #     f(ua);
296 /// #     Ok(())
297 /// # }
298 /// ```
299 ///
300 /// [`ComponentAmalgamation`]: struct.ComponentAmalgamation.html
301 /// [`ValidComponentAmalgamation`]: struct.ValidComponentAmalgamation.html
302 /// [`KeyAmalgamation`]: struct.KeyAmalgamation.html
303 /// [`ValidKeyAmalgamation`]: struct.ValidKeyAmalgamation.html
304 pub trait ValidateAmalgamation<'a, C: 'a> {
305     /// The type returned by `with_policy`.
306     ///
307     /// This is either a [`ValidComponentAmalgamation`] or
308     /// a [`ValidKeyAmalgamation`].
309     ///
310     /// [`ValidComponentAmalgamation`]: struct.ValidComponentAmalgamation.html
311     /// [`ValidKeyAmalgamation`]: struct.ValidKeyAmalgamation.html
312     type V;
313 
314     /// Uses the specified `Policy` and reference time with the amalgamation.
315     ///
316     /// If `time` is `None`, the current time is used.
with_policy<T>(self, policy: &'a dyn Policy, time: T) -> Result<Self::V> where T: Into<Option<time::SystemTime>>, Self: Sized317     fn with_policy<T>(self, policy: &'a dyn Policy, time: T) -> Result<Self::V>
318         where T: Into<Option<time::SystemTime>>,
319               Self: Sized;
320 }
321 
322 /// Applies a policy to an amalgamation.
323 ///
324 /// This is an internal variant of `ValidateAmalgamation`, which
325 /// allows validating a component for an otherwise invalid
326 /// certificate.  See `ValidComponentAmalgamation::primary` for an
327 /// explanation.
328 trait ValidateAmalgamationRelaxed<'a, C: 'a> {
329     /// The type returned by `with_policy`.
330     type V;
331 
332     /// Changes the amalgamation's policy.
333     ///
334     /// If `time` is `None`, the current time is used.
335     ///
336     /// If `valid_cert` is `false`, then this does not also check
337     /// whether the certificate is valid; it only checks whether the
338     /// component is valid.  Normally, this should be `true`.  This
339     /// option is only expose to allow breaking an infinite recursion:
340     ///
341     ///   - To check if a certificate is valid, we check if the
342     ///     primary key is valid.
343     ///
344     ///   - To check if the primary key is valid, we need the primary
345     ///     key's self signature
346     ///
347     ///   - To find the primary key's self signature, we need to find
348     ///     the primary user id
349     ///
350     ///   - To find the primary user id, we need to check if the user
351     ///     id is valid.
352     ///
353     ///   - To check if the user id is valid, we need to check that
354     ///     the corresponding certificate is valid.
with_policy_relaxed<T>(self, policy: &'a dyn Policy, time: T, valid_cert: bool) -> Result<Self::V> where T: Into<Option<time::SystemTime>>, Self: Sized355     fn with_policy_relaxed<T>(self, policy: &'a dyn Policy, time: T,
356                               valid_cert: bool) -> Result<Self::V>
357         where T: Into<Option<time::SystemTime>>,
358               Self: Sized;
359 }
360 
361 /// Methods for valid amalgamations.
362 ///
363 /// The methods exposed by a `ValidComponentAmalgamation` are similar
364 /// to those exposed by a `ComponentAmalgamation`, but the policy and
365 /// reference time are included in the `ValidComponentAmalgamation`.
366 /// This helps prevent using different policies or different reference
367 /// times when using a component, which can easily happen when the
368 /// checks span multiple functions.
369 pub trait ValidAmalgamation<'a, C: 'a>
370 {
371     /// Maps the given function over binding and direct key signature.
372     ///
373     /// Makes `f` consider both the binding signature and the direct
374     /// key signature.  Information in the binding signature takes
375     /// precedence over the direct key signature.  See also [Section
376     /// 5.2.3.3 of RFC 4880].
377     ///
378     ///   [Section 5.2.3.3 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-5.2.3.3
map<F: Fn(&'a Signature) -> Option<T>, T>(&self, f: F) -> Option<T>379     fn map<F: Fn(&'a Signature) -> Option<T>, T>(&self, f: F) -> Option<T> {
380         f(self.binding_signature())
381             .or_else(|| self.direct_key_signature().ok().and_then(f))
382     }
383 
384     /// Returns the valid amalgamation's associated certificate.
385     ///
386     /// # Examples
387     ///
388     /// ```
389     /// # extern crate sequoia_openpgp as openpgp;
390     /// # use openpgp::cert::prelude::*;
391     /// # use openpgp::policy::StandardPolicy;
392     /// #
393     /// fn f(ua: &ValidUserIDAmalgamation) {
394     ///     let cert = ua.cert();
395     ///     // ...
396     /// }
397     /// # fn main() -> openpgp::Result<()> {
398     /// #     let p = &StandardPolicy::new();
399     /// #     let (cert, _) =
400     /// #         CertBuilder::general_purpose(None, Some("alice@example.org"))
401     /// #         .generate()?;
402     /// #     let fpr = cert.fingerprint();
403     /// #     let ua = cert.userids().nth(0).expect("User IDs");
404     /// #     assert_eq!(ua.cert().fingerprint(), fpr);
405     /// #     f(&ua.with_policy(p, None)?);
406     /// #     Ok(())
407     /// # }
408     /// ```
cert(&self) -> &ValidCert<'a>409     fn cert(&self) -> &ValidCert<'a>;
410 
411     /// Returns the amalgamation's reference time.
412     ///
413     /// # Examples
414     ///
415     /// ```
416     /// # use std::time::{SystemTime, Duration, UNIX_EPOCH};
417     /// #
418     /// # extern crate sequoia_openpgp as openpgp;
419     /// # use openpgp::cert::prelude::*;
420     /// # use openpgp::policy::StandardPolicy;
421     /// fn f(ua: &ValidUserIDAmalgamation) {
422     ///     let t = ua.time();
423     ///     // ...
424     /// }
425     /// # fn main() -> openpgp::Result<()> {
426     /// #     let p = &StandardPolicy::new();
427     /// #     let t = UNIX_EPOCH + Duration::from_secs(1554542220);
428     /// #     let (cert, _) =
429     /// #         CertBuilder::general_purpose(None, Some("alice@example.org"))
430     /// #         .set_creation_time(t)
431     /// #         .generate()?;
432     /// #     let ua = cert.userids().nth(0).expect("User IDs");
433     /// #     let ua = ua.with_policy(p, t)?;
434     /// #     assert_eq!(t, ua.time());
435     /// #     f(&ua);
436     /// #     Ok(())
437     /// # }
438     /// ```
time(&self) -> SystemTime439     fn time(&self) -> SystemTime;
440 
441     /// Returns the amalgamation's policy.
442     ///
443     /// # Examples
444     ///
445     /// ```
446     /// # extern crate sequoia_openpgp as openpgp;
447     /// # use openpgp::cert::prelude::*;
448     /// # use openpgp::policy::{Policy, StandardPolicy};
449     /// #
450     /// fn f(ua: &ValidUserIDAmalgamation) {
451     ///     let policy = ua.policy();
452     ///     // ...
453     /// }
454     /// # fn main() -> openpgp::Result<()> {
455     /// #     let p: &dyn Policy = &StandardPolicy::new();
456     /// #     let (cert, _) =
457     /// #         CertBuilder::general_purpose(None, Some("alice@example.org"))
458     /// #         .generate()?;
459     /// #     let ua = cert.userids().nth(0).expect("User IDs");
460     /// #     let ua = ua.with_policy(p, None)?;
461     /// #     assert!(std::ptr::eq(p, ua.policy()));
462     /// #     f(&ua);
463     /// #     Ok(())
464     /// # }
465     /// ```
policy(&self) -> &'a dyn Policy466     fn policy(&self) -> &'a dyn Policy;
467 
468     /// Returns the component's binding signature as of the reference time.
469     ///
470     /// # Examples
471     ///
472     /// ```
473     /// # extern crate sequoia_openpgp as openpgp;
474     /// # use openpgp::cert::prelude::*;
475     /// # use openpgp::policy::{Policy, StandardPolicy};
476     /// #
477     /// fn f(ua: &ValidUserIDAmalgamation) {
478     ///     let sig = ua.binding_signature();
479     ///     // ...
480     /// }
481     /// # fn main() -> openpgp::Result<()> {
482     /// #     let p: &dyn Policy = &StandardPolicy::new();
483     /// #     let (cert, _) =
484     /// #         CertBuilder::general_purpose(None, Some("alice@example.org"))
485     /// #         .generate()?;
486     /// #     let ua = cert.userids().nth(0).expect("User IDs");
487     /// #     let ua = ua.with_policy(p, None)?;
488     /// #     f(&ua);
489     /// #     Ok(())
490     /// # }
491     /// ```
binding_signature(&self) -> &'a Signature492     fn binding_signature(&self) -> &'a Signature;
493 
494     /// Returns the certificate's direct key signature as of the
495     /// reference time, if any.
496     ///
497     /// Subpackets on direct key signatures apply to all components of
498     /// the certificate, cf. [Section 5.2.3.3 of RFC 4880].
499     ///
500     /// [Section 5.2.3.3 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-5.2.3.3
501     ///
502     /// # Examples
503     ///
504     /// ```
505     /// # extern crate sequoia_openpgp as openpgp;
506     /// # use openpgp::cert::prelude::*;
507     /// # use openpgp::policy::{Policy, StandardPolicy};
508     /// #
509     /// fn f(ua: &ValidUserIDAmalgamation) {
510     ///     let sig = ua.direct_key_signature();
511     ///     // ...
512     /// }
513     /// # fn main() -> openpgp::Result<()> {
514     /// #     let p: &dyn Policy = &StandardPolicy::new();
515     /// #     let (cert, _) =
516     /// #         CertBuilder::general_purpose(None, Some("alice@example.org"))
517     /// #         .generate()?;
518     /// #     let cert = cert.with_policy(p, None)?;
519     /// #     let ua = cert.userids().nth(0).expect("User IDs");
520     /// #     assert!(std::ptr::eq(ua.direct_key_signature().unwrap(),
521     /// #                          cert.direct_key_signature().unwrap()));
522     /// #     f(&ua);
523     /// #     Ok(())
524     /// # }
525     /// ```
direct_key_signature(&self) -> Result<&'a Signature>526     fn direct_key_signature(&self) -> Result<&'a Signature> {
527         self.cert().cert.primary.binding_signature(self.policy(), self.time())
528     }
529 
530     /// Returns the component's revocation status as of the amalgamation's
531     /// reference time.
532     ///
533     /// This does *not* check whether the certificate has been
534     /// revoked.  For that, use `Cert::revocation_status()`.
535     ///
536     /// Note, as per [RFC 4880], a key is considered to be revoked at
537     /// some time if there were no soft revocations created as of that
538     /// time, and no hard revocations:
539     ///
540     /// > If a key has been revoked because of a compromise, all signatures
541     /// > created by that key are suspect.  However, if it was merely
542     /// > superseded or retired, old signatures are still valid.
543     ///
544     /// [RFC 4880]: https://tools.ietf.org/html/rfc4880#section-5.2.3.23
545     ///
546     /// # Examples
547     ///
548     /// ```
549     /// # extern crate sequoia_openpgp as openpgp;
550     /// use openpgp::cert::prelude::*;
551     /// # use openpgp::policy::StandardPolicy;
552     /// use openpgp::types::RevocationStatus;
553     ///
554     /// # fn main() -> openpgp::Result<()> {
555     /// #     let p = &StandardPolicy::new();
556     /// #     let (cert, _) =
557     /// #         CertBuilder::general_purpose(None, Some("alice@example.org"))
558     /// #         .generate()?;
559     /// #     let cert = cert.with_policy(p, None)?;
560     /// #     let ua = cert.userids().nth(0).expect("User IDs");
561     /// match ua.revocation_status() {
562     ///     RevocationStatus::Revoked(revs) => {
563     ///         // The certificate holder revoked the User ID.
564     /// #       unreachable!();
565     ///     }
566     ///     RevocationStatus::CouldBe(revs) => {
567     ///         // There are third-party revocations.  You still need
568     ///         // to check that they are valid (this is necessary,
569     ///         // because without the Certificates are not normally
570     ///         // available to Sequoia).
571     /// #       unreachable!();
572     ///     }
573     ///     RevocationStatus::NotAsFarAsWeKnow => {
574     ///         // We have no evidence that the User ID is revoked.
575     ///     }
576     /// }
577     /// #     Ok(())
578     /// # }
579     /// ```
revocation_status(&self) -> RevocationStatus<'a>580     fn revocation_status(&self) -> RevocationStatus<'a>;
581 }
582 
583 /// A certificate component, its associated data, and useful methods.
584 ///
585 /// [`Cert::userids`], [`Cert::primary_userid`], [`Cert::user_attributes`], and
586 /// [`Cert::unknowns`] return `ComponentAmalgamation`s.
587 ///
588 /// `ComponentAmalgamation` implements [`ValidateAmalgamation`], which
589 /// allows you to turn a `ComponentAmalgamation` into a
590 /// [`ValidComponentAmalgamation`] using
591 /// [`ComponentAmalgamation::with_policy`].
592 ///
593 /// [See the module's documentation] for more details.
594 ///
595 /// # Examples
596 ///
597 /// ```
598 /// # extern crate sequoia_openpgp as openpgp;
599 /// # use openpgp::cert::prelude::*;
600 /// # use openpgp::policy::StandardPolicy;
601 /// #
602 /// # fn main() -> openpgp::Result<()> {
603 /// #     let p = &StandardPolicy::new();
604 /// #     let (cert, _) =
605 /// #         CertBuilder::general_purpose(None, Some("alice@example.org"))
606 /// #         .generate()?;
607 /// #     let fpr = cert.fingerprint();
608 /// // Iterate over all User IDs.
609 /// for ua in cert.userids() {
610 ///     // ua is a `ComponentAmalgamation`, specifically, a `UserIDAmalgamation`.
611 /// }
612 /// #     Ok(())
613 /// # }
614 /// ```
615 ///
616 /// [`Cert`]: ../struct.Cert.html
617 /// [`Cert::userids`]: ../struct.Cert.html#method.userids
618 /// [`Cert::primary_userid`]: ../struct.Cert.html#method.primary_userid
619 /// [`Cert::user_attributes`]: ../struct.Cert.html#method.user_attributes
620 /// [`Cert::unknowns`]: ../struct.Cert.html#method.unknown
621 /// [`ValidateAmalgamation`]: trait.ValidateAmalgamation.html
622 /// [`ValidComponentAmalgamation`]: struct.ValidComponentAmalgamation.html
623 /// [`ComponentAmalgamation::with_policy`]: trait.ValidateAmalgamation.html#method.with_policy
624 /// [See the module's documentation]: index.html
625 #[derive(Debug, PartialEq)]
626 pub struct ComponentAmalgamation<'a, C> {
627     cert: &'a Cert,
628     bundle: &'a ComponentBundle<C>,
629 }
630 
631 /// A User ID and its associated data.
632 ///
633 /// A specialized version of [`ComponentAmalgamation`].
634 ///
635 /// [`ComponentAmalgamation`]: struct.ComponentAmalgamation.html
636 pub type UserIDAmalgamation<'a> = ComponentAmalgamation<'a, UserID>;
637 
638 /// A User Attribute and its associated data.
639 ///
640 /// A specialized version of [`ComponentAmalgamation`].
641 ///
642 /// [`ComponentAmalgamation`]: struct.ComponentAmalgamation.html
643 pub type UserAttributeAmalgamation<'a>
644     = ComponentAmalgamation<'a, UserAttribute>;
645 
646 /// An Unknown component and its associated data.
647 ///
648 /// A specialized version of [`ComponentAmalgamation`].
649 ///
650 /// [`ComponentAmalgamation`]: struct.ComponentAmalgamation.html
651 pub type UnknownComponentAmalgamation<'a>
652     = ComponentAmalgamation<'a, Unknown>;
653 
654 // derive(Clone) doesn't work with generic parameters that don't
655 // implement clone.  But, we don't need to require that C implements
656 // Clone, because we're not cloning C, just the reference.
657 //
658 // See: https://github.com/rust-lang/rust/issues/26925
659 impl<'a, C> Clone for ComponentAmalgamation<'a, C> {
clone(&self) -> Self660     fn clone(&self) -> Self {
661         Self {
662             cert: self.cert,
663             bundle: self.bundle,
664         }
665     }
666 }
667 
668 impl<'a, C> std::ops::Deref for ComponentAmalgamation<'a, C> {
669     type Target = ComponentBundle<C>;
670 
deref(&self) -> &Self::Target671     fn deref(&self) -> &Self::Target {
672         self.bundle
673     }
674 }
675 
676 impl<'a, C> ComponentAmalgamation<'a, C> {
677     /// Creates a new amalgamation.
new(cert: &'a Cert, bundle: &'a ComponentBundle<C>) -> Self678     pub(crate) fn new(cert: &'a Cert, bundle: &'a ComponentBundle<C>) -> Self
679     {
680         Self {
681             cert,
682             bundle,
683         }
684     }
685 
686     /// Returns the component's associated certificate.
687     ///
688     /// ```
689     /// # extern crate sequoia_openpgp as openpgp;
690     /// # use openpgp::cert::prelude::*;
691     /// #
692     /// # fn main() -> openpgp::Result<()> {
693     /// # let (cert, _) =
694     /// #     CertBuilder::general_purpose(None, Some("alice@example.org"))
695     /// #     .generate()?;
696     /// for u in cert.userids() {
697     ///     // It's not only an identical `Cert`, it's the same one.
698     ///     assert!(std::ptr::eq(u.cert(), &cert));
699     /// }
700     /// # Ok(()) }
701     /// ```
cert(&self) -> &'a Cert702     pub fn cert(&self) -> &'a Cert {
703         &self.cert
704     }
705 
706     /// Selects a binding signature.
707     ///
708     /// Uses the provided policy and reference time to select an
709     /// appropriate binding signature.
710     ///
711     /// Note: this function is not exported.  Users of this interface
712     /// should do: ca.with_policy(policy, time)?.binding_signature().
binding_signature<T>(&self, policy: &dyn Policy, time: T) -> Result<&'a Signature> where T: Into<Option<time::SystemTime>>713     fn binding_signature<T>(&self, policy: &dyn Policy, time: T)
714         -> Result<&'a Signature>
715         where T: Into<Option<time::SystemTime>>
716     {
717         let time = time.into().unwrap_or_else(SystemTime::now);
718         self.bundle.binding_signature(policy, time)
719     }
720 
721     /// Returns this amalgamation's bundle.
722     ///
723     /// Note: although `ComponentAmalgamation` derefs to a
724     /// `&ComponentBundle`, this method provides a more accurate
725     /// lifetime, which is helpful when returning the reference from a
726     /// function.  [See the module's documentation] for more details.
727     ///
728     /// [See the module's documentation]: index.html
729     ///
730     /// # Examples
731     ///
732     /// ```
733     /// # extern crate sequoia_openpgp as openpgp;
734     /// use openpgp::cert::prelude::*;
735     /// use openpgp::packet::prelude::*;
736     ///
737     /// # let (cert, _) = CertBuilder::new()
738     /// #     .add_userid("Alice")
739     /// #     .add_signing_subkey()
740     /// #     .add_transport_encryption_subkey()
741     /// #     .generate().unwrap();
742     /// cert.userids()
743     ///     .map(|ua| {
744     ///         // The following doesn't work:
745     ///         //
746     ///         //   let b: &ComponentBundle<_> = &ua; b
747     ///         //
748     ///         // Because ua's lifetime is this closure and autoderef
749     ///         // assigns `b` the same lifetime as `ua`.  `bundle()`,
750     ///         // however, returns a reference whose lifetime is that
751     ///         // of `cert`.
752     ///         ua.bundle()
753     ///     })
754     ///     .collect::<Vec<&ComponentBundle<_>>>();
755     /// ```
bundle(&self) -> &'a ComponentBundle<C>756     pub fn bundle(&self) -> &'a ComponentBundle<C> {
757         &self.bundle
758     }
759 
760     /// Returns this amalgamation's component.
761     ///
762     /// Note: although `ComponentAmalgamation` derefs to a
763     /// `&Component` (via `&ComponentBundle`), this method provides a
764     /// more accurate lifetime, which is helpful when returning the
765     /// reference from a function.  [See the module's documentation]
766     /// for more details.
767     ///
768     /// [See the module's documentation]: index.html
component(&self) -> &'a C769     pub fn component(&self) -> &'a C {
770         self.bundle().component()
771     }
772 
773     /// The component's self-signatures.
774     ///
775     /// This method is a forwarder for
776     /// [`ComponentBundle::self_signatures`].  Although
777     /// `ComponentAmalgamation` derefs to a `&ComponentBundle`, this
778     /// method provides a more accurate lifetime, which is helpful
779     /// when returning the reference from a function.  [See the
780     /// module's documentation] for more details.
781     ///
782     /// [`ComponentBundle::self_signatures`]: ../bundle/struct.ComponentBundle.html#method.self_signatures
783     /// [See the module's documentation]: index.html
self_signatures(&self) -> &'a [Signature]784     pub fn self_signatures(&self) -> &'a [Signature] {
785         self.bundle().self_signatures()
786     }
787 
788     /// The component's third-party certifications.
789     ///
790     /// This method is a forwarder for
791     /// [`ComponentBundle::certifications`].  Although
792     /// `ComponentAmalgamation` derefs to a `&ComponentBundle`, this
793     /// method provides a more accurate lifetime, which is helpful
794     /// when returning the reference from a function.  [See the
795     /// module's documentation] for more details.
796     ///
797     /// [`ComponentBundle::certifications`]: ../bundle/struct.ComponentBundle.html#method.certifications
798     /// [See the module's documentation]: index.html
certifications(&self) -> &'a [Signature]799     pub fn certifications(&self) -> &'a [Signature] {
800         self.bundle().certifications()
801     }
802 
803     /// The component's revocations that were issued by the
804     /// certificate holder.
805     ///
806     /// This method is a forwarder for
807     /// [`ComponentBundle::self_revocations`].  Although
808     /// `ComponentAmalgamation` derefs to a `&ComponentBundle`, this
809     /// method provides a more accurate lifetime, which is helpful
810     /// when returning the reference from a function.  [See the
811     /// module's documentation] for more details.
812     ///
813     /// [`ComponentBundle::self_revocations`]: ../bundle/struct.ComponentBundle.html#method.self_revocations
814     /// [See the module's documentation]: index.html
self_revocations(&self) -> &'a [Signature]815     pub fn self_revocations(&self) -> &'a [Signature] {
816         self.bundle().self_revocations()
817     }
818 
819     /// The component's revocations that were issued by other
820     /// certificates.
821     ///
822     /// This method is a forwarder for
823     /// [`ComponentBundle::other_revocations`].  Although
824     /// `ComponentAmalgamation` derefs to a `&ComponentBundle`, this
825     /// method provides a more accurate lifetime, which is helpful
826     /// when returning the reference from a function.  [See the
827     /// module's documentation] for more details.
828     ///
829     /// [`ComponentBundle::other_revocations`]: ../bundle/struct.ComponentBundle.html#method.other_revocations
830     /// [See the module's documentation]: index.html
other_revocations(&self) -> &'a [Signature]831     pub fn other_revocations(&self) -> &'a [Signature] {
832         self.bundle().other_revocations()
833     }
834 
835     /// Returns a list of any designated revokers for this component.
836     ///
837     /// This function returns the designated revokers listed on both
838     /// this component's binding signature and the certificate's
839     /// direct key signature.
840     ///
841     /// Note: the returned list is deduplicated.
842     ///
843     /// # Examples
844     ///
845     /// ```
846     /// # extern crate sequoia_openpgp as openpgp;
847     /// # use openpgp::Result;
848     /// use openpgp::cert::prelude::*;
849     /// use openpgp::policy::StandardPolicy;
850     /// use openpgp::types::RevocationKey;
851     ///
852     /// # fn main() -> Result<()> {
853     /// let p = &StandardPolicy::new();
854     ///
855     /// let (alice, _) =
856     ///     CertBuilder::general_purpose(None, Some("alice@example.org"))
857     ///     .generate()?;
858     /// // Make Alice a designated revoker for Bob.
859     /// let (bob, _) =
860     ///     CertBuilder::general_purpose(None, Some("bob@example.org"))
861     ///     .set_revocation_keys(vec![(&alice).into()])
862     ///     .generate()?;
863     ///
864     /// // Make sure Alice is listed as a designated revoker for Bob
865     /// // on a component.
866     /// assert_eq!(bob.with_policy(p, None)?.primary_userid()?.revocation_keys(p)
867     ///                .collect::<Vec<&RevocationKey>>(),
868     ///            vec![&(&alice).into()]);
869     /// # Ok(()) }
870     /// ```
revocation_keys(&self, policy: &dyn Policy) -> Box<dyn Iterator<Item = &'a RevocationKey> + 'a>871     pub fn revocation_keys(&self, policy: &dyn Policy)
872         -> Box<dyn Iterator<Item = &'a RevocationKey> + 'a>
873     {
874         let mut keys = std::collections::HashSet::new();
875         for rk in self.self_signatures().iter()
876             .filter(|sig| {
877                 policy.signature(sig).is_ok()
878             })
879             .flat_map(|sig| sig.revocation_keys())
880         {
881             keys.insert(rk);
882         }
883         for rk in self.cert().primary_key().self_signatures().iter()
884             .filter(|sig| {
885                 policy.signature(sig).is_ok()
886             })
887             .flat_map(|sig| sig.revocation_keys())
888         {
889             keys.insert(rk);
890         }
891         Box::new(keys.into_iter())
892     }
893 }
894 
895 macro_rules! impl_with_policy {
896     ($func:ident, $value:ident $(, $arg:ident: $type:ty )*) => {
897         fn $func<T>(self, policy: &'a dyn Policy, time: T, $($arg: $type, )*)
898             -> Result<Self::V>
899             where T: Into<Option<time::SystemTime>>,
900                   Self: Sized
901         {
902             let time = time.into().unwrap_or_else(SystemTime::now);
903 
904             if $value {
905                 self.cert.with_policy(policy, time)?;
906             }
907 
908             let binding_signature = self.binding_signature(policy, time)?;
909             let cert = self.cert;
910             // We can't do `Cert::with_policy` as that would
911             // result in infinite recursion.  But at this point,
912             // we know the certificate is valid (unless the caller
913             // doesn't care).
914             Ok(ValidComponentAmalgamation {
915                 ca: self,
916                 cert: ValidCert {
917                     cert: cert,
918                     policy: policy,
919                     time: time,
920                 },
921                 binding_signature: binding_signature,
922             })
923         }
924     }
925 }
926 
927 impl<'a, C> ValidateAmalgamation<'a, C> for ComponentAmalgamation<'a, C> {
928     type V = ValidComponentAmalgamation<'a, C>;
929 
930     impl_with_policy!(with_policy, true);
931 }
932 
933 impl<'a, C> ValidateAmalgamationRelaxed<'a, C> for ComponentAmalgamation<'a, C> {
934     type V = ValidComponentAmalgamation<'a, C>;
935 
936     impl_with_policy!(with_policy_relaxed, valid_cert, valid_cert: bool);
937 }
938 
939 impl<'a> UserIDAmalgamation<'a> {
940     /// Returns a reference to the User ID.
941     ///
942     /// Note: although `ComponentAmalgamation<UserID>` derefs to a
943     /// `&UserID` (via `&ComponentBundle`), this method provides a
944     /// more accurate lifetime, which is helpful when returning the
945     /// reference from a function.  [See the module's documentation]
946     /// for more details.
947     ///
948     /// [See the module's documentation]: index.html
userid(&self) -> &'a UserID949     pub fn userid(&self) -> &'a UserID {
950         self.component()
951     }
952 }
953 
954 impl<'a> UserAttributeAmalgamation<'a> {
955     /// Returns a reference to the User Attribute.
956     ///
957     /// Note: although `ComponentAmalgamation<UserAttribute>` derefs
958     /// to a `&UserAttribute` (via `&ComponentBundle`), this method
959     /// provides a more accurate lifetime, which is helpful when
960     /// returning the reference from a function.  [See the module's
961     /// documentation] for more details.
962     ///
963     /// [See the module's documentation]: index.html
user_attribute(&self) -> &'a UserAttribute964     pub fn user_attribute(&self) -> &'a UserAttribute {
965         self.component()
966     }
967 }
968 
969 /// A `ComponentAmalgamation` plus a `Policy` and a reference time.
970 ///
971 /// A `ValidComponentAmalgamation` combines a
972 /// [`ComponentAmalgamation`] with a [`Policy`] and a reference time.
973 /// This allows it to implement the [`ValidAmalgamation`] trait, which
974 /// provides methods that require a [`Policy`] and a reference time.
975 /// Although `ComponentAmalgamation` could implement these methods by
976 /// requiring that the caller explicitly pass them in, embedding them
977 /// in the `ValidComponentAmalgamation` helps ensure that multipart
978 /// operations, even those that span multiple functions, use the same
979 /// `Policy` and reference time.
980 ///
981 /// A `ValidComponentAmalgamation` is typically obtained by
982 /// transforming a `ComponentAmalgamation` using
983 /// [`ValidateAmalgamation::with_policy`].  A
984 /// [`ComponentAmalgamationIter`] can also be changed to yield
985 /// `ValidComponentAmalgamation`s.
986 ///
987 /// A `ValidComponentAmalgamation` is guaranteed to come from a valid
988 /// certificate, and have a valid and live binding signature at the
989 /// specified reference time.  Note: this only means that the binding
990 /// signatures are live; it says nothing about whether the
991 /// *certificate* is live.  If you care about that, then you need to
992 /// check it separately.
993 ///
994 /// # Examples
995 ///
996 /// Print out information about all non-revoked User IDs.
997 ///
998 /// ```
999 /// # extern crate sequoia_openpgp as openpgp;
1000 /// use openpgp::cert::prelude::*;
1001 /// use openpgp::packet::prelude::*;
1002 /// use openpgp::policy::StandardPolicy;
1003 /// use openpgp::types::RevocationStatus;
1004 ///
1005 /// # fn main() -> openpgp::Result<()> {
1006 /// let p = &StandardPolicy::new();
1007 /// # let (cert, _) = CertBuilder::new()
1008 /// #     .add_userid("Alice")
1009 /// #     .add_signing_subkey()
1010 /// #     .add_transport_encryption_subkey()
1011 /// #     .generate().unwrap();
1012 /// for u in cert.userids() {
1013 ///     // Create a `ValidComponentAmalgamation`.  This may fail if
1014 ///     // there are no binding signatures that are accepted by the
1015 ///     // policy and that are live right now.
1016 ///     let u = u.with_policy(p, None)?;
1017 ///
1018 ///     // Before using the User ID, we still need to check that it is
1019 ///     // not revoked; `ComponentAmalgamation::with_policy` ensures
1020 ///     // that there is a valid *binding signature*, not that the
1021 ///     // `ComponentAmalgamation` is valid.
1022 ///     //
1023 ///     // Note: `ValidComponentAmalgamation::revocation_status` and
1024 ///     // `Preferences::preferred_symmetric_algorithms` use the
1025 ///     // embedded policy and timestamp.  Even though we used `None` for
1026 ///     // the timestamp (i.e., now), they are guaranteed to use the same
1027 ///     // timestamp, because `with_policy` eagerly transforms it into
1028 ///     // the current time.
1029 ///     //
1030 ///     // Note: we only check whether the User ID is not revoked.  If
1031 ///     // we were using a key, we'd also want to check that it is alive.
1032 ///     // (Keys can expire, but User IDs cannot.)
1033 ///     if let RevocationStatus::Revoked(_revs) = u.revocation_status() {
1034 ///         // Revoked by the key owner.  (If we care about
1035 ///         // designated revokers, then we need to check those
1036 ///         // ourselves.)
1037 ///     } else {
1038 ///         // Print information about the User ID.
1039 ///         eprintln!("{}: preferred symmetric algorithms: {:?}",
1040 ///                   String::from_utf8_lossy(u.value()),
1041 ///                   u.preferred_symmetric_algorithms());
1042 ///     }
1043 /// }
1044 /// # Ok(()) }
1045 /// ```
1046 ///
1047 /// [`ComponentAmalgamation`]: struct.ComponentAmalgamation.html
1048 /// [`Policy`]: ../../policy/index.html
1049 /// [`ValidAmalgamation`]: trait.ValidAmalgamation.html
1050 /// [`ValidateAmalgamation::with_policy`]: trait.ValidateAmalgamation.html#tymethod.with_policy
1051 /// [`ComponentAmalgamationIter`]: struct.ComponentAmalgamationIter.html
1052 #[derive(Debug)]
1053 pub struct ValidComponentAmalgamation<'a, C> {
1054     ca: ComponentAmalgamation<'a, C>,
1055     cert: ValidCert<'a>,
1056     // The binding signature at time `time`.  (This is just a cache.)
1057     binding_signature: &'a Signature,
1058 }
1059 
1060 /// A Valid User ID and its associated data.
1061 ///
1062 /// A specialized version of [`ValidComponentAmalgamation`].
1063 ///
1064 /// [`ValidComponentAmalgamation`]: struct.ValidComponentAmalgamation.html
1065 pub type ValidUserIDAmalgamation<'a> = ValidComponentAmalgamation<'a, UserID>;
1066 
1067 /// A Valid User Attribute and its associated data.
1068 ///
1069 /// A specialized version of [`ValidComponentAmalgamation`].
1070 ///
1071 /// [`ValidComponentAmalgamation`]: struct.ValidComponentAmalgamation.html
1072 pub type ValidUserAttributeAmalgamation<'a>
1073     = ValidComponentAmalgamation<'a, UserAttribute>;
1074 
1075 // derive(Clone) doesn't work with generic parameters that don't
1076 // implement clone.  But, we don't need to require that C implements
1077 // Clone, because we're not cloning C, just the reference.
1078 //
1079 // See: https://github.com/rust-lang/rust/issues/26925
1080 impl<'a, C> Clone for ValidComponentAmalgamation<'a, C> {
clone(&self) -> Self1081     fn clone(&self) -> Self {
1082         Self {
1083             ca: self.ca.clone(),
1084             cert: self.cert.clone(),
1085             binding_signature: self.binding_signature,
1086         }
1087     }
1088 }
1089 
1090 impl<'a, C> std::ops::Deref for ValidComponentAmalgamation<'a, C> {
1091     type Target = ComponentAmalgamation<'a, C>;
1092 
deref(&self) -> &Self::Target1093     fn deref(&self) -> &Self::Target {
1094         assert!(std::ptr::eq(self.ca.cert(), self.cert.cert()));
1095         &self.ca
1096     }
1097 }
1098 
1099 impl<'a, C: 'a> From<ValidComponentAmalgamation<'a, C>>
1100     for ComponentAmalgamation<'a, C>
1101 {
from(vca: ValidComponentAmalgamation<'a, C>) -> Self1102     fn from(vca: ValidComponentAmalgamation<'a, C>) -> Self {
1103         assert!(std::ptr::eq(vca.ca.cert(), vca.cert.cert()));
1104         vca.ca
1105     }
1106 }
1107 
1108 impl<'a, C> ValidComponentAmalgamation<'a, C>
1109     where C: Ord
1110 {
1111     /// Returns the amalgamated primary component at time `time`
1112     ///
1113     /// If `time` is None, then the current time is used.
1114     /// `ValidComponentAmalgamationIter` for the definition of a valid component.
1115     ///
1116     /// The primary component is determined by taking the components that
1117     /// are alive at time `t`, and sorting them as follows:
1118     ///
1119     ///   - non-revoked first
1120     ///   - primary first
1121     ///   - signature creation first
1122     ///
1123     /// If there is more than one, than one is selected in a
1124     /// deterministic, but undefined manner.
1125     ///
1126     /// If `valid_cert` is `false`, then this does not also check
1127     /// whether the certificate is valid; it only checks whether the
1128     /// component is valid.  Normally, this should be `true`.  This
1129     /// option is only expose to allow breaking an infinite recursion:
1130     ///
1131     ///   - To check if a certificate is valid, we check if the
1132     ///     primary key is valid.
1133     ///
1134     ///   - To check if the primary key is valid, we need the primary
1135     ///     key's self signature
1136     ///
1137     ///   - To find the primary key's self signature, we need to find
1138     ///     the primary user id
1139     ///
1140     ///   - To find the primary user id, we need to check if the user
1141     ///     id is valid.
1142     ///
1143     ///   - To check if the user id is valid, we need to check that
1144     ///     the corresponding certificate is valid.
primary(cert: &'a Cert, iter: std::slice::Iter<'a, ComponentBundle<C>>, policy: &'a dyn Policy, t: SystemTime, valid_cert: bool) -> Result<ValidComponentAmalgamation<'a, C>>1145     pub(super) fn primary(cert: &'a Cert,
1146                           iter: std::slice::Iter<'a, ComponentBundle<C>>,
1147                           policy: &'a dyn Policy, t: SystemTime,
1148                           valid_cert: bool)
1149         -> Result<ValidComponentAmalgamation<'a, C>>
1150     {
1151         use std::cmp::Ordering;
1152 
1153         let mut error = None;
1154 
1155         // Filter out components that are not alive at time `t`.
1156         //
1157         // While we have the binding signature, extract a few
1158         // properties to avoid recomputing the same thing multiple
1159         // times.
1160         iter.filter_map(|c| {
1161             // No binding signature at time `t` => not alive.
1162             let sig = match c.binding_signature(policy, t) {
1163                 Ok(sig) => Some(sig),
1164                 Err(e) => {
1165                     error = Some(e);
1166                     None
1167                 },
1168             }?;
1169 
1170             let revoked = c._revocation_status(policy, t, false, Some(sig));
1171             let primary = sig.primary_userid().unwrap_or(false);
1172             let signature_creation_time = match sig.signature_creation_time() {
1173                 Some(time) => Some(time),
1174                 None => {
1175                     error = Some(Error::MalformedPacket(
1176                         "Signature has no creation time".into()).into());
1177                     None
1178                 },
1179             }?;
1180 
1181             Some(((c, sig, revoked), primary, signature_creation_time))
1182         })
1183             .max_by(|(a, a_primary, a_signature_creation_time),
1184                     (b, b_primary, b_signature_creation_time)| {
1185                 match (destructures_to!(RevocationStatus::Revoked(_) = &a.2),
1186                        destructures_to!(RevocationStatus::Revoked(_) = &b.2)) {
1187                     (true, false) => return Ordering::Less,
1188                     (false, true) => return Ordering::Greater,
1189                     _ => (),
1190                 }
1191                 match (a_primary, b_primary) {
1192                     (true, false) => return Ordering::Greater,
1193                     (false, true) => return Ordering::Less,
1194                     _ => (),
1195                 }
1196                 match a_signature_creation_time.cmp(&b_signature_creation_time)
1197                 {
1198                     Ordering::Less => return Ordering::Less,
1199                     Ordering::Greater => return Ordering::Greater,
1200                     Ordering::Equal => (),
1201                 }
1202 
1203                 // Fallback to a lexographical comparison.  Prefer
1204                 // the "smaller" one.
1205                 match a.0.component().cmp(&b.0.component()) {
1206                     Ordering::Less => return Ordering::Greater,
1207                     Ordering::Greater => return Ordering::Less,
1208                     Ordering::Equal =>
1209                         panic!("non-canonicalized Cert (duplicate components)"),
1210                 }
1211             })
1212             .ok_or_else(|| {
1213                 error.map(|e| e.context(format!(
1214                     "No binding signature at time {}", crate::fmt::time(&t))))
1215                     .unwrap_or(Error::NoBindingSignature(t).into())
1216             })
1217             .and_then(|c| ComponentAmalgamation::new(cert, (c.0).0)
1218                       .with_policy_relaxed(policy, t, valid_cert))
1219     }
1220 }
1221 
1222 impl<'a, C> ValidateAmalgamation<'a, C> for ValidComponentAmalgamation<'a, C> {
1223     type V = Self;
1224 
with_policy<T>(self, policy: &'a dyn Policy, time: T) -> Result<Self::V> where T: Into<Option<time::SystemTime>>, Self: Sized,1225     fn with_policy<T>(self, policy: &'a dyn Policy, time: T) -> Result<Self::V>
1226         where T: Into<Option<time::SystemTime>>,
1227               Self: Sized,
1228     {
1229         assert!(std::ptr::eq(self.ca.cert(), self.cert.cert()));
1230 
1231         let time = time.into().unwrap_or_else(SystemTime::now);
1232         self.ca.with_policy(policy, time)
1233     }
1234 }
1235 
1236 impl<'a, C> ValidAmalgamation<'a, C> for ValidComponentAmalgamation<'a, C> {
cert(&self) -> &ValidCert<'a>1237     fn cert(&self) -> &ValidCert<'a> {
1238         assert!(std::ptr::eq(self.ca.cert(), self.cert.cert()));
1239         &self.cert
1240     }
1241 
time(&self) -> SystemTime1242     fn time(&self) -> SystemTime {
1243         assert!(std::ptr::eq(self.ca.cert(), self.cert.cert()));
1244         self.cert.time
1245     }
1246 
policy(&self) -> &'a dyn Policy1247     fn policy(&self) -> &'a dyn Policy
1248     {
1249         assert!(std::ptr::eq(self.ca.cert(), self.cert.cert()));
1250         self.cert.policy
1251     }
1252 
binding_signature(&self) -> &'a Signature1253     fn binding_signature(&self) -> &'a Signature {
1254         assert!(std::ptr::eq(self.ca.cert(), self.cert.cert()));
1255         self.binding_signature
1256     }
1257 
revocation_status(&self) -> RevocationStatus<'a>1258     fn revocation_status(&self) -> RevocationStatus<'a> {
1259         self.bundle._revocation_status(self.policy(), self.cert.time,
1260                                        false, Some(self.binding_signature))
1261     }
1262 }
1263 
1264 impl<'a, C> crate::cert::Preferences<'a>
1265     for ValidComponentAmalgamation<'a, C>
1266 {
preferred_symmetric_algorithms(&self) -> Option<&'a [SymmetricAlgorithm]>1267     fn preferred_symmetric_algorithms(&self)
1268                                       -> Option<&'a [SymmetricAlgorithm]> {
1269         self.map(|s| s.preferred_symmetric_algorithms())
1270     }
1271 
preferred_hash_algorithms(&self) -> Option<&'a [HashAlgorithm]>1272     fn preferred_hash_algorithms(&self) -> Option<&'a [HashAlgorithm]> {
1273         self.map(|s| s.preferred_hash_algorithms())
1274     }
1275 
preferred_compression_algorithms(&self) -> Option<&'a [CompressionAlgorithm]>1276     fn preferred_compression_algorithms(&self)
1277                                         -> Option<&'a [CompressionAlgorithm]> {
1278         self.map(|s| s.preferred_compression_algorithms())
1279     }
1280 
preferred_aead_algorithms(&self) -> Option<&'a [AEADAlgorithm]>1281     fn preferred_aead_algorithms(&self) -> Option<&'a [AEADAlgorithm]> {
1282         self.map(|s| s.preferred_aead_algorithms())
1283     }
1284 
key_server_preferences(&self) -> Option<KeyServerPreferences>1285     fn key_server_preferences(&self) -> Option<KeyServerPreferences> {
1286         self.map(|s| s.key_server_preferences())
1287     }
1288 
preferred_key_server(&self) -> Option<&'a [u8]>1289     fn preferred_key_server(&self) -> Option<&'a [u8]> {
1290         self.map(|s| s.preferred_key_server())
1291     }
1292 
features(&self) -> Option<Features>1293     fn features(&self) -> Option<Features> {
1294         self.map(|s| s.features())
1295     }
1296 }
1297 
1298 #[cfg(test)]
1299 mod test {
1300     use crate::policy::StandardPolicy as P;
1301     use crate::cert::prelude::*;
1302 
1303     // derive(Clone) doesn't work with generic parameters that don't
1304     // implement clone.  Make sure that our custom implementations
1305     // work.
1306     //
1307     // See: https://github.com/rust-lang/rust/issues/26925
1308     #[test]
clone()1309     fn clone() {
1310         let p = &P::new();
1311 
1312         let (cert, _) = CertBuilder::new()
1313             .add_userid("test@example.example")
1314             .generate()
1315             .unwrap();
1316 
1317         let userid : UserIDAmalgamation = cert.userids().nth(0).unwrap();
1318         assert_eq!(userid.userid(), userid.clone().userid());
1319 
1320         let userid : ValidUserIDAmalgamation
1321             = userid.with_policy(p, None).unwrap();
1322         let c = userid.clone();
1323         assert_eq!(userid.userid(), c.userid());
1324         assert_eq!(userid.time(), c.time());
1325     }
1326 
1327     #[test]
map()1328     fn map() {
1329         // The reference returned by `ComponentAmalgamation::userid`
1330         // and `ComponentAmalgamation::user_attribute` is bound by the
1331         // reference to the `Component` in the
1332         // `ComponentAmalgamation`, not the `ComponentAmalgamation`
1333         // itself.
1334         let (cert, _) = CertBuilder::new()
1335             .add_userid("test@example.example")
1336             .generate()
1337             .unwrap();
1338 
1339         let _ = cert.userids().map(|ua| ua.userid())
1340             .collect::<Vec<_>>();
1341 
1342         let _ = cert.user_attributes().map(|ua| ua.user_attribute())
1343             .collect::<Vec<_>>();
1344     }
1345 }
1346