CVE-2017-12974: Improper Verification of Cryptographic Signature (CWE-347)
value: 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.
CWE description: The product does not verify, or incorrectly verifies, the cryptographic signature for data.
CVSS v3 base score: 7.5
Published: 2017-08-20T16:29Z
Repository: https://bitbucket.org/connect2id/nimbus-jose-jwt
Language: Java
Files changed: CHANGELOG.txt, src/main/java/com/nimbusds/jose/crypto/ECDH.java, src/main/java/com/nimbusds/jose/crypto/ECDHDecrypter.java, src/main/java/com/nimbusds/jose/crypto/ECDSA.java, src/main/java/com/nimbusds/jose/crypto/ECDSAProvider.java, src/main/java/com/nimbusds/jose/crypto/ECDSAVerifier.java, src/main/java/com/nimbusds/jose/crypto/utils/ECChecks.java, src/main/java/com/nimbusds/jose/crypto/utils/package-info.java, src/main/java/com/nimbusds/jose/jwk/ECKey.java, src/test/java/com/nimbusds/jose/crypto/ECDHCryptoTest.java, src/test/java/com/nimbusds/jose/crypto/ECDHCurveCheckTest.java, src/test/java/com/nimbusds/jose/crypto/ECDHTest.java, src/test/java/com/nimbusds/jose/crypto/utils/ECChecksTest.java, src/test/java/com/nimbusds/jose/jwk/ECKeyTest.java, src/test/java/com/nimbusds/jose/jwk/JWKMatcherTest.java, src/test/java/com/nimbusds/jose/jwk/JWKSelectorTest.java, src/test/java/com/nimbusds/jose/jwk/JWKSetTest.java
Commit date: 2017-04-13 12:26:07 +0300
Commit message: Adds EC JWK constructor checks for x and y being on crv (iss #217)

Diff: diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index c638ab5..ecc175b 100644
--- a/CHANGELOG.txt
+++ b/CHANGELOG.txt
@@ -685,5 +685,11 @@ version 4.35 (2017-04-09)
     * Upgraded JSON Smart dependency to support version range from 1.3.1 to
       2.3.
     * 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).
+
diff --git a/src/main/java/com/nimbusds/jose/crypto/ECDH.java b/src/main/java/com/nimbusds/jose/crypto/ECDH.java
index 20e5f2d..961ad84 100644
--- a/src/main/java/com/nimbusds/jose/crypto/ECDH.java
+++ b/src/main/java/com/nimbusds/jose/crypto/ECDH.java
@@ -16,22 +16,16 @@
  */
 
 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;
 
 import com.nimbusds.jose.EncryptionMethod;
