From 049cec48539051ce4d2166d7851fbe495304d036 Mon Sep 17 00:00:00 2001 From: Joowon-Seo Date: Thu, 12 Mar 2026 22:42:02 +0900 Subject: [PATCH 1/2] EC: Validate local domain parameters in MQV key agreement Ensure static and ephemeral EC keys used during MQV initialization share the same domain parameters and fail early if they differ. Add tests for matching and mismatched curve scenarios. --- .../asymmetric/ec/KeyAgreementSpi.java | 21 +++++- .../jcajce/provider/test/AllTests.java | 1 + .../ECKeyAgreementDomainValidationTest.java | 71 +++++++++++++++++++ 3 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 prov/src/test/java/org/bouncycastle/jcajce/provider/test/ECKeyAgreementDomainValidationTest.java diff --git a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java index a7c9c3362f..04c2911ce7 100644 --- a/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java +++ b/prov/src/main/java/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyAgreementSpi.java @@ -227,7 +227,12 @@ protected void doInitFromKey(Key key, AlgorithmParameterSpec parameterSpec, Secu MQVPrivateParameters localParams = new MQVPrivateParameters(staticPrivKey, ephemPrivKey, ephemPubKey); this.parameters = staticPrivKey.getParameters(); - // TODO Validate that all the keys are using the same parameters? + validateSameDomainParameters(staticPrivKey.getParameters(), ephemPrivKey.getParameters()); + + if (ephemPubKey != null) + { + validateSameDomainParameters(staticPrivKey.getParameters(), ephemPubKey.getParameters()); + } ((ECMQVBasicAgreement)agreement).init(localParams); } @@ -286,6 +291,20 @@ private static String getSimpleName(Class clazz) return fullName.substring(fullName.lastIndexOf('.') + 1); } + + private static void validateSameDomainParameters(ECDomainParameters a, ECDomainParameters b) + throws InvalidKeyException + { + if (a == b) + { + return; + } + + if (a == null || !a.equals(b)) + { + throw new InvalidKeyException("EC domain parameters do not match"); + } + } protected byte[] doCalcSecret() { diff --git a/prov/src/test/java/org/bouncycastle/jcajce/provider/test/AllTests.java b/prov/src/test/java/org/bouncycastle/jcajce/provider/test/AllTests.java index b14545d2f2..5eeaac6a18 100644 --- a/prov/src/test/java/org/bouncycastle/jcajce/provider/test/AllTests.java +++ b/prov/src/test/java/org/bouncycastle/jcajce/provider/test/AllTests.java @@ -34,6 +34,7 @@ public static Test suite() suite.addTestSuite(BouncyCastleProviderTest.class); suite.addTestSuite(PQCSignatureTest.class); suite.addTestSuite(SecretKeyUtilTest.class); + suite.addTestSuite(ECKeyAgreementDomainValidationTest.class); return new BCTestSetup(suite); } diff --git a/prov/src/test/java/org/bouncycastle/jcajce/provider/test/ECKeyAgreementDomainValidationTest.java b/prov/src/test/java/org/bouncycastle/jcajce/provider/test/ECKeyAgreementDomainValidationTest.java new file mode 100644 index 0000000000..59822a78db --- /dev/null +++ b/prov/src/test/java/org/bouncycastle/jcajce/provider/test/ECKeyAgreementDomainValidationTest.java @@ -0,0 +1,71 @@ +package org.bouncycastle.jcajce.provider.test; + +import junit.framework.TestCase; +import org.bouncycastle.jce.provider.BouncyCastleProvider; + +import javax.crypto.KeyAgreement; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.Security; + +public class ECKeyAgreementDomainValidationTest extends TestCase { + protected void setUp() { + Security.addProvider(new BouncyCastleProvider()); + } + + protected void tearDown() { + Security.removeProvider("BC"); + } + + /** + * Same curve should succeed. + */ + public void testSameCurveAgreement() + throws Exception { + KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", "BC"); + + kpg.initialize(256); + + KeyPair kp1 = kpg.generateKeyPair(); + KeyPair kp2 = kpg.generateKeyPair(); + + KeyAgreement ka1 = KeyAgreement.getInstance("ECDH", "BC"); + KeyAgreement ka2 = KeyAgreement.getInstance("ECDH", "BC"); + + ka1.init(kp1.getPrivate()); + ka1.doPhase(kp2.getPublic(), true); + + ka2.init(kp2.getPrivate()); + ka2.doPhase(kp1.getPublic(), true); + + byte[] s1 = ka1.generateSecret(); + byte[] s2 = ka2.generateSecret(); + + assertTrue(java.util.Arrays.equals(s1, s2)); + } + + /** + * Different curves should fail due to domain parameter mismatch. + */ + public void testDifferentCurveAgreement() + throws Exception { + KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", "BC"); + + kpg.initialize(256); + KeyPair kp256 = kpg.generateKeyPair(); + + kpg.initialize(384); + KeyPair kp384 = kpg.generateKeyPair(); + + KeyAgreement ka = KeyAgreement.getInstance("ECDH", "BC"); + + try { + ka.init(kp256.getPrivate()); + ka.doPhase(kp384.getPublic(), true); + + fail("Expected InvalidKeyException for mismatched EC domain parameters"); + } catch (java.security.InvalidKeyException e) { + // expected + } + } +} \ No newline at end of file From d099604c2ada56f5f381be448e5e1bb3918725c8 Mon Sep 17 00:00:00 2001 From: Joowon-Seo Date: Thu, 12 Mar 2026 23:12:53 +0900 Subject: [PATCH 2/2] Test: Use ECGenParameterSpec for EC key generation in tests --- .../provider/test/ECKeyAgreementDomainValidationTest.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/prov/src/test/java/org/bouncycastle/jcajce/provider/test/ECKeyAgreementDomainValidationTest.java b/prov/src/test/java/org/bouncycastle/jcajce/provider/test/ECKeyAgreementDomainValidationTest.java index 59822a78db..09eab78661 100644 --- a/prov/src/test/java/org/bouncycastle/jcajce/provider/test/ECKeyAgreementDomainValidationTest.java +++ b/prov/src/test/java/org/bouncycastle/jcajce/provider/test/ECKeyAgreementDomainValidationTest.java @@ -7,6 +7,7 @@ import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.Security; +import java.security.spec.ECGenParameterSpec; public class ECKeyAgreementDomainValidationTest extends TestCase { protected void setUp() { @@ -24,7 +25,7 @@ public void testSameCurveAgreement() throws Exception { KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", "BC"); - kpg.initialize(256); + kpg.initialize(new ECGenParameterSpec("secp256r1")); KeyPair kp1 = kpg.generateKeyPair(); KeyPair kp2 = kpg.generateKeyPair(); @@ -51,10 +52,10 @@ public void testDifferentCurveAgreement() throws Exception { KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", "BC"); - kpg.initialize(256); + kpg.initialize(new ECGenParameterSpec("secp256r1")); KeyPair kp256 = kpg.generateKeyPair(); - kpg.initialize(384); + kpg.initialize(new ECGenParameterSpec("secp384r1")); KeyPair kp384 = kpg.generateKeyPair(); KeyAgreement ka = KeyAgreement.getInstance("ECDH", "BC");