diff --git a/jni/include/com_wolfssl_wolfcrypt_Rsa.h b/jni/include/com_wolfssl_wolfcrypt_Rsa.h index d7c30f84..fae433db 100644 --- a/jni/include/com_wolfssl_wolfcrypt_Rsa.h +++ b/jni/include/com_wolfssl_wolfcrypt_Rsa.h @@ -223,6 +223,14 @@ JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_wolfcrypt_Rsa_wc_1RsaSSL_1Verify JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_Rsa_rsaMinSize (JNIEnv *, jclass); +/* + * Class: com_wolfssl_wolfcrypt_Rsa + * Method: rsaMinExponent + * Signature: ()J + */ +JNIEXPORT jlong JNICALL Java_com_wolfssl_wolfcrypt_Rsa_rsaMinExponent + (JNIEnv *, jclass); + /* * Class: com_wolfssl_wolfcrypt_Rsa * Method: wc_RsaPSS_Sign @@ -287,6 +295,14 @@ JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_wolfcrypt_Rsa_wc_1RsaDirect JNIEXPORT jlong JNICALL Java_com_wolfssl_wolfcrypt_Rsa_getDefaultRsaExponent (JNIEnv *, jclass); +/* + * Class: com_wolfssl_wolfcrypt_Rsa + * Method: keyGenSizeAllowed + * Signature: (I)Z + */ +JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_Rsa_keyGenSizeAllowed + (JNIEnv *, jclass, jint); + #ifdef __cplusplus } #endif diff --git a/jni/jni_rsa.c b/jni/jni_rsa.c index 923ed079..8fa19d59 100644 --- a/jni/jni_rsa.c +++ b/jni/jni_rsa.c @@ -20,6 +20,7 @@ */ #include +#include #ifdef WOLFSSL_USER_SETTINGS #include @@ -98,6 +99,47 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_Rsa_rsaMinSize return (jint)RSA_MIN_SIZE; } +JNIEXPORT jlong JNICALL Java_com_wolfssl_wolfcrypt_Rsa_rsaMinExponent + (JNIEnv *env, jclass jcl) +{ + /* wc_MakeRsaKey() minimum public exponent, smallest odd e > 1 */ + jlong minExp = 3; + (void)env; + (void)jcl; + +#if !defined(NO_RSA) && defined(HAVE_FIPS) + /* FIPS 186-4/186-5 key generation requires e > 2^16 */ + minExp = WC_RSA_EXPONENT; +#endif + + return minExp; +} + +JNIEXPORT jboolean JNICALL Java_com_wolfssl_wolfcrypt_Rsa_keyGenSizeAllowed + (JNIEnv *env, jclass jcl, jint size) +{ + (void)env; + (void)jcl; + +#ifdef NO_RSA + (void)size; + return JNI_FALSE; +#else + if (size < RSA_MIN_SIZE || size > RSA_MAX_SIZE) { + return JNI_FALSE; + } + + #ifdef WC_RSA_FIPS_GEN_MIN + /* wc_MakeRsaKey_fips() minimum, defined on FIPS v6+ */ + if (size < WC_RSA_FIPS_GEN_MIN) { + return JNI_FALSE; + } + #endif + + return JNI_TRUE; +#endif +} + JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Rsa_MakeRsaKey( JNIEnv *env, jobject this, jint size, jlong e, jobject rng_object) @@ -119,7 +161,8 @@ Java_com_wolfssl_wolfcrypt_Rsa_MakeRsaKey( return; } - if (key == NULL || rng == NULL) { + /* e is passed as a C long, reject values that would be truncated */ + if (key == NULL || rng == NULL || e < LONG_MIN || e > LONG_MAX) { ret = BAD_FUNC_ARG; } else { diff --git a/src/main/java/com/wolfssl/provider/jce/WolfCryptKeyPairGenerator.java b/src/main/java/com/wolfssl/provider/jce/WolfCryptKeyPairGenerator.java index c2f4503a..b4afe843 100644 --- a/src/main/java/com/wolfssl/provider/jce/WolfCryptKeyPairGenerator.java +++ b/src/main/java/com/wolfssl/provider/jce/WolfCryptKeyPairGenerator.java @@ -426,11 +426,9 @@ else if (keysize == 8192) { if (type == KeyType.WC_RSA || type == KeyType.WC_RSA_PSS) { - /* Sanity check on key size */ - if (keysize < Rsa.RSA_MIN_SIZE) { - throw new InvalidParameterException( - "RSA key size too small, min is " + - Rsa.RSA_MIN_SIZE); + if (!Rsa.keyGenSizeAllowed(keysize)) { + throw new InvalidParameterException("RSA key size " + keysize + + " not supported for key generation"); } /* Set default RSA exponent for wolfSSL */ @@ -474,13 +472,19 @@ public synchronized void initialize(AlgorithmParameterSpec params, } RSAKeyGenParameterSpec rsaSpec = (RSAKeyGenParameterSpec)params; + if (!Rsa.keyGenSizeAllowed(rsaSpec.getKeysize())) { + throw new InvalidAlgorithmParameterException( + "RSA key size " + rsaSpec.getKeysize() + + " not supported for key generation"); + } this.keysize = rsaSpec.getKeysize(); - /* Exponent should be larger than 1 and odd */ + /* Exponent must be odd and at least the native minimum */ long exp = rsaSpec.getPublicExponent().longValue(); - if ((exp <= 1) || (exp % 2 == 0)) { + if ((exp < Rsa.RSA_MIN_EXPONENT) || (exp % 2 == 0)) { throw new InvalidAlgorithmParameterException( - "RSA public exponent must be positive and odd" ); + "RSA public exponent must be odd and at least " + + Rsa.RSA_MIN_EXPONENT); } this.publicExponent = exp; diff --git a/src/main/java/com/wolfssl/wolfcrypt/Rsa.java b/src/main/java/com/wolfssl/wolfcrypt/Rsa.java index beecc99b..e3ae6e3a 100644 --- a/src/main/java/com/wolfssl/wolfcrypt/Rsa.java +++ b/src/main/java/com/wolfssl/wolfcrypt/Rsa.java @@ -37,6 +37,13 @@ public class Rsa extends NativeStruct { */ public static final int RSA_MIN_SIZE = Rsa.rsaMinSize(); + /** + * Minimum RSA public exponent for key generation, as supported by + * native wolfSSL. WC_RSA_EXPONENT (65537) on wolfCrypt FIPS builds per + * FIPS 186-4/186-5, otherwise 3. + */ + public static final long RSA_MIN_EXPONENT = Rsa.rsaMinExponent(); + /** direct() operation, encrypt with public key */ public static final int RSA_PUBLIC_ENCRYPT = 0; /** direct() operation, decrypt with public key */ @@ -167,6 +174,7 @@ private native byte[] wc_RsaSSL_Sign(byte[] data, Rng rng) private native byte[] wc_RsaSSL_Verify(byte[] data) throws WolfCryptException; private static native int rsaMinSize(); + private static native long rsaMinExponent(); /* RSA-PSS functions */ private native byte[] wc_RsaPSS_Sign(byte[] data, long hashType, int mgf, @@ -258,6 +266,17 @@ public Rsa(byte[] n, byte[] e) throws WolfCryptException { */ public static native long getDefaultRsaExponent(); + /** + * Checks if native wolfCrypt RSA key generation supports a key size, + * from native RSA_MIN_SIZE, RSA_MAX_SIZE, and the wolfCrypt FIPS v6+ + * WC_RSA_FIPS_GEN_MIN. + * + * @param size RSA key size in bits + * + * @return true if key generation supports this size + */ + public static native boolean keyGenSizeAllowed(int size); + @Override public synchronized void releaseNativeStruct() { synchronized (stateLock) { diff --git a/src/test/java/com/wolfssl/provider/jce/test/WolfCryptKeyPairGeneratorTest.java b/src/test/java/com/wolfssl/provider/jce/test/WolfCryptKeyPairGeneratorTest.java index c4f1b7f5..e2c1bc09 100644 --- a/src/test/java/com/wolfssl/provider/jce/test/WolfCryptKeyPairGeneratorTest.java +++ b/src/test/java/com/wolfssl/provider/jce/test/WolfCryptKeyPairGeneratorTest.java @@ -158,19 +158,10 @@ public static void testProviderInstallationAtRuntime() { Provider p = Security.getProvider("wolfJCE"); assertNotNull(p); - /* FIPS after 2425 doesn't allow 1024-bit RSA key gen */ - if ((!Fips.enabled || Fips.fipsVersion < 5) && - (Rsa.RSA_MIN_SIZE <= 1024)) { - testedRSAKeySizes.add(Integer.valueOf(1024)); - } - if (Rsa.RSA_MIN_SIZE <= 2048) { - testedRSAKeySizes.add(Integer.valueOf(2048)); - } - if (Rsa.RSA_MIN_SIZE <= 3072) { - testedRSAKeySizes.add(Integer.valueOf(3072)); - } - if (Rsa.RSA_MIN_SIZE <= 4096) { - testedRSAKeySizes.add(Integer.valueOf(4096)); + for (int size : new int[] { 1024, 2048, 3072, 4096 }) { + if (Rsa.keyGenSizeAllowed(size)) { + testedRSAKeySizes.add(Integer.valueOf(size)); + } } /* build list of enabled curves and key sizes, @@ -267,10 +258,68 @@ public void testKeyPairGeneratorRsaInitializeWithParamSpec() rsaSpec = new RSAKeyGenParameterSpec(10, BigInteger.valueOf(Rsa.getDefaultRsaExponent())); kpg.initialize(rsaSpec); + fail("RSA key size 10 should be rejected"); } catch (InvalidAlgorithmParameterException e) {} } } + @Test + public void testKeyPairGeneratorRsaInitializeWithBadKeySize() + throws NoSuchProviderException, NoSuchAlgorithmException { + + KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", "wolfJCE"); + BigInteger e = BigInteger.valueOf(Rsa.getDefaultRsaExponent()); + + /* Rejected sizes depend on native limits, MAX_VALUE never allowed */ + assertFalse(Rsa.keyGenSizeAllowed(Integer.MAX_VALUE)); + for (int size : new int[] { 10, 1024, 5000, Integer.MAX_VALUE }) { + if (Rsa.keyGenSizeAllowed(size)) { + continue; + } + try { + kpg.initialize(size); + fail("RSA key size " + size + " should be rejected"); + } catch (InvalidParameterException ex) { + /* expected */ + } + try { + kpg.initialize(new RSAKeyGenParameterSpec(size, e)); + fail("RSA key size " + size + " should be rejected"); + } catch (InvalidAlgorithmParameterException ex) { + /* expected */ + } + } + } + + @Test + public void testKeyPairGeneratorRsaInitializeWithBadExponent() + throws NoSuchProviderException, NoSuchAlgorithmException, + InvalidAlgorithmParameterException { + + Assume.assumeTrue(testedRSAKeySizes.size() > 0); + int size = testedRSAKeySizes.get(0); + long[] badExps = { + -1, 0, 1, 4, Rsa.RSA_MIN_EXPONENT - 2, Rsa.RSA_MIN_EXPONENT + 1 + }; + + KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", "wolfJCE"); + + for (long e : badExps) { + try { + kpg.initialize(new RSAKeyGenParameterSpec(size, + BigInteger.valueOf(e))); + fail("RSA public exponent " + e + " should be rejected"); + } catch (InvalidAlgorithmParameterException ex) { + /* expected */ + } + } + + /* Minimum exponent must be accepted by native key generation */ + kpg.initialize(new RSAKeyGenParameterSpec(size, + BigInteger.valueOf(Rsa.RSA_MIN_EXPONENT))); + assertNotNull(kpg.generateKeyPair()); + } + @Test public void testKeyPairGeneratorRsaInitializeWithKeySize() throws NoSuchProviderException, NoSuchAlgorithmException,