summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2020-02-10 12:48:47 +0100
committerJustus Winter <justus@sequoia-pgp.org>2020-02-10 15:18:30 +0100
commit7eae54c9fff3062aa8f3a4c3011a8a7e6890d3e1 (patch)
treead72787ee58684554bb84f1a8da266b889827dc4
parent99202aa7cc79337aa0bcd2895c0a57b8fe2308da (diff)
openpgp: New type RevocationKey.
- See #431.
-rw-r--r--openpgp/src/cert/amalgamation.rs7
-rw-r--r--openpgp/src/packet/signature/subpacket.rs53
-rw-r--r--openpgp/src/parse/parse.rs13
-rw-r--r--openpgp/src/serialize/mod.rs27
-rw-r--r--openpgp/src/types/mod.rs2
-rw-r--r--openpgp/src/types/revocation_key.rs98
-rw-r--r--tool/src/commands/dump.rs11
7 files changed, 153 insertions, 58 deletions
diff --git a/openpgp/src/cert/amalgamation.rs b/openpgp/src/cert/amalgamation.rs
index 4db585f3..ce6a0849 100644
--- a/openpgp/src/cert/amalgamation.rs
+++ b/openpgp/src/cert/amalgamation.rs
@@ -6,14 +6,13 @@ use crate::{
Cert,
cert::components::ComponentBundle,
Error,
- Fingerprint,
packet::Signature,
Result,
RevocationStatus,
policy::Policy,
types::{
+ RevocationKey,
KeyFlags,
- PublicKeyAlgorithm,
},
};
@@ -358,9 +357,7 @@ pub trait Amalgamation<'a> {
/// 5.2.3.3 of RFC 4880].
///
/// [Section 5.2.3.3 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-5.2.3.3
- fn revocation_key(&self) -> Option<(u8,
- PublicKeyAlgorithm,
- Fingerprint)> {
+ fn revocation_key(&self) -> Option<&'a RevocationKey> {
self.map(|s| s.revocation_key())
}
}
diff --git a/openpgp/src/packet/signature/subpacket.rs b/openpgp/src/packet/signature/subpacket.rs
index c423a1f1..010795d1 100644
--- a/openpgp/src/packet/signature/subpacket.rs
+++ b/openpgp/src/packet/signature/subpacket.rs
@@ -89,6 +89,7 @@ use crate::types::{
KeyServerPreferences,
PublicKeyAlgorithm,
ReasonForRevocation,
+ RevocationKey,
SymmetricAlgorithm,
Timestamp,
};
@@ -633,19 +634,7 @@ pub enum SubpacketValue {
PreferredSymmetricAlgorithms(Vec<SymmetricAlgorithm>),
/// 1 octet of class, 1 octet of public-key algorithm ID, 20 octets of
/// fingerprint
- RevocationKey {
- /// Class octet must have bit 0x80 set. If the bit 0x40 is
- /// set, then this means that the revocation information is
- /// sensitive. Other bits are for future expansion to other
- /// kinds of authorizations.
- class: u8,
-
- /// XXX: RFC4880 says nothing about this.
- pk_algo: PublicKeyAlgorithm,
-
- /// Fingerprint of authorized key.
- fp: Fingerprint,
- },
+ RevocationKey(RevocationKey),
/// 8-octet Key ID
Issuer(KeyID),
/// The notation has a name and a value, each of
@@ -1103,16 +1092,10 @@ impl SubpacketArea {
///
/// Note: if the signature contains multiple instances of this
/// subpacket, only the last one is considered.
- pub fn revocation_key(&self) -> Option<(u8,
- PublicKeyAlgorithm,
- Fingerprint)> {
- // 1 octet of class, 1 octet of public-key algorithm ID, 20 or
- // 32 octets of fingerprint.
+ pub fn revocation_key(&self) -> Option<&RevocationKey> {
if let Some(sb) = self.subpacket(SubpacketTag::RevocationKey) {
- if let SubpacketValue::RevocationKey {
- class, pk_algo, fp,
- } = &sb.value {
- Some((*class, *pk_algo, fp.clone()))
+ if let SubpacketValue::RevocationKey(rk) = &sb.value {
+ Some(rk)
} else {
None
}
@@ -1962,14 +1945,9 @@ impl signature::Builder {
/// Sets the value of the Revocation Key subpacket, which contains
/// a designated revoker.
- pub fn set_revocation_key(mut self, class: u8, pk_algo: PublicKeyAlgorithm,
- fp: Fingerprint) -> Result<Self> {
+ pub fn set_revocation_key(mut self, rk: RevocationKey) -> Result<Self> {
self.hashed_area.replace(Subpacket::new(
- SubpacketValue::RevocationKey {
- class: class,
- pk_algo: pk_algo,
- fp: fp,
- },
+ SubpacketValue::RevocationKey(rk),
true)?)?;
Ok(self)
@@ -2327,11 +2305,11 @@ fn accessors() {
assert_eq!(sig_.preferred_symmetric_algorithms(), Some(&pref[..]));
let fp = Fingerprint::from_bytes(b"bbbbbbbbbbbbbbbbbbbb");
- sig = sig.set_revocation_key(2, pk_algo, fp.clone()).unwrap();
+ let rk = RevocationKey::new(pk_algo, fp.clone(), true);
+ sig = sig.set_revocation_key(rk.clone()).unwrap();
let sig_ =
sig.clone().sign_hash(&mut keypair, hash.clone()).unwrap();
- assert_eq!(sig_.revocation_key(),
- Some((2, pk_algo.into(), fp.clone())));
+ assert_eq!(sig_.revocation_key(), Some(&rk));
sig = sig.set_issuer(fp.clone().into()).unwrap();
let sig_ =
@@ -2797,17 +2775,14 @@ fn subpacket_test_2() {
let fp = Fingerprint::from_hex(
"361A96BDE1A65B6D6C25AE9FF004B9A45C586126").unwrap();
- assert_eq!(sig.revocation_key(),
- Some((128, PublicKeyAlgorithm::RSAEncryptSign, fp.clone())));
+ let rk = RevocationKey::new(PublicKeyAlgorithm::RSAEncryptSign,
+ fp.clone(), false);
+ assert_eq!(sig.revocation_key(), Some(&rk));
assert_eq!(sig.subpacket(SubpacketTag::RevocationKey),
Some(&Subpacket {
length: 23.into(),
critical: false,
- value: SubpacketValue::RevocationKey {
- class: 0x80,
- pk_algo: PublicKeyAlgorithm::RSAEncryptSign,
- fp: fp,
- },
+ value: SubpacketValue::RevocationKey(rk),
}));
diff --git a/openpgp/src/parse/parse.rs b/openpgp/src/parse/parse.rs
index 8848e292..52531262 100644
--- a/openpgp/src/parse/parse.rs
+++ b/openpgp/src/parse/parse.rs
@@ -39,6 +39,7 @@ use crate::types::{
KeyFlags,
KeyServerPreferences,
PublicKeyAlgorithm,
+ RevocationKey,
SignatureType,
SymmetricAlgorithm,
Timestamp,
@@ -1280,12 +1281,12 @@ impl Subpacket {
"Short revocation key subpacket".into())
.into());
}
- SubpacketValue::RevocationKey {
- class: php.parse_u8("class")?,
- pk_algo: php.parse_u8("pk algo")?.into(),
- fp: Fingerprint::from_bytes(&php.parse_bytes("fingerprint",
- len - 2)?),
- }
+ let class = php.parse_u8("class")?;
+ let pk_algo = php.parse_u8("pk algo")?.into();
+ let fp = Fingerprint::from_bytes(
+ &php.parse_bytes("fingerprint", len - 2)?);
+ SubpacketValue::RevocationKey(
+ RevocationKey::from_bits(pk_algo, fp, class)?)
},
SubpacketTag::Issuer =>
SubpacketValue::Issuer(
diff --git a/openpgp/src/serialize/mod.rs b/openpgp/src/serialize/mod.rs
index a672817c..3c97704e 100644
--- a/openpgp/src/serialize/mod.rs
+++ b/openpgp/src/serialize/mod.rs
@@ -41,6 +41,7 @@ use crate::packet::signature::subpacket::{
};
use crate::packet::prelude::*;
use crate::types::{
+ RevocationKey,
Timestamp,
};
@@ -1016,10 +1017,7 @@ impl Serialize for SubpacketValue {
for a in p {
o.write_all(&[(*a).into()])?;
},
- RevocationKey { ref class, ref pk_algo, ref fp } => {
- o.write_all(&[*class, (*pk_algo).into()])?;
- o.write_all(fp.as_slice())?;
- },
+ RevocationKey(rk) => rk.serialize(o)?,
Issuer(ref id) =>
o.write_all(id.as_slice())?,
NotationData(nd) => {
@@ -1100,7 +1098,7 @@ impl SerializeInto for SubpacketValue {
Revocable(_) => 1,
KeyExpirationTime(_) => 4,
PreferredSymmetricAlgorithms(ref p) => p.len(),
- RevocationKey { ref fp, .. } => 2 + fp.serialized_len(),
+ RevocationKey(rk) => rk.serialized_len(),
Issuer(ref id) => id.serialized_len(),
NotationData(nd) => 4 + 2 + 2 + nd.name().len() + nd.value().len(),
PreferredHashAlgorithms(ref p) => p.len(),
@@ -1136,6 +1134,25 @@ impl SerializeInto for SubpacketValue {
}
}
+impl Serialize for RevocationKey {
+ fn serialize(&self, o: &mut dyn std::io::Write) -> Result<()> {
+ let (pk_algo, fp) = self.revoker();
+ o.write_all(&[self.class(), (pk_algo).into()])?;
+ o.write_all(fp.as_slice())?;
+ Ok(())
+ }
+}
+
+impl SerializeInto for RevocationKey {
+ fn serialized_len(&self) -> usize {
+ 1 + 1 + self.revoker().1.as_slice().len()
+ }
+
+ fn serialize_into(&self, buf: &mut [u8]) -> Result<usize> {
+ generic_serialize_into(self, buf)
+ }
+}
+
impl Serialize for Signature {
fn serialize(&self, o: &mut dyn std::io::Write) -> Result<()> {
match self {
diff --git a/openpgp/src/types/mod.rs b/openpgp/src/types/mod.rs
index ac6811d5..58b7b03b 100644
--- a/openpgp/src/types/mod.rs
+++ b/openpgp/src/types/mod.rs
@@ -16,6 +16,8 @@ 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;
diff --git a/openpgp/src/types/revocation_key.rs b/openpgp/src/types/revocation_key.rs
new file mode 100644
index 00000000..c96910a2
--- /dev/null
+++ b/openpgp/src/types/revocation_key.rs
@@ -0,0 +1,98 @@
+use crate::{
+ Error,
+ Fingerprint,
+ Result,
+ types::{
+ PublicKeyAlgorithm,
+ },
+};
+
+/// Designates a key as a valid third-party revoker.
+#[derive(Clone, Debug, PartialEq, Eq, Hash)]
+pub struct RevocationKey {
+ /// XXX: RFC4880 says nothing about this.
+ pk_algo: PublicKeyAlgorithm,
+
+ /// Fingerprint of authorized key.
+ fp: Fingerprint,
+
+ /// Indicates that the relation between revoker and revokee is
+ /// of a sensitive nature.
+ sensitive: bool,
+
+ /// Other bits are for future expansion to other kinds of
+ /// authorizations.
+ unknown: u8,
+}
+
+impl RevocationKey {
+ /// Creates a new instance.
+ pub fn new(pk_algo: PublicKeyAlgorithm, fp: Fingerprint, sensitive: bool)
+ -> Self
+ {
+ RevocationKey {
+ pk_algo, fp, sensitive, unknown: 0,
+ }
+ }
+
+ /// Creates a new instance from `bits`.
+ pub fn from_bits(pk_algo: PublicKeyAlgorithm, fp: Fingerprint, class: u8)
+ -> Result<Self> {
+ if class & REVOCATION_KEY_FLAG_MUST_BE_SET == 0 {
+ return Err(Error::InvalidArgument(
+ "Most significant bit of class must be set".into()).into());
+ }
+ let sensitive = class & REVOCATION_KEY_FLAG_SENSITIVE > 0;
+ let unknown = class & REVOCATION_KEY_MASK_UNKNOWN;
+ Ok(RevocationKey {
+ pk_algo, fp, sensitive, unknown,
+ })
+ }
+
+ /// Returns the `class` octet, the sum of all flags.
+ pub fn class(&self) -> u8 {
+ (REVOCATION_KEY_FLAG_MUST_BE_SET
+ | if self.sensitive() {
+ REVOCATION_KEY_FLAG_SENSITIVE
+ } else {
+ 0
+ }
+ | self.unknown)
+ }
+
+ /// Returns the revoker's identity.
+ pub fn revoker(&self) -> (PublicKeyAlgorithm, &Fingerprint) {
+ (self.pk_algo, &self.fp)
+ }
+
+ /// Sets the revoker's identity.
+ pub fn set_revoker(&mut self, pk_algo: PublicKeyAlgorithm, fp: Fingerprint)
+ -> (PublicKeyAlgorithm, Fingerprint) {
+ let pk_algo = std::mem::replace(&mut self.pk_algo, pk_algo);
+ let fp = std::mem::replace(&mut self.fp, fp);
+ (pk_algo, fp)
+ }
+
+ /// Returns whether or not the relation between revoker and
+ /// revokee is of a sensitive nature.
+ pub fn sensitive(&self) -> bool {
+ self.sensitive
+ }
+
+ /// Sets whether or not the relation between revoker and revokee
+ /// is of a sensitive nature.
+ pub fn set_sensitive(mut self, v: bool) -> Self {
+ self.sensitive = v;
+ self
+ }
+}
+
+/// This bit must be set.
+const REVOCATION_KEY_FLAG_MUST_BE_SET: u8 = 0x80;
+
+/// Relation is of a sensitive nature.
+const REVOCATION_KEY_FLAG_SENSITIVE: u8 = 0x40;
+
+/// Mask covering the unknown bits.
+const REVOCATION_KEY_MASK_UNKNOWN: u8 = ! (REVOCATION_KEY_FLAG_MUST_BE_SET
+ | REVOCATION_KEY_FLAG_SENSITIVE);
diff --git a/tool/src/commands/dump.rs b/tool/src/commands/dump.rs
index aed7fb15..349255b9 100644
--- a/tool/src/commands/dump.rs
+++ b/tool/src/commands/dump.rs
@@ -760,10 +760,15 @@ impl PacketDumper {
write!(output, "{} Symmetric algo preferences: {}", i,
c.iter().map(|c| format!("{:?}", c))
.collect::<Vec<String>>().join(", "))?,
- RevocationKey{class, pk_algo, ref fp} =>
+ RevocationKey(rk) => {
+ let (pk_algo, fp) = rk.revoker();
write!(output,
- "{} Revocation key: class {} algo {} fingerprint {}", i,
- class, pk_algo, fp)?,
+ "{} Revocation key: {}/{}", i,
+ fp, pk_algo)?;
+ if rk.sensitive() {
+ write!(output, ", sensitive")?;
+ }
+ },
Issuer(ref is) =>
write!(output, "{} Issuer: {}", i, is)?,
NotationData(ref n) =>