diff options
author | Neal H. Walfield <neal@pep.foundation> | 2020-02-13 12:22:08 +0100 |
---|---|---|
committer | Neal H. Walfield <neal@pep.foundation> | 2020-02-13 14:54:17 +0100 |
commit | d8918d1789d639370df6f7dea83a16e0e5df2ea9 (patch) | |
tree | 38c78efb2a38aba4674f624c277978553ae81e74 | |
parent | b61438c891b7c6a38db647ce08726ea41df3ab06 (diff) |
openpgp: Generalize the conversion functions to reduce duplication.
- Generalize the code for converting between the KeyParts marker
traits on Key-like things.
- Use it for generating the conversions for KeyAmalgamation,
ValidKeyAmalgamation, PrimaryKeyAmalgamation, and
ValidPrimaryKeyAmalgamation.
- This also generates the .mark_parts_secret(), etc. methods, which
were missing.
-rw-r--r-- | openpgp/src/cert/key_amalgamation.rs | 83 | ||||
-rw-r--r-- | openpgp/src/packet/key/mod.rs | 169 |
2 files changed, 92 insertions, 160 deletions
diff --git a/openpgp/src/cert/key_amalgamation.rs b/openpgp/src/cert/key_amalgamation.rs index 952f3775..77c6c85a 100644 --- a/openpgp/src/cert/key_amalgamation.rs +++ b/openpgp/src/cert/key_amalgamation.rs @@ -1,6 +1,5 @@ use std::time; use std::time::SystemTime; -use std::convert::TryFrom; use std::ops::Deref; use crate::{ @@ -45,88 +44,6 @@ impl<'a, P: key::KeyParts> Deref for KeyAmalgamation<'a, P> { } } -macro_rules! create_p_conversions { - ( $Key:ident ) => { - macro_rules! convert { - ( $x:ident ) => { - // XXX: This is ugly, but how can we do better? - unsafe { std::mem::transmute($x) } - } - } - - macro_rules! convert_ref { - ( $x:ident ) => { - // XXX: This is ugly, but how can we do better? - unsafe { std::mem::transmute($x) } - } - } - - // Convert between two KeyParts for a constant KeyRole. - // Unfortunately, we can't let the KeyRole vary as otherwise we - // get conflicting types when we do the same to convert between - // two KeyRoles for a constant KeyParts. :( - macro_rules! p { - ( <$from_parts:ty> -> <$to_parts:ty>) => { - impl<'a> From<$Key<'a, $from_parts>> for $Key<'a, $to_parts> { - fn from(p: $Key<'a, $from_parts>) -> Self { - convert!(p) - } - } - - impl<'a> From<&$Key<'a, $from_parts>> for &$Key<'a, $to_parts> { - fn from(p: &$Key<'a, $from_parts>) -> Self { - convert_ref!(p) - } - } - } - } - - // Likewise, but using TryFrom. - macro_rules! p_try { - ( <$from_parts:ty> -> <$to_parts:ty>) => { - impl<'a> TryFrom<$Key<'a, $from_parts>> for $Key<'a, $to_parts> { - type Error = failure::Error; - fn try_from(p: $Key<'a, $from_parts>) -> Result<Self> { - if p.secret().is_some() { - Ok(convert!(p)) - } else { - Err(Error::InvalidArgument("No secret key".into()) - .into()) - } - } - } - - impl<'a> TryFrom<&$Key<'a, $from_parts>> for &$Key<'a, $to_parts> { - type Error = failure::Error; - fn try_from(p: &$Key<'a, $from_parts>) -> Result<Self> { - if p.secret().is_some() { - Ok(convert_ref!(p)) - } else { - Err(Error::InvalidArgument("No secret key".into()) - .into()) - } - } - } - } - } - - - p_try!(<key::PublicParts> -> <key::SecretParts>); - p!(<key::PublicParts> -> <key::UnspecifiedParts>); - - p!(<key::SecretParts> -> <key::PublicParts>); - p!(<key::SecretParts> -> <key::UnspecifiedParts>); - - p!(<key::UnspecifiedParts> -> <key::PublicParts>); - p_try!(<key::UnspecifiedParts> -> <key::SecretParts>); - } -} - -create_p_conversions!(KeyAmalgamation); -create_p_conversions!(PrimaryKeyAmalgamation); -create_p_conversions!(ValidKeyAmalgamation); -create_p_conversions!(ValidPrimaryKeyAmalgamation); - impl<'a, P: 'a + key::KeyParts> KeyAmalgamation<'a, P> { pub(crate) fn new_primary(cert: &'a Cert) -> Self { KeyAmalgamation { diff --git a/openpgp/src/packet/key/mod.rs b/openpgp/src/packet/key/mod.rs index 875cf5b1..0479c592 100644 --- a/openpgp/src/packet/key/mod.rs +++ b/openpgp/src/packet/key/mod.rs @@ -59,7 +59,10 @@ use std::time; use crate::Error; use crate::cert::components::{ KeyBundle, + KeyAmalgamation, ValidKeyAmalgamation, + PrimaryKeyAmalgamation, + ValidPrimaryKeyAmalgamation, }; use crate::crypto::{self, mem::{self, Protected}, mpis, hash::Hash}; use crate::packet; @@ -449,26 +452,26 @@ macro_rules! convert_ref { // To solve this, we need at least one generic variable to be // concrete on both sides of the `From`. -macro_rules! create_conversions { - ( $Key:ident ) => { +macro_rules! create_part_conversions { + ( $Key:ident<$( $l:lifetime ),*; $( $g:ident ),*> where $( $w:ident: $c:ident ),* ) => { // Convert between two KeyParts for a constant KeyRole. // Unfortunately, we can't let the KeyRole vary as otherwise we // get conflicting types when we do the same to convert between // two KeyRoles for a constant KeyParts. :( macro_rules! p { - ( <$from_parts:ty> -> <$to_parts:ty>) => { - impl<R> From<$Key<$from_parts, R>> for $Key<$to_parts, R> - where R: KeyRole + ( <$from_parts:ty> -> <$to_parts:ty> ) => { + impl<$($l, )* $($g, )* > From<$Key<$($l, )* $from_parts, $($g, )* >> for $Key<$($l, )* $to_parts, $($g, )* > + where $($w: $c ),* { - fn from(p: $Key<$from_parts, R>) -> Self { + fn from(p: $Key<$($l, )* $from_parts, $($g, )* >) -> Self { convert!(p) } } - impl<R> From<&$Key<$from_parts, R>> for &$Key<$to_parts, R> - where R: KeyRole + impl<$($l, )* $($g, )* > From<&$Key<$($l, )* $from_parts, $($g, )* >> for &$Key<$($l, )* $to_parts, $($g, )* > + where $($w: $c ),* { - fn from(p: &$Key<$from_parts, R>) -> Self { + fn from(p: &$Key<$($l, )* $from_parts, $($g, )* >) -> Self { convert_ref!(p) } } @@ -478,20 +481,20 @@ macro_rules! create_conversions { // Likewise, but using TryFrom. macro_rules! p_try { ( <$from_parts:ty> -> <$to_parts:ty>) => { - impl<R> TryFrom<$Key<$from_parts, R>> for $Key<$to_parts, R> - where R: KeyRole + impl<$($l, )* $($g, )* > TryFrom<$Key<$($l, )* $from_parts, $($g, )* >> for $Key<$($l, )* $to_parts, $($g, )* > + where $($w: $c ),* { type Error = failure::Error; - fn try_from(p: $Key<$from_parts, R>) -> Result<Self> { + fn try_from(p: $Key<$($l, )* $from_parts, $($g, )* >) -> Result<Self> { p.mark_parts_secret() } } - impl<R> TryFrom<&$Key<$from_parts, R>> for &$Key<$to_parts, R> - where R: KeyRole + impl<$($l, )* $($g, )* > TryFrom<&$Key<$($l, )* $from_parts, $($g, )* >> for &$Key<$($l, )* $to_parts, $($g, )* > + where $($w: $c ),* { type Error = failure::Error; - fn try_from(p: &$Key<$from_parts, R>) -> Result<Self> { + fn try_from(p: &$Key<$($l, )* $from_parts, $($g, )* >) -> Result<Self> { if p.secret().is_some() { Ok(convert_ref!(p)) } else { @@ -513,6 +516,75 @@ macro_rules! create_conversions { p!(<UnspecifiedParts> -> <PublicParts>); p_try!(<UnspecifiedParts> -> <SecretParts>); + + impl<$($l, )* P, $($g, )*> $Key<$($l, )* P, $($g, )*> where P: KeyParts, $($w: $c ),* + { + /// Changes the key's parts tag to `PublicParts`. + pub fn mark_parts_public(self) -> $Key<$($l, )* PublicParts, $($g, )*> { + // Ideally, we'd use self.into() to do the actually + // conversion. But, because P is not concrete, we get the + // following error: + // + // error[E0277]: the trait bound `packet::Key<packet::key::PublicParts, R>: std::convert::From<packet::Key<P, R>>` is not satisfied + // --> openpgp/src/packet/key.rs:401:18 + // | + // 401 | self.into() + // | ^^^^ the trait `std::convert::From<packet::Key<P, R>>` is not implemented for `packet::Key<packet::key::PublicParts, R>` + // | + // = help: consider adding a `where packet::Key<packet::key::PublicParts, R>: std::convert::From<packet::Key<P, R>>` bound + // = note: required because of the requirements on the impl of `std::convert::Into<packet::Key<packet::key::PublicParts, R>>` for `packet::Key<P, R>` + // + // But we can't implement implement `From<Key<P, R>>` for + // `Key<PublicParts, R>`, because that conflicts with a + // standard conversion! (See the comment for the `p` + // macro above.) + // + // Adding the trait bound is annoying, because then we'd + // have to add it everywhere that we use into. + convert!(self) + } + + /// Changes the key's parts tag to `PublicParts`. + pub fn mark_parts_public_ref(&self) -> &$Key<$($l, )* PublicParts, $($g, )*> { + convert_ref!(self) + } + + /// Changes the key's parts tag to `SecretParts`. + pub fn mark_parts_secret(self) -> Result<$Key<$($l, )* SecretParts, $($g, )*>> { + if self.secret().is_some() { + Ok(convert!(self)) + } else { + Err(Error::InvalidArgument("No secret key".into()).into()) + } + } + + /// Changes the key's parts tag to `SecretParts`. + pub fn mark_parts_secret_ref(&self) -> Result<&$Key<$($l, )* SecretParts, $($g, )*>> + { + if self.secret().is_some() { + Ok(convert_ref!(self)) + } else { + Err(Error::InvalidArgument("No secret key".into()).into()) + } + } + + /// Changes the key's parts tag to `UnspecifiedParts`. + pub fn mark_parts_unspecified(self) -> $Key<$($l, )* UnspecifiedParts, $($g, )*> { + convert!(self) + } + + /// Changes the key's parts tag to `UnspecifiedParts`. + pub fn mark_parts_unspecified_ref(&self) -> &$Key<$($l, )* UnspecifiedParts, $($g, )*> { + convert_ref!(self) + } + } + }; +} + +macro_rules! create_conversions { + ( $Key:ident ) => { + create_part_conversions!($Key<; R> where R: KeyRole); + // Convert between two KeyRoles for a constant KeyParts. See // the comment for the p macro above. macro_rules! r { @@ -662,68 +734,6 @@ macro_rules! create_conversions { impl<P, R> $Key<P, R> where P: KeyParts, R: KeyRole { - /// Changes the key's parts tag to `PublicParts`. - pub fn mark_parts_public(self) -> $Key<PublicParts, R> { - // Ideally, we'd use self.into() to do the actually - // conversion. But, because P is not concrete, we get the - // following error: - // - // error[E0277]: the trait bound `packet::Key<packet::key::PublicParts, R>: std::convert::From<packet::Key<P, R>>` is not satisfied - // --> openpgp/src/packet/key.rs:401:18 - // | - // 401 | self.into() - // | ^^^^ the trait `std::convert::From<packet::Key<P, R>>` is not implemented for `packet::Key<packet::key::PublicParts, R>` - // | - // = help: consider adding a `where packet::Key<packet::key::PublicParts, R>: std::convert::From<packet::Key<P, R>>` bound - // = note: required because of the requirements on the impl of `std::convert::Into<packet::Key<packet::key::PublicParts, R>>` for `packet::Key<P, R>` - // - // But we can't implement implement `From<Key<P, R>>` for - // `Key<PublicParts, R>`, because that conflicts with a - // standard conversion! (See the comment for the `p` - // macro above.) - // - // Adding the trait bound is annoying, because then we'd - // have to add it everywhere that we use into. - convert!(self) - } - - /// Changes the key's parts tag to `PublicParts`. - pub fn mark_parts_public_ref(&self) -> &$Key<PublicParts, R> { - convert_ref!(self) - } - - /// Changes the key's parts tag to `SecretParts`. - pub fn mark_parts_secret(self) -> Result<$Key<SecretParts, R>> { - if self.secret().is_some() { - Ok(convert!(self)) - } else { - Err(Error::InvalidArgument("No secret key".into()).into()) - } - } - - /// Changes the key's parts tag to `SecretParts`. - pub fn mark_parts_secret_ref(&self) -> Result<&$Key<SecretParts, R>> - { - if self.secret().is_some() { - Ok(convert_ref!(self)) - } else { - Err(Error::InvalidArgument("No secret key".into()).into()) - } - } - - /// Changes the key's parts tag to `UnspecifiedParts`. - pub fn mark_parts_unspecified(self) -> $Key<UnspecifiedParts, R> { - convert!(self) - } - - /// Changes the key's parts tag to `UnspecifiedParts`. - pub fn mark_parts_unspecified_ref(&self) -> &$Key<UnspecifiedParts, R> { - convert_ref!(self) - } - } - - impl<P, R> $Key<P, R> where P: KeyParts, R: KeyRole - { /// Changes the key's role tag to `PrimaryRole`. pub fn mark_role_primary(self) -> $Key<P, PrimaryRole> { convert!(self) @@ -765,6 +775,11 @@ create_conversions!(Key); create_conversions!(Key4); create_conversions!(KeyBundle); +create_part_conversions!(KeyAmalgamation<'a;> where); +create_part_conversions!(PrimaryKeyAmalgamation<'a;> where); +create_part_conversions!(ValidKeyAmalgamation<'a;> where); +create_part_conversions!(ValidPrimaryKeyAmalgamation<'a;> where); + /// Holds a public key, public subkey, private key or private subkey packet. /// /// See [Section 5.5 of RFC 4880] for details. |