Skip to content

Commit

Permalink
Merge pull request ibmruntimes#14 from JasonFengJ9/delaynativeload
Browse files Browse the repository at this point in the history
Lazily initialize native crypto libraries
  • Loading branch information
keithc-ca authored Feb 6, 2023
2 parents 0bbbf1b + 18ee646 commit 3d7cac4
Show file tree
Hide file tree
Showing 14 changed files with 139 additions and 113 deletions.
2 changes: 2 additions & 0 deletions closed/GensrcJ9JCL.gmk
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ $(eval $(call SetupCopyFiles,COPY_OVERLAY_FILES, \
src/java.base/share/classes/java/util/Timer.java \
src/java.base/share/classes/java/util/TimerTask.java \
src/java.base/share/classes/java/util/concurrent/ConcurrentHashMap.java \
src/java.base/share/classes/sun/security/jca/ProviderConfig.java \
src/java.base/share/classes/sun/security/jca/ProviderList.java \
src/java.base/unix/classes/java/lang/ProcessEnvironment.java \
))

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* ===========================================================================
* (c) Copyright IBM Corp. 2018, 2022 All Rights Reserved
* (c) Copyright IBM Corp. 2018, 2023 All Rights Reserved
* ===========================================================================
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -35,6 +35,10 @@

import sun.security.action.GetPropertyAction;

/*[IF CRIU_SUPPORT]*/
import openj9.internal.criu.InternalCRIUSupport;
/*[ENDIF] CRIU_SUPPORT */

