Skip to content

Commit

Permalink
Check if OpenSSL is in FIPS mode and use Java for some algorithms
Browse files Browse the repository at this point in the history
If the OpenSSL library used is in FIPS mode, avoid using it
for algorithms that are not FIPS compliant and revert to the
original Java implementation.

Signed-off-by: Kostas Tsiounis <[email protected]>
  • Loading branch information
KostasTsiounis committed Oct 24, 2024
1 parent 26e9b54 commit 261d80c
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@

import java.lang.ref.Cleaner;
import java.security.*;
import java.util.Set;

import com.ibm.oti.vm.VM;

Expand Down Expand Up @@ -70,6 +71,8 @@ public class NativeCrypto {
private static final boolean traceEnabled = Boolean.parseBoolean(
GetPropertyAction.privilegedGetProperty("jdk.nativeCryptoTrace", "false"));

private static final Set<String> disallowedAlgosFIPS = Set.of("MD5", "ChaCha20");

private static final class InstanceHolder {
private static final NativeCrypto instance = new NativeCrypto();
}
Expand All @@ -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;

Expand All @@ -105,6 +110,11 @@ private static long loadCryptoLibraries() {
@SuppressWarnings("removal")
private NativeCrypto() {
ossl_ver = AccessController.doPrivileged((PrivilegedAction<Long>) () -> loadCryptoLibraries()).longValue();
if (ossl_ver != -1) {
isOpenSSLFIPS = isOpenSSLFIPS();
} else {
isOpenSSLFIPS = false;
}
}

/**
Expand Down Expand Up @@ -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();
Expand All @@ -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,
Expand Down
36 changes: 36 additions & 0 deletions closed/src/java.base/share/native/libjncrypto/NativeCrypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
10 changes: 5 additions & 5 deletions src/java.base/share/classes/sun/security/ec/SunEC.java
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down

0 comments on commit 261d80c

Please sign in to comment.