sequoia_openpgp/types/
server_preferences.rs

1use std::fmt;
2
3#[cfg(test)]
4use quickcheck::{Arbitrary, Gen};
5
6use crate::types::Bitfield;
7
8/// Describes preferences regarding key servers.
9///
10/// Key server preferences are specified in [Section 5.2.3.25 of RFC 9580].
11///
12/// [Section 5.2.3.25 of RFC 9580]: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.25
13///
14/// The keyserver preferences are set by the user's OpenPGP
15/// implementation to communicate them to any peers.
16///
17/// # A note on equality
18///
19/// `PartialEq` compares the serialized form of the two key server
20/// preference sets.  If you prefer to compare two key server
21/// preference sets for semantic equality, you should use
22/// [`KeyServerPreferences::normalized_eq`].  The difference between
23/// semantic equality and serialized equality is that semantic
24/// equality ignores differences in the amount of padding.
25///
26///   [`KeyServerPreferences::normalized_eq`]: KeyServerPreferences::normalized_eq()
27///
28/// # Examples
29///
30/// ```
31/// use sequoia_openpgp as openpgp;
32/// # use openpgp::Result;
33/// use openpgp::cert::prelude::*;
34/// use openpgp::policy::StandardPolicy;
35///
36/// # fn main() -> Result<()> {
37/// let p = &StandardPolicy::new();
38///
39/// let (cert, _) =
40///     CertBuilder::general_purpose(Some("alice@example.org"))
41///     .generate()?;
42///
43/// match cert.with_policy(p, None)?.primary_userid()?.key_server_preferences() {
44///     Some(preferences) => {
45///         println!("Certificate holder's keyserver preferences:");
46///         assert!(preferences.no_modify());
47/// #       unreachable!();
48///     }
49///     None => {
50///         println!("Certificate Holder did not specify any key server preferences.");
51///     }
52/// }
53/// # Ok(()) }
54/// ```
55#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
56pub struct KeyServerPreferences(Bitfield);
57assert_send_and_sync!(KeyServerPreferences);
58
59impl fmt::Debug for KeyServerPreferences {
60    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
61        let mut need_comma = false;
62        if self.no_modify() {
63            f.write_str("no modify")?;
64            need_comma = true;
65        }
66
67        for i in self.0.iter_set() {
68            match i {
69                KEYSERVER_PREFERENCE_NO_MODIFY => (),
70                i => {
71                    if need_comma { f.write_str(", ")?; }
72                    write!(f, "#{}", i)?;
73                    need_comma = true;
74                },
75            }
76        }
77
78        // Mention any padding, as equality is sensitive to this.
79        if let Some(padding) = self.0.padding_bytes() {
80            if need_comma { f.write_str(", ")?; }
81            write!(f, "+padding({} bytes)", padding)?;
82        }
83
84        Ok(())
85    }
86}
87
88impl KeyServerPreferences {
89    /// Creates a new instance from `bits`.
90    pub fn new<B: AsRef<[u8]>>(bits: B) -> Self {
91        KeyServerPreferences(bits.as_ref().to_vec().into())
92    }
93
94    /// Returns an empty key server preference set.
95    pub fn empty() -> Self {
96        Self::new(&[])
97    }
98
99    /// Returns a reference to the underlying [`Bitfield`].
100    pub fn as_bitfield(&self) -> &Bitfield {
101        &self.0
102    }
103
104    /// Returns a mutable reference to the underlying [`Bitfield`].
105    pub fn as_bitfield_mut(&mut self) -> &mut Bitfield {
106        &mut self.0
107    }
108
109    /// Compares two key server preference sets for semantic equality.
110    ///
111    /// `KeyServerPreferences` implementation of `PartialEq` compares
112    /// two key server preference sets for serialized equality.  That
113    /// is, the `PartialEq` implementation considers two key server
114    /// preference sets to *not* be equal if they have different
115    /// amounts of padding.  This comparison function ignores padding.
116    ///
117    /// # Examples
118    ///
119    /// ```
120    /// use sequoia_openpgp as openpgp;
121    /// use openpgp::types::KeyServerPreferences;
122    ///
123    /// # fn main() -> openpgp::Result<()> {
124    /// let a = KeyServerPreferences::new(&[0x1]);
125    /// let b = KeyServerPreferences::new(&[0x1, 0x0]);
126    ///
127    /// assert!(a != b);
128    /// assert!(a.normalized_eq(&b));
129    /// # Ok(()) }
130    /// ```
131    pub fn normalized_eq(&self, other: &Self) -> bool {
132        self.0.normalized_eq(&other.0)
133    }
134
135    /// Returns whether the specified keyserver preference flag is set.
136    ///
137    /// # Examples
138    ///
139    /// ```
140    /// use sequoia_openpgp as openpgp;
141    /// use openpgp::types::KeyServerPreferences;
142    ///
143    /// # fn main() -> openpgp::Result<()> {
144    /// // Keyserver Preferences flags 0 and 2.
145    /// let ksp = KeyServerPreferences::new(&[0x5]);
146    ///
147    /// assert!(ksp.get(0));
148    /// assert!(! ksp.get(1));
149    /// assert!(ksp.get(2));
150    /// assert!(! ksp.get(3));
151    /// assert!(! ksp.get(8));
152    /// assert!(! ksp.get(80));
153    /// # assert!(! ksp.no_modify());
154    /// # Ok(()) }
155    /// ```
156    pub fn get(&self, bit: usize) -> bool {
157        self.0.get(bit)
158    }
159
160    /// Sets the specified keyserver preference flag.
161    ///
162    /// This also clears any padding (trailing NUL bytes).
163    ///
164    /// # Examples
165    ///
166    /// ```
167    /// use sequoia_openpgp as openpgp;
168    /// use openpgp::types::KeyServerPreferences;
169    ///
170    /// # fn main() -> openpgp::Result<()> {
171    /// let ksp = KeyServerPreferences::empty().set(0).set(2);
172    ///
173    /// assert!(ksp.get(0));
174    /// assert!(! ksp.get(1));
175    /// assert!(ksp.get(2));
176    /// assert!(! ksp.get(3));
177    /// # assert!(! ksp.no_modify());
178    /// # Ok(()) }
179    /// ```
180    pub fn set(mut self, bit: usize) -> Self {
181        self.0.set(bit);
182        self.0.canonicalize();
183        self
184    }
185
186    /// Clears the specified keyserver preference flag.
187    ///
188    /// This also clears any padding (trailing NUL bytes).
189    ///
190    /// # Examples
191    ///
192    /// ```
193    /// use sequoia_openpgp as openpgp;
194    /// use openpgp::types::KeyServerPreferences;
195    ///
196    /// # fn main() -> openpgp::Result<()> {
197    /// let ksp = KeyServerPreferences::empty().set(0).set(2).clear(2);
198    ///
199    /// assert!(ksp.get(0));
200    /// assert!(! ksp.get(1));
201    /// assert!(! ksp.get(2));
202    /// assert!(! ksp.get(3));
203    /// # assert!(! ksp.no_modify());
204    /// # Ok(()) }
205    /// ```
206    pub fn clear(mut self, bit: usize) -> Self {
207        self.0.clear(bit);
208        self.0.canonicalize();
209        self
210    }
211
212    /// Returns whether the certificate's owner requests that the
213    /// certificate is not modified.
214    ///
215    /// If this flag is set, the certificate's owner requests that the
216    /// certificate should only be changed by the owner and the key
217    /// server's operator.
218    ///
219    /// # Examples
220    ///
221    /// ```
222    /// use sequoia_openpgp as openpgp;
223    /// use openpgp::types::KeyServerPreferences;
224    ///
225    /// # fn main() -> openpgp::Result<()> {
226    /// let ksp = KeyServerPreferences::empty();
227    /// assert!(! ksp.no_modify());
228    /// # Ok(()) }
229    /// ```
230    pub fn no_modify(&self) -> bool {
231        self.get(KEYSERVER_PREFERENCE_NO_MODIFY)
232    }
233
234    /// Requests that the certificate is not modified.
235    ///
236    /// See [`KeyServerPreferences::no_modify`].
237    ///
238    ///   [`KeyServerPreferences::no_modify`]: KeyServerPreferences::no_modify()
239    ///
240    /// # Examples
241    ///
242    /// ```
243    /// use sequoia_openpgp as openpgp;
244    /// use openpgp::types::KeyServerPreferences;
245    ///
246    /// # fn main() -> openpgp::Result<()> {
247    /// let ksp = KeyServerPreferences::empty().set_no_modify();
248    /// assert!(ksp.no_modify());
249    /// # Ok(()) }
250    /// ```
251    pub fn set_no_modify(self) -> Self {
252        self.set(KEYSERVER_PREFERENCE_NO_MODIFY)
253    }
254
255    /// Clears the request that the certificate is not modified.
256    ///
257    /// See [`KeyServerPreferences::no_modify`].
258    ///
259    ///   [`KeyServerPreferences::no_modify`]: KeyServerPreferences::no_modify()
260    ///
261    /// # Examples
262    ///
263    /// ```
264    /// use sequoia_openpgp as openpgp;
265    /// use openpgp::types::KeyServerPreferences;
266    ///
267    /// # fn main() -> openpgp::Result<()> {
268    /// let ksp = KeyServerPreferences::new(&[0x80][..]);
269    /// assert!(ksp.no_modify());
270    /// let ksp = ksp.clear_no_modify();
271    /// assert!(! ksp.no_modify());
272    /// # Ok(()) }
273    /// ```
274    pub fn clear_no_modify(self) -> Self {
275        self.clear(KEYSERVER_PREFERENCE_NO_MODIFY)
276    }
277}
278
279/// The key holder requests that this key only be modified or updated
280/// by the key holder or an administrator of the key server.
281const KEYSERVER_PREFERENCE_NO_MODIFY: usize = 7;
282
283#[cfg(test)]
284impl Arbitrary for KeyServerPreferences {
285    fn arbitrary(g: &mut Gen) -> Self {
286        Self::new(Vec::arbitrary(g))
287    }
288}
289
290#[cfg(test)]
291mod tests {
292    use super::*;
293
294    #[test]
295    fn basics() -> crate::Result<()> {
296        let p = KeyServerPreferences::empty();
297        assert_eq!(p.no_modify(), false);
298        let p = KeyServerPreferences::new(&[]);
299        assert_eq!(p.no_modify(), false);
300        let p = KeyServerPreferences::new(&[0xff]);
301        assert_eq!(p.no_modify(), true);
302        Ok(())
303    }
304
305    quickcheck! {
306        fn roundtrip(val: KeyServerPreferences) -> bool {
307            let mut q_bytes = val.as_bitfield().as_bytes().to_vec();
308            let q = KeyServerPreferences::new(&q_bytes);
309            assert_eq!(val, q);
310            assert!(val.normalized_eq(&q));
311
312            // Add some padding to q.  Make sure they are still equal.
313            q_bytes.push(0);
314            let q = KeyServerPreferences::new(&q_bytes);
315            assert!(val != q);
316            assert!(val.normalized_eq(&q));
317
318            q_bytes.push(0);
319            let q = KeyServerPreferences::new(&q_bytes);
320            assert!(val != q);
321            assert!(val.normalized_eq(&q));
322
323            true
324        }
325    }
326}