sequoia_openpgp/cert/revoke.rs
1use std::convert::TryFrom;
2use std::time;
3
4use crate::{
5 HashAlgorithm,
6 Result,
7 SignatureType,
8};
9use crate::types::{
10 ReasonForRevocation,
11};
12use crate::crypto::Signer;
13use crate::packet::{
14 Key,
15 key,
16 signature,
17 Signature,
18 UserAttribute,
19 UserID,
20};
21use crate::packet::signature::subpacket::NotationDataFlags;
22use crate::cert::prelude::*;
23
24/// A builder for revocation certificates for OpenPGP certificates.
25///
26/// A revocation certificate for an OpenPGP certificate (as opposed
27/// to, say, a subkey) has two degrees of freedom: the certificate,
28/// and the key used to sign the revocation certificate.
29///
30/// Normally, the key used to sign the revocation certificate is the
31/// certificate's primary key. However, this is not required. For
32/// instance, if Alice has marked Robert's certificate (`R`) as a
33/// [designated revoker] for her certificate (`A`), then `R` can
34/// revoke `A` or parts of `A`. In this case, the certificate is `A`,
35/// and the key used to sign the revocation certificate comes from
36/// `R`.
37///
38/// [designated revoker]: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.23
39///
40/// # Examples
41///
42/// Revoke `cert`, which was compromised yesterday:
43///
44/// ```rust
45/// use sequoia_openpgp as openpgp;
46/// # use openpgp::Result;
47/// use openpgp::cert::prelude::*;
48/// use openpgp::policy::StandardPolicy;
49/// use openpgp::types::ReasonForRevocation;
50/// use openpgp::types::RevocationStatus;
51/// use openpgp::types::SignatureType;
52///
53/// # fn main() -> Result<()> {
54/// let p = &StandardPolicy::new();
55///
56/// # let (cert, _) = CertBuilder::new()
57/// # .generate()?;
58/// # assert_eq!(RevocationStatus::NotAsFarAsWeKnow,
59/// # cert.revocation_status(p, None));
60/// #
61/// // Create and sign a revocation certificate.
62/// let mut signer = cert.primary_key().key().clone()
63/// .parts_into_secret()?.into_keypair()?;
64/// # let yesterday = std::time::SystemTime::now();
65/// let sig = CertRevocationBuilder::new()
66/// // Don't use the current time, since the certificate was
67/// // actually compromised yesterday.
68/// .set_signature_creation_time(yesterday)?
69/// .set_reason_for_revocation(ReasonForRevocation::KeyCompromised,
70/// b"It was the maid :/")?
71/// .build(&mut signer, &cert, None)?;
72///
73/// // Merge it into the certificate.
74/// let cert = cert.insert_packets(sig.clone())?.0;
75///
76/// // Now it's revoked.
77/// assert_eq!(RevocationStatus::Revoked(vec![&sig]),
78/// cert.revocation_status(p, None));
79/// # Ok(())
80/// # }
81pub struct CertRevocationBuilder {
82 builder: signature::SignatureBuilder,
83}
84assert_send_and_sync!(CertRevocationBuilder);
85
86impl CertRevocationBuilder {
87 /// Returns a new `CertRevocationBuilder`.
88 ///
89 /// # Examples
90 ///
91 /// ```rust
92 /// use sequoia_openpgp as openpgp;
93 /// # use openpgp::Result;
94 /// use openpgp::cert::prelude::*;
95 ///
96 /// # fn main() -> Result<()> {
97 /// let builder = CertRevocationBuilder::new();
98 /// # Ok(())
99 /// # }
100 pub fn new() -> Self {
101 Self {
102 builder:
103 signature::SignatureBuilder::new(SignatureType::KeyRevocation)
104 }
105 }
106
107 /// Sets the reason for revocation.
108 ///
109 /// # Examples
110 ///
111 /// ```rust
112 /// use sequoia_openpgp as openpgp;
113 /// # use openpgp::Result;
114 /// use openpgp::cert::prelude::*;
115 /// use openpgp::types::ReasonForRevocation;
116 ///
117 /// # fn main() -> Result<()> {
118 /// let builder = CertRevocationBuilder::new()
119 /// .set_reason_for_revocation(ReasonForRevocation::KeyRetired,
120 /// b"I'm retiring this key. \
121 /// Please use my new OpenPGP certificate (FPR)");
122 /// # Ok(())
123 /// # }
124 pub fn set_reason_for_revocation(self, code: ReasonForRevocation,
125 reason: &[u8])
126 -> Result<Self>
127 {
128 Ok(Self {
129 builder: self.builder.set_reason_for_revocation(code, reason)?
130 })
131 }
132
133 /// Sets the revocation certificate's creation time.
134 ///
135 /// The creation time is interpreted as the time at which the
136 /// certificate should be considered revoked. For a soft
137 /// revocation, artifacts created prior to the revocation are
138 /// still considered valid.
139 ///
140 /// You'll usually want to set this explicitly and not use the
141 /// current time.
142 ///
143 /// First, the creation time should reflect the time of the event
144 /// that triggered the revocation. As such, if it is discovered
145 /// that a certificate was compromised a week ago, then the
146 /// revocation certificate should be backdated appropriately.
147 ///
148 /// Second, because access to secret key material can be lost, it
149 /// can be useful to create a revocation certificate in advance.
150 /// Of course, such a revocation certificate will inevitably be
151 /// outdated. To mitigate this problem, a number of revocation
152 /// certificates can be created with different creation times.
153 /// Then should a revocation certificate be needed, the most
154 /// appropriate one can be used.
155 ///
156 /// # Examples
157 ///
158 /// ```rust
159 /// use std::time::{SystemTime, Duration};
160 /// use sequoia_openpgp as openpgp;
161 /// # use openpgp::Result;
162 /// use openpgp::cert::prelude::*;
163 ///
164 /// # fn main() -> Result<()> {
165 /// let now = SystemTime::now();
166 /// let month = Duration::from_secs(((365.24 / 12.) * 24. * 60. * 60.) as u64);
167 ///
168 /// // Pre-generate revocation certificates, one for each month
169 /// // for the next 48 months.
170 /// for i in 0..48 {
171 /// let builder = CertRevocationBuilder::new()
172 /// .set_signature_creation_time(now + i * month);
173 /// // ...
174 /// }
175 /// # Ok(())
176 /// # }
177 pub fn set_signature_creation_time(self, creation_time: time::SystemTime)
178 -> Result<Self>
179 {
180 Ok(Self {
181 builder: self.builder.set_signature_creation_time(creation_time)?
182 })
183 }
184
185 /// Adds a notation to the revocation certificate.
186 ///
187 /// Unlike the [`CertRevocationBuilder::set_notation`] method, this function
188 /// does not first remove any existing notation with the specified name.
189 ///
190 /// See [`SignatureBuilder::add_notation`] for further documentation.
191 ///
192 /// [`SignatureBuilder::add_notation`]: crate::packet::signature::SignatureBuilder::add_notation()
193 ///
194 /// # Examples
195 ///
196 /// ```rust
197 /// use sequoia_openpgp as openpgp;
198 /// # use openpgp::Result;
199 /// use openpgp::cert::prelude::*;
200 /// use openpgp::packet::signature::subpacket::NotationDataFlags;
201 ///
202 /// # fn main() -> Result<()> {
203 /// let builder = CertRevocationBuilder::new().add_notation(
204 /// "revocation-policy@example.org",
205 /// "https://policy.example.org/cert-revocation-policy",
206 /// NotationDataFlags::empty().set_human_readable(),
207 /// false,
208 /// );
209 /// # Ok(())
210 /// # }
211 pub fn add_notation<N, V, F>(self, name: N, value: V, flags: F,
212 critical: bool)
213 -> Result<Self>
214 where
215 N: AsRef<str>,
216 V: AsRef<[u8]>,
217 F: Into<Option<NotationDataFlags>>,
218 {
219 Ok(Self {
220 builder: self.builder.add_notation(name, value, flags, critical)?
221 })
222 }
223
224 /// Sets a notation to the revocation certificate.
225 ///
226 /// Unlike the [`CertRevocationBuilder::add_notation`] method, this function
227 /// first removes any existing notation with the specified name.
228 ///
229 /// See [`SignatureBuilder::set_notation`] for further documentation.
230 ///
231 /// [`SignatureBuilder::set_notation`]: crate::packet::signature::SignatureBuilder::set_notation()
232 ///
233 /// # Examples
234 ///
235 /// ```rust
236 /// use sequoia_openpgp as openpgp;
237 /// # use openpgp::Result;
238 /// use openpgp::cert::prelude::*;
239 /// use openpgp::packet::signature::subpacket::NotationDataFlags;
240 ///
241 /// # fn main() -> Result<()> {
242 /// let builder = CertRevocationBuilder::new().set_notation(
243 /// "revocation-policy@example.org",
244 /// "https://policy.example.org/cert-revocation-policy",
245 /// NotationDataFlags::empty().set_human_readable(),
246 /// false,
247 /// );
248 /// # Ok(())
249 /// # }
250 pub fn set_notation<N, V, F>(self, name: N, value: V, flags: F,
251 critical: bool)
252 -> Result<Self>
253 where
254 N: AsRef<str>,
255 V: AsRef<[u8]>,
256 F: Into<Option<NotationDataFlags>>,
257 {
258 Ok(Self {
259 builder: self.builder.set_notation(name, value, flags, critical)?
260 })
261 }
262
263 /// Returns a signed revocation certificate.
264 ///
265 /// A revocation certificate is generated for `cert` and signed
266 /// using `signer` with the specified hash algorithm. Normally,
267 /// you should pass `None` to select the default hash algorithm.
268 ///
269 /// # Examples
270 ///
271 /// ```rust
272 /// use sequoia_openpgp as openpgp;
273 /// # use openpgp::Result;
274 /// use openpgp::cert::prelude::*;
275 /// use openpgp::policy::StandardPolicy;
276 /// use openpgp::types::ReasonForRevocation;
277 /// # use openpgp::types::RevocationStatus;
278 /// # use openpgp::types::SignatureType;
279 ///
280 /// # fn main() -> Result<()> {
281 /// let p = &StandardPolicy::new();
282 ///
283 /// # let (cert, _) = CertBuilder::new()
284 /// # .generate()?;
285 /// #
286 /// // Create and sign a revocation certificate.
287 /// let mut signer = cert.primary_key().key().clone()
288 /// .parts_into_secret()?.into_keypair()?;
289 /// let sig = CertRevocationBuilder::new()
290 /// .set_reason_for_revocation(ReasonForRevocation::KeyRetired,
291 /// b"Left Foo Corp.")?
292 /// .build(&mut signer, &cert, None)?;
293 ///
294 /// # assert_eq!(sig.typ(), SignatureType::KeyRevocation);
295 /// #
296 /// # // Merge it into the certificate.
297 /// # let cert = cert.insert_packets(sig.clone())?.0;
298 /// #
299 /// # // Now it's revoked.
300 /// # assert_eq!(RevocationStatus::Revoked(vec![&sig]),
301 /// # cert.revocation_status(p, None));
302 /// # Ok(())
303 /// # }
304 pub fn build<H>(self, signer: &mut dyn Signer, cert: &Cert, hash_algo: H)
305 -> Result<Signature>
306 where H: Into<Option<HashAlgorithm>>
307 {
308 self.builder
309 .set_hash_algo(hash_algo.into().unwrap_or(HashAlgorithm::SHA512))
310 .sign_direct_key(signer, cert.primary_key().key())
311 }
312}
313
314impl TryFrom<signature::SignatureBuilder> for CertRevocationBuilder {
315 type Error = anyhow::Error;
316
317 fn try_from(builder: signature::SignatureBuilder) -> Result<Self> {
318 if builder.typ() != SignatureType::KeyRevocation {
319 return Err(
320 crate::Error::InvalidArgument(
321 format!("Expected signature type to be KeyRevocation but got {}",
322 builder.typ())).into());
323 }
324 Ok(Self {
325 builder
326 })
327 }
328}
329
330/// A builder for revocation certificates for subkeys.
331///
332/// A revocation certificate for a subkey has three degrees of
333/// freedom: the certificate, the key used to generate the revocation
334/// certificate, and the subkey being revoked.
335///
336/// Normally, the key used to sign the revocation certificate is the
337/// certificate's primary key, and the subkey is a subkey that is
338/// bound to the certificate. However, this is not required. For
339/// instance, if Alice has marked Robert's certificate (`R`) as a
340/// [designated revoker] for her certificate (`A`), then `R` can
341/// revoke `A` or parts of `A`. In such a case, the certificate is
342/// `A`, the key used to sign the revocation certificate comes from
343/// `R`, and the subkey being revoked is bound to `A`.
344///
345/// But, the subkey doesn't technically need to be bound to the
346/// certificate either. For instance, it is technically possible for
347/// `R` to create a revocation certificate for a subkey in the context
348/// of `A`, even if that subkey is not bound to `A`. Semantically,
349/// such a revocation certificate is currently meaningless.
350///
351/// [designated revoker]: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.23
352///
353/// # Examples
354///
355/// Revoke a subkey, which is now considered to be too weak:
356///
357/// ```rust
358/// use sequoia_openpgp as openpgp;
359/// # use openpgp::Result;
360/// use openpgp::cert::prelude::*;
361/// use openpgp::policy::StandardPolicy;
362/// use openpgp::types::ReasonForRevocation;
363/// use openpgp::types::RevocationStatus;
364/// use openpgp::types::SignatureType;
365///
366/// # fn main() -> Result<()> {
367/// let p = &StandardPolicy::new();
368///
369/// # let (cert, _) = CertBuilder::new()
370/// # .add_transport_encryption_subkey()
371/// # .generate()?;
372/// # assert_eq!(RevocationStatus::NotAsFarAsWeKnow,
373/// # cert.revocation_status(p, None));
374/// #
375/// // Create and sign a revocation certificate.
376/// let mut signer = cert.primary_key().key().clone()
377/// .parts_into_secret()?.into_keypair()?;
378/// let subkey = cert.keys().subkeys().nth(0).unwrap();
379/// let sig = SubkeyRevocationBuilder::new()
380/// .set_reason_for_revocation(ReasonForRevocation::KeyRetired,
381/// b"Revoking due to the recent crypto vulnerabilities.")?
382/// .build(&mut signer, &cert, subkey.key(), None)?;
383///
384/// // Merge it into the certificate.
385/// let cert = cert.insert_packets(sig.clone())?.0;
386///
387/// // Now it's revoked.
388/// let subkey = cert.keys().subkeys().nth(0).unwrap();
389/// if let RevocationStatus::Revoked(revocations) = subkey.revocation_status(p, None) {
390/// assert_eq!(revocations.len(), 1);
391/// assert_eq!(*revocations[0], sig);
392/// } else {
393/// panic!("Subkey is not revoked.");
394/// }
395///
396/// // But the certificate isn't.
397/// assert_eq!(RevocationStatus::NotAsFarAsWeKnow,
398/// cert.revocation_status(p, None));
399/// # Ok(()) }
400/// ```
401pub struct SubkeyRevocationBuilder {
402 builder: signature::SignatureBuilder,
403}
404assert_send_and_sync!(SubkeyRevocationBuilder);
405
406impl SubkeyRevocationBuilder {
407 /// Returns a new `SubkeyRevocationBuilder`.
408 ///
409 /// # Examples
410 ///
411 /// ```rust
412 /// use sequoia_openpgp as openpgp;
413 /// # use openpgp::Result;
414 /// use openpgp::cert::prelude::*;
415 ///
416 /// # fn main() -> Result<()> {
417 /// let builder = SubkeyRevocationBuilder::new();
418 /// # Ok(())
419 /// # }
420 pub fn new() -> Self {
421 Self {
422 builder:
423 signature::SignatureBuilder::new(SignatureType::SubkeyRevocation)
424 }
425 }
426
427 /// Sets the reason for revocation.
428 ///
429 /// # Examples
430 ///
431 /// Revoke a possibly compromised subkey:
432 ///
433 /// ```rust
434 /// use sequoia_openpgp as openpgp;
435 /// # use openpgp::Result;
436 /// use openpgp::cert::prelude::*;
437 /// use openpgp::types::ReasonForRevocation;
438 ///
439 /// # fn main() -> Result<()> {
440 /// let builder = SubkeyRevocationBuilder::new()
441 /// .set_reason_for_revocation(ReasonForRevocation::KeyCompromised,
442 /// b"I lost my smartcard.");
443 /// # Ok(())
444 /// # }
445 pub fn set_reason_for_revocation(self, code: ReasonForRevocation,
446 reason: &[u8])
447 -> Result<Self>
448 {
449 Ok(Self {
450 builder: self.builder.set_reason_for_revocation(code, reason)?
451 })
452 }
453
454 /// Sets the revocation certificate's creation time.
455 ///
456 /// The creation time is interpreted as the time at which the
457 /// subkey should be considered revoked. For a soft revocation,
458 /// artifacts created prior to the revocation are still considered
459 /// valid.
460 ///
461 /// You'll usually want to set this explicitly and not use the
462 /// current time. In particular, if a subkey is compromised,
463 /// you'll want to set this to the time when the compromise
464 /// happened.
465 ///
466 /// # Examples
467 ///
468 /// Create a revocation certificate for a subkey that was
469 /// compromised yesterday:
470 ///
471 /// ```rust
472 /// use sequoia_openpgp as openpgp;
473 /// # use openpgp::Result;
474 /// use openpgp::cert::prelude::*;
475 ///
476 /// # fn main() -> Result<()> {
477 /// # let yesterday = std::time::SystemTime::now();
478 /// let builder = SubkeyRevocationBuilder::new()
479 /// .set_signature_creation_time(yesterday);
480 /// # Ok(())
481 /// # }
482 pub fn set_signature_creation_time(self, creation_time: time::SystemTime)
483 -> Result<Self>
484 {
485 Ok(Self {
486 builder: self.builder.set_signature_creation_time(creation_time)?
487 })
488 }
489
490 /// Adds a notation to the revocation certificate.
491 ///
492 /// Unlike the [`SubkeyRevocationBuilder::set_notation`] method, this function
493 /// does not first remove any existing notation with the specified name.
494 ///
495 /// See [`SignatureBuilder::add_notation`] for further documentation.
496 ///
497 /// [`SignatureBuilder::add_notation`]: crate::packet::signature::SignatureBuilder::add_notation()
498 ///
499 /// # Examples
500 ///
501 /// ```rust
502 /// use sequoia_openpgp as openpgp;
503 /// # use openpgp::Result;
504 /// use openpgp::cert::prelude::*;
505 /// use openpgp::packet::signature::subpacket::NotationDataFlags;
506 ///
507 /// # fn main() -> Result<()> {
508 /// let builder = CertRevocationBuilder::new().add_notation(
509 /// "revocation-policy@example.org",
510 /// "https://policy.example.org/cert-revocation-policy",
511 /// NotationDataFlags::empty().set_human_readable(),
512 /// false,
513 /// );
514 /// # Ok(())
515 /// # }
516 pub fn add_notation<N, V, F>(self, name: N, value: V, flags: F,
517 critical: bool)
518 -> Result<Self>
519 where
520 N: AsRef<str>,
521 V: AsRef<[u8]>,
522 F: Into<Option<NotationDataFlags>>,
523 {
524 Ok(Self {
525 builder: self.builder.add_notation(name, value, flags, critical)?
526 })
527 }
528
529 /// Sets a notation to the revocation certificate.
530 ///
531 /// Unlike the [`SubkeyRevocationBuilder::add_notation`] method, this function
532 /// first removes any existing notation with the specified name.
533 ///
534 /// See [`SignatureBuilder::set_notation`] for further documentation.
535 ///
536 /// [`SignatureBuilder::set_notation`]: crate::packet::signature::SignatureBuilder::set_notation()
537 ///
538 /// # Examples
539 ///
540 /// ```rust
541 /// use sequoia_openpgp as openpgp;
542 /// # use openpgp::Result;
543 /// use openpgp::cert::prelude::*;
544 /// use openpgp::packet::signature::subpacket::NotationDataFlags;
545 ///
546 /// # fn main() -> Result<()> {
547 /// let builder = CertRevocationBuilder::new().set_notation(
548 /// "revocation-policy@example.org",
549 /// "https://policy.example.org/cert-revocation-policy",
550 /// NotationDataFlags::empty().set_human_readable(),
551 /// false,
552 /// );
553 /// # Ok(())
554 /// # }
555 pub fn set_notation<N, V, F>(self, name: N, value: V, flags: F,
556 critical: bool)
557 -> Result<Self>
558 where
559 N: AsRef<str>,
560 V: AsRef<[u8]>,
561 F: Into<Option<NotationDataFlags>>,
562 {
563 Ok(Self {
564 builder: self.builder.set_notation(name, value, flags, critical)?
565 })
566 }
567
568 /// Returns a signed revocation certificate.
569 ///
570 /// A revocation certificate is generated for `cert` and `key` and
571 /// signed using `signer` with the specified hash algorithm.
572 /// Normally, you should pass `None` to select the default hash
573 /// algorithm.
574 ///
575 /// # Examples
576 ///
577 /// Revoke a subkey, which is now considered to be too weak:
578 ///
579 /// ```rust
580 /// use sequoia_openpgp as openpgp;
581 /// # use openpgp::Result;
582 /// use openpgp::cert::prelude::*;
583 /// use openpgp::policy::StandardPolicy;
584 /// use openpgp::types::ReasonForRevocation;
585 /// # use openpgp::types::RevocationStatus;
586 /// # use openpgp::types::SignatureType;
587 ///
588 /// # fn main() -> Result<()> {
589 /// let p = &StandardPolicy::new();
590 ///
591 /// # let (cert, _) = CertBuilder::new()
592 /// # .add_transport_encryption_subkey()
593 /// # .generate()?;
594 /// #
595 /// // Create and sign a revocation certificate.
596 /// let mut signer = cert.primary_key().key().clone()
597 /// .parts_into_secret()?.into_keypair()?;
598 /// let subkey = cert.keys().subkeys().nth(0).unwrap();
599 /// let sig = SubkeyRevocationBuilder::new()
600 /// .set_reason_for_revocation(ReasonForRevocation::KeyRetired,
601 /// b"Revoking due to the recent crypto vulnerabilities.")?
602 /// .build(&mut signer, &cert, subkey.key(), None)?;
603 ///
604 /// # assert_eq!(sig.typ(), SignatureType::SubkeyRevocation);
605 /// #
606 /// # // Merge it into the certificate.
607 /// # let cert = cert.insert_packets(sig.clone())?.0;
608 /// #
609 /// # // Now it's revoked.
610 /// # assert_eq!(RevocationStatus::Revoked(vec![&sig]),
611 /// # cert.keys().subkeys().nth(0).unwrap().revocation_status(p, None));
612 /// # Ok(())
613 /// # }
614 pub fn build<H, P>(mut self, signer: &mut dyn Signer,
615 cert: &Cert, key: &Key<P, key::SubordinateRole>,
616 hash_algo: H)
617 -> Result<Signature>
618 where H: Into<Option<HashAlgorithm>>,
619 P: key::KeyParts,
620 {
621 self.builder = self.builder
622 .set_hash_algo(hash_algo.into().unwrap_or(HashAlgorithm::SHA512));
623
624 key.bind(signer, cert, self.builder)
625 }
626}
627
628impl TryFrom<signature::SignatureBuilder> for SubkeyRevocationBuilder {
629 type Error = anyhow::Error;
630
631 fn try_from(builder: signature::SignatureBuilder) -> Result<Self> {
632 if builder.typ() != SignatureType::SubkeyRevocation {
633 return Err(
634 crate::Error::InvalidArgument(
635 format!("Expected signature type to be SubkeyRevocation but got {}",
636 builder.typ())).into());
637 }
638 Ok(Self {
639 builder
640 })
641 }
642}
643
644/// A builder for revocation certificates for User ID.
645///
646/// A revocation certificate for a [User ID] has three degrees of
647/// freedom: the certificate, the key used to generate the revocation
648/// certificate, and the User ID being revoked.
649///
650/// Normally, the key used to sign the revocation certificate is the
651/// certificate's primary key, and the User ID is a User ID that is
652/// bound to the certificate. However, this is not required. For
653/// instance, if Alice has marked Robert's certificate (`R`) as a
654/// [designated revoker] for her certificate (`A`), then `R` can
655/// revoke `A` or parts of `A`. In such a case, the certificate is
656/// `A`, the key used to sign the revocation certificate comes from
657/// `R`, and the User ID being revoked is bound to `A`.
658///
659/// But, the User ID doesn't technically need to be bound to the
660/// certificate either. For instance, it is technically possible for
661/// `R` to create a revocation certificate for a User ID in the
662/// context of `A`, even if that User ID is not bound to `A`.
663/// Semantically, such a revocation certificate is currently
664/// meaningless.
665///
666/// [User ID]: crate::packet::UserID
667/// [designated revoker]: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.23
668///
669/// # Examples
670///
671/// Revoke a User ID that is no longer valid:
672///
673/// ```rust
674/// use sequoia_openpgp as openpgp;
675/// # use openpgp::Result;
676/// use openpgp::cert::prelude::*;
677/// use openpgp::policy::StandardPolicy;
678/// use openpgp::types::ReasonForRevocation;
679/// use openpgp::types::RevocationStatus;
680/// use openpgp::types::SignatureType;
681///
682/// # fn main() -> Result<()> {
683/// let p = &StandardPolicy::new();
684///
685/// # let (cert, _) = CertBuilder::new()
686/// # .add_userid("some@example.org")
687/// # .generate()?;
688/// # assert_eq!(RevocationStatus::NotAsFarAsWeKnow,
689/// # cert.revocation_status(p, None));
690/// #
691/// // Create and sign a revocation certificate.
692/// let mut signer = cert.primary_key().key().clone()
693/// .parts_into_secret()?.into_keypair()?;
694/// let ua = cert.userids().nth(0).unwrap();
695/// let sig = UserIDRevocationBuilder::new()
696/// .set_reason_for_revocation(ReasonForRevocation::UIDRetired,
697/// b"Left example.org.")?
698/// .build(&mut signer, &cert, ua.userid(), None)?;
699///
700/// // Merge it into the certificate.
701/// let cert = cert.insert_packets(sig.clone())?.0;
702///
703/// // Now it's revoked.
704/// let ua = cert.userids().nth(0).unwrap();
705/// if let RevocationStatus::Revoked(revocations) = ua.revocation_status(p, None) {
706/// assert_eq!(revocations.len(), 1);
707/// assert_eq!(*revocations[0], sig);
708/// } else {
709/// panic!("User ID is not revoked.");
710/// }
711///
712/// // But the certificate isn't.
713/// assert_eq!(RevocationStatus::NotAsFarAsWeKnow,
714/// cert.revocation_status(p, None));
715/// # Ok(()) }
716/// ```
717pub struct UserIDRevocationBuilder {
718 builder: signature::SignatureBuilder,
719}
720assert_send_and_sync!(UserIDRevocationBuilder);
721
722impl UserIDRevocationBuilder {
723 /// Returns a new `UserIDRevocationBuilder`.
724 ///
725 /// # Examples
726 ///
727 /// ```rust
728 /// use sequoia_openpgp as openpgp;
729 /// # use openpgp::Result;
730 /// use openpgp::cert::prelude::*;
731 ///
732 /// # fn main() -> Result<()> {
733 /// let builder = UserIDRevocationBuilder::new();
734 /// # Ok(())
735 /// # }
736 pub fn new() -> Self {
737 Self {
738 builder:
739 signature::SignatureBuilder::new(SignatureType::CertificationRevocation)
740 }
741 }
742
743 /// Sets the reason for revocation.
744 ///
745 /// Note: of the assigned reasons for revocation, only
746 /// [`ReasonForRevocation::UIDRetired`] is appropriate for User
747 /// IDs. This parameter is not fixed, however, to allow the use
748 /// of the [private name space].
749 ///
750 /// [`ReasonForRevocation::UIDRetired`]: crate::types::ReasonForRevocation::UIDRetired
751 /// [private name space]: crate::types::ReasonForRevocation::Private
752 ///
753 ///
754 /// # Examples
755 ///
756 /// Revoke a User ID that is no longer valid:
757 ///
758 /// ```rust
759 /// use sequoia_openpgp as openpgp;
760 /// # use openpgp::Result;
761 /// use openpgp::cert::prelude::*;
762 /// use openpgp::types::ReasonForRevocation;
763 ///
764 /// # fn main() -> Result<()> {
765 /// let builder = UserIDRevocationBuilder::new()
766 /// .set_reason_for_revocation(ReasonForRevocation::UIDRetired,
767 /// b"Left example.org.");
768 /// # Ok(())
769 /// # }
770 pub fn set_reason_for_revocation(self, code: ReasonForRevocation,
771 reason: &[u8])
772 -> Result<Self>
773 {
774 Ok(Self {
775 builder: self.builder.set_reason_for_revocation(code, reason)?
776 })
777 }
778
779 /// Sets the revocation certificate's creation time.
780 ///
781 /// The creation time is interpreted as the time at which the User
782 /// ID should be considered revoked.
783 ///
784 /// You'll usually want to set this explicitly and not use the
785 /// current time. In particular, if a User ID is retired, you'll
786 /// want to set this to the time when the User ID was actually
787 /// retired.
788 ///
789 /// # Examples
790 ///
791 /// Create a revocation certificate for a User ID that was
792 /// retired yesterday:
793 ///
794 /// ```rust
795 /// use sequoia_openpgp as openpgp;
796 /// # use openpgp::Result;
797 /// use openpgp::cert::prelude::*;
798 ///
799 /// # fn main() -> Result<()> {
800 /// # let yesterday = std::time::SystemTime::now();
801 /// let builder = UserIDRevocationBuilder::new()
802 /// .set_signature_creation_time(yesterday);
803 /// # Ok(())
804 /// # }
805 pub fn set_signature_creation_time(self, creation_time: time::SystemTime)
806 -> Result<Self>
807 {
808 Ok(Self {
809 builder: self.builder.set_signature_creation_time(creation_time)?
810 })
811 }
812
813 /// Adds a notation to the revocation certificate.
814 ///
815 /// Unlike the [`UserIDRevocationBuilder::set_notation`] method, this function
816 /// does not first remove any existing notation with the specified name.
817 ///
818 /// See [`SignatureBuilder::add_notation`] for further documentation.
819 ///
820 /// [`SignatureBuilder::add_notation`]: crate::packet::signature::SignatureBuilder::add_notation()
821 ///
822 /// # Examples
823 ///
824 /// ```rust
825 /// use sequoia_openpgp as openpgp;
826 /// # use openpgp::Result;
827 /// use openpgp::cert::prelude::*;
828 /// use openpgp::packet::signature::subpacket::NotationDataFlags;
829 ///
830 /// # fn main() -> Result<()> {
831 /// let builder = CertRevocationBuilder::new().add_notation(
832 /// "revocation-policy@example.org",
833 /// "https://policy.example.org/cert-revocation-policy",
834 /// NotationDataFlags::empty().set_human_readable(),
835 /// false,
836 /// );
837 /// # Ok(())
838 /// # }
839 pub fn add_notation<N, V, F>(self, name: N, value: V, flags: F,
840 critical: bool)
841 -> Result<Self>
842 where
843 N: AsRef<str>,
844 V: AsRef<[u8]>,
845 F: Into<Option<NotationDataFlags>>,
846 {
847 Ok(Self {
848 builder: self.builder.add_notation(name, value, flags, critical)?
849 })
850 }
851
852 /// Sets a notation to the revocation certificate.
853 ///
854 /// Unlike the [`UserIDRevocationBuilder::add_notation`] method, this function
855 /// first removes any existing notation with the specified name.
856 ///
857 /// See [`SignatureBuilder::set_notation`] for further documentation.
858 ///
859 /// [`SignatureBuilder::set_notation`]: crate::packet::signature::SignatureBuilder::set_notation()
860 ///
861 /// # Examples
862 ///
863 /// ```rust
864 /// use sequoia_openpgp as openpgp;
865 /// # use openpgp::Result;
866 /// use openpgp::cert::prelude::*;
867 /// use openpgp::packet::signature::subpacket::NotationDataFlags;
868 ///
869 /// # fn main() -> Result<()> {
870 /// let builder = CertRevocationBuilder::new().set_notation(
871 /// "revocation-policy@example.org",
872 /// "https://policy.example.org/cert-revocation-policy",
873 /// NotationDataFlags::empty().set_human_readable(),
874 /// false,
875 /// );
876 /// # Ok(())
877 /// # }
878 pub fn set_notation<N, V, F>(self, name: N, value: V, flags: F,
879 critical: bool)
880 -> Result<Self>
881 where
882 N: AsRef<str>,
883 V: AsRef<[u8]>,
884 F: Into<Option<NotationDataFlags>>,
885 {
886 Ok(Self {
887 builder: self.builder.set_notation(name, value, flags, critical)?
888 })
889 }
890
891 /// Returns a signed revocation certificate.
892 ///
893 /// A revocation certificate is generated for `cert` and `userid`
894 /// and signed using `signer` with the specified hash algorithm.
895 /// Normally, you should pass `None` to select the default hash
896 /// algorithm.
897 ///
898 /// # Examples
899 ///
900 /// Revoke a User ID, because the user has left the organization:
901 ///
902 /// ```rust
903 /// use sequoia_openpgp as openpgp;
904 /// # use openpgp::Result;
905 /// use openpgp::cert::prelude::*;
906 /// use openpgp::policy::StandardPolicy;
907 /// use openpgp::types::ReasonForRevocation;
908 /// # use openpgp::types::RevocationStatus;
909 /// # use openpgp::types::SignatureType;
910 ///
911 /// # fn main() -> Result<()> {
912 /// let p = &StandardPolicy::new();
913 ///
914 /// # let (cert, _) = CertBuilder::new()
915 /// # .add_userid("some@example.org")
916 /// # .generate()?;
917 /// #
918 /// // Create and sign a revocation certificate.
919 /// let mut signer = cert.primary_key().key().clone()
920 /// .parts_into_secret()?.into_keypair()?;
921 /// let ua = cert.userids().nth(0).unwrap();
922 /// let sig = UserIDRevocationBuilder::new()
923 /// .set_reason_for_revocation(ReasonForRevocation::UIDRetired,
924 /// b"Left example.org.")?
925 /// .build(&mut signer, &cert, ua.userid(), None)?;
926 ///
927 /// # assert_eq!(sig.typ(), SignatureType::CertificationRevocation);
928 /// #
929 /// # // Merge it into the certificate.
930 /// # let cert = cert.insert_packets(sig.clone())?.0;
931 /// #
932 /// # // Now it's revoked.
933 /// # assert_eq!(RevocationStatus::Revoked(vec![&sig]),
934 /// # cert.userids().nth(0).unwrap().revocation_status(p, None));
935 /// # Ok(())
936 /// # }
937 pub fn build<H>(mut self, signer: &mut dyn Signer,
938 cert: &Cert, userid: &UserID,
939 hash_algo: H)
940 -> Result<Signature>
941 where H: Into<Option<HashAlgorithm>>
942 {
943 self.builder = self.builder
944 .set_hash_algo(hash_algo.into().unwrap_or(HashAlgorithm::SHA512));
945
946 userid.bind(signer, cert, self.builder)
947 }
948}
949
950impl TryFrom<signature::SignatureBuilder> for UserIDRevocationBuilder {
951 type Error = anyhow::Error;
952
953 fn try_from(builder: signature::SignatureBuilder) -> Result<Self> {
954 if builder.typ() != SignatureType::CertificationRevocation {
955 return Err(
956 crate::Error::InvalidArgument(
957 format!("Expected signature type to be CertificationRevocation but got {}",
958 builder.typ())).into());
959 }
960 Ok(Self {
961 builder
962 })
963 }
964}
965
966/// A builder for revocation certificates for User Attributes.
967///
968/// A revocation certificate for a [User Attribute] has three degrees of
969/// freedom: the certificate, the key used to generate the revocation
970/// certificate, and the User Attribute being revoked.
971///
972/// Normally, the key used to sign the revocation certificate is the
973/// certificate's primary key, and the User Attribute is a User
974/// Attribute that is bound to the certificate. However, this is not
975/// required. For instance, if Alice has marked Robert's certificate
976/// (`R`) as a [designated revoker] for her certificate (`A`), then
977/// `R` can revoke `A` or parts of `A`. In such a case, the
978/// certificate is `A`, the key used to sign the revocation
979/// certificate comes from `R`, and the User Attribute being revoked
980/// is bound to `A`.
981///
982/// But, the User Attribute doesn't technically need to be bound to
983/// the certificate either. For instance, it is technically possible
984/// for `R` to create a revocation certificate for a User Attribute in
985/// the context of `A`, even if that User Attribute is not bound to
986/// `A`. Semantically, such a revocation certificate is currently
987/// meaningless.
988///
989/// [User Attribute]: crate::packet::user_attribute
990/// [designated revoker]: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.23
991///
992/// # Examples
993///
994/// Revoke a User Attribute that is no longer valid:
995///
996/// ```rust
997/// # use openpgp::packet::user_attribute::Subpacket;
998/// use sequoia_openpgp as openpgp;
999/// # use openpgp::Result;
1000/// use openpgp::cert::prelude::*;
1001/// # use openpgp::packet::UserAttribute;
1002/// use openpgp::policy::StandardPolicy;
1003/// use openpgp::types::ReasonForRevocation;
1004/// use openpgp::types::RevocationStatus;
1005/// use openpgp::types::SignatureType;
1006///
1007/// # fn main() -> Result<()> {
1008/// let p = &StandardPolicy::new();
1009///
1010/// # // Create some user attribute. Doctests do not pass cfg(test),
1011/// # // so UserAttribute::arbitrary is not available
1012/// # let sp = Subpacket::Unknown(7, vec![7; 7].into_boxed_slice());
1013/// # let user_attribute = UserAttribute::new(&[sp])?;
1014/// #
1015/// # let (cert, _) = CertBuilder::new()
1016/// # .add_user_attribute(user_attribute)
1017/// # .generate()?;
1018/// # assert_eq!(RevocationStatus::NotAsFarAsWeKnow,
1019/// # cert.revocation_status(p, None));
1020/// #
1021/// // Create and sign a revocation certificate.
1022/// let mut signer = cert.primary_key().key().clone()
1023/// .parts_into_secret()?.into_keypair()?;
1024/// let ua = cert.user_attributes().nth(0).unwrap();
1025/// let sig = UserAttributeRevocationBuilder::new()
1026/// .set_reason_for_revocation(ReasonForRevocation::UIDRetired,
1027/// b"Lost the beard.")?
1028/// .build(&mut signer, &cert, ua.user_attribute(), None)?;
1029///
1030/// // Merge it into the certificate.
1031/// let cert = cert.insert_packets(sig.clone())?.0;
1032///
1033/// // Now it's revoked.
1034/// let ua = cert.user_attributes().nth(0).unwrap();
1035/// if let RevocationStatus::Revoked(revocations) = ua.revocation_status(p, None) {
1036/// assert_eq!(revocations.len(), 1);
1037/// assert_eq!(*revocations[0], sig);
1038/// } else {
1039/// panic!("User Attribute is not revoked.");
1040/// }
1041///
1042/// // But the certificate isn't.
1043/// assert_eq!(RevocationStatus::NotAsFarAsWeKnow,
1044/// cert.revocation_status(p, None));
1045/// # Ok(()) }
1046/// ```
1047pub struct UserAttributeRevocationBuilder {
1048 builder: signature::SignatureBuilder,
1049}
1050assert_send_and_sync!(UserAttributeRevocationBuilder);
1051
1052impl UserAttributeRevocationBuilder {
1053 /// Returns a new `UserAttributeRevocationBuilder`.
1054 ///
1055 /// # Examples
1056 ///
1057 /// ```rust
1058 /// use sequoia_openpgp as openpgp;
1059 /// # use openpgp::Result;
1060 /// use openpgp::cert::prelude::*;
1061 ///
1062 /// # fn main() -> Result<()> {
1063 /// let builder = UserAttributeRevocationBuilder::new();
1064 /// # Ok(())
1065 /// # }
1066 pub fn new() -> Self {
1067 Self {
1068 builder:
1069 signature::SignatureBuilder::new(SignatureType::CertificationRevocation)
1070 }
1071 }
1072
1073 /// Sets the reason for revocation.
1074 ///
1075 /// Note: of the assigned reasons for revocation, only
1076 /// [`ReasonForRevocation::UIDRetired`] is appropriate for User
1077 /// Attributes. This parameter is not fixed, however, to allow
1078 /// the use of the [private name space].
1079 ///
1080 /// [`ReasonForRevocation::UIDRetired`]: crate::types::ReasonForRevocation::UIDRetired
1081 /// [private name space]: crate::types::ReasonForRevocation::Private
1082 ///
1083 /// # Examples
1084 ///
1085 /// Revoke a User Attribute that is no longer valid:
1086 ///
1087 /// ```rust
1088 /// use sequoia_openpgp as openpgp;
1089 /// # use openpgp::Result;
1090 /// use openpgp::cert::prelude::*;
1091 /// use openpgp::types::ReasonForRevocation;
1092 ///
1093 /// # fn main() -> Result<()> {
1094 /// let builder = UserAttributeRevocationBuilder::new()
1095 /// .set_reason_for_revocation(ReasonForRevocation::UIDRetired,
1096 /// b"Lost the beard.");
1097 /// # Ok(())
1098 /// # }
1099 pub fn set_reason_for_revocation(self, code: ReasonForRevocation,
1100 reason: &[u8])
1101 -> Result<Self>
1102 {
1103 Ok(Self {
1104 builder: self.builder.set_reason_for_revocation(code, reason)?
1105 })
1106 }
1107
1108 /// Sets the revocation certificate's creation time.
1109 ///
1110 /// The creation time is interpreted as the time at which the User
1111 /// Attribute should be considered revoked.
1112 ///
1113 /// You'll usually want to set this explicitly and not use the
1114 /// current time. In particular, if a User Attribute is retired,
1115 /// you'll want to set this to the time when the User Attribute
1116 /// was actually retired.
1117 ///
1118 /// # Examples
1119 ///
1120 /// Create a revocation certificate for a User Attribute that was
1121 /// retired yesterday:
1122 ///
1123 /// ```rust
1124 /// use sequoia_openpgp as openpgp;
1125 /// # use openpgp::Result;
1126 /// use openpgp::cert::prelude::*;
1127 ///
1128 /// # fn main() -> Result<()> {
1129 /// # let yesterday = std::time::SystemTime::now();
1130 /// let builder = UserAttributeRevocationBuilder::new()
1131 /// .set_signature_creation_time(yesterday);
1132 /// # Ok(())
1133 /// # }
1134 pub fn set_signature_creation_time(self, creation_time: time::SystemTime)
1135 -> Result<Self>
1136 {
1137 Ok(Self {
1138 builder: self.builder.set_signature_creation_time(creation_time)?
1139 })
1140 }
1141
1142 /// Adds a notation to the revocation certificate.
1143 ///
1144 /// Unlike the [`UserAttributeRevocationBuilder::set_notation`] method, this function
1145 /// does not first remove any existing notation with the specified name.
1146 ///
1147 /// See [`SignatureBuilder::add_notation`] for further documentation.
1148 ///
1149 /// [`SignatureBuilder::add_notation`]: crate::packet::signature::SignatureBuilder::add_notation()
1150 ///
1151 /// # Examples
1152 ///
1153 /// ```rust
1154 /// use sequoia_openpgp as openpgp;
1155 /// # use openpgp::Result;
1156 /// use openpgp::cert::prelude::*;
1157 /// use openpgp::packet::signature::subpacket::NotationDataFlags;
1158 ///
1159 /// # fn main() -> Result<()> {
1160 /// let builder = CertRevocationBuilder::new().add_notation(
1161 /// "revocation-policy@example.org",
1162 /// "https://policy.example.org/cert-revocation-policy",
1163 /// NotationDataFlags::empty().set_human_readable(),
1164 /// false,
1165 /// );
1166 /// # Ok(())
1167 /// # }
1168 pub fn add_notation<N, V, F>(self, name: N, value: V, flags: F,
1169 critical: bool)
1170 -> Result<Self>
1171 where
1172 N: AsRef<str>,
1173 V: AsRef<[u8]>,
1174 F: Into<Option<NotationDataFlags>>,
1175 {
1176 Ok(Self {
1177 builder: self.builder.add_notation(name, value, flags, critical)?
1178 })
1179 }
1180
1181 /// Sets a notation to the revocation certificate.
1182 ///
1183 /// Unlike the [`UserAttributeRevocationBuilder::add_notation`] method, this function
1184 /// first removes any existing notation with the specified name.
1185 ///
1186 /// See [`SignatureBuilder::set_notation`] for further documentation.
1187 ///
1188 /// [`SignatureBuilder::set_notation`]: crate::packet::signature::SignatureBuilder::set_notation()
1189 ///
1190 /// # Examples
1191 ///
1192 /// ```rust
1193 /// use sequoia_openpgp as openpgp;
1194 /// # use openpgp::Result;
1195 /// use openpgp::cert::prelude::*;
1196 /// use openpgp::packet::signature::subpacket::NotationDataFlags;
1197 ///
1198 /// # fn main() -> Result<()> {
1199 /// let builder = CertRevocationBuilder::new().set_notation(
1200 /// "revocation-policy@example.org",
1201 /// "https://policy.example.org/cert-revocation-policy",
1202 /// NotationDataFlags::empty().set_human_readable(),
1203 /// false,
1204 /// );
1205 /// # Ok(())
1206 /// # }
1207 pub fn set_notation<N, V, F>(self, name: N, value: V, flags: F,
1208 critical: bool)
1209 -> Result<Self>
1210 where
1211 N: AsRef<str>,
1212 V: AsRef<[u8]>,
1213 F: Into<Option<NotationDataFlags>>,
1214 {
1215 Ok(Self {
1216 builder: self.builder.set_notation(name, value, flags, critical)?
1217 })
1218 }
1219
1220 /// Returns a signed revocation certificate.
1221 ///
1222 /// A revocation certificate is generated for `cert` and `ua` and
1223 /// signed using `signer` with the specified hash algorithm.
1224 /// Normally, you should pass `None` to select the default hash
1225 /// algorithm.
1226 ///
1227 /// # Examples
1228 ///
1229 /// Revoke a User Attribute, because the identity is no longer
1230 /// valid:
1231 ///
1232 /// ```rust
1233 /// # use openpgp::packet::user_attribute::Subpacket;
1234 /// use sequoia_openpgp as openpgp;
1235 /// # use openpgp::Result;
1236 /// use openpgp::cert::prelude::*;
1237 /// # use openpgp::packet::UserAttribute;
1238 /// use openpgp::policy::StandardPolicy;
1239 /// use openpgp::types::ReasonForRevocation;
1240 /// # use openpgp::types::RevocationStatus;
1241 /// # use openpgp::types::SignatureType;
1242 ///
1243 /// # fn main() -> Result<()> {
1244 /// let p = &StandardPolicy::new();
1245 ///
1246 /// # // Create some user attribute. Doctests do not pass cfg(test),
1247 /// # // so UserAttribute::arbitrary is not available
1248 /// # let sp = Subpacket::Unknown(7, vec![7; 7].into_boxed_slice());
1249 /// # let user_attribute = UserAttribute::new(&[sp])?;
1250 /// #
1251 /// # let (cert, _) = CertBuilder::new()
1252 /// # .add_user_attribute(user_attribute)
1253 /// # .generate()?;
1254 /// // Create and sign a revocation certificate.
1255 /// let mut signer = cert.primary_key().key().clone()
1256 /// .parts_into_secret()?.into_keypair()?;
1257 /// let ua = cert.user_attributes().nth(0).unwrap();
1258 /// let sig = UserAttributeRevocationBuilder::new()
1259 /// .set_reason_for_revocation(ReasonForRevocation::UIDRetired,
1260 /// b"Lost the beard.")?
1261 /// .build(&mut signer, &cert, ua.user_attribute(), None)?;
1262 ///
1263 /// # assert_eq!(sig.typ(), SignatureType::CertificationRevocation);
1264 /// #
1265 /// # // Merge it into the certificate.
1266 /// # let cert = cert.insert_packets(sig.clone())?.0;
1267 /// #
1268 /// # // Now it's revoked.
1269 /// # assert_eq!(RevocationStatus::Revoked(vec![&sig]),
1270 /// # cert.user_attributes().nth(0).unwrap().revocation_status(p, None));
1271 /// # Ok(())
1272 /// # }
1273 pub fn build<H>(mut self, signer: &mut dyn Signer,
1274 cert: &Cert, ua: &UserAttribute,
1275 hash_algo: H)
1276 -> Result<Signature>
1277 where H: Into<Option<HashAlgorithm>>
1278 {
1279 self.builder = self.builder
1280 .set_hash_algo(hash_algo.into().unwrap_or(HashAlgorithm::SHA512));
1281
1282 ua.bind(signer, cert, self.builder)
1283 }
1284}
1285
1286impl TryFrom<signature::SignatureBuilder> for UserAttributeRevocationBuilder {
1287 type Error = anyhow::Error;
1288
1289 fn try_from(builder: signature::SignatureBuilder) -> Result<Self> {
1290 if builder.typ() != SignatureType::CertificationRevocation {
1291 return Err(
1292 crate::Error::InvalidArgument(
1293 format!("Expected signature type to be CertificationRevocation but got {}",
1294 builder.typ())).into());
1295 }
1296 Ok(Self {
1297 builder
1298 })
1299 }
1300}
1301
1302#[cfg(test)]
1303mod tests {
1304 #[test]
1305 fn try_into_cert_revocation_builder_success() -> crate::Result<()> {
1306 use std::convert::TryInto;
1307 use crate as openpgp;
1308 use openpgp::cert::prelude::*;
1309 use openpgp::packet::signature::SignatureBuilder;
1310 use openpgp::cert::CertRevocationBuilder;
1311 use openpgp::types::SignatureType;
1312
1313 let (cert, _) = CertBuilder::new()
1314 .generate()?;
1315
1316 // Create and sign a revocation certificate.
1317 let mut signer = cert.primary_key().key().clone()
1318 .parts_into_secret()?.into_keypair()?;
1319 let builder = SignatureBuilder::new(SignatureType::KeyRevocation);
1320 let revocation_builder: CertRevocationBuilder = builder.try_into()?;
1321 let sig = revocation_builder.build(&mut signer, &cert, None)?;
1322 assert_eq!(sig.typ(), SignatureType::KeyRevocation);
1323 Ok(())
1324 }
1325
1326 #[test]
1327 fn try_into_cert_revocation_builder_failure() -> crate::Result<()> {
1328 use std::convert::TryInto;
1329 use crate as openpgp;
1330 use openpgp::packet::signature::SignatureBuilder;
1331 use openpgp::cert::CertRevocationBuilder;
1332 use openpgp::types::SignatureType;
1333
1334 let builder = SignatureBuilder::new(SignatureType::Binary);
1335 let result: openpgp::Result<CertRevocationBuilder> = builder.try_into();
1336 assert!(result.is_err());
1337 Ok(())
1338 }
1339
1340 #[test]
1341 fn try_into_subkey_revocation_builder_success() -> crate::Result<()> {
1342 use std::convert::TryInto;
1343 use crate as openpgp;
1344 use openpgp::cert::prelude::*;
1345 use openpgp::packet::signature::SignatureBuilder;
1346 use openpgp::cert::SubkeyRevocationBuilder;
1347 use openpgp::types::SignatureType;
1348
1349 let (cert, _) = CertBuilder::new()
1350 .add_transport_encryption_subkey()
1351 .generate()?;
1352
1353 // Create and sign a revocation certificate.
1354 let mut signer = cert.primary_key().key().clone()
1355 .parts_into_secret()?.into_keypair()?;
1356 let subkey = cert.keys().subkeys().nth(0).unwrap();
1357 let builder = SignatureBuilder::new(SignatureType::SubkeyRevocation);
1358 let revocation_builder: SubkeyRevocationBuilder = builder.try_into()?;
1359 let sig = revocation_builder.build(&mut signer, &cert, subkey.key(), None)?;
1360 assert_eq!(sig.typ(), SignatureType::SubkeyRevocation);
1361 Ok(())
1362 }
1363
1364 #[test]
1365 fn try_into_subkey_revocation_builder_failure() -> crate::Result<()> {
1366 use std::convert::TryInto;
1367 use crate as openpgp;
1368 use openpgp::packet::signature::SignatureBuilder;
1369 use openpgp::cert::SubkeyRevocationBuilder;
1370 use openpgp::types::SignatureType;
1371
1372 let builder = SignatureBuilder::new(SignatureType::Binary);
1373 let result: openpgp::Result<SubkeyRevocationBuilder> = builder.try_into();
1374 assert!(result.is_err());
1375 Ok(())
1376 }
1377
1378 #[test]
1379 fn try_into_userid_revocation_builder_success() -> crate::Result<()> {
1380 use std::convert::TryInto;
1381 use crate as openpgp;
1382 use openpgp::cert::prelude::*;
1383 use openpgp::packet::signature::SignatureBuilder;
1384 use openpgp::cert::UserIDRevocationBuilder;
1385 use openpgp::types::SignatureType;
1386
1387 let (cert, _) = CertBuilder::new()
1388 .add_userid("test@example.com")
1389 .generate()?;
1390
1391 // Create and sign a revocation certificate.
1392 let mut signer = cert.primary_key().key().clone()
1393 .parts_into_secret()?.into_keypair()?;
1394 let user_id = cert.userids().next().unwrap().userid();
1395 let builder = SignatureBuilder::new(SignatureType::CertificationRevocation);
1396 let revocation_builder: UserIDRevocationBuilder = builder.try_into()?;
1397 let sig = revocation_builder.build(&mut signer, &cert, user_id, None)?;
1398 assert_eq!(sig.typ(), SignatureType::CertificationRevocation);
1399 Ok(())
1400 }
1401
1402 #[test]
1403 fn try_into_userid_revocation_builder_failure() -> crate::Result<()> {
1404 use std::convert::TryInto;
1405 use crate as openpgp;
1406 use openpgp::packet::signature::SignatureBuilder;
1407 use openpgp::cert::UserIDRevocationBuilder;
1408 use openpgp::types::SignatureType;
1409
1410 let builder = SignatureBuilder::new(SignatureType::Binary);
1411 let result: openpgp::Result<UserIDRevocationBuilder> = builder.try_into();
1412 assert!(result.is_err());
1413 Ok(())
1414 }
1415
1416 #[test]
1417 fn try_into_userattribute_revocation_builder_success() -> crate::Result<()> {
1418 use std::convert::TryInto;
1419 use crate as openpgp;
1420 use openpgp::cert::prelude::*;
1421 use openpgp::packet::prelude::*;
1422 use openpgp::packet::signature::SignatureBuilder;
1423 use openpgp::packet::user_attribute::Subpacket;
1424 use openpgp::cert::UserAttributeRevocationBuilder;
1425 use openpgp::types::SignatureType;
1426
1427 let sp = Subpacket::Unknown(7, vec![7; 7].into_boxed_slice());
1428 let user_attribute = UserAttribute::new(&[sp])?;
1429
1430 let (cert, _) = CertBuilder::new()
1431 .add_user_attribute(user_attribute)
1432 .generate()?;
1433
1434 // Create and sign a revocation certificate.
1435 let mut signer = cert.primary_key().key().clone()
1436 .parts_into_secret()?.into_keypair()?;
1437 let user_attribute =
1438 cert.user_attributes().next().unwrap().user_attribute();
1439 let builder = SignatureBuilder::new(SignatureType::CertificationRevocation);
1440 let revocation_builder: UserAttributeRevocationBuilder = builder.try_into()?;
1441 let sig = revocation_builder.build(&mut signer, &cert, user_attribute, None)?;
1442 assert_eq!(sig.typ(), SignatureType::CertificationRevocation);
1443 Ok(())
1444 }
1445
1446 #[test]
1447 fn try_into_userattribute_revocation_builder_failure() -> crate::Result<()> {
1448 use std::convert::TryInto;
1449 use crate as openpgp;
1450 use openpgp::packet::signature::SignatureBuilder;
1451 use openpgp::cert::UserAttributeRevocationBuilder;
1452 use openpgp::types::SignatureType;
1453
1454 let builder = SignatureBuilder::new(SignatureType::Binary);
1455 let result: openpgp::Result<UserAttributeRevocationBuilder> = builder.try_into();
1456 assert!(result.is_err());
1457 Ok(())
1458 }
1459}