@@ -42,11 +36,11 @@ 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 {
 
 
 	/**
@@ -76,11 +70,11 @@ class ECDH {
 	 *
 	 * @return The algorithm mode.
 	 *
 	 * @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)) {
 
 			return AlgorithmMode.DIRECT;
@@ -111,11 +105,11 @@ class ECDH {
 	 * @return The bit length of the shared key.
 	 *
 	 * @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)) {
 
 			int length = enc.cekBitLength();
@@ -154,13 +148,13 @@ class ECDH {
 	 *
 	 * @return The derived shared secret ('Z'), with algorithm "AES".
 	 *
 	 * @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
 		KeyAgreement keyAgreement;
 
@@ -199,13 +193,13 @@ class ECDH {
 	 *
 	 * @return The derived shared key.
 	 *
 	 * @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());
 
 		// Set the alg ID for the concat KDF
@@ -230,51 +224,12 @@ class ECDH {
 			ConcatKDF.encodeDataWithLength(header.getAgreementPartyUInfo()),
 			ConcatKDF.encodeDataWithLength(header.getAgreementPartyVInfo()),
 			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.
 	 */
 	private ECDH() {
 
diff --git a/src/main/java/com/nimbusds/jose/crypto/ECDHDecrypter.java b/src/main/java/com/nimbusds/jose/crypto/ECDHDecrypter.java
index 6f0830b..e8920e6 100644
--- a/src/main/java/com/nimbusds/jose/crypto/ECDHDecrypter.java
+++ b/src/main/java/com/nimbusds/jose/crypto/ECDHDecrypter.java
@@ -19,14 +19,14 @@ 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;
 
 
 /**
@@ -69,11 +69,11 @@ import com.nimbusds.jose.util.Base64URL;
  *     <li>{@link com.nimbusds.jose.EncryptionMethod#A128CBC_HS256_DEPRECATED}
  *     <li>{@link com.nimbusds.jose.EncryptionMethod#A256CBC_HS512_DEPRECATED}
  * </ul>
  *
  * @author Vladimir Dzhuvinov
- * @version 2017-02-28
+ * @version 2017-04-13
  */
 public class ECDHDecrypter extends ECDHCryptoProvider implements JWEDecrypter, CriticalHeaderParamsAware {
 
 
 	/**
@@ -190,11 +190,13 @@ 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(
 			ephemeralPublicKey,
 			privateKey,
diff --git a/src/main/java/com/nimbusds/jose/crypto/ECDSA.java b/src/main/java/com/nimbusds/jose/crypto/ECDSA.java
index 5ad65d1..4c53343 100644
--- a/src/main/java/com/nimbusds/jose/crypto/ECDSA.java
+++ b/src/main/java/com/nimbusds/jose/crypto/ECDSA.java
@@ -175,20 +175,20 @@ class ECDSA {
 	 */
 	public static byte[] transcodeSignatureToConcat(final byte[] derSignature, int outputLength)
 		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;
 		if (derSignature[1] > 0) {
 			offset = 2;
 		} 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];
 
 		int i;
@@ -208,11 +208,11 @@ class ECDSA {
 
 		if ((derSignature[offset - 1] & 0xff) != derSignature.length - offset
 			|| (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];
 
 		System.arraycopy(derSignature, (offset + 2 + rLength) - i, concatSignature, rawLen - i, i);
diff --git a/src/main/java/com/nimbusds/jose/crypto/ECDSAProvider.java b/src/main/java/com/nimbusds/jose/crypto/ECDSAProvider.java
index 29e38dc..4c82dce 100644
--- a/src/main/java/com/nimbusds/jose/crypto/ECDSAProvider.java
+++ b/src/main/java/com/nimbusds/jose/crypto/ECDSAProvider.java
@@ -37,11 +37,11 @@ import com.nimbusds.jose.JWSAlgorithm;
  *     <li>{@link com.nimbusds.jose.JWSAlgorithm#ES512}
  * </ul>
  * 
  * @author Axel Nennker
  * @author Vladimir Dzhuvinov
- * @version 2015-06-07
+ * @version 2017-05-13
  */
 abstract class ECDSAProvider extends BaseJWSProvider {
 
 
 	/**
@@ -75,7 +75,20 @@ abstract class ECDSAProvider extends BaseJWSProvider {
 
 		if (! SUPPORTED_ALGORITHMS.contains(alg)) {
 			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();
+	}
 }
 
diff --git a/src/main/java/com/nimbusds/jose/crypto/ECDSAVerifier.java b/src/main/java/com/nimbusds/jose/crypto/ECDSAVerifier.java
index 906cf13..e8f5589 100644
--- a/src/main/java/com/nimbusds/jose/crypto/ECDSAVerifier.java
+++ b/src/main/java/com/nimbusds/jose/crypto/ECDSAVerifier.java
@@ -22,15 +22,15 @@ import java.security.InvalidKeyException;
 import java.security.Signature;
 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;
 
 
 /**
  * Elliptic Curve Digital Signature Algorithm (ECDSA) verifier of 
  * {@link com.nimbusds.jose.JWSObject JWS objects}. Expects a private EC key
@@ -50,11 +50,11 @@ import com.nimbusds.jose.util.Base64URL;
  *     <li>{@link com.nimbusds.jose.JWSAlgorithm#ES512}
  * </ul>
  * 
  * @author Axel Nennker
  * @author Vladimir Dzhuvinov
- * @version 2015-06-07
+ * @version 2017-04-13
  */
 @ThreadSafe
 public class ECDSAVerifier extends ECDSAProvider implements JWSVerifier, CriticalHeaderParamsAware {
 
 
@@ -81,12 +81,11 @@ public class ECDSAVerifier extends ECDSAProvider implements JWSVerifier, Critica
 	public ECDSAVerifier(final ECPublicKey publicKey)
 		throws JOSEException {
 
 		this(publicKey, null);
 	}
-
-
+	
 
 	/**
 	 * Creates a new Elliptic Curve Digital Signature Algorithm (ECDSA)
 	 * verifier.
 	 *
@@ -116,10 +115,16 @@ public class ECDSAVerifier extends ECDSAProvider implements JWSVerifier, Critica
 		throws JOSEException {
 
 		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);
 	}
 
 
diff --git a/src/main/java/com/nimbusds/jose/crypto/utils/ECChecks.java b/src/main/java/com/nimbusds/jose/crypto/utils/ECChecks.java
new file mode 100644
index 0000000..e2bc226
--- /dev/null
+++ b/src/main/java/com/nimbusds/jose/crypto/utils/ECChecks.java
@@ -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() {}
+}
diff --git a/src/main/java/com/nimbusds/jose/crypto/utils/package-info.java b/src/main/java/com/nimbusds/jose/crypto/utils/package-info.java
new file mode 100644
index 0000000..d5b3ec6
--- /dev/null
+++ b/src/main/java/com/nimbusds/jose/crypto/utils/package-info.java
@@ -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
diff --git a/src/main/java/com/nimbusds/jose/jwk/ECKey.java b/src/main/java/com/nimbusds/jose/jwk/ECKey.java
index f9e114f..37bb598 100644
--- a/src/main/java/com/nimbusds/jose/jwk/ECKey.java
+++ b/src/main/java/com/nimbusds/jose/jwk/ECKey.java
@@ -35,10 +35,11 @@ import java.util.List;
 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;
 import com.nimbusds.jose.util.JSONObjectUtils;
 import net.jcip.annotations.Immutable;
@@ -902,10 +903,32 @@ 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");
+		}
+	}
 
 
 	/**
 	 * Creates a new public Elliptic Curve JSON Web Key (JWK) with the 
 	 * specified parameters.
@@ -958,10 +981,12 @@ public final class ECKey extends JWK implements AssymetricJWK {
 		if (y == null) {
 			throw new IllegalArgumentException("The 'y' coordinate must not be null");
 		}
 
 		this.y = y;
+		
+		ensurePublicCoordinatesOnCurve(crv, x, y);
 
 		this.d = null;
 		
 		this.privateKey = null;
 	}
@@ -1024,10 +1049,12 @@ public final class ECKey extends JWK implements AssymetricJWK {
 			throw new IllegalArgumentException("The 'y' coordinate must not be null");
 		}
 
 		this.y = y;
 		
+		ensurePublicCoordinatesOnCurve(crv, x, y);
+		
 		if (d == null) {
 			throw new IllegalArgumentException("The 'd' coordinate must not be null");
 		}
 
 		this.d = d;
@@ -1090,10 +1117,12 @@ public final class ECKey extends JWK implements AssymetricJWK {
 			throw new IllegalArgumentException("The 'y' coordinate must not be null");
 		}
 
 		this.y = y;
 		
+		ensurePublicCoordinatesOnCurve(crv, x, y);
+		
 		d = null;
 		
 		this.privateKey = priv;
 	}
 
diff --git a/src/test/java/com/nimbusds/jose/crypto/ECDHCryptoTest.java b/src/test/java/com/nimbusds/jose/crypto/ECDHCryptoTest.java
index d1f0f7e..a493d3b 100644
--- a/src/test/java/com/nimbusds/jose/crypto/ECDHCryptoTest.java
+++ b/src/test/java/com/nimbusds/jose/crypto/ECDHCryptoTest.java
@@ -48,11 +48,11 @@ 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 {
 
 
 	private static ECKey generateECJWK(final ECKey.Curve curve)
@@ -702,35 +702,10 @@ public class ECDHCryptoTest extends TestCase {
 			// ok
 		}
 	}
 
 
-	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 {
 
 		ECKey ecJWK = generateECJWK(ECKey.Curve.P_256);
 
diff --git a/src/test/java/com/nimbusds/jose/crypto/ECDHCurveCheckTest.java b/src/test/java/com/nimbusds/jose/crypto/ECDHCurveCheckTest.java
index d057b88..3e53176 100644
--- a/src/test/java/com/nimbusds/jose/crypto/ECDHCurveCheckTest.java
+++ b/src/test/java/com/nimbusds/jose/crypto/ECDHCurveCheckTest.java
@@ -22,20 +22,22 @@ import java.math.BigInteger;
 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.text.ParseException;
 
 import com.nimbusds.jose.*;
 import com.nimbusds.jose.crypto.bc.BouncyCastleProviderSingleton;
 import com.nimbusds.jose.jwk.ECKey;
 import com.nimbusds.jose.util.Base64URL;
 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 {
 	
 	
 	private static ECKey generateECJWK(final ECKey.Curve curve)
@@ -108,22 +110,29 @@ public class ECDHCurveCheckTest extends TestCase {
 //			+ receiverPrivateKeyModAttackerOrderGroup1 + " mod "
 //			+ attackerOrderGroup1);
 		
 		// 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());
 		
 		// THIS CAN BE DOIN MANY TIME
@@ -158,19 +167,26 @@ public class ECDHCurveCheckTest extends TestCase {
 //			+ attackerOrderGroup2);
 		
 		// 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.",
 //			jweObject2.getPayload().toString());
 		
diff --git a/src/test/java/com/nimbusds/jose/crypto/ECDHTest.java b/src/test/java/com/nimbusds/jose/crypto/ECDHTest.java
index e13eb7c..b1daa4c 100644
--- a/src/test/java/com/nimbusds/jose/crypto/ECDHTest.java
+++ b/src/test/java/com/nimbusds/jose/crypto/ECDHTest.java
@@ -16,30 +16,23 @@
  */
 
 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;
 import junit.framework.TestCase;
 
 
 /**
  * Tests the ECDH key agreement derivation.
  *
- * @version 2017-02-28
+ * @version 2017-04-13
  */
 public class ECDHTest extends TestCase{
 
 
 	public void testDerive256BitSecret()
@@ -124,81 +117,6 @@ public class ECDHTest extends TestCase{
 			(byte)251, (byte) 49, (byte)110, (byte)163, (byte)218, (byte)128, (byte)106, (byte) 72,
 			(byte)246, (byte)218, (byte)167, (byte)121, (byte)140, (byte)254, (byte)144, (byte)196 };
 
 		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());
-		}
-	}
 }
diff --git a/src/test/java/com/nimbusds/jose/crypto/utils/ECChecksTest.java b/src/test/java/com/nimbusds/jose/crypto/utils/ECChecksTest.java
new file mode 100644
index 0000000..c83db4e
--- /dev/null
+++ b/src/test/java/com/nimbusds/jose/crypto/utils/ECChecksTest.java
@@ -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));
+	}
+}
diff --git a/src/test/java/com/nimbusds/jose/jwk/ECKeyTest.java b/src/test/java/com/nimbusds/jose/jwk/ECKeyTest.java
index 6b7a1b8..946943b 100644
--- a/src/test/java/com/nimbusds/jose/jwk/ECKeyTest.java
+++ b/src/test/java/com/nimbusds/jose/jwk/ECKeyTest.java
@@ -25,10 +25,13 @@ import java.nio.charset.Charset;
 import java.security.*;
 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;
 import com.nimbusds.jose.JWSAlgorithm;
 import com.nimbusds.jose.crypto.bc.BouncyCastleProviderSingleton;
