sequoia_openpgp/cert/builder/key.rs
1use std::time::{Duration, SystemTime};
2
3use crate::packet::{
4 Key,
5 key,
6};
7
8use crate::Result;
9use crate::Packet;
10use crate::packet::signature::{
11 SignatureBuilder,
12 SIG_BACKDATE_BY,
13 subpacket::SubpacketTag,
14};
15use crate::cert::prelude::*;
16use crate::Error;
17use crate::Profile;
18use crate::crypto::{Password, Signer};
19use crate::types::{
20 HashAlgorithm,
21 KeyFlags,
22 SignatureType,
23};
24
25/// A Key builder.
26///
27/// A `KeyBuilder` is used to create a key, which can then be attached
28/// to an existing certificate as a subkey using
29/// [`KeyBuilder::subkey`].
30///
31/// # Examples
32///
33/// Generate a signing key and attach it to a certificate:
34///
35/// ```
36/// use sequoia_openpgp as openpgp;
37/// use openpgp::cert::prelude::*;
38/// use openpgp::policy::StandardPolicy;
39/// use openpgp::types::KeyFlags;
40///
41/// # fn main() -> openpgp::Result<()> {
42/// let p = &StandardPolicy::new();
43///
44/// # let (cert, _) =
45/// # CertBuilder::general_purpose(Some("alice@example.org"))
46/// # .generate()?;
47/// #
48/// let vc = cert.with_policy(p, None)?;
49/// # let vc1 = vc.clone();
50/// let cert_new = KeyBuilder::new(KeyFlags::empty().set_signing())
51/// .subkey(vc)?
52/// .attach_cert()?;
53/// # let vc2 = cert_new.with_policy(p, None)?;
54/// # assert_eq!(vc1.keys().count() + 1, vc2.keys().count());
55/// # Ok(())
56/// # }
57/// ```
58pub struct KeyBuilder {
59 flags: KeyFlags,
60 cipher_suite: CipherSuite,
61 password: Option<Password>,
62 creation_time: Option<SystemTime>,
63}
64assert_send_and_sync!(KeyBuilder);
65
66impl KeyBuilder {
67 /// Returns a new `KeyBuilder`.
68 ///
69 /// Use [`KeyBuilder::subkey`] to generate a subkey and get a
70 /// [`SubkeyBuilder`], which can be used to add the subkey to a
71 /// certificate.
72 pub fn new(flags: KeyFlags) -> Self {
73 KeyBuilder {
74 flags,
75 cipher_suite: Default::default(),
76 creation_time: None,
77 password: None,
78 }
79 }
80
81 /// Returns the selected cipher suite.
82 pub fn cipher_suite(&self) -> CipherSuite {
83 self.cipher_suite
84 }
85
86 /// Sets the cipher suite.
87 pub fn set_cipher_suite(mut self, cipher_suite: CipherSuite) -> Self {
88 self.cipher_suite = cipher_suite;
89 self
90 }
91
92 /// Returns the creation time.
93 ///
94 /// Returns `None` if the creation time hasn't been specified. In
95 /// that case, the creation time will be set to the current time
96 /// when the key material is generated by [`KeyBuilder::subkey`].
97 pub fn creation_time(&self) -> Option<SystemTime> {
98 self.creation_time
99 }
100
101 /// Sets the creation time.
102 ///
103 /// If `None`, then the creation time will be set to the current
104 /// time when the key material is generated by
105 /// [`KeyBuilder::subkey`].
106 pub fn set_creation_time<T>(mut self, creation_time: T) -> Self
107 where T: Into<Option<SystemTime>>
108 {
109 self.creation_time = creation_time.into();
110 self
111 }
112
113 /// Returns the password, if any.
114 pub fn password(&self) -> Option<&Password> {
115 self.password.as_ref()
116 }
117
118 /// Sets the password.
119 pub fn set_password<T>(mut self, password: T) -> Self
120 where T: Into<Option<Password>>
121 {
122 self.password = password.into();
123 self
124 }
125
126 /// Generates a key, and returns a `SubkeyBuilder`.
127 ///
128 /// The [`SubkeyBuilder`] will add the key to the specified
129 /// certificate.
130 ///
131 /// If the key creation time has not been explicitly set using
132 /// [`KeyBuilder::set_creation_time`], then the key's creation
133 /// time is set to the current time minus a few seconds.
134 ///
135 /// Setting the creation time to a short time in the past solves
136 /// two problems. First, when a new binding signature is created,
137 /// it must have a newer time than the previous binding signature.
138 /// This policy ensures that if a second binding signature is
139 /// immediately created after the key is created it does not need
140 /// to be postdated and thus can be used immediately. Second, if
141 /// the key is immediately transferred to another computer and its
142 /// clock is not quite synchronized, the key may appear to have
143 /// been created in the future and will thus be ignored. Although
144 /// NTP is widely used, empirically it seems that some virtual
145 /// machines have laggy clocks.
146 pub fn subkey(self, vc: ValidCert) -> Result<SubkeyBuilder<'_>> {
147 let profile = match vc.primary_key().key().version() {
148 4 => Profile::RFC4880,
149 6 => Profile::RFC9580,
150 n => return Err(Error::InvalidOperation(format!(
151 "Cannot generate a subkey for version {} primary key", n))
152 .into()),
153 };
154
155 let mut key: Key<key::SecretParts, key::SubordinateRole>
156 = self.cipher_suite.generate_key(&self.flags, profile)?
157 .role_into_subordinate();
158 let ct = self.creation_time.unwrap_or_else(|| {
159 crate::now() - Duration::new(SIG_BACKDATE_BY, 0)
160 });
161 key.set_creation_time(ct)?;
162
163 let signer = key.clone().into_keypair().unwrap();
164
165 if let Some(ref password) = self.password {
166 let (k, mut secret) = key.take_secret();
167 secret.encrypt_in_place(&k, password)?;
168 key = k.add_secret(secret).0;
169 }
170
171 let mut builder = SubkeyBuilder::new(
172 vc, key.parts_into_unspecified(), self.flags)?;
173 builder = builder.set_signature_creation_time(ct)?;
174 Ok(builder.set_subkey_signer(signer))
175 }
176}
177
178/// A Subkey builder.
179///
180/// This builder simplifies attaching a subkey to a certificate, or
181/// updating an existing subkey's binding signature. It is a more
182/// high-level variant of [`SignatureBuilder`], which should be used
183/// if more control is needed than this builder provides.
184///
185/// # Security Considerations: Key Expiration
186///
187/// **It is essential that keys have reasonable expiration times.** If
188/// a binding signature is accidentally published without an
189/// expiration time, it is effectively impossible to retract this by
190/// publishing a new binding signature that has an expiration. This
191/// is because an attacker may be able to withhold the newer binding
192/// signature thereby causing a victim to use a key that is actually
193/// expired.
194///
195/// The heuristic described below takes this security consideration
196/// into account. However, because the heuristic never extends a
197/// key's expiration on its own, there are still cases where it is
198/// necessary to set the expiration manually.
199///
200/// # Binding Signature
201///
202/// To attach a subkey to a certificate, the primary key needs to
203/// issue a [subkey binding signature]. This binding signature
204/// provides information about the key including its validity period
205/// (i.e., when it expires), and may contain auxiliary information
206/// like notations. A subkey binding signature usually contains the
207/// following information:
208///
209/// [subkey binding signature]: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.1
210///
211/// - [Signature creation time](https://datatracker.ietf.org/doc/html/rfc4880#section-5.2.3.4)
212///
213/// - [Key flags](https://datatracker.ietf.org/doc/html/rfc4880#section-5.2.3.21)
214///
215/// - [Issuer](https://datatracker.ietf.org/doc/html/rfc4880#section-5.2.3.5) and Issuer Fingerprint.
216///
217/// - [Primary key binding signature](https://datatracker.ietf.org/doc/html/rfc4880#section-5.2.3.26) (if the key is signing capable)
218///
219/// The following information is also meaningful in the context of
220/// a subkey binding signature:
221///
222/// - [Key expiration time](https://datatracker.ietf.org/doc/html/rfc4880#section-5.2.3.6)
223/// (relative to the key's creation time, not the signature's
224/// creation time!)
225///
226/// - [Signature exiration time](https://datatracker.ietf.org/doc/html/rfc4880#section-5.2.3.10)
227///
228/// - [Exportable certification](https://datatracker.ietf.org/doc/html/rfc4880#section-5.2.3.11)
229///
230/// - [Notations](https://datatracker.ietf.org/doc/html/rfc4880#section-5.2.3.16)
231///
232/// Because a `SubkeyBuilder` is just a wrapper around a
233/// [`SignatureBuilder`], refer [`SignatureBuilder`]'s documentation
234/// about to understand how some of these subpackets are automatically
235/// set.
236///
237/// It is possible to change the signature's creation time and key
238/// expiration time using the
239/// [`SubkeyBuilder::set_signature_creation_time`] and
240/// [`SubkeyBuilder::set_key_expiration_time`] methods. Other
241/// subpackets can be modified using
242/// [`SubkeyBuilder::with_signature_template`].
243///
244/// ## Heuristic
245///
246/// This builder uses a heuristic to select a binding signature to use
247/// as a template and to select a key expiration. It is possible to
248/// use your own binding signature by calling
249/// [`SubkeyBuilder::set_signature_template`], and override the key
250/// expiration time using [`SubkeyBuilder::set_key_expiration_time`].
251/// In general, you should use an existing binding signature as a
252/// template to preserve any customizations that the user may have
253/// made.
254///
255/// Because forgetting to set an expiration time can be security
256/// relevant, this heuristic acts conservatively. If possible, the
257/// user interface should show the expiration time, and allow the user
258/// to adjust it manually.
259///
260/// The heuristic is:
261///
262/// - If the subkey is already present on the certificate, the default
263/// binding signature is based on the subkey's active binding
264/// signature, and the key expiration time is reused.
265///
266/// If the key would expire before the binding signature becomes
267/// valid then [`SubkeyBuilder::attach`] will fail.
268///
269/// Note: if the subkey is present, but it does not have a valid
270/// binding signature, then the subkey is treated as a new subkey.
271///
272/// - If the subkey is new, then the active binding signature of the
273/// newest live, non-revoked, valid subkey is used as the binding
274/// signature template. Newest means the key with the latest
275/// Key Creation Time and not necessarily the newest binding
276/// signature. (If multiple keys have the same key creation time,
277/// the key to use is chosen in an undefined, but deterministic
278/// manner.)
279///
280/// If the certificate does not have a subkey, then a default
281/// binding signature is created. In this case, the default
282/// expiration is set to the same expiration as the primary key, if
283/// any.
284///
285/// As above, if the key would expire before the binding signature
286/// becomes valid then [`SubkeyBuilder::attach`] will fail.
287///
288/// # Examples
289///
290/// Add a new, signing-capable subkey to a certificate:
291///
292/// ```
293/// use sequoia_openpgp as openpgp;
294/// use openpgp::cert::prelude::*;
295/// use openpgp::policy::StandardPolicy;
296/// use openpgp::types::KeyFlags;
297///
298/// # fn main() -> openpgp::Result<()> {
299/// let p = &StandardPolicy::new();
300///
301/// # let (cert, _) =
302/// # CertBuilder::general_purpose(Some("alice@example.org"))
303/// # .generate()?;
304/// #
305/// let vc = cert.with_policy(p, None)?;
306/// # let vc1 = vc.clone();
307/// let cert_new = KeyBuilder::new(KeyFlags::empty().set_signing())
308/// .subkey(vc)?
309/// .attach_cert()?;
310/// # let vc2 = cert_new.with_policy(p, None)?;
311/// # assert_eq!(vc1.keys().count() + 1, vc2.keys().count());
312/// # Ok(())
313/// # }
314/// ```
315///
316/// Import a raw encryption key:
317///
318/// ```
319/// use std::time::SystemTime;
320///
321/// use sequoia_openpgp as openpgp;
322/// use openpgp::cert::prelude::*;
323/// use openpgp::packet::Key;
324/// use openpgp::packet::key::Key4;
325/// use openpgp::policy::StandardPolicy;
326/// use openpgp::types::KeyFlags;
327///
328/// # fn main() -> openpgp::Result<()> {
329/// let p = &StandardPolicy::new();
330///
331/// # let q = b"\x57\x15\x45\x1B\x68\xA5\x13\xA2\x20\x0F\x71\x9D\xE3\x05\x3B\xED\xA2\x21\xDE\x61\x5A\xF5\x67\x45\xBB\x97\x99\x43\x53\x59\x7C\x3F";
332/// let k: Key<_, _>
333/// = Key4::import_public_ed25519(q, SystemTime::now())?.into();
334///
335/// # let (cert, _) = CertBuilder::new().generate()?;
336/// #
337/// let vc = cert.with_policy(p, None)?;
338/// # let vc1 = vc.clone();
339/// let mut cert2 = SubkeyBuilder::new(
340/// vc, k.parts_into_unspecified(),
341/// KeyFlags::empty().set_transport_encryption())?
342/// .attach_cert()?;
343/// #
344/// # let vc2 = cert2.with_policy(p, None)?;
345/// # assert_eq!(vc1.keys().count() + 1, vc2.keys().count());
346/// # Ok(())
347/// # }
348/// ```
349///
350/// Change all valid, non-revoked subkeys to expire in a year from now:
351///
352/// ```
353/// use std::time::{SystemTime, Duration};
354///
355/// use sequoia_openpgp as openpgp;
356/// use openpgp::cert::prelude::*;
357/// use openpgp::Packet;
358/// use openpgp::policy::StandardPolicy;
359/// use openpgp::types::KeyFlags;
360///
361/// # fn main() -> openpgp::Result<()> {
362/// let p = &StandardPolicy::new();
363///
364/// let now = SystemTime::now();
365/// let e = now + Duration::new(365 * 24 * 60 * 60, 0);
366///
367/// # let v = Duration::new(24 * 60 * 60, 0);
368/// # let (cert, _) =
369/// # CertBuilder::new()
370/// # .set_creation_time(now - Duration::new(60, 0))
371/// # .add_subkey(KeyFlags::empty().set_storage_encryption(),
372/// # v, None)
373/// # .add_subkey(KeyFlags::empty().set_signing(),
374/// # v, None)
375/// # .generate()?;
376/// # assert_eq!(cert.keys().subkeys().count(), 2);
377/// let vc = cert.with_policy(p, None)?;
378/// # assert_eq!(vc.keys().subkeys().count(), 2);
379/// # for ka in vc.keys().subkeys() {
380/// # assert_eq!(ka.key_validity_period(), Some(v));
381/// # }
382///
383/// // If you only want to extend non-expired keys, then add .alive().
384/// let packets = vc.keys().subkeys().revoked(false)
385/// .map(|ka| {
386/// SubkeyBuilder::from(ka)
387/// .set_signature_creation_time(now)?
388/// .set_key_expiration_time(e)?
389/// .attach()
390/// })
391/// .collect::<Result<Vec<Vec<Packet>>, _>>()?;
392/// let cert = cert.insert_packets(packets.into_iter().flatten())?.0;
393///
394/// let vc = cert.with_policy(p, now)?;
395/// # assert_eq!(vc.keys().subkeys().count(), 2);
396/// for ka in vc.keys().subkeys().revoked(false) {
397/// // Check that the key's expiration time is really e. Note: We
398/// // need to take into account that SystemTime has a subsecond
399/// // resolution, but OpenPGP's timestamps only have a 1-second
400/// // resolution.
401/// assert!(e.duration_since(ka.key_expiration_time().unwrap()).unwrap()
402/// < Duration::new(1, 0));
403/// }
404/// # Ok(())
405/// # }
406/// ```
407pub struct SubkeyBuilder<'a> {
408 vc: ValidCert<'a>,
409 primary_signer: Option<Box<dyn Signer + Send + Sync + 'a>>,
410
411 subkey: Key<key::UnspecifiedParts, key::SubordinateRole>,
412 subkey_signer: Option<Box<dyn Signer + Send + Sync + 'a>>,
413
414 template: SignatureBuilder,
415}
416assert_send_and_sync!(SubkeyBuilder<'_>);
417
418impl<'a> SubkeyBuilder<'a> {
419 /// Returns a SubkeyBuilder that will add the key to the specified
420 /// certificate.
421 ///
422 /// If the subkey is already present on the certificate, then the
423 /// `SubkeyBuilder` effectively adds a new binding signature to
424 /// the certificate.
425 pub fn new<P>(vc: ValidCert<'a>,
426 subkey: Key<P, key::SubordinateRole>,
427 subkey_flags: KeyFlags)
428 -> Result<Self>
429 where P: key::KeyParts,
430 {
431 // If the key is already present on the certificate, then we
432 // use the current self signature on that subkey as the
433 // template.
434 let (template, key_expiration): (SignatureBuilder, Option<SystemTime>)
435 = vc.keys().subkeys()
436 .filter_map(|ka| {
437 if ka.key().parts_as_unspecified().public_eq(&subkey) {
438 let sig = ka.binding_signature().clone();
439 let e = sig.key_validity_period().map(|v| {
440 ka.key().creation_time() + v
441 });
442 Some((sig.into(), e))
443 } else {
444 None
445 }
446 })
447 .next()
448 .or_else(|| {
449 // The key is completely new. Use the active self
450 // signature on the newest, non-revoked, non-expired
451 // subkey.
452 vc.keys().subkeys().revoked(false).alive()
453 // Fallback to sorting by fingerprint to ensure
454 // this is deterministic.
455 .max_by_key(|ka| (ka.key().creation_time(), ka.key().fingerprint()))
456 .map(|ka| {
457 let sig = ka.binding_signature().clone();
458 let e = sig.key_validity_period().map(|v| {
459 ka.key().creation_time() + v
460 });
461 (sig.into(), e)
462 })
463 })
464 .unwrap_or_else(|| {
465 // The certificate doesn't have any valid subkeys, so
466 // we don't have existing signatures that we can use
467 // as a template. In this case, we use a default
468 // binding signature, and the primary key's expiration
469 // time.
470 (SignatureBuilder::new(SignatureType::SubkeyBinding),
471 vc.primary_key().key_validity_period().map(|v| {
472 vc.primary_key().key().creation_time() + v
473 }))
474 });
475
476 let template = template.set_key_flags(subkey_flags)?;
477
478 let mut builder = SubkeyBuilder {
479 vc,
480 primary_signer: None,
481 subkey: subkey.parts_into_unspecified(),
482 subkey_signer: None,
483 template: SignatureBuilder::new(SignatureType::SubkeyBinding),
484 };
485 builder = builder.set_signature_template(template);
486 builder = builder.set_key_expiration_time(key_expiration)?;
487
488 Ok(builder)
489 }
490
491 /// Like SubkeyBuilder::new, but the binding signature is supplied.
492 ///
493 /// # Security Considerations
494 ///
495 /// The key validity period (i.e., the [Key Expiration Time
496 /// subpacket]) is left as is. **The Key Expiration Time
497 /// subpacket contains a relative time.** Thus, if you are using a
498 /// signature from another key with a different key creation time
499 /// as a template, the effective key expiration time will be
500 /// different! In this case, you should set the key expiration
501 /// time explicitly by calling
502 /// [`SubkeyBuilder::set_key_expiration_time`] or
503 /// [`SubkeyBuilder::set_key_validity_period`].
504 ///
505 /// [Key Expiration Time subpacket]: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.13
506 ///
507 /// # Examples
508 ///
509 /// Adjusting the key expiration time:
510 ///
511 /// ```
512 /// use std::time::{SystemTime, Duration};
513 ///
514 /// use sequoia_openpgp as openpgp;
515 /// use openpgp::cert::prelude::*;
516 /// use openpgp::packet::Key;
517 /// use openpgp::packet::key::Key4;
518 /// use openpgp::policy::StandardPolicy;
519 /// use openpgp::types::KeyFlags;
520 ///
521 /// # fn main() -> openpgp::Result<()> {
522 /// let p = &StandardPolicy::new();
523 ///
524 /// let now = SystemTime::now();
525 /// let year = Duration::new(365 * 24 * 60 * 60, 0);
526 /// let last_year = now - year;
527 /// // cert was created last year and expires after two years.
528 /// let (cert, _) =
529 /// CertBuilder::new()
530 /// .set_creation_time(now - year)
531 /// .add_subkey(KeyFlags::empty().set_transport_encryption(),
532 /// 2 * year, None)
533 /// .generate()?;
534 ///
535 /// // Import a raw key and add it to the certificate. We
536 /// // explicitly reuse the existing subkey's signature, and adjust
537 /// // the key expiration time.
538 ///
539 /// # let q = b"\x57\x15\x45\x1B\x68\xA5\x13\xA2\x20\x0F\x71\x9D\xE3\x05\x3B\xED\xA2\x21\xDE\x61\x5A\xF5\x67\x45\xBB\x97\x99\x43\x53\x59\x7C\x3F";
540 /// let k: Key<_, _> = Key4::import_public_ed25519(q, now)?.into();
541 ///
542 /// let vc = cert.with_policy(p, now)?;
543 /// let template
544 /// = vc.keys().subkeys().next().unwrap().binding_signature().clone();
545 /// # let vc1 = vc.clone();
546 /// let cert2 = SubkeyBuilder::new_with(vc, k, template)
547 /// .set_key_validity_period(year)?
548 /// .attach_cert()?;
549 /// let vc2 = cert2.with_policy(p, now)?;
550 /// # assert_eq!(vc1.keys().count() + 1, vc2.keys().count());
551 ///
552 /// // Observe that both keys expire one year from now. If we
553 /// // hadn't adjusted the validity period of the new key, it would
554 /// // have expired in two years from now, because the key validity
555 /// // period is relative to the key's creation time!
556 /// vc2.keys().subkeys().for_each(|sig| {
557 /// // SystemTime has a subsection resolution.
558 /// assert!((now + year)
559 /// .duration_since(sig.key_expiration_time().unwrap())
560 /// .unwrap()
561 /// < Duration::new(1, 0));
562 /// });
563 /// # Ok(())
564 /// # }
565 /// ```
566 pub fn new_with<P, T>(vc: ValidCert<'a>,
567 subkey: Key<P, key::SubordinateRole>,
568 template: T)
569 -> Self
570 where P: key::KeyParts,
571 T: Into<SignatureBuilder>,
572 {
573 let template = template.into();
574
575 let mut builder = SubkeyBuilder {
576 vc,
577 primary_signer: None,
578 subkey: subkey.parts_into_unspecified(),
579 subkey_signer: None,
580 template: SignatureBuilder::new(SignatureType::SubkeyBinding),
581 };
582 builder = builder.set_signature_template(template);
583 builder
584 }
585
586 /// Sets the signature template that will be used for the binding
587 /// signature.
588 ///
589 /// This effectively discards any previous calls to
590 /// [`SubkeyBuilder::set_signature_creation_time`],
591 /// [`SubkeyBuilder::set_key_expiration_time`], etc.
592 ///
593 /// This function modifies the template as follows:
594 ///
595 /// - The hash algorithm is set to a safe default.
596 ///
597 /// These changes can be overridden by using
598 /// [`SubkeyBuilder::with_signature_template`].
599 ///
600 /// # Security Considerations
601 ///
602 /// The key validity period (i.e., the [Key Expiration Time
603 /// subpacket]) is left as is. **This packet contains a relative
604 /// time.** Thus, if you are using a Signature from another key
605 /// with a different key creation time as a template, the
606 /// effective key expiration time will be different! In this
607 /// case, you should set the key expiration time explicitly by
608 /// calling [`SubkeyBuilder::set_key_expiration_time`] or
609 /// [`SubkeyBuilder::set_key_validity_period`].
610 ///
611 /// [Key Expiration Time subpacket]: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.3.13
612 pub fn set_signature_template<T>(mut self, template: T) -> Self
613 where T: Into<SignatureBuilder>,
614 {
615 self.template = template.into();
616
617 // GnuPG wants at least a 512-bit hash for P521 keys.
618 self.template = self.template.set_hash_algo(HashAlgorithm::SHA512);
619
620 self
621 }
622
623 /// Allows a function to directly modify the signature template.
624 ///
625 /// This function does not fail; it returns the result of the
626 /// callback function.
627 ///
628 /// # Examples
629 ///
630 /// Add a notation to an existing key:
631 ///
632 /// ```
633 /// use sequoia_openpgp as openpgp;
634 /// use openpgp::cert::prelude::*;
635 /// use openpgp::packet::signature::subpacket::NotationDataFlags;
636 /// use openpgp::policy::StandardPolicy;
637 /// use openpgp::types::KeyFlags;
638 ///
639 /// # fn main() -> openpgp::Result<()> {
640 /// let p = &StandardPolicy::new();
641 ///
642 /// # let (cert, _) = CertBuilder::new().add_signing_subkey().generate()?;
643 /// let vc = cert.with_policy(p, None)?;
644 /// let cert2 = SubkeyBuilder::from(vc.keys().subkeys().next().unwrap())
645 /// .with_signature_template(|sig| {
646 /// sig.add_notation("policy@example.org", b"1",
647 /// NotationDataFlags::empty().set_human_readable(),
648 /// false /* critical */)
649 /// })?
650 /// .attach_cert()?;
651 /// # let vc2 = cert2.with_policy(p, None)?;
652 /// # assert_eq!(vc2.keys().count(), 2);
653 /// # let ka = vc2.keys().subkeys().next().unwrap();
654 /// # assert_eq!(ka.self_signatures().count(), 2);
655 /// # assert_eq!(
656 /// # ka.binding_signature().notation("policy@example.org")
657 /// # .collect::<Vec<_>>(),
658 /// # vec![ b"1" ]);
659 /// # Ok(())
660 /// # }
661 /// ```
662 pub fn with_signature_template<F>(mut self, f: F) -> Result<Self>
663 where F: FnOnce(SignatureBuilder) -> Result<SignatureBuilder>
664 {
665 self.template = f(self.template.clone())?;
666
667 Ok(self)
668 }
669
670 /// Sets the binding signature's creation time.
671 ///
672 /// This directly modifies the current signature template.
673 ///
674 /// This just calls
675 /// [`SignatureBuilder::set_signature_creation_time`] on the
676 /// signature template.
677 pub fn set_signature_creation_time<T>(mut self, creation_time: T)
678 -> Result<Self>
679 where T: Into<SystemTime>
680 {
681 self.template = self.template.set_signature_creation_time(
682 creation_time.into())?;
683 Ok(self)
684 }
685
686 /// Preserves the signature creation time set in the template.
687 ///
688 /// This directly modifies the current signature template.
689 ///
690 /// This just calls
691 /// [`SignatureBuilder::preserve_signature_creation_time`] on the
692 /// signature template.
693 pub fn preserve_signature_creation_time(mut self) -> Result<Self>
694 {
695 self.template
696 = self.template.preserve_signature_creation_time()?;
697 Ok(self)
698 }
699
700 /// Sets the key's expiration time.
701 ///
702 /// This directly modifies the current signature template.
703 ///
704 /// This returns an error if the expiration time is before the
705 /// key's creation time.
706 pub fn set_key_expiration_time<T>(mut self, key_expiration_time: T)
707 -> Result<Self>
708 where T: Into<Option<SystemTime>>
709 {
710 let key_expiration_time = key_expiration_time.into();
711 let validity_period = key_expiration_time
712 .map(|e| {
713 e.duration_since(self.subkey.creation_time())
714 .map_err(|_| {
715 Error::InvalidArgument(
716 "expiration time precedes creation time".into())
717 })
718 })
719 .transpose()?;
720
721 self = self.with_signature_template(|sig| {
722 sig.set_key_validity_period(validity_period)
723 })?;
724
725 Ok(self)
726 }
727
728 /// Sets the key's validity period.
729 ///
730 /// The validity period is the amount of time after the key's
731 /// creation time that the key is considered fresh (i.e., not
732 /// expired).
733 ///
734 /// This directly modifies the current signature template.
735 pub fn set_key_validity_period<T>(mut self, validity: T)
736 -> Result<Self>
737 where T: Into<Option<Duration>>
738 {
739 self = self.with_signature_template(|sig| {
740 sig.set_key_validity_period(validity.into())
741 })?;
742
743 Ok(self)
744 }
745
746 /// Returns a reference to the subkey.
747 pub fn key(&self) -> &Key<key::UnspecifiedParts, key::SubordinateRole> {
748 &self.subkey
749 }
750
751 /// Adds a signer for the primary key.
752 ///
753 /// In order to attach a subkey to a certificate one or more
754 /// signatures need to be issued. First, the primary key needs to
755 /// issue a [subkey binding signature]. If the subkey is signing
756 /// capable, then it also needs to issue a [primary key binding
757 /// signature]. By default, [`SubkeyBuilder::attach`] will
758 /// automatically derive the signers from the key material. This
759 /// only works, however, if the key material is present, and it is
760 /// unencrypted. This method allows you to explicitly provide a
761 /// signer for the primary key.
762 ///
763 /// [subkey binding signature]: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.1
764 /// [primary binding signature]: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.1
765 pub fn set_primary_key_signer<S>(mut self, signer: S) -> Self
766 where S: Signer + Send + Sync + 'a,
767 {
768 self.primary_signer = Some(Box::new(signer));
769 self
770 }
771
772 /// Adds a signer for the subkey.
773 ///
774 /// In order to attach a subkey to a certificate one or more
775 /// signatures need to be issued. First, the primary key needs to
776 /// issue a [subkey binding signature]. If the subkey is signing
777 /// capable, then it also needs to issue a [primary key binding
778 /// signature]. By default, [`SubkeyBuilder::attach`] will
779 /// automatically derive the signers from the key material. This
780 /// only works, however, if the key material is present, and it is
781 /// unencrypted. This method allows you to explicitly provide a
782 /// signer for the subkey.
783 ///
784 /// [subkey binding signature]: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.1
785 /// [primary binding signature]: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.2.1
786 pub fn set_subkey_signer<S>(mut self, signer: S) -> Self
787 where S: Signer + Send + Sync + 'a,
788 {
789 self.subkey_signer = Some(Box::new(signer));
790 self
791 }
792
793 /// Attaches the subkey to the certificate.
794 ///
795 /// This method generates the appropriate signatures to attach the
796 /// subkey to the certificate.
797 ///
798 /// This function returns an error if the expiration time would
799 /// cause the key to expire before the binding signature's
800 /// expiration time.
801 ///
802 /// This method returns a number of packets, which need to be
803 /// merged into the cert. This can be done using
804 /// [`Cert::insert_packets`].
805 pub fn attach(self) -> Result<Vec<Packet>> {
806 let SubkeyBuilder {
807 vc,
808 primary_signer,
809 subkey,
810 subkey_signer,
811 template,
812 } = self;
813
814 if template.typ() != SignatureType::SubkeyBinding {
815 return Err(Error::InvalidArgument(
816 format!("Expected a SubkeyBinding signature, got a {}",
817 template.typ())).into());
818 }
819
820 let mut builder = template;
821
822 let creation_time = builder.effective_signature_creation_time()?;
823
824 // creation_time is only None if
825 // preserve_signature_creation_time is done and that's a
826 // Highly Advanced Interface that doesn't need sanity checks.
827 if let Some(sig_ct) = creation_time {
828 if let Some(v) = builder.key_validity_period() {
829 let e = subkey.creation_time() + v;
830 if let Err(err) = e.duration_since(sig_ct) {
831 return Err(Error::InvalidArgument(
832 format!(
833 "key expiration precedes signature creation time \
834 (by {:?})",
835 err.duration())).into());
836 }
837 }
838 }
839
840 if let Some(flags) = builder.key_flags() {
841 if flags.for_certification() || flags.for_signing()
842 || flags.for_authentication()
843 {
844 // We need to create a primary key binding signature.
845 let mut subkey_signer = if let Some(signer) = subkey_signer {
846 signer
847 } else {
848 Box::new(
849 subkey.clone().parts_into_secret()?.into_keypair()?)
850 };
851
852 let mut backsig =
853 SignatureBuilder::new(
854 SignatureType::PrimaryKeyBinding)
855 // GnuPG wants at least a 512-bit hash for P521 keys.
856 .set_hash_algo(HashAlgorithm::SHA512)
857 .set_reference_time(creation_time)?;
858 if let Some(t) = creation_time {
859 backsig = backsig.set_reference_time(t)?;
860 } else {
861 backsig = backsig.preserve_signature_creation_time()?;
862 }
863 let backsig = backsig.sign_primary_key_binding(
864 &mut *subkey_signer, vc.primary_key().key(), &subkey)?;
865 builder = builder.set_embedded_signature(backsig)?;
866 } else {
867 // We don't need the embedded signature, remove it.
868 builder.hashed_area_mut()
869 .remove_all(SubpacketTag::EmbeddedSignature);
870 builder.unhashed_area_mut()
871 .remove_all(SubpacketTag::EmbeddedSignature);
872 }
873 }
874
875 let mut primary_signer = if let Some(signer) = primary_signer {
876 signer
877 } else {
878 Box::new(
879 vc.primary_key().key().clone()
880 .parts_into_secret()?.into_keypair()?)
881 };
882
883 let signature = subkey.bind(
884 &mut *primary_signer, vc.cert(), builder)?;
885
886 let subkey = if subkey.has_secret() {
887 Packet::SecretSubkey(subkey.parts_into_secret().unwrap())
888 } else {
889 Packet::PublicSubkey(subkey.parts_into_public())
890 };
891
892 Ok(vec![subkey, signature.into()])
893 }
894
895 /// Attaches the subkey directly to the certificate.
896 ///
897 /// This function is like [`SubkeyBuilder::attach`], but it also
898 /// merges the resulting packets into the certificate.
899 ///
900 /// Note: if you are adding multiple subkeys to a certificate or
901 /// updating multiple subkeys, it is usually more efficient to use
902 /// [`SubkeyBuilder::attach`], and then merge all the packets
903 /// at once.
904 ///
905 /// # Examples
906 ///
907 /// ```
908 /// use sequoia_openpgp as openpgp;
909 /// use openpgp::cert::prelude::*;
910 /// use openpgp::policy::StandardPolicy;
911 /// use openpgp::types::KeyFlags;
912 ///
913 /// # fn main() -> openpgp::Result<()> {
914 /// let p = &StandardPolicy::new();
915 ///
916 /// # let (cert, _) =
917 /// # CertBuilder::general_purpose(Some("alice@example.org"))
918 /// # .generate()?;
919 /// #
920 /// let vc = cert.with_policy(p, None)?;
921 /// # let vc1 = vc.clone();
922 /// let cert2 = KeyBuilder::new(KeyFlags::empty().set_signing())
923 /// .subkey(vc)?
924 /// .attach_cert()?;
925 /// # let vc2 = cert2.with_policy(p, None)?;
926 /// # assert_eq!(vc1.keys().count() + 1, vc2.keys().count());
927 /// # Ok(())
928 /// # }
929 /// ```
930 pub fn attach_cert(self) -> Result<Cert> {
931 let cert = self.vc.cert().clone();
932 let packets = self.attach()?;
933 Ok(cert.insert_packets(packets)?.0)
934 }
935}
936
937impl<'a, P> From<ValidPrimaryKeyAmalgamation<'a, P>> for SubkeyBuilder<'a>
938where
939 P: key::KeyParts + Clone,
940{
941 fn from(ka: ValidPrimaryKeyAmalgamation<'a, P>) -> Self {
942 ValidErasedKeyAmalgamation::from(ka).into()
943 }
944}
945
946impl<'a, P> From<ValidSubordinateKeyAmalgamation<'a, P>> for SubkeyBuilder<'a>
947where
948 P: key::KeyParts + Clone,
949{
950 fn from(ka: ValidSubordinateKeyAmalgamation<'a, P>) -> Self {
951 ValidErasedKeyAmalgamation::from(ka).into()
952 }
953}
954
955impl<'a, P> From<ValidErasedKeyAmalgamation<'a, P>> for SubkeyBuilder<'a>
956where
957 P: key::KeyParts + Clone,
958{
959 fn from(ka: ValidErasedKeyAmalgamation<'a, P>) -> SubkeyBuilder<'a> {
960 let key = ka.key().clone().role_into_subordinate();
961 SubkeyBuilder::new_with(
962 ka.valid_cert().clone(), key, ka.binding_signature().clone())
963 }
964}
965
966#[cfg(test)]
967mod test {
968 use super::*;
969 use std::time::{Duration, UNIX_EPOCH};
970
971 use crate::policy::StandardPolicy;
972
973 #[test]
974 fn expiry() -> Result<()> {
975 let p = &StandardPolicy::new();
976
977 // t0: Create certificate, keys expire at t2.
978 // t1: Add a new key, heuristic should have it expire at t2.
979 // t2: All keys expire.
980
981 // We do it all in the past to make sure the current time is
982 // never used.
983
984 // Avoid milliseconds.
985 let t1 = crate::now() - Duration::new(7 * 24 * 60 * 60, 0);
986 let t1 = t1.duration_since(UNIX_EPOCH)?.as_secs();
987 let t1 = UNIX_EPOCH + Duration::new(t1, 0);
988
989 let t0 = t1 - Duration::new(60 * 60, 0);
990 let t2 = t1 + Duration::new(60 * 60, 0);
991 let validity = t2.duration_since(t0).unwrap();
992
993 let (pre, _) =
994 CertBuilder::general_purpose(Some("alice@example.org"))
995 .set_creation_time(t0)
996 .set_validity_period(validity)
997 .generate()?;
998
999 let vc_pre = pre.with_policy(p, t1)?;
1000 let post = KeyBuilder::new(KeyFlags::empty().set_signing())
1001 .set_creation_time(t1)
1002 .subkey(vc_pre)?
1003 .set_signature_creation_time(t1)?
1004 .attach_cert()?;
1005
1006 let vc_post = post.with_policy(p, t1).unwrap();
1007
1008 // We should have one more key.
1009 assert_eq!(pre.keys().count() + 1, post.keys().count());
1010
1011 // Make sure the signature and backsig are valid.
1012 assert_eq!(post.keys().count(), vc_post.keys().count());
1013
1014 // And the new key should have inherited the other keys'
1015 // expiration.
1016 eprintln!("t0: {:?}", t0);
1017 eprintln!("t1: {:?}", t1);
1018 eprintln!("t2: {:?}", t2);
1019 assert!(vc_post.keys().all(|ka| {
1020 eprintln!("{}: {:?} -> {:?}",
1021 ka.key().fingerprint(),
1022 ka.key().creation_time(),
1023 ka.key_expiration_time());
1024 ka.key_expiration_time() == Some(t2)
1025 }));
1026
1027 Ok(())
1028 }
1029}