summaryrefslogtreecommitdiffstats
path: root/openpgp
diff options
context:
space:
mode:
authorJustus Winter <justus@sequoia-pgp.org>2023-07-07 13:57:59 +0200
committerJustus Winter <justus@sequoia-pgp.org>2023-07-07 15:22:03 +0200
commit9e48a064e55e5ee61bc8caf6d7d0979c398aa4cd (patch)
tree2acfa90127206209d1ce574a97838adcb5f88b00 /openpgp
parenta9c4715115ceaf766b277cc89bcda52f42cb0b75 (diff)
openpgp: Better support early v4 certificates.
- If there is no key flags subpacket. Match on the key role and algorithm and synthesize one. We do this to better support very early v4 certificates, where either the binding signature is a v3 signature and cannot contain subpackets, or it is a v4 signature, but the key's capabilities were implied by the public key algorithm. - We only match on public key algorithms used at the time.
Diffstat (limited to 'openpgp')
-rw-r--r--openpgp/NEWS6
-rw-r--r--openpgp/src/cert.rs15
-rw-r--r--openpgp/src/cert/amalgamation/key.rs60
3 files changed, 79 insertions, 2 deletions
diff --git a/openpgp/NEWS b/openpgp/NEWS
index ba31c24e..cd56b1b7 100644
--- a/openpgp/NEWS
+++ b/openpgp/NEWS
@@ -8,6 +8,7 @@
- Sequoia now ignores some formatting errors when reading secret
keys. Being lenient in this case helps the user recover their
valuable key material.
+
- Previously, Sequoia would buffer packet bodies when mapping is
enabled in the parser, even if the packet parser is not
configured to buffer the bodies. This adds considerable
@@ -21,6 +22,11 @@
body in the map, but changes the default behavior. If you need
the old behavior, please do adjust your code to buffer unread
content.
+
+ - To increase compatibility with early v4 certificates, if there is
+ no key flags subpacket on either the active binding signature or
+ the active direct key signature, we infer the key flags from the
+ key's role and public key algorithm.
** New functionality
- crypto::SessionKey::as_protected
- types::AEADAlgorithm::GCM
diff --git a/openpgp/src/cert.rs b/openpgp/src/cert.rs
index 0170b0e8..f1f233da 100644
--- a/openpgp/src/cert.rs
+++ b/openpgp/src/cert.rs
@@ -7267,12 +7267,23 @@ Pu1xwz57O4zo1VYf6TqHJzVC3OMvMUM2hhdecMUe5x6GorNaj6g=
let vcert = c.with_policy(&np, None)?;
assert_eq!(vcert.keys().subkeys().count(), 1);
- // XXX: Unfortunately, it being a v3 signature, the subkey has
- // no keyflags, limiting its usefulness for now.
+ // A v3 signature has no subpackets, so there are no key
+ // flags. But, we then consider the key role and public key
+ // algorithm.
+ assert_eq!(vcert.keys().for_signing().count(), 1);
+ assert_eq!(vcert.keys().for_transport_encryption().count(), 1);
// The subkey is interesting because it is bound using a v3
// signature.
assert_eq!(c.keys().subkeys().with_policy(&np, None).count(), 1);
+
+ // A v3 signature has no subpackets, so there are no key
+ // flags. But, we then consider the key role and public key
+ // algorithm.
+ assert_eq!(c.keys().with_policy(&np, None).for_signing().count(), 1);
+ assert_eq!(c.keys().with_policy(&np, None)
+ .for_transport_encryption().count(), 1);
+
Ok(())
}
}
diff --git a/openpgp/src/cert/amalgamation/key.rs b/openpgp/src/cert/amalgamation/key.rs
index fb6ce57b..f04010a4 100644
--- a/openpgp/src/cert/amalgamation/key.rs
+++ b/openpgp/src/cert/amalgamation/key.rs
@@ -1874,6 +1874,11 @@ impl<'a, P, R, R2> ValidKeyAmalgamation<'a, P, R, R2>
/// a key's flags may change depending on the policy and the
/// reference time.
///
+ /// To increase compatibility with early v4 certificates, if there
+ /// is no key flags subpacket on the considered signatures, we
+ /// infer the key flags from the key's role and public key
+ /// algorithm.
+ ///
/// [`Key Flags`]: https://tools.ietf.org/html/rfc4880#section-5.2.3.21
/// [SSS]: https://de.wikipedia.org/wiki/Shamir%E2%80%99s_Secret_Sharing
/// [Section 5.2.3.3 of RFC 4880]: https://tools.ietf.org/html/rfc4880#section-5.2.3.3
@@ -1898,6 +1903,61 @@ impl<'a, P, R, R2> ValidKeyAmalgamation<'a, P, R, R2>
/// ```
pub fn key_flags(&self) -> Option<KeyFlags> {
self.map(|s| s.key_flags())
+ .or_else(|| {
+ // There is no key flags subpacket. Match on the key
+ // role and algorithm and synthesize one. We do this
+ // to better support very early v4 certificates, where
+ // either the binding signature is a v3 signature and
+ // cannot contain subpackets, or it is a v4 signature,
+ // but the key's capabilities were implied by the
+ // public key algorithm.
+ use crate::types::PublicKeyAlgorithm;
+
+ // XXX: We cannot know whether this is a primary key
+ // or not because of
+ // https://gitlab.com/sequoia-pgp/sequoia/-/issues/1036
+ let is_primary = false;
+
+ // We only match on public key algorithms used at the
+ // time.
+ #[allow(deprecated)]
+ match (is_primary, self.key().pk_algo()) {
+ (true, PublicKeyAlgorithm::RSAEncryptSign) =>
+ Some(KeyFlags::empty()
+ .set_certification()
+ .set_transport_encryption()
+ .set_storage_encryption()
+ .set_signing()),
+
+ (true, _) =>
+ Some(KeyFlags::empty()
+ .set_certification()
+ .set_signing()),
+
+ (false, PublicKeyAlgorithm::RSAEncryptSign) =>
+ Some(KeyFlags::empty()
+ .set_transport_encryption()
+ .set_storage_encryption()
+ .set_signing()),
+
+ (false,
+ | PublicKeyAlgorithm::RSASign
+ | PublicKeyAlgorithm::DSA) =>
+ Some(KeyFlags::empty().set_signing()),
+
+ (false,
+ | PublicKeyAlgorithm::RSAEncrypt
+ | PublicKeyAlgorithm::ElGamalEncrypt
+ | PublicKeyAlgorithm::ElGamalEncryptSign) =>
+ Some(KeyFlags::empty()
+ .set_transport_encryption()
+ .set_storage_encryption()),
+
+ // Be conservative: newer algorithms don't get to
+ // benefit from implicit key flags.
+ (false, _) => None,
+ }
+ })
}
/// Returns whether the key has at least one of the specified key