@@ -48,11 +51,11 @@ 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 {
 
 
 	// Test parameters are from JWK spec
@@ -138,17 +141,17 @@ public class ECKeyTest extends TestCase {
 		assertEquals(384, new ECKey.Builder(ExampleKeyP384Alt.CRV, ExampleKeyP384Alt.X, ExampleKeyP384Alt.Y).build().size());
 		assertEquals(521, new ECKey.Builder(ExampleKeyP521Alt.CRV, ExampleKeyP521Alt.X, ExampleKeyP521Alt.Y).build().size());
 	}
 
 
-	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());
 		}
 	}
 
 
 	public void testAltECKeyParamLengths() {
@@ -996,6 +999,99 @@ public class ECKeyTest extends TestCase {
 		char[] password = "secret".toCharArray();
 		keyStore.load(null, password);
 		
 		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
diff --git a/src/test/java/com/nimbusds/jose/jwk/JWKMatcherTest.java b/src/test/java/com/nimbusds/jose/jwk/JWKMatcherTest.java
index 373e8c6..1ba18a8 100644
--- a/src/test/java/com/nimbusds/jose/jwk/JWKMatcherTest.java
+++ b/src/test/java/com/nimbusds/jose/jwk/JWKMatcherTest.java
@@ -16,11 +16,16 @@
  */
 
 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;
 
 import com.nimbusds.jose.Algorithm;
 import com.nimbusds.jose.JWSAlgorithm;
@@ -31,13 +36,38 @@ 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() {
 
 		JWKMatcher matcher = new JWKMatcher(null, null, null, null, null, false, false, 0, 0, null);
@@ -389,45 +419,45 @@ public class JWKMatcherTest extends TestCase {
 	public void testMatchType() {
 
 		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());
 	}
 
 
 	public void testMatchTwoTypes() {
 
 		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());
 	}
 
 
 	public void testMatchUse() {
 
 		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());
 	}
 
 
 	public void testMatchUseNotSpecifiedOrSignature() {
 
 		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());
 	}
 
 
