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<T>(creation_time: T,
325                          pk_algo: PublicKeyAlgorithm,
326                          mpis: mpi::PublicKey,
327                          secret: Option<SecretKeyMaterial>)
328                          -> Result<Self>
329    where
330        T: Into<Timestamp>,
331    {
332        Ok(Key6 {
333            common: Key4::make(creation_time, pk_algo, mpis, secret)?,
334        })
335    }
336
337    pub(crate) fn role(&self) -> KeyRoleRT {
338        self.common.role()
339    }
340
341    pub(crate) fn set_role(&mut self, role: KeyRoleRT) {
342        self.common.set_role(role);
343    }
344}
345
346impl<R> Key6<key::PublicParts, R>
347where R: KeyRole,
348{
349    /// Creates an OpenPGP public key from the specified key material.
350    pub fn new<T>(creation_time: T, pk_algo: PublicKeyAlgorithm,
351                  mpis: mpi::PublicKey)
352                  -> Result<Self>
353    where T: Into<time::SystemTime>
354    {
355        Ok(Key6 {
356            common: Key4::new(creation_time, pk_algo, mpis)?,
357        })
358    }
359
360    /// Creates an OpenPGP public key packet from existing X25519 key
361    /// material.
362    ///
363    /// The key will have its creation date set to `ctime` or the
364    /// current time if `None` is given.
365    pub fn import_public_x25519<T>(public_key: &[u8], ctime: T)
366                                   -> Result<Self>
367    where
368        T: Into<Option<time::SystemTime>>,
369    {
370        Ok(Key6 {
371            common: Key4::new(ctime.into().unwrap_or_else(crate::now),
372                              PublicKeyAlgorithm::X25519,
373                              mpi::PublicKey::X25519 {
374                                  u: public_key.try_into()?,
375                              })?,
376        })
377    }
378
379    /// Creates an OpenPGP public key packet from existing X448 key
380    /// material.
381    ///
382    /// The key will have its creation date set to `ctime` or the
383    /// current time if `None` is given.
384    pub fn import_public_x448<T>(public_key: &[u8], ctime: T)
385                                 -> Result<Self>
386    where
387        T: Into<Option<time::SystemTime>>,
388    {
389        Ok(Key6 {
390            common: Key4::new(ctime.into().unwrap_or_else(crate::now),
391                              PublicKeyAlgorithm::X448,
392                              mpi::PublicKey::X448 {
393                                  u: Box::new(public_key.try_into()?),
394                              })?,
395        })
396    }
397
398    /// Creates an OpenPGP public key packet from existing Ed25519 key
399    /// material.
400    ///
401    /// The key will have its creation date set to `ctime` or the
402    /// current time if `None` is given.
403    pub fn import_public_ed25519<T>(public_key: &[u8], ctime: T) -> Result<Self>
404    where
405        T: Into<Option<time::SystemTime>>,
406    {
407        Ok(Key6 {
408            common: Key4::new(ctime.into().unwrap_or_else(crate::now),
409                              PublicKeyAlgorithm::Ed25519,
410                              mpi::PublicKey::Ed25519 {
411                                  a: public_key.try_into()?,
412                              })?,
413        })
414    }
415
416    /// Creates an OpenPGP public key packet from existing Ed448 key
417    /// material.
418    ///
419    /// The key will have its creation date set to `ctime` or the
420    /// current time if `None` is given.
421    pub fn import_public_ed448<T>(public_key: &[u8], ctime: T) -> Result<Self>
422    where
423        T: Into<Option<time::SystemTime>>,
424    {
425        Ok(Key6 {
426            common: Key4::new(ctime.into().unwrap_or_else(crate::now),
427                              PublicKeyAlgorithm::Ed448,
428                              mpi::PublicKey::Ed448 {
429                                  a: Box::new(public_key.try_into()?),
430                              })?,
431        })
432    }
433
434    /// Creates an OpenPGP public key packet from existing RSA key
435    /// material.
436    ///
437    /// The RSA key will use the public exponent `e` and the modulo
438    /// `n`. The key will have its creation date set to `ctime` or the
439    /// current time if `None` is given.
440    pub fn import_public_rsa<T>(e: &[u8], n: &[u8], ctime: T)
441                                -> Result<Self> where T: Into<Option<time::SystemTime>>
442    {
443        Ok(Key6 {
444            common: Key4::import_public_rsa(e, n, ctime)?,
445        })
446    }
447}
448
449impl<R> Key6<SecretParts, R>
450where R: KeyRole,
451{
452    /// Creates an OpenPGP key packet from the specified secret key
453    /// material.
454    pub fn with_secret<T>(creation_time: T, pk_algo: PublicKeyAlgorithm,
455                          mpis: mpi::PublicKey,
456                          secret: SecretKeyMaterial)
457                          -> Result<Self>
458    where T: Into<time::SystemTime>
459    {
460        Ok(Key6 {
461            common: Key4::with_secret(creation_time, pk_algo, mpis, secret)?,
462        })
463    }
464
465    /// Creates a new OpenPGP secret key packet for an existing X25519
466    /// key.
467    ///
468    /// The given `private_key` is expected to be in the native X25519
469    /// representation, i.e. as opaque byte string of length 32.
470    ///
471    /// The key will have its creation date set to `ctime` or the
472    /// current time if `None` is given.
473    pub fn import_secret_x25519<T>(private_key: &[u8],
474                                   ctime: T)
475                                   -> Result<Self>
476    where
477        T: Into<Option<std::time::SystemTime>>,
478    {
479        use crate::crypto::backend::{Backend, interface::Asymmetric};
480
481        let private_key = Protected::from(private_key);
482        let public_key = Backend::x25519_derive_public(&private_key)?;
483
484        Self::with_secret(
485            ctime.into().unwrap_or_else(crate::now),
486            PublicKeyAlgorithm::X25519,
487            mpi::PublicKey::X25519 {
488                u: public_key,
489            },
490            mpi::SecretKeyMaterial::X25519 {
491                x: private_key.into(),
492            }.into())
493    }
494
495    /// Creates a new OpenPGP secret key packet for an existing X448
496    /// key.
497    ///
498    /// The given `private_key` is expected to be in the native X448
499    /// representation, i.e. as opaque byte string of length 32.
500    ///
501    /// The key will have its creation date set to `ctime` or the
502    /// current time if `None` is given.
503    pub fn import_secret_x448<T>(private_key: &[u8],
504                                 ctime: T)
505                                 -> Result<Self>
506    where
507        T: Into<Option<std::time::SystemTime>>,
508    {
509        use crate::crypto::backend::{Backend, interface::Asymmetric};
510
511        let private_key = Protected::from(private_key);
512        let public_key = Backend::x448_derive_public(&private_key)?;
513
514        Self::with_secret(
515            ctime.into().unwrap_or_else(crate::now),
516            PublicKeyAlgorithm::X448,
517            mpi::PublicKey::X448 {
518                u: Box::new(public_key),
519            },
520            mpi::SecretKeyMaterial::X448 {
521                x: private_key.into(),
522            }.into())
523    }
524
525    /// Creates a new OpenPGP secret key packet for an existing
526    /// Ed25519 key.
527    ///
528    /// The key will have its creation date set to `ctime` or the
529    /// current time if `None` is given.
530    pub fn import_secret_ed25519<T>(private_key: &[u8], ctime: T)
531                                    -> Result<Self>
532    where
533        T: Into<Option<time::SystemTime>>,
534    {
535        use crate::crypto::backend::{Backend, interface::Asymmetric};
536
537        let private_key = Protected::from(private_key);
538        let public_key = Backend::ed25519_derive_public(&private_key)?;
539
540        Self::with_secret(
541            ctime.into().unwrap_or_else(crate::now),
542            PublicKeyAlgorithm::Ed25519,
543            mpi::PublicKey::Ed25519 {
544                a: public_key,
545            },
546            mpi::SecretKeyMaterial::Ed25519 {
547                x: private_key.into(),
548            }.into())
549    }
550
551    /// Creates a new OpenPGP secret key packet for an existing
552    /// Ed448 key.
553    ///
554    /// The key will have its creation date set to `ctime` or the
555    /// current time if `None` is given.
556    pub fn import_secret_ed448<T>(private_key: &[u8], ctime: T)
557                                  -> Result<Self>
558    where
559        T: Into<Option<time::SystemTime>>,
560    {
561        use crate::crypto::backend::{Backend, interface::Asymmetric};
562
563        let private_key = Protected::from(private_key);
564        let public_key = Backend::ed448_derive_public(&private_key)?;
565
566        Self::with_secret(
567            ctime.into().unwrap_or_else(crate::now),
568            PublicKeyAlgorithm::Ed448,
569            mpi::PublicKey::Ed448 {
570                a: Box::new(public_key),
571            },
572            mpi::SecretKeyMaterial::Ed448 {
573                x: private_key.into(),
574            }.into())
575    }
576
577    /// Creates a new key pair from a secret `Key` with an unencrypted
578    /// secret key.
579    ///
580    /// # Errors
581    ///
582    /// Fails if the secret key is encrypted.  You can use
583    /// [`Key::decrypt_secret`] to decrypt a key.
584    pub fn into_keypair(self) -> Result<KeyPair> {
585        let (key, secret) = self.take_secret();
586        let secret = match secret {
587            SecretKeyMaterial::Unencrypted(secret) => secret,
588            SecretKeyMaterial::Encrypted(_) =>
589                return Err(Error::InvalidArgument(
590                    "secret key material is encrypted".into()).into()),
591        };
592
593        KeyPair::new(key.role_into_unspecified().into(), secret)
594    }
595}
596
597macro_rules! impl_common_secret_functions_v6 {
598    ($t: ident) => {
599        /// Secret key material handling.
600        impl<R> Key6<$t, R>
601        where R: KeyRole,
602        {
603            /// Takes the `Key`'s `SecretKeyMaterial`, if any.
604            pub fn take_secret(mut self)
605                               -> (Key6<PublicParts, R>, Option<SecretKeyMaterial>)
606            {
607                let old = std::mem::replace(&mut self.common.secret, None);
608                (self.parts_into_public(), old)
609            }
610
611            /// Adds the secret key material to the `Key`, returning
612            /// the old secret key material, if any.
613            pub fn add_secret(mut self, secret: SecretKeyMaterial)
614                              -> (Key6<SecretParts, R>, Option<SecretKeyMaterial>)
615            {
616                let old = std::mem::replace(&mut self.common.secret, Some(secret));
617                (self.parts_into_secret().expect("secret just set"), old)
618            }
619
620            /// Takes the `Key`'s `SecretKeyMaterial`, if any.
621            pub fn steal_secret(&mut self) -> Option<SecretKeyMaterial>
622            {
623                std::mem::replace(&mut self.common.secret, None)
624            }
625        }
626    }
627}
628impl_common_secret_functions_v6!(PublicParts);
629impl_common_secret_functions_v6!(UnspecifiedParts);
630
631/// Secret key handling.
632impl<R> Key6<SecretParts, R>
633where R: KeyRole,
634{
635    /// Gets the `Key`'s `SecretKeyMaterial`.
636    pub fn secret(&self) -> &SecretKeyMaterial {
637        self.common.secret()
638    }
639
640    /// Gets a mutable reference to the `Key`'s `SecretKeyMaterial`.
641    pub fn secret_mut(&mut self) -> &mut SecretKeyMaterial {
642        self.common.secret_mut()
643    }
644
645    /// Takes the `Key`'s `SecretKeyMaterial`.
646    pub fn take_secret(mut self)
647                       -> (Key6<PublicParts, R>, SecretKeyMaterial)
648    {
649        let old = std::mem::replace(&mut self.common.secret, None);
650        (self.parts_into_public(),
651         old.expect("Key<SecretParts, _> has a secret key material"))
652    }
653
654    /// Adds `SecretKeyMaterial` to the `Key`.
655    ///
656    /// This function returns the old secret key material, if any.
657    pub fn add_secret(mut self, secret: SecretKeyMaterial)
658                      -> (Key6<SecretParts, R>, SecretKeyMaterial)
659    {
660        let old = std::mem::replace(&mut self.common.secret, Some(secret));
661        (self.parts_into_secret().expect("secret just set"),
662         old.expect("Key<SecretParts, _> has a secret key material"))
663    }
664
665    /// Decrypts the secret key material using `password`.
666    ///
667    /// In OpenPGP, secret key material can be [protected with a
668    /// password].  The password is usually hardened using a [KDF].
669    ///
670    /// Refer to the documentation of [`Key::decrypt_secret`] for
671    /// details.
672    ///
673    /// This function returns an error if the secret key material is
674    /// not encrypted or the password is incorrect.
675    ///
676    /// [protected with a password]: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.5.3
677    /// [KDF]: https://www.rfc-editor.org/rfc/rfc9580.html#section-3.7
678    /// [`Key::decrypt_secret`]: super::Key::decrypt_secret()
679    pub fn decrypt_secret(self, password: &Password) -> Result<Self> {
680        let (key, mut secret) = self.take_secret();
681        // Note: Key version is authenticated.
682        let key = Key::V6(key);
683        secret.decrypt_in_place(&key, password)?;
684        let key = if let Key::V6(k) = key { k } else { unreachable!() };
685        Ok(key.add_secret(secret).0)
686    }
687
688    /// Encrypts the secret key material using `password`.
689    ///
690    /// In OpenPGP, secret key material can be [protected with a
691    /// password].  The password is usually hardened using a [KDF].
692    ///
693    /// Refer to the documentation of [`Key::encrypt_secret`] for
694    /// details.
695    ///
696    /// This returns an error if the secret key material is already
697    /// encrypted.
698    ///
699    /// [protected with a password]: https://www.rfc-editor.org/rfc/rfc9580.html#section-5.5.3
700    /// [KDF]: https://www.rfc-editor.org/rfc/rfc9580.html#section-3.7
701    /// [`Key::encrypt_secret`]: super::Key::encrypt_secret()
702    pub fn encrypt_secret(self, password: &Password)
703                          -> Result<Key6<SecretParts, R>>
704    {
705        let (key, mut secret) = self.take_secret();
706        // Note: Key version is authenticated.
707        let key = Key::V6(key);
708        secret.encrypt_in_place(&key, password)?;
709        let key = if let Key::V6(k) = key { k } else { unreachable!() };
710        Ok(key.add_secret(secret).0)
711    }
712}
713
714impl<P, R> From<Key6<P, R>> for super::Key<P, R>
715where P: KeyParts,
716      R: KeyRole,
717{
718    fn from(p: Key6<P, R>) -> Self {
719        super::Key::V6(p)
720    }
721}
722
723#[cfg(test)]
724use crate::packet::key::{
725    PrimaryRole,
726    SubordinateRole,
727    UnspecifiedRole,
728};
729
730#[cfg(test)]
731impl Arbitrary for Key6<PublicParts, PrimaryRole> {
732    fn arbitrary(g: &mut Gen) -> Self {
733        Key6::from_common(Key4::arbitrary(g))
734    }
735}
736
737#[cfg(test)]
738impl Arbitrary for Key6<PublicParts, SubordinateRole> {
739    fn arbitrary(g: &mut Gen) -> Self {
740        Key6::from_common(Key4::arbitrary(g))
741    }
742}
743
744#[cfg(test)]
745impl Arbitrary for Key6<PublicParts, UnspecifiedRole> {
746    fn arbitrary(g: &mut Gen) -> Self {
747        Key6::from_common(Key4::arbitrary(g))
748    }
749}
750
751#[cfg(test)]
752impl Arbitrary for Key6<SecretParts, PrimaryRole> {
753    fn arbitrary(g: &mut Gen) -> Self {
754        Key6::from_common(Key4::arbitrary(g))
755    }
756}
757
758#[cfg(test)]
759impl Arbitrary for Key6<SecretParts, SubordinateRole> {
760    fn arbitrary(g: &mut Gen) -> Self {
761        Key6::from_common(Key4::arbitrary(g))
762    }
763}
764
765
766#[cfg(test)]
767mod tests {
768    use std::time::Duration;
769    use std::time::UNIX_EPOCH;
770
771    use crate::crypto::S2K;
772    use crate::packet::Key;
773    use crate::packet::key;
774    use crate::packet::Packet;
775    use super::*;
776    use crate::PacketPile;
777    use crate::serialize::Serialize;
778    use crate::types::*;
779    use crate::parse::Parse;
780
781    #[test]
782    fn primary_key_encrypt_decrypt() -> Result<()> {
783        key_encrypt_decrypt::<PrimaryRole>()
784    }
785
786    #[test]
787    fn subkey_encrypt_decrypt() -> Result<()> {
788        key_encrypt_decrypt::<SubordinateRole>()
789    }
790
791    fn key_encrypt_decrypt<R>() -> Result<()>
792    where
793        R: KeyRole + PartialEq,
794    {
795        let mut g = quickcheck::Gen::new(256);
796        let p: Password = Vec::<u8>::arbitrary(&mut g).into();
797
798        let check = |key: Key6<SecretParts, R>| -> Result<()> {
799            let key: Key<_, _> = key.into();
800            let encrypted = key.clone().encrypt_secret(&p)?;
801            let decrypted = encrypted.decrypt_secret(&p)?;
802            assert_eq!(key, decrypted);
803            Ok(())
804        };
805
806        use crate::types::Curve::*;
807        for curve in vec![NistP256, NistP384, NistP521, Ed25519] {
808            if ! curve.is_supported() {
809                eprintln!("Skipping unsupported {}", curve);
810                continue;
811            }
812
813            let key: Key6<_, R>
814                = Key6::generate_ecc(true, curve.clone())?;
815            check(key)?;
816        }
817
818        for bits in vec![2048, 3072] {
819            if ! PublicKeyAlgorithm::RSAEncryptSign.is_supported() {
820                eprintln!("Skipping unsupported RSA");
821                continue;
822            }
823
824            let key: Key6<_, R>
825                = Key6::generate_rsa(bits)?;
826            check(key)?;
827        }
828
829        Ok(())
830    }
831
832    #[test]
833    fn eq() {
834        use crate::types::Curve::*;
835
836        for curve in vec![NistP256, NistP384, NistP521] {
837            if ! curve.is_supported() {
838                eprintln!("Skipping unsupported {}", curve);
839                continue;
840            }
841
842            let sign_key : Key6<_, key::UnspecifiedRole>
843                = Key6::generate_ecc(true, curve.clone()).unwrap();
844            let enc_key : Key6<_, key::UnspecifiedRole>
845                = Key6::generate_ecc(false, curve).unwrap();
846            let sign_clone = sign_key.clone();
847            let enc_clone = enc_key.clone();
848
849            assert_eq!(sign_key, sign_clone);
850            assert_eq!(enc_key, enc_clone);
851        }
852
853        for bits in vec![1024, 2048, 3072, 4096] {
854            if ! PublicKeyAlgorithm::RSAEncryptSign.is_supported() {
855                eprintln!("Skipping unsupported RSA");
856                continue;
857            }
858
859            let key : Key6<_, key::UnspecifiedRole>
860                = Key6::generate_rsa(bits).unwrap();
861            let clone = key.clone();
862            assert_eq!(key, clone);
863        }
864    }
865
866    #[test]
867    fn generate_roundtrip() {
868        use crate::types::Curve::*;
869
870        let keys = vec![NistP256, NistP384, NistP521].into_iter().flat_map(|cv|
871        {
872            if ! cv.is_supported() {
873                eprintln!("Skipping unsupported {}", cv);
874                return Vec::new();
875            }
876
877            let sign_key : Key6<key::SecretParts, key::PrimaryRole>
878                = Key6::generate_ecc(true, cv.clone()).unwrap();
879            let enc_key = Key6::generate_ecc(false, cv).unwrap();
880
881            vec![sign_key, enc_key]
882        }).chain(vec![1024, 2048, 3072, 4096].into_iter().filter_map(|b| {
883            Key6::generate_rsa(b).ok()
884        }));
885
886        for key in keys {
887            let mut b = Vec::new();
888            Packet::SecretKey(key.clone().into()).serialize(&mut b).unwrap();
889
890            let pp = PacketPile::from_bytes(&b).unwrap();
891            if let Some(Packet::SecretKey(Key::V6(ref parsed_key))) =
892                pp.path_ref(&[0])
893            {
894                assert_eq!(key.creation_time(), parsed_key.creation_time());
895                assert_eq!(key.pk_algo(), parsed_key.pk_algo());
896                assert_eq!(key.mpis(), parsed_key.mpis());
897                assert_eq!(key.secret(), parsed_key.secret());
898
899                assert_eq!(&key, parsed_key);
900            } else {
901                panic!("bad packet: {:?}", pp.path_ref(&[0]));
902            }
903
904            let mut b = Vec::new();
905            let pk4 : Key6<PublicParts, PrimaryRole> = key.clone().into();
906            Packet::PublicKey(pk4.into()).serialize(&mut b).unwrap();
907
908            let pp = PacketPile::from_bytes(&b).unwrap();
909            if let Some(Packet::PublicKey(Key::V6(ref parsed_key))) =
910                pp.path_ref(&[0])
911            {
912                assert!(! parsed_key.has_secret());
913
914                let key = key.take_secret().0;
915                assert_eq!(&key, parsed_key);
916            } else {
917                panic!("bad packet: {:?}", pp.path_ref(&[0]));
918            }
919        }
920    }
921
922    #[test]
923    fn encryption_roundtrip() {
924        use crate::crypto::SessionKey;
925        use crate::types::Curve::*;
926
927        let keys = vec![NistP256, NistP384, NistP521].into_iter()
928            .filter_map(|cv| {
929                Key6::generate_ecc(false, cv).ok()
930            }).chain(vec![1024, 2048, 3072, 4096].into_iter().filter_map(|b| {
931                Key6::generate_rsa(b).ok()
932            }));
933
934        for key in keys.into_iter() {
935            let key: Key<key::SecretParts, key::UnspecifiedRole> = key.into();
936            let mut keypair = key.clone().into_keypair().unwrap();
937            let cipher = SymmetricAlgorithm::AES256;
938            let sk = SessionKey::new(cipher.key_size().unwrap()).unwrap();
939
940            let pkesk = PKESK6::for_recipient(&sk, &key).unwrap();
941            let sk_ = pkesk.decrypt(&mut keypair, None)
942                .expect("keypair should be able to decrypt PKESK");
943            assert_eq!(sk, sk_);
944
945            let sk_ =
946                pkesk.decrypt(&mut keypair, Some(cipher)).unwrap();
947            assert_eq!(sk, sk_);
948        }
949    }
950
951    #[test]
952    fn signature_roundtrip() {
953        use crate::types::{Curve::*, SignatureType};
954
955        let keys = vec![NistP256, NistP384, NistP521].into_iter()
956            .filter_map(|cv| {
957                Key6::generate_ecc(true, cv).ok()
958            }).chain(vec![1024, 2048, 3072, 4096].into_iter().filter_map(|b| {
959                Key6::generate_rsa(b).ok()
960            }));
961
962        for key in keys.into_iter() {
963            let key: Key<key::SecretParts, key::UnspecifiedRole> = key.into();
964            let mut keypair = key.clone().into_keypair().unwrap();
965            let hash = HashAlgorithm::default();
966
967            // Sign.
968            let ctx = hash.context().unwrap().for_signature(key.version());
969            let sig = SignatureBuilder::new(SignatureType::Binary)
970                .sign_hash(&mut keypair, ctx).unwrap();
971
972            // Verify.
973            let ctx = hash.context().unwrap().for_signature(key.version());
974            sig.verify_hash(&key, ctx).unwrap();
975        }
976    }
977
978    #[test]
979    fn secret_encryption_roundtrip() {
980        use crate::types::Curve::*;
981        use crate::types::SymmetricAlgorithm::*;
982        use crate::types::AEADAlgorithm::*;
983
984        let keys = vec![NistP256, NistP384, NistP521].into_iter()
985            .filter_map(|cv| -> Option<Key<key::SecretParts, key::PrimaryRole>> {
986                Key6::generate_ecc(false, cv).map(Into::into).ok()
987            }).chain(vec![1024, 2048, 3072, 4096].into_iter().filter_map(|b| {
988                Key6::generate_rsa(b).map(Into::into).ok()
989            }));
990
991        for key in keys {
992          for (symm, aead) in [(AES128, None),
993                               (AES128, Some(OCB)),
994                               (AES256, Some(EAX))] {
995            if ! aead.map(|a| a.is_supported()).unwrap_or(true) {
996                continue;
997            }
998            assert!(! key.secret().is_encrypted());
999
1000            let password = Password::from("foobarbaz");
1001            let mut encrypted_key = key.clone();
1002
1003            encrypted_key.secret_mut()
1004                .encrypt_in_place_with(&key, S2K::default(), symm, aead,
1005                                       &password).unwrap();
1006            assert!(encrypted_key.secret().is_encrypted());
1007
1008            encrypted_key.secret_mut()
1009                .decrypt_in_place(&key, &password).unwrap();
1010            assert!(! key.secret().is_encrypted());
1011            assert_eq!(key, encrypted_key);
1012            assert_eq!(key.secret(), encrypted_key.secret());
1013          }
1014        }
1015    }
1016
1017    #[test]
1018    fn encrypt_huge_plaintext() -> Result<()> {
1019        let sk = crate::crypto::SessionKey::new(256).unwrap();
1020
1021        if PublicKeyAlgorithm::RSAEncryptSign.is_supported() {
1022            let rsa2k: Key<SecretParts, UnspecifiedRole> =
1023                Key6::generate_rsa(2048)?.into();
1024            assert!(matches!(
1025                rsa2k.encrypt(&sk).unwrap_err().downcast().unwrap(),
1026                crate::Error::InvalidArgument(_)
1027            ));
1028        }
1029
1030        Ok(())
1031    }
1032
1033    #[test]
1034    fn issue_1016() {
1035        // The fingerprint is a function of the creation time,
1036        // algorithm, and public MPIs.  When we change them make sure
1037        // the fingerprint also changes.
1038
1039        let mut g = quickcheck::Gen::new(256);
1040
1041        let mut key = Key6::<PublicParts, UnspecifiedRole>::arbitrary(&mut g);
1042        let fpr1 = key.fingerprint();
1043        if key.creation_time() == UNIX_EPOCH {
1044            key.set_creation_time(UNIX_EPOCH + Duration::new(1, 0)).expect("ok");
1045        } else {
1046            key.set_creation_time(UNIX_EPOCH).expect("ok");
1047        }
1048        assert_ne!(fpr1, key.fingerprint());
1049
1050        let mut key = Key6::<PublicParts, UnspecifiedRole>::arbitrary(&mut g);
1051        let fpr1 = key.fingerprint();
1052        key.set_pk_algo(PublicKeyAlgorithm::from(u8::from(key.pk_algo()) + 1));
1053        assert_ne!(fpr1, key.fingerprint());
1054
1055        let mut key = Key6::<PublicParts, UnspecifiedRole>::arbitrary(&mut g);
1056        let fpr1 = key.fingerprint();
1057        loop {
1058            let mpis2 = mpi::PublicKey::arbitrary(&mut g);
1059            if key.mpis() != &mpis2 {
1060                *key.mpis_mut() = mpis2;
1061                break;
1062            }
1063        }
1064        assert_ne!(fpr1, key.fingerprint());
1065
1066        let mut key = Key6::<PublicParts, UnspecifiedRole>::arbitrary(&mut g);
1067        let fpr1 = key.fingerprint();
1068        loop {
1069            let mpis2 = mpi::PublicKey::arbitrary(&mut g);
1070            if key.mpis() != &mpis2 {
1071                key.set_mpis(mpis2);
1072                break;
1073            }
1074        }
1075        assert_ne!(fpr1, key.fingerprint());
1076    }
1077
1078    /// Smoke test for ECC key creation, signing and verification, and
1079    /// encryption and decryption.
1080    #[test]
1081    fn ecc_support() -> Result<()> {
1082        for for_signing in [true, false] {
1083            for curve in Curve::variants()
1084                .filter(Curve::is_supported)
1085            {
1086                match curve {
1087                    Curve::Cv25519 if for_signing => continue,
1088                    Curve::Ed25519 if ! for_signing => continue,
1089                    _ => (),
1090                }
1091
1092                eprintln!("curve {}, for signing {:?}", curve, for_signing);
1093                let key: Key<SecretParts, UnspecifiedRole> =
1094                    Key6::generate_ecc(for_signing, curve.clone())?.into();
1095                let mut pair = key.into_keypair()?;
1096
1097                if for_signing {
1098                    use crate::crypto::Signer;
1099                    let hash = HashAlgorithm::default();
1100                    let digest = hash.context()?
1101                        .for_signature(pair.public().version())
1102                        .into_digest()?;
1103                    let sig = pair.sign(hash, &digest)?;
1104                    pair.public().verify(&sig, hash, &digest)?;
1105                } else {
1106                    use crate::crypto::{SessionKey, Decryptor};
1107                    let sk = SessionKey::new(32).unwrap();
1108                    let ciphertext = pair.public().encrypt(&sk)?;
1109                    assert_eq!(pair.decrypt(&ciphertext, Some(sk.len()))?, sk);
1110                }
1111            }
1112        }
1113        Ok(())
1114    }
1115
1116    #[test]
1117    fn ecc_encoding() -> Result<()> {
1118        for for_signing in [true, false] {
1119            for curve in Curve::variants()
1120                .filter(Curve::is_supported)
1121            {
1122                match curve {
1123                    Curve::Cv25519 if for_signing => continue,
1124                    Curve::Ed25519 if ! for_signing => continue,
1125                    _ => (),
1126                }
1127
1128                use crate::crypto::mpi::{Ciphertext, MPI, PublicKey};
1129                eprintln!("curve {}, for signing {:?}", curve, for_signing);
1130
1131                let key: Key<SecretParts, UnspecifiedRole> =
1132                    Key6::generate_ecc(for_signing, curve.clone())?.into();
1133
1134                let uncompressed = |mpi: &MPI| mpi.value()[0] == 0x04;
1135
1136                match key.mpis() {
1137                    PublicKey::X25519 { .. } if ! for_signing => (),
1138                    PublicKey::X448 { .. } if ! for_signing => (),
1139                    PublicKey::Ed25519 { .. } if for_signing => (),
1140                    PublicKey::Ed448 { .. } if for_signing => (),
1141                    PublicKey::ECDSA { curve: c, q } if for_signing => {
1142                        assert!(c == &curve);
1143                        assert!(c != &Curve::Ed25519);
1144                        assert!(uncompressed(q));
1145                    },
1146                    PublicKey::ECDH { curve: c, q, .. } if ! for_signing => {
1147                        assert!(c == &curve);
1148                        assert!(c != &Curve::Cv25519);
1149                        assert!(uncompressed(q));
1150
1151                        use crate::crypto::SessionKey;
1152                        let sk = SessionKey::new(32).unwrap();
1153                        let ciphertext = key.encrypt(&sk)?;
1154                        if let Ciphertext::ECDH { e, .. } = &ciphertext {
1155                            assert!(uncompressed(e));
1156                        } else {
1157                            panic!("unexpected ciphertext: {:?}", ciphertext);
1158                        }
1159                    },
1160                    mpi => unreachable!(
1161                        "curve {}, mpi {:?}, for signing {:?}",
1162                        curve, mpi, for_signing),
1163                }
1164            }
1165        }
1166        Ok(())
1167    }
1168
1169
1170    #[test]
1171    fn v6_key_fingerprint() -> Result<()> {
1172        let p = Packet::from_bytes("-----BEGIN PGP ARMORED FILE-----
1173
1174xjcGY4d/4xYAAAAtCSsGAQQB2kcPAQEHQPlNp7tI1gph5WdwamWH0DMZmbudiRoI
1175JC6thFQ9+JWj
1176=SgmS
1177-----END PGP ARMORED FILE-----")?;
1178        let k: &Key<PublicParts, PrimaryRole> = p.downcast_ref().unwrap();
1179        assert_eq!(k.fingerprint().to_string(),
1180                   "4EADF309C6BC874AE04702451548F93F\
1181                    96FA7A01D0A33B5AF7D4E379E0F9F8EE".to_string());
1182        Ok(())
1183    }
1184}