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}