@@ -435,11 +465,11 @@ public class JWKMatcherTest extends TestCase {
 
 		JWKMatcher matcher = new JWKMatcher.Builder().keyOperation(KeyOperation.DECRYPT).build();
 
 		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());
 	}
 
 
@@ -447,11 +477,11 @@ public class JWKMatcherTest extends TestCase {
 
 		JWKMatcher matcher = new JWKMatcher.Builder().keyOperations(new LinkedHashSet<>(Arrays.asList(KeyOperation.SIGN, KeyOperation.VERIFY))).build();
 
 		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());
 	}
 
 
@@ -460,13 +490,13 @@ public class JWKMatcherTest extends TestCase {
 		JWKMatcher matcher = new JWKMatcher.Builder().keyOperations(KeyOperation.SIGN, null).build();
 
 		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());
 	}
 
diff --git a/src/test/java/com/nimbusds/jose/jwk/JWKSelectorTest.java b/src/test/java/com/nimbusds/jose/jwk/JWKSelectorTest.java
index 4581cee..bf06fed 100644
--- a/src/test/java/com/nimbusds/jose/jwk/JWKSelectorTest.java
+++ b/src/test/java/com/nimbusds/jose/jwk/JWKSelectorTest.java
@@ -16,10 +16,15 @@
  */
 
 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;
 
 import com.nimbusds.jose.JWSAlgorithm;
