summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2023-08-22 10:14:47 +0200
committerJustus Winter <justus@sequoia-pgp.org>2024-03-13 10:59:08 +0100
commitf92e298f9ac1785d29e93d86ce0aba51b250433e (patch)
tree7c6cd23152b1da3ee00437775683b7b4632a4fe5
parentee37f1d7ff2747e799064e07f859f30942ec8e06 (diff)
openpgp: Implement the PreferredAEADCiphersuites subpacket.
-rw-r--r--openpgp/examples/statistics.rs23
-rw-r--r--openpgp/src/cert.rs27
-rw-r--r--openpgp/src/cert/amalgamation.rs7
-rw-r--r--openpgp/src/packet/signature.rs1
-rw-r--r--openpgp/src/packet/signature/subpacket.rs113
-rw-r--r--openpgp/src/parse.rs15
-rw-r--r--openpgp/src/serialize.rs7
7 files changed, 159 insertions, 34 deletions
diff --git a/openpgp/examples/statistics.rs b/openpgp/examples/statistics.rs
index 4382a924..48a16dbf 100644
--- a/openpgp/examples/statistics.rs
+++ b/openpgp/examples/statistics.rs
@@ -69,6 +69,8 @@ fn main() -> openpgp::Result<()> {
Default::default();
let mut p_comp: HashMap<Vec<CompressionAlgorithm>, usize> =
Default::default();
+ let mut p_aead_ciphersuites: HashMap<Vec<(SymmetricAlgorithm, AEADAlgorithm)>, usize> =
+ Default::default();
let mut p_aead: HashMap<Vec<AEADAlgorithm>, usize> =
Default::default();
@@ -210,6 +212,13 @@ fn main() -> openpgp::Result<()> {
} else {
p_comp.insert(a.clone(), 1);
},
+ SubpacketValue::PreferredAEADCiphersuites(a)
+ =>
+ if let Some(count) = p_aead_ciphersuites.get_mut(a) {
+ *count += 1;
+ } else {
+ p_aead_ciphersuites.insert(a.clone(), 1);
+ },
SubpacketValue::PreferredAEADAlgorithms(a)
=>
if let Some(count) = p_aead.get_mut(a) {
@@ -528,6 +537,20 @@ fn main() -> openpgp::Result<()> {
}
}
+ if !p_aead_ciphersuites.is_empty() {
+ println!();
+ println!("# PreferredAEADCiphersuites statistics");
+ println!();
+ println!("{:>70} {:>9}", "", "count",);
+ println!("----------------------------------------\
+ ----------------------------------------");
+
+ for (a, n) in p_aead_ciphersuites.iter() {
+ let a = format!("{:?}", a);
+ println!("{:>70} {:>9}", &a[1..a.len()-1], n);
+ }
+ }
+
if !p_aead.is_empty() {
println!();
println!("# PreferredAEADAlgorithms statistics");
diff --git a/openpgp/src/cert.rs b/openpgp/src/cert.rs
index b35fd7eb..acb4e7ab 100644
--- a/openpgp/src/cert.rs
+++ b/openpgp/src/cert.rs
@@ -472,6 +472,14 @@ pub trait Preferences<'a>: seal::Sealed {
fn preferred_compression_algorithms(&self)
-> Option<&'a [CompressionAlgorithm]>;
+ /// Returns the supported AEAD ciphersuites ordered by preference.
+ ///
+ /// The algorithms are ordered according by the certificate holder's
+ /// preference.
+ fn preferred_aead_ciphersuites(
+ &self)
+ -> Option<&'a [(SymmetricAlgorithm, AEADAlgorithm)]>;
+
/// Returns the supported AEAD algorithms ordered by preference.
///
/// The algorithms are ordered according by the certificate holder's
@@ -4465,6 +4473,7 @@ impl<'a> 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_ciphersuites, &'a [(SymmetricAlgorithm, AEADAlgorithm)]);
impl_pref!(preferred_aead_algorithms, &'a [AEADAlgorithm]);
impl_pref!(key_server_preferences, KeyServerPreferences);
impl_pref!(preferred_key_server, &'a [u8]);
@@ -6752,9 +6761,7 @@ Pu1xwz57O4zo1VYf6TqHJzVC3OMvMUM2hhdecMUe5x6GorNaj6g=
assert_eq!(userid.preferred_compression_algorithms(),
Some(&[ Zlib, BZip2, Zip ][..]));
- #[allow(deprecated)] {
- assert_eq!(userid.preferred_aead_algorithms(), None);
- }
+ assert_eq!(userid.preferred_aead_ciphersuites(), None);
// assert_eq!(userid.key_server_preferences(),
// Some(KeyServerPreferences::new(&[])));
@@ -6783,9 +6790,7 @@ Pu1xwz57O4zo1VYf6TqHJzVC3OMvMUM2hhdecMUe5x6GorNaj6g=
assert_eq!(userid.preferred_compression_algorithms(),
Some(&[ Zlib, BZip2, Zip ][..]));
- #[allow(deprecated)] {
- assert_eq!(userid.preferred_aead_algorithms(), None);
- }
+ assert_eq!(userid.preferred_aead_ciphersuites(), None);
assert_eq!(userid.key_server_preferences(),
Some(KeyServerPreferences::new(&[0x80])));
@@ -6803,10 +6808,8 @@ Pu1xwz57O4zo1VYf6TqHJzVC3OMvMUM2hhdecMUe5x6GorNaj6g=
cert.preferred_hash_algorithms());
assert_eq!(userid.preferred_compression_algorithms(),
cert.preferred_compression_algorithms());
- #[allow(deprecated)] {
- assert_eq!(userid.preferred_aead_algorithms(),
- cert.preferred_aead_algorithms());
- }
+ assert_eq!(userid.preferred_aead_ciphersuites(),
+ cert.preferred_aead_ciphersuites());
assert_eq!(userid.key_server_preferences(),
cert.key_server_preferences());
assert_eq!(userid.features(),
@@ -6833,9 +6836,7 @@ Pu1xwz57O4zo1VYf6TqHJzVC3OMvMUM2hhdecMUe5x6GorNaj6g=
assert_eq!(userid.preferred_compression_algorithms(),
Some(&[ BZip2, Zlib, Zip ][..]));
- #[allow(deprecated)] {
- assert_eq!(userid.preferred_aead_algorithms(), None);
- }
+ assert_eq!(userid.preferred_aead_ciphersuites(), None);
assert_eq!(userid.key_server_preferences(),
Some(KeyServerPreferences::new(&[0x80])));
diff --git a/openpgp/src/cert/amalgamation.rs b/openpgp/src/cert/amalgamation.rs
index a36699aa..9548bd11 100644
--- a/openpgp/src/cert/amalgamation.rs
+++ b/openpgp/src/cert/amalgamation.rs
@@ -2303,6 +2303,13 @@ impl<'a, C> crate::cert::Preferences<'a>
self.map(|s| s.preferred_compression_algorithms())
}
+ fn preferred_aead_ciphersuites(
+ &self)
+ -> Option<&'a [(SymmetricAlgorithm, AEADAlgorithm)]>
+ {
+ self.map(|s| s.preferred_aead_ciphersuites())
+ }
+
fn preferred_aead_algorithms(&self) -> Option<&'a [AEADAlgorithm]> {
#[allow(deprecated)]
self.map(|s| s.preferred_aead_algorithms())
diff --git a/openpgp/src/packet/signature.rs b/openpgp/src/packet/signature.rs
index 41f56453..e3e58f88 100644
--- a/openpgp/src/packet/signature.rs
+++ b/openpgp/src/packet/signature.rs
@@ -2569,6 +2569,7 @@ impl crate::packet::Signature {
| PreferredAEADAlgorithms
| IntendedRecipient
| AttestedCertifications
+ | PreferredAEADCiphersuites
| Reserved(_)
=> false,
Issuer
diff --git a/openpgp/src/packet/signature/subpacket.rs b/openpgp/src/packet/signature/subpacket.rs
index 79b61fdd..9be2842c 100644
--- a/openpgp/src/packet/signature/subpacket.rs
+++ b/openpgp/src/packet/signature/subpacket.rs
@@ -325,6 +325,27 @@ pub enum SubpacketTag {
///
/// [Section 5.2.3.30 of RFC 4880bis]: https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-10.html#section-5.2.3.30
AttestedCertifications,
+
+ /// The AEAD Ciphersuites that the certificate holder prefers.
+ ///
+ /// A series of paired algorithm identifiers indicating how the
+ /// keyholder prefers to receive version 2 Symmetrically Encrypted
+ /// Integrity Protected Data. Each pair of octets indicates a
+ /// combination of a symmetric cipher and an AEAD mode that the
+ /// key holder prefers to use.
+ ///
+ /// It is assumed that only the combinations of algorithms listed
+ /// are supported by the recipient's software, with the exception
+ /// of the mandatory-to-implement combination of AES-128 and OCB.
+ /// If AES-128 and OCB are not found in the subpacket, it is
+ /// implicitly listed at the end.
+ ///
+ /// See [Section 5.2.3.15 of draft-ietf-openpgp-crypto-refresh-10]
+ /// for details.
+ ///
+ /// [Section 5.2.3.15 of draft-ietf-openpgp-crypto-refresh-10]: https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-preferred-aead-ciphersuites
+ PreferredAEADCiphersuites,
+
/// Reserved subpacket tag.
Reserved(u8),
/// Private subpacket tag.
@@ -375,6 +396,7 @@ impl From<u8> for SubpacketTag {
34 => SubpacketTag::PreferredAEADAlgorithms,
35 => SubpacketTag::IntendedRecipient,
37 => SubpacketTag::AttestedCertifications,
+ 39 => SubpacketTag::PreferredAEADCiphersuites,
0| 1| 8| 13| 14| 15| 17| 18| 19 | 38 => SubpacketTag::Reserved(u),
100..=110 => SubpacketTag::Private(u),
_ => SubpacketTag::Unknown(u),
@@ -414,6 +436,7 @@ impl From<SubpacketTag> for u8 {
SubpacketTag::PreferredAEADAlgorithms => 34,
SubpacketTag::IntendedRecipient => 35,
SubpacketTag::AttestedCertifications => 37,
+ SubpacketTag::PreferredAEADCiphersuites => 39,
SubpacketTag::Reserved(u) => u,
SubpacketTag::Private(u) => u,
SubpacketTag::Unknown(u) => u,
@@ -422,7 +445,7 @@ impl From<SubpacketTag> for u8 {
}
#[allow(deprecated)]
-const SUBPACKET_TAG_VARIANTS: [SubpacketTag; 28] = [
+const SUBPACKET_TAG_VARIANTS: [SubpacketTag; 29] = [
SubpacketTag::SignatureCreationTime,
SubpacketTag::SignatureExpirationTime,
SubpacketTag::ExportableCertification,
@@ -451,6 +474,7 @@ const SUBPACKET_TAG_VARIANTS: [SubpacketTag; 28] = [
SubpacketTag::PreferredAEADAlgorithms,
SubpacketTag::IntendedRecipient,
SubpacketTag::AttestedCertifications,
+ SubpacketTag::PreferredAEADCiphersuites,
];
impl SubpacketTag {
@@ -1687,6 +1711,26 @@ pub enum SubpacketValue {
///
/// [Section 5.2.3.30 of RFC 4880bis]: https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-10.html#section-5.2.3.30
AttestedCertifications(Vec<Box<[u8]>>),
+
+ /// The AEAD Ciphersuites that the certificate holder prefers.
+ ///
+ /// A series of paired algorithm identifiers indicating how the
+ /// keyholder prefers to receive version 2 Symmetrically Encrypted
+ /// Integrity Protected Data. Each pair of octets indicates a
+ /// combination of a symmetric cipher and an AEAD mode that the
+ /// key holder prefers to use.
+ ///
+ /// It is assumed that only the combinations of algorithms listed
+ /// are supported by the recipient's software, with the exception
+ /// of the mandatory-to-implement combination of AES-128 and OCB.
+ /// If AES-128 and OCB are not found in the subpacket, it is
+ /// implicitly listed at the end.
+ ///
+ /// See [Section 5.2.3.15 of draft-ietf-openpgp-crypto-refresh-10]
+ /// for details.
+ ///
+ /// [Section 5.2.3.15 of draft-ietf-openpgp-crypto-refresh-10]: https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-preferred-aead-ciphersuites
+ PreferredAEADCiphersuites(Vec<(SymmetricAlgorithm, AEADAlgorithm)>),
}
assert_send_and_sync!(SubpacketValue);
@@ -1698,7 +1742,7 @@ impl ArbitraryBounded for SubpacketValue {
loop {
#[allow(deprecated)]
- break match gen_arbitrary_from_range(0..26, g) {
+ break match gen_arbitrary_from_range(0..27, g) {
0 => SignatureCreationTime(Arbitrary::arbitrary(g)),
1 => SignatureExpirationTime(Arbitrary::arbitrary(g)),
2 => ExportableCertification(Arbitrary::arbitrary(g)),
@@ -1737,6 +1781,7 @@ impl ArbitraryBounded for SubpacketValue {
23 => IssuerFingerprint(Arbitrary::arbitrary(g)),
24 => PreferredAEADAlgorithms(Arbitrary::arbitrary(g)),
25 => IntendedRecipient(Arbitrary::arbitrary(g)),
+ 26 => PreferredAEADCiphersuites(Arbitrary::arbitrary(g)),
_ => unreachable!(),
}
}
@@ -1785,6 +1830,8 @@ impl SubpacketValue {
SubpacketTag::PreferredAEADAlgorithms,
IntendedRecipient(_) => SubpacketTag::IntendedRecipient,
AttestedCertifications(_) => SubpacketTag::AttestedCertifications,
+ PreferredAEADCiphersuites(_) =>
+ SubpacketTag::PreferredAEADCiphersuites,
Unknown { tag, .. } => *tag,
}
}
@@ -3259,18 +3306,16 @@ impl SubpacketAreas {
}
}
- /// Returns the value of the Preferred AEAD Algorithms subpacket.
+ /// Returns the value of the Preferred AEAD Ciphersuites subpacket.
///
- /// The [Preferred AEAD Algorithms subpacket] indicates what AEAD
- /// algorithms the key holder prefers ordered by preference. If
- /// this is set, then the AEAD feature flag should in the
+ /// The [Preferred AEAD Ciphersuites subpacket] indicates what
+ /// AEAD ciphersuites (i.e. pairs of symmetric algorithm and AEAD
+ /// algorithm) the key holder prefers ordered by preference. If
+ /// this is set, then the SEIPDv2 feature flag should in the
/// [Features subpacket] should also be set.
///
- /// Note: because support for AEAD has not yet been standardized,
- /// we recommend not yet advertising support for it.
- ///
- /// [Preferred AEAD Algorithms subpacket]: https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-09.html#section-5.2.3.8
- /// [Features subpacket]: https://tools.ietf.org/html/draft-ietf-openpgp-rfc4880bis-09.html#section-5.2.3.25
+ /// [Preferred AEAD Ciphersuites subpacket]: https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#name-preferred-aead-ciphersuites
+ /// [Features subpacket]: https://www.ietf.org/archive/id/draft-ietf-openpgp-crypto-refresh-10.html#features-subpacket
///
/// This subpacket is a type of preference. When looking up a
/// preference, an OpenPGP implementation should first look for
@@ -3294,7 +3339,25 @@ impl SubpacketAreas {
/// Note: if the signature contains multiple instances of this
/// subpacket in the hashed subpacket area, the last one is
/// returned.
- #[deprecated]
+ pub fn preferred_aead_ciphersuites(&self)
+ -> Option<&[(SymmetricAlgorithm, AEADAlgorithm)]>
+ {
+ if let Some(sb) = self.subpacket(
+ SubpacketTag::PreferredAEADCiphersuites)
+ {
+ if let SubpacketValue::PreferredAEADCiphersuites(v)
+ = &sb.value
+ {
+ Some(v)
+ } else {
+ None
+ }
+ } else {
+ None
+ }
+ }
+
+ /// Returns the value of the Preferred AEAD Algorithms subpacket.
pub fn preferred_aead_algorithms(&self)
-> Option<&[AEADAlgorithm]> {
// array of one-octet values
@@ -6954,7 +7017,19 @@ impl signature::SignatureBuilder {
/// # Ok(())
/// # }
/// ```
- #[deprecated]
+ pub fn set_preferred_aead_ciphersuites(
+ mut self,
+ preferences: Vec<(SymmetricAlgorithm, AEADAlgorithm)>)
+ -> Result<Self>
+ {
+ self.hashed_area.replace(Subpacket::new(
+ SubpacketValue::PreferredAEADCiphersuites(preferences),
+ false)?)?;
+
+ Ok(self)
+ }
+
+ /// Sets the Preferred AEAD Algorithms subpacket.
pub fn set_preferred_aead_algorithms(mut self,
preferences: Vec<AEADAlgorithm>)
-> Result<Self>
@@ -7397,16 +7472,12 @@ fn accessors() {
assert_eq!(sig_.issuer_fingerprints().collect::<Vec<_>>(),
vec![ &fp ]);
- let pref = vec![AEADAlgorithm::EAX,
- AEADAlgorithm::OCB];
- #[allow(deprecated)] {
- sig = sig.set_preferred_aead_algorithms(pref.clone()).unwrap();
- }
+ let pref = vec![(SymmetricAlgorithm::AES128, AEADAlgorithm::EAX),
+ (SymmetricAlgorithm::AES128, AEADAlgorithm::OCB)];
+ sig = sig.set_preferred_aead_ciphersuites(pref.clone()).unwrap();
let sig_ =
sig.clone().sign_hash(&mut keypair, hash.clone()).unwrap();
- #[allow(deprecated)] {
- assert_eq!(sig_.preferred_aead_algorithms(), Some(&pref[..]));
- }
+ assert_eq!(sig_.preferred_aead_ciphersuites(), Some(&pref[..]));
let fps = vec![
Fingerprint::from_bytes(b"aaaaaaaaaaaaaaaaaaaa"),
diff --git a/openpgp/src/parse.rs b/openpgp/src/parse.rs
index 05598ea7..f7daffe7 100644
--- a/openpgp/src/parse.rs
+++ b/openpgp/src/parse.rs
@@ -1859,6 +1859,21 @@ impl Subpacket {
bytes.chunks(digest_size).map(Into::into).collect())
}
},
+
+ SubpacketTag::PreferredAEADCiphersuites => {
+ if len % 2 != 0 {
+ return Err(Error::BadSignature(
+ "Wrong number of bytes in preferred AEAD \
+ Ciphersuites subpacket"
+ .into()).into());
+ }
+
+ SubpacketValue::PreferredAEADCiphersuites(
+ php.parse_bytes("pref aead ciphersuites", len)?
+ .chunks(2).map(|o| (o[0].into(),
+ o[1].into())).collect())
+ },
+
SubpacketTag::Reserved(_)
| SubpacketTag::PlaceholderForBackwardCompatibility
| SubpacketTag::Private(_)
diff --git a/openpgp/src/serialize.rs b/openpgp/src/serialize.rs
index 1bdd062f..a45e84dc 100644
--- a/openpgp/src/serialize.rs
+++ b/openpgp/src/serialize.rs
@@ -1527,6 +1527,12 @@ impl Marshal for SubpacketValue {
o.write_all(digest)?;
}
},
+
+ PreferredAEADCiphersuites(p) =>
+ for (symm, aead) in p {
+ o.write_all(&[(*symm).into(), (*aead).into()])?;
+ },
+
Unknown { body, .. } =>
o.write_all(body)?,
}
@@ -1569,6 +1575,7 @@ impl MarshalInto for SubpacketValue {
1 + (fp as &dyn MarshalInto).serialized_len(),
AttestedCertifications(digests) =>
digests.iter().map(|d| d.len()).sum(),
+ PreferredAEADCiphersuites(c) => c.len() * 2,
Unknown { body, .. } => body.len(),
}
}