1 //! A certificate component and its associated signatures. 2 //! 3 //! Certificates ([`Cert`]s) are a collection of components where each 4 //! component corresponds to a [`Packet`], and each component has zero 5 //! or more associated [`Signature`]s. A [`ComponentBundle`] 6 //! encapsulates a component and its associated signatures. 7 //! 8 //! Sequoia supports four different kinds of components: [`Key`]s, 9 //! [`UserID`]s, [`UserAttribute`]s, and [`Unknown`] components. The 10 //! `Unknown` component has two purposes. First, it is used to store 11 //! packets that appear in a certificate and have an unknown [`Tag`]. 12 //! By not silently dropping these packets, it is possible to round 13 //! trip certificates without losing any information. This provides a 14 //! measure of future compatibility. Second, the `Unknown` component 15 //! is used to store unsupported components. For instance, Sequoia 16 //! doesn't support v3 `Key`s, which are deprecated, or v5 `Key`s, 17 //! which are still being standardized. Because these keys are 18 //! effectively unusable, they are stored as `Unknown` components 19 //! instead of `Key`s. 20 //! 21 //! There are four types of signatures associated with a component: 22 //! self signatures, self revocations, third-party signatures, and 23 //! third-party revocations. When parsing a certificate, self 24 //! signatures and self revocations are checked for validity and 25 //! invalid signatures and revocations are discarded. Since the keys 26 //! are not normally available, third-party signatures and third-party 27 //! revocations cannot be rigorously (i.e., cryptographically) checked 28 //! for validity. 29 //! 30 //! With the exception of the primary key, a component's self 31 //! signatures are binding signatures. A binding signature firstly 32 //! binds the component to the certificate. That is, it provides 33 //! cryptographic evidence that the certificate holder intended for 34 //! the component to be associated with the certificate. Binding 35 //! signatures also provide information about the component. For 36 //! instance, the binding signature for a subkey includes its 37 //! capabilities, and its expiry time. 38 //! 39 //! Since the primary key is the embodiment of the certificate, there 40 //! is nothing to bind it to. Correspondingly, self signatures on a 41 //! primary key are called direct key signatures. Direct key 42 //! signatures are used to provide information about the whole 43 //! certificate. For instance, they can include the default `Key` 44 //! expiry time. This is used if a subkey's binding signature doesn't 45 //! include a expiry. 46 //! 47 //! Self-revocations are revocation certificates issued by the key 48 //! certificate holder. 49 //! 50 //! Third-party signatures are typically signatures certifying that a 51 //! `User ID` or `User Attribute` accurately describes the certificate 52 //! holder. This information is used by trust models, like the Web of 53 //! Trust, to indirectly authenticate keys. 54 //! 55 //! Third-party revocations are revocations issued by another 56 //! certificate. They should normally only be respected if the 57 //! certificate holder made the issuer a so-called [designated 58 //! revoker]. 59 //! 60 //! # Important 61 //! 62 //! When looking up information about a component, it is generally 63 //! better to use the [`ComponentAmalgamation`] or [`KeyAmalgamation`] 64 //! data structures. These data structures provide convenience 65 //! methods that implement the [complicated semantics] for correctly 66 //! locating information. 67 //! 68 //! [`Cert`]: ../index.html 69 //! [`Packet`]: ../../packet/index.html 70 //! [`Signature`]: ../../packet/signature/index.html 71 //! [`ComponentBundle`]: ./struct.ComponentBundle.html 72 //! [`Key`]: ../../packet/key/index.html 73 //! [`UserID`]: ../../packet/struct.UserID.html 74 //! [`UserAttribute`]: ../../packet/user_attribute/index.html 75 //! [`Unknown`]: ../../packet/struct.Unknown.html 76 //! [`Tag`]: ../../packet/enum.Tag.html 77 //! [designated revoker]: https://tools.ietf.org/html/rfc4880#section-5.2.3.15 78 //! [`ComponentAmalgamation`]: ../amalgamation/index.html 79 //! [`KeyAmalgamation`]: ../key_amalgamation/index.html 80 //! [complicated semantics]: https://tools.ietf.org/html/rfc4880#section-5.2.3.3 81 82 use std::time; 83 use std::ops::Deref; 84 85 use crate::{ 86 Error, 87 packet::Signature, 88 packet::Key, 89 packet::key, 90 packet::UserID, 91 packet::UserAttribute, 92 packet::Unknown, 93 Packet, 94 policy::Policy, 95 Result, 96 }; 97 use crate::types::{ 98 RevocationType, 99 RevocationStatus, 100 }; 101 102 use super::{ 103 sig_cmp, 104 canonical_signature_order, 105 }; 106 107 /// A certificate component and its associated signatures. 108 /// 109 /// [See the module level documentation]](index.html) for a detailed 110 /// description. 111 #[derive(Debug, Clone, PartialEq)] 112 pub struct ComponentBundle<C> { 113 pub(crate) component: C, 114 115 // Self signatures. 116 pub(crate) self_signatures: Vec<Signature>, 117 118 // Third-party certifications. (In general, this will only be by 119 // designated revokers.) 120 pub(crate) certifications: Vec<Signature>, 121 122 // Self revocations. 123 pub(crate) self_revocations: Vec<Signature>, 124 125 // Third-party revocations (e.g., designated revokers). 126 pub(crate) other_revocations: Vec<Signature>, 127 } 128 129 /// A key (primary or subkey, public or private) and any associated 130 /// signatures. 131 /// 132 /// [See the module level documentation.](index.html) 133 pub type KeyBundle<KeyPart, KeyRole> = ComponentBundle<Key<KeyPart, KeyRole>>; 134 135 /// A primary key and any associated signatures. 136 /// 137 /// [See the module level documentation.](index.html) 138 pub type PrimaryKeyBundle<KeyPart> = 139 KeyBundle<KeyPart, key::PrimaryRole>; 140 141 /// A subkey and any associated signatures. 142 /// 143 /// [See the module level documentation.](index.html) 144 pub type SubkeyBundle<KeyPart> 145 = KeyBundle<KeyPart, key::SubordinateRole>; 146 147 /// A User ID and any associated signatures. 148 /// 149 /// [See the module level documentation.](index.html) 150 pub type UserIDBundle = ComponentBundle<UserID>; 151 152 /// A User Attribute and any associated signatures. 153 /// 154 /// [See the module level documentation.](index.html) 155 pub type UserAttributeBundle = ComponentBundle<UserAttribute>; 156 157 /// An unknown component and any associated signatures. 158 /// 159 /// Note: all signatures are stored as certifications. 160 /// 161 /// [See the module level documentation.](index.html) 162 pub type UnknownBundle = ComponentBundle<Unknown>; 163 164 165 impl<C> Deref for ComponentBundle<C> 166 { 167 type Target = C; 168 deref(&self) -> &Self::Target169 fn deref(&self) -> &Self::Target { 170 &self.component 171 } 172 } 173 174 impl<C> ComponentBundle<C> { 175 /// Returns a reference to the bundle's component. 176 /// 177 /// # Examples 178 /// 179 /// ``` 180 /// # extern crate sequoia_openpgp as openpgp; 181 /// # use openpgp::cert::prelude::*; 182 /// # 183 /// # fn main() -> openpgp::Result<()> { 184 /// # let (cert, _) = 185 /// # CertBuilder::general_purpose(None, Some("alice@example.org")) 186 /// # .generate()?; 187 /// // Display some information about any unknown components. 188 /// for u in cert.unknowns() { 189 /// eprintln!(" - {:?}", u.component()); 190 /// } 191 /// # Ok(()) } 192 /// ``` component(&self) -> &C193 pub fn component(&self) -> &C { 194 &self.component 195 } 196 197 /// Returns a mutable reference to the component. component_mut(&mut self) -> &mut C198 fn component_mut(&mut self) -> &mut C { 199 &mut self.component 200 } 201 202 /// Returns the active binding signature at time `t`. 203 /// 204 /// The active binding signature is the most recent, non-revoked 205 /// self-signature that is valid according to the `policy` and 206 /// alive at time `t` (`creation time <= t`, `t < expiry`). If 207 /// there are multiple such signatures then the signatures are 208 /// ordered by their MPIs interpreted as byte strings. 209 /// 210 /// # Examples 211 /// 212 /// ``` 213 /// # extern crate sequoia_openpgp as openpgp; 214 /// # use openpgp::cert::prelude::*; 215 /// use openpgp::policy::StandardPolicy; 216 /// # 217 /// # fn main() -> openpgp::Result<()> { 218 /// let p = &StandardPolicy::new(); 219 /// 220 /// # let (cert, _) = 221 /// # CertBuilder::general_purpose(None, Some("alice@example.org")) 222 /// # .generate()?; 223 /// // Display information about each User ID's current active 224 /// // binding signature (the `time` parameter is `None`), if any. 225 /// for ua in cert.userids() { 226 /// eprintln!("{:?}", ua.binding_signature(p, None)); 227 /// } 228 /// # Ok(()) } 229 /// ``` binding_signature<T>(&self, policy: &dyn Policy, t: T) -> Result<&Signature> where T: Into<Option<time::SystemTime>>230 pub fn binding_signature<T>(&self, policy: &dyn Policy, t: T) 231 -> Result<&Signature> 232 where T: Into<Option<time::SystemTime>> 233 { 234 let t = t.into().unwrap_or_else(time::SystemTime::now); 235 236 // Recall: the signatures are sorted by their creation time in 237 // descending order, i.e., newest first. 238 // 239 // We want the newest signature that is older than t. So, 240 // search for `t`. 241 242 let i = 243 // Usually, the first signature is what we are looking for. 244 // Short circuit the binary search. 245 if Some(t) >= self.self_signatures.get(0) 246 .and_then(|s| s.signature_creation_time()) 247 { 248 0 249 } else { 250 match self.self_signatures.binary_search_by( 251 |s| canonical_signature_order( 252 s.signature_creation_time(), Some(t))) 253 { 254 // If there are multiple matches, then we need to search 255 // backwards to find the first one. Consider: 256 // 257 // t: 9 8 8 8 8 7 258 // i: 0 1 2 3 4 5 259 // 260 // If we are looking for t == 8, then binary_search could 261 // return index 1, 2, 3 or 4. 262 Ok(mut i) => { 263 while i > 0 264 && self.self_signatures[i - 1].signature_creation_time() 265 == Some(t) 266 { 267 i -= 1; 268 } 269 i 270 } 271 272 // There was no match. `i` is where a new element could 273 // be inserted while maintaining the sorted order. 274 // Consider: 275 // 276 // t: 9 8 6 5 277 // i: 0 1 2 3 278 // 279 // If we are looing for t == 7, then binary_search will 280 // return i == 2. That's exactly where we should start 281 // looking. 282 Err(i) => i, 283 } 284 }; 285 286 let mut sig = None; 287 288 // Prefer the first error, which is the error arising from the 289 // most recent binding signature that wasn't created after 290 // `t`. 291 let mut error = None; 292 293 for s in self.self_signatures[i..].iter() { 294 if let Err(e) = s.signature_alive(t, time::Duration::new(0, 0)) { 295 // We know that t >= signature's creation time. So, 296 // it is expired. But an older signature might not 297 // be. So, keep trying. 298 if error.is_none() { 299 error = Some(e); 300 } 301 continue; 302 } 303 304 if let Err(e) = policy.signature(s) { 305 if error.is_none() { 306 error = Some(e); 307 } 308 continue; 309 } 310 311 // The signature is good, but we may still need to verify the 312 // back sig. 313 if s.typ() == crate::types::SignatureType::SubkeyBinding && 314 s.key_flags().map(|kf| kf.for_signing()).unwrap_or(false) 315 { 316 if let Some(backsig) = s.embedded_signature() { 317 if let Err(e) = backsig.signature_alive( 318 t, time::Duration::new(0, 0)) 319 { 320 // The primary key binding signature is not 321 // alive. 322 if error.is_none() { 323 error = Some(e); 324 } 325 continue; 326 } 327 328 if let Err(e) = policy.signature(backsig) { 329 if error.is_none() { 330 error = Some(e); 331 } 332 continue; 333 } 334 } else { 335 // This shouldn't happen because 336 // Signature::verify_subkey_binding checks for the 337 // primary key signature. But, better be safe. 338 if error.is_none() { 339 error = Some(Error::BadSignature( 340 "Primary key binding signature missing".into()) 341 .into()); 342 } 343 continue; 344 } 345 } 346 347 sig = Some(s); 348 break; 349 } 350 351 if let Some(sig) = sig { 352 Ok(sig) 353 } else if let Some(err) = error { 354 Err(err) 355 } else { 356 Err(Error::NoBindingSignature(t).into()) 357 } 358 } 359 360 /// Returns the component's self-signatures. 361 /// 362 /// The signatures are validated, and they are sorted by their 363 /// creation time, most recent first. 364 /// 365 /// # Examples 366 /// 367 /// ``` 368 /// # extern crate sequoia_openpgp as openpgp; 369 /// # use openpgp::cert::prelude::*; 370 /// use openpgp::policy::StandardPolicy; 371 /// # 372 /// # fn main() -> openpgp::Result<()> { 373 /// let p = &StandardPolicy::new(); 374 /// 375 /// # let (cert, _) = 376 /// # CertBuilder::general_purpose(None, Some("alice@example.org")) 377 /// # .generate()?; 378 /// for (i, ka) in cert.keys().enumerate() { 379 /// eprintln!("Key #{} ({}) has {:?} self signatures", 380 /// i, ka.fingerprint(), 381 /// ka.self_signatures().len()); 382 /// } 383 /// # Ok(()) } 384 /// ``` self_signatures(&self) -> &[Signature]385 pub fn self_signatures(&self) -> &[Signature] { 386 &self.self_signatures 387 } 388 389 /// Returns the component's third-party certifications. 390 /// 391 /// The signatures are *not* validated. They are sorted by their 392 /// creation time, most recent first. 393 /// 394 /// # Examples 395 /// 396 /// ``` 397 /// # extern crate sequoia_openpgp as openpgp; 398 /// # use openpgp::cert::prelude::*; 399 /// use openpgp::policy::StandardPolicy; 400 /// # 401 /// # fn main() -> openpgp::Result<()> { 402 /// let p = &StandardPolicy::new(); 403 /// 404 /// # let (cert, _) = 405 /// # CertBuilder::general_purpose(None, Some("alice@example.org")) 406 /// # .generate()?; 407 /// for ua in cert.userids() { 408 /// eprintln!("User ID {} has {:?} unverified, third-party certifications", 409 /// String::from_utf8_lossy(ua.userid().value()), 410 /// ua.certifications().len()); 411 /// } 412 /// # Ok(()) } 413 /// ``` certifications(&self) -> &[Signature]414 pub fn certifications(&self) -> &[Signature] { 415 &self.certifications 416 } 417 418 /// Returns the component's revocations that were issued by the 419 /// certificate holder. 420 /// 421 /// The revocations are validated, and they are sorted by their 422 /// creation time, most recent first. 423 /// 424 /// # Examples 425 /// 426 /// ``` 427 /// # extern crate sequoia_openpgp as openpgp; 428 /// # use openpgp::cert::prelude::*; 429 /// use openpgp::policy::StandardPolicy; 430 /// # 431 /// # fn main() -> openpgp::Result<()> { 432 /// let p = &StandardPolicy::new(); 433 /// 434 /// # let (cert, _) = 435 /// # CertBuilder::general_purpose(None, Some("alice@example.org")) 436 /// # .generate()?; 437 /// for u in cert.userids() { 438 /// eprintln!("User ID {} has {:?} revocation certificates.", 439 /// String::from_utf8_lossy(u.userid().value()), 440 /// u.self_revocations().len()); 441 /// } 442 /// # Ok(()) } 443 /// ``` self_revocations(&self) -> &[Signature]444 pub fn self_revocations(&self) -> &[Signature] { 445 &self.self_revocations 446 } 447 448 /// Returns the component's revocations that were issued by other 449 /// certificates. 450 /// 451 /// The revocations are *not* validated. They are sorted by their 452 /// creation time, most recent first. 453 /// 454 /// # Examples 455 /// 456 /// ``` 457 /// # extern crate sequoia_openpgp as openpgp; 458 /// # use openpgp::cert::prelude::*; 459 /// use openpgp::policy::StandardPolicy; 460 /// # 461 /// # fn main() -> openpgp::Result<()> { 462 /// let p = &StandardPolicy::new(); 463 /// 464 /// # let (cert, _) = 465 /// # CertBuilder::general_purpose(None, Some("alice@example.org")) 466 /// # .generate()?; 467 /// for u in cert.userids() { 468 /// eprintln!("User ID {} has {:?} unverified, third-party revocation certificates.", 469 /// String::from_utf8_lossy(u.userid().value()), 470 /// u.other_revocations().len()); 471 /// } 472 /// # Ok(()) } 473 /// ``` other_revocations(&self) -> &[Signature]474 pub fn other_revocations(&self) -> &[Signature] { 475 &self.other_revocations 476 } 477 478 /// Returns the component's revocation status at time `t`. 479 /// 480 /// A component is considered to be revoked at time `t` if: 481 /// 482 /// - There is a live revocation at time `t` that is newer than 483 /// all live self signatures at time `t`. 484 /// 485 /// - `hard_revocations_are_final` is true, and there is a hard 486 /// revocation (even if it is not yet live at time `t`, and 487 /// even if there is a newer self-signature). 488 /// 489 /// selfsig must be the newest live self signature at time `t`. _revocation_status<'a, T>(&'a self, policy: &dyn Policy, t: T, hard_revocations_are_final: bool, selfsig: Option<&Signature>) -> RevocationStatus<'a> where T: Into<Option<time::SystemTime>>490 pub(crate) fn _revocation_status<'a, T>(&'a self, policy: &dyn Policy, t: T, 491 hard_revocations_are_final: bool, 492 selfsig: Option<&Signature>) 493 -> RevocationStatus<'a> 494 where T: Into<Option<time::SystemTime>> 495 { 496 // Fallback time. 497 let time_zero = || time::UNIX_EPOCH; 498 let t = t.into().unwrap_or_else(time::SystemTime::now); 499 let selfsig_creation_time 500 = selfsig.and_then(|s| s.signature_creation_time()) 501 .unwrap_or_else(time_zero); 502 503 tracer!(super::TRACE, "ComponentBundle::_revocation_status", 0); 504 t!("hard_revocations_are_final: {}, selfsig: {:?}, t: {:?}", 505 hard_revocations_are_final, 506 selfsig_creation_time, 507 t); 508 if let Some(selfsig) = selfsig { 509 assert!( 510 selfsig.signature_alive(t, time::Duration::new(0, 0)).is_ok()); 511 } 512 513 let check = |revs: &'a [Signature]| -> Option<Vec<&'a Signature>> { 514 let revs = revs.iter().filter_map(|rev| { 515 if let Err(err) = policy.signature(rev) { 516 t!(" revocation rejected by caller policy: {}", err); 517 None 518 } else if hard_revocations_are_final 519 && rev.reason_for_revocation() 520 .map(|(r, _)| { 521 r.revocation_type() == RevocationType::Hard 522 }) 523 // If there is no Reason for Revocation 524 // packet, assume that it is a hard 525 // revocation. 526 .unwrap_or(true) 527 { 528 t!(" got a hard revocation: {:?}, {:?}", 529 rev.signature_creation_time() 530 .unwrap_or_else(time_zero), 531 rev.reason_for_revocation() 532 .map(|r| (r.0, String::from_utf8_lossy(r.1)))); 533 Some(rev) 534 } else if selfsig_creation_time 535 > rev.signature_creation_time().unwrap_or_else(time_zero) 536 { 537 // This comes after the hard revocation check, 538 // because a hard revocation is always valid. 539 t!(" newer binding signature trumps soft revocation ({:?} > {:?})", 540 selfsig_creation_time, 541 rev.signature_creation_time().unwrap_or_else(time_zero)); 542 None 543 } else if let Err(err) 544 = rev.signature_alive(t, time::Duration::new(0, 0)) 545 { 546 // This comes after the hard revocation check, 547 // because a hard revocation is always valid. 548 t!(" revocation not alive ({:?} - {:?}): {}", 549 rev.signature_creation_time().unwrap_or_else(time_zero), 550 rev.signature_validity_period() 551 .unwrap_or_else(|| time::Duration::new(0, 0)), 552 err); 553 None 554 } else { 555 t!(" got a revocation: {:?} ({:?})", 556 rev.signature_creation_time().unwrap_or_else(time_zero), 557 rev.reason_for_revocation() 558 .map(|r| (r.0, String::from_utf8_lossy(r.1)))); 559 Some(rev) 560 } 561 }).collect::<Vec<&Signature>>(); 562 563 if revs.len() == 0 { 564 None 565 } else { 566 Some(revs) 567 } 568 }; 569 570 if let Some(revs) = check(&self.self_revocations) { 571 RevocationStatus::Revoked(revs) 572 } else if let Some(revs) = check(&self.other_revocations) { 573 RevocationStatus::CouldBe(revs) 574 } else { 575 RevocationStatus::NotAsFarAsWeKnow 576 } 577 } 578 579 /// Turns the `ComponentBundle` into an iterator over its 580 /// `Packet`s. 581 /// 582 /// The signatures are ordered as follows: 583 /// 584 /// - Self revocations, 585 /// - Self signatures, 586 /// - Third-party signatures, and 587 /// - Third-party revocations. 588 /// 589 /// For a given type of signature, the signatures are ordered by 590 /// their creation time, most recent first. into_packets<'a>(self) -> impl Iterator<Item=Packet> where Packet: From<C>591 pub(crate) fn into_packets<'a>(self) -> impl Iterator<Item=Packet> 592 where Packet: From<C> 593 { 594 let p : Packet = self.component.into(); 595 std::iter::once(p) 596 .chain(self.self_revocations.into_iter().map(|s| s.into())) 597 .chain(self.self_signatures.into_iter().map(|s| s.into())) 598 .chain(self.certifications.into_iter().map(|s| s.into())) 599 .chain(self.other_revocations.into_iter().map(|s| s.into())) 600 } 601 602 // Sorts and dedups the binding's signatures. 603 // 604 // This function assumes that the signatures have already been 605 // cryptographically checked. 606 // 607 // Note: this uses Signature::eq to compare signatures. That 608 // function ignores unhashed packets. If there are two signatures 609 // that only differ in their unhashed subpackets, they will be 610 // deduped. The unhashed areas are *not* merged; the one that is 611 // kept is undefined. sort_and_dedup(&mut self)612 pub(crate) fn sort_and_dedup(&mut self) 613 { 614 self.self_signatures.sort_by(sig_cmp); 615 self.self_signatures.dedup(); 616 617 // There is no need to sort the certifications, but we do 618 // want to remove dups and sorting is a prerequisite. 619 self.certifications.sort_by(sig_cmp); 620 self.certifications.dedup(); 621 622 self.self_revocations.sort_by(sig_cmp); 623 self.self_revocations.dedup(); 624 625 self.other_revocations.sort_by(sig_cmp); 626 self.other_revocations.dedup(); 627 } 628 } 629 630 impl<P: key::KeyParts, R: key::KeyRole> ComponentBundle<Key<P, R>> { 631 /// Returns a reference to the key. 632 /// 633 /// This is just a type-specific alias for 634 /// [`ComponentBundle::component`]. 635 /// 636 /// [`ComponentBundle::component`]: #method.component 637 /// 638 /// # Examples 639 /// 640 /// ``` 641 /// # extern crate sequoia_openpgp as openpgp; 642 /// # use openpgp::cert::prelude::*; 643 /// # 644 /// # fn main() -> openpgp::Result<()> { 645 /// # let (cert, _) = 646 /// # CertBuilder::general_purpose(None, Some("alice@example.org")) 647 /// # .generate()?; 648 /// // Display some information about the keys. 649 /// for ka in cert.keys() { 650 /// eprintln!(" - {:?}", ka.key()); 651 /// } 652 /// # Ok(()) } 653 /// ``` key(&self) -> &Key<P, R>654 pub fn key(&self) -> &Key<P, R> { 655 self.component() 656 } 657 658 /// Returns a mut reference to the key. key_mut(&mut self) -> &mut Key<P, R>659 pub(crate) fn key_mut(&mut self) -> &mut Key<P, R> { 660 self.component_mut() 661 } 662 } 663 664 impl<P: key::KeyParts> ComponentBundle<Key<P, key::SubordinateRole>> { 665 /// Returns the subkey's revocation status at time `t`. 666 /// 667 /// A subkey is revoked at time `t` if: 668 /// 669 /// - There is a live revocation at time `t` that is newer than 670 /// all live self signatures at time `t`, or 671 /// 672 /// - There is a hard revocation (even if it is not live at 673 /// time `t`, and even if there is a newer self-signature). 674 /// 675 /// Note: Certs and subkeys have different criteria from User IDs 676 /// and User Attributes. 677 /// 678 /// Note: this only returns whether this subkey is revoked; it 679 /// does not imply anything about the Cert or other components. 680 /// 681 /// # Examples 682 /// 683 /// ``` 684 /// # extern crate sequoia_openpgp as openpgp; 685 /// # use openpgp::cert::prelude::*; 686 /// use openpgp::policy::StandardPolicy; 687 /// # 688 /// # fn main() -> openpgp::Result<()> { 689 /// let p = &StandardPolicy::new(); 690 /// 691 /// # let (cert, _) = 692 /// # CertBuilder::general_purpose(None, Some("alice@example.org")) 693 /// # .generate()?; 694 /// // Display the subkeys' revocation status. 695 /// for ka in cert.keys().subkeys() { 696 /// eprintln!(" Revocation status of {}: {:?}", 697 /// ka.fingerprint(), ka.revocation_status(p, None)); 698 /// } 699 /// # Ok(()) } 700 /// ``` revocation_status<T>(&self, policy: &dyn Policy, t: T) -> RevocationStatus where T: Into<Option<time::SystemTime>>701 pub fn revocation_status<T>(&self, policy: &dyn Policy, t: T) 702 -> RevocationStatus 703 where T: Into<Option<time::SystemTime>> 704 { 705 let t = t.into(); 706 self._revocation_status(policy, t, true, 707 self.binding_signature(policy, t).ok()) 708 } 709 } 710 711 impl ComponentBundle<UserID> { 712 /// Returns a reference to the User ID. 713 /// 714 /// This is just a type-specific alias for 715 /// [`ComponentBundle::component`]. 716 /// 717 /// [`ComponentBundle::component`]: #method.component 718 /// 719 /// # Examples 720 /// 721 /// ``` 722 /// # extern crate sequoia_openpgp as openpgp; 723 /// # use openpgp::cert::prelude::*; 724 /// # 725 /// # fn main() -> openpgp::Result<()> { 726 /// # let (cert, _) = 727 /// # CertBuilder::general_purpose(None, Some("alice@example.org")) 728 /// # .generate()?; 729 /// // Display some information about the User IDs. 730 /// for ua in cert.userids() { 731 /// eprintln!(" - {:?}", ua.userid()); 732 /// } 733 /// # Ok(()) } 734 /// ``` userid(&self) -> &UserID735 pub fn userid(&self) -> &UserID { 736 self.component() 737 } 738 739 /// Returns the User ID's revocation status at time `t`.<a 740 /// name="userid_revocation_status"></a> 741 /// 742 /// <!-- Why we have the above anchor: 743 /// https://github.com/rust-lang/rust/issues/71912 --> 744 /// 745 /// A User ID is revoked at time `t` if: 746 /// 747 /// - There is a live revocation at time `t` that is newer than 748 /// all live self signatures at time `t`. 749 /// 750 /// Note: Certs and subkeys have different criteria from User IDs 751 /// and User Attributes. 752 /// 753 /// Note: this only returns whether this User ID is revoked; it 754 /// does not imply anything about the Cert or other components. 755 // 756 /// # Examples 757 /// 758 /// ``` 759 /// # extern crate sequoia_openpgp as openpgp; 760 /// # use openpgp::cert::prelude::*; 761 /// use openpgp::policy::StandardPolicy; 762 /// # 763 /// # fn main() -> openpgp::Result<()> { 764 /// let p = &StandardPolicy::new(); 765 /// 766 /// # let (cert, _) = 767 /// # CertBuilder::general_purpose(None, Some("alice@example.org")) 768 /// # .generate()?; 769 /// // Display the User IDs' revocation status. 770 /// for ua in cert.userids() { 771 /// eprintln!(" Revocation status of {}: {:?}", 772 /// String::from_utf8_lossy(ua.userid().value()), 773 /// ua.revocation_status(p, None)); 774 /// } 775 /// # Ok(()) } 776 /// ``` revocation_status<T>(&self, policy: &dyn Policy, t: T) -> RevocationStatus where T: Into<Option<time::SystemTime>>777 pub fn revocation_status<T>(&self, policy: &dyn Policy, t: T) 778 -> RevocationStatus 779 where T: Into<Option<time::SystemTime>> 780 { 781 let t = t.into(); 782 self._revocation_status(policy, t, false, self.binding_signature(policy, t).ok()) 783 } 784 } 785 786 impl ComponentBundle<UserAttribute> { 787 /// Returns a reference to the User Attribute. 788 /// 789 /// This is just a type-specific alias for 790 /// [`ComponentBundle::component`]. 791 /// 792 /// [`ComponentBundle::component`]: #method.component 793 /// 794 /// # Examples 795 /// 796 /// ``` 797 /// # extern crate sequoia_openpgp as openpgp; 798 /// # use openpgp::cert::prelude::*; 799 /// # 800 /// # fn main() -> openpgp::Result<()> { 801 /// # let (cert, _) = 802 /// # CertBuilder::general_purpose(None, Some("alice@example.org")) 803 /// # .generate()?; 804 /// // Display some information about the User Attributes 805 /// for ua in cert.user_attributes() { 806 /// eprintln!(" - {:?}", ua.user_attribute()); 807 /// } 808 /// # Ok(()) } 809 /// ``` user_attribute(&self) -> &UserAttribute810 pub fn user_attribute(&self) -> &UserAttribute { 811 self.component() 812 } 813 814 /// Returns the User Attribute's revocation status at time `t`. 815 /// 816 /// A User Attribute is revoked at time `t` if: 817 /// 818 /// - There is a live revocation at time `t` that is newer than 819 /// all live self signatures at time `t`. 820 /// 821 /// Note: Certs and subkeys have different criteria from User IDs 822 /// and User Attributes. 823 /// 824 /// Note: this only returns whether this User Attribute is revoked; 825 /// it does not imply anything about the Cert or other components. 826 // 827 /// # Examples 828 /// 829 /// ``` 830 /// # extern crate sequoia_openpgp as openpgp; 831 /// # use openpgp::cert::prelude::*; 832 /// use openpgp::policy::StandardPolicy; 833 /// # 834 /// # fn main() -> openpgp::Result<()> { 835 /// let p = &StandardPolicy::new(); 836 /// 837 /// # let (cert, _) = 838 /// # CertBuilder::general_purpose(None, Some("alice@example.org")) 839 /// # .generate()?; 840 /// // Display the User Attributes' revocation status. 841 /// for (i, ua) in cert.user_attributes().enumerate() { 842 /// eprintln!(" Revocation status of User Attribute #{}: {:?}", 843 /// i, ua.revocation_status(p, None)); 844 /// } 845 /// # Ok(()) } 846 /// ``` revocation_status<T>(&self, policy: &dyn Policy, t: T) -> RevocationStatus where T: Into<Option<time::SystemTime>>847 pub fn revocation_status<T>(&self, policy: &dyn Policy, t: T) 848 -> RevocationStatus 849 where T: Into<Option<time::SystemTime>> 850 { 851 let t = t.into(); 852 self._revocation_status(policy, t, false, 853 self.binding_signature(policy, t).ok()) 854 } 855 } 856 857 impl ComponentBundle<Unknown> { 858 /// Returns a reference to the unknown component. 859 /// 860 /// This is just a type-specific alias for 861 /// [`ComponentBundle::component`]. 862 /// 863 /// [`ComponentBundle::component`]: #method.component 864 /// 865 /// # Examples 866 /// 867 /// ``` 868 /// # extern crate sequoia_openpgp as openpgp; 869 /// # use openpgp::cert::prelude::*; 870 /// # 871 /// # fn main() -> openpgp::Result<()> { 872 /// # let (cert, _) = 873 /// # CertBuilder::general_purpose(None, Some("alice@example.org")) 874 /// # .generate()?; 875 /// // Display some information about the User Attributes 876 /// for u in cert.unknowns() { 877 /// eprintln!(" - {:?}", u.unknown()); 878 /// } 879 /// # Ok(()) } 880 /// ``` unknown(&self) -> &Unknown881 pub fn unknown(&self) -> &Unknown { 882 self.component() 883 } 884 } 885