Skip to main content

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