8182999: SunEC throws ProviderException on invalid curves
authorapetcher
Thu, 13 Jul 2017 12:24:55 +0100
changeset 45883 89df6f9465a3
parent 45882 341b124f1001
child 45884 a9b4ac260f46
8182999: SunEC throws ProviderException on invalid curves Reviewed-by: vinnie
jdk/make/mapfiles/libsunec/mapfile-vers
jdk/src/java.base/share/classes/sun/security/util/ECUtil.java
jdk/src/jdk.crypto.ec/share/classes/sun/security/ec/ECKeyPairGenerator.java
jdk/src/jdk.crypto.ec/share/native/libsunec/ECC_JNI.cpp
jdk/test/sun/security/ec/InvalidCurve.java
--- a/jdk/make/mapfiles/libsunec/mapfile-vers	Wed Jul 12 14:30:00 2017 -0700
+++ b/jdk/make/mapfiles/libsunec/mapfile-vers	Thu Jul 13 12:24:55 2017 +0100
@@ -1,5 +1,5 @@
 #
-# Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved.
 # DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 #
 # This code is free software; you can redistribute it and/or modify it
@@ -27,6 +27,7 @@
 
 SUNWprivate_1.1 {
         global:
+                Java_sun_security_ec_ECKeyPairGenerator_isCurveSupported;
                 Java_sun_security_ec_ECKeyPairGenerator_generateECKeyPair;
                 Java_sun_security_ec_ECDSASignature_signDigest;
                 Java_sun_security_ec_ECDSASignature_verifySignedDigest;
--- a/jdk/src/java.base/share/classes/sun/security/util/ECUtil.java	Wed Jul 12 14:30:00 2017 -0700
+++ b/jdk/src/java.base/share/classes/sun/security/util/ECUtil.java	Thu Jul 13 12:24:55 2017 +0100
@@ -130,7 +130,7 @@
         return (ECPrivateKey)keyFactory.generatePrivate(keySpec);
     }
 
