diff --git a/closed/src/java.base/share/classes/jdk/crypto/jniprovider/NativeCrypto.java b/closed/src/java.base/share/classes/jdk/crypto/jniprovider/NativeCrypto.java index c8358b4b4d5..4487aca4f11 100644 --- a/closed/src/java.base/share/classes/jdk/crypto/jniprovider/NativeCrypto.java +++ b/closed/src/java.base/share/classes/jdk/crypto/jniprovider/NativeCrypto.java @@ -25,6 +25,7 @@ import java.lang.ref.Cleaner; import java.security.*; +import java.util.Set; import com.ibm.oti.vm.VM; @@ -70,6 +71,8 @@ public class NativeCrypto { private static final boolean traceEnabled = Boolean.parseBoolean( GetPropertyAction.privilegedGetProperty("jdk.nativeCryptoTrace", "false")); + private static final Set disallowedAlgosFIPS = Set.of("MD5", "ChaCha20"); + private static final class InstanceHolder { private static final NativeCrypto instance = new NativeCrypto(); } @@ -79,6 +82,8 @@ private static final class InstanceHolder { // or one of the OPENSSL_VERSION_x_x_x constants private final long ossl_ver; + private final boolean isOpenSSLFIPS; + private static long loadCryptoLibraries() { long osslVersion; @@ -105,6 +110,11 @@ private static long loadCryptoLibraries() { @SuppressWarnings("removal") private NativeCrypto() { ossl_ver = AccessController.doPrivileged((PrivilegedAction) () -> loadCryptoLibraries()).longValue(); + if (ossl_ver != -1) { + isOpenSSLFIPS = isOpenSSLFIPS(); + } else { + isOpenSSLFIPS = false; + } } /** @@ -178,6 +188,45 @@ public static final boolean isTraceEnabled() { return traceEnabled; } + public static final boolean isOpenSSLFIPSVersion() { + return InstanceHolder.instance.isOpenSSLFIPS; + } + + /** + * Check whether a native implementation is available in the loaded OpenSSL library. + * Note that, an algorithm could be unavailable due to options used to build the + * OpenSSL version utilized, or using a FIPS version that doesn't allow it. + * + * @param algorithm the algorithm checked + * @return whether a native implementation of the given crypto algorithm is available + */ + public static final boolean isAlgorithmAvailable(String algorithm) { + boolean isAlgorithmAvailable = false; + if (isAllowedAndLoaded()) { + if (isOpenSSLFIPSVersion()) { + if (disallowedAlgosFIPS.contains(algorithm)) { + return false; + } + } + switch (algorithm) { + case "MD5": + return isMD5Available(); + default: + return true; + } + } + + //Issue a message indicating whether the crypto implementation is available. + if (traceEnabled) { + if (isAlgorithmAvailable) { + System.err.println(algorithm + " native crypto implementation is available."); + } else { + System.err.println(algorithm + " native crypto implementation is not available."); + } + } + return isAlgorithmAvailable; + } + @CallerSensitive public static NativeCrypto getNativeCrypto() { ClassLoader callerClassLoader = Reflection.getCallerClass().getClassLoader(); @@ -202,6 +251,8 @@ public void run() { private static final native long loadCrypto(boolean trace); + private static final native boolean isOpenSSLFIPS(); + public static final native boolean isMD5Available(); public final native long DigestCreateContext(long nativeBuffer, diff --git a/closed/src/java.base/share/native/libjncrypto/NativeCrypto.c b/closed/src/java.base/share/native/libjncrypto/NativeCrypto.c index 4d9a05a58c7..8e76b3278c0 100644 --- a/closed/src/java.base/share/native/libjncrypto/NativeCrypto.c +++ b/closed/src/java.base/share/native/libjncrypto/NativeCrypto.c @@ -82,6 +82,9 @@ int OSSL102_RSA_set0_crt_params(RSA *, BIGNUM *, BIGNUM *, BIGNUM *); #define EVP_CTRL_AEAD_SET_TAG EVP_CTRL_GCM_SET_TAG #endif +/* Check whether loaded library is in FIPS mode. */ +jboolean OSSL_IS_FIPS; + /* Header for EC algorithm */ jboolean OSSL_ECGF2M; int setECPublicCoordinates(EC_KEY *, BIGNUM *, BIGNUM *, int); @@ -365,6 +368,18 @@ static jlong extractVersionToJlong(const char *astring) } static void *crypto_library = NULL; + +/* + * Class: jdk_crypto_jniprovider_NativeCrypto + * Method: isOpenSSLFIPS + * Signature: ()Z + */ +JNIEXPORT jboolean JNICALL Java_jdk_crypto_jniprovider_NativeCrypto_isOpenSSLFIPS + (JNIEnv *env, jclass thisObj) +{ + return OSSL_IS_FIPS; +} + /* * Class: jdk_crypto_jniprovider_NativeCrypto * Method: loadCrypto @@ -440,6 +455,27 @@ JNIEXPORT jlong JNICALL Java_jdk_crypto_jniprovider_NativeCrypto_loadCrypto } } + /* Check whether the loaded OpenSSL library is in FIPS mode. */ + if (ossl_ver >= OPENSSL_VERSION_3_0_0) { + typedef int OSSL_fipsmode_t(OSSL_LIB_CTX *); + OSSL_fipsmode_t* OSSL_fipsmode; + OSSL_fipsmode = (OSSL_fipsmode_t*)find_crypto_symbol(crypto_library, "EVP_default_properties_is_fips_enabled"); + if ((NULL != OSSL_fipsmode) && ((*OSSL_fipsmode)(NULL) == 1)) { + OSSL_IS_FIPS = JNI_TRUE; + } else { + OSSL_IS_FIPS = JNI_FALSE; + } + } else { + typedef int OSSL_fipsmode_t(void); + OSSL_fipsmode_t* OSSL_fipsmode; + OSSL_fipsmode = (OSSL_fipsmode_t*)find_crypto_symbol(crypto_library, "FIPS_mode"); + if ((NULL != OSSL_fipsmode) && ((*OSSL_fipsmode)() == 1)) { + OSSL_IS_FIPS = JNI_TRUE; + } else { + OSSL_IS_FIPS = JNI_FALSE; + } + } + /* Load the function symbols for OpenSSL errors. */ OSSL_error_string_n = (OSSL_error_string_n_t*)find_crypto_symbol(crypto_library, "ERR_error_string_n"); OSSL_error_string = (OSSL_error_string_t*)find_crypto_symbol(crypto_library, "ERR_error_string"); diff --git a/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java b/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java index 863ec6e077b..975d679875a 100644 --- a/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java +++ b/src/java.base/share/classes/com/sun/crypto/provider/SunJCE.java @@ -340,7 +340,10 @@ void putEntries() { attrs.clear(); attrs.put("SupportedKeyFormats", "RAW"); - if (useNativeChaCha20Cipher && (NativeCrypto.getVersionIfAvailable() >= NativeCrypto.OPENSSL_VERSION_1_1_0)) { + if (useNativeChaCha20Cipher + && NativeCrypto.isAlgorithmAvailable("ChaCha20") + && (NativeCrypto.getVersionIfAvailable() >= NativeCrypto.OPENSSL_VERSION_1_1_0) + ) { ps("Cipher", "ChaCha20", "com.sun.crypto.provider.NativeChaCha20Cipher$ChaCha20Only", null, attrs); diff --git a/src/java.base/share/classes/sun/security/ec/SunEC.java b/src/java.base/share/classes/sun/security/ec/SunEC.java index b2c8da66aab..e3d8f195797 100644 --- a/src/java.base/share/classes/sun/security/ec/SunEC.java +++ b/src/java.base/share/classes/sun/security/ec/SunEC.java @@ -65,30 +65,30 @@ public final class SunEC extends Provider { /* The property 'jdk.nativeEC' is used to control enablement of the native * ECDH implementation. */ - private static final boolean useNativeECDH = NativeCrypto.isAlgorithmEnabled("jdk.nativeEC", "SunEC"); + private static final boolean useNativeECDH = NativeCrypto.isAlgorithmEnabled("jdk.nativeEC", "ECDH"); /* The property 'jdk.nativeECKeyGen' is used to control enablement of the native * ECKeyGeneration implementation. * OpenSSL 1.1.0 or above is required for EC key generation support. */ - private static final boolean useNativeECKeyGen = NativeCrypto.isAlgorithmEnabled("jdk.nativeECKeyGen", "SunEC"); + private static final boolean useNativeECKeyGen = NativeCrypto.isAlgorithmEnabled("jdk.nativeECKeyGen", "ECKeyGen"); /* The property 'jdk.nativeECDSA' is used to control enablement of the native * ECDSA signature implementation. */ - private static final boolean useNativeECDSA = NativeCrypto.isAlgorithmEnabled("jdk.nativeECDSA", "SunEC"); + private static final boolean useNativeECDSA = NativeCrypto.isAlgorithmEnabled("jdk.nativeECDSA", "ECDSA"); /* The property 'jdk.nativeXDHKeyAgreement' is used to control enablement of the native * XDH key agreement. XDH key agreement is only supported in OpenSSL 1.1.1 and above. */ private static final boolean useNativeXDHKeyAgreement = - NativeCrypto.isAlgorithmEnabled("jdk.nativeXDHKeyAgreement", "SunEC"); + NativeCrypto.isAlgorithmEnabled("jdk.nativeXDHKeyAgreement", "XDHKeyAgreement"); /* The property 'jdk.nativeXDHKeyGen' is used to control enablement of the native * XDH key generation. XDH key generation is only supported in OpenSSL 1.1.1 and above. */ private static final boolean useNativeXDHKeyGen = - NativeCrypto.isAlgorithmEnabled("jdk.nativeXDHKeyGen", "SunEC"); + NativeCrypto.isAlgorithmEnabled("jdk.nativeXDHKeyGen", "XDHKeyGen"); private static class ProviderServiceA extends ProviderService { ProviderServiceA(Provider p, String type, String algo, String cn, diff --git a/src/java.base/share/classes/sun/security/provider/SunEntries.java b/src/java.base/share/classes/sun/security/provider/SunEntries.java index 8928a9e0fd7..df990a7030c 100644 --- a/src/java.base/share/classes/sun/security/provider/SunEntries.java +++ b/src/java.base/share/classes/sun/security/provider/SunEntries.java @@ -330,8 +330,7 @@ public final class SunEntries { */ /* Don't use native MD5 on AIX due to an observed performance regression. */ if (useNativeMD5 - && NativeCrypto.isAllowedAndLoaded() - && NativeCrypto.isMD5Available() + && NativeCrypto.isAlgorithmAvailable("MD5") && !OperatingSystem.isAix() ) { providerMD5 = "sun.security.provider.NativeMD5";