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}