sequoia_openpgp/packet/key/
v6.rs

1//! OpenPGP v6 key packet.
2
3use std::fmt;
4use std::cmp::Ordering;
5use std::hash::Hasher;
6use std::time;
7
8#[cfg(test)]
9use quickcheck::{Arbitrary, Gen};
10
11use crate::Error;
12use crate::crypto::{mpi, hash::Hash, mem::Protected, KeyPair};
13use crate::packet::key::{
14    KeyParts,
15    KeyRole,
16    KeyRoleRT,
17    PublicParts,
18    SecretParts,
19    UnspecifiedParts,
20};
21use crate::packet::prelude::*;
22use crate::PublicKeyAlgorithm;
23use crate::HashAlgorithm;
24use crate::types::Timestamp;
25use crate::Result;
26use crate::crypto::Password;
27use crate::KeyID;
28use crate::Fingerprint;
29use crate::KeyHandle;
30use crate::policy::HashAlgoSecurity;
31
32/// Holds a public key, public subkey, private key or private subkey
33/// packet.
34///
35/// Use [`Key6::generate_rsa`] or [`Key6::generate_ecc`] to create a
36/// new key.
37///
38/// Existing key material can be turned into an OpenPGP key using
39/// [`Key6::new`], [`Key6::with_secret`], [`Key6::import_public_x25519`],
40/// [`Key6::import_public_ed25519`], [`Key6::import_public_rsa`],
41/// [`Key6::import_secret_x25519`], [`Key6::import_secret_ed25519`],
42/// and [`Key6::import_secret_rsa`].
43///
44/// Whether you create a new key or import existing key material, you
45/// still need to create a binding signature, and, for signing keys, a
46/// back signature before integrating the key into a certificate.
47///
48/// Normally, you won't directly use `Key6`, but [`Key`], which is a
49/// relatively thin wrapper around `Key6`.
50///
51/// See [Section 5.5 of RFC 9580] and [the documentation for `Key`]
52/// for more details.
53///
54/// [Section 5.5 of RFC 9580]: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.5
55/// [the documentation for `Key`]: super::Key
56/// [`Key`]: super::Key
57#[derive(PartialEq, Eq, Hash)]
58pub struct Key6<P: KeyParts, R: KeyRole> {
59    pub(crate) common: Key4<P, R>,
60}
61
62// derive(Clone) doesn't work as expected with generic type parameters
63// that don't implement clone: it adds a trait bound on Clone to P and
64// R in the Clone implementation.  Happily, we don't need P or R to
65// implement Clone: they are just marker traits, which we can clone
66// manually.
67//
68// See: https://github.com/rust-lang/rust/issues/26925
69impl<P, R> Clone for Key6<P, R>
70    where P: KeyParts, R: KeyRole
71{
72    fn clone(&self) -> Self {
73        Key6 {
74            common: self.common.clone(),
75        }
76    }
77}
78
79impl<P, R> fmt::Debug for Key6<P, R>
80where P: KeyParts,
81      R: KeyRole,
82{
83    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
84        f.debug_struct("Key6")
85            .field("fingerprint", &self.fingerprint())
86            .field("creation_time", &self.creation_time())
87            .field("pk_algo", &self.pk_algo())
88            .field("mpis", &self.mpis())
89            .field("secret", &self.optional_secret())
90            .finish()
91    }
92}
93
94impl<P, R> fmt::Display for Key6<P, R>
95where P: KeyParts,
96      R: KeyRole,
97{
98    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
99        write!(f, "{}", self.fingerprint())
100    }
101}
102
103impl<P, R> Key6<P, R>
104where P: KeyParts,
105      R: KeyRole,
106{
107    /// The security requirements of the hash algorithm for
108    /// self-signatures.
109    ///
110    /// A cryptographic hash algorithm usually has [three security
111    /// properties]: pre-image resistance, second pre-image
112    /// resistance, and collision resistance.  If an attacker can
113    /// influence the signed data, then the hash algorithm needs to
114    /// have both second pre-image resistance, and collision
115    /// resistance.  If not, second pre-image resistance is
116    /// sufficient.
117    ///
118    ///   [three security properties]: https://en.wikipedia.org/wiki/Cryptographic_hash_function#Properties
119    ///
120    /// In general, an attacker may be able to influence third-party
121    /// signatures.  But direct key signatures, and binding signatures
122    /// are only over data fully determined by signer.  And, an
123    /// attacker's control over self signatures over User IDs is
124    /// limited due to their structure.
125    ///
126    /// These observations can be used to extend the life of a hash
127    /// algorithm after its collision resistance has been partially
128    /// compromised, but not completely broken.  For more details,
129    /// please refer to the documentation for [HashAlgoSecurity].
130    ///
131    ///   [HashAlgoSecurity]: crate::policy::HashAlgoSecurity
132    pub fn hash_algo_security(&self) -> HashAlgoSecurity {
133        HashAlgoSecurity::SecondPreImageResistance
134    }
135
136    /// Compares the public bits of two keys.
137    ///
138    /// This returns `Ordering::Equal` if the public MPIs, creation
139    /// time, and algorithm of the two `Key6`s match.  This does not
140    /// consider the packets' encodings, packets' tags or their secret
141    /// key material.
142    pub fn public_cmp<PB, RB>(&self, b: &Key6<PB, RB>) -> Ordering
143    where PB: KeyParts,
144          RB: KeyRole,
145    {
146        self.mpis().cmp(b.mpis())
147            .then_with(|| self.creation_time().cmp(&b.creation_time()))
148            .then_with(|| self.pk_algo().cmp(&b.pk_algo()))
149    }
150
151    /// Tests whether two keys are equal modulo their secret key
152    /// material.
153    ///
154    /// This returns true if the public MPIs, creation time and
155    /// algorithm of the two `Key6`s match.  This does not consider
156    /// the packets' encodings, packets' tags or their secret key
157    /// material.
158    pub fn public_eq<PB, RB>(&self, b: &Key6<PB, RB>) -> bool
159    where PB: KeyParts,
160          RB: KeyRole,
161    {
162        self.public_cmp(b) == Ordering::Equal
163    }
164
165    /// Hashes everything but any secret key material into state.
166    ///
167    /// This is an alternate implementation of [`Hash`], which never
168    /// hashes the secret key material.
169    ///
170    ///   [`Hash`]: std::hash::Hash
171    pub fn public_hash<H>(&self, state: &mut H)
172    where H: Hasher
173    {
174        self.common.public_hash(state);
175    }
176}
177
178impl<P, R> Key6<P, R>
179where
180    P: KeyParts,
181    R: KeyRole,
182{
183    /// Gets the `Key`'s creation time.
184    pub fn creation_time(&self) -> time::SystemTime {
185        self.common.creation_time()
186    }
187
188    /// Gets the `Key`'s creation time without converting it to a
189    /// system time.
190    ///
191    /// This conversion may truncate the time to signed 32-bit time_t.
192    pub(crate) fn creation_time_raw(&self) -> Timestamp {
193        self.common.creation_time_raw()
194    }
195
196    /// Sets the `Key`'s creation time.
197    ///
198    /// `timestamp` is converted to OpenPGP's internal format,
199    /// [`Timestamp`]: a 32-bit quantity containing the number of
200    /// seconds since the Unix epoch.
201    ///
202    /// `timestamp` is silently rounded to match the internal
203    /// resolution.  An error is returned if `timestamp` is out of
204    /// range.
205    ///
206    /// [`Timestamp`]: crate::types::Timestamp
207    pub fn set_creation_time<T>(&mut self, timestamp: T)
208                                -> Result<time::SystemTime>
209    where T: Into<time::SystemTime>
210    {
211        self.common.set_creation_time(timestamp)
212    }
213
214    /// Gets the public key algorithm.
215    pub fn pk_algo(&self) -> PublicKeyAlgorithm {
216        self.common.pk_algo()
217    }
218
219    /// Sets the public key algorithm.
220    ///
221    /// Returns the old public key algorithm.
222    pub fn set_pk_algo(&mut self, pk_algo: PublicKeyAlgorithm)
223                       -> PublicKeyAlgorithm
224    {
225        self.common.set_pk_algo(pk_algo)
226    }
227
228    /// Returns a reference to the `Key`'s MPIs.
229    pub fn mpis(&self) -> &mpi::PublicKey {
230        self.common.mpis()
231    }
232
233    /// Returns a mutable reference to the `Key`'s MPIs.
234    pub fn mpis_mut(&mut self) -> &mut mpi::PublicKey {
235        self.common.mpis_mut()
236    }
237
238    /// Sets the `Key`'s MPIs.
239    ///
240    /// This function returns the old MPIs, if any.
241    pub fn set_mpis(&mut self, mpis: mpi::PublicKey) -> mpi::PublicKey {
242        self.common.set_mpis(mpis)
243    }
244
245    /// Returns whether the `Key` contains secret key material.
246    pub fn has_secret(&self) -> bool {
247        self.common.has_secret()
248    }
249
250    /// Returns whether the `Key` contains unencrypted secret key
251    /// material.
252    ///
253    /// This returns false if the `Key` doesn't contain any secret key
254    /// material.
255    pub fn has_unencrypted_secret(&self) -> bool {
256        self.common.has_unencrypted_secret()
257    }
258
259    /// Returns `Key`'s secret key material, if any.
260    pub fn optional_secret(&self) -> Option<&SecretKeyMaterial> {
261        self.common.optional_secret()
262    }
263
264    /// Computes and returns the `Key`'s `Fingerprint` and returns it as
265    /// a `KeyHandle`.
266    ///
267    /// See [Section 5.5.4 of RFC 9580].
268    ///
269    /// [Section 5.5.4 of RFC 9580]: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.5.4
270    pub fn key_handle(&self) -> KeyHandle {
271        self.fingerprint().into()
272    }
273
274    /// Computes and returns the `Key`'s `Fingerprint`.
275    ///
276    /// See [Key IDs and Fingerprints].
277    ///
278    /// [Key IDs and Fingerprints]: https://www.rfc-editor.org/rfc/rfc9580.html#key-ids-fingerprints
279    pub fn fingerprint(&self) -> Fingerprint {
280        let fp = self.common.fingerprint.get_or_init(|| {
281            let mut h = HashAlgorithm::SHA256.context()
282                .expect("SHA256 is MTI for RFC9580")
283            // v6 fingerprints are computed the same way a key is
284            // hashed for v6 signatures.
285                .for_signature(6);
286
287            self.hash(&mut h).expect("v6 key hashing is infallible");
288
289            let mut digest = [0u8; 32];
290            let _ = h.digest(&mut digest);
291            Fingerprint::V6(digest)
292        });
293
294        // Currently, it could happen that a Key4 has its fingerprint
295        // computed, and is then converted to a Key6.  That is only
296        // possible within this crate, and should not happen.  Assert
297        // that.  The better way to handle this is to have a CommonKey
298        // struct which both Key4 and Key6 use, so that a Key6 does
299        // not start out as a Key4, preventing this issue.
300        debug_assert!(matches!(fp, Fingerprint::V6(_)));
301
302        fp.clone()
303    }
304
305    /// Computes and returns the `Key`'s `Key ID`.
306    ///
307    /// See [Section 5.5.4 of RFC 9580].
308    ///
309    /// [Section 5.5.4 of RFC 9580]: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.5.4
310    pub fn keyid(&self) -> KeyID {
311        self.fingerprint().into()
312    }
313
314    /// Creates a v6 key from a v4 key.  Used internally in
315    /// constructors.
316    pub(crate) fn from_common(common: Key4<P, R>) -> Self {
317        Key6 { common }
318    }
319
320    /// Creates an OpenPGP public key from the specified key material.
321    ///
322    /// This is an internal version for parse.rs that avoids going
323    /// through SystemTime.
324    pub(crate) fn make(creation_time: Timestamp,
325                       pk_algo: PublicKeyAlgorithm,
326                       mpis: mpi::PublicKey,
327                       secret: Option<SecretKeyMaterial>)
328                       -> Result<Self>
329    where
330    {
331        Ok(Key6 {
332            common: Key4::make(creation_time, pk_algo, mpis, secret)?,
333        })
334    }
335
336    pub(crate) fn role(&self) -> KeyRoleRT {
337        self.common.role()
338    }
339
340    pub(crate) fn set_role(&mut self, role: KeyRoleRT) {
341        self.common.set_role(role);
342    }
343}
344
345impl<R> Key6<key::PublicParts, R>
346where R: KeyRole,
347{
348    /// Creates an OpenPGP public key from the specified key material.
349    pub fn new<T>(creation_time: T, pk_algo: PublicKeyAlgorithm,
350                  mpis: mpi::PublicKey)
351                  -> Result<Self>
352    where T: Into<time::SystemTime>
353    {
354        Ok(Key6 {
355            common: Key4::new(creation_time, pk_algo, mpis)?,
356        })
357    }
358
359    /// Creates an OpenPGP public key packet from existing X25519 key
360    /// material.
361    ///
362    /// The key will have its creation date set to `ctime` or the
363    /// current time if `None` is given.
364    pub fn import_public_x25519<T>(public_key: &[u8], ctime: T)
365                                   -> Result<Self>
366    where
367        T: Into<Option<time::SystemTime>>,
368    {
369        Ok(Key6 {
370            common: Key4::new(ctime.into().unwrap_or_else(crate::now),
371                              PublicKeyAlgorithm::X25519,
372                              mpi::PublicKey::X25519 {
373                                  u: public_key.try_into()?,
374                              })?,
375        })
376    }
377
378    /// Creates an OpenPGP public key packet from existing X448 key
379    /// material.
380    ///
381    /// The key will have its creation date set to `ctime` or the
382    /// current time if `None` is given.
383    pub fn import_public_x448<T>(public_key: &[u8], ctime: T)
384                                 -> Result<Self>
385    where
386        T: Into<Option<time::SystemTime>>,
387    {
388        Ok(Key6 {
389            common: Key4::new(ctime.into().unwrap_or_else(crate::now),
390                              PublicKeyAlgorithm::X448,
391                              mpi::PublicKey::X448 {
392                                  u: Box::new(public_key.try_into()?),
393                              })?,
394        })
395    }
396
397    /// Creates an OpenPGP public key packet from existing Ed25519 key
398    /// material.
399    ///
400    /// The key will have its creation date set to `ctime` or the
401    /// current time if `None` is given.
402    pub fn import_public_ed25519<T>(public_key: &[u8], ctime: T) -> Result<Self>
403    where
404        T: Into<Option<time::SystemTime>>,
405    {
406        Ok(Key6 {
407            common: Key4::new(ctime.into().unwrap_or_else(crate::now),
408                              PublicKeyAlgorithm::Ed25519,
409                              mpi::PublicKey::Ed25519 {
410                                  a: public_key.try_into()?,
411                              })?,
412        })
413    }
414
415    /// Creates an OpenPGP public key packet from existing Ed448 key
416    /// material.
417    ///
418    /// The key will have its creation date set to `ctime` or the
419    /// current time if `None` is given.
420    pub fn import_public_ed448<T>(public_key: &[u8], ctime: T) -> Result<Self>
421    where
422        T: Into<Option<time::SystemTime>>,
423    {
424        Ok(Key6 {
425            common: Key4::new(ctime.into().unwrap_or_else(crate::now),
426                              PublicKeyAlgorithm::Ed448,
427                              mpi::PublicKey::Ed448 {
428                                  a: Box::new(public_key.try_into()?),
429                              })?,
430        })
431    }
432
433    /// Creates an OpenPGP public key packet from existing RSA key
434    /// material.
435    ///
436    /// The RSA key will use the public exponent `e` and the modulo
437    /// `n`. The key will have its creation date set to `ctime` or the
438    /// current time if `None` is given.
439    pub fn import_public_rsa<T>(e: &[u8], n: &[u8], ctime: T)
440                                -> Result<Self> where T: Into<Option<time::SystemTime>>
441    {
442        Ok(Key6 {
443            common: Key4::import_public_rsa(e, n, ctime)?,
444        })
445    }
446}
447
448impl<R> Key6<SecretParts, R>
449where R: KeyRole,
450{
451    /// Creates an OpenPGP key packet from the specified secret key
452    /// material.
453    pub fn with_secret<T>(creation_time: T, pk_algo: PublicKeyAlgorithm,
454                          mpis: mpi::PublicKey,
455                          secret: SecretKeyMaterial)
456                          -> Result<Self>
457    where T: Into<time::SystemTime>
458    {
459        Ok(Key6 {
460            common: Key4::with_secret(creation_time, pk_algo, mpis, secret)?,
461        })
462    }
463
464    /// Creates a new OpenPGP secret key packet for an existing X25519
465    /// key.
466    ///
467    /// The given `private_key` is expected to be in the native X25519
468    /// representation, i.e. as opaque byte string of length 32.
469    ///
470    /// The key will have its creation date set to `ctime` or the
471    /// current time if `None` is given.
472    pub fn import_secret_x25519<T>(private_key: &[u8],
473                                   ctime: T)
474                                   -> Result<Self>
475    where
476        T: Into<Option<std::time::SystemTime>>,
477    {
478        use crate::crypto::backend::{Backend, interface::Asymmetric};
479
480        let private_key = Protected::from(private_key);
481        let public_key = Backend::x25519_derive_public(&private_key)?;
482
483        Self::with_secret(
484            ctime.into().unwrap_or_else(crate::now),
485            PublicKeyAlgorithm::X25519,
486            mpi::PublicKey::X25519 {
487                u: public_key,
488            },
489            mpi::SecretKeyMaterial::X25519 {
490                x: private_key.into(),
491            }.into())
492    }
493
494    /// Creates a new OpenPGP secret key packet for an existing X448
495    /// key.
496    ///
497    /// The given `private_key` is expected to be in the native X448
498    /// representation, i.e. as opaque byte string of length 32.
499    ///
500    /// The key will have its creation date set to `ctime` or the
501    /// current time if `None` is given.
502    pub fn import_secret_x448<T>(private_key: &[u8],
503                                 ctime: T)
504                                 -> Result<Self>
505    where
506        T: Into<Option<std::time::SystemTime>>,
507    {
508        use crate::crypto::backend::{Backend, interface::Asymmetric};
509
510        let private_key = Protected::from(private_key);
511        let public_key = Backend::x448_derive_public(&private_key)?;
512
513        Self::with_secret(
514            ctime.into().unwrap_or_else(crate::now),
515            PublicKeyAlgorithm::X448,
516            mpi::PublicKey::X448 {
517                u: Box::new(public_key),
518            },
519            mpi::SecretKeyMaterial::X448 {
520                x: private_key.into(),
521            }.into())
522    }
523
524    /// Creates a new OpenPGP secret key packet for an existing
525    /// Ed25519 key.
526    ///
527    /// The key will have its creation date set to `ctime` or the
528    /// current time if `None` is given.
529    pub fn import_secret_ed25519<T>(private_key: &[u8], ctime: T)
530                                    -> Result<Self>
531    where
532        T: Into<Option<time::SystemTime>>,
533    {
534        use crate::crypto::backend::{Backend, interface::Asymmetric};
535
536        let private_key = Protected::from(private_key);
537        let public_key = Backend::ed25519_derive_public(&private_key)?;
538
539        Self::with_secret(
540            ctime.into().unwrap_or_else(crate::now),
541            PublicKeyAlgorithm::Ed25519,
542            mpi::PublicKey::Ed25519 {
543                a: public_key,
544            },
545            mpi::SecretKeyMaterial::Ed25519 {
546                x: private_key.into(),
547            }.into())
548    }
549
550    /// Creates a new OpenPGP secret key packet for an existing
551    /// Ed448 key.
552    ///
553    /// The key will have its creation date set to `ctime` or the
554    /// current time if `None` is given.
555    pub fn import_secret_ed448<T>(private_key: &[u8], ctime: T)
556                                  -> Result<Self>
557    where
558        T: Into<Option<time::SystemTime>>,
559    {
560        use crate::crypto::backend::{Backend, interface::Asymmetric};
561
562        let private_key = Protected::from(private_key);
563        let public_key = Backend::ed448_derive_public(&private_key)?;
564
565        Self::with_secret(
566            ctime.into().unwrap_or_else(crate::now),
567            PublicKeyAlgorithm::Ed448,
568            mpi::PublicKey::Ed448 {
569                a: Box::new(public_key),
570            },
571            mpi::SecretKeyMaterial::Ed448 {
572                x: private_key.into(),
573            }.into())
574    }
575
576    /// Creates a new key pair from a secret `Key` with an unencrypted
577    /// secret key.
578    ///
579    /// # Errors
580    ///
581    /// Fails if the secret key is encrypted.  You can use
582    /// [`Key::decrypt_secret`] to decrypt a key.
583    pub fn into_keypair(self) -> Result<KeyPair> {
584        let (key, secret) = self.take_secret();
585        let secret = match secret {
586            SecretKeyMaterial::Unencrypted(secret) => secret,
587            SecretKeyMaterial::Encrypted(_) =>
588                return Err(Error::InvalidArgument(
589                    "secret key material is encrypted".into()).into()),
590        };
591
592        KeyPair::new(key.role_into_unspecified().into(), secret)
593    }
594}
595
596macro_rules! impl_common_secret_functions_v6 {
597    ($t: ident) => {
598        /// Secret key material handling.
599        impl<R> Key6<$t, R>
600        where R: KeyRole,
601        {
602            /// Takes the `Key`'s `SecretKeyMaterial`, if any.
603            pub fn take_secret(mut self)
604                               -> (Key6<PublicParts, R>, Option<SecretKeyMaterial>)
605            {
606                let old = std::mem::replace(&mut self.common.secret, None);
607                (self.parts_into_public(), old)
608            }
609
610            /// Adds the secret key material to the `Key`, returning
611            /// the old secret key material, if any.
612            pub fn add_secret(mut self, secret: SecretKeyMaterial)
613                              -> (Key6<SecretParts, R>, Option<SecretKeyMaterial>)
614            {
615                let old = std::mem::replace(&mut self.common.secret, Some(secret));
616                (self.parts_into_secret().expect("secret just set"), old)
617            }
618
619            /// Takes the `Key`'s `SecretKeyMaterial`, if any.
620            pub fn steal_secret(&mut self) -> Option<SecretKeyMaterial>
621            {
622                std::mem::replace(&mut self.common.secret, None)
623            }
624        }
625    }
626}
627impl_common_secret_functions_v6!(PublicParts);
628impl_common_secret_functions_v6!(UnspecifiedParts);
629
630/// Secret key handling.
631impl<R> Key6<SecretParts, R>
632where R: KeyRole,
633{
634    /// Gets the `Key`'s `SecretKeyMaterial`.
635    pub fn secret(&self) -> &SecretKeyMaterial {
636        self.common.secret()
637    }
638
639    /// Gets a mutable reference to the `Key`'s `SecretKeyMaterial`.
640    pub fn secret_mut(&mut self) -> &mut SecretKeyMaterial {
641        self.common.secret_mut()
642    }
643
644    /// Takes the `Key`'s `SecretKeyMaterial`.
645    pub fn take_secret(mut self)
646                       -> (Key6<PublicParts, R>, SecretKeyMaterial)
647    {
648        let old = std::mem::replace(&mut self.common.secret, None);
649        (self.parts_into_public(),
650         old.expect("Key<SecretParts, _> has a secret key material"))
651    }
652
653    /// Adds `SecretKeyMaterial` to the `Key`.
654    ///
655    /// This function returns the old secret key material, if any.
656    pub fn add_secret(mut self, secret: SecretKeyMaterial)
657                      -> (Key6<SecretParts, R>, SecretKeyMaterial)
658    {
659        let old = std::mem::replace(&mut self.common.secret, Some(secret));
660        (self.parts_into_secret().expect("secret just set"),
661         old.expect("Key<SecretParts, _> has a secret key material"))
662    }
663
664    /// Decrypts the secret key material using `password`.
665    ///
666    /// In OpenPGP, secret key material can be [protected with a
667    /// password].  The password is usually hardened using a [KDF].
668    ///
669    /// Refer to the documentation of [`Key::decrypt_secret`] for
670    /// details.
671    ///
672    /// This function returns an error if the secret key material is
673    /// not encrypted or the password is incorrect.
674    ///
675    /// [protected with a password]: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.5.3
676    /// [KDF]: https://www.rfc-editor.org/rfc/rfc9580.html#section-3.7
677    /// [`Key::decrypt_secret`]: super::Key::decrypt_secret()
678    pub fn decrypt_secret(self, password: &Password) -> Result<Self> {
679        let (key, mut secret) = self.take_secret();
680        // Note: Key version is authenticated.
681        let key = Key::V6(key);
682        secret.decrypt_in_place(&key, password)?;
683        let key = if let Key::V6(k) = key { k } else { unreachable!() };
684        Ok(key.add_secret(secret).0)
685    }
686
687    /// Encrypts the secret key material using `password`.
688    ///
689    /// In OpenPGP, secret key material can be [protected with a
690    /// password].  The password is usually hardened using a [KDF].
691    ///
692    /// Refer to the documentation of [`Key::encrypt_secret`] for
693    /// details.
694    ///
695    /// This returns an error if the secret key material is already
696    /// encrypted.
697    ///
698    /// [protected with a password]: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.5.3
699    /// [KDF]: https://www.rfc-editor.org/rfc/rfc9580.html#section-3.7
700    /// [`Key::encrypt_secret`]: super::Key::encrypt_secret()
701    pub fn encrypt_secret(self, password: &Password)
702                          -> Result<Key6<SecretParts, R>>
703    {
704        let (key, mut secret) = self.take_secret();
705        // Note: Key version is authenticated.
706        let key = Key::V6(key);
707        secret.encrypt_in_place(&key, password)?;
708        let key = if let Key::V6(k) = key { k } else { unreachable!() };
709        Ok(key.add_secret(secret).0)
710    }
711}
712
713impl<P, R> From<Key6<P, R>> for super::Key<P, R>
714where P: KeyParts,
715      R: KeyRole,
716{
717    fn from(p: Key6<P, R>) -> Self {
718        super::Key::V6(p)
719    }
720}
721
722#[cfg(test)]
723use crate::packet::key::{
724    PrimaryRole,
725    SubordinateRole,
726    UnspecifiedRole,
727};
728
729#[cfg(test)]
730impl Arbitrary for Key6<PublicParts, PrimaryRole> {
731    fn arbitrary(g: &mut Gen) -> Self {
732        Key6::from_common(Key4::arbitrary(g))
733    }
734}
735
736#[cfg(test)]
737impl Arbitrary for Key6<PublicParts, SubordinateRole> {
738    fn arbitrary(g: &mut Gen) -> Self {
739        Key6::from_common(Key4::arbitrary(g))
740    }
741}
742
743#[cfg(test)]
744impl Arbitrary for Key6<PublicParts, UnspecifiedRole> {
745    fn arbitrary(g: &mut Gen) -> Self {
746        Key6::from_common(Key4::arbitrary(g))
747    }
748}
749
750#[cfg(test)]
751impl Arbitrary for Key6<SecretParts, PrimaryRole> {
752    fn arbitrary(g: &mut Gen) -> Self {
753        Key6::from_common(Key4::arbitrary(g))
754    }
755}
756
757#[cfg(test)]
758impl Arbitrary for Key6<SecretParts, SubordinateRole> {
759    fn arbitrary(g: &mut Gen) -> Self {
760        Key6::from_common(Key4::arbitrary(g))
761    }
762}
763
764
765#[cfg(test)]
766mod tests {
767    use std::time::Duration;
768    use std::time::UNIX_EPOCH;
769
770    use crate::crypto::S2K;
771    use crate::packet::Key;
772    use crate::packet::key;
773    use crate::packet::Packet;
774    use super::*;
775    use crate::PacketPile;
776    use crate::serialize::Serialize;
777    use crate::types::*;
778    use crate::parse::Parse;
779
780    #[test]
781    fn primary_key_encrypt_decrypt() -> Result<()> {
782        key_encrypt_decrypt::<PrimaryRole>()
783    }
784
785    #[test]
786    fn subkey_encrypt_decrypt() -> Result<()> {
787        key_encrypt_decrypt::<SubordinateRole>()
788    }
789
790    fn key_encrypt_decrypt<R>() -> Result<()>
791    where
792        R: KeyRole + PartialEq,
793    {
794        let mut g = quickcheck::Gen::new(256);
795        let p: Password = Vec::<u8>::arbitrary(&mut g).into();
796
797        let check = |key: Key6<SecretParts, R>| -> Result<()> {
798            let key: Key<_, _> = key.into();
799            let encrypted = key.clone().encrypt_secret(&p)?;
800            let decrypted = encrypted.decrypt_secret(&p)?;
801            assert_eq!(key, decrypted);
802            Ok(())
803        };
804
805        use crate::types::Curve::*;
806        for curve in vec![NistP256, NistP384, NistP521, Ed25519] {
807            if ! curve.is_supported() {
808                eprintln!("Skipping unsupported {}", curve);
809                continue;
810            }
811
812            let key: Key6<_, R>
813                = Key6::generate_ecc(true, curve.clone())?;
814            check(key)?;
815        }
816
817        for bits in vec![2048, 3072] {
818            if ! PublicKeyAlgorithm::RSAEncryptSign.is_supported() {
819                eprintln!("Skipping unsupported RSA");
820                continue;
821            }
822
823            let key: Key6<_, R>
824                = Key6::generate_rsa(bits)?;
825            check(key)?;
826        }
827
828        Ok(())
829    }
830
831    #[test]
832    fn eq() {
833        use crate::types::Curve::*;
834
835        for curve in vec![NistP256, NistP384, NistP521] {
836            if ! curve.is_supported() {
837                eprintln!("Skipping unsupported {}", curve);
838                continue;
839            }
840
841            let sign_key : Key6<_, key::UnspecifiedRole>
842                = Key6::generate_ecc(true, curve.clone()).unwrap();
843            let enc_key : Key6<_, key::UnspecifiedRole>
844                = Key6::generate_ecc(false, curve).unwrap();
845            let sign_clone = sign_key.clone();
846            let enc_clone = enc_key.clone();
847
848            assert_eq!(sign_key, sign_clone);
849            assert_eq!(enc_key, enc_clone);
850        }
851
852        for bits in vec![1024, 2048, 3072, 4096] {
853            if ! PublicKeyAlgorithm::RSAEncryptSign.is_supported() {
854                eprintln!("Skipping unsupported RSA");
855                continue;
856            }
857
858            let key : Key6<_, key::UnspecifiedRole>
859                = Key6::generate_rsa(bits).unwrap();
860            let clone = key.clone();
861            assert_eq!(key, clone);
862        }
863    }
864
865    #[test]
866    fn generate_roundtrip() {
867        use crate::types::Curve::*;
868
869        let keys = vec![NistP256, NistP384, NistP521].into_iter().flat_map(|cv|
870        {
871            if ! cv.is_supported() {
872                eprintln!("Skipping unsupported {}", cv);
873                return Vec::new();
874            }
875
876            let sign_key : Key6<key::SecretParts, key::PrimaryRole>
877                = Key6::generate_ecc(true, cv.clone()).unwrap();
878            let enc_key = Key6::generate_ecc(false, cv).unwrap();
879
880            vec![sign_key, enc_key]
881        }).chain(vec![1024, 2048, 3072, 4096].into_iter().filter_map(|b| {
882            Key6::generate_rsa(b).ok()
883        }));
884
885        for key in keys {
886            let mut b = Vec::new();
887            Packet::SecretKey(key.clone().into()).serialize(&mut b).unwrap();
888
889            let pp = PacketPile::from_bytes(&b).unwrap();
890            if let Some(Packet::SecretKey(Key::V6(ref parsed_key))) =
891                pp.path_ref(&[0])
892            {
893                assert_eq!(key.creation_time(), parsed_key.creation_time());
894                assert_eq!(key.pk_algo(), parsed_key.pk_algo());
895                assert_eq!(key.mpis(), parsed_key.mpis());
896                assert_eq!(key.secret(), parsed_key.secret());
897
898                assert_eq!(&key, parsed_key);
899            } else {
900                panic!("bad packet: {:?}", pp.path_ref(&[0]));
901            }
902
903            let mut b = Vec::new();
904            let pk4 : Key6<PublicParts, PrimaryRole> = key.clone().into();
905            Packet::PublicKey(pk4.into()).serialize(&mut b).unwrap();
906
907            let pp = PacketPile::from_bytes(&b).unwrap();
908            if let Some(Packet::PublicKey(Key::V6(ref parsed_key))) =
909                pp.path_ref(&[0])
910            {
911                assert!(! parsed_key.has_secret());
912
913                let key = key.take_secret().0;
914                assert_eq!(&key, parsed_key);
915            } else {
916                panic!("bad packet: {:?}", pp.path_ref(&[0]));
917            }
918        }
919    }
920
921    #[test]
922    fn encryption_roundtrip() {
923        use crate::crypto::SessionKey;
924        use crate::types::Curve::*;
925
926        let keys = vec![NistP256, NistP384, NistP521].into_iter()
927            .filter_map(|cv| {
928                Key6::generate_ecc(false, cv).ok()
929            }).chain(vec![1024, 2048, 3072, 4096].into_iter().filter_map(|b| {
930                Key6::generate_rsa(b).ok()
931            }));
932
933        for key in keys.into_iter() {
934            let key: Key<key::SecretParts, key::UnspecifiedRole> = key.into();
935            let mut keypair = key.clone().into_keypair().unwrap();
936            let cipher = SymmetricAlgorithm::AES256;
937            let sk = SessionKey::new(cipher.key_size().unwrap()).unwrap();
938
939            let pkesk = PKESK6::for_recipient(&sk, &key).unwrap();
940            let sk_ = pkesk.decrypt(&mut keypair, None)
941                .expect("keypair should be able to decrypt PKESK");
942            assert_eq!(sk, sk_);
943
944            let sk_ =
945                pkesk.decrypt(&mut keypair, Some(cipher)).unwrap();
946            assert_eq!(sk, sk_);
947        }
948    }
949
950    #[test]
951    fn signature_roundtrip() {
952        use crate::types::{Curve::*, SignatureType};
953
954        let keys = vec![NistP256, NistP384, NistP521].into_iter()
955            .filter_map(|cv| {
956                Key6::generate_ecc(true, cv).ok()
957            }).chain(vec![1024, 2048, 3072, 4096].into_iter().filter_map(|b| {
958                Key6::generate_rsa(b).ok()
959            }));
960
961        for key in keys.into_iter() {
962            let key: Key<key::SecretParts, key::UnspecifiedRole> = key.into();
963            let mut keypair = key.clone().into_keypair().unwrap();
964            let hash = HashAlgorithm::default();
965
966            // Sign.
967            let ctx = hash.context().unwrap().for_signature(key.version());
968            let sig = SignatureBuilder::new(SignatureType::Binary)
969                .sign_hash(&mut keypair, ctx).unwrap();
970
971            // Verify.
972            let ctx = hash.context().unwrap().for_signature(key.version());
973            sig.verify_hash(&key, ctx).unwrap();
974        }
975    }
976
977    #[test]
978    fn secret_encryption_roundtrip() {
979        use crate::types::Curve::*;
980        use crate::types::SymmetricAlgorithm::*;
981        use crate::types::AEADAlgorithm::*;
982
983        let keys = vec![NistP256, NistP384, NistP521].into_iter()
984            .filter_map(|cv| -> Option<Key<key::SecretParts, key::PrimaryRole>> {
985                Key6::generate_ecc(false, cv).map(Into::into).ok()
986            }).chain(vec![1024, 2048, 3072, 4096].into_iter().filter_map(|b| {
987                Key6::generate_rsa(b).map(Into::into).ok()
988            }));
989
990        for key in keys {
991          for (symm, aead) in [(AES128, None),
992                               (AES128, Some(OCB)),
993                               (AES256, Some(EAX))] {
994            if ! aead.map(|a| a.is_supported()).unwrap_or(true) {
995                continue;
996            }
997            assert!(! key.secret().is_encrypted());
998
999            let password = Password::from("foobarbaz");
1000            let mut encrypted_key = key.clone();
1001
1002            encrypted_key.secret_mut()
1003                .encrypt_in_place_with(&key, S2K::default(), symm, aead,
1004                                       &password).unwrap();
1005            assert!(encrypted_key.secret().is_encrypted());
1006
1007            encrypted_key.secret_mut()
1008                .decrypt_in_place(&key, &password).unwrap();
1009            assert!(! key.secret().is_encrypted());
1010            assert_eq!(key, encrypted_key);
1011            assert_eq!(key.secret(), encrypted_key.secret());
1012          }
1013        }
1014    }
1015
1016    #[test]
1017    fn encrypt_huge_plaintext() -> Result<()> {
1018        let sk = crate::crypto::SessionKey::new(256).unwrap();
1019
1020        if PublicKeyAlgorithm::RSAEncryptSign.is_supported() {
1021            let rsa2k: Key<SecretParts, UnspecifiedRole> =
1022                Key6::generate_rsa(2048)?.into();
1023            assert!(matches!(
1024                rsa2k.encrypt(&sk).unwrap_err().downcast().unwrap(),
1025                crate::Error::InvalidArgument(_)
1026            ));
1027        }
1028
1029        Ok(())
1030    }
1031
1032    #[test]
1033    fn issue_1016() {
1034        // The fingerprint is a function of the creation time,
1035        // algorithm, and public MPIs.  When we change them make sure
1036        // the fingerprint also changes.
1037
1038        let mut g = quickcheck::Gen::new(256);
1039
1040        let mut key = Key6::<PublicParts, UnspecifiedRole>::arbitrary(&mut g);
1041        let fpr1 = key.fingerprint();
1042        if key.creation_time() == UNIX_EPOCH {
1043            key.set_creation_time(UNIX_EPOCH + Duration::new(1, 0)).expect("ok");
1044        } else {
1045            key.set_creation_time(UNIX_EPOCH).expect("ok");
1046        }
1047        assert_ne!(fpr1, key.fingerprint());
1048
1049        let mut key = Key6::<PublicParts, UnspecifiedRole>::arbitrary(&mut g);
1050        let fpr1 = key.fingerprint();
1051        key.set_pk_algo(PublicKeyAlgorithm::from(u8::from(key.pk_algo()) + 1));
1052        assert_ne!(fpr1, key.fingerprint());
1053
1054        let mut key = Key6::<PublicParts, UnspecifiedRole>::arbitrary(&mut g);
1055        let fpr1 = key.fingerprint();
1056        loop {
1057            let mpis2 = mpi::PublicKey::arbitrary(&mut g);
1058            if key.mpis() != &mpis2 {
1059                *key.mpis_mut() = mpis2;
1060                break;
1061            }
1062        }
1063        assert_ne!(fpr1, key.fingerprint());
1064
1065        let mut key = Key6::<PublicParts, UnspecifiedRole>::arbitrary(&mut g);
1066        let fpr1 = key.fingerprint();
1067        loop {
1068            let mpis2 = mpi::PublicKey::arbitrary(&mut g);
1069            if key.mpis() != &mpis2 {
1070                key.set_mpis(mpis2);
1071                break;
1072            }
1073        }
1074        assert_ne!(fpr1, key.fingerprint());
1075    }
1076
1077    /// Smoke test for ECC key creation, signing and verification, and
1078    /// encryption and decryption.
1079    #[test]
1080    fn ecc_support() -> Result<()> {
1081        for for_signing in [true, false] {
1082            for curve in Curve::variants()
1083                .filter(Curve::is_supported)
1084            {
1085                match curve {
1086                    Curve::Cv25519 if for_signing => continue,
1087                    Curve::Ed25519 if ! for_signing => continue,
1088                    _ => (),
1089                }
1090
1091                eprintln!("curve {}, for signing {:?}", curve, for_signing);
1092                let key: Key<SecretParts, UnspecifiedRole> =
1093                    Key6::generate_ecc(for_signing, curve.clone())?.into();
1094                let mut pair = key.into_keypair()?;
1095
1096                if for_signing {
1097                    use crate::crypto::Signer;
1098                    let hash = HashAlgorithm::default();
1099                    let digest = hash.context()?
1100                        .for_signature(pair.public().version())
1101                        .into_digest()?;
1102                    let sig = pair.sign(hash, &digest)?;
1103                    pair.public().verify(&sig, hash, &digest)?;
1104                } else {
1105                    use crate::crypto::{SessionKey, Decryptor};
1106                    let sk = SessionKey::new(32).unwrap();
1107                    let ciphertext = pair.public().encrypt(&sk)?;
1108                    assert_eq!(pair.decrypt(&ciphertext, Some(sk.len()))?, sk);
1109                }
1110            }
1111        }
1112        Ok(())
1113    }
1114
1115    #[test]
1116    fn ecc_encoding() -> Result<()> {
1117        for for_signing in [true, false] {
1118            for curve in Curve::variants()
1119                .filter(Curve::is_supported)
1120            {
1121                match curve {
1122                    Curve::Cv25519 if for_signing => continue,
1123                    Curve::Ed25519 if ! for_signing => continue,
1124                    _ => (),
1125                }
1126
1127                use crate::crypto::mpi::{Ciphertext, MPI, PublicKey};
1128                eprintln!("curve {}, for signing {:?}", curve, for_signing);
1129
1130                let key: Key<SecretParts, UnspecifiedRole> =
1131                    Key6::generate_ecc(for_signing, curve.clone())?.into();
1132
1133                let uncompressed = |mpi: &MPI| mpi.value()[0] == 0x04;
1134
1135                match key.mpis() {
1136                    PublicKey::X25519 { .. } if ! for_signing => (),
1137                    PublicKey::X448 { .. } if ! for_signing => (),
1138                    PublicKey::Ed25519 { .. } if for_signing => (),
1139                    PublicKey::Ed448 { .. } if for_signing => (),
1140                    PublicKey::ECDSA { curve: c, q } if for_signing => {
1141                        assert!(c == &curve);
1142                        assert!(c != &Curve::Ed25519);
1143                        assert!(uncompressed(q));
1144                    },
1145                    PublicKey::ECDH { curve: c, q, .. } if ! for_signing => {
1146                        assert!(c == &curve);
1147                        assert!(c != &Curve::Cv25519);
1148                        assert!(uncompressed(q));
1149
1150                        use crate::crypto::SessionKey;
1151                        let sk = SessionKey::new(32).unwrap();
1152                        let ciphertext = key.encrypt(&sk)?;
1153                        if let Ciphertext::ECDH { e, .. } = &ciphertext {
1154                            assert!(uncompressed(e));
1155                        } else {
1156                            panic!("unexpected ciphertext: {:?}", ciphertext);
1157                        }
1158                    },
1159                    mpi => unreachable!(
1160                        "curve {}, mpi {:?}, for signing {:?}",
1161                        curve, mpi, for_signing),
1162                }
1163            }
1164        }
1165        Ok(())
1166    }
1167
1168
1169    #[test]
1170    fn v6_key_fingerprint() -> Result<()> {
1171        let p = Packet::from_bytes("-----BEGIN PGP ARMORED FILE-----
1172
1173xjcGY4d/4xYAAAAtCSsGAQQB2kcPAQEHQPlNp7tI1gph5WdwamWH0DMZmbudiRoI
1174JC6thFQ9+JWj
1175=SgmS
1176-----END PGP ARMORED FILE-----")?;
1177        let k: &Key<PublicParts, PrimaryRole> = p.downcast_ref().unwrap();
1178        assert_eq!(k.fingerprint().to_string(),
1179                   "4EADF309C6BC874AE04702451548F93F\
1180                    96FA7A01D0A33B5AF7D4E379E0F9F8EE".to_string());
1181        Ok(())
1182    }
1183}