From 913904754ddd585d93522bc45e8d9e830d278f9a Mon Sep 17 00:00:00 2001 From: Justus Winter Date: Wed, 1 Mar 2023 16:25:59 +0100 Subject: openpgp: Add support for brainpoolP384r1. - One of the brainpool curves was not included in our enum Curve, because at the time we implemented ECC support, it wasn't part of the RFC4880bis document. - Unfortunately, we failed to mark enum Curve as non-exhaustive, so we cannot add a variant without breaking the API. - We can, however, support the curve by matching on its OID. --- openpgp/NEWS | 3 +++ openpgp/examples/supported-algorithms.rs | 1 + openpgp/src/crypto/backend/openssl/asymmetric.rs | 6 +++++- openpgp/src/crypto/mpi.rs | 7 +++--- openpgp/src/policy.rs | 11 ++++++++-- openpgp/src/types/mod.rs | 27 +++++++++++++++++++----- 6 files changed, 44 insertions(+), 11 deletions(-) diff --git a/openpgp/NEWS b/openpgp/NEWS index 744d47c4..f0c89281 100644 --- a/openpgp/NEWS +++ b/openpgp/NEWS @@ -3,6 +3,9 @@ #+TITLE: sequoia-openpgp NEWS – history of user-visible changes #+STARTUP: content hidestars +* Changes in 1.14.0 +** New functionality + - policy::AsymmetricAlgorithm::BrainpoolP384 * Changes in 1.13.0 ** New cryptographic backends - We added a backend that uses OpenSSL. diff --git a/openpgp/examples/supported-algorithms.rs b/openpgp/examples/supported-algorithms.rs index 570cdc96..760da1f4 100644 --- a/openpgp/examples/supported-algorithms.rs +++ b/openpgp/examples/supported-algorithms.rs @@ -39,6 +39,7 @@ fn main() { Curve::NistP384, Curve::NistP521, Curve::BrainpoolP256, + Curve::Unknown([0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0B].into()), // XXX Curve::BrainpoolP512, Curve::Ed25519, Curve::Cv25519, diff --git a/openpgp/src/crypto/backend/openssl/asymmetric.rs b/openpgp/src/crypto/backend/openssl/asymmetric.rs index aef777bf..5a1dc295 100644 --- a/openpgp/src/crypto/backend/openssl/asymmetric.rs +++ b/openpgp/src/crypto/backend/openssl/asymmetric.rs @@ -70,8 +70,12 @@ impl TryFrom<&Curve> for Nid { Curve::NistP384 => Nid::SECP384R1, Curve::NistP521 => Nid::SECP521R1, Curve::BrainpoolP256 => Nid::BRAINPOOL_P256R1, + Curve::Unknown(_) if curve.is_brainpoolp384() => Nid::BRAINPOOL_P384R1, Curve::BrainpoolP512 => Nid::BRAINPOOL_P512R1, - _ => return Err(crate::Error::UnsupportedEllipticCurve(curve.clone()).into()), + Curve::Ed25519 | // Handled differently. + Curve::Cv25519 | // Handled differently. + Curve::Unknown(_) => + return Err(crate::Error::UnsupportedEllipticCurve(curve.clone()).into()), }) } } diff --git a/openpgp/src/crypto/mpi.rs b/openpgp/src/crypto/mpi.rs index e2a93992..7cc94206 100644 --- a/openpgp/src/crypto/mpi.rs +++ b/openpgp/src/crypto/mpi.rs @@ -201,10 +201,14 @@ impl MPI { Ok((&value[1..], &[])) }, + Unknown(_) if ! curve.is_brainpoolp384() => + Err(Error::UnsupportedEllipticCurve(curve.clone()).into()), + NistP256 | NistP384 | NistP521 | BrainpoolP256 + | Unknown(_) | BrainpoolP512 => { @@ -232,9 +236,6 @@ impl MPI { Ok((&value[1..1 + coordinate_length], &value[1 + coordinate_length..])) }, - - Unknown(_) => - Err(Error::UnsupportedEllipticCurve(curve.clone()).into()), } } diff --git a/openpgp/src/policy.rs b/openpgp/src/policy.rs index 542fa64f..92b08a47 100644 --- a/openpgp/src/policy.rs +++ b/openpgp/src/policy.rs @@ -700,7 +700,7 @@ a_cutoff_list!(SubpacketTagCutoffList, SubpacketTag, 38, ACCEPT, // 37. AttestedCertifications. ]); -a_cutoff_list!(AsymmetricAlgorithmCutoffList, AsymmetricAlgorithm, 18, +a_cutoff_list!(AsymmetricAlgorithmCutoffList, AsymmetricAlgorithm, 19, [ Some(Timestamp::Y2014M2), // 0. RSA1024. ACCEPT, // 1. RSA2048. @@ -720,6 +720,7 @@ a_cutoff_list!(AsymmetricAlgorithmCutoffList, AsymmetricAlgorithm, 18, ACCEPT, // 15. BrainpoolP256. ACCEPT, // 16. BrainpoolP512. ACCEPT, // 17. Cv25519. + ACCEPT, // 16. BrainpoolP384. ]); a_cutoff_list!(SymmetricAlgorithmCutoffList, SymmetricAlgorithm, 14, @@ -1560,6 +1561,8 @@ impl<'a> Policy for StandardPolicy<'a> { Curve::NistP384 => NistP384, Curve::NistP521 => NistP521, Curve::BrainpoolP256 => BrainpoolP256, + Curve::Unknown(_) if curve.is_brainpoolp384() + => BrainpoolP384, Curve::BrainpoolP512 => BrainpoolP512, Curve::Ed25519 => Cv25519, Curve::Cv25519 => Cv25519, @@ -1688,6 +1691,8 @@ pub enum AsymmetricAlgorithm { NistP521, /// brainpoolP256r1. BrainpoolP256, + /// brainpoolP384r1. + BrainpoolP384, /// brainpoolP512r1. BrainpoolP512, /// D.J. Bernstein's Curve25519. @@ -1697,7 +1702,7 @@ pub enum AsymmetricAlgorithm { } assert_send_and_sync!(AsymmetricAlgorithm); -const ASYMMETRIC_ALGORITHM_VARIANTS: [AsymmetricAlgorithm; 18] = [ +const ASYMMETRIC_ALGORITHM_VARIANTS: [AsymmetricAlgorithm; 19] = [ AsymmetricAlgorithm::RSA1024, AsymmetricAlgorithm::RSA2048, AsymmetricAlgorithm::RSA3072, @@ -1714,6 +1719,7 @@ const ASYMMETRIC_ALGORITHM_VARIANTS: [AsymmetricAlgorithm; 18] = [ AsymmetricAlgorithm::NistP384, AsymmetricAlgorithm::NistP521, AsymmetricAlgorithm::BrainpoolP256, + AsymmetricAlgorithm::BrainpoolP384, AsymmetricAlgorithm::BrainpoolP512, AsymmetricAlgorithm::Cv25519, ]; @@ -1754,6 +1760,7 @@ impl From for u8 { NistP384 => 13, NistP521 => 14, BrainpoolP256 => 15, + BrainpoolP384 => 18, BrainpoolP512 => 16, Cv25519 => 17, Unknown => 255, diff --git a/openpgp/src/types/mod.rs b/openpgp/src/types/mod.rs index 863880e5..698b65d1 100644 --- a/openpgp/src/types/mod.rs +++ b/openpgp/src/types/mod.rs @@ -365,6 +365,13 @@ pub enum Curve { /// Unknown curve. Unknown(Box<[u8]>), } +impl Curve { + /// Hack! Curve is not non-exhaustive, so we cannot easily add + /// a variant. + pub(crate) fn is_brainpoolp384(&self) -> bool { + self.oid() == BRAINPOOL_P384_OID + } +} assert_send_and_sync!(Curve); impl Curve { @@ -398,6 +405,7 @@ impl Curve { NistP384 => Some(384), NistP521 => Some(521), BrainpoolP256 => Some(256), + Unknown(_) if self.is_brainpoolp384() => Some(384), BrainpoolP512 => Some(512), Ed25519 => Some(256), Cv25519 => Some(256), @@ -455,6 +463,8 @@ impl fmt::Display for Curve { NistP384 => f.write_str("NIST curve P-384"), NistP521 => f.write_str("NIST curve P-521"), BrainpoolP256 => f.write_str("brainpoolP256r1"), + Unknown(_) if self.is_brainpoolp384() => + f.write_str("brainpoolP384r1"), BrainpoolP512 => f.write_str("brainpoolP512r1"), Ed25519 => f.write_str("D.J. Bernstein's \"Twisted\" Edwards curve Ed25519"), @@ -469,6 +479,8 @@ impl fmt::Display for Curve { NistP384 => f.write_str("NIST P-384"), NistP521 => f.write_str("NIST P-521"), BrainpoolP256 => f.write_str("brainpoolP256r1"), + Unknown(_) if self.is_brainpoolp384() => + f.write_str("brainpoolP384r1"), BrainpoolP512 => f.write_str("brainpoolP512r1"), Ed25519 => f.write_str("Ed25519"), @@ -486,6 +498,8 @@ const NIST_P384_OID: &[u8] = &[0x2B, 0x81, 0x04, 0x00, 0x22]; const NIST_P521_OID: &[u8] = &[0x2B, 0x81, 0x04, 0x00, 0x23]; const BRAINPOOL_P256_OID: &[u8] = &[0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x07]; +const BRAINPOOL_P384_OID: &[u8] = + &[0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0B]; const BRAINPOOL_P512_OID: &[u8] = &[0x2B, 0x24, 0x03, 0x03, 0x02, 0x08, 0x01, 0x01, 0x0D]; const ED25519_OID: &[u8] = @@ -513,6 +527,7 @@ impl Curve { NIST_P384_OID => Curve::NistP384, NIST_P521_OID => Curve::NistP521, BRAINPOOL_P256_OID => Curve::BrainpoolP256, + BRAINPOOL_P384_OID => Curve::Unknown(BRAINPOOL_P384_OID.into()), BRAINPOOL_P512_OID => Curve::BrainpoolP512, ED25519_OID => Curve::Ed25519, CV25519_OID => Curve::Cv25519, @@ -568,6 +583,7 @@ impl Curve { Curve::NistP384 => Ok(384), Curve::NistP521 => Ok(521), Curve::BrainpoolP256 => Ok(256), + Curve::Unknown(_) if self.is_brainpoolp384() => Ok(384), Curve::BrainpoolP512 => Ok(512), Curve::Ed25519 => Ok(256), Curve::Cv25519 => Ok(256), @@ -596,15 +612,16 @@ impl Curve { #[cfg(test)] impl Arbitrary for Curve { fn arbitrary(g: &mut Gen) -> Self { - match u8::arbitrary(g) % 8 { + match u8::arbitrary(g) % 9 { 0 => Curve::NistP256, 1 => Curve::NistP384, 2 => Curve::NistP521, 3 => Curve::BrainpoolP256, - 4 => Curve::BrainpoolP512, - 5 => Curve::Ed25519, - 6 => Curve::Cv25519, - 7 => Curve::Unknown({ + 4 => Curve::Unknown(BRAINPOOL_P384_OID.into()), + 5 => Curve::BrainpoolP512, + 6 => Curve::Ed25519, + 7 => Curve::Cv25519, + 8 => Curve::Unknown({ let mut k = >::arbitrary(g); k.truncate(255); k.into_boxed_slice() -- cgit v1.2.3