From e7c56a5f184240ebd1f902579915adbee8b58ae0 Mon Sep 17 00:00:00 2001 From: andrew Date: Mon, 17 Jun 2019 16:46:10 +0100 Subject: [PATCH] 8182999: SunEC throws ProviderException on invalid curves Reviewed-by: vinnie --- make/mapfiles/libsunec/mapfile-vers | 3 +- .../sun/security/ec/ECKeyPairGenerator.java | 48 +++++++++++++-- .../classes/sun/security/util/ECUtil.java | 2 +- src/share/native/sun/security/ec/ECC_JNI.cpp | 44 +++++++++++++ test/sun/security/ec/InvalidCurve.java | 61 +++++++++++++++++++ 5 files changed, 152 insertions(+), 6 deletions(-) create mode 100644 test/sun/security/ec/InvalidCurve.java diff --git a/make/mapfiles/libsunec/mapfile-vers b/make/mapfiles/libsunec/mapfile-vers index 329532263..7ba855202 100644 --- a/make/mapfiles/libsunec/mapfile-vers +++ b/make/mapfiles/libsunec/mapfile-vers @@ -1,5 +1,5 @@ # -# Copyright (c) 2009, 2014, 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; diff --git a/src/share/classes/sun/security/ec/ECKeyPairGenerator.java b/src/share/classes/sun/security/ec/ECKeyPairGenerator.java index 72c099466..91e1c7366 100644 --- a/src/share/classes/sun/security/ec/ECKeyPairGenerator.java +++ b/src/share/classes/sun/security/ec/ECKeyPairGenerator.java @@ -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.NamedCurve; import sun.security.ec.ECParameters; @@ -86,17 +88,19 @@ public final class ECKeyPairGenerator extends KeyPairGeneratorSpi { 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); } @@ -104,11 +108,36 @@ public final class ECKeyPairGenerator extends KeyPairGeneratorSpi { 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() { @@ -160,6 +189,17 @@ public final class ECKeyPairGenerator extends KeyPairGeneratorSpi { 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. diff --git a/src/share/classes/sun/security/util/ECUtil.java b/src/share/classes/sun/security/util/ECUtil.java index 8bdc575fb..fac103421 100644 --- a/src/share/classes/sun/security/util/ECUtil.java +++ b/src/share/classes/sun/security/util/ECUtil.java @@ -89,7 +89,7 @@ public class ECUtil { return Arrays.copyOfRange(b, i, b.length); } - private static AlgorithmParameters getECParameters(Provider p) { + public static AlgorithmParameters getECParameters(Provider p) { try { if (p != null) { return AlgorithmParameters.getInstance("EC", p); diff --git a/src/share/native/sun/security/ec/ECC_JNI.cpp b/src/share/native/sun/security/ec/ECC_JNI.cpp index b7fb6750e..0e49b3ed3 100644 --- a/src/share/native/sun/security/ec/ECC_JNI.cpp +++ b/src/share/native/sun/security/ec/ECC_JNI.cpp @@ -82,6 +82,50 @@ jbyteArray getEncodedBytes(JNIEnv *env, SECItem *hSECItem) return jEncodedBytes; } +/* + * 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(¶ms_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 diff --git a/test/sun/security/ec/InvalidCurve.java b/test/sun/security/ec/InvalidCurve.java new file mode 100644 index 000000000..9321c2617 --- /dev/null +++ b/test/sun/security/ec/InvalidCurve.java @@ -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."); + + } + +} + -- GitLab