1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
#[cfg(any(test, feature = "quickcheck"))]
use quickcheck::{Arbitrary, Gen};

use crate::{
    cert::prelude::*,
    Error,
    Fingerprint,
    Result,
    types::{
        PublicKeyAlgorithm,
    },
};

/// Designates a key as a valid third-party revoker.
///
/// This is described in [Section 5.2.3.15 of RFC 4880].
///
/// [Section 5.2.3.15 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-5.2.3.15
///
/// Revocation keys can be retrieved using [`ComponentAmalgamation::revocation_keys`]
/// and set using [`CertBuilder::set_revocation_keys`].
///
/// [`ComponentAmalgamation::revocation_keys`]: ../cert/amalgamation/struct.ComponentAmalgamation.html#method.revocation_keys
/// [`CertBuilder::set_revocation_keys`]: ../cert/struct.CertBuilder.html#method.set_revocation_keys
///
/// # Examples
///
/// ```
/// use sequoia_openpgp as openpgp;
/// # use openpgp::Result;
/// use openpgp::cert::prelude::*;
/// use openpgp::policy::StandardPolicy;
/// use openpgp::types::RevocationKey;
///
/// # fn main() -> Result<()> {
/// let p = &StandardPolicy::new();
///
/// let (alice, _) =
///     CertBuilder::general_purpose(None, Some("alice@example.org"))
///     .generate()?;
///
/// // Make Alice a designated revoker for Bob.
/// let (bob, _) =
///     CertBuilder::general_purpose(None, Some("bob@example.org"))
///     .set_revocation_keys(vec![ (&alice).into() ])
///     .generate()?;
///
/// // Make sure Alice is listed as a designated revoker for Bob
/// // on a component.
/// assert_eq!(bob.with_policy(p, None)?.primary_userid()?.revocation_keys(p)
///                .collect::<Vec<&RevocationKey>>(),
///            vec![ &(&alice).into() ]);
/// # Ok(()) }
/// ```
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct RevocationKey {
    /// The public key algorithm used by the authorized key.
    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 From<&Cert> for RevocationKey {
    fn from(cert: &Cert) -> Self {
        RevocationKey::new(cert.primary_key().pk_algo(),
                           cert.fingerprint(),
                           false)
    }
}

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 the raw `class` parameter.
    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);

#[cfg(any(test, feature = "quickcheck"))]
impl Arbitrary for RevocationKey {
    fn arbitrary<G: Gen>(g: &mut G) -> Self {
        RevocationKey {
            pk_algo: Arbitrary::arbitrary(g),
            fp: Arbitrary::arbitrary(g),
            sensitive: Arbitrary::arbitrary(g),
            unknown: u8::arbitrary(g) & REVOCATION_KEY_MASK_UNKNOWN,
        }
    }
}