Skip to content

Commit

Permalink
Merge pull request #617 from JasonFengJ9/delaynativeload
Browse files Browse the repository at this point in the history
Lazily initialize native crypto libraries
  • Loading branch information
keithc-ca committed Feb 9, 2023
2 parents 60c8836 + fc9cdcb commit 7c4ecf2
Show file tree
Hide file tree
Showing 14 changed files with 147 additions and 124 deletions.
2 changes: 2 additions & 0 deletions closed/GensrcJ9JCL.gmk
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,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,54 +56,69 @@ public class NativeCrypto {
private static final boolean traceEnabled = Boolean.parseBoolean(
GetPropertyAction.privilegedGetProperty("jdk.nativeCryptoTrace", "false"));

//ossl_ver:
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 = -1;

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");
}
// Return that ossl_ver is -1 (default set above)
}

return ossl_ver;
});

private static final boolean loaded = ossl_ver != -1;

public static final boolean isLoaded() {
return loaded;
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 @@ -111,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 (loaded) {
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 @@ -170,17 +164,13 @@ 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
23 changes: 11 additions & 12 deletions src/java.base/share/classes/com/sun/crypto/provider/CipherCore.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 @@ -204,7 +204,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 Expand Up @@ -232,7 +232,7 @@ void setMode(String mode) throws NoSuchAlgorithmException {
* Check whether native GCM is enabled and instantiate
* the NativeGaloisCounterMode class.
*/
if (useNativeGCM) {
if (useNativeGCM && NativeCrypto.isAllowedAndLoaded()) {
cipher = new NativeGaloisCounterMode(rawImpl);
} else {
cipher = new GaloisCounterMode(rawImpl);
Expand Down Expand Up @@ -362,8 +362,8 @@ private int getOutputSizeByOperation(int inputLen, boolean isDoFinal) {
switch (cipherMode) {
case GCM_MODE:
if (isDoFinal) {
int tagLen = 0;
if (useNativeGCM) {
int tagLen;
if (cipher instanceof NativeGaloisCounterMode) {
tagLen = ((NativeGaloisCounterMode) cipher).getTagLen();
} else {
tagLen = ((GaloisCounterMode) cipher).getTagLen();
Expand Down Expand Up @@ -446,14 +446,13 @@ AlgorithmParameters getParameters(String algName) {
if (cipherMode == GCM_MODE) {
algName = "GCM";

if (useNativeGCM) {
spec = new GCMParameterSpec
(((NativeGaloisCounterMode) cipher).getTagLen()*8, iv);
int tagLen;
if (cipher instanceof NativeGaloisCounterMode) {
tagLen = ((NativeGaloisCounterMode) cipher).getTagLen();
} else {
spec = new GCMParameterSpec
(((GaloisCounterMode) cipher).getTagLen()*8, iv);
tagLen = ((GaloisCounterMode) cipher).getTagLen();
}

spec = new GCMParameterSpec(tagLen * 8, iv);
} else {
if (algName.equals("RC2")) {
RC2Crypt rawImpl = (RC2Crypt) cipher.getEmbeddedCipher();
Expand Down Expand Up @@ -633,7 +632,7 @@ void init(int opmode, Key key, AlgorithmParameterSpec params,
lastEncKey = keyBytes;
}

if (useNativeGCM) {
if (cipher instanceof NativeGaloisCounterMode) {
((NativeGaloisCounterMode) cipher).init
(decrypting, algorithm, keyBytes, ivBytes, tagLen);
} else {
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 @@ -64,7 +64,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 @@ -102,7 +102,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 @@ -119,6 +119,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 @@ -91,8 +91,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");

private static final long serialVersionUID = 6812507587804302833L;

Expand Down Expand Up @@ -319,7 +318,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 @@ -308,6 +314,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 @@ -91,6 +97,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

0 comments on commit 7c4ecf2

Please sign in to comment.