public class NativeCrypto {

/* Define constants for the native digest algorithm indices. */
Expand All @@ -52,52 +56,69 @@ public class NativeCrypto {
private static final boolean traceEnabled = Boolean.parseBoolean(
GetPropertyAction.privilegedGetProperty("jdk.nativeCryptoTrace", "false"));

private static final class InstanceHolder {
private static final NativeCrypto instance = new NativeCrypto();
}

//ossl_vers:
// -1 : library load failed
// 0 : openssl 1.0.x
// 1 : openssl 1.1.x or newer
private static final int ossl_ver = AccessController.doPrivileged(
(PrivilegedAction<Integer>) () -> {
int ossl_ver;
try {
System.loadLibrary("jncrypto"); // check for native library
// load OpenSSL crypto library dynamically
ossl_ver = loadCrypto(traceEnabled);
} catch (UnsatisfiedLinkError usle) {
if (traceEnabled) {
System.err.println("UnsatisfiedLinkError: Failure attempting to load jncrypto JNI library");
}
// signal load failure
ossl_ver = -1;
}

return ossl_ver;
}).intValue();

public static final boolean isLoaded() {
return ossl_ver != -1;
private final int ossl_ver;

private static int loadCryptoLibraries() {
int osslVersion;

try {
// load jncrypto JNI library
System.loadLibrary("jncrypto");
// load OpenSSL crypto library dynamically
osslVersion = loadCrypto(traceEnabled);
if (traceEnabled && (osslVersion != -1)) {
System.err.println("Native crypto library load succeeded - using native crypto library.");
}
} catch (UnsatisfiedLinkError usle) {
if (traceEnabled) {
System.err.println("UnsatisfiedLinkError: Failure attempting to load jncrypto JNI library");
System.err.println("Warning: Native crypto library load failed." +
" Using Java crypto implementation.");
}
// signal load failure
osslVersion = -1;
}
return osslVersion;
}

public static final int getVersion() {
return ossl_ver;
@SuppressWarnings("removal")
private NativeCrypto() {
ossl_ver = AccessController.doPrivileged((PrivilegedAction<Integer>) () -> loadCryptoLibraries()).intValue();
}

/**
* Check whether native crypto is enabled. Note that, by default, native
* crypto is enabled (the native crypto library implementation is used).
* Check whether the native crypto libraries are loaded successfully.
* If CRIU is enabled and a checkpoint is allowed, the library loading
* is disallowed, and this returns false.
*
* The property 'jdk.nativeCrypto' is used to control enablement of all
* native cryptos (Digest, CBC, GCM, RSA, ChaCha20, EC, and PBE), while
* the given property should be used to control enablement of the given
* native crypto algorithm.
* @return whether the native crypto libraries have been loaded successfully
*/
public static final boolean isAllowedAndLoaded() {
return getVersionIfAvailable() >= 0;
}

/**
* Return the OpenSSL version.
* -1 is returned if CRIU is enabled and the checkpoint is allowed.
* The libraries are to be loaded for the first reference of InstanceHolder.instance.
*
* @param property the property used to control enablement of the given
* algorithm
* @param name the name of the class or the algorithm
* @return whether the given native crypto algorithm is enabled
* @return the OpenSSL library version if it is available
*/
public static final boolean isAlgorithmEnabled(String property, String name) {
return isAlgorithmEnabled(property, name, true, null);
public static final int getVersionIfAvailable() {
/*[IF CRIU_SUPPORT]*/
if (InternalCRIUSupport.isCheckpointAllowed()) {
return -1;
}
/*[ENDIF] CRIU_SUPPORT */
return InstanceHolder.instance.ossl_ver;
}

/**
Expand All @@ -109,50 +130,25 @@ public static final boolean isAlgorithmEnabled(String property, String name) {
* the given property should be used to control enablement of the given
* native crypto algorithm.
*
* This method is used for native cryptos that have additional requirements
* in order to load.
*
* @param property the property used to control enablement of the given
* algorithm
* @param name the name of the class or the algorithm
* @param satisfied whether the additional requirements are met
* @param explanation explanation if the native crypto is not loaded
* due to the additional requirements not being met
* @return whether the given native crypto algorithm is enabled
*/
public static final boolean isAlgorithmEnabled(String property, String name, boolean satisfied, String explanation) {
public static final boolean isAlgorithmEnabled(String property, String name) {
boolean useNativeAlgorithm = false;
if (useNativeCrypto) {
useNativeAlgorithm = Boolean.parseBoolean(
GetPropertyAction.privilegedGetProperty(property, "true"));
}
if (useNativeAlgorithm) {
/*
* User wants to use the native crypto implementation. Ensure that the
* native crypto library is loaded successfully. Otherwise, issue a warning
* message and fall back to the built-in java crypto implementation.
*/
if (isLoaded()) {
if (satisfied) {
if (traceEnabled) {
System.err.println(name + " - using native crypto library.");
}
} else {
useNativeAlgorithm = false;
if (traceEnabled) {
System.err.println("Warning: " + name + " native requirements not satisfied. " +
explanation + " Using Java crypto implementation.");
}
}
/*
* User wants to use the native crypto implementation. Ensure that the native crypto library is enabled.
* Otherwise, issue a warning message.
*/
if (traceEnabled) {
if (useNativeAlgorithm) {
System.err.println(name + " native crypto implementation enabled.");
} else {
useNativeAlgorithm = false;
if (traceEnabled) {
System.err.println("Warning: Native crypto library load failed." +
" Using Java crypto implementation.");
}
}
} else {
if (traceEnabled) {
System.err.println(name + " native crypto implementation disabled." +
" Using Java crypto implementation.");
}
Expand All @@ -168,16 +164,12 @@ public static final boolean isTraceEnabled() {
return traceEnabled;
}

private NativeCrypto() {
// empty
}

@CallerSensitive
public static NativeCrypto getNativeCrypto() {
ClassLoader callerClassLoader = Reflection.getCallerClass().getClassLoader();

if ((callerClassLoader == null) || (callerClassLoader == VM.getVMLangAccess().getExtClassLoader())) {
return new NativeCrypto();
return InstanceHolder.instance;
}

throw new SecurityException("NativeCrypto");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
*/
/*
* ===========================================================================
* (c) Copyright IBM Corp. 2018, 2022 All Rights Reserved
* (c) Copyright IBM Corp. 2018, 2023 All Rights Reserved
* ===========================================================================
*/

Expand Down Expand Up @@ -183,7 +183,7 @@ void setMode(String mode) throws NoSuchAlgorithmException {
* Check whether native CBC is enabled and instantiate
* the NativeCipherBlockChaining class.
*/
if (useNativeCBC && blockSize == 16) {
if (useNativeCBC && (blockSize == 16) && NativeCrypto.isAllowedAndLoaded()) {
cipher = new NativeCipherBlockChaining(rawImpl);
} else {
cipher = new CipherBlockChaining(rawImpl);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
*/
/*
* ===========================================================================
* (c) Copyright IBM Corp. 2022, 2022 All Rights Reserved
* (c) Copyright IBM Corp. 2022, 2023 All Rights Reserved
* ===========================================================================
*/

Expand Down Expand Up @@ -60,7 +60,7 @@ final class PKCS12PBECipherCore {

private static final int DEFAULT_SALT_LENGTH = 20;
private static final int DEFAULT_COUNT = 1024;
private static final NativeCrypto nativeCrypto = NativeCrypto.getNativeCrypto();
private static NativeCrypto nativeCrypto;
private static final boolean nativeCryptTrace = NativeCrypto.isTraceEnabled();
/* The property 'jdk.nativePBE' is used to control enablement of the native
* PBE implementation.
Expand Down Expand Up @@ -98,7 +98,7 @@ static byte[] derive(char[] chars, byte[] salt, int ic, int n, int type,
}
byte[] key = new byte[n];

if (useNativePBE) {
if (useNativePBE && NativeCrypto.isAllowedAndLoaded()) {
boolean hashSupported = true;
int hashIndex = 0;
if (hashAlgo.equals("SHA") || hashAlgo.equals("SHA1") || hashAlgo.equals("SHA-1")) {
Expand All @@ -115,6 +115,9 @@ static byte[] derive(char[] chars, byte[] salt, int ic, int n, int type,
hashSupported = false;
}
if (hashSupported) {
if (nativeCrypto == null) {
nativeCrypto = NativeCrypto.getNativeCrypto();
}
if (nativeCrypto.PBEDerive(passwd, passwd.length, salt, salt.length, key, ic, n, type, hashIndex) != -1) {
return key;
} else if (nativeCryptTrace) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
*/
/*
* ===========================================================================
* (c) Copyright IBM Corp. 2018, 2022 All Rights Reserved
* (c) Copyright IBM Corp. 2018, 2023 All Rights Reserved
* ===========================================================================
*/

Expand Down Expand Up @@ -90,8 +90,7 @@ public final class SunJCE extends Provider {
/* The property 'jdk.nativeChaCha20' is used to control enablement of the native
* ChaCha20 implementation. ChaCha20 is only supported in OpenSSL 1.1.0 and above.
*/
private static final boolean useNativeChaCha20Cipher = NativeCrypto.isAlgorithmEnabled("jdk.nativeChaCha20",
"NativeChaCha20Cipher", NativeCrypto.getVersion() >= 1, "Need OpenSSL 1.1.0 or above for ChaCha20 support.");
private static final boolean useNativeChaCha20Cipher = NativeCrypto.isAlgorithmEnabled("jdk.nativeChaCha20", "NativeChaCha20Cipher");

/* The property 'jdk.nativeGCM' is used to control enablement of the native
* GCM implementation.
Expand Down Expand Up @@ -292,7 +291,7 @@ void putEntries() {
attrs.put("SupportedModes", "GCM");
attrs.put("SupportedKeyFormats", "RAW");

if (useNativeGaloisCounterMode) {
if (useNativeGaloisCounterMode && NativeCrypto.isAllowedAndLoaded()) {
ps("Cipher", "AES/GCM/NoPadding",
"com.sun.crypto.provider.NativeGaloisCounterMode$AESGCM", null,
attrs);
Expand Down Expand Up @@ -337,7 +336,7 @@ void putEntries() {
attrs.clear();
attrs.put("SupportedKeyFormats", "RAW");

if (useNativeChaCha20Cipher) {
if (useNativeChaCha20Cipher && (NativeCrypto.getVersionIfAvailable() >= 1)) {
ps("Cipher", "ChaCha20",
"com.sun.crypto.provider.NativeChaCha20Cipher$ChaCha20Only",
null, attrs);
Expand Down
12 changes: 12 additions & 0 deletions src/java.base/share/classes/sun/security/jca/ProviderConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@
* questions.
*/

/*
* ===========================================================================
* (c) Copyright IBM Corp. 2023, 2023 All Rights Reserved
* ===========================================================================
*/

package sun.security.jca;

import java.io.File;
Expand Down Expand Up @@ -314,6 +320,12 @@ public String run() {
});
}

/*[IF CRIU_SUPPORT]*/
static void reloadServices() {
ProviderLoader.INSTANCE.services.reload();
}
/*[ENDIF] CRIU_SUPPORT */

// Inner class for loading security providers listed in java.security file
private static final class ProviderLoader {
static final ProviderLoader INSTANCE = new ProviderLoader();
Expand Down
10 changes: 10 additions & 0 deletions src/java.base/share/classes/sun/security/jca/ProviderList.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@
* questions.
*/

/*
* ===========================================================================
* (c) Copyright IBM Corp. 2023, 2023 All Rights Reserved
* ===========================================================================
*/

package sun.security.jca;

import java.util.*;
Expand Down Expand Up @@ -93,6 +99,10 @@ static ProviderList fromSecurityProperties() {
return AccessController.doPrivileged(
new PrivilegedAction<ProviderList>() {
public ProviderList run() {
/*[IF CRIU_SUPPORT]*/
// ensure the providers are reloaded from scratch
ProviderConfig.reloadServices();
/*[ENDIF] CRIU_SUPPORT */
return new ProviderList();
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
*/
/*
* ===========================================================================
* (c) Copyright IBM Corp. 2018, 2022 All Rights Reserved
* (c) Copyright IBM Corp. 2018, 2023 All Rights Reserved
* ===========================================================================
*/

Expand Down Expand Up @@ -287,7 +287,7 @@ public final class SunEntries {
* Set the digest provider based on whether native crypto is
* enabled or not.
*/
if (useNativeDigest) {
if (useNativeDigest && NativeCrypto.isAllowedAndLoaded()) {
providerSHA = "sun.security.provider.NativeSHA";
providerSHA224 = "sun.security.provider.NativeSHA2$SHA224";
providerSHA256 = "sun.security.provider.NativeSHA2$SHA256";
Expand Down
10 changes: 5 additions & 5 deletions src/java.base/share/classes/sun/security/rsa/RSACore.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
*/
/*
* ===========================================================================
* (c) Copyright IBM Corp. 2018, 2022 All Rights Reserved
* (c) Copyright IBM Corp. 2018, 2023 All Rights Reserved
* ===========================================================================
*/

Expand Down Expand Up @@ -117,8 +117,8 @@ public static byte[] convert(byte[] b, int ofs, int len) {
*/
public static byte[] rsa(byte[] msg, RSAPublicKey key)
throws BadPaddingException {
if (useNativeRsa && key instanceof sun.security.rsa.RSAPublicKeyImpl) {
byte[] ret = NativeRSACore.rsa(msg, (sun.security.rsa.RSAPublicKeyImpl) key);
if (useNativeRsa && key instanceof sun.security.rsa.RSAPublicKeyImpl rsaKey && NativeCrypto.isAllowedAndLoaded()) {
byte[] ret = NativeRSACore.rsa(msg, rsaKey);
if (ret != null) {
return ret;
}
Expand Down Expand Up @@ -146,8 +146,8 @@ public static byte[] rsa(byte[] msg, RSAPrivateKey key)
public static byte[] rsa(byte[] msg, RSAPrivateKey key, boolean verify)
throws BadPaddingException {
if (key instanceof RSAPrivateCrtKey) {
if (useNativeRsa && key instanceof sun.security.rsa.RSAPrivateCrtKeyImpl) {
byte[] ret = NativeRSACore.rsa(msg, (sun.security.rsa.RSAPrivateCrtKeyImpl) key, verify);
if (useNativeRsa && key instanceof sun.security.rsa.RSAPrivateCrtKeyImpl rsaKey && NativeCrypto.isAllowedAndLoaded()) {
byte[] ret = NativeRSACore.rsa(msg, rsaKey, verify);
if (ret != null) {
return ret;
}
Expand Down
Loading

0 comments on commit 3d7cac4

Please sign in to comment.