Merge pull request #263 from cconlon/fenrirAug20

Zeroize native private key copies before JNI byte array release
pull/252/merge
Ruby Martin 2026-08-25 13:18:22 -05:00 committed by GitHub
commit 67072b3a46
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 216 additions and 40 deletions

View File

@ -36,6 +36,8 @@ word32 getDirectBufferLimit(JNIEnv* env, jobject buffer);
void setDirectBufferLimit(JNIEnv* env, jobject buffer, jint limit);
byte* getByteArray(JNIEnv* env, jbyteArray array);
byte* getByteArrayIsCopy(JNIEnv* env, jbyteArray array, jboolean* isCopy);
void zeroizeByteArrayCopy(byte* buf, word32 sz, jboolean isCopy);
void releaseByteArray(JNIEnv* env, jbyteArray array, byte* elements, jint abort);
word32 getByteArrayLength(JNIEnv* env, jbyteArray array);
void initializeNativeStruct(JNIEnv* env, jobject obj);

View File

@ -117,6 +117,7 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_AesCcm_wc_1AesCcmSetKey
Aes* aes = NULL;
const byte* key = NULL;
word32 keyLen = 0;
jboolean keyIsCopy = JNI_FALSE;
aes = (Aes*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
@ -125,7 +126,8 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_AesCcm_wc_1AesCcmSetKey
}
if (keyArr != NULL) {
key = (const byte*)(*env)->GetByteArrayElements(env, keyArr, NULL);
key = (const byte*)(*env)->GetByteArrayElements(env, keyArr,
&keyIsCopy);
keyLen = (*env)->GetArrayLength(env, keyArr);
}
@ -138,6 +140,7 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_AesCcm_wc_1AesCcmSetKey
}
if (keyArr != NULL) {
zeroizeByteArrayCopy((byte*)key, keyLen, keyIsCopy);
(*env)->ReleaseByteArrayElements(env, keyArr, (jbyte*)key, JNI_ABORT);
}

View File

