use std::fmt;
#[cfg(test)]
use quickcheck::{Arbitrary, Gen};
mod bitfield;
pub use bitfield::Bitfield;
mod compression_level;
pub use compression_level::CompressionLevel;
mod features;
pub use self::features::Features;
mod key_flags;
pub use self::key_flags::KeyFlags;
mod revocation_key;
pub use revocation_key::RevocationKey;
mod server_preferences;
pub use self::server_preferences::KeyServerPreferences;
mod timestamp;
pub use timestamp::{Timestamp, Duration};
pub(crate) use timestamp::normalize_systemtime;
#[allow(dead_code)] pub(crate) trait Sendable : Send {}
#[allow(dead_code)] pub(crate) trait Syncable : Sync {}
pub use crate::crypto::AEADAlgorithm;
pub use crate::crypto::Curve;
pub use crate::crypto::HashAlgorithm;
pub use crate::crypto::PublicKeyAlgorithm;
pub use crate::crypto::SymmetricAlgorithm;
#[non_exhaustive]
#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug, PartialOrd, Ord)]
pub enum CompressionAlgorithm {
Uncompressed,
Zip,
Zlib,
BZip2,
Private(u8),
Unknown(u8),
}
assert_send_and_sync!(CompressionAlgorithm);
const COMPRESSION_ALGORITHM_VARIANTS: [CompressionAlgorithm; 4] = [
CompressionAlgorithm::Uncompressed,
CompressionAlgorithm::Zip,
CompressionAlgorithm::Zlib,
CompressionAlgorithm::BZip2,
];
impl Default for CompressionAlgorithm {
fn default() -> Self {
use self::CompressionAlgorithm::*;
#[cfg(feature = "compression-deflate")]
{ Zip }
#[cfg(all(feature = "compression-bzip2",
not(feature = "compression-deflate")))]
{ BZip2 }
#[cfg(all(not(feature = "compression-bzip2"),
not(feature = "compression-deflate")))]
{ Uncompressed }
}
}
impl CompressionAlgorithm {
pub fn is_supported(&self) -> bool {
use self::CompressionAlgorithm::*;
match &self {
Uncompressed => true,
#[cfg(feature = "compression-deflate")]
Zip | Zlib => true,
#[cfg(feature = "compression-bzip2")]
BZip2 => true,
_ => false,
}
}
pub fn variants() -> impl Iterator<Item=Self> {
COMPRESSION_ALGORITHM_VARIANTS.iter().cloned()
}
}
impl From<u8> for CompressionAlgorithm {
fn from(u: u8) -> Self {
match u {
0 => CompressionAlgorithm::Uncompressed,
1 => CompressionAlgorithm::Zip,
2 => CompressionAlgorithm::Zlib,
3 => CompressionAlgorithm::BZip2,
100..=110 => CompressionAlgorithm::Private(u),
u => CompressionAlgorithm::Unknown(u),
}
}
}
impl From<CompressionAlgorithm> for u8 {
fn from(c: CompressionAlgorithm) -> u8 {
match c {
CompressionAlgorithm::Uncompressed => 0,
CompressionAlgorithm::Zip => 1,
CompressionAlgorithm::Zlib => 2,
CompressionAlgorithm::BZip2 => 3,
CompressionAlgorithm::Private(u) => u,
CompressionAlgorithm::Unknown(u) => u,
}
}
}
impl fmt::Display for CompressionAlgorithm {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
CompressionAlgorithm::Uncompressed => f.write_str("Uncompressed"),
CompressionAlgorithm::Zip => f.write_str("ZIP"),
CompressionAlgorithm::Zlib => f.write_str("ZLIB"),
CompressionAlgorithm::BZip2 => f.write_str("BZip2"),
CompressionAlgorithm::Private(u) =>
f.write_fmt(format_args!("Private/Experimental compression algorithm {}", u)),
CompressionAlgorithm::Unknown(u) =>
f.write_fmt(format_args!("Unknown compression algorithm {}", u)),
}
}
}
#[cfg(test)]
impl Arbitrary for CompressionAlgorithm {
fn arbitrary(g: &mut Gen) -> Self {
u8::arbitrary(g).into()
}
}
#[non_exhaustive]
#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub enum SignatureType {
Binary,
Text,
Standalone,
GenericCertification,
PersonaCertification,
CasualCertification,
PositiveCertification,
CertificationApproval,
SubkeyBinding,
PrimaryKeyBinding,
DirectKey,
KeyRevocation,
SubkeyRevocation,
CertificationRevocation,
Timestamp,
Confirmation,
Unknown(u8),
}
assert_send_and_sync!(SignatureType);
const SIGNATURE_TYPE_VARIANTS: [SignatureType; 16] = [
SignatureType::Binary,
SignatureType::Text,
SignatureType::Standalone,
SignatureType::GenericCertification,
SignatureType::PersonaCertification,
SignatureType::CasualCertification,
SignatureType::PositiveCertification,
SignatureType::CertificationApproval,
SignatureType::SubkeyBinding,
SignatureType::PrimaryKeyBinding,
SignatureType::DirectKey,
SignatureType::KeyRevocation,
SignatureType::SubkeyRevocation,
SignatureType::CertificationRevocation,
SignatureType::Timestamp,
SignatureType::Confirmation,
];
impl From<u8> for SignatureType {
fn from(u: u8) -> Self {
match u {
0x00 => SignatureType::Binary,
0x01 => SignatureType::Text,
0x02 => SignatureType::Standalone,
0x10 => SignatureType::GenericCertification,
0x11 => SignatureType::PersonaCertification,
0x12 => SignatureType::CasualCertification,
0x13 => SignatureType::PositiveCertification,
0x16 => SignatureType::CertificationApproval,
0x18 => SignatureType::SubkeyBinding,
0x19 => SignatureType::PrimaryKeyBinding,
0x1f => SignatureType::DirectKey,
0x20 => SignatureType::KeyRevocation,
0x28 => SignatureType::SubkeyRevocation,
0x30 => SignatureType::CertificationRevocation,
0x40 => SignatureType::Timestamp,
0x50 => SignatureType::Confirmation,
_ => SignatureType::Unknown(u),
}
}
}
impl From<SignatureType> for u8 {
fn from(t: SignatureType) -> Self {
match t {
SignatureType::Binary => 0x00,
SignatureType::Text => 0x01,
SignatureType::Standalone => 0x02,
SignatureType::GenericCertification => 0x10,
SignatureType::PersonaCertification => 0x11,
SignatureType::CasualCertification => 0x12,
SignatureType::PositiveCertification => 0x13,
SignatureType::CertificationApproval => 0x16,
SignatureType::SubkeyBinding => 0x18,
SignatureType::PrimaryKeyBinding => 0x19,
SignatureType::DirectKey => 0x1f,
SignatureType::KeyRevocation => 0x20,
SignatureType::SubkeyRevocation => 0x28,
SignatureType::CertificationRevocation => 0x30,
SignatureType::Timestamp => 0x40,
SignatureType::Confirmation => 0x50,
SignatureType::Unknown(u) => u,
}
}
}
impl fmt::Display for SignatureType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
SignatureType::Binary =>
f.write_str("Binary"),
SignatureType::Text =>
f.write_str("Text"),
SignatureType::Standalone =>
f.write_str("Standalone"),
SignatureType::GenericCertification =>
f.write_str("GenericCertification"),
SignatureType::PersonaCertification =>
f.write_str("PersonaCertification"),
SignatureType::CasualCertification =>
f.write_str("CasualCertification"),
SignatureType::PositiveCertification =>
f.write_str("PositiveCertification"),
SignatureType::CertificationApproval =>
f.write_str("CertificationApproval"),
SignatureType::SubkeyBinding =>
f.write_str("SubkeyBinding"),
SignatureType::PrimaryKeyBinding =>
f.write_str("PrimaryKeyBinding"),
SignatureType::DirectKey =>
f.write_str("DirectKey"),
SignatureType::KeyRevocation =>
f.write_str("KeyRevocation"),
SignatureType::SubkeyRevocation =>
f.write_str("SubkeyRevocation"),
SignatureType::CertificationRevocation =>
f.write_str("CertificationRevocation"),
SignatureType::Timestamp =>
f.write_str("Timestamp"),
SignatureType::Confirmation =>
f.write_str("Confirmation"),
SignatureType::Unknown(u) =>
f.write_fmt(format_args!("Unknown signature type 0x{:x}", u)),
}
}
}
#[cfg(test)]
impl Arbitrary for SignatureType {
fn arbitrary(g: &mut Gen) -> Self {
u8::arbitrary(g).into()
}
}
impl SignatureType {
pub fn variants() -> impl Iterator<Item=Self> {
SIGNATURE_TYPE_VARIANTS.iter().cloned()
}
}
#[non_exhaustive]
#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug, PartialOrd, Ord)]
pub enum ReasonForRevocation {
Unspecified,
KeySuperseded,
KeyCompromised,
KeyRetired,
UIDRetired,
Private(u8),
Unknown(u8),
}
assert_send_and_sync!(ReasonForRevocation);
const REASON_FOR_REVOCATION_VARIANTS: [ReasonForRevocation; 5] = [
ReasonForRevocation::Unspecified,
ReasonForRevocation::KeySuperseded,
ReasonForRevocation::KeyCompromised,
ReasonForRevocation::KeyRetired,
ReasonForRevocation::UIDRetired,
];
impl From<u8> for ReasonForRevocation {
fn from(u: u8) -> Self {
use self::ReasonForRevocation::*;
match u {
0 => Unspecified,
1 => KeySuperseded,
2 => KeyCompromised,
3 => KeyRetired,
32 => UIDRetired,
100..=110 => Private(u),
u => Unknown(u),
}
}
}
impl From<ReasonForRevocation> for u8 {
fn from(r: ReasonForRevocation) -> u8 {
use self::ReasonForRevocation::*;
match r {
Unspecified => 0,
KeySuperseded => 1,
KeyCompromised => 2,
KeyRetired => 3,
UIDRetired => 32,
Private(u) => u,
Unknown(u) => u,
}
}
}
impl fmt::Display for ReasonForRevocation {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::ReasonForRevocation::*;
match *self {
Unspecified =>
f.write_str("No reason specified"),
KeySuperseded =>
f.write_str("Key is superseded"),
KeyCompromised =>
f.write_str("Key material has been compromised"),
KeyRetired =>
f.write_str("Key is retired and no longer used"),
UIDRetired =>
f.write_str("User ID information is no longer valid"),
Private(u) =>
f.write_fmt(format_args!(
"Private/Experimental revocation reason {}", u)),
Unknown(u) =>
f.write_fmt(format_args!(
"Unknown revocation reason {}", u)),
}
}
}
#[cfg(test)]
impl Arbitrary for ReasonForRevocation {
fn arbitrary(g: &mut Gen) -> Self {
u8::arbitrary(g).into()
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum RevocationType {
Hard,
Soft,
}
assert_send_and_sync!(RevocationType);
impl ReasonForRevocation {
pub fn revocation_type(&self) -> RevocationType {
match self {
ReasonForRevocation::Unspecified => RevocationType::Hard,
ReasonForRevocation::KeySuperseded => RevocationType::Soft,
ReasonForRevocation::KeyCompromised => RevocationType::Hard,
ReasonForRevocation::KeyRetired => RevocationType::Soft,
ReasonForRevocation::UIDRetired => RevocationType::Soft,
ReasonForRevocation::Private(_) => RevocationType::Hard,
ReasonForRevocation::Unknown(_) => RevocationType::Hard,
}
}
pub fn variants() -> impl Iterator<Item=Self> {
REASON_FOR_REVOCATION_VARIANTS.iter().cloned()
}
}
#[non_exhaustive]
#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug, PartialOrd, Ord)]
pub enum DataFormat {
Binary,
Unicode,
#[deprecated(note = "Use Dataformat::Unicode instead.")]
Text,
Unknown(u8),
}
assert_send_and_sync!(DataFormat);
#[allow(deprecated)]
const DATA_FORMAT_VARIANTS: [DataFormat; 3] = [
DataFormat::Binary,
DataFormat::Text,
DataFormat::Unicode,
];
impl Default for DataFormat {
fn default() -> Self {
DataFormat::Binary
}
}
impl From<u8> for DataFormat {
fn from(u: u8) -> Self {
#[allow(deprecated)]
match u {
b'b' => DataFormat::Binary,
b'u' => DataFormat::Unicode,
b't' => DataFormat::Text,
_ => DataFormat::Unknown(u),
}
}
}
impl From<DataFormat> for u8 {
fn from(f: DataFormat) -> u8 {
use self::DataFormat::*;
match f {
Binary => b'b',
Unicode => b'u',
#[allow(deprecated)]
Text => b't',
Unknown(c) => c,
}
}
}
impl fmt::Display for DataFormat {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::DataFormat::*;
match *self {
Binary =>
f.write_str("Binary data"),
#[allow(deprecated)]
Text =>
f.write_str("Text data"),
Unicode =>
f.write_str("Text data (UTF-8)"),
Unknown(c) =>
f.write_fmt(format_args!(
"Unknown data format identifier {:?}", c)),
}
}
}
#[cfg(test)]
impl Arbitrary for DataFormat {
fn arbitrary(g: &mut Gen) -> Self {
u8::arbitrary(g).into()
}
}
impl DataFormat {
pub fn variants() -> impl Iterator<Item=Self> {
DATA_FORMAT_VARIANTS.iter().cloned()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum RevocationStatus<'a> {
Revoked(Vec<&'a crate::packet::Signature>),
CouldBe(Vec<&'a crate::packet::Signature>),
NotAsFarAsWeKnow,
}
assert_send_and_sync!(RevocationStatus<'_>);
#[cfg(test)]
mod tests {
use super::*;
quickcheck! {
fn comp_roundtrip(comp: CompressionAlgorithm) -> bool {
let val: u8 = comp.into();
comp == CompressionAlgorithm::from(val)
}
}
quickcheck! {
fn comp_display(comp: CompressionAlgorithm) -> bool {
let s = format!("{}", comp);
!s.is_empty()
}
}
quickcheck! {
fn comp_parse(comp: CompressionAlgorithm) -> bool {
match comp {
CompressionAlgorithm::Unknown(u) => u > 110 || (u > 3 && u < 100),
CompressionAlgorithm::Private(u) => (100..=110).contains(&u),
_ => true
}
}
}
quickcheck! {
fn signature_type_roundtrip(t: SignatureType) -> bool {
let val: u8 = t.into();
t == SignatureType::from(val)
}
}
quickcheck! {
fn signature_type_display(t: SignatureType) -> bool {
let s = format!("{}", t);
!s.is_empty()
}
}
quickcheck! {
fn rfr_roundtrip(rfr: ReasonForRevocation) -> bool {
let val: u8 = rfr.into();
rfr == ReasonForRevocation::from(val)
}
}
quickcheck! {
fn rfr_display(rfr: ReasonForRevocation) -> bool {
let s = format!("{}", rfr);
!s.is_empty()
}
}
quickcheck! {
fn rfr_parse(rfr: ReasonForRevocation) -> bool {
match rfr {
ReasonForRevocation::Unknown(u) =>
(u > 3 && u < 32)
|| (u > 32 && u < 100)
|| u > 110,
ReasonForRevocation::Private(u) =>
(100..=110).contains(&u),
_ => true
}
}
}
quickcheck! {
fn df_roundtrip(df: DataFormat) -> bool {
let val: u8 = df.into();
df == DataFormat::from(val)
}
}
quickcheck! {
fn df_display(df: DataFormat) -> bool {
let s = format!("{}", df);
!s.is_empty()
}
}
quickcheck! {
fn df_parse(df: DataFormat) -> bool {
match df {
DataFormat::Unknown(u) =>
u != b'b' && u != b't' && u != b'u',
_ => true
}
}
}
#[test]
fn compression_algorithms_variants() {
use std::collections::HashSet;
use std::iter::FromIterator;
let derived_variants = (0..=u8::MAX)
.map(CompressionAlgorithm::from)
.filter(|t| {
match t {
CompressionAlgorithm::Private(_) => false,
CompressionAlgorithm::Unknown(_) => false,
_ => true,
}
})
.collect::<HashSet<_>>();
let known_variants
= HashSet::from_iter(COMPRESSION_ALGORITHM_VARIANTS
.iter().cloned());
let missing = known_variants
.symmetric_difference(&derived_variants)
.collect::<Vec<_>>();
assert!(missing.is_empty(), "{:?}", missing);
}
#[test]
fn signature_types_variants() {
use std::collections::HashSet;
use std::iter::FromIterator;
let derived_variants = (0..=u8::MAX)
.map(SignatureType::from)
.filter(|t| {
match t {
SignatureType::Unknown(_) => false,
_ => true,
}
})
.collect::<HashSet<_>>();
let known_variants
= HashSet::from_iter(SIGNATURE_TYPE_VARIANTS
.iter().cloned());
let missing = known_variants
.symmetric_difference(&derived_variants)
.collect::<Vec<_>>();
assert!(missing.is_empty(), "{:?}", missing);
}
#[test]
fn reason_for_revocation_variants() {
use std::collections::HashSet;
use std::iter::FromIterator;
let derived_variants = (0..=u8::MAX)
.map(ReasonForRevocation::from)
.filter(|t| {
match t {
ReasonForRevocation::Private(_) => false,
ReasonForRevocation::Unknown(_) => false,
_ => true,
}
})
.collect::<HashSet<_>>();
let known_variants
= HashSet::from_iter(REASON_FOR_REVOCATION_VARIANTS
.iter().cloned());
let missing = known_variants
.symmetric_difference(&derived_variants)
.collect::<Vec<_>>();
assert!(missing.is_empty(), "{:?}", missing);
}
#[test]
fn data_format_variants() {
use std::collections::HashSet;
use std::iter::FromIterator;
let derived_variants = (0..=u8::MAX)
.map(DataFormat::from)
.filter(|t| {
match t {
DataFormat::Unknown(_) => false,
_ => true,
}
})
.collect::<HashSet<_>>();
let known_variants
= HashSet::from_iter(DATA_FORMAT_VARIANTS
.iter().cloned());
let missing = known_variants
.symmetric_difference(&derived_variants)
.collect::<Vec<_>>();
assert!(missing.is_empty(), "{:?}", missing);
}
}