summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeal H. Walfield <neal@pep.foundation>2020-03-31 09:43:34 +0200
committerNeal H. Walfield <neal@pep.foundation>2020-03-31 21:22:03 +0200
commite82e6f543eb536ac9463d64e04c1f7f6962aa2c9 (patch)
tree049db9a71e38cece716285b0c1736136cef512f2
parentf4e2ccaad808ca83094d07eef7a6e03fc3625bc7 (diff)
openpgp: Implement Preferences for ValidCert.
- Preferences should be implemented for ValidComponentAmalgamation and ValidCert, not ValidComponentAmalgamation and ValidKeyAmalgamation. - Adjust the Preferences trait since ValidCert doesn't implement ValidAmalgamation.
-rw-r--r--openpgp/src/cert/amalgamation.rs45
-rw-r--r--openpgp/src/cert/key_amalgamation.rs9
-rw-r--r--openpgp/src/cert/mod.rs183
-rw-r--r--openpgp/tests/data/keys/different-preferences.asc52
4 files changed, 252 insertions, 37 deletions
diff --git a/openpgp/src/cert/amalgamation.rs b/openpgp/src/cert/amalgamation.rs
index 0fc44d98..79b49dcc 100644
--- a/openpgp/src/cert/amalgamation.rs
+++ b/openpgp/src/cert/amalgamation.rs
@@ -23,9 +23,15 @@ use crate::{
Result,
policy::Policy,
types::{
+ AEADAlgorithm,
+ CompressionAlgorithm,
+ Features,
+ HashAlgorithm,
+ KeyFlags,
+ KeyServerPreferences,
RevocationKey,
RevocationStatus,
- KeyFlags,
+ SymmetricAlgorithm,
},
};
@@ -276,7 +282,7 @@ pub trait ValidAmalgamation<'a, C: 'a>
/// A certificate's component and its associated data.
#[derive(Debug, PartialEq)]
-pub struct ComponentAmalgamation<'a, C>{
+pub struct ComponentAmalgamation<'a, C> {
cert: &'a Cert,
bundle: &'a ComponentBundle<C>,
}
@@ -751,8 +757,39 @@ impl<'a, C> ValidAmalgamation<'a, C> for ValidComponentAmalgamation<'a, C> {
}
}
-impl<'a, C> crate::cert::Preferences<'a, C>
- for ValidComponentAmalgamation<'a, C> {}
+impl<'a, C> crate::cert::Preferences<'a>
+ for ValidComponentAmalgamation<'a, C>
+{
+ fn preferred_symmetric_algorithms(&self)
+ -> Option<&'a [SymmetricAlgorithm]> {
+ self.map(|s| s.preferred_symmetric_algorithms())
+ }
+
+ fn preferred_hash_algorithms(&self) -> Option<&'a [HashAlgorithm]> {
+ self.map(|s| s.preferred_hash_algorithms())
+ }
+
+ fn preferred_compression_algorithms(&self)
+ -> Option<&'a [CompressionAlgorithm]> {
+ self.map(|s| s.preferred_compression_algorithms())
+ }
+
+ fn preferred_aead_algorithms(&self) -> Option<&'a [AEADAlgorithm]> {
+ self.map(|s| s.preferred_aead_algorithms())
+ }
+
+ fn key_server_preferences(&self) -> Option<KeyServerPreferences> {
+ self.map(|s| s.key_server_preferences())
+ }
+
+ fn preferred_key_server(&self) -> Option<&'a [u8]> {
+ self.map(|s| s.preferred_key_server())
+ }
+
+ fn features(&self) -> Option<Features> {
+ self.map(|s| s.features())
+ }
+}
#[cfg(test)]
mod test {
diff --git a/openpgp/src/cert/key_amalgamation.rs b/openpgp/src/cert/key_amalgamation.rs
index d8e1a4b7..3b138340 100644
--- a/openpgp/src/cert/key_amalgamation.rs
+++ b/openpgp/src/cert/key_amalgamation.rs
@@ -890,15 +890,6 @@ impl<'a, P, R, R2> ValidKeyAmalgamation<'a, P, R, R2>
}
-impl<'a, P, R, R2> crate::cert::Preferences<'a, Key<P, R>>
- for ValidKeyAmalgamation<'a, P, R, R2>
- where P: 'a + key::KeyParts,
- R: 'a + key::KeyRole,
- R2: Copy,
- Self: Primary<'a, P, R>,
-{
-}
-
#[cfg(test)]
mod test {
use crate::policy::StandardPolicy as P;
diff --git a/openpgp/src/cert/mod.rs b/openpgp/src/cert/mod.rs
index b6f12c2e..642f0d6d 100644
--- a/openpgp/src/cert/mod.rs
+++ b/openpgp/src/cert/mod.rs
@@ -43,7 +43,6 @@ use crate::types::{
};
pub mod amalgamation;
-use amalgamation::ValidAmalgamation;
mod builder;
mod bindings;
pub mod components;
@@ -232,55 +231,40 @@ type UnknownBindings = ComponentBundles<Unknown>;
/// on self signatures can be used to express preferences for
/// algorithms and key management. Furthermore, the key holder's
/// OpenPGP implementation can express its feature set.
-pub trait Preferences<'a, C: 'a>: ValidAmalgamation<'a, C> {
+pub trait Preferences<'a> {
/// Returns symmetric algorithms that the key holder prefers.
///
/// The algorithms are ordered according by the key holder's
- /// preference.
fn preferred_symmetric_algorithms(&self)
- -> Option<&'a [SymmetricAlgorithm]> {
- self.map(|s| s.preferred_symmetric_algorithms())
- }
+ -> Option<&'a [SymmetricAlgorithm]>;
/// Returns hash algorithms that the key holder prefers.
///
/// The algorithms are ordered according by the key holder's
/// preference.
- fn preferred_hash_algorithms(&self) -> Option<&'a [HashAlgorithm]> {
- self.map(|s| s.preferred_hash_algorithms())
- }
+ fn preferred_hash_algorithms(&self) -> Option<&'a [HashAlgorithm]>;
/// Returns compression algorithms that the key holder prefers.
///
/// The algorithms are ordered according by the key holder's
/// preference.
fn preferred_compression_algorithms(&self)
- -> Option<&'a [CompressionAlgorithm]> {
- self.map(|s| s.preferred_compression_algorithms())
- }
+ -> Option<&'a [CompressionAlgorithm]>;
/// Returns AEAD algorithms that the key holder prefers.
///
/// The algorithms are ordered according by the key holder's
/// preference.
- fn preferred_aead_algorithms(&self) -> Option<&'a [AEADAlgorithm]> {
- self.map(|s| s.preferred_aead_algorithms())
- }
+ fn preferred_aead_algorithms(&self) -> Option<&'a [AEADAlgorithm]>;
/// Returns the key holder's keyserver preferences.
- fn key_server_preferences(&self) -> Option<KeyServerPreferences> {
- self.map(|s| s.key_server_preferences())
- }
+ fn key_server_preferences(&self) -> Option<KeyServerPreferences>;
/// Returns the key holder's preferred keyserver for updates.
- fn preferred_key_server(&self) -> Option<&'a [u8]> {
- self.map(|s| s.preferred_key_server())
- }
+ fn preferred_key_server(&self) -> Option<&'a [u8]>;
/// Returns the key holder's feature set.
- fn features(&self) -> Option<Features> {
- self.map(|s| s.features())
- }
+ fn features(&self) -> Option<Features>;
}
// DOC-HACK: To avoid having a top-level re-export of `Cert`, we move
@@ -1511,6 +1495,36 @@ impl<'a> ValidCert<'a> {
}
}
+macro_rules! impl_pref {
+ ($subpacket:ident, $rt:ty) => {
+ fn $subpacket(&self) -> Option<$rt>
+ {
+ // When addressed by the fingerprint or keyid, we first
+ // look on the primary User ID and then fall back to the
+ // direct key signature. We need to be careful to handle
+ // the case where there are no User IDs.
+ if let Ok(u) = self.primary_userid() {
+ u.$subpacket()
+ } else if let Ok(sig) = self.direct_key_signature() {
+ sig.$subpacket()
+ } else {
+ None
+ }
+ }
+ }
+}
+
+impl<'a> crate::cert::Preferences<'a> for ValidCert<'a>
+{
+ impl_pref!(preferred_symmetric_algorithms, &'a [SymmetricAlgorithm]);
+ impl_pref!(preferred_hash_algorithms, &'a [HashAlgorithm]);
+ impl_pref!(preferred_compression_algorithms, &'a [CompressionAlgorithm]);
+ impl_pref!(preferred_aead_algorithms, &'a [AEADAlgorithm]);
+ impl_pref!(key_server_preferences, KeyServerPreferences);
+ impl_pref!(preferred_key_server, &'a [u8]);
+ impl_pref!(features, Features);
+}
+
#[cfg(test)]
mod test {
use crate::serialize::Serialize;
@@ -3436,4 +3450,125 @@ Pu1xwz57O4zo1VYf6TqHJzVC3OMvMUM2hhdecMUe5x6GorNaj6g=
assert_eq!(cert_at.keys().count(), 1);
Ok(())
}
+
+ #[test]
+ fn different_preferences() -> Result<()> {
+ use crate::cert::Preferences;
+ let p = &crate::policy::StandardPolicy::new();
+
+ // This key returns different preferences depending on how you
+ // address it. (It has two user ids and the user ids have
+ // different preference packets on their respective self
+ // signatures.)
+
+ let cert = Cert::from_bytes(
+ crate::tests::key("different-preferences.asc"))?;
+ assert_eq!(cert.userids().count(), 2);
+
+ if let Some(userid) = cert.userids().nth(0) {
+ assert_eq!(userid.userid().value(),
+ &b"Alice Confusion <alice@example.com>"[..]);
+
+ let userid = userid.with_policy(p, None).expect("valid");
+
+ use crate::types::SymmetricAlgorithm::*;
+ assert_eq!(userid.preferred_symmetric_algorithms(),
+ Some(&[ AES256, AES192, AES128, TripleDES ][..]));
+
+ use crate::types::HashAlgorithm::*;
+ assert_eq!(userid.preferred_hash_algorithms(),
+ Some(&[ SHA512, SHA384, SHA256, SHA224, SHA1 ][..]));
+
+ use crate::types::CompressionAlgorithm::*;
+ assert_eq!(userid.preferred_compression_algorithms(),
+ Some(&[ Zlib, BZip2, Zip ][..]));
+
+ assert_eq!(userid.preferred_aead_algorithms(), None);
+
+ // assert_eq!(userid.key_server_preferences(),
+ // Some(KeyServerPreferences::new(&[])));
+
+ assert_eq!(userid.features(),
+ Some(Features::new(&[]).set_mdc(true)));
+ } else {
+ panic!("two user ids");
+ }
+
+ if let Some(userid) = cert.userids().nth(0) {
+ assert_eq!(userid.userid().value(),
+ &b"Alice Confusion <alice@example.com>"[..]);
+
+ let userid = userid.with_policy(p, None).expect("valid");
+
+ use crate::types::SymmetricAlgorithm::*;
+ assert_eq!(userid.preferred_symmetric_algorithms(),
+ Some(&[ AES256, AES192, AES128, TripleDES ][..]));
+
+ use crate::types::HashAlgorithm::*;
+ assert_eq!(userid.preferred_hash_algorithms(),
+ Some(&[ SHA512, SHA384, SHA256, SHA224, SHA1 ][..]));
+
+ use crate::types::CompressionAlgorithm::*;
+ assert_eq!(userid.preferred_compression_algorithms(),
+ Some(&[ Zlib, BZip2, Zip ][..]));
+
+ assert_eq!(userid.preferred_aead_algorithms(), None);
+
+ assert_eq!(userid.key_server_preferences(),
+ Some(KeyServerPreferences::new(&[0x80])));
+
+ assert_eq!(userid.features(),
+ Some(Features::new(&[]).set_mdc(true)));
+
+ // Using the certificate should choose the primary user
+ // id, which is this one (because it is lexicographically
+ // earlier).
+ let cert = cert.with_policy(p, None).expect("valid");
+ assert_eq!(userid.preferred_symmetric_algorithms(),
+ cert.preferred_symmetric_algorithms());
+ assert_eq!(userid.preferred_hash_algorithms(),
+ cert.preferred_hash_algorithms());
+ assert_eq!(userid.preferred_compression_algorithms(),
+ cert.preferred_compression_algorithms());
+ assert_eq!(userid.preferred_aead_algorithms(),
+ cert.preferred_aead_algorithms());
+ assert_eq!(userid.key_server_preferences(),
+ cert.key_server_preferences());
+ assert_eq!(userid.features(),
+ cert.features());
+ } else {
+ panic!("two user ids");
+ }
+
+ if let Some(userid) = cert.userids().nth(1) {
+ assert_eq!(userid.userid().value(),
+ &b"Alice Confusion <alice@example.net>"[..]);
+
+ let userid = userid.with_policy(p, None).expect("valid");
+
+ use crate::types::SymmetricAlgorithm::*;
+ assert_eq!(userid.preferred_symmetric_algorithms(),
+ Some(&[ AES192, AES256, AES128, TripleDES ][..]));
+
+ use crate::types::HashAlgorithm::*;
+ assert_eq!(userid.preferred_hash_algorithms(),
+ Some(&[ SHA384, SHA512, SHA256, SHA224, SHA1 ][..]));
+
+ use crate::types::CompressionAlgorithm::*;
+ assert_eq!(userid.preferred_compression_algorithms(),
+ Some(&[ BZip2, Zlib, Zip ][..]));
+
+ assert_eq!(userid.preferred_aead_algorithms(), None);
+
+ assert_eq!(userid.key_server_preferences(),
+ Some(KeyServerPreferences::new(&[0x80])));
+
+ assert_eq!(userid.features(),
+ Some(Features::new(&[]).set_mdc(true)));
+ } else {
+ panic!("two user ids");
+ }
+
+ Ok(())
+ }
}
diff --git a/openpgp/tests/data/keys/different-preferences.asc b/openpgp/tests/data/keys/different-preferences.asc
new file mode 100644
index 00000000..ebd04704
--- /dev/null
+++ b/openpgp/tests/data/keys/different-preferences.asc
@@ -0,0 +1,52 @@
+-----BEGIN PGP PUBLIC KEY BLOCK-----
+
+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
+Tg==
+=URg9
+-----END PGP PUBLIC KEY BLOCK-----