sequoia_openpgp/cert/builder.rs
1use std::time;
2use std::marker::PhantomData;
3
4use crate::packet;
5use crate::packet::{
6 Key,
7 key::Key4,
8 key::Key6,
9 key::UnspecifiedRole,
10 key::SecretKey as KeySecretKey,
11 key::SecretParts as KeySecretParts,
12};
13use crate::Profile;
14use crate::Result;
15use crate::packet::Signature;
16use crate::packet::signature::{
17 self,
18 SignatureBuilder,
19 subpacket::SubpacketTag,
20};
21use crate::cert::prelude::*;
22use crate::Error;
23use crate::crypto::{Password, Signer};
24use crate::types::{
25 Features,
26 HashAlgorithm,
27 KeyFlags,
28 SignatureType,
29 SymmetricAlgorithm,
30 RevocationKey,
31};
32
33mod key;
34pub use key::{
35 KeyBuilder,
36 SubkeyBuilder,
37};
38
39/// Groups symmetric and asymmetric algorithms.
40///
41/// This is used to select a suite of ciphers.
42///
43/// # Examples
44///
45/// ```
46/// use sequoia_openpgp as openpgp;
47/// use openpgp::cert::prelude::*;
48/// use openpgp::types::PublicKeyAlgorithm;
49///
50/// # fn main() -> openpgp::Result<()> {
51/// let (ecc, _) =
52/// CertBuilder::general_purpose(Some("alice@example.org"))
53/// .set_cipher_suite(CipherSuite::Cv25519)
54/// .generate()?;
55/// assert_eq!(ecc.primary_key().key().pk_algo(), PublicKeyAlgorithm::EdDSA);
56///
57/// let (rsa, _) =
58/// CertBuilder::general_purpose(Some("alice@example.org"))
59/// .set_cipher_suite(CipherSuite::RSA4k)
60/// .generate()?;
61/// assert_eq!(rsa.primary_key().key().pk_algo(), PublicKeyAlgorithm::RSAEncryptSign);
62/// # Ok(())
63/// # }
64/// ```
65#[derive(Clone, Copy, PartialEq, Eq, Debug)]
66#[non_exhaustive]
67pub enum CipherSuite {
68 /// EdDSA and ECDH over Curve25519 with SHA512 and AES256
69 Cv25519,
70 /// EdDSA and ECDH over Curve448 with SHA512 and AES256
71 Cv448,
72 /// 3072 bit RSA with SHA512 and AES256
73 RSA3k,
74 /// EdDSA and ECDH over NIST P-256 with SHA256 and AES256
75 P256,
76 /// EdDSA and ECDH over NIST P-384 with SHA384 and AES256
77 P384,
78 /// EdDSA and ECDH over NIST P-521 with SHA512 and AES256
79 P521,
80 /// 2048 bit RSA with SHA512 and AES256
81 RSA2k,
82 /// 4096 bit RSA with SHA512 and AES256
83 RSA4k,
84
85 // If you add a variant here, be sure to update
86 // CipherSuite::variants below.
87}
88assert_send_and_sync!(CipherSuite);
89
90impl Default for CipherSuite {
91 fn default() -> Self {
92 CipherSuite::Cv25519
93 }
94}
95
96impl CipherSuite {
97 /// Returns an iterator over `CipherSuite`'s variants.
98 pub fn variants() -> impl Iterator<Item=CipherSuite> {
99 use CipherSuite::*;
100
101 [ Cv25519, Cv448, RSA3k, P256, P384, P521, RSA2k, RSA4k ]
102 .into_iter()
103 }
104
105 /// Returns whether the currently selected cryptographic backend
106 /// supports the encryption and signing algorithms that the cipher
107 /// suite selects.
108 pub fn is_supported(&self) -> Result<()> {
109 use crate::types::{Curve, PublicKeyAlgorithm};
110 use CipherSuite::*;
111
112 macro_rules! check_pk {
113 ($pk: expr) => {
114 if ! $pk.is_supported() {
115 return Err(Error::UnsupportedPublicKeyAlgorithm($pk)
116 .into());
117 }
118 }
119 }
120
121 macro_rules! check_curve {
122 ($curve: expr) => {
123 if ! $curve.is_supported() {
124 return Err(Error::UnsupportedEllipticCurve($curve)
125 .into());
126 }
127 }
128 }
129
130 match self {
131 Cv25519 => {
132 check_pk!(PublicKeyAlgorithm::EdDSA);
133 check_curve!(Curve::Ed25519);
134 check_pk!(PublicKeyAlgorithm::ECDH);
135 check_curve!(Curve::Cv25519);
136 },
137 Cv448 => {
138 check_pk!(PublicKeyAlgorithm::X448);
139 check_pk!(PublicKeyAlgorithm::Ed448);
140 },
141 RSA2k | RSA3k | RSA4k => {
142 check_pk!(PublicKeyAlgorithm::RSAEncryptSign);
143 },
144 P256 => {
145 check_pk!(PublicKeyAlgorithm::ECDSA);
146 check_curve!(Curve::NistP256);
147 check_pk!(PublicKeyAlgorithm::ECDH);
148 },
149 P384 => {
150 check_pk!(PublicKeyAlgorithm::ECDSA);
151 check_curve!(Curve::NistP384);
152 check_pk!(PublicKeyAlgorithm::ECDH);
153 },
154 P521 => {
155 check_pk!(PublicKeyAlgorithm::ECDSA);
156 check_curve!(Curve::NistP521);
157 check_pk!(PublicKeyAlgorithm::ECDH);
158 },
159 }
160 Ok(())
161 }
162
163 fn generate_key<K>(self, flags: K, profile: Profile)
164 -> Result<Key<KeySecretParts, UnspecifiedRole>>
165 where K: AsRef<KeyFlags>,
166 {
167 match profile {
168 Profile::RFC9580 => Ok(self.generate_v6_key(flags)?.into()),
169 Profile::RFC4880 => Ok(self.generate_v4_key(flags)?.into()),
170 }
171 }
172
173 fn generate_v4_key<K>(self, flags: K)
174 -> Result<Key4<KeySecretParts, UnspecifiedRole>>
175 where K: AsRef<KeyFlags>,
176 {
177 use crate::types::Curve;
178
179 match self {
180 CipherSuite::RSA2k =>
181 Key4::generate_rsa(2048),
182 CipherSuite::RSA3k =>
183 Key4::generate_rsa(3072),
184 CipherSuite::RSA4k =>
185 Key4::generate_rsa(4096),
186 CipherSuite::Cv448 => {
187 let flags = flags.as_ref();
188 let sign = flags.for_certification() || flags.for_signing()
189 || flags.for_authentication();
190 let encrypt = flags.for_transport_encryption()
191 || flags.for_storage_encryption();
192 match (sign, encrypt) {
193 (true, false) => Key4::generate_ed448(),
194 (false, true) => Key4::generate_x448(),
195 (true, true) =>
196 Err(Error::InvalidOperation(
197 "Can't use key for encryption and signing".into())
198 .into()),
199 (false, false) =>
200 Err(Error::InvalidOperation(
201 "No key flags set".into())
202 .into()),
203 }
204 }
205 CipherSuite::Cv25519 | CipherSuite::P256 |
206 CipherSuite::P384 | CipherSuite::P521 => {
207 let flags = flags.as_ref();
208 let sign = flags.for_certification() || flags.for_signing()
209 || flags.for_authentication();
210 let encrypt = flags.for_transport_encryption()
211 || flags.for_storage_encryption();
212 let curve = match self {
213 CipherSuite::Cv25519 if sign => Curve::Ed25519,
214 CipherSuite::Cv25519 if encrypt => Curve::Cv25519,
215 CipherSuite::Cv25519 => {
216 return Err(Error::InvalidOperation(
217 "No key flags set".into())
218 .into());
219 }
220 CipherSuite::P256 => Curve::NistP256,
221 CipherSuite::P384 => Curve::NistP384,
222 CipherSuite::P521 => Curve::NistP521,
223 _ => unreachable!(),
224 };
225
226 match (sign, encrypt) {
227 (true, false) => Key4::generate_ecc(true, curve),
228 (false, true) => Key4::generate_ecc(false, curve),
229 (true, true) =>
230 Err(Error::InvalidOperation(
231 "Can't use key for encryption and signing".into())
232 .into()),
233 (false, false) =>
234 Err(Error::InvalidOperation(
235 "No key flags set".into())
236 .into()),
237 }
238 },
239 }
240 }
241
242 fn generate_v6_key<K>(self, flags: K)
243 -> Result<Key6<KeySecretParts, UnspecifiedRole>>
244 where K: AsRef<KeyFlags>,
245 {
246 use crate::types::Curve;
247
248 let flags = flags.as_ref();
249 let sign = flags.for_certification() || flags.for_signing()
250 || flags.for_authentication();
251 let encrypt = flags.for_transport_encryption()
252 || flags.for_storage_encryption();
253
254 match self {
255 CipherSuite::Cv25519 => match (sign, encrypt) {
256 (true, false) => Key6::generate_ed25519(),
257 (false, true) => Key6::generate_x25519(),
258 (true, true) =>
259 Err(Error::InvalidOperation(
260 "Can't use key for encryption and signing".into())
261 .into()),
262 (false, false) =>
263 Err(Error::InvalidOperation(
264 "No key flags set".into())
265 .into()),
266 },
267 CipherSuite::RSA2k =>
268 Key6::generate_rsa(2048),
269 CipherSuite::RSA3k =>
270 Key6::generate_rsa(3072),
271 CipherSuite::RSA4k =>
272 Key6::generate_rsa(4096),
273 CipherSuite::Cv448 => match (sign, encrypt) {
274 (true, false) => Key6::generate_ed448(),
275 (false, true) => Key6::generate_x448(),
276 (true, true) =>
277 Err(Error::InvalidOperation(
278 "Can't use key for encryption and signing".into())
279 .into()),
280 (false, false) =>
281 Err(Error::InvalidOperation(
282 "No key flags set".into())
283 .into()),
284 },
285 CipherSuite::P256 | CipherSuite::P384 | CipherSuite::P521 => {
286 let curve = match self {
287 CipherSuite::Cv25519 if sign => Curve::Ed25519,
288 CipherSuite::Cv25519 if encrypt => Curve::Cv25519,
289 CipherSuite::Cv25519 => {
290 return Err(Error::InvalidOperation(
291 "No key flags set".into())
292 .into());
293 }
294 CipherSuite::P256 => Curve::NistP256,
295 CipherSuite::P384 => Curve::NistP384,
296 CipherSuite::P521 => Curve::NistP521,
297 _ => unreachable!(),
298 };
299
300 match (sign, encrypt) {
301 (true, false) => Key6::generate_ecc(true, curve),
302 (false, true) => Key6::generate_ecc(false, curve),
303 (true, true) =>
304 Err(Error::InvalidOperation(
305 "Can't use key for encryption and signing".into())
306 .into()),
307 (false, false) =>
308 Err(Error::InvalidOperation(
309 "No key flags set".into())
310 .into()),
311 }
312 },
313 }
314 }
315}
316
317#[derive(Clone, Debug)]
318pub struct KeyBlueprint {
319 flags: KeyFlags,
320 validity: Option<time::Duration>,
321 // If not None, uses the specified ciphersuite. Otherwise, uses
322 // CertBuilder::ciphersuite.
323 ciphersuite: Option<CipherSuite>,
324}
325assert_send_and_sync!(KeyBlueprint);
326
327/// Simplifies the generation of OpenPGP certificates.
328///
329/// A builder to generate complex certificate hierarchies with multiple
330/// [`UserID`s], [`UserAttribute`s], and [`Key`s].
331///
332/// This builder does not aim to be as flexible as creating
333/// certificates manually, but it should be sufficiently powerful to
334/// cover most use cases.
335///
336/// [`UserID`s]: crate::packet::UserID
337/// [`UserAttribute`s]: crate::packet::user_attribute::UserAttribute
338/// [`Key`s]: crate::packet::Key
339///
340/// # Security considerations
341///
342/// ## Expiration
343///
344/// There are two ways to invalidate cryptographic key material:
345/// revocation and freshness. Both variants come with their own
346/// challenges. Revocations rely on a robust channel to update
347/// certificates (and attackers may interfere with that).
348///
349/// On the other hand, freshness involves creating key material that
350/// expires after a certain time, then periodically extending the
351/// expiration time. Again, consumers need a way to update
352/// certificates, but should that fail (maybe because it was
353/// interfered with), the consumer errs on the side of no longer
354/// trusting that key material.
355///
356/// Because of the way metadata is added to OpenPGP certificates,
357/// attackers who control the certificate lookup and update mechanism
358/// may strip components like signatures from the certificate. This
359/// has implications for the robustness of relying on freshness.
360///
361/// If you first create a certificate that does not expire, and then
362/// change your mind and set an expiration time, an attacker can
363/// simply strip off that update, yielding the original certificate
364/// that does not expire.
365///
366/// Hence, to ensure robust key expiration, you must set an expiration
367/// with [`CertBuilder::set_validity_period`] when you create the
368/// certificate.
369///
370/// By default, the `CertBuilder` creates certificates that do not
371/// expire, because the expiration time is a policy decision and
372/// depends on the use case. For general purpose certificates,
373/// [`CertBuilder::general_purpose`] sets the validity period to
374/// roughly three years.
375///
376/// # Examples
377///
378/// Generate a general-purpose certificate with one User ID:
379///
380/// ```
381/// use sequoia_openpgp as openpgp;
382/// use openpgp::cert::prelude::*;
383///
384/// # fn main() -> openpgp::Result<()> {
385/// let (cert, rev) =
386/// CertBuilder::general_purpose(Some("alice@example.org"))
387/// .generate()?;
388/// # Ok(())
389/// # }
390/// ```
391pub struct CertBuilder<'a> {
392 creation_time: Option<std::time::SystemTime>,
393 ciphersuite: CipherSuite,
394 profile: Profile,
395
396 /// Advertised features.
397 features: Features,
398 primary: KeyBlueprint,
399 subkeys: Vec<(Option<SignatureBuilder>, KeyBlueprint)>,
400 userids: Vec<(Option<SignatureBuilder>, packet::UserID)>,
401 user_attributes: Vec<(Option<SignatureBuilder>, packet::UserAttribute)>,
402 password: Option<Password>,
403 revocation_keys: Option<Vec<RevocationKey>>,
404 exportable: bool,
405 phantom: PhantomData<&'a ()>,
406}
407assert_send_and_sync!(CertBuilder<'_>);
408
409impl CertBuilder<'_> {
410 /// Returns a new `CertBuilder`.
411 ///
412 /// The returned builder is configured to generate a minimal
413 /// OpenPGP certificate, a certificate with just a
414 /// certification-capable primary key. You'll typically want to
415 /// add at least one User ID (using
416 /// [`CertBuilder::add_userid`]). and some subkeys (using
417 /// [`CertBuilder::add_signing_subkey`],
418 /// [`CertBuilder::add_transport_encryption_subkey`], etc.).
419 ///
420 /// By default, the generated certificate does not expire. It is
421 /// recommended to set a suitable validity period using
422 /// [`CertBuilder::set_validity_period`]. See [this
423 /// section](CertBuilder#expiration) of the type's documentation
424 /// for security considerations of key expiration.
425 ///
426 /// # Examples
427 ///
428 /// ```
429 /// use sequoia_openpgp as openpgp;
430 /// use openpgp::cert::prelude::*;
431 ///
432 /// # fn main() -> openpgp::Result<()> {
433 /// let (cert, rev) =
434 /// CertBuilder::new()
435 /// .add_userid("Alice Lovelace <alice@lovelace.name>")
436 /// .add_signing_subkey()
437 /// .add_transport_encryption_subkey()
438 /// .add_storage_encryption_subkey()
439 /// .generate()?;
440 /// # assert_eq!(cert.keys().count(), 1 + 3);
441 /// # assert_eq!(cert.userids().count(), 1);
442 /// # assert_eq!(cert.user_attributes().count(), 0);
443 /// # Ok(())
444 /// # }
445 /// ```
446 pub fn new() -> Self {
447 CertBuilder {
448 creation_time: None,
449 ciphersuite: CipherSuite::default(),
450 profile: Default::default(),
451 features: Features::sequoia(),
452 primary: KeyBlueprint{
453 flags: KeyFlags::empty().set_certification(),
454 validity: None,
455 ciphersuite: None,
456 },
457 subkeys: vec![],
458 userids: vec![],
459 user_attributes: vec![],
460 password: None,
461 revocation_keys: None,
462 exportable: true,
463 phantom: PhantomData,
464 }
465 }
466
467 /// Generates a general-purpose certificate.
468 ///
469 /// The returned builder is set to generate a certificate with a
470 /// certification-capable primary key, a signing-capable subkey,
471 /// and an encryption-capable subkey. The encryption subkey is
472 /// marked as being appropriate for both data in transit and data
473 /// at rest.
474 ///
475 /// The certificate and all subkeys are valid for approximately
476 /// three years.
477 ///
478 /// # Examples
479 ///
480 /// ```
481 /// use sequoia_openpgp as openpgp;
482 /// use openpgp::cert::prelude::*;
483 ///
484 /// # fn main() -> openpgp::Result<()> {
485 /// let (cert, rev) =
486 /// CertBuilder::general_purpose(["Alice Lovelace", "<alice@example.org>"])
487 /// .generate()?;
488 /// # assert_eq!(cert.keys().count(), 3);
489 /// # assert_eq!(cert.userids().count(), 2);
490 ///
491 /// let (cert, rev) =
492 /// CertBuilder::general_purpose(["Alice Lovelace <alice@example.org>"])
493 /// .generate()?;
494 /// # assert_eq!(cert.keys().count(), 3);
495 /// # assert_eq!(cert.userids().count(), 1);
496 /// # Ok(())
497 /// # }
498 /// ```
499 pub fn general_purpose<U>(userids: U) -> Self
500 where
501 U: IntoIterator,
502 U::Item: Into<packet::UserID>,
503 {
504 let mut builder = Self::new()
505 .set_primary_key_flags(KeyFlags::empty().set_certification())
506 .set_validity_period(
507 time::Duration::new(3 * 52 * 7 * 24 * 60 * 60, 0))
508 .add_signing_subkey()
509 .add_subkey(KeyFlags::empty()
510 .set_transport_encryption()
511 .set_storage_encryption(), None, None);
512
513 for u in userids {
514 builder = builder.add_userid(u.into());
515 }
516
517 builder
518 }
519
520 /// Sets the creation time.
521 ///
522 /// If `creation_time` is not `None`, this causes the
523 /// `CertBuilder` to use that time when [`CertBuilder::generate`]
524 /// is called. If it is `None`, the default, then the current
525 /// time minus 60 seconds is used as creation time. Backdating
526 /// the certificate by a minute has the advantage that the
527 /// certificate can immediately be customized:
528 ///
529 /// In order to reliably override a binding signature, the
530 /// overriding binding signature must be newer than the existing
531 /// signature. If, however, the existing signature is created
532 /// `now`, any newer signature must have a future creation time,
533 /// and is considered invalid by Sequoia. To avoid this, we
534 /// backdate certificate creation times (and hence binding
535 /// signature creation times), so that there is "space" between
536 /// the creation time and now for signature updates.
537 ///
538 /// Warning: this function takes a [`SystemTime`]. A `SystemTime`
539 /// has a higher resolution, and a larger range than an OpenPGP
540 /// [`Timestamp`]. Assuming the `creation_time` is in range, it
541 /// will automatically be truncated to the nearest time that is
542 /// representable by a `Timestamp`. If it is not in range,
543 /// [`generate`] will return an error.
544 ///
545 /// [`CertBuilder::generate`]: CertBuilder::generate()
546 /// [`SystemTime`]: std::time::SystemTime
547 /// [`Timestamp`]: crate::types::Timestamp
548 /// [`generate`]: CertBuilder::generate()
549 ///
550 /// # Examples
551 ///
552 /// Generate a backdated certificate:
553 ///
554 /// ```
555 /// use std::time::{SystemTime, Duration};
556 /// use std::convert::TryFrom;
557 ///
558 /// use sequoia_openpgp as openpgp;
559 /// use openpgp::cert::prelude::*;
560 /// use openpgp::types::Timestamp;
561 ///
562 /// # fn main() -> openpgp::Result<()> {
563 /// let t = SystemTime::now() - Duration::from_secs(365 * 24 * 60 * 60);
564 /// // Roundtrip the time so that the assert below works.
565 /// let t = SystemTime::from(Timestamp::try_from(t)?);
566 ///
567 /// let (cert, rev) =
568 /// CertBuilder::general_purpose(Some("Alice Lovelace <alice@example.org>"))
569 /// .set_creation_time(t)
570 /// .generate()?;
571 /// assert_eq!(cert.primary_key().self_signatures().nth(0).unwrap()
572 /// .signature_creation_time(),
573 /// Some(t));
574 /// # Ok(())
575 /// # }
576 /// ```
577 pub fn set_creation_time<T>(mut self, creation_time: T) -> Self
578 where T: Into<Option<std::time::SystemTime>>,
579 {
580 self.creation_time = creation_time.into();
581 self
582 }
583
584 /// Returns the configured creation time, if any.
585 ///
586 /// # Examples
587 ///
588 /// ```
589 /// use std::time::SystemTime;
590 ///
591 /// use sequoia_openpgp as openpgp;
592 /// use openpgp::cert::prelude::*;
593 ///
594 /// # fn main() -> openpgp::Result<()> {
595 /// let mut builder = CertBuilder::new();
596 /// assert!(builder.creation_time().is_none());
597 ///
598 /// let now = std::time::SystemTime::now();
599 /// builder = builder.set_creation_time(Some(now));
600 /// assert_eq!(builder.creation_time(), Some(now));
601 ///
602 /// builder = builder.set_creation_time(None);
603 /// assert!(builder.creation_time().is_none());
604 /// # Ok(())
605 /// # }
606 /// ```
607 pub fn creation_time(&self) -> Option<std::time::SystemTime>
608 {
609 self.creation_time
610 }
611
612 /// Sets the default asymmetric algorithms.
613 ///
614 /// This method controls the set of algorithms that is used to
615 /// generate the certificate's keys.
616 ///
617 /// # Examples
618 ///
619 /// ```
620 /// use sequoia_openpgp as openpgp;
621 /// use openpgp::cert::prelude::*;
622 /// use openpgp::types::PublicKeyAlgorithm;
623 ///
624 /// # fn main() -> openpgp::Result<()> {
625 /// let (ecc, _) =
626 /// CertBuilder::general_purpose(Some("alice@example.org"))
627 /// .set_cipher_suite(CipherSuite::Cv25519)
628 /// .generate()?;
629 /// assert_eq!(ecc.primary_key().key().pk_algo(), PublicKeyAlgorithm::EdDSA);
630 ///
631 /// let (rsa, _) =
632 /// CertBuilder::general_purpose(Some("alice@example.org"))
633 /// .set_cipher_suite(CipherSuite::RSA2k)
634 /// .generate()?;
635 /// assert_eq!(rsa.primary_key().key().pk_algo(), PublicKeyAlgorithm::RSAEncryptSign);
636 /// # Ok(())
637 /// # }
638 /// ```
639 pub fn set_cipher_suite(mut self, cs: CipherSuite) -> Self {
640 self.ciphersuite = cs;
641 self
642 }
643
644 /// Sets whether the certificate is exportable.
645 ///
646 /// This method controls whether the certificate is exportable.
647 /// If the certificate builder is configured to make a
648 /// non-exportable certificate, then all the signatures that it
649 /// creates include the [Exportable Certification] subpacket
650 /// that is set to `false`.
651 ///
652 /// [Exportable Certification]: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.19
653 ///
654 /// # Examples
655 ///
656 /// When exporting a non-exportable certificate, nothing will be
657 /// exported. This is also the case when the output is ASCII
658 /// armored.
659 ///
660 /// ```
661 /// use sequoia_openpgp as openpgp;
662 /// use openpgp::Result;
663 /// use openpgp::cert::prelude::*;
664 /// use openpgp::parse::Parse;
665 /// use openpgp::serialize::Serialize;
666 ///
667 /// # fn main() -> openpgp::Result<()> {
668 /// let (cert, _) =
669 /// CertBuilder::general_purpose(Some("alice@example.org"))
670 /// .set_exportable(false)
671 /// .generate()?;
672 /// let mut exported = Vec::new();
673 /// cert.armored().export(&mut exported)?;
674 ///
675 /// let certs = CertParser::from_bytes(&exported)?
676 /// .collect::<Result<Vec<Cert>>>()?;
677 /// assert_eq!(certs.len(), 0);
678 /// assert_eq!(exported.len(), 0, "{}", String::from_utf8_lossy(&exported));
679 /// # Ok(())
680 /// # }
681 /// ```
682 pub fn set_exportable(mut self, exportable: bool) -> Self {
683 self.exportable = exportable;
684 self
685 }
686
687 /// Sets the version of OpenPGP to generate keys for.
688 ///
689 /// Supported are [`Profile::RFC9580`] which will generate version
690 /// 6 keys, and [`Profile::RFC4880`] which will version 4 keys.
691 /// By default, we generate version 6 keys.
692 ///
693 /// # Examples
694 ///
695 /// ```
696 /// use sequoia_openpgp as openpgp;
697 /// use openpgp::cert::prelude::*;
698 ///
699 /// # fn main() -> openpgp::Result<()> {
700 /// let (key, _) =
701 /// CertBuilder::general_purpose(Some("alice@example.org"))
702 /// .set_profile(openpgp::Profile::RFC9580)?
703 /// .generate()?;
704 /// assert_eq!(key.primary_key().key().version(), 6);
705 ///
706 /// let (key, _) =
707 /// CertBuilder::general_purpose(Some("bob@example.org"))
708 /// .set_profile(openpgp::Profile::RFC4880)?
709 /// .generate()?;
710 /// assert_eq!(key.primary_key().key().version(), 4);
711 /// # Ok(())
712 /// # }
713 /// ```
714 pub fn set_profile(mut self, profile: Profile) -> Result<Self> {
715 self.profile = profile;
716 Ok(self)
717 }
718
719 /// Sets the features the certificate will advertise.
720 ///
721 /// # Examples
722 ///
723 /// ```
724 /// use sequoia_openpgp as openpgp;
725 /// use openpgp::cert::prelude::*;
726 /// use openpgp::types::Features;
727 ///
728 /// # fn main() -> openpgp::Result<()> {
729 /// let (key, _) =
730 /// CertBuilder::general_purpose(Some("alice@example.org"))
731 /// .set_profile(openpgp::Profile::RFC9580)?
732 /// .generate()?;
733 /// assert_eq!(key.primary_key().key().version(), 6);
734 ///
735 /// // Bob is old-school: he needs this key to work on an old
736 /// // phone. Therefore, he doesn't want to get SEIPDv2 messages,
737 /// // which his phone doesn't handle. He advertises support for
738 /// // SEIPDv1 only.
739 /// let (key, _) =
740 /// CertBuilder::general_purpose(Some("bob@example.org"))
741 /// .set_profile(openpgp::Profile::RFC4880)?
742 /// .set_features(Features::empty().set_seipdv1())?
743 /// .generate()?;
744 /// assert_eq!(key.primary_key().key().version(), 4);
745 /// # Ok(())
746 /// # }
747 /// ```
748 pub fn set_features(mut self, features: Features) -> Result<Self> {
749 self.features = features;
750 Ok(self)
751 }
752
753 /// Adds a User ID.
754 ///
755 /// Adds a User ID to the certificate. The first User ID that is
756 /// added, whether via this interface or another interface, e.g.,
757 /// [`CertBuilder::general_purpose`], will have the [primary User
758 /// ID flag] set.
759 ///
760 /// [`CertBuilder::general_purpose`]: CertBuilder::general_purpose()
761 /// [primary User ID flag]: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.27
762 ///
763 /// # Examples
764 ///
765 /// ```
766 /// use sequoia_openpgp as openpgp;
767 /// use openpgp::cert::prelude::*;
768 /// use openpgp::packet::prelude::*;
769 /// use openpgp::policy::StandardPolicy;
770 ///
771 /// # fn main() -> openpgp::Result<()> {
772 /// let p = &StandardPolicy::new();
773 ///
774 /// let (cert, rev) =
775 /// CertBuilder::general_purpose(Some("Alice Lovelace <alice@example.org>"))
776 /// .add_userid("Alice Lovelace <alice@lovelace.name>")
777 /// .generate()?;
778 ///
779 /// assert_eq!(cert.userids().count(), 2);
780 /// let mut userids = cert.with_policy(p, None)?.userids().collect::<Vec<_>>();
781 /// // Sort lexicographically.
782 /// userids.sort_by(|a, b| a.userid().value().cmp(b.userid().value()));
783 /// assert_eq!(userids[0].userid(),
784 /// &UserID::from("Alice Lovelace <alice@example.org>"));
785 /// assert_eq!(userids[1].userid(),
786 /// &UserID::from("Alice Lovelace <alice@lovelace.name>"));
787 ///
788 ///
789 /// assert_eq!(userids[0].binding_signature().primary_userid().unwrap_or(false), true);
790 /// assert_eq!(userids[1].binding_signature().primary_userid().unwrap_or(false), false);
791 /// # Ok(())
792 /// # }
793 /// ```
794 pub fn add_userid<U>(mut self, uid: U) -> Self
795 where U: Into<packet::UserID>
796 {
797 self.userids.push((None, uid.into()));
798 self
799 }
800
801 /// Adds a User ID with a binding signature based on `builder`.
802 ///
803 /// Adds a User ID to the certificate, creating the binding
804 /// signature using `builder`. The `builder`s signature type must
805 /// be a certification signature (i.e. either
806 /// [`GenericCertification`], [`PersonaCertification`],
807 /// [`CasualCertification`], or [`PositiveCertification`]).
808 ///
809 /// The key generation step uses `builder` as a template, but
810 /// tweaks it so the signature is a valid binding signature. If
811 /// you need more control, consider using
812 /// [`UserID::bind`](crate::packet::UserID::bind).
813 ///
814 /// The following modifications are performed on `builder`:
815 ///
816 /// - An appropriate hash algorithm is selected.
817 ///
818 /// - The creation time is set.
819 ///
820 /// - Primary key metadata is added (key flags, key validity period).
821 ///
822 /// - Certificate metadata is added (feature flags, algorithm
823 /// preferences).
824 ///
825 /// - The [`CertBuilder`] marks exactly one User ID or User
826 /// Attribute as primary: The first one provided to
827 /// [`CertBuilder::add_userid_with`] or
828 /// [`CertBuilder::add_user_attribute_with`] (the UserID takes
829 /// precedence) that is marked as primary, or the first User
830 /// ID or User Attribute added to the [`CertBuilder`].
831 ///
832 /// [`GenericCertification`]: crate::types::SignatureType::GenericCertification
833 /// [`PersonaCertification`]: crate::types::SignatureType::PersonaCertification
834 /// [`CasualCertification`]: crate::types::SignatureType::CasualCertification
835 /// [`PositiveCertification`]: crate::types::SignatureType::PositiveCertification
836 /// [primary User ID flag]: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.27
837 ///
838 /// # Examples
839 ///
840 /// This example very casually binds a User ID to a certificate.
841 ///
842 /// ```
843 /// # fn main() -> sequoia_openpgp::Result<()> {
844 /// # use sequoia_openpgp as openpgp;
845 /// # use openpgp::cert::prelude::*;
846 /// # use openpgp::packet::{prelude::*, signature::subpacket::*};
847 /// # use openpgp::policy::StandardPolicy;
848 /// # use openpgp::types::*;
849 /// # let policy = &StandardPolicy::new();
850 /// #
851 /// let (cert, revocation_cert) =
852 /// CertBuilder::general_purpose(
853 /// Some("Alice Lovelace <alice@example.org>"))
854 /// .add_userid_with(
855 /// "trinity",
856 /// SignatureBuilder::new(SignatureType::CasualCertification)
857 /// .set_notation("rabbit@example.org", b"follow me",
858 /// NotationDataFlags::empty().set_human_readable(),
859 /// false)?)?
860 /// .generate()?;
861 ///
862 /// assert_eq!(cert.userids().count(), 2);
863 /// let mut userids = cert.with_policy(policy, None)?.userids().collect::<Vec<_>>();
864 /// // Sort lexicographically.
865 /// userids.sort_by(|a, b| a.userid().value().cmp(b.userid().value()));
866 /// assert_eq!(userids[0].userid(),
867 /// &UserID::from("Alice Lovelace <alice@example.org>"));
868 /// assert_eq!(userids[1].userid(),
869 /// &UserID::from("trinity"));
870 ///
871 /// assert!(userids[0].binding_signature().primary_userid().unwrap_or(false));
872 /// assert!(! userids[1].binding_signature().primary_userid().unwrap_or(false));
873 /// assert_eq!(userids[1].binding_signature().notation("rabbit@example.org")
874 /// .next().unwrap(), b"follow me");
875 /// # Ok(()) }
876 /// ```
877 pub fn add_userid_with<U, B>(mut self, uid: U, builder: B)
878 -> Result<Self>
879 where U: Into<packet::UserID>,
880 B: Into<SignatureBuilder>,
881 {
882 let builder = builder.into();
883 match builder.typ() {
884 SignatureType::GenericCertification
885 | SignatureType::PersonaCertification
886 | SignatureType::CasualCertification
887 | SignatureType::PositiveCertification =>
888 {
889 self.userids.push((Some(builder), uid.into()));
890 Ok(self)
891 },
892 t =>
893 Err(Error::InvalidArgument(format!(
894 "Signature type is not a certification: {}", t)).into()),
895 }
896 }
897
898 /// Adds a new User Attribute.
899 ///
900 /// Adds a User Attribute to the certificate. If there are no
901 /// User IDs, the first User attribute that is added, whether via
902 /// this interface or another interface, will have the [primary
903 /// User ID flag] set.
904 ///
905 /// [primary User ID flag]: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.27
906 ///
907 /// # Examples
908 ///
909 /// When there are no User IDs, the first User Attribute has the
910 /// primary User ID flag set:
911 ///
912 /// ```
913 /// # use openpgp::packet::user_attribute::Subpacket;
914 /// use sequoia_openpgp as openpgp;
915 /// use openpgp::cert::prelude::*;
916 /// use openpgp::packet::prelude::*;
917 /// use openpgp::policy::StandardPolicy;
918 ///
919 /// # fn main() -> openpgp::Result<()> {
920 /// let p = &StandardPolicy::new();
921 /// #
922 /// # // Create some user attribute. Doctests do not pass cfg(test),
923 /// # // so UserAttribute::arbitrary is not available
924 /// # let sp = Subpacket::Unknown(7, vec![7; 7].into_boxed_slice());
925 /// # let user_attribute = UserAttribute::new(&[sp])?;
926 ///
927 /// let (cert, rev) =
928 /// CertBuilder::new()
929 /// .add_user_attribute(user_attribute)
930 /// .generate()?;
931 ///
932 /// assert_eq!(cert.userids().count(), 0);
933 /// assert_eq!(cert.user_attributes().count(), 1);
934 /// let mut uas = cert.with_policy(p, None)?.user_attributes().collect::<Vec<_>>();
935 /// assert_eq!(uas[0].binding_signature().primary_userid().unwrap_or(false), true);
936 /// # Ok(())
937 /// # }
938 /// ```
939 ///
940 /// Where there are User IDs, then the primary User ID flag is not
941 /// set:
942 ///
943 /// ```
944 /// # use openpgp::packet::user_attribute::Subpacket;
945 /// use sequoia_openpgp as openpgp;
946 /// use openpgp::cert::prelude::*;
947 /// use openpgp::packet::prelude::*;
948 /// use openpgp::policy::StandardPolicy;
949 ///
950 /// # fn main() -> openpgp::Result<()> {
951 /// let p = &StandardPolicy::new();
952 /// #
953 /// # // Create some user attribute. Doctests do not pass cfg(test),
954 /// # // so UserAttribute::arbitrary is not available
955 /// # let sp = Subpacket::Unknown(7, vec![7; 7].into_boxed_slice());
956 /// # let user_attribute = UserAttribute::new(&[sp])?;
957 ///
958 /// let (cert, rev) =
959 /// CertBuilder::new()
960 /// .add_userid("alice@example.org")
961 /// .add_user_attribute(user_attribute)
962 /// .generate()?;
963 ///
964 /// assert_eq!(cert.userids().count(), 1);
965 /// assert_eq!(cert.user_attributes().count(), 1);
966 /// let mut uas = cert.with_policy(p, None)?.user_attributes().collect::<Vec<_>>();
967 /// assert_eq!(uas[0].binding_signature().primary_userid().unwrap_or(false), false);
968 /// # Ok(())
969 /// # }
970 /// ```
971 pub fn add_user_attribute<U>(mut self, ua: U) -> Self
972 where U: Into<packet::UserAttribute>
973 {
974 self.user_attributes.push((None, ua.into()));
975 self
976 }
977
978 /// Adds a User Attribute with a binding signature based on `builder`.
979 ///
980 /// Adds a User Attribute to the certificate, creating the binding
981 /// signature using `builder`. The `builder`s signature type must
982 /// be a certification signature (i.e. either
983 /// [`GenericCertification`], [`PersonaCertification`],
984 /// [`CasualCertification`], or [`PositiveCertification`]).
985 ///
986 /// The key generation step uses `builder` as a template, but
987 /// tweaks it so the signature is a valid binding signature. If
988 /// you need more control, consider using
989 /// [`UserAttribute::bind`](crate::packet::UserAttribute::bind).
990 ///
991 /// The following modifications are performed on `builder`:
992 ///
993 /// - An appropriate hash algorithm is selected.
994 ///
995 /// - The creation time is set.
996 ///
997 /// - Primary key metadata is added (key flags, key validity period).
998 ///
999 /// - Certificate metadata is added (feature flags, algorithm
1000 /// preferences).
1001 ///
1002 /// - The [`CertBuilder`] marks exactly one User ID or User
1003 /// Attribute as primary: The first one provided to
1004 /// [`CertBuilder::add_userid_with`] or
1005 /// [`CertBuilder::add_user_attribute_with`] (the UserID takes
1006 /// precedence) that is marked as primary, or the first User
1007 /// ID or User Attribute added to the [`CertBuilder`].
1008 ///
1009 /// [`GenericCertification`]: crate::types::SignatureType::GenericCertification
1010 /// [`PersonaCertification`]: crate::types::SignatureType::PersonaCertification
1011 /// [`CasualCertification`]: crate::types::SignatureType::CasualCertification
1012 /// [`PositiveCertification`]: crate::types::SignatureType::PositiveCertification
1013 /// [primary User ID flag]: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.27
1014 ///
1015 /// # Examples
1016 ///
1017 /// This example very casually binds a user attribute to a
1018 /// certificate.
1019 ///
1020 /// ```
1021 /// # fn main() -> sequoia_openpgp::Result<()> {
1022 /// # use sequoia_openpgp as openpgp;
1023 /// # use openpgp::packet::user_attribute::Subpacket;
1024 /// # use openpgp::cert::prelude::*;
1025 /// # use openpgp::packet::{prelude::*, signature::subpacket::*};
1026 /// # use openpgp::policy::StandardPolicy;
1027 /// # use openpgp::types::*;
1028 /// #
1029 /// # let policy = &StandardPolicy::new();
1030 /// #
1031 /// # // Create some user attribute. Doctests do not pass cfg(test),
1032 /// # // so UserAttribute::arbitrary is not available
1033 /// # let user_attribute =
1034 /// # UserAttribute::new(&[Subpacket::Unknown(7, vec![7; 7].into())])?;
1035 /// let (cert, revocation_cert) =
1036 /// CertBuilder::general_purpose(
1037 /// Some("Alice Lovelace <alice@example.org>"))
1038 /// .add_user_attribute_with(
1039 /// user_attribute,
1040 /// SignatureBuilder::new(SignatureType::CasualCertification)
1041 /// .set_notation("rabbit@example.org", b"follow me",
1042 /// NotationDataFlags::empty().set_human_readable(),
1043 /// false)?)?
1044 /// .generate()?;
1045 ///
1046 /// let uas = cert.with_policy(policy, None)?.user_attributes().collect::<Vec<_>>();
1047 /// assert_eq!(uas.len(), 1);
1048 /// assert!(! uas[0].binding_signature().primary_userid().unwrap_or(false));
1049 /// assert_eq!(uas[0].binding_signature().notation("rabbit@example.org")
1050 /// .next().unwrap(), b"follow me");
1051 /// # Ok(()) }
1052 /// ```
1053 pub fn add_user_attribute_with<U, B>(mut self, ua: U, builder: B)
1054 -> Result<Self>
1055 where U: Into<packet::UserAttribute>,
1056 B: Into<SignatureBuilder>,
1057 {
1058 let builder = builder.into();
1059 match builder.typ() {
1060 SignatureType::GenericCertification
1061 | SignatureType::PersonaCertification
1062 | SignatureType::CasualCertification
1063 | SignatureType::PositiveCertification =>
1064 {
1065 self.user_attributes.push((Some(builder), ua.into()));
1066 Ok(self)
1067 },
1068 t =>
1069 Err(Error::InvalidArgument(format!(
1070 "Signature type is not a certification: {}", t)).into()),
1071 }
1072 }
1073
1074 /// Adds a signing-capable subkey.
1075 ///
1076 /// The key uses the default cipher suite (see
1077 /// [`CertBuilder::set_cipher_suite`]), and is not set to expire.
1078 /// Use [`CertBuilder::add_subkey`] if you need to change these
1079 /// parameters.
1080 ///
1081 /// [`CertBuilder::set_cipher_suite`]: CertBuilder::set_cipher_suite()
1082 /// [`CertBuilder::add_subkey`]: CertBuilder::add_subkey()
1083 ///
1084 /// # Examples
1085 ///
1086 /// ```
1087 /// use sequoia_openpgp as openpgp;
1088 /// use openpgp::cert::prelude::*;
1089 /// use openpgp::policy::StandardPolicy;
1090 /// use openpgp::types::KeyFlags;
1091 ///
1092 /// # fn main() -> openpgp::Result<()> {
1093 /// let p = &StandardPolicy::new();
1094 ///
1095 /// let (cert, rev) =
1096 /// CertBuilder::new()
1097 /// .add_signing_subkey()
1098 /// .generate()?;
1099 ///
1100 /// assert_eq!(cert.keys().count(), 2);
1101 /// let ka = cert.with_policy(p, None)?.keys().nth(1).unwrap();
1102 /// assert_eq!(ka.key_flags(),
1103 /// Some(KeyFlags::empty().set_signing()));
1104 /// # Ok(())
1105 /// # }
1106 /// ```
1107 pub fn add_signing_subkey(self) -> Self {
1108 self.add_subkey(KeyFlags::empty().set_signing(), None, None)
1109 }
1110
1111 /// Adds a subkey suitable for transport encryption.
1112 ///
1113 /// The key uses the default cipher suite (see
1114 /// [`CertBuilder::set_cipher_suite`]), and is not set to expire.
1115 /// Use [`CertBuilder::add_subkey`] if you need to change these
1116 /// parameters.
1117 ///
1118 /// [`CertBuilder::set_cipher_suite`]: CertBuilder::set_cipher_suite()
1119 /// [`CertBuilder::add_subkey`]: CertBuilder::add_subkey()
1120 ///
1121 ///
1122 /// # Examples
1123 ///
1124 /// ```
1125 /// use sequoia_openpgp as openpgp;
1126 /// use openpgp::cert::prelude::*;
1127 /// use openpgp::policy::StandardPolicy;
1128 /// use openpgp::types::KeyFlags;
1129 ///
1130 /// # fn main() -> openpgp::Result<()> {
1131 /// let p = &StandardPolicy::new();
1132 ///
1133 /// let (cert, rev) =
1134 /// CertBuilder::new()
1135 /// .add_transport_encryption_subkey()
1136 /// .generate()?;
1137 ///
1138 /// assert_eq!(cert.keys().count(), 2);
1139 /// let ka = cert.with_policy(p, None)?.keys().nth(1).unwrap();
1140 /// assert_eq!(ka.key_flags(),
1141 /// Some(KeyFlags::empty().set_transport_encryption()));
1142 /// # Ok(())
1143 /// # }
1144 /// ```
1145 pub fn add_transport_encryption_subkey(self) -> Self {
1146 self.add_subkey(KeyFlags::empty().set_transport_encryption(),
1147 None, None)
1148 }
1149
1150 /// Adds a subkey suitable for storage encryption.
1151 ///
1152 /// The key uses the default cipher suite (see
1153 /// [`CertBuilder::set_cipher_suite`]), and is not set to expire.
1154 /// Use [`CertBuilder::add_subkey`] if you need to change these
1155 /// parameters.
1156 ///
1157 /// [`CertBuilder::set_cipher_suite`]: CertBuilder::set_cipher_suite()
1158 /// [`CertBuilder::add_subkey`]: CertBuilder::add_subkey()
1159 ///
1160 ///
1161 /// # Examples
1162 ///
1163 /// ```
1164 /// use sequoia_openpgp as openpgp;
1165 /// use openpgp::cert::prelude::*;
1166 /// use openpgp::policy::StandardPolicy;
1167 /// use openpgp::types::KeyFlags;
1168 ///
1169 /// # fn main() -> openpgp::Result<()> {
1170 /// let p = &StandardPolicy::new();
1171 ///
1172 /// let (cert, rev) =
1173 /// CertBuilder::new()
1174 /// .add_storage_encryption_subkey()
1175 /// .generate()?;
1176 ///
1177 /// assert_eq!(cert.keys().count(), 2);
1178 /// let ka = cert.with_policy(p, None)?.keys().nth(1).unwrap();
1179 /// assert_eq!(ka.key_flags(),
1180 /// Some(KeyFlags::empty().set_storage_encryption()));
1181 /// # Ok(())
1182 /// # }
1183 /// ```
1184 pub fn add_storage_encryption_subkey(self) -> Self {
1185 self.add_subkey(KeyFlags::empty().set_storage_encryption(),
1186 None, None)
1187 }
1188
1189 /// Adds a certification-capable subkey.
1190 ///
1191 /// The key uses the default cipher suite (see
1192 /// [`CertBuilder::set_cipher_suite`]), and is not set to expire.
1193 /// Use [`CertBuilder::add_subkey`] if you need to change these
1194 /// parameters.
1195 ///
1196 /// [`CertBuilder::set_cipher_suite`]: CertBuilder::set_cipher_suite()
1197 /// [`CertBuilder::add_subkey`]: CertBuilder::add_subkey()
1198 ///
1199 ///
1200 /// # Examples
1201 ///
1202 /// ```
1203 /// use sequoia_openpgp as openpgp;
1204 /// use openpgp::cert::prelude::*;
1205 /// use openpgp::policy::StandardPolicy;
1206 /// use openpgp::types::KeyFlags;
1207 ///
1208 /// # fn main() -> openpgp::Result<()> {
1209 /// let p = &StandardPolicy::new();
1210 ///
1211 /// let (cert, rev) =
1212 /// CertBuilder::new()
1213 /// .add_certification_subkey()
1214 /// .generate()?;
1215 ///
1216 /// assert_eq!(cert.keys().count(), 2);
1217 /// let ka = cert.with_policy(p, None)?.keys().nth(1).unwrap();
1218 /// assert_eq!(ka.key_flags(),
1219 /// Some(KeyFlags::empty().set_certification()));
1220 /// # Ok(())
1221 /// # }
1222 /// ```
1223 pub fn add_certification_subkey(self) -> Self {
1224 self.add_subkey(KeyFlags::empty().set_certification(), None, None)
1225 }
1226
1227 /// Adds an authentication-capable subkey.
1228 ///
1229 /// The key uses the default cipher suite (see
1230 /// [`CertBuilder::set_cipher_suite`]), and is not set to expire.
1231 /// Use [`CertBuilder::add_subkey`] if you need to change these
1232 /// parameters.
1233 ///
1234 /// [`CertBuilder::set_cipher_suite`]: CertBuilder::set_cipher_suite()
1235 /// [`CertBuilder::add_subkey`]: CertBuilder::add_subkey()
1236 ///
1237 ///
1238 /// # Examples
1239 ///
1240 /// ```
1241 /// use sequoia_openpgp as openpgp;
1242 /// use openpgp::cert::prelude::*;
1243 /// use openpgp::policy::StandardPolicy;
1244 /// use openpgp::types::KeyFlags;
1245 ///
1246 /// # fn main() -> openpgp::Result<()> {
1247 /// let p = &StandardPolicy::new();
1248 ///
1249 /// let (cert, rev) =
1250 /// CertBuilder::new()
1251 /// .add_authentication_subkey()
1252 /// .generate()?;
1253 ///
1254 /// assert_eq!(cert.keys().count(), 2);
1255 /// let ka = cert.with_policy(p, None)?.keys().nth(1).unwrap();
1256 /// assert_eq!(ka.key_flags(),
1257 /// Some(KeyFlags::empty().set_authentication()));
1258 /// # Ok(())
1259 /// # }
1260 /// ```
1261 pub fn add_authentication_subkey(self) -> Self {
1262 self.add_subkey(KeyFlags::empty().set_authentication(), None, None)
1263 }
1264
1265 /// Adds a custom subkey.
1266 ///
1267 /// If `validity` is `None`, the subkey will be valid for the same
1268 /// period as the primary key.
1269 ///
1270 /// Likewise, if `cs` is `None`, the same cipher suite is used as
1271 /// for the primary key.
1272 ///
1273 /// # Examples
1274 ///
1275 /// Generates a certificate with an encryption subkey that is for
1276 /// protecting *both* data in transit and data at rest, and
1277 /// expires at a different time from the primary key:
1278 ///
1279 /// ```
1280 /// use sequoia_openpgp as openpgp;
1281 /// # use openpgp::Result;
1282 /// use openpgp::cert::prelude::*;
1283 /// use openpgp::policy::StandardPolicy;
1284 /// use openpgp::types::KeyFlags;
1285 ///
1286 /// # fn main() -> Result<()> {
1287 /// let p = &StandardPolicy::new();
1288 ///
1289 /// let now = std::time::SystemTime::now();
1290 /// let y = std::time::Duration::new(365 * 24 * 60 * 60, 0);
1291 ///
1292 /// // Make the certificate expire in 2 years, and the subkey
1293 /// // expire in a year.
1294 /// let (cert,_) = CertBuilder::new()
1295 /// .set_creation_time(now)
1296 /// .set_validity_period(2 * y)
1297 /// .add_subkey(KeyFlags::empty()
1298 /// .set_storage_encryption()
1299 /// .set_transport_encryption(),
1300 /// y,
1301 /// None)
1302 /// .generate()?;
1303 ///
1304 /// assert_eq!(cert.with_policy(p, now)?.keys().alive().count(), 2);
1305 /// assert_eq!(cert.with_policy(p, now + y)?.keys().alive().count(), 1);
1306 /// assert_eq!(cert.with_policy(p, now + 2 * y)?.keys().alive().count(), 0);
1307 ///
1308 /// let ka = cert.with_policy(p, None)?.keys().nth(1).unwrap();
1309 /// assert_eq!(ka.key_flags(),
1310 /// Some(KeyFlags::empty()
1311 /// .set_storage_encryption()
1312 /// .set_transport_encryption()));
1313 /// # Ok(()) }
1314 /// ```
1315 pub fn add_subkey<T, C>(mut self, flags: KeyFlags, validity: T, cs: C)
1316 -> Self
1317 where T: Into<Option<time::Duration>>,
1318 C: Into<Option<CipherSuite>>,
1319 {
1320 self.subkeys.push((None, KeyBlueprint {
1321 flags,
1322 validity: validity.into(),
1323 ciphersuite: cs.into(),
1324 }));
1325 self
1326 }
1327
1328 /// Adds a subkey with a binding signature based on `builder`.
1329 ///
1330 /// Adds a subkey to the certificate, creating the binding
1331 /// signature using `builder`. The `builder`s signature type must
1332 /// be [`SubkeyBinding`].
1333 ///
1334 /// The key generation step uses `builder` as a template, but adds
1335 /// all subpackets that the signature needs to be a valid binding
1336 /// signature. If you need more control, or want to adopt
1337 /// existing keys, consider using
1338 /// [`Key::bind`](crate::packet::Key::bind).
1339 ///
1340 /// The following modifications are performed on `builder`:
1341 ///
1342 /// - An appropriate hash algorithm is selected.
1343 ///
1344 /// - The creation time is set.
1345 ///
1346 /// - Key metadata is added (key flags, key validity period).
1347 ///
1348 /// [`SubkeyBinding`]: crate::types::SignatureType::SubkeyBinding
1349 ///
1350 /// If `validity` is `None`, the subkey will be valid for the same
1351 /// period as the primary key.
1352 ///
1353 /// # Examples
1354 ///
1355 /// This example binds a signing subkey to a certificate,
1356 /// restricting its use to authentication of software.
1357 ///
1358 /// ```
1359 /// # fn main() -> sequoia_openpgp::Result<()> {
1360 /// # use sequoia_openpgp as openpgp;
1361 /// # use openpgp::packet::user_attribute::Subpacket;
1362 /// # use openpgp::cert::prelude::*;
1363 /// # use openpgp::packet::{prelude::*, signature::subpacket::*};
1364 /// # use openpgp::policy::StandardPolicy;
1365 /// # use openpgp::types::*;
1366 /// let (cert, revocation_cert) =
1367 /// CertBuilder::general_purpose(
1368 /// Some("Alice Lovelace <alice@example.org>"))
1369 /// .add_subkey_with(
1370 /// KeyFlags::empty().set_signing(), None, None,
1371 /// SignatureBuilder::new(SignatureType::SubkeyBinding)
1372 /// // Add a critical notation!
1373 /// .set_notation("code-signing@policy.example.org", b"",
1374 /// NotationDataFlags::empty(), true)?)?
1375 /// .generate()?;
1376 ///
1377 /// // Under the standard policy, the additional signing subkey
1378 /// // is not bound.
1379 /// let p = StandardPolicy::new();
1380 /// assert_eq!(cert.with_policy(&p, None)?.keys().for_signing().count(), 1);
1381 ///
1382 /// // However, software implementing the notation see the additional
1383 /// // signing subkey.
1384 /// let mut p = StandardPolicy::new();
1385 /// p.good_critical_notations(&["code-signing@policy.example.org"]);
1386 /// assert_eq!(cert.with_policy(&p, None)?.keys().for_signing().count(), 2);
1387 /// # Ok(()) }
1388 /// ```
1389 pub fn add_subkey_with<T, C, B>(mut self, flags: KeyFlags, validity: T,
1390 cs: C, builder: B) -> Result<Self>
1391 where T: Into<Option<time::Duration>>,
1392 C: Into<Option<CipherSuite>>,
1393 B: Into<SignatureBuilder>,
1394 {
1395 let builder = builder.into();
1396 match builder.typ() {
1397 SignatureType::SubkeyBinding => {
1398 self.subkeys.push((Some(builder), KeyBlueprint {
1399 flags,
1400 validity: validity.into(),
1401 ciphersuite: cs.into(),
1402 }));
1403 Ok(self)
1404 },
1405 t =>
1406 Err(Error::InvalidArgument(format!(
1407 "Signature type is not a subkey binding: {}", t)).into()),
1408 }
1409 }
1410
1411 /// Sets the primary key's key flags.
1412 ///
1413 /// By default, the primary key is set to only be certification
1414 /// capable. This allows the caller to set additional flags.
1415 ///
1416 /// # Examples
1417 ///
1418 /// Makes the primary key signing-capable but not
1419 /// certification-capable.
1420 ///
1421 /// ```
1422 /// use sequoia_openpgp as openpgp;
1423 /// # use openpgp::Result;
1424 /// use openpgp::cert::prelude::*;
1425 /// use openpgp::policy::StandardPolicy;
1426 /// use openpgp::types::KeyFlags;
1427 ///
1428 /// # fn main() -> Result<()> {
1429 /// let p = &StandardPolicy::new();
1430 ///
1431 /// let (cert, rev) =
1432 /// CertBuilder::general_purpose(Some("Alice Lovelace <alice@example.org>"))
1433 /// .set_primary_key_flags(KeyFlags::empty().set_signing())
1434 /// .generate()?;
1435 ///
1436 /// // Observe that the primary key's certification capability is
1437 /// // set implicitly.
1438 /// assert_eq!(cert.with_policy(p, None)?.primary_key().key_flags(),
1439 /// Some(KeyFlags::empty().set_signing()));
1440 /// # Ok(()) }
1441 /// ```
1442 pub fn set_primary_key_flags(mut self, flags: KeyFlags) -> Self {
1443 self.primary.flags = flags;
1444 self
1445 }
1446
1447 /// Sets a password to encrypt the secret keys with.
1448 ///
1449 /// The password is used to encrypt all secret key material.
1450 ///
1451 /// # Examples
1452 ///
1453 /// ```
1454 /// use sequoia_openpgp as openpgp;
1455 /// # use openpgp::Result;
1456 /// use openpgp::cert::prelude::*;
1457 ///
1458 /// # fn main() -> Result<()> {
1459 /// // Make the certificate expire in 10 minutes.
1460 /// let (cert, rev) =
1461 /// CertBuilder::general_purpose(Some("Alice Lovelace <alice@example.org>"))
1462 /// .set_password(Some("1234".into()))
1463 /// .generate()?;
1464 ///
1465 /// for ka in cert.keys() {
1466 /// assert!(ka.key().has_secret());
1467 /// }
1468 /// # Ok(()) }
1469 /// ```
1470 pub fn set_password(mut self, password: Option<Password>) -> Self {
1471 self.password = password;
1472 self
1473 }
1474
1475 /// Sets the certificate's validity period.
1476 ///
1477 /// The determines how long the certificate is valid. That is,
1478 /// after the validity period, the certificate is considered to be
1479 /// expired.
1480 ///
1481 /// The validity period starts with the creation time (see
1482 /// [`CertBuilder::set_creation_time`]).
1483 ///
1484 /// A value of `None` means that the certificate never expires.
1485 ///
1486 /// See [this section](CertBuilder#expiration) of the type's
1487 /// documentation for security considerations of key expiration.
1488 ///
1489 /// # Examples
1490 ///
1491 /// ```
1492 /// use sequoia_openpgp as openpgp;
1493 /// # use openpgp::Result;
1494 /// use openpgp::cert::prelude::*;
1495 /// use openpgp::policy::StandardPolicy;
1496 /// use openpgp::types::RevocationKey;
1497 ///
1498 /// # fn main() -> Result<()> {
1499 /// let p = &StandardPolicy::new();
1500 ///
1501 /// let now = std::time::SystemTime::now();
1502 /// let s = std::time::Duration::new(1, 0);
1503 ///
1504 /// // Make the certificate expire in 10 minutes.
1505 /// let (cert,_) = CertBuilder::new()
1506 /// .set_creation_time(now)
1507 /// .set_validity_period(600 * s)
1508 /// .generate()?;
1509 ///
1510 /// assert!(cert.with_policy(p, now)?.primary_key().alive().is_ok());
1511 /// assert!(cert.with_policy(p, now + 599 * s)?.primary_key().alive().is_ok());
1512 /// assert!(cert.with_policy(p, now + 600 * s)?.primary_key().alive().is_err());
1513 /// # Ok(()) }
1514 /// ```
1515 pub fn set_validity_period<T>(mut self, validity: T) -> Self
1516 where T: Into<Option<time::Duration>>
1517 {
1518 self.primary.validity = validity.into();
1519 self
1520 }
1521
1522 /// Sets designated revokers.
1523 ///
1524 /// Adds designated revokers to the primary key. This allows the
1525 /// designated revoker to issue revocation certificates on behalf
1526 /// of the primary key.
1527 ///
1528 /// # Examples
1529 ///
1530 /// Make Alice a designated revoker for Bob:
1531 ///
1532 /// ```
1533 /// use sequoia_openpgp as openpgp;
1534 /// # use openpgp::Result;
1535 /// use openpgp::cert::prelude::*;
1536 /// use openpgp::policy::StandardPolicy;
1537 /// use openpgp::types::RevocationKey;
1538 ///
1539 /// # fn main() -> Result<()> {
1540 /// let p = &StandardPolicy::new();
1541 ///
1542 /// let (alice, _) =
1543 /// CertBuilder::general_purpose(Some("alice@example.org"))
1544 /// .generate()?;
1545 /// let (bob, _) =
1546 /// CertBuilder::general_purpose(Some("bob@example.org"))
1547 /// .set_revocation_keys(vec![(&alice).into()])
1548 /// .generate()?;
1549 ///
1550 /// // Make sure Alice is listed as a designated revoker for Bob.
1551 /// assert_eq!(bob.revocation_keys(p).collect::<Vec<&RevocationKey>>(),
1552 /// vec![&(&alice).into()]);
1553 /// # Ok(()) }
1554 /// ```
1555 pub fn set_revocation_keys(mut self, revocation_keys: Vec<RevocationKey>)
1556 -> Self
1557 {
1558 self.revocation_keys = Some(revocation_keys);
1559 self
1560 }
1561
1562 /// Generates a certificate.
1563 ///
1564 /// # Examples
1565 ///
1566 /// ```
1567 /// use sequoia_openpgp as openpgp;
1568 /// # use openpgp::Result;
1569 /// use openpgp::cert::prelude::*;
1570 /// use openpgp::policy::StandardPolicy;
1571 /// use openpgp::types::RevocationKey;
1572 ///
1573 /// # fn main() -> Result<()> {
1574 /// let p = &StandardPolicy::new();
1575 ///
1576 /// let (alice, _) =
1577 /// CertBuilder::general_purpose(Some("alice@example.org"))
1578 /// .generate()?;
1579 /// # Ok(()) }
1580 /// ```
1581 pub fn generate(mut self) -> Result<(Cert, Signature)> {
1582 use crate::Packet;
1583 use crate::types::ReasonForRevocation;
1584
1585 let creation_time =
1586 self.creation_time.unwrap_or_else(|| {
1587 use crate::packet::signature::SIG_BACKDATE_BY;
1588 crate::now() -
1589 time::Duration::new(SIG_BACKDATE_BY, 0)
1590 });
1591
1592 // Generate & self-sign primary key.
1593 let (primary, sig, mut signer) = self.primary_key(creation_time)?;
1594
1595 // Construct a skeleton cert. We need this to bind the new
1596 // components to.
1597 let cert = Cert::try_from(vec![
1598 Packet::SecretKey({
1599 let mut primary = primary.clone();
1600 if let Some(ref password) = self.password {
1601 let (k, mut secret) = primary.take_secret();
1602 secret.encrypt_in_place(&k, password)?;
1603 primary = k.add_secret(secret).0;
1604 }
1605 primary
1606 }),
1607 ])?;
1608 // We will, however, collect any signatures and components in
1609 // a separate vector, and only add them in the end, so that we
1610 // canonicalize the new certificate just once.
1611 let mut acc = vec![
1612 Packet::from(sig),
1613 ];
1614
1615 // We want to mark exactly one User ID or Attribute as primary.
1616 // First, figure out whether one of the binding signature
1617 // templates have the primary flag set.
1618 let have_primary_user_thing = {
1619 let is_primary = |osig: &Option<SignatureBuilder>| -> bool {
1620 osig.as_ref().and_then(|s| s.primary_userid()).unwrap_or(false)
1621 };
1622
1623 self.userids.iter().map(|(s, _)| s).any(is_primary)
1624 || self.user_attributes.iter().map(|(s, _)| s).any(is_primary)
1625 };
1626 let mut emitted_primary_user_thing = false;
1627
1628 // Sign UserIDs.
1629 for (template, uid) in std::mem::take(&mut self.userids).into_iter() {
1630 let sig = template.unwrap_or_else(
1631 || SignatureBuilder::new(SignatureType::PositiveCertification));
1632 let sig = Self::signature_common(sig, creation_time,
1633 self.exportable)?;
1634 let mut sig = self.add_primary_key_metadata(sig)?;
1635
1636 // Make sure we mark exactly one User ID or Attribute as
1637 // primary.
1638 if emitted_primary_user_thing {
1639 sig = sig.modify_hashed_area(|mut a| {
1640 a.remove_all(SubpacketTag::PrimaryUserID);
1641 Ok(a)
1642 })?;
1643 } else if have_primary_user_thing {
1644 // Check if this is the first explicitly selected
1645 // user thing.
1646 emitted_primary_user_thing |=
1647 sig.primary_userid().unwrap_or(false);
1648 } else {
1649 // Implicitly mark the first as primary.
1650 sig = sig.set_primary_userid(true)?;
1651 emitted_primary_user_thing = true;
1652 }
1653
1654 let signature = uid.bind(&mut signer, &cert, sig)?;
1655 acc.push(uid.into());
1656 acc.push(signature.into());
1657 }
1658
1659 // Sign UserAttributes.
1660 for (template, ua) in std::mem::take(&mut self.user_attributes) {
1661 let sig = template.unwrap_or_else(
1662 || SignatureBuilder::new(SignatureType::PositiveCertification));
1663 let sig = Self::signature_common(
1664 sig, creation_time, self.exportable)?;
1665 let mut sig = self.add_primary_key_metadata(sig)?;
1666
1667 // Make sure we mark exactly one User ID or Attribute as
1668 // primary.
1669 if emitted_primary_user_thing {
1670 sig = sig.modify_hashed_area(|mut a| {
1671 a.remove_all(SubpacketTag::PrimaryUserID);
1672 Ok(a)
1673 })?;
1674 } else if have_primary_user_thing {
1675 // Check if this is the first explicitly selected
1676 // user thing.
1677 emitted_primary_user_thing |=
1678 sig.primary_userid().unwrap_or(false);
1679 } else {
1680 // Implicitly mark the first as primary.
1681 sig = sig.set_primary_userid(true)?;
1682 emitted_primary_user_thing = true;
1683 }
1684
1685 let signature = ua.bind(&mut signer, &cert, sig)?;
1686 acc.push(ua.into());
1687 acc.push(signature.into());
1688 }
1689
1690 // Sign subkeys.
1691 for (template, blueprint) in self.subkeys {
1692 let flags = &blueprint.flags;
1693 let mut subkey = blueprint.ciphersuite
1694 .unwrap_or(self.ciphersuite)
1695 .generate_key(flags, self.profile)?
1696 .role_into_subordinate();
1697 subkey.set_creation_time(creation_time)?;
1698
1699 let sig = template.unwrap_or_else(
1700 || SignatureBuilder::new(SignatureType::SubkeyBinding));
1701 let sig = Self::signature_common(
1702 sig, creation_time, self.exportable)?;
1703 let mut builder = sig
1704 .set_key_flags(flags.clone())?
1705 .set_key_validity_period(blueprint.validity.or(self.primary.validity))?;
1706
1707 if flags.for_certification() || flags.for_signing()
1708 || flags.for_authentication()
1709 {
1710 // We need to create a primary key binding signature.
1711 let mut subkey_signer = subkey.clone().into_keypair().unwrap();
1712 let backsig =
1713 signature::SignatureBuilder::new(SignatureType::PrimaryKeyBinding)
1714 .set_signature_creation_time(creation_time)?
1715 // GnuPG wants at least a 512-bit hash for P521 keys.
1716 .set_hash_algo(HashAlgorithm::SHA512)
1717 .sign_primary_key_binding(&mut subkey_signer, &primary,
1718 &subkey)?;
1719 builder = builder.set_embedded_signature(backsig)?;
1720 }
1721
1722 let signature = subkey.bind(&mut signer, &cert, builder)?;
1723
1724 if let Some(ref password) = self.password {
1725 let (k, mut secret) = subkey.take_secret();
1726 secret.encrypt_in_place(&k, password)?;
1727 subkey = k.add_secret(secret).0;
1728 }
1729 acc.push(subkey.into());
1730 acc.push(signature.into());
1731 }
1732
1733 // Now add the new components and canonicalize once.
1734 let cert = cert.insert_packets(acc)?.0;
1735
1736 let revocation = CertRevocationBuilder::new()
1737 .set_signature_creation_time(creation_time)?
1738 .set_reason_for_revocation(
1739 ReasonForRevocation::Unspecified, b"Unspecified")?
1740 .build(&mut signer, &cert, None)?;
1741
1742 // keys generated by the builder are never invalid
1743 assert!(cert.bad.is_empty());
1744 assert!(cert.unknowns.is_empty());
1745
1746 Ok((cert, revocation))
1747 }
1748
1749 /// Creates the primary key and a direct key signature.
1750 fn primary_key(&self, creation_time: std::time::SystemTime)
1751 -> Result<(KeySecretKey, Signature, Box<dyn Signer>)>
1752 {
1753 let mut key = self.primary.ciphersuite
1754 .unwrap_or(self.ciphersuite)
1755 .generate_key(KeyFlags::empty().set_certification(),
1756 self.profile)?
1757 .role_into_primary();
1758 key.set_creation_time(creation_time)?;
1759 let sig = SignatureBuilder::new(SignatureType::DirectKey);
1760 let sig = Self::signature_common(
1761 sig, creation_time, self.exportable)?;
1762 let mut sig = self.add_primary_key_metadata(sig)?;
1763
1764 if let Some(ref revocation_keys) = self.revocation_keys {
1765 for k in revocation_keys.into_iter().cloned() {
1766 sig = sig.add_revocation_key(k)?;
1767 }
1768 }
1769
1770 let mut signer = key.clone().into_keypair()
1771 .expect("key generated above has a secret");
1772 let sig = sig.sign_direct_key(&mut signer, key.parts_as_public())?;
1773
1774 Ok((key, sig, Box::new(signer)))
1775 }
1776
1777 /// Common settings for generated signatures.
1778 fn signature_common(builder: SignatureBuilder,
1779 creation_time: time::SystemTime,
1780 exportable: bool)
1781 -> Result<SignatureBuilder>
1782 {
1783 let mut builder = builder
1784 // GnuPG wants at least a 512-bit hash for P521 keys.
1785 .set_hash_algo(HashAlgorithm::SHA512)
1786 .set_signature_creation_time(creation_time)?;
1787 if ! exportable {
1788 builder = builder.set_exportable_certification(false)?;
1789 }
1790 Ok(builder)
1791 }
1792
1793
1794 /// Adds primary key metadata to the signature.
1795 fn add_primary_key_metadata(&self,
1796 builder: SignatureBuilder)
1797 -> Result<SignatureBuilder>
1798 {
1799 builder
1800 .set_features(self.features.clone())?
1801 .set_key_flags(self.primary.flags.clone())?
1802 .set_key_validity_period(self.primary.validity)?
1803 .set_preferred_hash_algorithms(vec![
1804 HashAlgorithm::SHA512,
1805 HashAlgorithm::SHA256,
1806 ])?
1807 .set_preferred_symmetric_algorithms(vec![
1808 SymmetricAlgorithm::AES256,
1809 SymmetricAlgorithm::AES128,
1810 ])
1811 }
1812}
1813
1814#[cfg(test)]
1815mod tests {
1816 use std::str::FromStr;
1817
1818 use super::*;
1819 use crate::Fingerprint;
1820 use crate::crypto::mpi::PublicKey;
1821 use crate::packet::signature::subpacket::{SubpacketTag, SubpacketValue};
1822 use crate::types::Curve;
1823 use crate::types::PublicKeyAlgorithm;
1824 use crate::parse::Parse;
1825 use crate::policy::StandardPolicy as P;
1826 use crate::serialize::Serialize;
1827
1828 #[test]
1829 fn all_opts() {
1830 let p = &P::new();
1831
1832 let (cert, _) = CertBuilder::new()
1833 .set_cipher_suite(CipherSuite::Cv25519)
1834 .add_userid("test1@example.com")
1835 .add_userid("test2@example.com")
1836 .add_signing_subkey()
1837 .add_transport_encryption_subkey()
1838 .add_certification_subkey()
1839 .generate().unwrap();
1840
1841 let mut userids = cert.userids().with_policy(p, None)
1842 .map(|u| String::from_utf8_lossy(u.userid().value()).into_owned())
1843 .collect::<Vec<String>>();
1844 userids.sort();
1845
1846 assert_eq!(userids,
1847 &[ "test1@example.com",
1848 "test2@example.com",
1849 ][..]);
1850 assert_eq!(cert.subkeys().count(), 3);
1851 }
1852
1853 #[test]
1854 fn direct_key_sig() {
1855 let p = &P::new();
1856
1857 let (cert, _) = CertBuilder::new()
1858 .set_cipher_suite(CipherSuite::Cv25519)
1859 .add_signing_subkey()
1860 .add_transport_encryption_subkey()
1861 .add_certification_subkey()
1862 .generate().unwrap();
1863
1864 assert_eq!(cert.userids().count(), 0);
1865 assert_eq!(cert.subkeys().count(), 3);
1866 let sig =
1867 cert.primary_key().with_policy(p, None).unwrap().binding_signature();
1868 assert_eq!(sig.typ(), crate::types::SignatureType::DirectKey);
1869 assert!(sig.features().unwrap().supports_seipdv1());
1870 }
1871
1872 #[test]
1873 fn setter() {
1874 let (cert1, _) = CertBuilder::new()
1875 .set_cipher_suite(CipherSuite::Cv25519)
1876 .set_cipher_suite(CipherSuite::RSA3k)
1877 .set_cipher_suite(CipherSuite::Cv25519)
1878 .generate().unwrap();
1879 assert_eq!(cert1.primary_key().key().pk_algo(), PublicKeyAlgorithm::EdDSA);
1880
1881 let (cert2, _) = CertBuilder::new()
1882 .set_cipher_suite(CipherSuite::RSA3k)
1883 .add_userid("test2@example.com")
1884 .add_transport_encryption_subkey()
1885 .generate().unwrap();
1886 assert_eq!(cert2.primary_key().key().pk_algo(),
1887 PublicKeyAlgorithm::RSAEncryptSign);
1888 assert_eq!(cert2.subkeys().next().unwrap().key().pk_algo(),
1889 PublicKeyAlgorithm::RSAEncryptSign);
1890 }
1891
1892 #[test]
1893 fn defaults() {
1894 let p = &P::new();
1895 let (cert1, _) = CertBuilder::new()
1896 .add_userid("test2@example.com")
1897 .generate().unwrap();
1898 assert_eq!(cert1.primary_key().key().pk_algo(),
1899 PublicKeyAlgorithm::EdDSA);
1900 assert!(cert1.subkeys().next().is_none());
1901 assert!(cert1.with_policy(p, None).unwrap().primary_userid().unwrap()
1902 .binding_signature().features().unwrap().supports_seipdv1());
1903 }
1904
1905 #[test]
1906 fn not_always_certify() {
1907 let p = &P::new();
1908 let (cert1, _) = CertBuilder::new()
1909 .set_cipher_suite(CipherSuite::Cv25519)
1910 .set_primary_key_flags(KeyFlags::empty())
1911 .add_transport_encryption_subkey()
1912 .generate().unwrap();
1913 assert!(! cert1.primary_key().with_policy(p, None).unwrap().for_certification());
1914 assert_eq!(cert1.keys().subkeys().count(), 1);
1915 }
1916
1917 #[test]
1918 fn gen_wired_subkeys() {
1919 let (cert1, _) = CertBuilder::new()
1920 .set_cipher_suite(CipherSuite::Cv25519)
1921 .set_primary_key_flags(KeyFlags::empty())
1922 .add_subkey(KeyFlags::empty().set_certification(), None, None)
1923 .generate().unwrap();
1924 let sig_pkts = cert1.subkeys().next().unwrap().bundle()
1925 .self_signatures().next().unwrap().hashed_area();
1926
1927 match sig_pkts.subpacket(SubpacketTag::KeyFlags).unwrap().value() {
1928 SubpacketValue::KeyFlags(ref ks) => assert!(ks.for_certification()),
1929 v => panic!("Unexpected subpacket: {:?}", v),
1930 }
1931
1932 assert_eq!(cert1.subkeys().count(), 1);
1933 }
1934
1935 #[test]
1936 fn generate_revocation_certificate() {
1937 let p = &P::new();
1938 use crate::types::RevocationStatus;
1939 let (cert, revocation) = CertBuilder::new()
1940 .set_cipher_suite(CipherSuite::Cv25519)
1941 .generate().unwrap();
1942 assert_eq!(cert.revocation_status(p, None),
1943 RevocationStatus::NotAsFarAsWeKnow);
1944
1945 let cert = cert.insert_packets(revocation.clone()).unwrap().0;
1946 assert_eq!(cert.revocation_status(p, None),
1947 RevocationStatus::Revoked(vec![ &revocation ]));
1948 }
1949
1950 #[test]
1951 fn builder_roundtrip() {
1952 use std::convert::TryFrom;
1953
1954 let (cert,_) = CertBuilder::new()
1955 .set_cipher_suite(CipherSuite::Cv25519)
1956 .add_signing_subkey()
1957 .generate().unwrap();
1958 let pile = cert.clone().into_packet_pile().into_children().collect::<Vec<_>>();
1959 let exp = Cert::try_from(pile).unwrap();
1960
1961 assert_eq!(cert, exp);
1962 }
1963
1964 #[test]
1965 fn encrypted_secrets() {
1966 let (cert,_) = CertBuilder::new()
1967 .set_cipher_suite(CipherSuite::Cv25519)
1968 .set_password(Some(String::from("streng geheim").into()))
1969 .generate().unwrap();
1970 assert!(cert.primary_key().key().optional_secret().unwrap().is_encrypted());
1971 }
1972
1973 #[test]
1974 fn all_ciphersuites() {
1975 for cs in CipherSuite::variants()
1976 .into_iter().filter(|cs| cs.is_supported().is_ok())
1977 {
1978 assert!(CertBuilder::new()
1979 .set_cipher_suite(cs)
1980 .generate().is_ok());
1981 }
1982 }
1983
1984 #[test]
1985 fn validity_periods() {
1986 let p = &P::new();
1987
1988 let now = crate::now();
1989 let s = std::time::Duration::new(1, 0);
1990
1991 let (cert,_) = CertBuilder::new()
1992 .set_creation_time(now)
1993 .set_validity_period(600 * s)
1994 .add_subkey(KeyFlags::empty().set_signing(),
1995 300 * s, None)
1996 .add_subkey(KeyFlags::empty().set_authentication(),
1997 None, None)
1998 .generate().unwrap();
1999
2000 let key = cert.primary_key().key();
2001 let sig = &cert.primary_key().bundle().self_signatures().next().unwrap();
2002 assert!(sig.key_alive(key, now).is_ok());
2003 assert!(sig.key_alive(key, now + 590 * s).is_ok());
2004 assert!(! sig.key_alive(key, now + 610 * s).is_ok());
2005
2006 let ka = cert.keys().with_policy(p, now).alive().revoked(false)
2007 .for_signing().next().unwrap();
2008 assert!(ka.alive().is_ok());
2009 assert!(ka.clone().with_policy(p, now + 290 * s).unwrap().alive().is_ok());
2010 assert!(! ka.clone().with_policy(p, now + 310 * s).unwrap().alive().is_ok());
2011
2012 let ka = cert.keys().with_policy(p, now).alive().revoked(false)
2013 .for_authentication().next().unwrap();
2014 assert!(ka.alive().is_ok());
2015 assert!(ka.clone().with_policy(p, now + 590 * s).unwrap().alive().is_ok());
2016 assert!(! ka.clone().with_policy(p, now + 610 * s).unwrap().alive().is_ok());
2017 }
2018
2019 #[test]
2020 fn creation_time() {
2021 let p = &P::new();
2022
2023 use std::time::UNIX_EPOCH;
2024 let (cert, rev) = CertBuilder::new()
2025 .set_creation_time(UNIX_EPOCH)
2026 .set_cipher_suite(CipherSuite::Cv25519)
2027 .add_userid("foo")
2028 .add_signing_subkey()
2029 .generate().unwrap();
2030
2031 assert_eq!(cert.primary_key().key().creation_time(), UNIX_EPOCH);
2032 assert_eq!(cert.primary_key().with_policy(p, None).unwrap()
2033 .binding_signature()
2034 .signature_creation_time().unwrap(), UNIX_EPOCH);
2035 assert_eq!(cert.primary_key().with_policy(p, None).unwrap()
2036 .direct_key_signature().unwrap()
2037 .signature_creation_time().unwrap(), UNIX_EPOCH);
2038 assert_eq!(rev.signature_creation_time().unwrap(), UNIX_EPOCH);
2039
2040 // (Sub)Keys.
2041 assert_eq!(cert.keys().with_policy(p, None).count(), 2);
2042 for ka in cert.keys().with_policy(p, None) {
2043 assert_eq!(ka.key().creation_time(), UNIX_EPOCH);
2044 assert_eq!(ka.binding_signature()
2045 .signature_creation_time().unwrap(), UNIX_EPOCH);
2046 }
2047
2048 // UserIDs.
2049 assert_eq!(cert.userids().count(), 1);
2050 for ui in cert.userids().with_policy(p, None) {
2051 assert_eq!(ui.binding_signature()
2052 .signature_creation_time().unwrap(), UNIX_EPOCH);
2053 }
2054 }
2055
2056 #[test]
2057 fn designated_revokers() -> Result<()> {
2058 use std::collections::HashSet;
2059
2060 let p = &P::new();
2061
2062 let fpr1 = "C03F A641 1B03 AE12 5764 6118 7223 B566 78E0 2528";
2063 let fpr2 = "50E6 D924 308D BF22 3CFB 510A C2B8 1905 6C65 2598";
2064 let revokers = vec![
2065 RevocationKey::new(PublicKeyAlgorithm::RSAEncryptSign,
2066 Fingerprint::from_str(fpr1)?,
2067 false),
2068 RevocationKey::new(PublicKeyAlgorithm::ECDSA,
2069 Fingerprint::from_str(fpr2)?,
2070 false)
2071 ];
2072
2073 let (cert,_)
2074 = CertBuilder::general_purpose(Some("alice@example.org"))
2075 .set_revocation_keys(revokers.clone())
2076 .generate()?;
2077 let cert = cert.with_policy(p, None)?;
2078
2079 assert_eq!(cert.revocation_keys().collect::<HashSet<_>>(),
2080 revokers.iter().collect::<HashSet<_>>());
2081
2082 // Do it again, with a key that has no User IDs.
2083 let (cert,_) = CertBuilder::new()
2084 .set_revocation_keys(revokers.clone())
2085 .generate()?;
2086 let cert = cert.with_policy(p, None)?;
2087 assert!(cert.primary_userid().is_err());
2088
2089 assert_eq!(cert.revocation_keys().collect::<HashSet<_>>(),
2090 revokers.iter().collect::<HashSet<_>>());
2091
2092 // The designated revokers on all signatures should be
2093 // considered.
2094 let now = crate::types::Timestamp::now();
2095 let then = now.checked_add(crate::types::Duration::days(1)?).unwrap();
2096 let (cert,_) = CertBuilder::new()
2097 .set_revocation_keys(revokers.clone())
2098 .set_creation_time(now)
2099 .generate()?;
2100
2101 // Add a newer direct key signature.
2102 use crate::crypto::hash::Hash;
2103 let mut primary_signer =
2104 cert.primary_key().key().clone().parts_into_secret()?
2105 .into_keypair()?;
2106 let mut hash = HashAlgorithm::SHA512.context()?
2107 .for_signature(primary_signer.public().version());
2108 cert.primary_key().key().hash(&mut hash)?;
2109 let sig = signature::SignatureBuilder::new(SignatureType::DirectKey)
2110 .set_signature_creation_time(then)?
2111 .sign_hash(&mut primary_signer, hash)?;
2112 let cert = cert.insert_packets(sig)?.0;
2113
2114 assert!(cert.with_policy(p, then)?.primary_userid().is_err());
2115 assert_eq!(cert.revocation_keys(p).collect::<HashSet<_>>(),
2116 revokers.iter().collect::<HashSet<_>>());
2117 Ok(())
2118 }
2119
2120 /// Checks that the builder emits exactly one user id or attribute
2121 /// marked as primary.
2122 #[test]
2123 fn primary_user_things() -> Result<()> {
2124 fn count_primary_user_things(c: Cert) -> usize {
2125 c.into_packets().map(|p| match p {
2126 Packet::Signature(s) if s.primary_userid().unwrap_or(false)
2127 => 1,
2128 _ => 0,
2129 }).sum()
2130 }
2131
2132 use crate::packet::{prelude::*, user_attribute::Subpacket};
2133 let ua_foo =
2134 UserAttribute::new(&[Subpacket::Unknown(7, vec![7; 7].into())])?;
2135 let ua_bar =
2136 UserAttribute::new(&[Subpacket::Unknown(11, vec![11; 11].into())])?;
2137
2138 let p = &P::new();
2139 let positive = SignatureType::PositiveCertification;
2140
2141 let (c, _) = CertBuilder::new().generate()?;
2142 assert_eq!(count_primary_user_things(c), 0);
2143
2144 let (c, _) = CertBuilder::new()
2145 .add_userid("foo")
2146 .generate()?;
2147 assert_eq!(count_primary_user_things(c), 1);
2148
2149 let (c, _) = CertBuilder::new()
2150 .add_userid("foo")
2151 .add_userid("bar")
2152 .generate()?;
2153 assert_eq!(count_primary_user_things(c), 1);
2154
2155 let (c, _) = CertBuilder::new()
2156 .add_user_attribute(ua_foo.clone())
2157 .generate()?;
2158 assert_eq!(count_primary_user_things(c), 1);
2159
2160 let (c, _) = CertBuilder::new()
2161 .add_user_attribute(ua_foo.clone())
2162 .add_user_attribute(ua_bar.clone())
2163 .generate()?;
2164 assert_eq!(count_primary_user_things(c), 1);
2165
2166 let (c, _) = CertBuilder::new()
2167 .add_userid("foo")
2168 .add_user_attribute(ua_foo.clone())
2169 .generate()?;
2170 let vc = c.with_policy(p, None)?;
2171 assert_eq!(vc.primary_userid()?.binding_signature().primary_userid(),
2172 Some(true));
2173 assert_eq!(vc.primary_user_attribute()?.binding_signature().primary_userid(),
2174 None);
2175 assert_eq!(count_primary_user_things(c), 1);
2176
2177 let (c, _) = CertBuilder::new()
2178 .add_user_attribute(ua_foo.clone())
2179 .add_userid("foo")
2180 .generate()?;
2181 let vc = c.with_policy(p, None)?;
2182 assert_eq!(vc.primary_userid()?.binding_signature().primary_userid(),
2183 Some(true));
2184 assert_eq!(vc.primary_user_attribute()?.binding_signature().primary_userid(),
2185 None);
2186 assert_eq!(count_primary_user_things(c), 1);
2187
2188 let (c, _) = CertBuilder::new()
2189 .add_userid("foo")
2190 .add_userid_with(
2191 "buz",
2192 SignatureBuilder::new(positive).set_primary_userid(false)?)?
2193 .add_userid_with(
2194 "bar",
2195 SignatureBuilder::new(positive).set_primary_userid(true)?)?
2196 .add_userid_with(
2197 "baz",
2198 SignatureBuilder::new(positive).set_primary_userid(true)?)?
2199 .generate()?;
2200 let vc = c.with_policy(p, None)?;
2201 assert_eq!(vc.primary_userid()?.userid().value(), b"bar");
2202 assert_eq!(count_primary_user_things(c), 1);
2203
2204 Ok(())
2205 }
2206
2207 #[test]
2208 fn non_exportable_cert() -> Result<()> {
2209 // Make sure that when we export a non-exportable cert,
2210 // nothing is exported.
2211
2212 let (cert, _) =
2213 CertBuilder::general_purpose(Some("alice@example.org"))
2214 .set_exportable(false)
2215 .generate()?;
2216
2217 let (bob, _) =
2218 CertBuilder::general_purpose(Some("bob@example.org"))
2219 .generate()?;
2220
2221 // Have Bob certify Alice's primary User ID with an exportable
2222 // signature. This shouldn't make Alice's certificate
2223 // exportable.
2224 let mut keypair = bob.primary_key().key().clone()
2225 .parts_into_secret()?.into_keypair()?;
2226 let certification = cert.userids().nth(0).unwrap()
2227 .userid()
2228 .certify(&mut keypair, &cert,
2229 SignatureType::PositiveCertification,
2230 None, None)?;
2231 let cert = cert.insert_packets(certification)?.0;
2232
2233 macro_rules! check {
2234 ($cert: expr, $export: ident, $expected: expr) => {
2235 let mut exported = Vec::new();
2236 $cert.$export(&mut exported)?;
2237
2238 let certs = CertParser::from_bytes(&exported)?
2239 .collect::<Result<Vec<Cert>>>()?;
2240
2241 assert_eq!(certs.len(), $expected);
2242
2243 if $expected == 0 {
2244 assert_eq!(exported.len(), 0,
2245 "{}", String::from_utf8_lossy(&exported));
2246 } else {
2247 assert!(exported.len() > 0);
2248 }
2249 }
2250 }
2251
2252 // Binary cert:
2253 check!(cert, export, 0);
2254 check!(cert, serialize, 1);
2255
2256 // Binary TSK:
2257 check!(cert.as_tsk(), export, 0);
2258 check!(cert.as_tsk(), serialize, 1);
2259
2260 // Armored cert:
2261 check!(cert.armored(), export, 0);
2262 check!(cert.armored(), serialize, 1);
2263
2264 // Armored TSK:
2265 check!(cert.as_tsk().armored(), export, 0);
2266 check!(cert.as_tsk().armored(), serialize, 1);
2267
2268 // Have Alice add an exportable self signature. Now her
2269 // certificate should be exportable.
2270 let mut keypair = cert.primary_key().key().clone()
2271 .parts_into_secret()?.into_keypair()?;
2272 let certification = cert.userids().nth(0).unwrap()
2273 .userid()
2274 .certify(&mut keypair, &cert,
2275 SignatureType::PositiveCertification,
2276 None, None)?;
2277 let cert = cert.insert_packets(certification)?.0;
2278
2279 macro_rules! check {
2280 ($cert: expr, $export: ident, $expected: expr) => {
2281 let mut exported = Vec::new();
2282 $cert.$export(&mut exported)?;
2283
2284 let certs = CertParser::from_bytes(&exported)?
2285 .collect::<Result<Vec<Cert>>>()?;
2286
2287 assert_eq!(certs.len(), $expected);
2288
2289 if $expected == 0 {
2290 assert_eq!(exported.len(), 0,
2291 "{}", String::from_utf8_lossy(&exported));
2292 } else {
2293 assert!(exported.len() > 0);
2294 }
2295 }
2296 }
2297
2298 // Binary cert:
2299 check!(cert, export, 1);
2300 check!(cert, serialize, 1);
2301
2302 // Binary TSK:
2303 check!(cert.as_tsk(), export, 1);
2304 check!(cert.as_tsk(), serialize, 1);
2305
2306 // Armored cert:
2307 check!(cert.armored(), export, 1);
2308 check!(cert.armored(), serialize, 1);
2309
2310 // Armored TSK:
2311 check!(cert.as_tsk().armored(), export, 1);
2312 check!(cert.as_tsk().armored(), serialize, 1);
2313
2314 Ok(())
2315 }
2316
2317 #[test]
2318 fn check_algos() {
2319 for (cipher_suite, profile, algos, curves) in [
2320 (CipherSuite::Cv25519,
2321 Profile::RFC4880,
2322 &[ PublicKeyAlgorithm::EdDSA, PublicKeyAlgorithm::ECDH ][..],
2323 &[ Curve::Ed25519, Curve::Cv25519, ][..]),
2324 (CipherSuite::Cv25519,
2325 Profile::RFC9580,
2326 &[ PublicKeyAlgorithm::Ed25519, PublicKeyAlgorithm::X25519 ],
2327 &[]),
2328
2329 (CipherSuite::Cv448,
2330 Profile::RFC4880,
2331 &[ PublicKeyAlgorithm::Ed448, PublicKeyAlgorithm::X448 ],
2332 &[]),
2333 (CipherSuite::Cv448,
2334 Profile::RFC9580,
2335 &[ PublicKeyAlgorithm::Ed448, PublicKeyAlgorithm::X448 ],
2336 &[]),
2337
2338 (CipherSuite::RSA2k,
2339 Profile::RFC4880,
2340 &[ PublicKeyAlgorithm::RSAEncryptSign ],
2341 &[]),
2342 (CipherSuite::RSA2k,
2343 Profile::RFC9580,
2344 &[ PublicKeyAlgorithm::RSAEncryptSign ],
2345 &[]),
2346
2347 (CipherSuite::RSA3k,
2348 Profile::RFC4880,
2349 &[ PublicKeyAlgorithm::RSAEncryptSign ],
2350 &[]),
2351 (CipherSuite::RSA3k,
2352 Profile::RFC9580,
2353 &[ PublicKeyAlgorithm::RSAEncryptSign ],
2354 &[]),
2355
2356 (CipherSuite::RSA4k,
2357 Profile::RFC4880,
2358 &[ PublicKeyAlgorithm::RSAEncryptSign ],
2359 &[]),
2360 (CipherSuite::RSA4k,
2361 Profile::RFC9580,
2362 &[ PublicKeyAlgorithm::RSAEncryptSign ],
2363 &[]),
2364
2365 (CipherSuite::P256,
2366 Profile::RFC4880,
2367 &[ PublicKeyAlgorithm::ECDSA, PublicKeyAlgorithm::ECDH ],
2368 &[ Curve::NistP256 ]),
2369 (CipherSuite::P256,
2370 Profile::RFC9580,
2371 &[ PublicKeyAlgorithm::ECDSA, PublicKeyAlgorithm::ECDH ],
2372 &[ Curve::NistP256 ]),
2373
2374 (CipherSuite::P384,
2375 Profile::RFC4880,
2376 &[ PublicKeyAlgorithm::ECDSA, PublicKeyAlgorithm::ECDH ],
2377 &[ Curve::NistP384 ]),
2378 (CipherSuite::P384,
2379 Profile::RFC9580,
2380 &[ PublicKeyAlgorithm::ECDSA, PublicKeyAlgorithm::ECDH ],
2381 &[ Curve::NistP384 ]),
2382
2383 (CipherSuite::P521,
2384 Profile::RFC4880,
2385 &[ PublicKeyAlgorithm::ECDSA, PublicKeyAlgorithm::ECDH ],
2386 &[ Curve::NistP521 ]),
2387 (CipherSuite::P521,
2388 Profile::RFC9580,
2389 &[ PublicKeyAlgorithm::ECDSA, PublicKeyAlgorithm::ECDH ],
2390 &[ Curve::NistP521 ]),
2391 ]
2392 {
2393 eprintln!("Testing that generating {:?}, {:?} results in \
2394 algorithms: {}; curves: {}",
2395 cipher_suite, profile,
2396 algos
2397 .iter()
2398 .map(|a| a.to_string())
2399 .collect::<Vec<_>>()
2400 .join(", "),
2401 if curves.is_empty() {
2402 "none".to_string()
2403 } else {
2404 curves
2405 .iter()
2406 .map(|a| a.to_string())
2407 .collect::<Vec<_>>()
2408 .join(", ")
2409 });
2410
2411 if let Err(err) = cipher_suite.is_supported() {
2412 eprintln!("Skipping, cipher suite is not supported: {}", err);
2413 continue;
2414 }
2415
2416 let (cert, _) = CertBuilder::general_purpose(Some("x@example.org"))
2417 .set_cipher_suite(cipher_suite)
2418 .set_profile(profile)
2419 .expect("Profile is supported")
2420 .generate()
2421 .expect("Cipher suite is supported");
2422
2423 let mut algos_got = cert.keys()
2424 .map(|ka| ka.key().pk_algo())
2425 .collect::<Vec<_>>();
2426 algos_got.sort();
2427 algos_got.dedup();
2428
2429 let mut algos_expected = algos.to_vec();
2430 algos_expected.sort();
2431
2432 assert_eq!(&algos_expected, &algos_got,
2433 "\n\
2434 algos expected: {}\n\
2435 algos got: {}",
2436 algos_expected
2437 .iter()
2438 .map(|a| a.to_string())
2439 .collect::<Vec<_>>()
2440 .join(", "),
2441 algos_got
2442 .iter()
2443 .map(|a| a.to_string())
2444 .collect::<Vec<_>>()
2445 .join(", "));
2446
2447
2448 let mut curves_got = cert.keys()
2449 .filter_map(|ka| match ka.key().mpis() {
2450 PublicKey::EdDSA { curve, .. }
2451 | PublicKey::ECDSA { curve, .. }
2452 | PublicKey::ECDH { curve, .. } =>
2453 {
2454 Some(curve.clone())
2455 }
2456 _ => None,
2457 })
2458 .collect::<Vec<_>>();
2459 curves_got.sort();
2460 curves_got.dedup();
2461
2462 let mut curves_expected = curves.to_vec();
2463 curves_expected.sort();
2464
2465 assert_eq!(&curves_expected, &curves_got,
2466 "\n\
2467 curves expected: {}\n\
2468 curves got: {}",
2469 if curves_expected.is_empty() {
2470 "(none)".to_string()
2471 } else {
2472 curves_expected
2473 .iter()
2474 .map(|a| a.to_string())
2475 .collect::<Vec<_>>()
2476 .join(", ")
2477 },
2478 if curves_got.is_empty() {
2479 "(none)".to_string()
2480 } else {
2481 curves_got
2482 .iter()
2483 .map(|a| a.to_string())
2484 .collect::<Vec<_>>()
2485 .join(", ")
2486 });
2487 }
2488 }
2489}