diff --git a/jni/include/wolfcrypt_jni_NativeStruct.h b/jni/include/wolfcrypt_jni_NativeStruct.h index 06eccd21..04d4b319 100644 --- a/jni/include/wolfcrypt_jni_NativeStruct.h +++ b/jni/include/wolfcrypt_jni_NativeStruct.h @@ -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); diff --git a/jni/jni_aesccm.c b/jni/jni_aesccm.c index 323c197d..dbada278 100644 --- a/jni/jni_aesccm.c +++ b/jni/jni_aesccm.c @@ -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); } diff --git a/jni/jni_aescmac.c b/jni/jni_aescmac.c index 2f43a29c..4109b99a 100644 --- a/jni/jni_aescmac.c +++ b/jni/jni_aescmac.c @@ -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; diff --git a/jni/jni_aesgcm.c b/jni/jni_aesgcm.c index 51e2fca1..a434f548 100644 --- a/jni/jni_aesgcm.c +++ b/jni/jni_aesgcm.c @@ -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); } diff --git a/jni/jni_aesgmac.c b/jni/jni_aesgmac.c index 1d666921..f5401828 100644 --- a/jni/jni_aesgmac.c +++ b/jni/jni_aesgmac.c @@ -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); diff --git a/jni/jni_curve25519.c b/jni/jni_curve25519.c index 43f7837a..70ee63b2 100644 --- a/jni/jni_curve25519.c +++ b/jni/jni_curve25519.c @@ -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); diff --git a/jni/jni_des3.c b/jni/jni_des3.c index 569559c8..20626a36 100644 --- a/jni/jni_des3.c +++ b/jni/jni_des3.c @@ -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 diff --git a/jni/jni_dh.c b/jni/jni_dh.c index 851eeed6..621f4ba4 100644 --- a/jni/jni_dh.c +++ b/jni/jni_dh.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -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) { diff --git a/jni/jni_ecc.c b/jni/jni_ecc.c index 995328d8..0aee05cc 100644 --- a/jni/jni_ecc.c +++ b/jni/jni_ecc.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -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); @@ -1442,6 +1447,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)) { @@ -1449,7 +1455,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) { @@ -1489,6 +1495,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); diff --git a/jni/jni_ed25519.c b/jni/jni_ed25519.c index 12c7e786..a0bc1e9a 100644 --- a/jni/jni_ed25519.c +++ b/jni/jni_ed25519.c @@ -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); diff --git a/jni/jni_native_struct.c b/jni/jni_native_struct.c index 858458a5..6eacfe22 100644 --- a/jni/jni_native_struct.c +++ b/jni/jni_native_struct.c @@ -25,7 +25,9 @@ #elif !defined(__ANDROID__) #include #endif +#include #include +#include #include #include @@ -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)) { diff --git a/jni/jni_rsa.c b/jni/jni_rsa.c index d11376de..75a92865 100644 --- a/jni/jni_rsa.c +++ b/jni/jni_rsa.c @@ -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; diff --git a/src/test/java/com/wolfssl/wolfcrypt/test/RsaTest.java b/src/test/java/com/wolfssl/wolfcrypt/test/RsaTest.java index 726c2204..738e01aa 100644 --- a/src/test/java/com/wolfssl/wolfcrypt/test/RsaTest.java +++ b/src/test/java/com/wolfssl/wolfcrypt/test/RsaTest.java @@ -735,6 +735,92 @@ public void exportRawPrivateKeySizesCorrect() { 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();