-    private static AlgorithmParameters getECParameters(Provider p) {
+    public static AlgorithmParameters getECParameters(Provider p) {
         try {
             if (p != null) {
                 return AlgorithmParameters.getInstance("EC", p);
--- a/jdk/src/jdk.crypto.ec/share/classes/sun/security/ec/ECKeyPairGenerator.java	Wed Jul 12 14:30:00 2017 -0700
+++ b/jdk/src/jdk.crypto.ec/share/classes/sun/security/ec/ECKeyPairGenerator.java	Thu Jul 13 12:24:55 2017 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -25,12 +25,14 @@
 
 package sun.security.ec;
 
+import java.io.IOException;
 import java.math.BigInteger;
 import java.security.*;
 import java.security.spec.AlgorithmParameterSpec;
 import java.security.spec.ECGenParameterSpec;
 import java.security.spec.ECParameterSpec;
 import java.security.spec.ECPoint;
+import java.security.spec.InvalidParameterSpecException;
 
 import sun.security.ec.ECPrivateKeyImpl;
 import sun.security.ec.ECPublicKeyImpl;
@@ -85,17 +87,19 @@
     public void initialize(AlgorithmParameterSpec params, SecureRandom random)
             throws InvalidAlgorithmParameterException {
 
+        ECParameterSpec ecSpec = null;
+
         if (params instanceof ECParameterSpec) {
-            this.params = ECUtil.getECParameterSpec(null,
+            ecSpec = ECUtil.getECParameterSpec(null,
                                                     (ECParameterSpec)params);
-            if (this.params == null) {
+            if (ecSpec == null) {
                 throw new InvalidAlgorithmParameterException(
                     "Unsupported curve: " + params);
             }
         } else if (params instanceof ECGenParameterSpec) {
             String name = ((ECGenParameterSpec)params).getName();
-            this.params = ECUtil.getECParameterSpec(null, name);
-            if (this.params == null) {
+            ecSpec = ECUtil.getECParameterSpec(null, name);
+            if (ecSpec == null) {
                 throw new InvalidAlgorithmParameterException(
                     "Unknown curve name: " + name);
             }
@@ -103,11 +107,36 @@
             throw new InvalidAlgorithmParameterException(
                 "ECParameterSpec or ECGenParameterSpec required for EC");
         }
+
+        // Not all known curves are supported by the native implementation
+        ensureCurveIsSupported(ecSpec);
+        this.params = ecSpec;
+
         this.keySize =
             ((ECParameterSpec)this.params).getCurve().getField().getFieldSize();
         this.random = random;
     }
 
+    private static void ensureCurveIsSupported(ECParameterSpec ecSpec)
+        throws InvalidAlgorithmParameterException {
+
+        AlgorithmParameters ecParams = ECUtil.getECParameters(null);
+        byte[] encodedParams;
+        try {
+            ecParams.init(ecSpec);
+            encodedParams = ecParams.getEncoded();
+        } catch (InvalidParameterSpecException ex) {
+            throw new InvalidAlgorithmParameterException(
+                "Unsupported curve: " + ecSpec.toString());
+        } catch (IOException ex) {
+            throw new RuntimeException(ex);
+        }
+        if (!isCurveSupported(encodedParams)) {
+            throw new InvalidAlgorithmParameterException(
+                "Unsupported curve: " + ecParams.toString());
+        }
+    }
+
     // generate the keypair. See JCA doc
     @Override
     public KeyPair generateKeyPair() {
@@ -159,6 +188,17 @@
         this.keySize = keySize;
     }
 
+    /**
+     * Checks whether the curve in the encoded parameters is supported by the
+     * native implementation.
+     *
+     * @param encodedParams encoded parameters in the same form accepted
+     *    by generateECKeyPair
+     * @return true if and only if generateECKeyPair will succeed for
+     *    the supplied parameters
+     */
+    private static native boolean isCurveSupported(byte[] encodedParams);
+
     /*
      * Generates the keypair and returns a 2-element array of encoding bytes.
      * The first one is for the private key, the second for the public key.
--- a/jdk/src/jdk.crypto.ec/share/native/libsunec/ECC_JNI.cpp	Wed Jul 12 14:30:00 2017 -0700
+++ b/jdk/src/jdk.crypto.ec/share/native/libsunec/ECC_JNI.cpp	Thu Jul 13 12:24:55 2017 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2009, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -90,6 +90,50 @@
 
 /*
  * Class:     sun_security_ec_ECKeyPairGenerator
+ * Method:    isCurveSupported
+ * Signature: ([B)Z
+ */
+JNIEXPORT jboolean
+JNICALL Java_sun_security_ec_ECKeyPairGenerator_isCurveSupported
+  (JNIEnv *env, jclass clazz, jbyteArray encodedParams)
+{
+    SECKEYECParams params_item;
+    ECParams *ecparams = NULL;
+    jboolean result = JNI_FALSE;
+
+    // The curve is supported if we can get parameters for it
+    params_item.len = env->GetArrayLength(encodedParams);
+    params_item.data =
+        (unsigned char *) env->GetByteArrayElements(encodedParams, 0);
+    if (params_item.data == NULL) {
+        goto cleanup;
+    }
+
+    // Fill a new ECParams using the supplied OID
+    if (EC_DecodeParams(&params_item, &ecparams, 0) != SECSuccess) {
+        /* bad curve OID */
+        goto cleanup;
+    }
+
+    // If we make it to here, then the curve is supported
+    result = JNI_TRUE;
+
+cleanup:
+    {
+        if (params_item.data) {
+            env->ReleaseByteArrayElements(encodedParams,
+                (jbyte *) params_item.data, JNI_ABORT);
+        }
+        if (ecparams) {
+            FreeECParams(ecparams, true);
+        }
+    }
+
+    return result;
+}
+
+/*
+ * Class:     sun_security_ec_ECKeyPairGenerator
  * Method:    generateECKeyPair
  * Signature: (I[B[B)[[B
  */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/sun/security/ec/InvalidCurve.java	Thu Jul 13 12:24:55 2017 +0100
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8182999
+ * @summary Ensure that SunEC behaves correctly for unsupported curves.
+ * @run main InvalidCurve
+ */
+
+import java.security.*;
+import java.security.spec.*;
+import java.math.*;
+
+public class InvalidCurve {
+
+    public static void main(String[] args) {
+
+        KeyPairGenerator keyGen;
+        try {
+            keyGen = KeyPairGenerator.getInstance("EC", "SunEC");
+            ECGenParameterSpec brainpoolSpec =
+                new ECGenParameterSpec("brainpoolP256r1");
+            keyGen.initialize(brainpoolSpec);
+        } catch (InvalidAlgorithmParameterException ex) {
+            System.out.println(ex.getMessage());
+            // this is expected
+            return;
+        } catch (NoSuchAlgorithmException | NoSuchProviderException ex) {
+            throw new RuntimeException(ex);
+        }
+
+        keyGen.generateKeyPair();
+
+        // If we make it to here, then the test is not working correctly.
+        throw new RuntimeException("The expected exception was not thrown.");
+
+    }
+
+}
+