@ -112,6 +112,7 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_AesCmac_wc_1CmacSetKey(
Cmac* cmac = NULL;
byte* key = NULL;
word32 keySz = 0;
jboolean keyIsCopy = JNI_FALSE;
cmac = (Cmac*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
@ -119,7 +120,7 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_AesCmac_wc_1CmacSetKey(
return;
}
key = getByteArray(env, key_object);
key = getByteArrayIsCopy(env, key_object, &keyIsCopy);
keySz = getByteArrayLength(env, key_object);
if (!cmac || !key) {
@ -134,6 +135,7 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_AesCmac_wc_1CmacSetKey(
LogStr("wc_InitCmac(cmac=%p, key, %d) = %d\n", cmac, keySz, ret);
zeroizeByteArrayCopy(key, keySz, keyIsCopy);
releaseByteArray(env, key_object, key, JNI_ABORT);
#else
throwNotCompiledInException(env);
@ -300,9 +302,11 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_AesCmac_wc_1AesCmacGenerate(
byte* key = NULL;
byte* mac = NULL;
word32 actualDataSz, actualKeySz, actualMacArraySz;
jboolean keyIsCopy = JNI_FALSE;
data = getByteArray(env, data_object);
key = getByteArray(env, key_object);
key = getByteArrayIsCopy(env, key_object, &keyIsCopy);
actualKeySz = getByteArrayLength(env, key_object);
mac = getByteArray(env, mac_object);
if (data == NULL || key == NULL || mac == NULL) {
@ -312,7 +316,6 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_AesCmac_wc_1AesCmacGenerate(
if (ret == 0) {
/* Validate size parameters against actual array sizes */
actualDataSz = getByteArrayLength(env, data_object);
actualKeySz = getByteArrayLength(env, key_object);
actualMacArraySz = getByteArrayLength(env, mac_object);
if (dataSz < 0 || keySz < 0 || macSz < 0 ||
@ -352,6 +355,7 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_AesCmac_wc_1AesCmacGenerate(
data, dataSz, key, keySz, ret);
releaseByteArray(env, data_object, data, JNI_ABORT);
zeroizeByteArrayCopy(key, actualKeySz, keyIsCopy);
releaseByteArray(env, key_object, key, JNI_ABORT);
releaseByteArray(env, mac_object, mac, JNI_ABORT);
@ -372,10 +376,12 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_AesCmac_wc_1AesCmacVerify(
byte* data = NULL;
byte* key = NULL;
word32 actualMacSz, actualDataSz, actualKeySz;
jboolean keyIsCopy = JNI_FALSE;
mac = getByteArray(env, mac_object);
data = getByteArray(env, data_object);
key = getByteArray(env, key_object);
key = getByteArrayIsCopy(env, key_object, &keyIsCopy);
actualKeySz = getByteArrayLength(env, key_object);
if (mac == NULL || data == NULL || key == NULL) {
ret = BAD_FUNC_ARG;
@ -385,7 +391,6 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_AesCmac_wc_1AesCmacVerify(
/* Validate size parameters against actual array sizes */
actualMacSz = getByteArrayLength(env, mac_object);
actualDataSz = getByteArrayLength(env, data_object);
actualKeySz = getByteArrayLength(env, key_object);
if (macSz < 0 || dataSz < 0 || keySz < 0 ||
(word32)macSz > actualMacSz ||
@ -405,6 +410,7 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_AesCmac_wc_1AesCmacVerify(
releaseByteArray(env, mac_object, mac, JNI_ABORT);
releaseByteArray(env, data_object, data, JNI_ABORT);
zeroizeByteArrayCopy(key, actualKeySz, keyIsCopy);
releaseByteArray(env, key_object, key, JNI_ABORT);
return ret;

View File

@ -117,6 +117,7 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_AesGcm_wc_1AesGcmSetKey
Aes* aes = NULL;
const byte* key = NULL;
word32 keyLen = 0;
jboolean keyIsCopy = JNI_FALSE;
aes = (Aes*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
@ -125,7 +126,8 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_AesGcm_wc_1AesGcmSetKey
}
if (keyArr != NULL) {
key = (const byte*)(*env)->GetByteArrayElements(env, keyArr, NULL);
key = (const byte*)(*env)->GetByteArrayElements(env, keyArr,
&keyIsCopy);
keyLen = (*env)->GetArrayLength(env, keyArr);
}
@ -138,6 +140,7 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_AesGcm_wc_1AesGcmSetKey
}
if (keyArr != NULL) {
zeroizeByteArrayCopy((byte*)key, keyLen, keyIsCopy);
(*env)->ReleaseByteArrayElements(env, keyArr, (jbyte*)key, JNI_ABORT);
}

View File

@ -111,6 +111,7 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_AesGmac_wc_1GmacSetKey(
Gmac* gmac = NULL;
byte* key = NULL;
word32 keySz = 0;
jboolean keyIsCopy = JNI_FALSE;
gmac = (Gmac*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
@ -118,7 +119,7 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_AesGmac_wc_1GmacSetKey(
return;
}
key = getByteArray(env, key_object);
key = getByteArrayIsCopy(env, key_object, &keyIsCopy);
keySz = getByteArrayLength(env, key_object);
if (!gmac || !key) {
@ -133,6 +134,7 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_AesGmac_wc_1GmacSetKey(
LogStr("wc_GmacSetKey(gmac=%p, key, %d) = %d\n", gmac, keySz, ret);
zeroizeByteArrayCopy(key, keySz, keyIsCopy);
releaseByteArray(env, key_object, key, JNI_ABORT);
#else
throwNotCompiledInException(env);
@ -220,8 +222,10 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_AesGmac_wc_1Gmac(
byte* authIn = NULL;
byte* authTag = NULL;
word32 keySz = 0, ivSz = 0, authInSz = 0, authTagSz = 0;
jboolean keyIsCopy = JNI_FALSE;
key = getByteArray(env, key_object);
key = getByteArrayIsCopy(env, key_object, &keyIsCopy);
keySz = getByteArrayLength(env, key_object);
iv = getByteArray(env, iv_object);
authIn = getByteArray(env, authIn_object);
authTag = getByteArray(env, authTag_object);
@ -234,7 +238,6 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_AesGmac_wc_1Gmac(
}
if (ret == 0) {
keySz = getByteArrayLength(env, key_object);
ivSz = getByteArrayLength(env, iv_object);
authInSz = getByteArrayLength(env, authIn_object);
authTagSz = getByteArrayLength(env, authTag_object);
@ -269,6 +272,7 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_AesGmac_wc_1Gmac(
"authInSz=%d, authTag=%p, authTagSz=%d, ret=%d\n",
key, keySz, iv, ivSz, authIn, authInSz, authTag, authTagSz, ret);
zeroizeByteArrayCopy(key, keySz, keyIsCopy);
releaseByteArray(env, key_object, key, JNI_ABORT);
releaseByteArray(env, iv_object, iv, JNI_ABORT);
releaseByteArray(env, authIn_object, authIn, JNI_ABORT);
@ -295,8 +299,10 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_AesGmac_wc_1GmacVerify(
byte* authIn = NULL;
byte* authTag = NULL;
word32 keySz = 0, ivSz = 0, authInSz = 0, authTagSz = 0;
jboolean keyIsCopy = JNI_FALSE;
key = getByteArray(env, key_object);
key = getByteArrayIsCopy(env, key_object, &keyIsCopy);
keySz = getByteArrayLength(env, key_object);
iv = getByteArray(env, iv_object);
authIn = getByteArray(env, authIn_object);
authTag = getByteArray(env, authTag_object);
@ -309,7 +315,6 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_AesGmac_wc_1GmacVerify(
}
if (ret == 0) {
keySz = getByteArrayLength(env, key_object);
ivSz = getByteArrayLength(env, iv_object);
authInSz = getByteArrayLength(env, authIn_object);
authTagSz = getByteArrayLength(env, authTag_object);
@ -344,6 +349,7 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_AesGmac_wc_1GmacVerify(
"authInSz=%d, authTag=%p, authTagSz=%d, ret=%d\n",
key, keySz, iv, ivSz, authIn, authInSz, authTag, authTagSz, ret);
zeroizeByteArrayCopy(key, keySz, keyIsCopy);
releaseByteArray(env, key_object, key, JNI_ABORT);
releaseByteArray(env, iv_object, iv, JNI_ABORT);
releaseByteArray(env, authIn_object, authIn, JNI_ABORT);

View File

@ -159,13 +159,14 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Curve25519_wc_1curve25519_1imp
byte* priv = NULL;
byte* pub = NULL;
word32 privSz = 0, pubSz = 0;
jboolean privIsCopy = JNI_FALSE;
curve25519 = (curve25519_key*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
/* getNativeStruct may throw exception, prevent throwing another */
return;
}
priv = getByteArray(env, priv_object);
priv = getByteArrayIsCopy(env, priv_object, &privIsCopy);
privSz = getByteArrayLength(env, priv_object);
pub = getByteArray(env, pub_object);
pubSz = getByteArrayLength(env, pub_object);
@ -184,6 +185,7 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Curve25519_wc_1curve25519_1imp
LogStr("wc_curve25519_import_private_key(curve25519=%p) = %d\n", curve25519, ret);
zeroizeByteArrayCopy(priv, privSz, privIsCopy);
releaseByteArray(env, priv_object, priv, JNI_ABORT);
releaseByteArray(env, pub_object, pub, JNI_ABORT);
#else
@ -199,13 +201,14 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Curve25519_wc_1curve25519_1imp
curve25519_key* curve25519 = NULL;
byte* priv = NULL;
word32 privSz = 0;
jboolean privIsCopy = JNI_FALSE;
curve25519 = (curve25519_key*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
/* getNativeStruct may throw exception, prevent throwing another */
return;
}
priv = getByteArray(env, priv_object);
priv = getByteArrayIsCopy(env, priv_object, &privIsCopy);
privSz = getByteArrayLength(env, priv_object);
/* pub may be null if only importing private key */
@ -221,6 +224,7 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Curve25519_wc_1curve25519_1imp
LogStr("wc_curve25519_import_private_key(curve25519=%p) = %d\n", curve25519, ret);
zeroizeByteArrayCopy(priv, privSz, privIsCopy);
releaseByteArray(env, priv_object, priv, JNI_ABORT);
#else
throwNotCompiledInException(env);

View File

@ -69,6 +69,8 @@ Java_com_wolfssl_wolfcrypt_Des3_native_1set_1key_1internal(
Des3* des = NULL;
byte* key = NULL;
byte* iv = NULL;
word32 keySz = 0;
jboolean keyIsCopy = JNI_FALSE;
des = (Des3*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
@ -76,7 +78,8 @@ Java_com_wolfssl_wolfcrypt_Des3_native_1set_1key_1internal(
return;
}
key = getByteArray(env, key_object);
key = getByteArrayIsCopy(env, key_object, &keyIsCopy);
keySz = getByteArrayLength(env, key_object);
iv = getByteArray(env, iv_object);
ret = (!des || !key) /* iv is optional */
@ -88,6 +91,7 @@ Java_com_wolfssl_wolfcrypt_Des3_native_1set_1key_1internal(
LogStr("wc_Des3SetKey(Des3=%p, key, iv, opmode) = %d\n", des, ret);
zeroizeByteArrayCopy(key, keySz, keyIsCopy);
releaseByteArray(env, key_object, key, JNI_ABORT);
releaseByteArray(env, iv_object, iv, JNI_ABORT);
#else

View File

@ -29,6 +29,7 @@
#include <wolfssl/version.h>
#include <wolfssl/wolfcrypt/dh.h>
#include <wolfssl/wolfcrypt/asn_public.h>
#include <wolfssl/wolfcrypt/memory.h>
#include <com_wolfssl_wolfcrypt_Dh.h>
#include <wolfcrypt_jni_NativeStruct.h>
@ -399,6 +400,7 @@ Java_com_wolfssl_wolfcrypt_Dh_wc_1DhAgree(
byte* pub = NULL;
byte* secret = NULL;
word32 privSz = 0, pubSz = 0, secretSz = 0;
jboolean privIsCopy = JNI_FALSE;
key = (DhKey*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
@ -406,7 +408,7 @@ Java_com_wolfssl_wolfcrypt_Dh_wc_1DhAgree(
return NULL;
}
priv = getByteArray(env, priv_object);
priv = getByteArrayIsCopy(env, priv_object, &privIsCopy);
privSz = getByteArrayLength(env, priv_object);
pub = getByteArray(env, pub_object);
pubSz = getByteArrayLength(env, pub_object);
@ -420,6 +422,7 @@ Java_com_wolfssl_wolfcrypt_Dh_wc_1DhAgree(
throwOutOfMemoryException(
env, "Failed to allocate shared secret buffer");
zeroizeByteArrayCopy(priv, privSz, privIsCopy);
releaseByteArray(env, priv_object, priv, JNI_ABORT);
releaseByteArray(env, pub_object, pub, JNI_ABORT);
@ -464,6 +467,7 @@ Java_com_wolfssl_wolfcrypt_Dh_wc_1DhAgree(
XFREE(secret, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
zeroizeByteArrayCopy(priv, privSz, privIsCopy);
releaseByteArray(env, priv_object, priv, JNI_ABORT);
releaseByteArray(env, pub_object, pub, JNI_ABORT);
#else
@ -783,6 +787,7 @@ Java_com_wolfssl_wolfcrypt_Dh_wc_1DhImportKeyPair(
byte* p = NULL;
byte* g = NULL;
word32 privSz = 0, pubSz = 0, pSz = 0, gSz = 0;
jboolean privIsCopy = JNI_FALSE;
key = (DhKey*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
@ -814,7 +819,7 @@ Java_com_wolfssl_wolfcrypt_Dh_wc_1DhImportKeyPair(
if (ret == 0) {
/* Get private key if provided */
if (priv_object != NULL) {
priv = getByteArray(env, priv_object);
priv = getByteArrayIsCopy(env, priv_object, &privIsCopy);
privSz = getByteArrayLength(env, priv_object);
}
@ -835,6 +840,7 @@ Java_com_wolfssl_wolfcrypt_Dh_wc_1DhImportKeyPair(
releaseByteArray(env, p_object, p, JNI_ABORT);
releaseByteArray(env, g_object, g, JNI_ABORT);
if (priv_object != NULL) {
zeroizeByteArrayCopy(priv, privSz, privIsCopy);
releaseByteArray(env, priv_object, priv, JNI_ABORT);
}
if (pub_object != NULL) {
@ -1126,6 +1132,7 @@ Java_com_wolfssl_wolfcrypt_Dh_wc_1DhPrivateKeyDecode(
byte* pkcs8 = NULL;
word32 pkcs8Sz = 0;
word32 idx = 0;
jboolean pkcs8IsCopy = JNI_FALSE;
key = (DhKey*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
@ -1138,7 +1145,7 @@ Java_com_wolfssl_wolfcrypt_Dh_wc_1DhPrivateKeyDecode(
return NULL;
}
pkcs8 = getByteArray(env, pkcs8_object);
pkcs8 = getByteArrayIsCopy(env, pkcs8_object, &pkcs8IsCopy);
pkcs8Sz = getByteArrayLength(env, pkcs8_object);
if (pkcs8 == NULL) {
@ -1166,6 +1173,7 @@ Java_com_wolfssl_wolfcrypt_Dh_wc_1DhPrivateKeyDecode(
LogStr("wc_DhKeyDecode(pkcs8=%p, key=%p) = %d\n", pkcs8, key, ret);
zeroizeByteArrayCopy(pkcs8, pkcs8Sz, pkcs8IsCopy);
releaseByteArray(env, pkcs8_object, pkcs8, JNI_ABORT);
if (ret != 0) {

View File

@ -30,6 +30,7 @@
#include <wolfssl/version.h>
#include <wolfssl/wolfcrypt/ecc.h>
#include <wolfssl/wolfcrypt/asn.h>
#include <wolfssl/wolfcrypt/memory.h>
#include <com_wolfssl_wolfcrypt_Ecc.h>
#include <wolfcrypt_jni_NativeStruct.h>
@ -304,6 +305,7 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Ecc_wc_1ecc_1import_1private
byte* pub = NULL;
word32 privSz = 0, pubSz = 0;
const char* name = NULL;
jboolean privIsCopy = JNI_FALSE;
ecc = (ecc_key*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
@ -311,7 +313,7 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Ecc_wc_1ecc_1import_1private
return;
}
priv = getByteArray(env, priv_object);
priv = getByteArrayIsCopy(env, priv_object, &privIsCopy);
privSz = getByteArrayLength(env, priv_object);
pub = getByteArray(env, pub_object);
pubSz = getByteArrayLength(env, pub_object);
@ -360,6 +362,7 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Ecc_wc_1ecc_1import_1private
LogStr("wc_ecc_import_private_key(ecc=%p) = %d\n", ecc, ret);
zeroizeByteArrayCopy(priv, privSz, privIsCopy);
releaseByteArray(env, priv_object, priv, JNI_ABORT);
releaseByteArray(env, pub_object, pub, JNI_ABORT);
#else
@ -569,6 +572,7 @@ Java_com_wolfssl_wolfcrypt_Ecc_wc_1EccPrivateKeyDecode(
ecc_key* ecc = NULL;
byte* key = NULL;
word32 keySz = 0;
jboolean keyIsCopy = JNI_FALSE;
ecc = (ecc_key*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
@ -576,7 +580,7 @@ Java_com_wolfssl_wolfcrypt_Ecc_wc_1EccPrivateKeyDecode(
return;
}
key = getByteArray(env, key_object);
key = getByteArrayIsCopy(env, key_object, &keyIsCopy);
keySz = getByteArrayLength(env, key_object);
if (ecc == NULL || key == NULL) {
@ -593,6 +597,7 @@ Java_com_wolfssl_wolfcrypt_Ecc_wc_1EccPrivateKeyDecode(
LogStr("wc_EccPrivateKeyDecode(key=%p, keySz=%d, ecc=%p) = %d\n",
key, (int)keySz, ecc, ret);
zeroizeByteArrayCopy(key, keySz, keyIsCopy);
releaseByteArray(env, key_object, key, JNI_ABORT);
#else
throwNotCompiledInException(env);
@ -1439,6 +1444,7 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Ecc_wc_1ecc_1import_1private_1
word32 privKeySz = 0;
const char* name = NULL;
int curveId = 0;
jboolean privIsCopy = JNI_FALSE;
ecc = (ecc_key*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
@ -1446,7 +1452,7 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Ecc_wc_1ecc_1import_1private_1
return;
}
privKey = getByteArray(env, priv_object);
privKey = getByteArrayIsCopy(env, priv_object, &privIsCopy);
privKeySz = getByteArrayLength(env, priv_object);
if (ecc == NULL || privKey == NULL || curveName == NULL) {
@ -1481,6 +1487,7 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Ecc_wc_1ecc_1import_1private_1
LogStr("wc_ecc_import_unsigned(ecc=%p, privKey=%p) = %d\n",
ecc, privKey, ret);
zeroizeByteArrayCopy(privKey, privKeySz, privIsCopy);
releaseByteArray(env, priv_object, privKey, JNI_ABORT);
#else
throwNotCompiledInException(env);

View File

@ -186,13 +186,14 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Ed25519_wc_1ed25519_1import_1p
byte* priv = NULL;
byte* pub = NULL;
word32 privSz = 0, pubSz = 0;
jboolean privIsCopy = JNI_FALSE;
ed25519 = (ed25519_key*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
/* getNativeStruct may throw exception, prevent throwing another */
return;
}
priv = getByteArray(env, priv_object);
priv = getByteArrayIsCopy(env, priv_object, &privIsCopy);
privSz = getByteArrayLength(env, priv_object);
pub = getByteArray(env, pub_object);
pubSz = getByteArrayLength(env, pub_object);
@ -214,6 +215,7 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Ed25519_wc_1ed25519_1import_1p
LogStr("wc_ed25519_import_private_key(ed25519=%p) = %d\n", ed25519, ret);
zeroizeByteArrayCopy(priv, privSz, privIsCopy);
releaseByteArray(env, priv_object, priv, JNI_ABORT);
releaseByteArray(env, pub_object, pub, JNI_ABORT);
#else
@ -263,13 +265,14 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Ed25519_wc_1ed25519_1import_1p
ed25519_key* ed25519 = NULL;
byte* priv = NULL;
word32 privSz = 0;
jboolean privIsCopy = JNI_FALSE;
ed25519 = (ed25519_key*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
/* getNativeStruct may throw exception, prevent throwing another */
return;
}
priv = getByteArray(env, priv_object);
priv = getByteArrayIsCopy(env, priv_object, &privIsCopy);
privSz = getByteArrayLength(env, priv_object);
if (!ed25519 || !priv) {
@ -284,6 +287,7 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Ed25519_wc_1ed25519_1import_1p
LogStr("wc_ed25519_import_private_key(ed25519=%p) = %d\n", ed25519, ret);
zeroizeByteArrayCopy(priv, privSz, privIsCopy);
releaseByteArray(env, priv_object, priv, JNI_ABORT);
#else
throwNotCompiledInException(env);

View File

@ -25,7 +25,9 @@
#elif !defined(__ANDROID__)
#include <wolfssl/options.h>
#endif
#include <wolfssl/version.h>
#include <wolfssl/wolfcrypt/types.h>
#include <wolfssl/wolfcrypt/memory.h>
#include <com_wolfssl_wolfcrypt_NativeStruct.h>
#include <wolfcrypt_jni_NativeStruct.h>
@ -207,6 +209,31 @@ byte* getByteArray(JNIEnv* env, jbyteArray array)
return array ? (byte*)(*env)->GetByteArrayElements(env, array, NULL) : NULL;
}
/* Same as getByteArray() but also returns the JNI isCopy flag. Flag is
* set to JNI_FALSE first so it is defined even when array is NULL */
byte* getByteArrayIsCopy(JNIEnv* env, jbyteArray array, jboolean* isCopy)
{
if (isCopy != NULL) {
*isCopy = JNI_FALSE;
}
return array ?
(byte*)(*env)->GetByteArrayElements(env, array, isCopy) : NULL;
}
/* Zeroize native copy of a sensitive array before JNI_ABORT release.
* Skip pinned arrays, they alias the caller's live Java array */
void zeroizeByteArrayCopy(byte* buf, word32 sz, jboolean isCopy)
{
if (buf != NULL && isCopy == JNI_TRUE) {
#if (LIBWOLFSSL_VERSION_HEX >= 0x05008004) && \
!defined(WOLFSSL_NO_FORCE_ZERO)
wc_ForceZero(buf, sz);
#else
XMEMSET(buf, 0, sz);
#endif
}
}
void releaseByteArray(JNIEnv* env, jbyteArray array, byte* elements, jint abort)
{
if ((env != NULL) && (array != NULL) && (elements != NULL)) {

View File

@ -760,6 +760,7 @@ Java_com_wolfssl_wolfcrypt_Rsa_wc_1RsaPrivateKeyDecode(
RsaKey* key = NULL;
byte* k = NULL;
word32 kSz = 0, index = 0;
jboolean kIsCopy = JNI_FALSE;
key = (RsaKey*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
@ -767,7 +768,7 @@ Java_com_wolfssl_wolfcrypt_Rsa_wc_1RsaPrivateKeyDecode(
return;
}
k = getByteArray(env, key_object);
k = getByteArrayIsCopy(env, key_object, &kIsCopy);
kSz = getByteArrayLength(env, key_object);
if (key == NULL || k == NULL) {
@ -785,6 +786,7 @@ Java_com_wolfssl_wolfcrypt_Rsa_wc_1RsaPrivateKeyDecode(
LogStr("key[%u]: [%p]\n", (word32)kSz, k);
LogHex((byte*) k, 0, kSz);
zeroizeByteArrayCopy(k, kSz, kIsCopy);
releaseByteArray(env, key_object, k, JNI_ABORT);
#else
@ -801,6 +803,7 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Rsa_wc_1RsaPrivateKeyDecodePKC
RsaKey* key = NULL;
byte* k = NULL;
word32 kSz = 0, offset = 0;
jboolean kIsCopy = JNI_FALSE;
key = (RsaKey*) getNativeStruct(env, this);
if ((*env)->ExceptionOccurred(env)) {
@ -808,7 +811,7 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Rsa_wc_1RsaPrivateKeyDecodePKC
return;
}
k = getByteArray(env, key_object);
k = getByteArrayIsCopy(env, key_object, &kIsCopy);
kSz = getByteArrayLength(env, key_object);
if (key == NULL || k == NULL) {
@ -834,6 +837,7 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Rsa_wc_1RsaPrivateKeyDecodePKC
LogStr("key[%u]: [%p]\n", (word32)kSz, k);
LogHex((byte*) k, 0, kSz);
zeroizeByteArrayCopy(k, kSz, kIsCopy);
releaseByteArray(env, key_object, k, JNI_ABORT);
#else
throwNotCompiledInException(env);
@ -2160,6 +2164,12 @@ Java_com_wolfssl_wolfcrypt_Rsa_wc_1RsaImportCrtKey(
byte* u = NULL;
word32 nSz = 0, eSz = 0, dSz = 0, pSz = 0;
word32 qSz = 0, dPSz = 0, dQSz = 0, uSz = 0;
jboolean dIsCopy = JNI_FALSE;
jboolean pIsCopy = JNI_FALSE;
jboolean qIsCopy = JNI_FALSE;
jboolean dPIsCopy = JNI_FALSE;
jboolean dQIsCopy = JNI_FALSE;
jboolean uIsCopy = JNI_FALSE;
#ifndef WOLFSSL_PUBLIC_MP
ret = NOT_COMPILED_IN;
@ -2179,22 +2189,22 @@ Java_com_wolfssl_wolfcrypt_Rsa_wc_1RsaImportCrtKey(
e = getByteArray(env, e_object);
eSz = getByteArrayLength(env, e_object);
d = getByteArray(env, d_object);
d = getByteArrayIsCopy(env, d_object, &dIsCopy);
dSz = getByteArrayLength(env, d_object);
p = getByteArray(env, p_object);
p = getByteArrayIsCopy(env, p_object, &pIsCopy);
pSz = getByteArrayLength(env, p_object);
q = getByteArray(env, q_object);
q = getByteArrayIsCopy(env, q_object, &qIsCopy);
qSz = getByteArrayLength(env, q_object);
dP = getByteArray(env, dP_object);
dP = getByteArrayIsCopy(env, dP_object, &dPIsCopy);
dPSz = getByteArrayLength(env, dP_object);
dQ = getByteArray(env, dQ_object);
dQ = getByteArrayIsCopy(env, dQ_object, &dQIsCopy);
dQSz = getByteArrayLength(env, dQ_object);
u = getByteArray(env, u_object);
u = getByteArrayIsCopy(env, u_object, &uIsCopy);
uSz = getByteArrayLength(env, u_object);
/* Validate inputs */
@ -2252,15 +2262,21 @@ Java_com_wolfssl_wolfcrypt_Rsa_wc_1RsaImportCrtKey(
throwWolfCryptExceptionFromError(env, ret);
}
/* Release all byte arrays */
releaseByteArray(env, n_object, n, ret);
releaseByteArray(env, e_object, e, ret);
releaseByteArray(env, d_object, d, ret);
releaseByteArray(env, p_object, p, ret);
releaseByteArray(env, q_object, q, ret);
releaseByteArray(env, dP_object, dP, ret);
releaseByteArray(env, dQ_object, dQ, ret);
releaseByteArray(env, u_object, u, ret);
/* Release all byte arrays, zeroize private components */
releaseByteArray(env, n_object, n, JNI_ABORT);
releaseByteArray(env, e_object, e, JNI_ABORT);
zeroizeByteArrayCopy(d, dSz, dIsCopy);
releaseByteArray(env, d_object, d, JNI_ABORT);
zeroizeByteArrayCopy(p, pSz, pIsCopy);
releaseByteArray(env, p_object, p, JNI_ABORT);
zeroizeByteArrayCopy(q, qSz, qIsCopy);
releaseByteArray(env, q_object, q, JNI_ABORT);
zeroizeByteArrayCopy(dP, dPSz, dPIsCopy);
releaseByteArray(env, dP_object, dP, JNI_ABORT);
zeroizeByteArrayCopy(dQ, dQSz, dQIsCopy);
releaseByteArray(env, dQ_object, dQ, JNI_ABORT);
zeroizeByteArrayCopy(u, uSz, uIsCopy);
releaseByteArray(env, u_object, u, JNI_ABORT);
#else
(void)env;
(void)this;

View File

@ -735,6 +735,92 @@ public class RsaTest {
key.releaseNativeStruct();
}
/**
* Native wc_RsaImportCrtKey zeroizes its component copies and must
* release with JNI_ABORT.
*/
@Test
public void importRawPrivateKeyShouldNotModifyCallerArrays() {
Rsa genKey = makeKeyWithRetry(2048, 65537, rng);
int bufSz = 512;
byte[] n = new byte[bufSz];
byte[] e = new byte[bufSz];
byte[] d = new byte[bufSz];
byte[] p = new byte[bufSz];
byte[] q = new byte[bufSz];
byte[] dP = new byte[bufSz];
byte[] dQ = new byte[bufSz];
byte[] u = new byte[bufSz];
long[] nSz = { bufSz };
long[] eSz = { bufSz };
long[] dSz = { bufSz };
long[] pSz = { bufSz };
long[] qSz = { bufSz };
long[] dPSz = { bufSz };
long[] dQSz = { bufSz };
long[] uSz = { bufSz };
try {
genKey.exportRawPrivateKey(n, nSz, e, eSz, d, dSz, p, pSz, q,
qSz, dP, dPSz, dQ, dQSz, u, uSz);
} catch (WolfCryptException ex) {
genKey.releaseNativeStruct();
Assume.assumeTrue("raw export not compiled in native wolfSSL",
ex.getError() != WolfCryptError.NOT_COMPILED_IN);
throw ex;
}
genKey.releaseNativeStruct();
/* importRawPrivateKey must not modify any caller component array */
byte[] nIn = Arrays.copyOf(n, (int)nSz[0]);
byte[] eIn = Arrays.copyOf(e, (int)eSz[0]);
byte[] dIn = Arrays.copyOf(d, (int)dSz[0]);
byte[] pIn = Arrays.copyOf(p, (int)pSz[0]);
byte[] qIn = Arrays.copyOf(q, (int)qSz[0]);
byte[] dPIn = Arrays.copyOf(dP, (int)dPSz[0]);
byte[] dQIn = Arrays.copyOf(dQ, (int)dQSz[0]);
byte[] uIn = Arrays.copyOf(u, (int)uSz[0]);
byte[] nCopy = nIn.clone();
byte[] eCopy = eIn.clone();
byte[] dCopy = dIn.clone();
byte[] pCopy = pIn.clone();
byte[] qCopy = qIn.clone();
byte[] dPCopy = dPIn.clone();
byte[] dQCopy = dQIn.clone();
byte[] uCopy = uIn.clone();
Rsa rawKey = new Rsa();
try {
rawKey.importRawPrivateKey(nIn, eIn, dIn, pIn, qIn, dPIn,
dQIn, uIn);
assertArrayEquals("importRawPrivateKey must not modify n",
nCopy, nIn);
assertArrayEquals("importRawPrivateKey must not modify e",
eCopy, eIn);
assertArrayEquals("importRawPrivateKey must not modify d",
dCopy, dIn);
assertArrayEquals("importRawPrivateKey must not modify p",
pCopy, pIn);
assertArrayEquals("importRawPrivateKey must not modify q",
qCopy, qIn);
assertArrayEquals("importRawPrivateKey must not modify dP",
dPCopy, dPIn);
assertArrayEquals("importRawPrivateKey must not modify dQ",
dQCopy, dQIn);
assertArrayEquals("importRawPrivateKey must not modify u",
uCopy, uIn);
} catch (WolfCryptException ex) {
Assume.assumeTrue("raw import not compiled in native wolfSSL",
ex.getError() != WolfCryptError.NOT_COMPILED_IN);
throw ex;
} finally {
rawKey.releaseNativeStruct();
}
}
@Test
public void rsaOperations() {
Rsa priv = new Rsa();