CVE-2017-12974 (published 2017-08-20T16:29Z)

Nimbus JOSE+JWT before 4.36 proceeds with ECKey construction without ensuring that the public x and y coordinates are on the specified curve, which allows attackers to conduct an Invalid Curve Attack in environments where the JCE provider lacks the applicable curve validation.

Severity: MEDIUM
CVSS v2 base score: 5.0 (AV:N/AC:L/Au:N/C:P/I:N/A:N)
CVSS v3 base score: 7.5, HIGH (CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N)

Weakness information:
cwe_id: CWE-347
cwe_name: Improper Verification of Cryptographic Signature
description: The product does not verify, or incorrectly verifies, the cryptographic signature for data.
extended_description: 
            
            
         
         

Fix information:
repo_url: https://bitbucket.org/connect2id/nimbus-jose-jwt
commit_details: repo_url: https://bitbucket.org/connect2id/nimbus-jose-jwt
author: Vladimir Dzhuvinov
author_date: 2017-04-13 12:26:07+03:00
msg: Adds EC JWK constructor checks for x and y being on crv (iss #217)
repository: repo_url: https://bitbucket.org/connect2id/nimbus-jose-jwt
repo_name: visit repo url
description: visit repo url
repo_language: visit repo url
owner: connect2id
file_changes: filename: CHANGELOG.txt
change_type: ModificationType.MODIFY
diff: @@ -687,3 +687,9 @@ version 4.35 (2017-04-09)
     * Refines exception messages of DefaultJOSEProcessor and
       DefaultJWTProcessor.
 
+version 4.36 (2017-04-13)
+    * Adds a check at ECKey construction time to ensure the public 'x' and 'y'
+      coordinates are on the specified curve (iss #217).
+    * Adds a new ECDSAProvider.supportedECDSAAlgorithm() method that returns
+      the name of the supported ECDSA algorithm (ES256, ES384 or ES512).
+

programming_language: Markdown
filename: ECDH.java
change_type: ModificationType.MODIFY
diff: @@ -18,18 +18,12 @@
 package com.nimbusds.jose.crypto;
 
 
-import java.math.BigInteger;
 import java.nio.charset.Charset;
 import java.security.InvalidKeyException;
 import java.security.NoSuchAlgorithmException;
 import java.security.Provider;
 import java.security.interfaces.ECPrivateKey;
 import java.security.interfaces.ECPublicKey;
-import java.security.spec.ECFieldFp;
-import java.security.spec.ECParameterSpec;
-import java.security.spec.ECPoint;
-import java.security.spec.EllipticCurve;
-
 import javax.crypto.KeyAgreement;
 import javax.crypto.SecretKey;
 import javax.crypto.spec.SecretKeySpec;
@@ -44,7 +38,7 @@ import com.nimbusds.jose.JWEHeader;
  * Elliptic Curve Diffie-Hellman key agreement functions and utilities.
  *
  * @author Vladimir Dzhuvinov
- * @version 2017-02-28
+ * @version 2017-04-13
  */
 class ECDH {
 
@@ -78,7 +72,7 @@ class ECDH {
 	 *
 	 * @throws JOSEException If the JWE algorithm is not supported.
 	 */
-	public static AlgorithmMode resolveAlgorithmMode(final JWEAlgorithm alg)
+	static AlgorithmMode resolveAlgorithmMode(final JWEAlgorithm alg)
 		throws JOSEException {
 
 		if (alg.equals(JWEAlgorithm.ECDH_ES)) {
@@ -113,7 +107,7 @@ class ECDH {
 	 * @throws JOSEException If the JWE algorithm or encryption method is
 	 *                       not supported.
 	 */
-	public static int sharedKeyLength(final JWEAlgorithm alg, final EncryptionMethod enc)
+	static int sharedKeyLength(final JWEAlgorithm alg, final EncryptionMethod enc)
 		throws JOSEException {
 
 		if (alg.equals(JWEAlgorithm.ECDH_ES)) {
@@ -156,9 +150,9 @@ class ECDH {
 	 *
 	 * @throws JOSEException If derivation of the shared secret failed.
 	 */
-	public static SecretKey deriveSharedSecret(final ECPublicKey publicKey,
-						   final ECPrivateKey privateKey,
-						   final Provider provider)
+	static SecretKey deriveSharedSecret(final ECPublicKey publicKey,
+					    final ECPrivateKey privateKey,
+					    final Provider provider)
 		throws JOSEException {
 
 		// Get an ECDH key agreement instance from the JCA provider
@@ -201,9 +195,9 @@ class ECDH {
 	 *
 	 * @throws JOSEException If derivation of the shared key failed.
 	 */
-	public static SecretKey deriveSharedKey(final JWEHeader header,
-						final SecretKey Z,
-						final ConcatKDF concatKDF)
+	static SecretKey deriveSharedKey(final JWEHeader header,
+					 final SecretKey Z,
+					 final ConcatKDF concatKDF)
 		throws JOSEException {
 
 		final int sharedKeyLength = sharedKeyLength(header.getAlgorithm(), header.getEncryptionMethod());
@@ -232,47 +226,8 @@ class ECDH {
 			ConcatKDF.encodeIntData(sharedKeyLength),
 			ConcatKDF.encodeNoData());
 	}
-	
-	
-	/**
-	 * Ensures the specified ephemeral public key is on the curve of the
-	 * private key. Intended to prevent an "Invalid Curve Attack",
-	 * independent from any JCA provider checks (the SUN provider in Java
-	 * 1.8.0_51+ and BouncyCastle have them, other / older provider do
-	 * not).
-	 *
-	 * <p>See https://www.cs.bris.ac.uk/Research/CryptographySecurity/RWC/2017/nguyen.quan.pdf
-	 *
-	 * @param ephemeralPublicKey The ephemeral public EC key. Must not be
-	 *                           {@code null}.
-	 * @param privateKey         The private EC key. Must not be
-	 *                           {@code null}.
-	 *
-	 * @throws JOSEException If the ephemeral public key didn't pass the
-	 *                       curve check.
-	 */
-	public static void ensurePointOnCurve(final ECPublicKey ephemeralPublicKey, final ECPrivateKey privateKey)
-		throws JOSEException {
-		
-		// Ensure the following is met:
-		// (y^2) mod p = (x^3 + ax + b) mod p
-		ECParameterSpec ecParameterSpec = privateKey.getParams();
-		EllipticCurve curve = ecParameterSpec.getCurve();
-		ECPoint point = ephemeralPublicKey.getW();
-		BigInteger x = point.getAffineX();
-		BigInteger y = point.getAffineY();
-		BigInteger a = curve.getA();
-		BigInteger b = curve.getB();
-		BigInteger p = ((ECFieldFp) curve.getField()).getP();
-		BigInteger leftSide = (y.pow(2)).mod(p);
-		BigInteger rightSide = (x.pow(3).add(a.multiply(x)).add(b)).mod(p);
-		
-		if (! leftSide.equals(rightSide)) {
-			throw new JOSEException("Invalid ephemeral public key: Point not on expected curve");
-		}
-	}
-
 
+	
 	/**
 	 * Prevents public instantiation.
 	 */

programming_language: Java
filename: ECDHDecrypter.java
change_type: ModificationType.MODIFY
diff: @@ -21,10 +21,10 @@ package com.nimbusds.jose.crypto;
 import java.security.interfaces.ECPrivateKey;
 import java.security.interfaces.ECPublicKey;
 import java.util.Set;
-
 import javax.crypto.SecretKey;
 
 import com.nimbusds.jose.*;
+import com.nimbusds.jose.crypto.utils.ECChecks;
 import com.nimbusds.jose.jwk.ECKey;
 import com.nimbusds.jose.util.Base64URL;
 
@@ -71,7 +71,7 @@ import com.nimbusds.jose.util.Base64URL;
  * </ul>
  *
  * @author Vladimir Dzhuvinov
- * @version 2017-02-28
+ * @version 2017-04-13
  */
 public class ECDHDecrypter extends ECDHCryptoProvider implements JWEDecrypter, CriticalHeaderParamsAware {
 
@@ -192,7 +192,9 @@ public class ECDHDecrypter extends ECDHCryptoProvider implements JWEDecrypter, C
 		ECPublicKey ephemeralPublicKey = ephemeralKey.toECPublicKey();
 		
 		// Curve check
-		ECDH.ensurePointOnCurve(ephemeralPublicKey, getPrivateKey());
+		if (! ECChecks.isPointOnCurve(ephemeralPublicKey, getPrivateKey())) {
+			throw new JOSEException("Invalid ephemeral public EC key: Point(s) not on the expected curve");
+		}
 
 		// Derive 'Z'
 		SecretKey Z = ECDH.deriveSharedSecret(

programming_language: Java
filename: ECDSA.java
change_type: ModificationType.MODIFY
diff: @@ -177,7 +177,7 @@ class ECDSA {
 		throws JOSEException {
 
 		if (derSignature.length < 8 || derSignature[0] != 48) {
-			throw new JOSEException("Invalid  ECDSA signature format");
+			throw new JOSEException("Invalid ECDSA signature format");
 		}
 
 		int offset;
@@ -186,7 +186,7 @@ class ECDSA {
 		} else if (derSignature[1] == (byte) 0x81) {
 			offset = 3;
 		} else {
-			throw new JOSEException("Invalid  ECDSA signature format");
+			throw new JOSEException("Invalid ECDSA signature format");
 		}
 
 		byte rLength = derSignature[offset + 1];
@@ -210,7 +210,7 @@ class ECDSA {
 			|| (derSignature[offset - 1] & 0xff) != 2 + rLength + 2 + sLength
 			|| derSignature[offset] != 2
 			|| derSignature[offset + 2 + rLength] != 2) {
-			throw new JOSEException("Invalid  ECDSA signature format");
+			throw new JOSEException("Invalid ECDSA signature format");
 		}
 
 		final byte[] concatSignature = new byte[2 * rawLen];

programming_language: Java
filename: ECDSAProvider.java
change_type: ModificationType.MODIFY
diff: @@ -39,7 +39,7 @@ import com.nimbusds.jose.JWSAlgorithm;
  * 
  * @author Axel Nennker
  * @author Vladimir Dzhuvinov
- * @version 2015-06-07
+ * @version 2017-05-13
  */
 abstract class ECDSAProvider extends BaseJWSProvider {
 
@@ -77,5 +77,18 @@ abstract class ECDSAProvider extends BaseJWSProvider {
 			throw new JOSEException("Unsupported EC DSA algorithm: " + alg);
 		}
 	}
+	
+	
+	/**
+	 * Returns the supported ECDSA algorithm.
+	 *
+	 * @see #supportedECDSAAlgorithm()
+	 *
+	 * @return The supported ECDSA algorithm.
+	 */
+	public JWSAlgorithm supportedECDSAAlgorithm() {
+		
+		return supportedJWSAlgorithms().iterator().next();
+	}
 }
 

programming_language: Java
filename: ECDSAVerifier.java
change_type: ModificationType.MODIFY
diff: @@ -24,11 +24,11 @@ import java.security.SignatureException;
 import java.security.interfaces.ECPublicKey;
 import java.util.Set;
 
-import net.jcip.annotations.ThreadSafe;
-
 import com.nimbusds.jose.*;
+import com.nimbusds.jose.crypto.utils.ECChecks;
 import com.nimbusds.jose.jwk.ECKey;
 import com.nimbusds.jose.util.Base64URL;
+import net.jcip.annotations.ThreadSafe;
 
 
 /**
@@ -52,7 +52,7 @@ import com.nimbusds.jose.util.Base64URL;
  * 
  * @author Axel Nennker
  * @author Vladimir Dzhuvinov
- * @version 2015-06-07
+ * @version 2017-04-13
  */
 @ThreadSafe
 public class ECDSAVerifier extends ECDSAProvider implements JWSVerifier, CriticalHeaderParamsAware {
@@ -83,8 +83,7 @@ public class ECDSAVerifier extends ECDSAProvider implements JWSVerifier, Critica
 
 		this(publicKey, null);
 	}
-
-
+	
 
 	/**
 	 * Creates a new Elliptic Curve Digital Signature Algorithm (ECDSA)
@@ -118,6 +117,12 @@ public class ECDSAVerifier extends ECDSAProvider implements JWSVerifier, Critica
 		super(ECDSA.resolveAlgorithm(publicKey));
 
 		this.publicKey = publicKey;
+		
+		if (! ECChecks.isPointOnCurve(
+			publicKey,
+			ECKey.Curve.forJWSAlgoritm(supportedECDSAAlgorithm()).toECParameterSpec())) {
+			throw new JOSEException("Curve / public key parameters mismatch");
+		}
 
 		critPolicy.setDeferredCriticalHeaderParams(defCritHeaders);
 	}

programming_language: Java
filename: ECChecks.java
change_type: ModificationType.ADD
diff: @@ -0,0 +1,114 @@
+/*
+ * nimbus-jose-jwt
+ *
+ * Copyright 2012-2016, Connect2id Ltd and contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+
+package com.nimbusds.jose.crypto.utils;
+
+
+import java.math.BigInteger;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECFieldFp;
+import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+import java.security.spec.EllipticCurve;
+
+
+/**
+ * Elliptic curve checks.
+ *
+ * @author Vladimir Dzhuvinov
+ * @version 2017-04-13
+ */
+public class ECChecks {
+	
+	
+	/**
+	 * Checks if the specified (ephemeral) public key is on the curve of
+	 * the private key. Intended to prevent an "Invalid Curve Attack",
+	 * independent from any JCA provider checks (the SUN provider in Java
+	 * 1.8.0_51+ and BouncyCastle have them, other / older provider do
+	 * not).
+	 *
+	 * <p>See https://www.cs.bris.ac.uk/Research/CryptographySecurity/RWC/2017/nguyen.quan.pdf
+	 *
+	 * @param publicKey  The public EC key. Must not be {@code null}.
+	 * @param privateKey The private EC key. Must not be {@code null}.
+	 *
+	 * @return {@code true} if public key passed the curve check.
+	 */
+	public static boolean isPointOnCurve(final ECPublicKey publicKey, final ECPrivateKey privateKey) {
+		
+		return isPointOnCurve(publicKey, privateKey.getParams());
+	}
+	
+	
+	/**
+	 * Checks if the specified (ephemeral) public key is on the given
+	 * curve. Intended to prevent an "Invalid Curve Attack", independent
+	 * from any JCA provider checks (the SUN provider in Java 1.8.0_51+ and
+	 * BouncyCastle have them, other / older provider do not).
+	 *
+	 * <p>See https://www.cs.bris.ac.uk/Research/CryptographySecurity/RWC/2017/nguyen.quan.pdf
+	 *
+	 * @param publicKey       The public EC key. Must not be {@code null}.
+	 * @param ecParameterSpec The EC spec. Must not be {@code null}.
+	 *
+	 * @return {@code true} if public key passed the curve check.
+	 */
+	public static boolean isPointOnCurve(final ECPublicKey publicKey, final ECParameterSpec ecParameterSpec) {
+		
+		ECPoint point = publicKey.getW();
+		return isPointOnCurve(point.getAffineX(), point.getAffineY(), ecParameterSpec);
+	}
+	
+	
+	/**
+	 * Checks if the specified (ephemeral) public key is on the given
+	 * curve. Intended to prevent an "Invalid Curve Attack", independent
+	 * from any JCA provider checks (the SUN provider in Java 1.8.0_51+ and
+	 * BouncyCastle have them, other / older provider do not).
+	 *
+	 * <p>See https://www.cs.bris.ac.uk/Research/CryptographySecurity/RWC/2017/nguyen.quan.pdf
+	 *
+	 * @param x               The public EC x coordinate. Must not be
+	 *                        {@code null}.
+	 * @param y               The public EC y coordinate. Must not be
+	 *                        {@code null}.
+	 * @param ecParameterSpec The EC spec. Must not be {@code null}.
+	 *
+	 * @return {@code true} if public key passed the curve check.
+	 */
+	public static boolean isPointOnCurve(final BigInteger x, final BigInteger y, final ECParameterSpec ecParameterSpec) {
+		
+		// Ensure the following condition is met:
+		// (y^2) mod p = (x^3 + ax + b) mod p
+		EllipticCurve curve = ecParameterSpec.getCurve();
+		BigInteger a = curve.getA();
+		BigInteger b = curve.getB();
+		BigInteger p = ((ECFieldFp) curve.getField()).getP();
+		BigInteger leftSide = (y.pow(2)).mod(p);
+		BigInteger rightSide = (x.pow(3).add(a.multiply(x)).add(b)).mod(p);
+		
+		return leftSide.equals(rightSide);
+	}
+	
+	
+	/**
+	 * Prevents public instantiation.
+	 */
+	private ECChecks() {}
+}

programming_language: Java
filename: package-info.java
change_type: ModificationType.ADD
diff: @@ -0,0 +1,21 @@
+/*
+ * nimbus-jose-jwt
+ *
+ * Copyright 2012-2016, Connect2id Ltd and contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+
+/**
+ * Cryptographic utilities.
+ */
+package com.nimbusds.jose.crypto.utils;
\ No newline at end of file

programming_language: Java
filename: ECKey.java
change_type: ModificationType.MODIFY
diff: @@ -37,6 +37,7 @@ import java.util.Set;
 import com.nimbusds.jose.Algorithm;
 import com.nimbusds.jose.JOSEException;
 import com.nimbusds.jose.JWSAlgorithm;
+import com.nimbusds.jose.crypto.utils.ECChecks;
 import com.nimbusds.jose.util.Base64;
 import com.nimbusds.jose.util.Base64URL;
 import com.nimbusds.jose.util.BigIntegerUtils;
@@ -904,6 +905,28 @@ public final class ECKey extends JWK implements AssymetricJWK {
 	 * Private PKCS#11 key handle.
 	 */
 	private final PrivateKey privateKey;
+	
+	
+	/**
+	 * Ensures the specified 'x' and 'y' public coordinates are on the
+	 * given curve.
+	 *
+	 * @param crv The curve. Must not be {@code null}.
+	 * @param x   The public 'x' coordinate. Must not be {@code null}.
+	 * @param y   The public 'y' coordinate. Must not be {@code null}.
+	 */
+	private static void ensurePublicCoordinatesOnCurve(final Curve crv, final Base64URL x, final Base64URL y) {
+		
+		ECParameterSpec ecSpec = crv.toECParameterSpec();
+		
+		if (ecSpec == null) {
+			throw new IllegalArgumentException("Unknown / unsupported curve: " + crv);
+		}
+		
+		if (! ECChecks.isPointOnCurve(x.decodeToBigInteger(), y.decodeToBigInteger(), crv.toECParameterSpec())) {
+			throw new IllegalArgumentException("Invalid EC JWK: The 'x' and 'y' public coordinates are not on the " + crv + " curve");
+		}
+	}
 
 
 	/**
@@ -960,6 +983,8 @@ public final class ECKey extends JWK implements AssymetricJWK {
 		}
 
 		this.y = y;
+		
+		ensurePublicCoordinatesOnCurve(crv, x, y);
 
 		this.d = null;
 		
@@ -1026,6 +1051,8 @@ public final class ECKey extends JWK implements AssymetricJWK {
 
 		this.y = y;
 		
+		ensurePublicCoordinatesOnCurve(crv, x, y);
+		
 		if (d == null) {
 			throw new IllegalArgumentException("The 'd' coordinate must not be null");
 		}
@@ -1092,6 +1119,8 @@ public final class ECKey extends JWK implements AssymetricJWK {
 
 		this.y = y;
 		
+		ensurePublicCoordinatesOnCurve(crv, x, y);
+		
 		d = null;
 		
 		this.privateKey = priv;

programming_language: Java
filename: ECDHCryptoTest.java
change_type: ModificationType.MODIFY
diff: @@ -50,7 +50,7 @@ import com.nimbusds.jose.util.Container;
  * Tests ECDH encryption and decryption.
  *
  * @author Vladimir Dzhuvinov
- * @version 2015-09-18
+ * @version 2017-04-13
  */
 public class ECDHCryptoTest extends TestCase {
 
@@ -704,31 +704,6 @@ public class ECDHCryptoTest extends TestCase {
 	}
 
 
-	public void testRejectECJWKWithUnsupportedCurve()
-		throws Exception {
-
-		KeyPair keyPair = createUnsupportedECKeyPair();
-		ECPublicKey ecPublicKey = (ECPublicKey)keyPair.getPublic();
-		ECPrivateKey ecPrivateKey = (ECPrivateKey)keyPair.getPrivate();
-
-		ECKey ecJWK = new ECKey.Builder(new ECKey.Curve("P-224"), ecPublicKey).privateKey(ecPrivateKey).build();
-
-		try {
-			new ECDHEncrypter(ecJWK);
-			fail();
-		} catch (JOSEException e) {
-			// ok
-		}
-
-		try {
-			new ECDHDecrypter(ecJWK);
-			fail();
-		} catch (JOSEException e) {
-			// ok
-		}
-	}
-
-
 	public void testECKeyGetters()
 		throws Exception {
 

programming_language: Java
filename: ECDHCurveCheckTest.java
change_type: ModificationType.MODIFY
diff: @@ -24,6 +24,7 @@ import java.security.KeyPairGenerator;
 import java.security.interfaces.ECPrivateKey;
 import java.security.interfaces.ECPublicKey;
 import java.security.spec.ECParameterSpec;
+import java.text.ParseException;
 
 import com.nimbusds.jose.*;
 import com.nimbusds.jose.crypto.bc.BouncyCastleProviderSingleton;
@@ -33,7 +34,8 @@ import junit.framework.TestCase;
 
 
 /**
- * Submitted by Antonio Sanso. See iss #210.
+ * Submitted by Antonio Sanso. See iss #210. Modified to suit new checks for
+ * iss #217.
  */
 public class ECDHCurveCheckTest extends TestCase {
 	
@@ -110,18 +112,25 @@ public class ECDHCurveCheckTest extends TestCase {
 		
 		// The malicious JWE contains a public key with order 113
 		String maliciousJWE1 = "eyJhbGciOiJFQ0RILUVTK0ExMjhLVyIsImVuYyI6IkExMjhDQkMtSFMyNTYiLCJlcGsiOnsia3R5IjoiRUMiLCJ4IjoiZ1RsaTY1ZVRRN3otQmgxNDdmZjhLM203azJVaURpRzJMcFlrV0FhRkpDYyIsInkiOiJjTEFuakthNGJ6akQ3REpWUHdhOUVQclJ6TUc3ck9OZ3NpVUQta2YzMEZzIiwiY3J2IjoiUC0yNTYifX0.qGAdxtEnrV_3zbIxU2ZKrMWcejNltjA_dtefBFnRh9A2z9cNIqYRWg.pEA5kX304PMCOmFSKX_cEg.a9fwUrx2JXi1OnWEMOmZhXd94-bEGCH9xxRwqcGuG2AMo-AwHoljdsH5C_kcTqlXS5p51OB1tvgQcMwB5rpTxg.72CHiYFecyDvuUa43KKT6w";
-		JWEObject jweObject1 = JWEObject.parse(maliciousJWE1);
-		
-		ECDHDecrypter decrypter = new ECDHDecrypter(ecJWK.toECPrivateKey());
-//		decrypter.getJCAContext().setKeyEncryptionProvider(BouncyCastleProviderSingleton.getInstance());
+		JWEObject jweObject1 = null;
 		
 		try {
-			jweObject1.decrypt(decrypter);
+			jweObject1 = JWEObject.parse(maliciousJWE1);
 			fail();
-		} catch (JOSEException e) {
-			assertEquals("Invalid ephemeral public key: Point not on expected curve", e.getMessage());
+		} catch (ParseException e) {
+			assertEquals("Invalid JWE header: Invalid EC JWK: The 'x' and 'y' public coordinates are not on the P-256 curve", e.getMessage());
 		}
 		
+//		ECDHDecrypter decrypter = new ECDHDecrypter(ecJWK.toECPrivateKey());
+////		decrypter.getJCAContext().setKeyEncryptionProvider(BouncyCastleProviderSingleton.getInstance());
+//
+//		try {
+//			jweObject1.decrypt(decrypter);
+//			fail();
+//		} catch (JOSEException e) {
+//			assertEquals("Invalid ephemeral public key: Point not on expected curve", e.getMessage());
+//		}
+		
 		// this proof that receiverPrivateKey is equals 26 % 113
 //		assertEquals("Gambling is illegal at Bushwood sir, and I never slice.",
 //			jweObject1.getPayload().toString());
@@ -160,15 +169,22 @@ public class ECDHCurveCheckTest extends TestCase {
 		// The malicious JWE contains a public key with order 2447
 		String maliciousJWE2 = "eyJhbGciOiJFQ0RILUVTK0ExMjhLVyIsImVuYyI6IkExMjhDQkMtSFMyNTYiLCJlcGsiOnsia3R5IjoiRUMiLCJ4IjoiWE9YR1E5XzZRQ3ZCZzN1OHZDSS1VZEJ2SUNBRWNOTkJyZnFkN3RHN29RNCIsInkiOiJoUW9XTm90bk56S2x3aUNuZUprTElxRG5UTnc3SXNkQkM1M1ZVcVZqVkpjIiwiY3J2IjoiUC0yNTYifX0.UGb3hX3ePAvtFB9TCdWsNkFTv9QWxSr3MpYNiSBdW630uRXRBT3sxw.6VpU84oMob16DxOR98YTRw.y1UslvtkoWdl9HpugfP0rSAkTw1xhm_LbK1iRXzGdpYqNwIG5VU33UBpKAtKFBoA1Kk_sYtfnHYAvn-aes4FTg.UZPN8h7FcvA5MIOq-Pkj8A";
 		
-		JWEObject jweObject2 = JWEObject.parse(maliciousJWE2);
-//		decrypter.getJCAContext().setContentEncryptionProvider(BouncyCastleProviderSingleton.getInstance());
+		JWEObject jweObject2 = null;
 		
 		try {
-			jweObject2.decrypt(decrypter);
+			jweObject2 = JWEObject.parse(maliciousJWE2);
 			fail();
-		} catch (JOSEException e) {
-			assertEquals("Invalid ephemeral public key: Point not on expected curve", e.getMessage());
+		} catch (ParseException e) {
+			assertEquals("Invalid JWE header: Invalid EC JWK: The 'x' and 'y' public coordinates are not on the P-256 curve", e.getMessage());
 		}
+//		decrypter.getJCAContext().setContentEncryptionProvider(BouncyCastleProviderSingleton.getInstance());
+		
+//		try {
+//			jweObject2.decrypt(decrypter);
+//			fail();
+//		} catch (JOSEException e) {
+//			assertEquals("Invalid ephemeral public key: Point not on expected curve", e.getMessage());
+//		}
 		
 		// this proof that receiverPrivateKey is equals 2446 % 2447
 //		assertEquals("Gambling is illegal at Bushwood sir, and I never slice.",

programming_language: Java
filename: ECDHTest.java
change_type: ModificationType.MODIFY
diff: @@ -18,16 +18,9 @@
 package com.nimbusds.jose.crypto;
 
 
-import java.security.KeyPair;
-import java.security.KeyPairGenerator;
-import java.security.interfaces.ECPrivateKey;
-import java.security.interfaces.ECPublicKey;
-import java.security.spec.ECParameterSpec;
 import java.util.Arrays;
 import javax.crypto.SecretKey;
 
-import com.nimbusds.jose.JOSEException;
-import com.nimbusds.jose.JWEObject;
 import com.nimbusds.jose.crypto.bc.BouncyCastleProviderSingleton;
 import com.nimbusds.jose.jwk.ECKey;
 import com.nimbusds.jose.util.Base64URL;
@@ -37,7 +30,7 @@ import junit.framework.TestCase;
 /**
  * Tests the ECDH key agreement derivation.
  *
- * @version 2017-02-28
+ * @version 2017-04-13
  */
 public class ECDHTest extends TestCase{
 
@@ -126,79 +119,4 @@ public class ECDHTest extends TestCase{
 
 		assertTrue(Arrays.equals(expected, sharedSecret.getEncoded()));
 	}
-	
-	
-	private static ECPrivateKey generateECPrivateKey(final ECKey.Curve curve)
-		throws Exception {
-		
-		final ECParameterSpec ecParameterSpec = curve.toECParameterSpec();
-		
-		KeyPairGenerator generator = KeyPairGenerator.getInstance("EC");
-		generator.initialize(ecParameterSpec);
-		KeyPair keyPair = generator.generateKeyPair();
-		
-		return (ECPrivateKey) keyPair.getPrivate();
-	}
-	
-	
-	private static ECPublicKey generateECPublicKey(final ECKey.Curve curve)
-		throws Exception {
-		
-		final ECParameterSpec ecParameterSpec = curve.toECParameterSpec();
-		
-		KeyPairGenerator generator = KeyPairGenerator.getInstance("EC");
-		generator.initialize(ecParameterSpec);
-		KeyPair keyPair = generator.generateKeyPair();
-		
-		return (ECPublicKey) keyPair.getPublic();
-	}
-	
-	
-	public void testCurveCheckOk()
-		throws Exception {
-		
-		ECPublicKey ephemeralPublicKey = generateECPublicKey(ECKey.Curve.P_256);
-		ECPrivateKey privateKey = generateECPrivateKey(ECKey.Curve.P_256);
-		ECDH.ensurePointOnCurve(ephemeralPublicKey, privateKey);
-	}
-	
-	
-	public void testCurveCheckNegative_P256_attackPt1()
-		throws Exception {
-		
-		// The malicious JWE contains a public key with order 113
-		String maliciousJWE = "eyJhbGciOiJFQ0RILUVTK0ExMjhLVyIsImVuYyI6IkExMjhDQkMtSFMyNTYiLCJlcGsiOnsia3R5IjoiRUMiLCJ4IjoiZ1RsaTY1ZVRRN3otQmgxNDdmZjhLM203azJVaURpRzJMcFlrV0FhRkpDYyIsInkiOiJjTEFuakthNGJ6akQ3REpWUHdhOUVQclJ6TUc3ck9OZ3NpVUQta2YzMEZzIiwiY3J2IjoiUC0yNTYifX0.qGAdxtEnrV_3zbIxU2ZKrMWcejNltjA_dtefBFnRh9A2z9cNIqYRWg.pEA5kX304PMCOmFSKX_cEg.a9fwUrx2JXi1OnWEMOmZhXd94-bEGCH9xxRwqcGuG2AMo-AwHoljdsH5C_kcTqlXS5p51OB1tvgQcMwB5rpTxg.72CHiYFecyDvuUa43KKT6w";
-		JWEObject jweObject = JWEObject.parse(maliciousJWE);
-		
-		ECPublicKey ephemeralPublicKey = jweObject.getHeader().getEphemeralPublicKey().toECPublicKey();
-		
-		ECPrivateKey privateKey = generateECPrivateKey(ECKey.Curve.P_256);
-		
-		try {
-			ECDH.ensurePointOnCurve(ephemeralPublicKey, privateKey);
-			fail();
-		} catch (JOSEException e) {
-			assertEquals("Invalid ephemeral public key: Point not on expected curve", e.getMessage());
-		}
-	}
-	
-	
-	public void testCurveCheckNegative_P256_attackPt2()
-		throws Exception {
-		
-		// The malicious JWE contains a public key with order 2447
-		String maliciousJWE = "eyJhbGciOiJFQ0RILUVTK0ExMjhLVyIsImVuYyI6IkExMjhDQkMtSFMyNTYiLCJlcGsiOnsia3R5IjoiRUMiLCJ4IjoiWE9YR1E5XzZRQ3ZCZzN1OHZDSS1VZEJ2SUNBRWNOTkJyZnFkN3RHN29RNCIsInkiOiJoUW9XTm90bk56S2x3aUNuZUprTElxRG5UTnc3SXNkQkM1M1ZVcVZqVkpjIiwiY3J2IjoiUC0yNTYifX0.UGb3hX3ePAvtFB9TCdWsNkFTv9QWxSr3MpYNiSBdW630uRXRBT3sxw.6VpU84oMob16DxOR98YTRw.y1UslvtkoWdl9HpugfP0rSAkTw1xhm_LbK1iRXzGdpYqNwIG5VU33UBpKAtKFBoA1Kk_sYtfnHYAvn-aes4FTg.UZPN8h7FcvA5MIOq-Pkj8A";
-		JWEObject jweObject = JWEObject.parse(maliciousJWE);
-		
-		ECPublicKey ephemeralPublicKey = jweObject.getHeader().getEphemeralPublicKey().toECPublicKey();
-		
-		ECPrivateKey privateKey = generateECPrivateKey(ECKey.Curve.P_256);
-		
-		try {
-			ECDH.ensurePointOnCurve(ephemeralPublicKey, privateKey);
-			fail();
-		} catch (JOSEException e) {
-			assertEquals("Invalid ephemeral public key: Point not on expected curve", e.getMessage());
-		}
-	}
 }

programming_language: Java
filename: ECChecksTest.java
change_type: ModificationType.ADD
diff: @@ -0,0 +1,67 @@
+/*
+ * nimbus-jose-jwt
+ *
+ * Copyright 2012-2016, Connect2id Ltd and contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use
+ * this file except in compliance with the License. You may obtain a copy of the
+ * License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed
+ * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+ * CONDITIONS OF ANY KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations under the License.
+ */
+
+package com.nimbusds.jose.crypto.utils;
+
+
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECParameterSpec;
+
+import com.nimbusds.jose.jwk.ECKey;
+import junit.framework.TestCase;
+
+
+public class ECChecksTest extends TestCase {
+	
+	
+	private static ECPrivateKey generateECPrivateKey(final ECKey.Curve curve)
+		throws Exception {
+		
+		final ECParameterSpec ecParameterSpec = curve.toECParameterSpec();
+		
+		KeyPairGenerator generator = KeyPairGenerator.getInstance("EC");
+		generator.initialize(ecParameterSpec);
+		KeyPair keyPair = generator.generateKeyPair();
+		
+		return (ECPrivateKey) keyPair.getPrivate();
+	}
+	
+	
+	private static ECPublicKey generateECPublicKey(final ECKey.Curve curve)
+		throws Exception {
+		
+		final ECParameterSpec ecParameterSpec = curve.toECParameterSpec();
+		
+		KeyPairGenerator generator = KeyPairGenerator.getInstance("EC");
+		generator.initialize(ecParameterSpec);
+		KeyPair keyPair = generator.generateKeyPair();
+		
+		return (ECPublicKey) keyPair.getPublic();
+	}
+	
+	
+	public void testCurveCheckOk()
+		throws Exception {
+		
+		ECPublicKey ephemeralPublicKey = generateECPublicKey(ECKey.Curve.P_256);
+		ECPrivateKey privateKey = generateECPrivateKey(ECKey.Curve.P_256);
+		assertTrue(ECChecks.isPointOnCurve(ephemeralPublicKey, privateKey));
+	}
+}

programming_language: Java
filename: ECKeyTest.java
change_type: ModificationType.MODIFY
diff: @@ -27,6 +27,9 @@ import java.security.cert.X509Certificate;
 import java.security.interfaces.ECPrivateKey;
 import java.security.interfaces.ECPublicKey;
 import java.security.spec.ECParameterSpec;
+import java.security.spec.ECPoint;
+import java.security.spec.ECPublicKeySpec;
+import java.security.spec.InvalidKeySpecException;
 import java.util.*;
 
 import com.nimbusds.jose.JOSEException;
@@ -50,7 +53,7 @@ import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
  * Tests the EC JWK class.
  *
  * @author Vladimir Dzhuvinov
- * @version 2017-04-09
+ * @version 2017-04-13
  */
 public class ECKeyTest extends TestCase {
 
@@ -140,13 +143,13 @@ public class ECKeyTest extends TestCase {
 	}
 
 
-	public void testKeySizeForUnknownCurve() {
+	public void testUnknownCurve() {
 
 		try {
-			new ECKey.Builder(new ECKey.Curve("unknown"), ExampleKeyP256.X, ExampleKeyP256.Y).build().size();
+			new ECKey.Builder(new ECKey.Curve("unknown"), ExampleKeyP256.X, ExampleKeyP256.Y).build();
 			fail();
-		} catch (UnsupportedOperationException e) {
-			assertEquals("Couldn't determine field size for curve unknown", e.getMessage());
+		} catch (IllegalStateException e) {
+			assertEquals("Unknown / unsupported curve: unknown", e.getMessage());
 		}
 	}
 
@@ -998,4 +1001,97 @@ public class ECKeyTest extends TestCase {
 		
 		assertNull(ECKey.load(keyStore, "1", null));
 	}
+	
+	
+	// iss #217
+	public void testEnsurePublicXYCoordinatesOnCurve()
+		throws Exception {
+		
+		try {
+			new ECKey(
+				ECKey.Curve.P_256,
+				ExampleKeyP384Alt.X, // on diff curve
+				ExampleKeyP384Alt.Y, // on diff curve
+				null,
+				null,
+				null,
+				null,
+				null,
+				null,
+				null,
+				null,
+				null);
+			fail();
+		} catch (IllegalArgumentException e) {
+			assertEquals("Invalid EC JWK: The 'x' and 'y' public coordinates are not on the P-256 curve", e.getMessage());
+		}
+		
+		try {
+			new ECKey(
+				ECKey.Curve.P_256,
+				ExampleKeyP384Alt.X, // on diff curve
+				ExampleKeyP384Alt.Y, // on diff curve
+				ExampleKeyP256.D,    // private D coordinate
+				null,
+				null,
+				null,
+				null,
+				null,
+				null,
+				null,
+				null,
+				null);
+			fail();
+		} catch (IllegalArgumentException e) {
+			assertEquals("Invalid EC JWK: The 'x' and 'y' public coordinates are not on the P-256 curve", e.getMessage());
+		}
+	}
+	
+	
+	// iss #217
+	public void testCurveMismatch()
+		throws Exception {
+		
+		// EC key on P_256
+		ECParameterSpec ecParameterSpec = ECKey.Curve.P_256.toECParameterSpec();
+		KeyPairGenerator generator = KeyPairGenerator.getInstance("EC");
+		generator.initialize(ecParameterSpec);
+		KeyPair keyPair = generator.generateKeyPair();
+		ECKey ecJWK_p256 = new ECKey.Builder(ECKey.Curve.P_256, (ECPublicKey) keyPair.getPublic())
+			.privateKey((ECPrivateKey) keyPair.getPrivate())
+			.build();
+		
+		// EC key on P_384
+		ecParameterSpec = ECKey.Curve.P_384.toECParameterSpec();
+		generator = KeyPairGenerator.getInstance("EC");
+		generator.initialize(ecParameterSpec);
+		keyPair = generator.generateKeyPair();
+		ECKey ecJWK_p384 = new ECKey.Builder(ECKey.Curve.P_384, (ECPublicKey) keyPair.getPublic())
+			.privateKey((ECPrivateKey) keyPair.getPrivate())
+			.build();
+		
+		
+		// Try to create EC key with P_256 params, but with x and y from P_384 curve key
+		
+		ECPoint w = new ECPoint(ecJWK_p384.getX().decodeToBigInteger(), ecJWK_p384.getY().decodeToBigInteger());
+		ECPublicKeySpec publicKeySpec = new ECPublicKeySpec(w, ECKey.Curve.P_256.toECParameterSpec());
+		
+		// Default Sun provider
+		try {
+			KeyFactory keyFactory = KeyFactory.getInstance("EC");
+			keyFactory.generatePublic(publicKeySpec);
+			fail();
+		} catch (RuntimeException e) {
+			assertEquals("Point coordinates do not match field size", e.getMessage());
+		}
+		
+		// BouncyCastle provider
+		try {
+			KeyFactory keyFactory = KeyFactory.getInstance("EC", BouncyCastleProviderSingleton.getInstance());
+			keyFactory.generatePublic(publicKeySpec);
+			fail();
+		} catch (InvalidKeySpecException e) {
+			assertEquals("invalid KeySpec: x value invalid for SecP256R1FieldElement", e.getMessage());
+		}
+	}
 }
\ No newline at end of file

programming_language: Java
filename: JWKMatcherTest.java
change_type: ModificationType.MODIFY
diff: @@ -18,7 +18,12 @@
 package com.nimbusds.jose.jwk;
 
 
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
 import java.security.SecureRandom;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECParameterSpec;
 import java.util.*;
 import javax.crypto.KeyGenerator;
 
@@ -33,9 +38,34 @@ import junit.framework.TestCase;
  * Tests the JWK matcher.
  *
  * @author Vladimir Dzhuvinov
- * @version 2016-08-24
+ * @version 2017-04-13
  */
 public class JWKMatcherTest extends TestCase {
+	
+	
+	private static final Base64URL EC_P256_X;
+	
+	private static final Base64URL EC_P256_Y;
+	
+	static {
+		try {
+			ECParameterSpec ecParameterSpec = ECKey.Curve.P_256.toECParameterSpec();
+			
+			KeyPairGenerator generator = KeyPairGenerator.getInstance("EC");
+			generator.initialize(ecParameterSpec);
+			KeyPair keyPair = generator.generateKeyPair();
+			
+			ECKey ecJWK = new ECKey.Builder(ECKey.Curve.P_256, (ECPublicKey)keyPair.getPublic()).
+				privateKey((ECPrivateKey) keyPair.getPrivate()).
+				build();
+			
+			EC_P256_X = ecJWK.getX();
+			EC_P256_Y = ecJWK.getY();
+			
+		} catch (Exception e) {
+			throw new RuntimeException(e);
+		}
+	}
 
 
 	public void testMinimalConstructor() {
@@ -391,7 +421,7 @@ public class JWKMatcherTest extends TestCase {
 		JWKMatcher matcher = new JWKMatcher.Builder().keyType(KeyType.RSA).build();
 
 		assertTrue(matcher.matches(new RSAKey.Builder(new Base64URL("n"), new Base64URL("e")).keyID("1").build()));
-		assertFalse(matcher.matches(new ECKey.Builder(ECKey.Curve.P_256, new Base64URL("x"), new Base64URL("y")).keyID("2").build()));
+		assertFalse(matcher.matches(new ECKey.Builder(ECKey.Curve.P_256, EC_P256_X, EC_P256_Y).keyID("2").build()));
 		
 		assertEquals("kty=RSA", matcher.toString());
 	}
@@ -402,7 +432,7 @@ public class JWKMatcherTest extends TestCase {
 		JWKMatcher matcher = new JWKMatcher.Builder().keyTypes(KeyType.RSA, KeyType.EC).build();
 
 		assertTrue(matcher.matches(new RSAKey.Builder(new Base64URL("n"), new Base64URL("e")).keyID("1").build()));
-		assertTrue(matcher.matches(new ECKey.Builder(ECKey.Curve.P_256, new Base64URL("x"), new Base64URL("y")).keyID("2").build()));
+		assertTrue(matcher.matches(new ECKey.Builder(ECKey.Curve.P_256, EC_P256_X, EC_P256_Y).keyID("2").build()));
 		
 		assertEquals("kty=[RSA, EC]", matcher.toString());
 	}
@@ -413,7 +443,7 @@ public class JWKMatcherTest extends TestCase {
 		JWKMatcher matcher = new JWKMatcher.Builder().keyUse(KeyUse.ENCRYPTION).build();
 
 		assertTrue(matcher.matches(new RSAKey.Builder(new Base64URL("n"), new Base64URL("e")).keyID("1").keyUse(KeyUse.ENCRYPTION).build()));
-		assertFalse(matcher.matches(new ECKey.Builder(ECKey.Curve.P_256, new Base64URL("x"), new Base64URL("y")).keyID("2").build()));
+		assertFalse(matcher.matches(new ECKey.Builder(ECKey.Curve.P_256,EC_P256_X, EC_P256_Y).keyID("2").build()));
 		
 		assertEquals("use=enc", matcher.toString());
 	}
@@ -424,8 +454,8 @@ public class JWKMatcherTest extends TestCase {
 		JWKMatcher matcher = new JWKMatcher.Builder().keyUses(KeyUse.SIGNATURE, null).build();
 
 		assertTrue(matcher.matches(new RSAKey.Builder(new Base64URL("n"), new Base64URL("e")).keyID("1").keyUse(KeyUse.SIGNATURE).build()));
-		assertTrue(matcher.matches(new ECKey.Builder(ECKey.Curve.P_256, new Base64URL("x"), new Base64URL("y")).keyID("2").build()));
-		assertFalse(matcher.matches(new ECKey.Builder(ECKey.Curve.P_256, new Base64URL("x"), new Base64URL("y")).keyID("3").keyUse(KeyUse.ENCRYPTION).build()));
+		assertTrue(matcher.matches(new ECKey.Builder(ECKey.Curve.P_256, EC_P256_X, EC_P256_Y).keyID("2").build()));
+		assertFalse(matcher.matches(new ECKey.Builder(ECKey.Curve.P_256, EC_P256_X, EC_P256_Y).keyID("3").keyUse(KeyUse.ENCRYPTION).build()));
 		
 		assertEquals("use=[sig, null]", matcher.toString());
 	}
@@ -437,7 +467,7 @@ public class JWKMatcherTest extends TestCase {
 
 		assertTrue(matcher.matches(new RSAKey.Builder(new Base64URL("n"), new Base64URL("e")).keyID("1")
 			.keyOperations(new HashSet<>(Collections.singletonList(KeyOperation.DECRYPT))).build()));
-		assertFalse(matcher.matches(new ECKey.Builder(ECKey.Curve.P_256, new Base64URL("x"), new Base64URL("y")).keyID("2").build()));
+		assertFalse(matcher.matches(new ECKey.Builder(ECKey.Curve.P_256, EC_P256_X, EC_P256_Y).keyID("2").build()));
 		
 		assertEquals("key_ops=decrypt", matcher.toString());
 	}
@@ -449,7 +479,7 @@ public class JWKMatcherTest extends TestCase {
 
 		assertTrue(matcher.matches(new RSAKey.Builder(new Base64URL("n"), new Base64URL("e")).keyID("1")
 			.keyOperations(new HashSet<>(Arrays.asList(KeyOperation.SIGN, KeyOperation.VERIFY))).build()));
-		assertFalse(matcher.matches(new ECKey.Builder(ECKey.Curve.P_256, new Base64URL("x"), new Base64URL("y")).keyID("2").build()));
+		assertFalse(matcher.matches(new ECKey.Builder(ECKey.Curve.P_256, EC_P256_X, EC_P256_Y).keyID("2").build()));
 		
 		assertEquals("key_ops=[sign, verify]", matcher.toString());
 	}
@@ -462,9 +492,9 @@ public class JWKMatcherTest extends TestCase {
 		assertTrue(matcher.matches(new RSAKey.Builder(new Base64URL("n"), new Base64URL("e")).keyID("1")
 			.keyOperations(new HashSet<>(Collections.singletonList(KeyOperation.SIGN))).build()));
 
-		assertTrue(matcher.matches(new ECKey.Builder(ECKey.Curve.P_256, new Base64URL("x"), new Base64URL("y")).keyID("2").build()));
+		assertTrue(matcher.matches(new ECKey.Builder(ECKey.Curve.P_256, EC_P256_X, EC_P256_Y).keyID("2").build()));
 
-		assertFalse(matcher.matches(new ECKey.Builder(ECKey.Curve.P_256, new Base64URL("x"), new Base64URL("y")).keyID("3")
+		assertFalse(matcher.matches(new ECKey.Builder(ECKey.Curve.P_256, EC_P256_X, EC_P256_Y).keyID("3")
 			.keyOperations(new HashSet<>(Collections.singletonList(KeyOperation.ENCRYPT))).build()));
 		
 		assertEquals("key_ops=[sign, null]", matcher.toString());

programming_language: Java
filename: JWKSelectorTest.java
change_type: ModificationType.MODIFY
diff: @@ -18,6 +18,11 @@
 package com.nimbusds.jose.jwk;
 
 
+import java.security.KeyPair;
+import java.security.KeyPairGenerator;
+import java.security.interfaces.ECPrivateKey;
+import java.security.interfaces.ECPublicKey;
+import java.security.spec.ECParameterSpec;
 import java.util.*;
 
 import junit.framework.TestCase;
@@ -30,10 +35,33 @@ import com.nimbusds.jose.util.Base64URL;
  * Tests the JWK selector.
  *
  * @author Vladimir Dzhuvinov
- * @version 2015-04-15
+ * @version 2017-04-13
  */
 public class JWKSelectorTest extends TestCase {
-
+	
+	private static final Base64URL EC_P256_X;
+	
+	private static final Base64URL EC_P256_Y;
+	
+	static {
+		try {
+			ECParameterSpec ecParameterSpec = ECKey.Curve.P_256.toECParameterSpec();
+			
+			KeyPairGenerator generator = KeyPairGenerator.getInstance("EC");
+			generator.initialize(ecParameterSpec);
+			KeyPair keyPair = generator.generateKeyPair();
+			
+			ECKey ecJWK = new ECKey.Builder(ECKey.Curve.P_256, (ECPublicKey)keyPair.getPublic()).
+				privateKey((ECPrivateKey) keyPair.getPrivate()).
+				build();
+			
+			EC_P256_X = ecJWK.getX();
+			EC_P256_Y = ecJWK.getY();
+			
+		} catch (Exception e) {
+			throw new RuntimeException(e);
+		}
+	}
 
 	public void testConstructor() {
 
@@ -67,7 +95,7 @@ public class JWKSelectorTest extends TestCase {
 
 		List<JWK> keyList = new ArrayList<>();
 		keyList.add(new RSAKey.Builder(new Base64URL("n"), new Base64URL("e")).keyID("1").build());
-		keyList.add(new ECKey.Builder(ECKey.Curve.P_256, new Base64URL("x"), new Base64URL("y")).keyID("2").build());
+		keyList.add(new ECKey.Builder(ECKey.Curve.P_256, EC_P256_X, EC_P256_Y).keyID("2").build());
 
 		JWKSet jwkSet = new JWKSet(keyList);
 
@@ -87,7 +115,7 @@ public class JWKSelectorTest extends TestCase {
 
 		List<JWK> keyList = new ArrayList<>();
 		keyList.add(new RSAKey.Builder(new Base64URL("n"), new Base64URL("e")).keyID("1").build());
-		keyList.add(new ECKey.Builder(ECKey.Curve.P_256, new Base64URL("x"), new Base64URL("y")).keyID("2").build());
+		keyList.add(new ECKey.Builder(ECKey.Curve.P_256, EC_P256_X, EC_P256_Y).keyID("2").build());
 
 		JWKSet jwkSet = new JWKSet(keyList);
 
@@ -111,7 +139,7 @@ public class JWKSelectorTest extends TestCase {
 
 		List<JWK> keyList = new ArrayList<>();
 		keyList.add(new RSAKey.Builder(new Base64URL("n"), new Base64URL("e")).keyID("1").keyUse(KeyUse.ENCRYPTION).build());
-		keyList.add(new ECKey.Builder(ECKey.Curve.P_256, new Base64URL("x"), new Base64URL("y")).keyID("2").build());
+		keyList.add(new ECKey.Builder(ECKey.Curve.P_256, EC_P256_X, EC_P256_Y).keyID("2").build());
 
 		JWKSet jwkSet = new JWKSet(keyList);
 
@@ -132,8 +160,8 @@ public class JWKSelectorTest extends TestCase {
 
 		List<JWK> keyList = new ArrayList<>();
 		keyList.add(new RSAKey.Builder(new Base64URL("n"), new Base64URL("e")).keyID("1").keyUse(KeyUse.SIGNATURE).build());
-		keyList.add(new ECKey.Builder(ECKey.Curve.P_256, new Base64URL("x"), new Base64URL("y")).keyID("2").build());
-		keyList.add(new ECKey.Builder(ECKey.Curve.P_256, new Base64URL("x"), new Base64URL("y")).keyID("3").keyUse(KeyUse.ENCRYPTION).build());
+		keyList.add(new ECKey.Builder(ECKey.Curve.P_256, EC_P256_X, EC_P256_Y).keyID("2").build());
+		keyList.add(new ECKey.Builder(ECKey.Curve.P_256, EC_P256_X, EC_P256_Y).keyID("3").keyUse(KeyUse.ENCRYPTION).build());
 
 		JWKSet jwkSet = new JWKSet(keyList);
 
@@ -159,7 +187,7 @@ public class JWKSelectorTest extends TestCase {
 		List<JWK> keyList = new ArrayList<>();
 		keyList.add(new RSAKey.Builder(new Base64URL("n"), new Base64URL("e")).keyID("1")
 			.keyOperations(new HashSet<>(Arrays.asList(KeyOperation.SIGN, KeyOperation.VERIFY))).build());
-		keyList.add(new ECKey.Builder(ECKey.Curve.P_256, new Base64URL("x"), new Base64URL("y")).keyID("2").build());
+		keyList.add(new ECKey.Builder(ECKey.Curve.P_256, EC_P256_X, EC_P256_Y).keyID("2").build());
 
 		JWKSet jwkSet = new JWKSet(keyList);
 
@@ -180,8 +208,8 @@ public class JWKSelectorTest extends TestCase {
 		List<JWK> keyList = new ArrayList<>();
 		keyList.add(new RSAKey.Builder(new Base64URL("n"), new Base64URL("e")).keyID("1")
 			.keyOperations(new HashSet<>(Collections.singletonList(KeyOperation.SIGN))).build());
-		keyList.add(new ECKey.Builder(ECKey.Curve.P_256, new Base64URL("x"), new Base64URL("y")).keyID("2").build());
-		keyList.add(new ECKey.Builder(ECKey.Curve.P_256, new Base64URL("x"), new Base64URL("y")).keyID("3")
+		keyList.add(new ECKey.Builder(ECKey.Curve.P_256, EC_P256_X, EC_P256_Y).keyID("2").build());
+		keyList.add(new ECKey.Builder(ECKey.Curve.P_256, EC_P256_X, EC_P256_Y).keyID("3")
 			.keyOperations(new HashSet<>(Collections.singletonList(KeyOperation.ENCRYPT))).build());
 
 		JWKSet jwkSet = new JWKSet(keyList);

programming_language: Java
filename: JWKSetTest.java
change_type: ModificationType.MODIFY
diff: @@ -35,6 +35,7 @@ import java.security.interfaces.ECPrivateKey;
 import java.security.interfaces.ECPublicKey;
 import java.security.interfaces.RSAPrivateKey;
 import java.security.interfaces.RSAPublicKey;
+import java.security.spec.ECParameterSpec;
 import java.text.ParseException;
 import java.util.Arrays;
 import java.util.Date;
@@ -63,7 +64,7 @@ import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
  * Tests JSON Web Key (JWK) set parsing and serialisation.
  *
  * @author Vladimir Dzhuvinov
- * @version 2017-04-09
+ * @version 2017-04-13
  */
 public class JWKSetTest extends TestCase {
 
@@ -138,10 +139,15 @@ public class JWKSetTest extends TestCase {
 
 	public void testSerializeAndParsePublicJWKSet()
 		throws Exception {
-
-		ECKey ecKey = new ECKey.Builder(ECKey.Curve.P_256,
-			new Base64URL("abc"),
-			new Base64URL("def"))
+		
+		ECParameterSpec ecParameterSpec = ECKey.Curve.P_256.toECParameterSpec();
+		
+		KeyPairGenerator generator = KeyPairGenerator.getInstance("EC");
+		generator.initialize(ecParameterSpec);
+		KeyPair keyPair = generator.generateKeyPair();
+		
+		ECKey ecKey = new ECKey.Builder(ECKey.Curve.P_256, (ECPublicKey)keyPair.getPublic())
+			.privateKey((ECPrivateKey) keyPair.getPrivate())
 			.keyUse(KeyUse.ENCRYPTION)
 			.algorithm(JWEAlgorithm.ECDH_ES)
 			.keyID("1234")
@@ -172,25 +178,25 @@ public class JWKSetTest extends TestCase {
 		assertEquals(2, keySet.getKeys().size());
 
 		// Check first EC key
-		ecKey = (ECKey)keySet.getKeys().get(0);
-		assertNotNull(ecKey);
-		assertEquals(ECKey.Curve.P_256, ecKey.getCurve());
-		assertEquals("abc", ecKey.getX().toString());
-		assertEquals("def", ecKey.getY().toString());
-		assertEquals(KeyUse.ENCRYPTION, ecKey.getKeyUse());
-		assertNull(ecKey.getKeyOperations());
-		assertEquals(JWEAlgorithm.ECDH_ES, ecKey.getAlgorithm());
-		assertEquals("1234", ecKey.getKeyID());
+		ECKey ecKeyOut = (ECKey)keySet.getKeys().get(0);
+		assertNotNull(ecKeyOut);
+		assertEquals(ECKey.Curve.P_256, ecKeyOut.getCurve());
+		assertEquals(ecKey.getX(), ecKeyOut.getX());
+		assertEquals(ecKey.getY(), ecKeyOut.getY());
+		assertEquals(KeyUse.ENCRYPTION, ecKeyOut.getKeyUse());
+		assertNull(ecKeyOut.getKeyOperations());
+		assertEquals(JWEAlgorithm.ECDH_ES, ecKeyOut.getAlgorithm());
+		assertEquals("1234", ecKeyOut.getKeyID());
 
 		// Check second RSA key
-		rsaKey = (RSAKey)keySet.getKeys().get(1);
-		assertNotNull(rsaKey);
-		assertEquals("abc", rsaKey.getModulus().toString());
-		assertEquals("def", rsaKey.getPublicExponent().toString());
-		assertEquals(KeyUse.SIGNATURE, rsaKey.getKeyUse());
-		assertNull(rsaKey.getKeyOperations());
-		assertEquals(JWSAlgorithm.RS256, rsaKey.getAlgorithm());
-		assertEquals("5678", rsaKey.getKeyID());
+		RSAKey rsaKeyOut = (RSAKey)keySet.getKeys().get(1);
+		assertNotNull(rsaKeyOut);
+		assertEquals("abc", rsaKeyOut.getModulus().toString());
+		assertEquals("def", rsaKeyOut.getPublicExponent().toString());
+		assertEquals(KeyUse.SIGNATURE, rsaKeyOut.getKeyUse());
+		assertNull(rsaKeyOut.getKeyOperations());
+		assertEquals(JWSAlgorithm.RS256, rsaKeyOut.getAlgorithm());
+		assertEquals("5678", rsaKeyOut.getKeyID());
 
 		// Check additional JWKSet members
 		assertEquals(1, keySet.getAdditionalMembers().size());

programming_language: Java