summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeal H. Walfield <neal@pep.foundation>2022-10-31 20:38:02 +0100
committerNeal H. Walfield <neal@pep.foundation>2022-11-15 19:46:48 +0100
commit095eed89ee4e6b4f924ff2f43aaadb5fd30c20a7 (patch)
tree8f04100e20aeb8209bfb2bf939f9d91cd97870a6
parentbe2de85d31674b6790b2f02bdac9bf7e7b4810aa (diff)
openpgp: Simplify using a good list with a StandardPolicy.
- To use a good list, we need to reject all options by default and then only enable those on the good list. - Add a mechanism to reject all options in a particular category (hash algorithms, critical subpackets, asymmetric algorithms, symmetric algorithms, AEAD algorithms, and packet tags). - See #941.
-rw-r--r--openpgp/NEWS6
-rw-r--r--openpgp/src/policy.rs166
-rw-r--r--openpgp/src/policy/cutofflist.rs12
3 files changed, 183 insertions, 1 deletions
diff --git a/openpgp/NEWS b/openpgp/NEWS
index 1ff35f6a..626e0e02 100644
--- a/openpgp/NEWS
+++ b/openpgp/NEWS
@@ -18,6 +18,12 @@
- DataFormat::variants.
- packet::Tag::variants.
- SubpacketTag::variants.
+ - StandardPolicy::reject_all_hashes
+ - StandardPolicy::reject_all_critical_subpackets
+ - StandardPolicy::reject_all_asymmetric_algos
+ - StandardPolicy::reject_all_symmetric_algos
+ - StandardPolicy::reject_all_aead_algos
+ - StandardPolicy::reject_all_packet_tags
* Changes in 1.10.0
** New functionality
- Cert::insert_packets2
diff --git a/openpgp/src/policy.rs b/openpgp/src/policy.rs
index 704a7ea8..bc9281c0 100644
--- a/openpgp/src/policy.rs
+++ b/openpgp/src/policy.rs
@@ -909,6 +909,18 @@ impl<'a> StandardPolicy<'a> {
self.second_pre_image_resistant_hash_algos.set(h, REJECT);
}
+ /// Considers all hash algorithms to be insecure.
+ ///
+ /// Causes all hash algorithms to be considered insecure in all
+ /// security contexts.
+ ///
+ /// This is useful when using a good list to determine what
+ /// algorithms are allowed.
+ pub fn reject_all_hashes(&mut self) {
+ self.collision_resistant_hash_algos.reject_all();
+ self.second_pre_image_resistant_hash_algos.reject_all();
+ }
+
/// Considers `h` to be insecure in all security contexts starting
/// at time `t`.
///
@@ -1114,6 +1126,14 @@ impl<'a> StandardPolicy<'a> {
self.critical_subpackets.set(s, REJECT);
}
+ /// Considers all critical subpackets to be insecure.
+ ///
+ /// This is useful when using a good list to determine what
+ /// critical subpackets are allowed.
+ pub fn reject_all_critical_subpackets(&mut self) {
+ self.critical_subpackets.reject_all();
+ }
+
/// Considers `s` to be insecure starting at `cutoff`.
///
/// A cutoff of `None` means that there is no cutoff and the
@@ -1153,6 +1173,14 @@ impl<'a> StandardPolicy<'a> {
self.asymmetric_algos.set(a, REJECT);
}
+ /// Considers all asymmetric algorithms to be insecure.
+ ///
+ /// This is useful when using a good list to determine what
+ /// algorithms are allowed.
+ pub fn reject_all_asymmetric_algos(&mut self) {
+ self.asymmetric_algos.reject_all();
+ }
+
/// Considers `a` to be insecure starting at `cutoff`.
///
/// A cutoff of `None` means that there is no cutoff and the
@@ -1188,6 +1216,14 @@ impl<'a> StandardPolicy<'a> {
self.symmetric_algos.set(s, REJECT);
}
+ /// Considers all symmetric algorithms to be insecure.
+ ///
+ /// This is useful when using a good list to determine what
+ /// algorithms are allowed.
+ pub fn reject_all_symmetric_algos(&mut self) {
+ self.symmetric_algos.reject_all();
+ }
+
/// Considers `s` to be insecure starting at `cutoff`.
///
/// A cutoff of `None` means that there is no cutoff and the
@@ -1233,6 +1269,14 @@ impl<'a> StandardPolicy<'a> {
self.aead_algos.set(a, REJECT);
}
+ /// Considers all AEAD algorithms to be insecure.
+ ///
+ /// This is useful when using a good list to determine what
+ /// algorithms are allowed.
+ pub fn reject_all_aead_algos(&mut self) {
+ self.aead_algos.reject_all();
+ }
+
/// Considers `a` to be insecure starting at `cutoff`.
///
/// A cutoff of `None` means that there is no cutoff and the
@@ -1268,6 +1312,14 @@ impl<'a> StandardPolicy<'a> {
self.packet_tags.set(tag, REJECT);
}
+ /// Considers all packets to be insecure.
+ ///
+ /// This is useful when using a good list to determine what
+ /// packets are allowed.
+ pub fn reject_all_packet_tags(&mut self) {
+ self.packet_tags.reject_all();
+ }
+
/// Start rejecting packets with the given tag at `t`.
///
/// A cutoff of `None` means that there is no cutoff and the
@@ -2733,4 +2785,118 @@ mod test {
assert_eq!(cert.with_policy(p, t).unwrap().keys().count(), 1);
Ok(())
}
+
+ #[test]
+ fn reject_all_hashes() -> Result<()> {
+ let mut p = StandardPolicy::new();
+
+ let set_variants = [
+ HashAlgorithm::MD5,
+ HashAlgorithm::Unknown(234),
+ ];
+ let check_variants = [
+ HashAlgorithm::SHA512,
+ HashAlgorithm::Unknown(239),
+ ];
+
+ // Accept a few hashes explicitly.
+ for v in set_variants.iter().cloned() {
+ p.accept_hash(v);
+ assert_eq!(
+ p.hash_cutoff(
+ v,
+ HashAlgoSecurity::SecondPreImageResistance),
+ ACCEPT.map(Into::into));
+ assert_eq!(
+ p.hash_cutoff(
+ v,
+ HashAlgoSecurity::CollisionResistance),
+ ACCEPT.map(Into::into));
+ }
+
+ // Reject all hashes.
+ p.reject_all_hashes();
+
+ for v in set_variants.iter().chain(check_variants.iter()).cloned() {
+ p.accept_hash(v);
+ assert_eq!(
+ p.hash_cutoff(
+ v,
+ HashAlgoSecurity::SecondPreImageResistance),
+ ACCEPT.map(Into::into));
+ assert_eq!(
+ p.hash_cutoff(
+ v,
+ HashAlgoSecurity::CollisionResistance),
+ ACCEPT.map(Into::into));
+ }
+
+ Ok(())
+ }
+
+ macro_rules! reject_all_check {
+ ($reject_all:ident, $accept_one:ident, $cutoff:ident,
+ $set_variants:expr, $check_variants:expr) => {
+ #[test]
+ fn $reject_all() -> Result<()> {
+ let mut p = StandardPolicy::new();
+
+ // Accept a few hashes explicitly.
+ for v in $set_variants.iter().cloned() {
+ p.$accept_one(v);
+ assert_eq!(p.$cutoff(v), ACCEPT.map(Into::into));
+ }
+
+ // Reject all hashes.
+ p.$reject_all();
+
+ for v in $set_variants.iter()
+ .chain($check_variants.iter()).cloned()
+ {
+ assert_eq!(
+ p.$cutoff(v),
+ REJECT.map(Into::into));
+ }
+ Ok(())
+ }
+ }
+ }
+
+ reject_all_check!(reject_all_critical_subpackets,
+ accept_critical_subpacket,
+ critical_subpacket_cutoff,
+ &[ SubpacketTag::TrustSignature,
+ SubpacketTag::Unknown(252) ],
+ &[ SubpacketTag::Unknown(253),
+ SubpacketTag::SignatureCreationTime ]);
+
+ reject_all_check!(reject_all_asymmetric_algos,
+ accept_asymmetric_algo,
+ asymmetric_algo_cutoff,
+ &[ AsymmetricAlgorithm::RSA3072,
+ AsymmetricAlgorithm::Cv25519 ],
+ &[ AsymmetricAlgorithm::Unknown,
+ AsymmetricAlgorithm::NistP256 ]);
+
+ reject_all_check!(reject_all_symmetric_algos,
+ accept_symmetric_algo,
+ symmetric_algo_cutoff,
+ &[ SymmetricAlgorithm::Unencrypted,
+ SymmetricAlgorithm::Unknown(252) ],
+ &[ SymmetricAlgorithm::AES256,
+ SymmetricAlgorithm::Unknown(230) ]);
+
+ reject_all_check!(reject_all_aead_algos,
+ accept_aead_algo,
+ aead_algo_cutoff,
+ &[ AEADAlgorithm::OCB ],
+ &[ AEADAlgorithm::EAX ]);
+
+ reject_all_check!(reject_all_packet_tags,
+ accept_packet_tag,
+ packet_tag_cutoff,
+ &[ Tag::SEIP,
+ Tag::Unknown(252) ],
+ &[ Tag::Signature,
+ Tag::Unknown(230) ]);
}
diff --git a/openpgp/src/policy/cutofflist.rs b/openpgp/src/policy/cutofflist.rs
index d21d83a5..d745ae7d 100644
--- a/openpgp/src/policy/cutofflist.rs
+++ b/openpgp/src/policy/cutofflist.rs
@@ -120,7 +120,7 @@ impl<A> Default for CutoffList<A> {
impl<A> CutoffList<A> {
// Rejects all algorithms.
- const fn reject_all() -> Self {
+ pub(super) const fn reject_all() -> Self {
Self {
cutoffs: VecOrSlice::empty(),
_a: std::marker::PhantomData,
@@ -192,6 +192,7 @@ macro_rules! a_cutoff_list {
Custom(CutoffList<$algo>),
}
+ #[allow(unused)]
impl $name {
const DEFAULTS : [ Option<Timestamp>; $values_count ] = $values;
@@ -217,6 +218,15 @@ macro_rules! a_cutoff_list {
self.force().set(a, cutoff)
}
+ // Reset the cutoff list to its defaults.
+ fn defaults(&mut self) {
+ *self = Self::Default();
+ }
+
+ fn reject_all(&mut self) {
+ *self = Self::Custom(CutoffList::reject_all());
+ }
+
fn cutoff(&self, a: $algo) -> Option<Timestamp> {
use crate::policy::cutofflist::DEFAULT_POLICY;