@@ -28,14 +33,37 @@ 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() {
 
 		JWKMatcher matcher = new JWKMatcher(null, null, null, null, null, false, false);
 
@@ -65,11 +93,11 @@ public class JWKSelectorTest extends TestCase {
 
 		JWKSelector selector = new JWKSelector(new JWKMatcher.Builder().keyType(KeyType.RSA).build());
 
 		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);
 
 		List<JWK> matches = selector.select(jwkSet);
 
@@ -85,11 +113,11 @@ public class JWKSelectorTest extends TestCase {
 
 		JWKSelector selector = new JWKSelector(new JWKMatcher.Builder().keyTypes(KeyType.RSA, KeyType.EC).build());
 
 		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);
 
 		List<JWK> matches = selector.select(jwkSet);
 
@@ -109,11 +137,11 @@ public class JWKSelectorTest extends TestCase {
 
 		JWKSelector selector = new JWKSelector(new JWKMatcher.Builder().keyUse(KeyUse.ENCRYPTION).build());
 
 		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);
 
 		List<JWK> matches = selector.select(jwkSet);
 
@@ -130,12 +158,12 @@ public class JWKSelectorTest extends TestCase {
 
 		JWKSelector selector = new JWKSelector(new JWKMatcher.Builder().keyUses(KeyUse.SIGNATURE, null).build());
 
 		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);
 
 		List<JWK> matches = selector.select(jwkSet);
 
@@ -157,11 +185,11 @@ public class JWKSelectorTest extends TestCase {
 		JWKSelector selector = new JWKSelector(new JWKMatcher.Builder().keyOperations(KeyOperation.SIGN, KeyOperation.VERIFY).build());
 
 		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);
 
 		List<JWK> matches = selector.select(jwkSet);
 
@@ -178,12 +206,12 @@ public class JWKSelectorTest extends TestCase {
 		JWKSelector selector = new JWKSelector(new JWKMatcher.Builder().keyOperations(KeyOperation.SIGN, null).build());
 
 		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);
 
 		List<JWK> matches = selector.select(jwkSet);
diff --git a/src/test/java/com/nimbusds/jose/jwk/JWKSetTest.java b/src/test/java/com/nimbusds/jose/jwk/JWKSetTest.java
index 60019cb..52f2e62 100644
--- a/src/test/java/com/nimbusds/jose/jwk/JWKSetTest.java
+++ b/src/test/java/com/nimbusds/jose/jwk/JWKSetTest.java
@@ -33,10 +33,11 @@ import java.security.cert.Certificate;
 import java.security.cert.X509Certificate;
 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;
 import java.util.LinkedList;
 import java.util.List;
@@ -61,11 +62,11 @@ 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 {
 
 
 	public void testParsePublicJWKSet()
@@ -136,14 +137,19 @@ 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")
 			.build();
 
@@ -170,29 +176,29 @@ public class JWKSetTest extends TestCase {
 
 		assertNotNull(keySet);
 		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());
 		assertEquals("xyz123", (String)keySet.getAdditionalMembers().get("setID"));
 	}

Vulnerable code: import java.math.BigInteger;
import java.security.spec.ECFieldFp;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPoint;
import java.security.spec.EllipticCurve;

 * @version 2017-02-28
	public static AlgorithmMode resolveAlgorithmMode(final JWEAlgorithm alg)
	public static int sharedKeyLength(final JWEAlgorithm alg, final EncryptionMethod enc)
	public static SecretKey deriveSharedSecret(final ECPublicKey publicKey,
						   final ECPrivateKey privateKey,
						   final Provider provider)
	public static SecretKey deriveSharedKey(final JWEHeader header,
						final SecretKey Z,
						final ConcatKDF concatKDF)
	
	
	/**
	 * 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");
		}
	}


 * @version 2017-02-28
		ECDH.ensurePointOnCurve(ephemeralPublicKey, getPrivateKey());
			throw new JOSEException("Invalid  ECDSA signature format");
			throw new JOSEException("Invalid  ECDSA signature format");
			throw new JOSEException("Invalid  ECDSA signature format");
 * @version 2015-06-07
import net.jcip.annotations.ThreadSafe;

 * @version 2015-06-07


 * @version 2015-09-18
	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
		}
	}


 * Submitted by Antonio Sanso. See iss #210.
		JWEObject jweObject1 = JWEObject.parse(maliciousJWE1);
		
		ECDHDecrypter decrypter = new ECDHDecrypter(ecJWK.toECPrivateKey());
//		decrypter.getJCAContext().setKeyEncryptionProvider(BouncyCastleProviderSingleton.getInstance());
			jweObject1.decrypt(decrypter);
		} catch (JOSEException e) {
			assertEquals("Invalid ephemeral public key: Point not on expected curve", e.getMessage());
		JWEObject jweObject2 = JWEObject.parse(maliciousJWE2);
//		decrypter.getJCAContext().setContentEncryptionProvider(BouncyCastleProviderSingleton.getInstance());
			jweObject2.decrypt(decrypter);
		} catch (JOSEException e) {
			assertEquals("Invalid ephemeral public key: Point not on expected curve", e.getMessage());
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.JOSEException;
import com.nimbusds.jose.JWEObject;
 * @version 2017-02-28
	
	
	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());
		}
	}
 * @version 2017-04-09
	public void testKeySizeForUnknownCurve() {
			new ECKey.Builder(new ECKey.Curve("unknown"), ExampleKeyP256.X, ExampleKeyP256.Y).build().size();
		} catch (UnsupportedOperationException e) {
			assertEquals("Couldn't determine field size for curve unknown", e.getMessage());
 * @version 2016-08-24
		assertFalse(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, 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("2").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()));
		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, new Base64URL("x"), new Base64URL("y")).keyID("2").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")
 * @version 2015-04-15

		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("2").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("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, 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("2").build());
		keyList.add(new ECKey.Builder(ECKey.Curve.P_256, new Base64URL("x"), new Base64URL("y")).keyID("3")
 * @version 2017-04-09

		ECKey ecKey = new ECKey.Builder(ECKey.Curve.P_256,
			new Base64URL("abc"),
			new Base64URL("def"))
		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());
		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());
Fixed code: 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).

 * @version 2017-04-13
	static AlgorithmMode resolveAlgorithmMode(final JWEAlgorithm alg)
	static int sharedKeyLength(final JWEAlgorithm alg, final EncryptionMethod enc)
	static SecretKey deriveSharedSecret(final ECPublicKey publicKey,
					    final ECPrivateKey privateKey,
					    final Provider provider)
	static SecretKey deriveSharedKey(final JWEHeader header,
					 final SecretKey Z,
					 final ConcatKDF concatKDF)
	
import com.nimbusds.jose.crypto.utils.ECChecks;
 * @version 2017-04-13
		if (! ECChecks.isPointOnCurve(ephemeralPublicKey, getPrivateKey())) {
			throw new JOSEException("Invalid ephemeral public EC key: Point(s) not on the expected curve");
		}
			throw new JOSEException("Invalid ECDSA signature format");
			throw new JOSEException("Invalid ECDSA signature format");
			throw new JOSEException("Invalid ECDSA signature format");
 * @version 2017-05-13
	
	
	/**
	 * Returns the supported ECDSA algorithm.
	 *
	 * @see #supportedECDSAAlgorithm()
	 *
	 * @return The supported ECDSA algorithm.
	 */
	public JWSAlgorithm supportedECDSAAlgorithm() {
		
		return supportedJWSAlgorithms().iterator().next();
	}
import com.nimbusds.jose.crypto.utils.ECChecks;
import net.jcip.annotations.ThreadSafe;
 * @version 2017-04-13
	
		
		if (! ECChecks.isPointOnCurve(
			publicKey,
			ECKey.Curve.forJWSAlgoritm(supportedECDSAAlgorithm()).toECParameterSpec())) {
			throw new JOSEException("Curve / public key parameters mismatch");
		}
/*
 * 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() {}
}
/*
 * 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;
import com.nimbusds.jose.crypto.utils.ECChecks;
	
	
	/**
	 * 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");
		}
	}
		
		ensurePublicCoordinatesOnCurve(crv, x, y);
		ensurePublicCoordinatesOnCurve(crv, x, y);
		
		ensurePublicCoordinatesOnCurve(crv, x, y);
		
 * @version 2017-04-13
import java.text.ParseException;
 * Submitted by Antonio Sanso. See iss #210. Modified to suit new checks for
 * iss #217.
		JWEObject jweObject1 = null;
			jweObject1 = JWEObject.parse(maliciousJWE1);
		} 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());
//		}
		
		JWEObject jweObject2 = null;
			jweObject2 = JWEObject.parse(maliciousJWE2);
		} 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());
//		}
 * @version 2017-04-13
/*
 * 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));
	}
}
import java.security.spec.ECPoint;
import java.security.spec.ECPublicKeySpec;
import java.security.spec.InvalidKeySpecException;
 * @version 2017-04-13
	public void testUnknownCurve() {
			new ECKey.Builder(new ECKey.Curve("unknown"), ExampleKeyP256.X, ExampleKeyP256.Y).build();
		} catch (IllegalStateException e) {
			assertEquals("Unknown / unsupported curve: unknown", e.getMessage());
	
	
	// 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());
		}
	}
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECParameterSpec;
 * @version 2017-04-13
	
	
	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);
		}
	}
		assertFalse(matcher.matches(new ECKey.Builder(ECKey.Curve.P_256, EC_P256_X, EC_P256_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,EC_P256_X, EC_P256_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, EC_P256_X, EC_P256_Y).keyID("3").keyUse(KeyUse.ENCRYPTION).build()));
		assertFalse(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("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, EC_P256_X, EC_P256_Y).keyID("3")
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECParameterSpec;
 * @version 2017-04-13
	
	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);
		}
	}
		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("2").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("2").build());
		keyList.add(new ECKey.Builder(ECKey.Curve.P_256, EC_P256_X, EC_P256_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("2").build());
		keyList.add(new ECKey.Builder(ECKey.Curve.P_256, EC_P256_X, EC_P256_Y).keyID("3")
import java.security.spec.ECParameterSpec;
 * @version 2017-04-13
		
		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())
		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());
		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());