summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2018-07-09 15:24:56 +0200
committerJustus Winter <justus@sequoia-pgp.org>2018-07-09 15:24:56 +0200
commitaef143f89e74f6b44f16561da2b6093f4166730b (patch)
treecfb2d446b355da5e843c8fd1f7cd4ca6b6fa09b4
parent627620533867cc136ebf4dfe4de8d087ffec803a (diff)
openpgp: Add and use a type specifying reasons for revocations.
-rw-r--r--openpgp/src/constants.rs117
-rw-r--r--openpgp/src/serialize/mod.rs2
-rw-r--r--openpgp/src/subpacket.rs22
3 files changed, 132 insertions, 9 deletions
diff --git a/openpgp/src/constants.rs b/openpgp/src/constants.rs
index ee7be8ee..bf41e428 100644
--- a/openpgp/src/constants.rs
+++ b/openpgp/src/constants.rs
@@ -664,6 +664,95 @@ impl Arbitrary for SignatureType {
}
}
+/// Describes the reason for a revocation.
+///
+/// See the description of revocation subpackets [Section 5.2.3.23 of RFC 4880].
+///
+/// [Section 5.2.3.23 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-5.2.3.23
+#[derive(Clone, Copy, PartialEq, Eq, Debug, PartialOrd, Ord)]
+pub enum ReasonForRevocation {
+ /// No reason specified (key revocations or cert revocations)
+ Unspecified,
+
+ /// Key is superseded (key revocations)
+ KeySuperseeded,
+
+ /// Key material has been compromised (key revocations)
+ KeyCompromised,
+
+ /// Key is retired and no longer used (key revocations)
+ KeyRetired,
+
+ /// User ID information is no longer valid (cert revocations)
+ UIDRetired,
+
+ /// Private reason identifier.
+ Private(u8),
+
+ /// Unknown reason identifier.
+ Unknown(u8),
+}
+
+impl From<u8> for ReasonForRevocation {
+ fn from(u: u8) -> Self {
+ use self::ReasonForRevocation::*;
+ match u {
+ 0 => Unspecified,
+ 1 => KeySuperseeded,
+ 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,
+ KeySuperseeded => 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"),
+ KeySuperseeded =>
+ 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)),
+ }
+ }
+}
+
+impl Arbitrary for ReasonForRevocation {
+ fn arbitrary<G: Gen>(g: &mut G) -> Self {
+ u8::arbitrary(g).into()
+ }
+}
+
#[cfg(test)]
mod tests {
use super::*;
@@ -805,4 +894,32 @@ mod tests {
}
}
}
+
+ quickcheck! {
+ fn rfr_roundtrip(rfr: ReasonForRevocation) -> bool {
+ let val: u8 = rfr.clone().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) =>
+ u >= 100 && u <= 110,
+ _ => true
+ }
+ }
+ }
}
diff --git a/openpgp/src/serialize/mod.rs b/openpgp/src/serialize/mod.rs
index 82c97347..039eacb1 100644
--- a/openpgp/src/serialize/mod.rs
+++ b/openpgp/src/serialize/mod.rs
@@ -464,7 +464,7 @@ impl<'a> Serialize for SubpacketValue<'a> {
SignersUserID(ref uid) =>
o.write_all(uid)?,
ReasonForRevocation { ref code, ref reason } => {
- o.write_all(&[*code])?;
+ o.write_all(&[(*code).into()])?;
o.write_all(reason)?;
},
Features(ref f) =>
diff --git a/openpgp/src/subpacket.rs b/openpgp/src/subpacket.rs
index 677eca49..c79d3965 100644
--- a/openpgp/src/subpacket.rs
+++ b/openpgp/src/subpacket.rs
@@ -77,6 +77,7 @@ use constants::{
CompressionAlgorithm,
HashAlgorithm,
PublicKeyAlgorithm,
+ ReasonForRevocation,
SymmetricAlgorithm,
};
use conversions::{
@@ -616,7 +617,7 @@ pub enum SubpacketValue<'a> {
/// 1 octet of revocation code, N octets of reason string
ReasonForRevocation {
/// Machine-readable reason for revocation.
- code: u8,
+ code: ReasonForRevocation,
/// Human-readable reason for revocation.
reason: &'a [u8],
@@ -937,7 +938,7 @@ impl<'a> From<SubpacketRaw<'a>> for Subpacket<'a> {
// 1 octet of revocation code, N octets of reason string
if raw.value.len() >= 1 {
Some(SubpacketValue::ReasonForRevocation {
- code: raw.value[0],
+ code: raw.value[0].into(),
reason: &raw.value[1..],
})
} else {
@@ -2190,7 +2191,8 @@ impl Signature {
///
/// Note: if the signature contains multiple instances of this
/// subpacket, only the last one is considered.
- pub fn reason_for_revocation(&self) -> Option<(u8, &[u8])> {
+ pub fn reason_for_revocation(&self)
+ -> Option<(ReasonForRevocation, &[u8])> {
// 1 octet of revocation code, N octets of reason string
if let Some(sb) = self.subpacket(SubpacketTag::ReasonForRevocation) {
if let SubpacketValue::ReasonForRevocation {
@@ -2206,7 +2208,8 @@ impl Signature {
}
/// Sets the value of the Reason for Revocation subpacket.
- pub fn set_reason_for_revocation(&mut self, code: u8, reason: &[u8])
+ pub fn set_reason_for_revocation(&mut self, code: ReasonForRevocation,
+ reason: &[u8])
-> Result<()> {
self.hashed_area.replace(Subpacket::new(
SubpacketValue::ReasonForRevocation {
@@ -2505,8 +2508,10 @@ fn accessors() {
sig.set_signers_user_id(b"foobar").unwrap();
assert_eq!(sig.signers_user_id(), Some(&b"foobar"[..]));
- sig.set_reason_for_revocation(3, b"foobar").unwrap();
- assert_eq!(sig.reason_for_revocation(), Some((3, &b"foobar"[..])));
+ sig.set_reason_for_revocation(ReasonForRevocation::KeyRetired,
+ b"foobar").unwrap();
+ assert_eq!(sig.reason_for_revocation(),
+ Some((ReasonForRevocation::KeyRetired, &b"foobar"[..])));
let feats = Features::default().set_mdc(true);
sig.set_features(&feats).unwrap();
@@ -2916,13 +2921,14 @@ fn subpacket_test_2() {
}));
assert_eq!(sig.reason_for_revocation(),
- Some((0, &b"Forgot to set a sig expiration."[..])));
+ Some((ReasonForRevocation::Unspecified,
+ &b"Forgot to set a sig expiration."[..])));
assert_eq!(sig.subpacket(SubpacketTag::ReasonForRevocation),
Some(Subpacket {
critical: false,
tag: SubpacketTag::ReasonForRevocation,
value: SubpacketValue::ReasonForRevocation {
- code: 0,
+ code: ReasonForRevocation::Unspecified,
reason: &b"Forgot to set a sig expiration."[..],
},
}));