sequoia_openpgp/types/
mod.rs

1//! Primitive types.
2//!
3//! This module provides types used in OpenPGP, like enumerations
4//! describing algorithms.
5//!
6//! # Common Operations
7//!
8//!  - *Rounding the creation time of signatures*: See the [`Timestamp::round_down`] method.
9//!  - *Checking key usage flags*: See the [`KeyFlags`] data structure.
10//!  - *Setting key validity ranges*: See the [`Timestamp`] and [`Duration`] data structures.
11//!
12//! # Data structures
13//!
14//! ## `CompressionLevel`
15//!
16//! Allows adjusting the amount of effort spent on compressing encoded data.
17//! This structure additionally has several helper methods for commonly used
18//! compression strategies.
19//!
20//! ## `Features`
21//!
22//! Describes particular features supported by the given OpenPGP implementation.
23//!
24//! ## `KeyFlags`
25//!
26//! Holds information about a key in particular how the given key can be used.
27//!
28//! ## `RevocationKey`
29//!
30//! Describes a key that has been designated to issue revocation signatures.
31//!
32//! # `KeyServerPreferences`
33//!
34//! Describes preferences regarding to key servers.
35//!
36//! ## `Timestamp` and `Duration`
37//!
38//! In OpenPGP time is represented as the number of seconds since the UNIX epoch stored
39//! as an `u32`. These two data structures allow manipulating OpenPGP time ensuring
40//! that adding or subtracting durations will never overflow or underflow without
41//! notice.
42//!
43//! [`Timestamp::round_down`]: Timestamp::round_down()
44
45use std::fmt;
46
47#[cfg(test)]
48use quickcheck::{Arbitrary, Gen};
49
50mod bitfield;
51pub use bitfield::Bitfield;
52mod compression_level;
53pub use compression_level::CompressionLevel;
54mod features;
55pub use self::features::Features;
56mod key_flags;
57pub use self::key_flags::KeyFlags;
58mod revocation_key;
59pub use revocation_key::RevocationKey;
60mod server_preferences;
61pub use self::server_preferences::KeyServerPreferences;
62mod timestamp;
63pub use timestamp::{Timestamp, Duration};
64pub(crate) use timestamp::normalize_systemtime;
65
66#[allow(dead_code)] // Used in assert_send_and_sync.
67pub(crate) trait Sendable : Send {}
68#[allow(dead_code)] // Used in assert_send_and_sync.
69pub(crate) trait Syncable : Sync {}
70
71pub use crate::crypto::AEADAlgorithm;
72pub use crate::crypto::Curve;
73pub use crate::crypto::HashAlgorithm;
74pub use crate::crypto::PublicKeyAlgorithm;
75pub use crate::crypto::SymmetricAlgorithm;
76
77/// The OpenPGP compression algorithms as defined in [Section 9.4 of RFC 9580].
78///
79///   [Section 9.4 of RFC 9580]: https://www.rfc-editor.org/rfc/rfc9580.html#section-9.4
80///
81/// # Examples
82///
83/// Use `CompressionAlgorithm` to set the preferred compressions algorithms on
84/// a signature:
85///
86/// ```rust
87/// use sequoia_openpgp as openpgp;
88/// use openpgp::packet::signature::SignatureBuilder;
89/// use openpgp::types::{HashAlgorithm, CompressionAlgorithm, SignatureType};
90///
91/// # fn main() -> openpgp::Result<()> {
92/// let mut builder = SignatureBuilder::new(SignatureType::DirectKey)
93///     .set_hash_algo(HashAlgorithm::SHA512)
94///     .set_preferred_compression_algorithms(vec![
95///         CompressionAlgorithm::Zlib,
96///         CompressionAlgorithm::BZip2,
97///     ])?;
98/// # Ok(()) }
99#[non_exhaustive]
100#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug, PartialOrd, Ord)]
101pub enum CompressionAlgorithm {
102    /// Null compression.
103    Uncompressed,
104    /// DEFLATE Compressed Data.
105    ///
106    /// See [RFC 1951] for details.  [Section 9.4 of RFC 9580]
107    /// recommends that this algorithm should be implemented.
108    ///
109    /// [RFC 1951]: https://tools.ietf.org/html/rfc1951
110    /// [Section 9.4 of RFC 9580]: https://www.rfc-editor.org/rfc/rfc9580.html#section-9.4
111    Zip,
112    /// ZLIB Compressed Data.
113    ///
114    /// See [RFC 1950] for details.
115    ///
116    /// [RFC 1950]: https://tools.ietf.org/html/rfc1950
117    Zlib,
118    /// bzip2
119    BZip2,
120    /// Private compression algorithm identifier.
121    Private(u8),
122    /// Unknown compression algorithm identifier.
123    Unknown(u8),
124}
125assert_send_and_sync!(CompressionAlgorithm);
126
127const COMPRESSION_ALGORITHM_VARIANTS: [CompressionAlgorithm; 4] = [
128    CompressionAlgorithm::Uncompressed,
129    CompressionAlgorithm::Zip,
130    CompressionAlgorithm::Zlib,
131    CompressionAlgorithm::BZip2,
132];
133
134impl Default for CompressionAlgorithm {
135    fn default() -> Self {
136        use self::CompressionAlgorithm::*;
137        #[cfg(feature = "compression-deflate")]
138        { Zip }
139        #[cfg(all(feature = "compression-bzip2",
140                  not(feature = "compression-deflate")))]
141        { BZip2 }
142        #[cfg(all(not(feature = "compression-bzip2"),
143                  not(feature = "compression-deflate")))]
144        { Uncompressed }
145    }
146}
147
148impl CompressionAlgorithm {
149    /// Returns whether this algorithm is supported.
150    ///
151    /// # Examples
152    ///
153    /// ```rust
154    /// use sequoia_openpgp as openpgp;
155    /// use openpgp::types::CompressionAlgorithm;
156    ///
157    /// assert!(CompressionAlgorithm::Uncompressed.is_supported());
158    ///
159    /// assert!(!CompressionAlgorithm::Private(101).is_supported());
160    /// ```
161    pub fn is_supported(&self) -> bool {
162        use self::CompressionAlgorithm::*;
163        match &self {
164            Uncompressed => true,
165            #[cfg(feature = "compression-deflate")]
166            Zip | Zlib => true,
167            #[cfg(feature = "compression-bzip2")]
168            BZip2 => true,
169            _ => false,
170        }
171    }
172
173    /// Returns an iterator over all valid variants.
174    ///
175    /// Returns an iterator over all known variants.  This does not
176    /// include the [`CompressionAlgorithm::Private`], or
177    /// [`CompressionAlgorithm::Unknown`] variants.
178    pub fn variants() -> impl Iterator<Item=Self> {
179        COMPRESSION_ALGORITHM_VARIANTS.iter().cloned()
180    }
181}
182
183impl From<u8> for CompressionAlgorithm {
184    fn from(u: u8) -> Self {
185        match u {
186            0 => CompressionAlgorithm::Uncompressed,
187            1 => CompressionAlgorithm::Zip,
188            2 => CompressionAlgorithm::Zlib,
189            3 => CompressionAlgorithm::BZip2,
190            100..=110 => CompressionAlgorithm::Private(u),
191            u => CompressionAlgorithm::Unknown(u),
192        }
193    }
194}
195
196impl From<CompressionAlgorithm> for u8 {
197    fn from(c: CompressionAlgorithm) -> u8 {
198        match c {
199            CompressionAlgorithm::Uncompressed => 0,
200            CompressionAlgorithm::Zip => 1,
201            CompressionAlgorithm::Zlib => 2,
202            CompressionAlgorithm::BZip2 => 3,
203            CompressionAlgorithm::Private(u) => u,
204            CompressionAlgorithm::Unknown(u) => u,
205        }
206    }
207}
208
209impl fmt::Display for CompressionAlgorithm {
210    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
211        match *self {
212            CompressionAlgorithm::Uncompressed => f.write_str("Uncompressed"),
213            CompressionAlgorithm::Zip => f.write_str("ZIP"),
214            CompressionAlgorithm::Zlib => f.write_str("ZLIB"),
215            CompressionAlgorithm::BZip2 => f.write_str("BZip2"),
216            CompressionAlgorithm::Private(u) =>
217                f.write_fmt(format_args!("Private/Experimental compression algorithm {}", u)),
218            CompressionAlgorithm::Unknown(u) =>
219                f.write_fmt(format_args!("Unknown compression algorithm {}", u)),
220        }
221    }
222}
223
224#[cfg(test)]
225impl Arbitrary for CompressionAlgorithm {
226    fn arbitrary(g: &mut Gen) -> Self {
227        u8::arbitrary(g).into()
228    }
229}
230
231/// Signature type as defined in [Section 5.2.1 of RFC 9580].
232///
233///   [Section 5.2.1 of RFC 9580]: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.1
234///
235/// # Examples
236///
237/// Use `SignatureType` to create a timestamp signature:
238///
239/// ```rust
240/// use sequoia_openpgp as openpgp;
241/// use std::time::SystemTime;
242/// use openpgp::packet::signature::SignatureBuilder;
243/// use openpgp::types::SignatureType;
244///
245/// # fn main() -> openpgp::Result<()> {
246/// let mut builder = SignatureBuilder::new(SignatureType::Timestamp)
247///     .set_signature_creation_time(SystemTime::now())?;
248/// # Ok(()) }
249/// ```
250#[non_exhaustive]
251#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)]
252pub enum SignatureType {
253    /// Signature over a binary document.
254    Binary,
255    /// Signature over a canonical text document.
256    Text,
257    /// Standalone signature.
258    Standalone,
259
260    /// Generic certification of a User ID and Public-Key packet.
261    GenericCertification,
262    /// Persona certification of a User ID and Public-Key packet.
263    PersonaCertification,
264    /// Casual certification of a User ID and Public-Key packet.
265    CasualCertification,
266    /// Positive certification of a User ID and Public-Key packet.
267    PositiveCertification,
268
269    /// Certification Approval Key Signature (experimental).
270    ///
271    /// Allows the certificate owner to attest to third party
272    /// certifications. See [Certification Approval Key Signature] for
273    /// details.
274    ///
275    ///   [Certification Approval Key Signature]: https://www.ietf.org/archive/id/draft-dkg-openpgp-1pa3pc-02.html#name-certification-approval-key-
276    CertificationApproval,
277
278    /// Subkey Binding Signature
279    SubkeyBinding,
280    /// Primary Key Binding Signature
281    PrimaryKeyBinding,
282    /// Signature directly on a key
283    DirectKey,
284
285    /// Key revocation signature
286    KeyRevocation,
287    /// Subkey revocation signature
288    SubkeyRevocation,
289    /// Certification revocation signature
290    CertificationRevocation,
291
292    /// Timestamp signature.
293    Timestamp,
294    /// Third-Party Confirmation signature.
295    Confirmation,
296
297    /// Catchall.
298    Unknown(u8),
299}
300assert_send_and_sync!(SignatureType);
301
302const SIGNATURE_TYPE_VARIANTS: [SignatureType; 16] = [
303    SignatureType::Binary,
304    SignatureType::Text,
305    SignatureType::Standalone,
306    SignatureType::GenericCertification,
307    SignatureType::PersonaCertification,
308    SignatureType::CasualCertification,
309    SignatureType::PositiveCertification,
310    SignatureType::CertificationApproval,
311    SignatureType::SubkeyBinding,
312    SignatureType::PrimaryKeyBinding,
313    SignatureType::DirectKey,
314    SignatureType::KeyRevocation,
315    SignatureType::SubkeyRevocation,
316    SignatureType::CertificationRevocation,
317    SignatureType::Timestamp,
318    SignatureType::Confirmation,
319];
320
321impl From<u8> for SignatureType {
322    fn from(u: u8) -> Self {
323        match u {
324            0x00 => SignatureType::Binary,
325            0x01 => SignatureType::Text,
326            0x02 => SignatureType::Standalone,
327            0x10 => SignatureType::GenericCertification,
328            0x11 => SignatureType::PersonaCertification,
329            0x12 => SignatureType::CasualCertification,
330            0x13 => SignatureType::PositiveCertification,
331            0x16 => SignatureType::CertificationApproval,
332            0x18 => SignatureType::SubkeyBinding,
333            0x19 => SignatureType::PrimaryKeyBinding,
334            0x1f => SignatureType::DirectKey,
335            0x20 => SignatureType::KeyRevocation,
336            0x28 => SignatureType::SubkeyRevocation,
337            0x30 => SignatureType::CertificationRevocation,
338            0x40 => SignatureType::Timestamp,
339            0x50 => SignatureType::Confirmation,
340            _ => SignatureType::Unknown(u),
341        }
342    }
343}
344
345impl From<SignatureType> for u8 {
346    fn from(t: SignatureType) -> Self {
347        match t {
348            SignatureType::Binary => 0x00,
349            SignatureType::Text => 0x01,
350            SignatureType::Standalone => 0x02,
351            SignatureType::GenericCertification => 0x10,
352            SignatureType::PersonaCertification => 0x11,
353            SignatureType::CasualCertification => 0x12,
354            SignatureType::PositiveCertification => 0x13,
355            SignatureType::CertificationApproval => 0x16,
356            SignatureType::SubkeyBinding => 0x18,
357            SignatureType::PrimaryKeyBinding => 0x19,
358            SignatureType::DirectKey => 0x1f,
359            SignatureType::KeyRevocation => 0x20,
360            SignatureType::SubkeyRevocation => 0x28,
361            SignatureType::CertificationRevocation => 0x30,
362            SignatureType::Timestamp => 0x40,
363            SignatureType::Confirmation => 0x50,
364            SignatureType::Unknown(u) => u,
365        }
366    }
367}
368
369impl fmt::Display for SignatureType {
370    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
371        match *self {
372            SignatureType::Binary =>
373                f.write_str("Binary"),
374            SignatureType::Text =>
375                f.write_str("Text"),
376            SignatureType::Standalone =>
377                f.write_str("Standalone"),
378            SignatureType::GenericCertification =>
379                f.write_str("GenericCertification"),
380            SignatureType::PersonaCertification =>
381                f.write_str("PersonaCertification"),
382            SignatureType::CasualCertification =>
383                f.write_str("CasualCertification"),
384            SignatureType::PositiveCertification =>
385                f.write_str("PositiveCertification"),
386            SignatureType::CertificationApproval =>
387                f.write_str("CertificationApproval"),
388            SignatureType::SubkeyBinding =>
389                f.write_str("SubkeyBinding"),
390            SignatureType::PrimaryKeyBinding =>
391                f.write_str("PrimaryKeyBinding"),
392            SignatureType::DirectKey =>
393                f.write_str("DirectKey"),
394            SignatureType::KeyRevocation =>
395                f.write_str("KeyRevocation"),
396            SignatureType::SubkeyRevocation =>
397                f.write_str("SubkeyRevocation"),
398            SignatureType::CertificationRevocation =>
399                f.write_str("CertificationRevocation"),
400            SignatureType::Timestamp =>
401                f.write_str("Timestamp"),
402            SignatureType::Confirmation =>
403                f.write_str("Confirmation"),
404            SignatureType::Unknown(u) =>
405                f.write_fmt(format_args!("Unknown signature type 0x{:x}", u)),
406        }
407    }
408}
409
410#[cfg(test)]
411impl Arbitrary for SignatureType {
412    fn arbitrary(g: &mut Gen) -> Self {
413        u8::arbitrary(g).into()
414    }
415}
416
417impl SignatureType {
418    /// Returns an iterator over all valid variants.
419    ///
420    /// Returns an iterator over all known variants.  This does not
421    /// include the [`SignatureType::Unknown`] variants.
422    pub fn variants() -> impl Iterator<Item=Self> {
423        SIGNATURE_TYPE_VARIANTS.iter().cloned()
424    }
425}
426
427/// Describes the reason for a revocation.
428///
429/// See the description of revocation subpackets [Section 5.2.3.31 of RFC 9580].
430///
431///   [Section 5.2.3.31 of RFC 9580]: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.31
432///
433/// # Examples
434///
435/// ```rust
436/// use sequoia_openpgp as openpgp;
437/// use openpgp::cert::prelude::*;
438/// use openpgp::policy::StandardPolicy;
439/// use openpgp::types::{RevocationStatus, ReasonForRevocation, SignatureType};
440///
441/// # fn main() -> openpgp::Result<()> {
442/// let p = &StandardPolicy::new();
443///
444/// // A certificate with a User ID.
445/// let (cert, _) = CertBuilder::new()
446///     .add_userid("Alice <alice@example.org>")
447///     .generate()?;
448///
449/// let mut keypair = cert.primary_key().key().clone()
450///     .parts_into_secret()?.into_keypair()?;
451/// let ca = cert.userids().nth(0).unwrap();
452///
453/// // Generate the revocation for the first and only UserID.
454/// let revocation =
455///     UserIDRevocationBuilder::new()
456///     .set_reason_for_revocation(
457///         ReasonForRevocation::UIDRetired,
458///         b"Left example.org.")?
459///     .build(&mut keypair, &cert, ca.userid(), None)?;
460/// assert_eq!(revocation.typ(), SignatureType::CertificationRevocation);
461///
462/// // Now merge the revocation signature into the Cert.
463/// let cert = cert.insert_packets(revocation.clone())?;
464///
465/// // Check that it is revoked.
466/// let ca = cert.0.userids().nth(0).unwrap();
467/// let status = ca.with_policy(p, None)?.revocation_status();
468/// if let RevocationStatus::Revoked(revs) = status {
469///     assert_eq!(revs.len(), 1);
470///     let rev = revs[0];
471///
472///     assert_eq!(rev.typ(), SignatureType::CertificationRevocation);
473///     assert_eq!(rev.reason_for_revocation(),
474///                Some((ReasonForRevocation::UIDRetired,
475///                      "Left example.org.".as_bytes())));
476///    // User ID has been revoked.
477/// }
478/// # else { unreachable!(); }
479/// # Ok(()) }
480/// ```
481#[non_exhaustive]
482#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug, PartialOrd, Ord)]
483pub enum ReasonForRevocation {
484    /// No reason specified (key revocations or cert revocations)
485    Unspecified,
486
487    /// Key is superseded (key revocations)
488    KeySuperseded,
489
490    /// Key material has been compromised (key revocations)
491    KeyCompromised,
492
493    /// Key is retired and no longer used (key revocations)
494    KeyRetired,
495
496    /// User ID information is no longer valid (cert revocations)
497    UIDRetired,
498
499    /// Private reason identifier.
500    Private(u8),
501
502    /// Unknown reason identifier.
503    Unknown(u8),
504}
505assert_send_and_sync!(ReasonForRevocation);
506
507const REASON_FOR_REVOCATION_VARIANTS: [ReasonForRevocation; 5] = [
508    ReasonForRevocation::Unspecified,
509    ReasonForRevocation::KeySuperseded,
510    ReasonForRevocation::KeyCompromised,
511    ReasonForRevocation::KeyRetired,
512    ReasonForRevocation::UIDRetired,
513];
514
515impl From<u8> for ReasonForRevocation {
516    fn from(u: u8) -> Self {
517        use self::ReasonForRevocation::*;
518        match u {
519            0 => Unspecified,
520            1 => KeySuperseded,
521            2 => KeyCompromised,
522            3 => KeyRetired,
523            32 => UIDRetired,
524            100..=110 => Private(u),
525            u => Unknown(u),
526        }
527    }
528}
529
530impl From<ReasonForRevocation> for u8 {
531    fn from(r: ReasonForRevocation) -> u8 {
532        use self::ReasonForRevocation::*;
533        match r {
534            Unspecified => 0,
535            KeySuperseded => 1,
536            KeyCompromised => 2,
537            KeyRetired => 3,
538            UIDRetired => 32,
539            Private(u) => u,
540            Unknown(u) => u,
541        }
542    }
543}
544
545impl fmt::Display for ReasonForRevocation {
546    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
547        use self::ReasonForRevocation::*;
548        match *self {
549            Unspecified =>
550                f.write_str("No reason specified"),
551            KeySuperseded =>
552                f.write_str("Key is superseded"),
553            KeyCompromised =>
554                f.write_str("Key material has been compromised"),
555            KeyRetired =>
556                f.write_str("Key is retired and no longer used"),
557            UIDRetired =>
558                f.write_str("User ID information is no longer valid"),
559            Private(u) =>
560                f.write_fmt(format_args!(
561                    "Private/Experimental revocation reason {}", u)),
562            Unknown(u) =>
563                f.write_fmt(format_args!(
564                    "Unknown revocation reason {}", u)),
565        }
566    }
567}
568
569#[cfg(test)]
570impl Arbitrary for ReasonForRevocation {
571    fn arbitrary(g: &mut Gen) -> Self {
572        u8::arbitrary(g).into()
573    }
574}
575
576/// Describes whether a `ReasonForRevocation` should be consider hard
577/// or soft.
578///
579/// A hard revocation is a revocation that indicates that the key was
580/// somehow compromised, and the provenance of *all* artifacts should
581/// be called into question.
582///
583/// A soft revocation is a revocation that indicates that the key
584/// should be considered invalid *after* the revocation signature's
585/// creation time.  `KeySuperseded`, `KeyRetired`, and `UIDRetired`
586/// are considered soft revocations.
587///
588/// # Examples
589///
590/// A certificate is considered to be revoked when a hard revocation is present
591/// even if it is not live at the specified time.
592///
593/// Here, a certificate is generated at `t0` and then revoked later at `t2`.
594/// At `t1` (`t0` < `t1` < `t2`) depending on the revocation type it will be
595/// either considered revoked (hard revocation) or not revoked (soft revocation):
596///
597/// ```rust
598/// # use sequoia_openpgp as openpgp;
599/// use std::time::{Duration, SystemTime};
600/// use openpgp::cert::prelude::*;
601/// use openpgp::types::{RevocationStatus, ReasonForRevocation};
602/// use openpgp::policy::StandardPolicy;
603///
604/// # fn main() -> openpgp::Result<()> {
605/// let p = &StandardPolicy::new();
606///
607/// let t0 = SystemTime::now();
608/// let (cert, _) =
609///     CertBuilder::general_purpose(Some("alice@example.org"))
610///     .set_creation_time(t0)
611///     .generate()?;
612///
613/// let t2 = t0 + Duration::from_secs(3600);
614///
615/// let mut signer = cert.primary_key().key().clone()
616///     .parts_into_secret()?.into_keypair()?;
617///
618/// // Create a hard revocation (KeyCompromised):
619/// let sig = CertRevocationBuilder::new()
620///     .set_reason_for_revocation(ReasonForRevocation::KeyCompromised,
621///                                b"The butler did it :/")?
622///     .set_signature_creation_time(t2)?
623///     .build(&mut signer, &cert, None)?;
624///
625/// let t1 = t0 + Duration::from_secs(1200);
626/// let cert1 = cert.clone().insert_packets(sig.clone())?.0;
627/// assert_eq!(cert1.revocation_status(p, Some(t1)),
628///            RevocationStatus::Revoked(vec![&sig.into()]));
629///
630/// // Create a soft revocation (KeySuperseded):
631/// let sig = CertRevocationBuilder::new()
632///     .set_reason_for_revocation(ReasonForRevocation::KeySuperseded,
633///                                b"Migrated to key XYZ")?
634///     .set_signature_creation_time(t2)?
635///     .build(&mut signer, &cert, None)?;
636///
637/// let t1 = t0 + Duration::from_secs(1200);
638/// let cert2 = cert.clone().insert_packets(sig.clone())?.0;
639/// assert_eq!(cert2.revocation_status(p, Some(t1)),
640///            RevocationStatus::NotAsFarAsWeKnow);
641/// #     Ok(())
642/// # }
643/// ```
644#[derive(Clone, Copy, Debug, PartialEq, Eq)]
645pub enum RevocationType {
646    /// A hard revocation.
647    ///
648    /// Artifacts stemming from the revoked object should not be
649    /// trusted.
650    Hard,
651    /// A soft revocation.
652    ///
653    /// Artifacts stemming from the revoked object *after* the
654    /// revocation time should not be trusted.  Earlier objects should
655    /// be considered okay.
656    ///
657    /// Only `KeySuperseded`, `KeyRetired`, and `UIDRetired` are
658    /// considered soft revocations.  All other reasons for
659    /// revocations including unknown reasons are considered hard
660    /// revocations.
661    Soft,
662}
663assert_send_and_sync!(RevocationType);
664
665impl ReasonForRevocation {
666    /// Returns the revocation's `RevocationType`.
667    ///
668    /// # Examples
669    ///
670    /// ```rust
671    /// use sequoia_openpgp as openpgp;
672    /// use openpgp::types::{ReasonForRevocation, RevocationType};
673    ///
674    /// assert_eq!(ReasonForRevocation::KeyCompromised.revocation_type(), RevocationType::Hard);
675    /// assert_eq!(ReasonForRevocation::Private(101).revocation_type(), RevocationType::Hard);
676    ///
677    /// assert_eq!(ReasonForRevocation::KeyRetired.revocation_type(), RevocationType::Soft);
678    /// ```
679    pub fn revocation_type(&self) -> RevocationType {
680        match self {
681            ReasonForRevocation::Unspecified => RevocationType::Hard,
682            ReasonForRevocation::KeySuperseded => RevocationType::Soft,
683            ReasonForRevocation::KeyCompromised => RevocationType::Hard,
684            ReasonForRevocation::KeyRetired => RevocationType::Soft,
685            ReasonForRevocation::UIDRetired => RevocationType::Soft,
686            ReasonForRevocation::Private(_) => RevocationType::Hard,
687            ReasonForRevocation::Unknown(_) => RevocationType::Hard,
688        }
689    }
690
691    /// Returns an iterator over all valid variants.
692    ///
693    /// Returns an iterator over all known variants.  This does not
694    /// include the [`ReasonForRevocation::Private`] or
695    /// [`ReasonForRevocation::Unknown`] variants.
696    pub fn variants() -> impl Iterator<Item=Self> {
697        REASON_FOR_REVOCATION_VARIANTS.iter().cloned()
698    }
699}
700
701/// Describes the format of the body of a literal data packet.
702///
703/// See the description of literal data packets [Section 5.9 of RFC 9580].
704///
705///   [Section 5.9 of RFC 9580]: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.9
706///
707/// # Examples
708///
709/// Construct a new [`Message`] containing one text literal packet:
710///
711/// [`Message`]: crate::Message
712///
713/// ```rust
714/// use sequoia_openpgp as openpgp;
715/// use std::convert::TryFrom;
716/// use openpgp::packet::prelude::*;
717/// use openpgp::types::DataFormat;
718/// use openpgp::message::Message;
719///
720/// let mut packets = Vec::new();
721/// let mut lit = Literal::new(DataFormat::Unicode);
722/// lit.set_body(b"data".to_vec());
723/// packets.push(lit.into());
724///
725/// let message = Message::try_from(packets);
726/// assert!(message.is_ok(), "{:?}", message);
727/// ```
728#[non_exhaustive]
729#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug, PartialOrd, Ord)]
730pub enum DataFormat {
731    /// Binary data.
732    ///
733    /// This is a hint that the content is probably binary data.
734    Binary,
735
736    /// Text data, probably valid UTF-8.
737    ///
738    /// This is a hint that the content is probably UTF-8 encoded.
739    Unicode,
740
741    /// Text data.
742    ///
743    /// This is a hint that the content is probably text; the encoding
744    /// is not specified.
745    #[deprecated(note = "Use Dataformat::Unicode instead.")]
746    Text,
747
748    /// Unknown format specifier.
749    Unknown(u8),
750}
751assert_send_and_sync!(DataFormat);
752
753#[allow(deprecated)]
754const DATA_FORMAT_VARIANTS: [DataFormat; 3] = [
755    DataFormat::Binary,
756    DataFormat::Text,
757    DataFormat::Unicode,
758];
759
760impl Default for DataFormat {
761    fn default() -> Self {
762        DataFormat::Binary
763    }
764}
765
766impl From<u8> for DataFormat {
767    fn from(u: u8) -> Self {
768        #[allow(deprecated)]
769        match u {
770            b'b' => DataFormat::Binary,
771            b'u' => DataFormat::Unicode,
772            b't' => DataFormat::Text,
773            _ => DataFormat::Unknown(u),
774        }
775    }
776}
777
778impl From<DataFormat> for u8 {
779    fn from(f: DataFormat) -> u8 {
780        use self::DataFormat::*;
781        match f {
782            Binary => b'b',
783            Unicode => b'u',
784            #[allow(deprecated)]
785            Text => b't',
786            Unknown(c) => c,
787        }
788    }
789}
790
791impl fmt::Display for DataFormat {
792    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
793        use self::DataFormat::*;
794        match *self {
795            Binary =>
796                f.write_str("Binary data"),
797            #[allow(deprecated)]
798            Text =>
799                f.write_str("Text data"),
800            Unicode =>
801                f.write_str("Text data (UTF-8)"),
802            Unknown(c) =>
803                f.write_fmt(format_args!(
804                    "Unknown data format identifier {:?}", c)),
805        }
806    }
807}
808
809#[cfg(test)]
810impl Arbitrary for DataFormat {
811    fn arbitrary(g: &mut Gen) -> Self {
812        u8::arbitrary(g).into()
813    }
814}
815
816impl DataFormat {
817    /// Returns an iterator over all valid variants.
818    ///
819    /// Returns an iterator over all known variants.  This does not
820    /// include the [`DataFormat::Unknown`] variants.
821    pub fn variants() -> impl Iterator<Item=Self> {
822        DATA_FORMAT_VARIANTS.iter().cloned()
823    }
824}
825
826/// The revocation status.
827///
828/// # Examples
829///
830/// Generates a new certificate then checks if the User ID is revoked or not under
831/// the given policy using [`ValidUserIDAmalgamation`]:
832///
833/// [`ValidUserIDAmalgamation`]: crate::cert::amalgamation::ValidUserIDAmalgamation
834///
835/// ```rust
836/// use sequoia_openpgp as openpgp;
837/// use openpgp::cert::prelude::*;
838/// use openpgp::policy::StandardPolicy;
839/// use openpgp::types::RevocationStatus;
840///
841/// # fn main() -> openpgp::Result<()> {
842/// let p = &StandardPolicy::new();
843///
844/// let (cert, _) =
845///     CertBuilder::general_purpose(Some("alice@example.org"))
846///     .generate()?;
847/// let cert = cert.with_policy(p, None)?;
848/// let ua = cert.userids().nth(0).expect("User IDs");
849///
850/// match ua.revocation_status() {
851///     RevocationStatus::Revoked(revs) => {
852///         // The certificate holder revoked the User ID.
853/// #       unreachable!();
854///     }
855///     RevocationStatus::CouldBe(revs) => {
856///         // There are third-party revocations.  You still need
857///         // to check that they are valid (this is necessary,
858///         // because without the Certificates are not normally
859///         // available to Sequoia).
860/// #       unreachable!();
861///     }
862///     RevocationStatus::NotAsFarAsWeKnow => {
863///         // We have no evidence that the User ID is revoked.
864///     }
865/// }
866/// #     Ok(())
867/// # }
868/// ```
869#[derive(Debug, Clone, PartialEq, Eq)]
870pub enum RevocationStatus<'a> {
871    /// The key is definitely revoked.
872    ///
873    /// The relevant self-revocations are returned.
874    Revoked(Vec<&'a crate::packet::Signature>),
875    /// There is a revocation certificate from a possible designated
876    /// revoker.
877    CouldBe(Vec<&'a crate::packet::Signature>),
878    /// The key does not appear to be revoked.
879    ///
880    /// An attacker could still have performed a DoS, which prevents
881    /// us from seeing the revocation certificate.
882    NotAsFarAsWeKnow,
883}
884assert_send_and_sync!(RevocationStatus<'_>);
885
886#[cfg(test)]
887mod tests {
888    use super::*;
889
890    quickcheck! {
891        fn comp_roundtrip(comp: CompressionAlgorithm) -> bool {
892            let val: u8 = comp.into();
893            comp == CompressionAlgorithm::from(val)
894        }
895    }
896
897    quickcheck! {
898        fn comp_display(comp: CompressionAlgorithm) -> bool {
899            let s = format!("{}", comp);
900            !s.is_empty()
901        }
902    }
903
904    quickcheck! {
905        fn comp_parse(comp: CompressionAlgorithm) -> bool {
906            match comp {
907                CompressionAlgorithm::Unknown(u) => u > 110 || (u > 3 && u < 100),
908                CompressionAlgorithm::Private(u) => (100..=110).contains(&u),
909                _ => true
910            }
911        }
912    }
913
914
915    quickcheck! {
916        fn signature_type_roundtrip(t: SignatureType) -> bool {
917            let val: u8 = t.into();
918            t == SignatureType::from(val)
919        }
920    }
921
922    quickcheck! {
923        fn signature_type_display(t: SignatureType) -> bool {
924            let s = format!("{}", t);
925            !s.is_empty()
926        }
927    }
928
929
930    quickcheck! {
931        fn rfr_roundtrip(rfr: ReasonForRevocation) -> bool {
932            let val: u8 = rfr.into();
933            rfr == ReasonForRevocation::from(val)
934        }
935    }
936
937    quickcheck! {
938        fn rfr_display(rfr: ReasonForRevocation) -> bool {
939            let s = format!("{}", rfr);
940            !s.is_empty()
941        }
942    }
943
944    quickcheck! {
945        fn rfr_parse(rfr: ReasonForRevocation) -> bool {
946            match rfr {
947                ReasonForRevocation::Unknown(u) =>
948                    (u > 3 && u < 32)
949                    || (u > 32 && u < 100)
950                    || u > 110,
951                ReasonForRevocation::Private(u) =>
952                    (100..=110).contains(&u),
953                _ => true
954            }
955        }
956    }
957
958    quickcheck! {
959        fn df_roundtrip(df: DataFormat) -> bool {
960            let val: u8 = df.into();
961            df == DataFormat::from(val)
962        }
963    }
964
965    quickcheck! {
966        fn df_display(df: DataFormat) -> bool {
967            let s = format!("{}", df);
968            !s.is_empty()
969        }
970    }
971
972    quickcheck! {
973        fn df_parse(df: DataFormat) -> bool {
974            match df {
975                DataFormat::Unknown(u) =>
976                    u != b'b' && u != b't' && u != b'u',
977                _ => true
978            }
979        }
980    }
981
982    #[test]
983    fn compression_algorithms_variants() {
984        use std::collections::HashSet;
985        use std::iter::FromIterator;
986
987        // COMPRESSION_ALGORITHM_VARIANTS is a list.  Derive it in a
988        // different way to double check that nothing is missing.
989        let derived_variants = (0..=u8::MAX)
990            .map(CompressionAlgorithm::from)
991            .filter(|t| {
992                match t {
993                    CompressionAlgorithm::Private(_) => false,
994                    CompressionAlgorithm::Unknown(_) => false,
995                    _ => true,
996                }
997            })
998            .collect::<HashSet<_>>();
999
1000        let known_variants
1001            = HashSet::from_iter(COMPRESSION_ALGORITHM_VARIANTS
1002                                 .iter().cloned());
1003
1004        let missing = known_variants
1005            .symmetric_difference(&derived_variants)
1006            .collect::<Vec<_>>();
1007
1008        assert!(missing.is_empty(), "{:?}", missing);
1009    }
1010
1011    #[test]
1012    fn signature_types_variants() {
1013        use std::collections::HashSet;
1014        use std::iter::FromIterator;
1015
1016        // SIGNATURE_TYPE_VARIANTS is a list.  Derive it in a
1017        // different way to double check that nothing is missing.
1018        let derived_variants = (0..=u8::MAX)
1019            .map(SignatureType::from)
1020            .filter(|t| {
1021                match t {
1022                    SignatureType::Unknown(_) => false,
1023                    _ => true,
1024                }
1025            })
1026            .collect::<HashSet<_>>();
1027
1028        let known_variants
1029            = HashSet::from_iter(SIGNATURE_TYPE_VARIANTS
1030                                 .iter().cloned());
1031
1032        let missing = known_variants
1033            .symmetric_difference(&derived_variants)
1034            .collect::<Vec<_>>();
1035
1036        assert!(missing.is_empty(), "{:?}", missing);
1037    }
1038
1039    #[test]
1040    fn reason_for_revocation_variants() {
1041        use std::collections::HashSet;
1042        use std::iter::FromIterator;
1043
1044        // REASON_FOR_REVOCATION_VARIANTS is a list.  Derive it in a
1045        // different way to double check that nothing is missing.
1046        let derived_variants = (0..=u8::MAX)
1047            .map(ReasonForRevocation::from)
1048            .filter(|t| {
1049                match t {
1050                    ReasonForRevocation::Private(_) => false,
1051                    ReasonForRevocation::Unknown(_) => false,
1052                    _ => true,
1053                }
1054            })
1055            .collect::<HashSet<_>>();
1056
1057        let known_variants
1058            = HashSet::from_iter(REASON_FOR_REVOCATION_VARIANTS
1059                                 .iter().cloned());
1060
1061        let missing = known_variants
1062            .symmetric_difference(&derived_variants)
1063            .collect::<Vec<_>>();
1064
1065        assert!(missing.is_empty(), "{:?}", missing);
1066    }
1067
1068    #[test]
1069    fn data_format_variants() {
1070        use std::collections::HashSet;
1071        use std::iter::FromIterator;
1072
1073        // DATA_FORMAT_VARIANTS is a list.  Derive it in a different
1074        // way to double check that nothing is missing.
1075        let derived_variants = (0..=u8::MAX)
1076            .map(DataFormat::from)
1077            .filter(|t| {
1078                match t {
1079                    DataFormat::Unknown(_) => false,
1080                    _ => true,
1081                }
1082            })
1083            .collect::<HashSet<_>>();
1084
1085        let known_variants
1086            = HashSet::from_iter(DATA_FORMAT_VARIANTS
1087                                 .iter().cloned());
1088
1089        let missing = known_variants
1090            .symmetric_difference(&derived_variants)
1091            .collect::<Vec<_>>();
1092
1093        assert!(missing.is_empty(), "{:?}", missing);
1094    }
1095}