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