Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use the OpenSSL PKCS12 method for PBE and simplify NativeCrypto property checking #45

Merged
merged 1 commit into from
Oct 31, 2022
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
Original file line number Diff line number Diff line change
Expand Up @@ -33,18 +33,32 @@
import jdk.internal.reflect.Reflection;
import jdk.internal.reflect.CallerSensitive;

import sun.security.action.GetPropertyAction;

public class NativeCrypto {

/* Define constants for the native digest algorithm indices. */
public static final int SHA1_160 = 0;
public static final int SHA2_224 = 1;
public static final int SHA2_256 = 2;
public static final int SHA5_384 = 3;
public static final int SHA5_512 = 4;

private static final Cleaner ECKeyCleaner = CleanerFactory.cleaner();

private static final boolean useNativeCrypto = Boolean.parseBoolean(
GetPropertyAction.privilegedGetProperty("jdk.nativeCrypto", "true"));

private static final boolean traceEnabled = Boolean.parseBoolean(
GetPropertyAction.privilegedGetProperty("jdk.nativeCryptoTrace", "false"));

//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;
boolean traceEnabled = Boolean.getBoolean("jdk.nativeCryptoTrace");
try {
System.loadLibrary("jncrypto"); // check for native library
// load OpenSSL crypto library dynamically
Expand All @@ -68,6 +82,92 @@ public static final int getVersion() {
return ossl_ver;
}

/**
* Check whether native crypto is enabled. Note that, by default, native
* crypto is enabled (the native crypto library implementation is used).
*
* 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.
*
* @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
*/
public static final boolean isAlgorithmEnabled(String property, String name) {
return isAlgorithmEnabled(property, name, true, null);
}

/**
* Check whether native crypto is enabled. Note that, by default, native
* crypto is enabled (the native crypto library implementation is used).
*
* 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.
*
* 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) {
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.");
}
}
} 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.");
}
}
return useNativeAlgorithm;
}

public static final boolean isEnabled() {
return useNativeCrypto;
}

public static final boolean isTraceEnabled() {
return traceEnabled;
}

private NativeCrypto() {
// empty
}
Expand Down Expand Up @@ -295,4 +395,14 @@ public final native int ECDeriveKey(long publicKey,

public final native boolean ECNativeGF2m();

public final native int PBEDerive(byte[] password,
int passwordLength,
byte[] salt,
int saltLength,
byte[] key,
int iterations,
int n,
int id,
int hashAlgorithm);

}
Original file line number Diff line number Diff line change
Expand Up @@ -24,18 +24,20 @@
*/
/*
* ===========================================================================
* (c) Copyright IBM Corp. 2018, 2019 All Rights Reserved
* (c) Copyright IBM Corp. 2018, 2022 All Rights Reserved
* ===========================================================================
*/

package sun.security.provider;

import jdk.crypto.jniprovider.NativeCrypto;

public final class NativeSHA extends NativeDigest {

/**
* Creates a new native SHA object.
*/
public NativeSHA() {
super("SHA-1", 20, 0);
super("SHA-1", 20, NativeCrypto.SHA1_160);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,14 @@
*/
/*
* ===========================================================================
* (c) Copyright IBM Corp. 2018, 2019 All Rights Reserved
* (c) Copyright IBM Corp. 2018, 2022 All Rights Reserved
* ===========================================================================
*/

package sun.security.provider;

import jdk.crypto.jniprovider.NativeCrypto;

abstract class NativeSHA2 {

/**
Expand All @@ -38,7 +40,7 @@ abstract class NativeSHA2 {
public static final class SHA224 extends NativeDigest {

public SHA224() {
super("SHA-224", 28, 2);
super("SHA-224", 28, NativeCrypto.SHA2_224);
}
}

Expand All @@ -48,7 +50,7 @@ public SHA224() {
public static final class SHA256 extends NativeDigest {

public SHA256() {
super("SHA-256", 32, 1);
super("SHA-256", 32, NativeCrypto.SHA2_256);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,14 @@
*/
/*
* ===========================================================================
* (c) Copyright IBM Corp. 2018, 2019 All Rights Reserved
* (c) Copyright IBM Corp. 2018, 2022 All Rights Reserved
* ===========================================================================
*/

package sun.security.provider;

import jdk.crypto.jniprovider.NativeCrypto;

abstract class NativeSHA5 {

/**
Expand All @@ -38,7 +40,7 @@ abstract class NativeSHA5 {
public static final class SHA512 extends NativeDigest {

public SHA512() {
super("SHA-512", 64, 4);
super("SHA-512", 64, NativeCrypto.SHA5_512);
}
}

Expand All @@ -48,7 +50,7 @@ public SHA512() {
public static final class SHA384 extends NativeDigest {

public SHA384() {
super("SHA-384", 48, 3);
super("SHA-384", 48, NativeCrypto.SHA5_384);
}
}
}
91 changes: 84 additions & 7 deletions closed/src/java.base/share/native/libjncrypto/NativeCrypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include <openssl/err.h>
#include <openssl/rsa.h>
#include <openssl/ecdh.h>
#include <openssl/pkcs12.h>

#include <jni.h>
#include <stdio.h>
Expand Down Expand Up @@ -134,6 +135,8 @@ typedef int OSSL_EC_KEY_set_public_key_t(EC_KEY *, const EC_POINT *);
typedef int OSSL_EC_KEY_check_key_t(const EC_KEY *);
typedef int EC_set_public_key_t(EC_KEY *, BIGNUM *, BIGNUM *, int);

typedef int OSSL_PKCS12_key_gen_t(const char *, int, unsigned char *, int, int, int, int, unsigned char *, const EVP_MD *);

typedef int OSSL_CRYPTO_num_locks_t();
typedef void OSSL_CRYPTO_THREADID_set_numeric_t(CRYPTO_THREADID *id, unsigned long val);
typedef void* OSSL_OPENSSL_malloc_t(size_t num);
Expand Down Expand Up @@ -235,6 +238,9 @@ OSSL_EC_KEY_set_public_key_t* OSSL_EC_KEY_set_public_key;
OSSL_EC_KEY_check_key_t* OSSL_EC_KEY_check_key;
EC_set_public_key_t* EC_set_public_key;

/* Define pointers for OpenSSL functions to handle PBE algorithm. */
OSSL_PKCS12_key_gen_t* OSSL_PKCS12_key_gen;

/* Structure for OpenSSL Digest context. */
typedef struct OpenSSLMDContext {
EVP_MD_CTX *ctx;
Expand Down Expand Up @@ -455,6 +461,9 @@ JNIEXPORT jint JNICALL Java_jdk_crypto_jniprovider_NativeCrypto_loadCrypto
OSSL_ECGF2M = JNI_TRUE;
}

/* Load the functions symbols for OpenSSL PBE algorithm. */
OSSL_PKCS12_key_gen = (OSSL_PKCS12_key_gen_t*)find_crypto_symbol(crypto_library, "PKCS12_key_gen_uni");

if ((NULL == OSSL_error_string) ||
(NULL == OSSL_error_string_n) ||
(NULL == OSSL_get_error) ||
Expand Down Expand Up @@ -513,6 +522,7 @@ JNIEXPORT jint JNICALL Java_jdk_crypto_jniprovider_NativeCrypto_loadCrypto
(NULL == OSSL_BN_CTX_free) ||
(NULL == OSSL_EC_KEY_set_public_key) ||
(NULL == OSSL_EC_KEY_check_key) ||
(NULL == OSSL_PKCS12_key_gen) ||
/* Check symbols that are only available in OpenSSL 1.1.x and above */
((1 == ossl_ver) && ((NULL == OSSL_chacha20) || (NULL == OSSL_chacha20_poly1305))) ||
/* Check symbols that are only available in OpenSSL 1.0.x and above */
Expand Down Expand Up @@ -703,19 +713,19 @@ JNIEXPORT jlong JNICALL Java_jdk_crypto_jniprovider_NativeCrypto_DigestCreateCon
OpenSSLMDContext *context = NULL;

switch (algoIdx) {
case 0:
case jdk_crypto_jniprovider_NativeCrypto_SHA1_160:
digestAlg = (*OSSL_sha1)();
break;
case 1:
digestAlg = (*OSSL_sha256)();
break;
case 2:
case jdk_crypto_jniprovider_NativeCrypto_SHA2_224:
digestAlg = (*OSSL_sha224)();
break;
case 3:
case jdk_crypto_jniprovider_NativeCrypto_SHA2_256:
digestAlg = (*OSSL_sha256)();
break;
case jdk_crypto_jniprovider_NativeCrypto_SHA5_384:
digestAlg = (*OSSL_sha384)();
break;
case 4:
case jdk_crypto_jniprovider_NativeCrypto_SHA5_512:
digestAlg = (*OSSL_sha512)();
break;
default:
Expand Down Expand Up @@ -2799,3 +2809,70 @@ setECPublicKey(EC_KEY *key, BIGNUM *x, BIGNUM *y, int field)

return ret;
}

/* Password-based encryption algorithm.
*
* Class: jdk_crypto_jniprovider_NativeCrypto
* Method: PBEDerive
* Signature: (J[BI[BI[BIIII)I
*/
JNIEXPORT jint JNICALL
Java_jdk_crypto_jniprovider_NativeCrypto_PBEDerive
(JNIEnv *env, jclass obj, jbyteArray password, jint passwordLength, jbyteArray salt, jint saltLength, jbyteArray key, jint iterations, jint n, jint id, jint hashAlgorithm)
{
const EVP_MD *digestAlgorithm = NULL;
char *nativePassword = NULL;
unsigned char *nativeSalt = NULL;
unsigned char *nativeKey = NULL;
jint ret = -1;

switch (hashAlgorithm) {
case jdk_crypto_jniprovider_NativeCrypto_SHA1_160:
digestAlgorithm = (*OSSL_sha1)();
break;
case jdk_crypto_jniprovider_NativeCrypto_SHA2_224:
digestAlgorithm = (*OSSL_sha224)();
break;
case jdk_crypto_jniprovider_NativeCrypto_SHA2_256:
digestAlgorithm = (*OSSL_sha256)();
break;
case jdk_crypto_jniprovider_NativeCrypto_SHA5_384:
digestAlgorithm = (*OSSL_sha384)();
break;
case jdk_crypto_jniprovider_NativeCrypto_SHA5_512:
digestAlgorithm = (*OSSL_sha512)();
break;
default:
goto cleanup;
}

nativePassword = (char*)((*env)->GetPrimitiveArrayCritical(env, password, 0));
if (NULL == nativePassword) {
goto cleanup;
}
nativeSalt = (unsigned char*)((*env)->GetPrimitiveArrayCritical(env, salt, 0));
if (NULL == nativeSalt) {
goto cleanup;
}
nativeKey = (unsigned char*)((*env)->GetPrimitiveArrayCritical(env, key, 0));
if (NULL == nativeKey) {
goto cleanup;
}

if (1 == (*OSSL_PKCS12_key_gen)(nativePassword, passwordLength, nativeSalt, saltLength, id, iterations, n, nativeKey, digestAlgorithm)) {
ret = 0;
}

cleanup:
if (NULL != nativePassword) {
(*env)->ReleasePrimitiveArrayCritical(env, password, nativePassword, JNI_ABORT);
}
if (NULL != nativeSalt) {
(*env)->ReleasePrimitiveArrayCritical(env, salt, nativeSalt, JNI_ABORT);
}
if (NULL != nativeKey) {
(*env)->ReleasePrimitiveArrayCritical(env, key, nativeKey, JNI_ABORT);
}

return ret;
}
Loading