diff options
-rw-r--r-- | openpgp/NEWS | 6 | ||||
-rw-r--r-- | openpgp/src/cert.rs | 15 | ||||
-rw-r--r-- | openpgp/src/cert/amalgamation/key.rs | 60 |
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 |