Skip to content
27 changes: 24 additions & 3 deletions jni/jni_aescmac.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@
/* #define WOLFCRYPT_JNI_DEBUG_ON */
#include <wolfcrypt_jni_debug.h>

#if (LIBWOLFSSL_VERSION_HEX >= 0x05006006) && (!defined(HAVE_FIPS) || \
(defined(HAVE_FIPS_VERSION) && (HAVE_FIPS_VERSION >= 6)))
#define WC_JNI_CMAC_HAVE_FREE
#endif

JNIEXPORT jlong JNICALL Java_com_wolfssl_wolfcrypt_AesCmac_mallocNativeStruct_1internal(
JNIEnv* env, jobject this)
{
Expand Down Expand Up @@ -94,10 +99,19 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_AesCmac_native_1free(
LogStr("free Cmac %p\n", cmac);

if (cmac) {
/* Only clear the CMAC struct - do NOT free the memory here.
* The base class NativeStruct.xfree() will handle the actual
* memory deallocation to avoid double-free. */
/* Release and zeroize CMAC context contents, not freeing the
* memory since base class NativeStruct.xfree() will handle that
* deallocation. */
#ifdef WC_JNI_CMAC_HAVE_FREE
if (cmac->type == WC_CMAC_AES) {
wc_CmacFree(cmac);
}
else {
XMEMSET(cmac, 0, sizeof(Cmac));
}
#else
XMEMSET(cmac, 0, sizeof(Cmac));
#endif
}
#else
throwNotCompiledInException(env);
Expand Down Expand Up @@ -125,6 +139,13 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_AesCmac_wc_1CmacSetKey(
if (!cmac || !key) {
ret = BAD_FUNC_ARG;
} else {
#ifdef WC_JNI_CMAC_HAVE_FREE
/* Free any active context first, reset() and repeated setKey() calls
* reinitialize the same struct */
if (cmac->type == WC_CMAC_AES) {
wc_CmacFree(cmac);
}
#endif
/* Initialize CMAC with the provided key */
ret = wc_InitCmac(cmac, key, keySz, WC_CMAC_AES, NULL);
}
Expand Down
8 changes: 3 additions & 5 deletions jni/jni_curve25519.c
Original file line number Diff line number Diff line change
Expand Up @@ -170,11 +170,10 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Curve25519_wc_1curve25519_1imp
pub = getByteArray(env, pub_object);
pubSz = getByteArrayLength(env, pub_object);

/* pub may be null if only importing private key */
if (!curve25519 || !priv) {
ret = BAD_FUNC_ARG;
} else {
/* detect, and later skip, leading zero byte */
/* Import raw fixed width private and public key bytes unchanged */
ret = wc_curve25519_import_private_raw(priv, privSz, pub,
pubSz, curve25519);
}
Expand Down Expand Up @@ -208,11 +207,10 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Curve25519_wc_1curve25519_1imp
priv = getByteArray(env, priv_object);
privSz = getByteArrayLength(env, priv_object);

/* pub may be null if only importing private key */
if (!curve25519 || !priv) {
ret = BAD_FUNC_ARG;
} else {
/* detect, and later skip, leading zero byte */
/* Import raw fixed width private key bytes unchanged */
ret = wc_curve25519_import_private(priv, privSz, curve25519);
}

Expand Down Expand Up @@ -247,7 +245,7 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Curve25519_wc_1curve25519_1imp
if (!curve25519 || !pub) {
ret = BAD_FUNC_ARG;
} else {
/* detect, and later skip, leading zero byte */
/* Import raw fixed width public key bytes unchanged */
ret = wc_curve25519_import_public(pub, pubSz, curve25519);
}

Expand Down
5 changes: 3 additions & 2 deletions jni/jni_ed25519.c
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,8 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Ed25519_wc_1ed25519_1import_1p
if (!ed25519 || !priv) {
ret = BAD_FUNC_ARG;
} else {
/* detect, and later skip, leading zero byte */
/* Select private only import when no public key is supplied,
* raw fixed width key bytes are passed unchanged */
if (!pub)
ret = wc_ed25519_import_private_only(priv, privSz, ed25519);
else
Expand Down Expand Up @@ -275,7 +276,7 @@ JNIEXPORT void JNICALL Java_com_wolfssl_wolfcrypt_Ed25519_wc_1ed25519_1import_1p
if (!ed25519 || !priv) {
ret = BAD_FUNC_ARG;
} else {
/* detect, and later skip, leading zero byte */
/* Import raw fixed width private key bytes unchanged */
ret = wc_ed25519_import_private_only(priv, privSz, ed25519);
}

Expand Down
98 changes: 40 additions & 58 deletions jni/jni_fips.c
Original file line number Diff line number Diff line change
Expand Up @@ -108,10 +108,11 @@ void NativeErrorCallback(const int ok, const int err, const char * const hash)
#ifdef HAVE_FIPS
JNIEnv* env;
jobject localCb = NULL;
jclass class;
jmethodID method;
jclass class = NULL;
jmethodID method = NULL;
jint ret;
jstring hashStr;
jstring hashStr = NULL;
int needsDetach = 0;

if (g_vm == NULL) {
return;
Expand All @@ -128,6 +129,7 @@ void NativeErrorCallback(const int ok, const int err, const char * const hash)
printf("Failed to attach JNIEnv to thread\n");
return;
}
needsDetach = 1;
}
else if (ret != JNI_OK) {
printf("Unable to get JNIEnv from JavaVM\n");
Expand All @@ -138,64 +140,44 @@ void NativeErrorCallback(const int ok, const int err, const char * const hash)
* so a concurrent wolfCrypt_1SetCb_1fips() cannot free the global
* reference while we use it. The rest of this function uses only the
* local reference and never touches g_errCb again. */
if (!g_fipsCbMutexInit || wc_LockMutex(&g_fipsCbMutex) != 0) {
return;
}
if (g_errCb != NULL &&
(*env)->GetObjectRefType(env, g_errCb) == JNIGlobalRefType) {
localCb = (*env)->NewLocalRef(env, g_errCb);
}
wc_UnLockMutex(&g_fipsCbMutex);

/* Return silently if no valid callback was registered */
if (localCb == NULL) {
if ((*env)->ExceptionOccurred(env)) {
(*env)->ExceptionDescribe(env);
(*env)->ExceptionClear(env);
if (g_fipsCbMutexInit && wc_LockMutex(&g_fipsCbMutex) == 0) {
if (g_errCb != NULL &&
(*env)->GetObjectRefType(env, g_errCb) == JNIGlobalRefType) {
localCb = (*env)->NewLocalRef(env, g_errCb);
}
return;
wc_UnLockMutex(&g_fipsCbMutex);
}

class = (*env)->GetObjectClass(env, localCb);
if (!class) {
if ((*env)->ExceptionOccurred(env)) {
(*env)->ExceptionDescribe(env);
(*env)->ExceptionClear(env);
}
(*env)->DeleteLocalRef(env, localCb);
return;
if (localCb != NULL) {
class = (*env)->GetObjectClass(env, localCb);
}

method = (*env)->GetMethodID(env, class, "errorCallback",
"(IILjava/lang/String;)V");
if (!method) {
if ((*env)->ExceptionOccurred(env)) {
(*env)->ExceptionDescribe(env);
(*env)->ExceptionClear(env);
}
(*env)->DeleteLocalRef(env, localCb);
return;
if (class != NULL) {
method = (*env)->GetMethodID(env, class, "errorCallback",
"(IILjava/lang/String;)V");
}

hashStr = (*env)->NewStringUTF(env, hash);
if (!hashStr) {
if ((*env)->ExceptionOccurred(env)) {
(*env)->ExceptionDescribe(env);
(*env)->ExceptionClear(env);
}
(*env)->DeleteLocalRef(env, localCb);
return;
if (method != NULL) {
hashStr = (*env)->NewStringUTF(env, hash);
}
if (hashStr != NULL) {
(*env)->CallVoidMethod(env, localCb, method, ok, err, hashStr);
(*env)->DeleteLocalRef(env, hashStr);
}

(*env)->CallVoidMethod(env, localCb, method, ok, err, hashStr);

(*env)->DeleteLocalRef(env, hashStr);
(*env)->DeleteLocalRef(env, localCb);

if ((*env)->ExceptionOccurred(env)) {
(*env)->ExceptionDescribe(env);
(*env)->ExceptionClear(env);
}

if (class != NULL) {
(*env)->DeleteLocalRef(env, class);
}
if (localCb != NULL) {
(*env)->DeleteLocalRef(env, localCb);
}

if (needsDetach) {
(*g_vm)->DetachCurrentThread(g_vm);
}
#endif
}

Expand Down Expand Up @@ -1231,10 +1213,10 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_Fips_wc_1AesGcmDecrypt_1fips__
LogStr(
"AesGcmDecrypt_fips(aes=%p, out, in, iv, authTag, authIn) = %d\n",
aes, ret);
LogStr("in[%u]: [%p]\n", (word32)AES_BLOCK_SIZE, in);
LogHex(in, 0, AES_BLOCK_SIZE);
LogStr("out[%u]: [%p]\n", (word32)AES_BLOCK_SIZE, out);
LogHex(out, 0, AES_BLOCK_SIZE);
LogStr("in[%u]: [%p]\n", (word32)size, in);
LogHex(in, 0, size);
LogStr("out[%u]: [%p]\n", (word32)size, out);
LogHex(out, 0, size);
LogStr("iv[%u]: [%p]\n", (word32)ivSz, iv);
LogHex(iv, 0, ivSz);
LogStr("authTag[%u]: [%p]\n", (word32)authTagSz, authTag);
Expand Down Expand Up @@ -1293,10 +1275,10 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_wolfcrypt_Fips_wc_1AesGcmDecrypt_1fips__
LogStr(
"AesGcmDecrypt_fips(aes=%p, out, in, iv, authTag, authIn) = %d\n",
aes, ret);
LogStr("in[%u]: [%p]\n", (word32)AES_BLOCK_SIZE, in);
LogHex(in, 0, AES_BLOCK_SIZE);
LogStr("out[%u]: [%p]\n", (word32)AES_BLOCK_SIZE, out);
LogHex(out, 0, AES_BLOCK_SIZE);
LogStr("in[%u]: [%p]\n", (word32)size, in);
LogHex(in, 0, size);
LogStr("out[%u]: [%p]\n", (word32)size, out);
LogHex(out, 0, size);
LogStr("iv[%u]: [%p]\n", (word32)ivSz, iv);
LogHex(iv, 0, ivSz);
LogStr("authTag[%u]: [%p]\n", (word32)authTagSz, authTag);
Expand Down
3 changes: 3 additions & 0 deletions jni/jni_native_struct.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,15 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
/* Initialize WolfSSLCertManager global mutex for thread-safe callback
* handling. Done here so it is before any CertManager ops happen. */
if (wolfSSL_CertManager_init() != 0) {
g_vm = NULL;
return JNI_ERR;
}

/* Initialize FIPS callback mutex for thread-safe error callback handling.
* No-op in non-FIPS builds. */
if (wolfCrypt_JNI_FipsCb_init() != 0) {
wolfSSL_CertManager_cleanup();
g_vm = NULL;
return JNI_ERR;
}

Expand Down
8 changes: 8 additions & 0 deletions jni/jni_rsa.c
Original file line number Diff line number Diff line change
Expand Up @@ -1989,6 +1989,14 @@ Java_com_wolfssl_wolfcrypt_Rsa_wc_1RsaExportCrtKey(
q == NULL || dP == NULL || dQ == NULL || u == NULL) {
ret = BAD_FUNC_ARG;
}
/* Supplied buffer sizes must not exceed actual array lengths */
else if (nSz < 0 || nSz > (jlong)(*env)->GetArrayLength(env, n_object) ||
eSz < 0 || eSz > (jlong)(*env)->GetArrayLength(env, e_object) ||
dSz < 0 || dSz > (jlong)(*env)->GetArrayLength(env, d_object) ||
pSz < 0 || pSz > (jlong)(*env)->GetArrayLength(env, p_object) ||
qSz < 0 || qSz > (jlong)(*env)->GetArrayLength(env, q_object)) {
ret = BAD_FUNC_ARG;
}
else {
/* Export e, n, d, p, q using wc_RsaExportKey() */
nSz32 = (word32)nSz;
Expand Down
17 changes: 15 additions & 2 deletions src/main/java/com/wolfssl/wolfcrypt/BlockCipher.java
Original file line number Diff line number Diff line change
Expand Up @@ -184,9 +184,22 @@ public synchronized byte[] update(byte[] input, int offset, int length)
checkStateAndInitialize();
throwIfKeyNotLoaded();

byte[] output = new byte[input.length];
if (input == null || offset < 0 || length < 0 ||
((long)offset + (long)length) > input.length) {
throw new WolfCryptException(WolfCryptError.BAD_FUNC_ARG.getCode());
}

int outputLength;
byte[] output = new byte[length];

native_update(opmode, input, offset, length, output, 0);
outputLength = native_update(opmode, input, offset, length, output, 0);

if (outputLength != length) {
/* resize array to match actual output length */
byte[] tmp = new byte[outputLength];
System.arraycopy(output, 0, tmp, 0, outputLength);
output = tmp;
}

return output;
}
Expand Down
21 changes: 21 additions & 0 deletions src/test/java/com/wolfssl/wolfcrypt/test/AesCmacTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,27 @@ public void aesCmacStaticMethodsShouldWork() {
}
}

@Test
public void aesCmacResetAndRekeyMidStreamShouldWork() {
byte[] keyBytes = Util.h2b("2b7e151628aed2a6abf7158809cf4f3c");
byte[] dataBytes = Util.h2b("6bc1bee22e409f96e93d7e117393172a");
byte[] expectedBytes = Util.h2b("070a16b46b4d4144f79bdd9dd04a287c");

/* reset() mid stream must reinitialize the active context */
AesCmac cmac = new AesCmac();
cmac.setKey(keyBytes);
cmac.update(new byte[8]);
cmac.reset();
cmac.update(dataBytes);
assertArrayEquals(expectedBytes, cmac.doFinal());

/* setKey() again without doFinal() must also reinitialize */
cmac.setKey(keyBytes);
cmac.update(new byte[4]);
cmac.setKey(keyBytes);
assertArrayEquals(expectedBytes, cmac.doFinal(dataBytes));
}

@Test
public void aesCmacAlgorithmInfoShouldWork() {
try {
Expand Down
32 changes: 32 additions & 0 deletions src/test/java/com/wolfssl/wolfcrypt/test/AesEcbTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,38 @@ public void checkSetKeyParams() {
}
}

@Test
public void updateWithInvalidLengthShouldThrow() {

AesEcb enc = new AesEcb();
enc.setKey(KEY_128, AesEcb.ENCRYPT_MODE);

byte[] in = new byte[AesEcb.BLOCK_SIZE];

try {
enc.update(null, 0, AesEcb.BLOCK_SIZE);
fail("null input should throw");
} catch (WolfCryptException e) {
/* expected */
}

try {
enc.update(in, 0, -1);
fail("negative length should throw");
} catch (WolfCryptException e) {
/* expected */
}

try {
enc.update(in, AesEcb.BLOCK_SIZE, AesEcb.BLOCK_SIZE);
fail("offset plus length beyond input should throw");
} catch (WolfCryptException e) {
/* expected */
}

enc.releaseNativeStruct();
}

@Test
public void checkUpdateParams() throws ShortBufferException {
byte[] input = new byte[AesEcb.BLOCK_SIZE];
Expand Down
Loading
Loading