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}