Skip to content
This repository has been archived by the owner on Dec 13, 2024. It is now read-only.

Lazily initialize native crypto libraries #66

Merged
merged 1 commit into from
Feb 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -315,6 +321,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 @@ -279,7 +279,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