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}