/* com_wolfssl_WolfSSLContext.c * * Copyright (C) 2006-2023 wolfSSL Inc. * * This file is part of wolfSSL. * * wolfSSL is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * wolfSSL is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ #include #include #ifdef WOLFSSL_USER_SETTINGS #include #else #include #endif #include #include #include #include "com_wolfssl_globals.h" #include "com_wolfssl_WolfSSLContext.h" /* global object refs for verify, CRL callbacks */ static jobject g_verifyCbIfaceObj; #ifdef HAVE_CRL static jobject g_crlCtxCbIfaceObj; #endif /* custom I/O native fn prototypes */ int NativeIORecvCb(WOLFSSL *ssl, char *buf, int sz, void *ctx); int NativeIOSendCb(WOLFSSL *ssl, char *buf, int sz, void *ctx); int NativeGenCookieCb(WOLFSSL *ssl, unsigned char *buf, int sz, void *ctx); int NativeVerifyCallback(int preverify_ok, WOLFSSL_X509_STORE_CTX* store); void NativeCtxMissingCRLCallback(const char* url); int NativeMacEncryptCb(WOLFSSL* ssl, unsigned char* macOut, const unsigned char* macIn, unsigned int macInSz, int macContent, int macVerify, unsigned char* encOut, const unsigned char* encIn, unsigned int encSz, void* ctx); int NativeDecryptVerifyCb(WOLFSSL* ssl, unsigned char* decOut, const unsigned char* decIn, unsigned int decSz, int content, int verify, unsigned int* padSz, void* ctx); int NativeEccSignCb(WOLFSSL* ssl, const unsigned char* in, unsigned int inSz, unsigned char* out, unsigned int* outSz, const unsigned char* keyDer, unsigned int keySz, void* ctx); int NativeEccVerifyCb(WOLFSSL* ssl, const unsigned char* sig, unsigned int sigSz, const unsigned char* hash, unsigned int hashSz, const unsigned char* keyDer, unsigned int keySz, int* result, void* ctx); int NativeEccSharedSecretCb(WOLFSSL* ssl, ecc_key* otherKey, unsigned char* publicKeyDer, unsigned int* pubKeySz, unsigned char* out, unsigned int* outlen, int side, void* ctx); int NativeRsaSignCb(WOLFSSL* ssl, const unsigned char* in, unsigned int inSz, unsigned char* out, unsigned int* outSz, const unsigned char* keyDer, unsigned int keySz, void* ctx); int NativeRsaVerifyCb(WOLFSSL* ssl, unsigned char* sig, unsigned int sigSz, unsigned char** out, const unsigned char* keyDer, unsigned int keySz, void* ctx); int NativeRsaEncCb(WOLFSSL* ssl, const unsigned char* in, unsigned int inSz, unsigned char* out, unsigned int* outSz, const unsigned char* keyDer, unsigned int keySz, void* ctx); int NativeRsaDecCb(WOLFSSL* ssl, unsigned char* in, unsigned int inSz, unsigned char** out, const unsigned char* keyDer, unsigned int keySz, void* ctx); #if defined(HAVE_PK_CALLBACKS) && defined(HAVE_ECC) /* get JavaEnv from JavaVM * sets needDetach == 1 if DeteachCurrentThread() needs to be called * upon caller exit/cleanup * return 0 on success, negative on error */ static int GetJNIEnvFromVM(JavaVM* vm, JNIEnv** jenv, int* needsDetach) { jint ret; ret = (int)((*vm)->GetEnv(vm, (void**)jenv, JNI_VERSION_1_6)); if (ret == JNI_EDETACHED) { #ifdef __ANDROID__ ret = (*vm)->AttachCurrentThread(vm, jenv, NULL); #else ret = (*vm)->AttachCurrentThread(vm, (void**)jenv, NULL); #endif if (ret) { return -1; } *needsDetach = 1; } else if (ret != JNI_OK) { return -1; } return 0; } #endif /* HAVE_PK_CALLBACKS && HAVE_ECC */ /* check is exception has occurred, if so describes and clears it. * returns 0 if no exception occurred, 1 if occurred. */ static int CheckException(JNIEnv* jenv) { int ret = 0; if (jenv == NULL) return ret; if ((*jenv)->ExceptionOccurred(jenv)) { ret = 1; (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } return ret; } /* throw WolfSSLJNIException with given message, detach current * thread from VM if needsDetach is set to 1 */ static void throwWolfSSLJNIExceptionWithMsg(JNIEnv* jenv, const char* msg, int needsDetach) { jclass class = NULL; if (g_vm == NULL || jenv == NULL || msg == NULL) return; class = (*jenv)->FindClass(jenv, "com/wolfssl/WolfSSLJNIException"); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return; } (*jenv)->ThrowNew(jenv, class, msg); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return; } JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLContext_newContext(JNIEnv* jenv, jclass jcl, jlong method) { (void)jenv; (void)jcl; /* wolfSSL checks for NULL method ptr */ return (jlong)(uintptr_t)wolfSSL_CTX_new((WOLFSSL_METHOD*)(uintptr_t)method); } JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLContext_useCertificateFile (JNIEnv* jenv, jobject jcl, jlong ctxPtr, jstring file, jint format) { #ifndef NO_FILESYSTEM jint ret = 0; jclass excClass; const char* certFile; WOLFSSL_CTX* ctx = (WOLFSSL_CTX*)(uintptr_t)ctxPtr; (void)jcl; if (jenv == NULL) { return SSL_FAILURE; } if (file == NULL) { excClass = (*jenv)->FindClass(jenv, "java/lang/NullPointerException"); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } /* throw NullPointerException */ (*jenv)->ThrowNew(jenv, excClass, "Input certificate file is NULL"); return SSL_FAILURE; } certFile = (*jenv)->GetStringUTFChars(jenv, file, 0); ret = (jint) wolfSSL_CTX_use_certificate_file(ctx, certFile, (int)format); (*jenv)->ReleaseStringUTFChars(jenv, file, certFile); return ret; #else (void)jenv; (void)jcl; (void)ctxPtr; (void)file; (void)format; return NOT_COMPILED_IN; #endif } JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLContext_usePrivateKeyFile (JNIEnv* jenv, jobject jcl, jlong ctxPtr, jstring file, jint format) { #ifndef NO_FILESYSTEM jint ret = 0; jclass excClass; const char* keyFile; WOLFSSL_CTX* ctx = (WOLFSSL_CTX*)(uintptr_t)ctxPtr; (void)jcl; if (jenv == NULL) { return SSL_FAILURE; } if (file == NULL) { excClass = (*jenv)->FindClass(jenv, "java/lang/NullPointerException"); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } /* throw NullPointerException */ (*jenv)->ThrowNew(jenv, excClass, "Input private key file is NULL"); return SSL_FAILURE; } keyFile = (*jenv)->GetStringUTFChars(jenv, file, 0); ret = (jint) wolfSSL_CTX_use_PrivateKey_file(ctx, keyFile, (int)format); (*jenv)->ReleaseStringUTFChars(jenv, file, keyFile); return ret; #else (void)jenv; (void)jcl; (void)ctxPtr; (void)file; (void)format; return NOT_COMPILED_IN; #endif } JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLContext_loadVerifyLocations (JNIEnv* jenv, jobject jcl, jlong ctxPtr, jstring file, jstring path) { #ifndef NO_FILESYSTEM jint ret = 0; jclass excClass; const char* caFile; const char* caPath; WOLFSSL_CTX* ctx = (WOLFSSL_CTX*)(uintptr_t)ctxPtr; (void)jcl; if (jenv == NULL) { return SSL_FAILURE; } if (file == NULL && path == NULL) { excClass = (*jenv)->FindClass(jenv, "java/lang/NullPointerException"); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } /* throw NullPointerException */ (*jenv)->ThrowNew(jenv, excClass, "Input file and path are both NULL"); return SSL_FAILURE; } if (file) { caFile = (*jenv)->GetStringUTFChars(jenv, file, 0); } else { caFile = NULL; } if (path) { caPath = (*jenv)->GetStringUTFChars(jenv, path, 0); } else { caPath = NULL; } ret = (jint) wolfSSL_CTX_load_verify_locations(ctx, caFile, caPath); if (caFile) (*jenv)->ReleaseStringUTFChars(jenv, file, caFile); if (caPath) (*jenv)->ReleaseStringUTFChars(jenv, path, caPath); return ret; #else (void)jenv; (void)jcl; (void)ctxPtr; (void)file; (void)path; return NOT_COMPILED_IN; #endif } JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLContext_useCertificateChainFile (JNIEnv* jenv, jobject jcl, jlong ctxPtr, jstring file) { #ifndef NO_FILESYSTEM jint ret = 0; jclass excClass; const char* chainFile; WOLFSSL_CTX* ctx = (WOLFSSL_CTX*)(uintptr_t)ctxPtr; (void)jcl; if (jenv == NULL) { return SSL_FAILURE; } /* throw exception if no input file */ if (file == NULL) { excClass = (*jenv)->FindClass(jenv, "java/lang/NullPointerException"); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } /* throw NullPointerException */ (*jenv)->ThrowNew(jenv, excClass, "Input certificate chain file is NULL"); return SSL_FAILURE; } chainFile = (*jenv)->GetStringUTFChars(jenv, file, 0); ret = (jint) wolfSSL_CTX_use_certificate_chain_file(ctx, chainFile); (*jenv)->ReleaseStringUTFChars(jenv, file, chainFile); return ret; #else (void)jenv; (void)jcl; (void)ctxPtr; (void)file; return NOT_COMPILED_IN; #endif } JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLContext_freeContext (JNIEnv* jenv, jobject jcl, jlong ctxPtr) { WOLFSSL_CTX* ctx = (WOLFSSL_CTX*)(uintptr_t)ctxPtr; (void)jenv; (void)jcl; /* release verify callback object if set */ if (g_verifyCbIfaceObj != NULL) { (*jenv)->DeleteGlobalRef(jenv, g_verifyCbIfaceObj); g_verifyCbIfaceObj = NULL; } #ifdef HAVE_CRL /* release global CRL callback object if set */ if (g_crlCtxCbIfaceObj != NULL) { (*jenv)->DeleteGlobalRef(jenv, g_crlCtxCbIfaceObj); g_crlCtxCbIfaceObj = NULL; } #endif /* HAVE_CRL */ /* wolfSSL checks for null pointer */ wolfSSL_CTX_free(ctx); } JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLContext_setVerify(JNIEnv* jenv, jobject jcl, jlong ctxPtr, jint mode, jobject callbackIface) { WOLFSSL_CTX* ctx = (WOLFSSL_CTX*)(uintptr_t)ctxPtr; (void)jcl; if (jenv == NULL) { return; } /* release verify callback object if set before */ if (g_verifyCbIfaceObj != NULL) { (*jenv)->DeleteGlobalRef(jenv, g_verifyCbIfaceObj); g_verifyCbIfaceObj = NULL; } if (!callbackIface) { wolfSSL_CTX_set_verify(ctx, mode, NULL); } else { /* store Java verify Interface object */ g_verifyCbIfaceObj = (*jenv)->NewGlobalRef(jenv, callbackIface); if (g_verifyCbIfaceObj == NULL) { printf("error storing global callback interface\n"); } /* set verify mode, register Java callback with wolfSSL */ wolfSSL_CTX_set_verify(ctx, mode, NativeVerifyCallback); } } int NativeVerifyCallback(int preverify_ok, WOLFSSL_X509_STORE_CTX* store) { JNIEnv* jenv; jint vmret = 0; jint retval = -1; jclass excClass = NULL; jclass verifyClass = NULL; jmethodID verifyMethod = NULL; jobjectRefType refcheck; if (!g_vm) { /* we can't throw an exception yet, so just return 0 (failure) */ return 0; } /* get JNIEnv from JavaVM */ vmret = (int)((*g_vm)->GetEnv(g_vm, (void**) &jenv, JNI_VERSION_1_6)); if (vmret == JNI_EDETACHED) { #ifdef __ANDROID__ vmret = (*g_vm)->AttachCurrentThread(g_vm, &jenv, NULL); #else vmret = (*g_vm)->AttachCurrentThread(g_vm, (void**) &jenv, NULL); #endif if (vmret) { return -101; /* failed to attach JNIEnv to thread */ } } else if (vmret != JNI_OK) { return -102; /* unable to get JNIEnv from JavaVM */ } /* find exception class */ excClass = (*jenv)->FindClass(jenv, "com/wolfssl/WolfSSLException"); if( (*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); return -103; } /* check if our stored object reference is valid */ refcheck = (*jenv)->GetObjectRefType(jenv, g_verifyCbIfaceObj); if (refcheck == 2) { /* lookup WolfSSLVerifyCallback class from global object ref */ verifyClass = (*jenv)->GetObjectClass(jenv, g_verifyCbIfaceObj); if (!verifyClass) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLVerifyCallback class reference"); return -104; } verifyMethod = (*jenv)->GetMethodID(jenv, verifyClass, "verifyCallback", "(IJ)I"); if (verifyMethod == 0) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Error getting verifyCallback method from JNI"); return -105; } retval = (*jenv)->CallIntMethod(jenv, g_verifyCbIfaceObj, verifyMethod, preverify_ok, (jlong)(uintptr_t)store); if ((*jenv)->ExceptionOccurred(jenv)) { /* exception occurred on the Java side during method call */ (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); return -106; } } else { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Object reference invalid in NativeVerifyCallback"); return -1; } return retval; } JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLContext_setOptions (JNIEnv* jenv, jobject jcl, jlong ctxPtr, jlong op) { WOLFSSL_CTX* ctx = (WOLFSSL_CTX*)(uintptr_t)ctxPtr; (void)jcl; if (jenv == NULL || ctx == NULL) { return 0; } return wolfSSL_CTX_set_options(ctx, (long)op); } JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLContext_getOptions (JNIEnv* jenv, jobject jcl, jlong ctxPtr) { WOLFSSL_CTX* ctx = (WOLFSSL_CTX*)(uintptr_t)ctxPtr; (void)jcl; if (jenv == NULL || ctx == NULL) { return 0; } return wolfSSL_CTX_get_options(ctx); } JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLContext_memsaveCertCache (JNIEnv* jenv, jobject jcl, jlong ctxPtr, jbyteArray mem, jint sz, jintArray used) { #ifdef PERSIST_CERT_CACHE int ret; int usedTmp; unsigned char* memBuf = NULL; WOLFSSL_CTX* ctx = (WOLFSSL_CTX*)(uintptr_t)ctxPtr; jclass excClass = NULL; (void)jcl; if (jenv == NULL || ctx == NULL || mem == NULL || sz <= 0) { return BAD_FUNC_ARG; } /* find exception class */ excClass = (*jenv)->FindClass(jenv, "com/wolfssl/WolfSSLJNIException"); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); return SSL_FAILURE; } memBuf = (unsigned char*)XMALLOC((int)sz, NULL, DYNAMIC_TYPE_TMP_BUFFER); if (memBuf == NULL) { return MEMORY_E; } XMEMSET(memBuf, 0, (int)sz); ret = wolfSSL_CTX_memsave_cert_cache(ctx, memBuf, (int)sz, &usedTmp); /* set used value for return */ (*jenv)->SetIntArrayRegion(jenv, used, 0, 1, &usedTmp); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); XFREE(memBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); (*jenv)->ThrowNew(jenv, excClass, "Failed to set array region in native memsaveCertCache"); return SSL_FAILURE; } /* set jbyteArray for return */ if (usedTmp >= 0) { (*jenv)->SetByteArrayRegion(jenv, mem, 0, usedTmp, (jbyte*)memBuf); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); XFREE(memBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); (*jenv)->ThrowNew(jenv, excClass, "Failed to set byte region in native memsaveCertCache"); return SSL_FAILURE; } } XFREE(memBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER); return ret; #else (void)jenv; (void)jcl; (void)ctxPtr; (void)mem; (void)sz; (void)used; return NOT_COMPILED_IN; #endif } JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLContext_memrestoreCertCache (JNIEnv* jenv, jobject jcl, jlong ctxPtr, jbyteArray mem, jint sz) { #ifdef PERSIST_CERT_CACHE int ret = WOLFSSL_FAILURE; byte* buff = NULL; word32 buffSz = 0; WOLFSSL_CTX* ctx = (WOLFSSL_CTX*)(uintptr_t)ctxPtr; (void)jcl; (void)sz; if (jenv == NULL || ctx == NULL || mem == NULL) { return (jint)BAD_FUNC_ARG; } buff = (byte*)(*jenv)->GetByteArrayElements(jenv, mem, NULL); buffSz = (*jenv)->GetArrayLength(jenv, mem); if (buff != NULL && buffSz > 0) { ret = wolfSSL_CTX_memrestore_cert_cache(ctx, buff, buffSz); } (*jenv)->ReleaseByteArrayElements(jenv, mem, (jbyte*)buff, JNI_ABORT); return (jint)ret; #else (void)jenv; (void)jcl; (void)ctxPtr; (void)mem; (void)sz; return NOT_COMPILED_IN; #endif } JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLContext_getCertCacheMemsize (JNIEnv* jenv, jobject jcl, jlong ctx) { (void)jenv; (void)jcl; #ifdef PERSIST_CERT_CACHE /* wolfSSL checks for null pointer */ return wolfSSL_CTX_get_cert_cache_memsize((WOLFSSL_CTX*)(uintptr_t)ctx); #else return NOT_COMPILED_IN; #endif } JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLContext_setCacheSize (JNIEnv* jenv, jobject jcl, jlong ctx, jlong sz) { (void)jenv; (void)jcl; return wolfSSL_CTX_sess_set_cache_size((WOLFSSL_CTX*)(uintptr_t)ctx, (long)sz); } JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLContext_getCacheSize (JNIEnv* jenv, jobject jcl, jlong ctx) { (void)jenv; (void)jcl; return wolfSSL_CTX_sess_get_cache_size((WOLFSSL_CTX*)(uintptr_t)ctx); } JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLContext_setCipherList (JNIEnv* jenv, jobject jcl, jlong ctxPtr, jstring list) { jint ret = 0; jclass excClass; const char* cipherList; WOLFSSL_CTX* ctx = (WOLFSSL_CTX*)(uintptr_t)ctxPtr; (void)jcl; if (jenv == NULL) { return SSL_FAILURE; } if (list == NULL) { excClass = (*jenv)->FindClass(jenv, "java/lang/NullPointerException"); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } /* throw NullPointerException */ (*jenv)->ThrowNew(jenv, excClass, "Input cipher list is NULL"); return SSL_FAILURE; } cipherList = (*jenv)->GetStringUTFChars(jenv, list, 0); ret = (jint) wolfSSL_CTX_set_cipher_list(ctx, cipherList); (*jenv)->ReleaseStringUTFChars(jenv, list, cipherList); return ret; } JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLContext_loadVerifyBuffer (JNIEnv* jenv, jobject jcl, jlong ctxPtr, jbyteArray in, jlong sz, jint format) { int ret = WOLFSSL_FAILURE; byte* buff = NULL; word32 buffSz = 0; WOLFSSL_CTX* ctx = (WOLFSSL_CTX*)(uintptr_t)ctxPtr; (void)jcl; (void)sz; if (jenv == NULL || ctx == NULL || in == NULL) { return (jint)BAD_FUNC_ARG; } buff = (byte*)(*jenv)->GetByteArrayElements(jenv, in, NULL); buffSz = (*jenv)->GetArrayLength(jenv, in); if (buff != NULL && buffSz > 0) { ret = wolfSSL_CTX_load_verify_buffer(ctx, buff, buffSz, format); } (*jenv)->ReleaseByteArrayElements(jenv, in, (jbyte*)buff, JNI_ABORT); return (jint)ret; } JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLContext_useCertificateBuffer (JNIEnv* jenv, jobject jcl, jlong ctxPtr, jbyteArray in, jlong sz, jint format) { int ret = WOLFSSL_FAILURE; byte* buff = NULL; word32 buffSz = 0; WOLFSSL_CTX* ctx = (WOLFSSL_CTX*)(uintptr_t)ctxPtr; (void)jcl; (void)sz; if (jenv == NULL || ctx == NULL || in == NULL) { return (jint)BAD_FUNC_ARG; } buff = (byte*)(*jenv)->GetByteArrayElements(jenv, in, NULL); buffSz = (*jenv)->GetArrayLength(jenv, in); if (buff != NULL && buffSz > 0) { ret = wolfSSL_CTX_use_certificate_buffer(ctx, buff, buffSz, format); } (*jenv)->ReleaseByteArrayElements(jenv, in, (jbyte*)buff, JNI_ABORT); return (jint)ret; } JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLContext_usePrivateKeyBuffer (JNIEnv* jenv, jobject jcl, jlong ctxPtr, jbyteArray in, jlong sz, jint format) { int ret = WOLFSSL_FAILURE; byte* buff = NULL; word32 buffSz = 0; WOLFSSL_CTX* ctx = (WOLFSSL_CTX*)(uintptr_t)ctxPtr; (void)jcl; (void)sz; if (jenv == NULL || ctx == NULL || in == NULL) { return (jint)BAD_FUNC_ARG; } buff = (byte*)(*jenv)->GetByteArrayElements(jenv, in, NULL); buffSz = (*jenv)->GetArrayLength(jenv, in); if (buff != NULL && buffSz > 0) { ret = wolfSSL_CTX_use_PrivateKey_buffer(ctx, buff, buffSz, format); } (*jenv)->ReleaseByteArrayElements(jenv, in, (jbyte*)buff, JNI_ABORT); return (jint)ret; } JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLContext_useCertificateChainBuffer (JNIEnv* jenv, jobject jcl, jlong ctxPtr, jbyteArray in, jlong sz) { int ret = WOLFSSL_FAILURE; byte* buff = NULL; word32 buffSz = 0; WOLFSSL_CTX* ctx = (WOLFSSL_CTX*)(uintptr_t)ctxPtr; (void)jcl; (void)sz; if (jenv == NULL || ctx == NULL || in == NULL) { return (jint)BAD_FUNC_ARG; } buff = (byte*)(*jenv)->GetByteArrayElements(jenv, in, NULL); buffSz = (*jenv)->GetArrayLength(jenv, in); if (buff != NULL && buffSz > 0) { ret = wolfSSL_CTX_use_certificate_chain_buffer(ctx, buff, buffSz); } (*jenv)->ReleaseByteArrayElements(jenv, in, (jbyte*)buff, JNI_ABORT); return (jint)ret; } JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLContext_useCertificateChainBufferFormat (JNIEnv* jenv, jobject jcl, jlong ctxPtr, jbyteArray in, jlong sz, jint format) { int ret = WOLFSSL_FAILURE; byte* buff = NULL; word32 buffSz = 0; WOLFSSL_CTX* ctx = (WOLFSSL_CTX*)(uintptr_t)ctxPtr; (void)jcl; (void)sz; if (jenv == NULL || ctx == NULL || in == NULL) { return (jint)BAD_FUNC_ARG; } buff = (byte*)(*jenv)->GetByteArrayElements(jenv, in, NULL); buffSz = (*jenv)->GetArrayLength(jenv, in); if (buff != NULL && buffSz > 0) { ret = wolfSSL_CTX_use_certificate_chain_buffer_format( ctx, buff, buffSz, format); } (*jenv)->ReleaseByteArrayElements(jenv, in, (jbyte*)buff, JNI_ABORT); return (jint)ret; } JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLContext_setGroupMessages (JNIEnv* jenv, jobject jcl, jlong ctx) { (void)jenv; (void)jcl; if (ctx == 0) { return (jint)BAD_FUNC_ARG; } return wolfSSL_CTX_set_group_messages((WOLFSSL_CTX*)(uintptr_t)ctx); } JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLContext_setIORecv(JNIEnv* jenv, jobject jcl, jlong ctxPtr) { WOLFSSL_CTX* ctx = (WOLFSSL_CTX*)(uintptr_t)ctxPtr; jclass excClass = NULL; (void)jcl; /* find exception class */ excClass = (*jenv)->FindClass(jenv, "com/wolfssl/WolfSSLJNIException"); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); return; } if(ctx != NULL) { /* set I/O recv callback */ wolfSSL_SetIORecv(ctx, NativeIORecvCb); } else { (*jenv)->ThrowNew(jenv, excClass, "Input WolfSSLContext object was null when setting IORecv"); } } int NativeIORecvCb(WOLFSSL *ssl, char *buf, int sz, void *ctx) { jint retval = 0; jint vmret = 0; JNIEnv* jenv; /* JNI environment */ jclass excClass; /* WolfSSLJNIException class */ int needsDetach = 0; /* Should we explicitly detach? */ static jobject* g_cachedSSLObj; /* WolfSSLSession cached object */ jclass sessClass; /* WolfSSLSession class */ jfieldID ctxFid; /* WolfSSLSession->ctx FieldID */ jmethodID getCtxMethodId; /* WolfSSLSession->getAssCtxPtr() ID */ jobject ctxRef; /* WolfSSLContext object */ jclass innerCtxClass; /* WolfSSLContext class */ jmethodID recvCbMethodId; /* internalIORecvCallback ID */ jbyteArray inData; if (!g_vm || !ssl || !buf || !ctx) { /* can't throw exception yet, just return error */ return WOLFSSL_CBIO_ERR_GENERAL; } /* get JavaEnv from JavaVM */ vmret = (int)((*g_vm)->GetEnv(g_vm, (void**) &jenv, JNI_VERSION_1_6)); if (vmret == JNI_EDETACHED) { #ifdef __ANDROID__ vmret = (*g_vm)->AttachCurrentThread(g_vm, &jenv, NULL); #else vmret = (*g_vm)->AttachCurrentThread(g_vm, (void**) &jenv, NULL); #endif if (vmret) { return WOLFSSL_CBIO_ERR_GENERAL; } needsDetach = 1; } else if (vmret != JNI_OK) { return WOLFSSL_CBIO_ERR_GENERAL; } /* find exception class in case we need it */ excClass = (*jenv)->FindClass(jenv, "com/wolfssl/WolfSSLJNIException"); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return WOLFSSL_CBIO_ERR_GENERAL; } /* get stored WolfSSLSession jobject */ g_cachedSSLObj = (jobject*) wolfSSL_get_jobject((WOLFSSL*)ssl); if (!g_cachedSSLObj) { (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLSession object reference in " "NativeIORecvCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return 0; } /* lookup WolfSSLSession class from object */ sessClass = (*jenv)->GetObjectClass(jenv, (jobject)(*g_cachedSSLObj)); if (!sessClass) { (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLSession class reference in " "NativeIORecvCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return WOLFSSL_CBIO_ERR_GENERAL; } /* lookup WolfSSLContext private member fieldID */ ctxFid = (*jenv)->GetFieldID(jenv, sessClass, "ctx", "Lcom/wolfssl/WolfSSLContext;"); if (!ctxFid) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLContext field ID in NativeIORecvCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return WOLFSSL_CBIO_ERR_GENERAL; } /* find WolfSSLContext.getAssociatedContextPtr() method */ getCtxMethodId = (*jenv)->GetMethodID(jenv, sessClass, "getAssociatedContextPtr", "()Lcom/wolfssl/WolfSSLContext;"); if (!getCtxMethodId) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Can't get getAssociatedContextPtr() method ID in " "NativeIORecvCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return WOLFSSL_CBIO_ERR_GENERAL; } /* get WolfSSLContext(ctx) object from Java WolfSSLSession object */ ctxRef = (*jenv)->CallObjectMethod(jenv, (jobject)(*g_cachedSSLObj), getCtxMethodId); CheckException(jenv); if (!ctxRef) { (*jenv)->ThrowNew(jenv, excClass, "Can't get WolfSSLContext object in NativeIORecvCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return WOLFSSL_CBIO_ERR_GENERAL; } /* get WolfSSLContext class reference from object */ innerCtxClass = (*jenv)->GetObjectClass(jenv, ctxRef); if (!innerCtxClass) { (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLContext class reference in " "NativeIORecvCb"); (*jenv)->DeleteLocalRef(jenv, ctxRef); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return WOLFSSL_CBIO_ERR_GENERAL; } /* call internal I/O recv callback */ recvCbMethodId = (*jenv)->GetMethodID(jenv, innerCtxClass, "internalIORecvCallback", "(Lcom/wolfssl/WolfSSLSession;[BI)I"); if (!recvCbMethodId) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Error getting internalIORecvCallback method from JNI"); (*jenv)->DeleteLocalRef(jenv, ctxRef); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return WOLFSSL_CBIO_ERR_GENERAL; } /* create jbyteArray to hold received data */ inData = (*jenv)->NewByteArray(jenv, sz); if (!inData) { (*jenv)->ThrowNew(jenv, excClass, "Error getting internalIORecvCallback method from JNI"); (*jenv)->DeleteLocalRef(jenv, ctxRef); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return WOLFSSL_CBIO_ERR_GENERAL; } /* call Java send callback, ignore native ctx since Java * handles it */ retval = (*jenv)->CallIntMethod(jenv, ctxRef, recvCbMethodId, (jobject)(*g_cachedSSLObj), inData, (jint)sz); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, inData); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return WOLFSSL_CBIO_ERR_GENERAL; } /* copy jbyteArray into char array */ if (retval >= 0) { (*jenv)->GetByteArrayRegion(jenv, inData, 0, retval, (jbyte*)buf); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, inData); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return WOLFSSL_CBIO_ERR_GENERAL; } } /* delete local refs, detach JNIEnv from thread */ (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, inData); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return retval; } JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLContext_setIOSend (JNIEnv* jenv, jobject jcl, jlong ctxPtr) { WOLFSSL_CTX* ctx = (WOLFSSL_CTX*)(uintptr_t)ctxPtr; jclass excClass = NULL; (void)jcl; /* find exception class in case we need it */ excClass = (*jenv)->FindClass(jenv, "com/wolfssl/WolfSSLJNIException"); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } if (ctx != NULL) { /* set I/O send callback */ wolfSSL_SetIOSend(ctx, NativeIOSendCb); } else { (*jenv)->ThrowNew(jenv, excClass, "Input WolfSSLContext object was null when setting IOSend"); } } int NativeIOSendCb(WOLFSSL *ssl, char *buf, int sz, void *ctx) { jint retval = 0; jint vmret = 0; JNIEnv* jenv; /* JNI environment */ jclass excClass; /* WolfSSLJNIException class */ int needsDetach = 0; /* Should we explicitly detach? */ static jobject* g_cachedSSLObj; /* WolfSSLSession cached object */ jclass sessClass; /* WolfSSLSession class */ jfieldID ctxFid; /* WolfSSLSession->ctx FieldID */ jmethodID getCtxMethodId; /* WolfSSLSession->getAssCtxPtr() ID */ jobject ctxRef; /* WolfSSLContext object */ jclass innerCtxClass; /* WolfSSLContext class */ jmethodID sendCbMethodId; /* internalIOSendCallback ID */ jbyteArray outData; /* jbyteArray for data to send */ if (!g_vm || !ssl || !buf || !ctx) { /* can't throw exception yet, just return error */ return WOLFSSL_CBIO_ERR_GENERAL; } /* get JavaEnv from JavaVM */ vmret = (int)((*g_vm)->GetEnv(g_vm, (void**) &jenv, JNI_VERSION_1_6)); if (vmret == JNI_EDETACHED) { #ifdef __ANDROID__ vmret = (*g_vm)->AttachCurrentThread(g_vm, &jenv, NULL); #else vmret = (*g_vm)->AttachCurrentThread(g_vm, (void**) &jenv, NULL); #endif if (vmret) { return WOLFSSL_CBIO_ERR_GENERAL; } needsDetach = 1; } else if (vmret != JNI_OK) { return WOLFSSL_CBIO_ERR_GENERAL; } /* find exception class in case we need it */ excClass = (*jenv)->FindClass(jenv, "com/wolfssl/WolfSSLJNIException"); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return WOLFSSL_CBIO_ERR_GENERAL; } /* get stored WolfSSLSession jobject */ g_cachedSSLObj = (jobject*) wolfSSL_get_jobject((WOLFSSL*)ssl); if (!g_cachedSSLObj) { (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLSession object reference in " "NativeIOSendCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return 0; } /* lookup WolfSSLSession class from object */ sessClass = (*jenv)->GetObjectClass(jenv, (jobject)(*g_cachedSSLObj)); if (!sessClass) { (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLSession class reference"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return WOLFSSL_CBIO_ERR_GENERAL; } /* lookup WolfSSLContext private member fieldID */ ctxFid = (*jenv)->GetFieldID(jenv, sessClass, "ctx", "Lcom/wolfssl/WolfSSLContext;"); if (!ctxFid) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLContext field ID in NativeIOSendCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return WOLFSSL_CBIO_ERR_GENERAL; } /* find WolfSSLContext.getAssociatedContextPtr() method */ getCtxMethodId = (*jenv)->GetMethodID(jenv, sessClass, "getAssociatedContextPtr", "()Lcom/wolfssl/WolfSSLContext;"); if (!getCtxMethodId) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Can't get getAssociatedContextPtr() method ID in " "NativeIOSendCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return WOLFSSL_CBIO_ERR_GENERAL; } /* get WolfSSLContext(ctx) object from Java WolfSSLSession object */ ctxRef = (*jenv)->CallObjectMethod(jenv, (jobject)(*g_cachedSSLObj), getCtxMethodId); CheckException(jenv); if (!ctxRef) { (*jenv)->ThrowNew(jenv, excClass, "Can't get WolfSSLContext object in NativeIOSendCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return WOLFSSL_CBIO_ERR_GENERAL; } /* get WolfSSLContext class reference from Java land */ innerCtxClass = (*jenv)->GetObjectClass(jenv, ctxRef); if (!innerCtxClass) { (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLContext class reference in " "NativeIOSendCb"); (*jenv)->DeleteLocalRef(jenv, ctxRef); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return WOLFSSL_CBIO_ERR_GENERAL; } /* call internal I/O recv callback */ sendCbMethodId = (*jenv)->GetMethodID(jenv, innerCtxClass, "internalIOSendCallback", "(Lcom/wolfssl/WolfSSLSession;[BI)I"); if (!sendCbMethodId) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Error getting internalIOSendCallback method from JNI"); (*jenv)->DeleteLocalRef(jenv, ctxRef); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return WOLFSSL_CBIO_ERR_GENERAL; } if (sz >= 0) { /* create jbyteArray to hold received data */ outData = (*jenv)->NewByteArray(jenv, sz); if (!outData) { (*jenv)->ThrowNew(jenv, excClass, "Error getting internalIOSendCallback method from JNI"); (*jenv)->DeleteLocalRef(jenv, ctxRef); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return WOLFSSL_CBIO_ERR_GENERAL; } (*jenv)->SetByteArrayRegion(jenv, outData, 0, sz, (jbyte*)buf); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, outData); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return WOLFSSL_CBIO_ERR_GENERAL; } /* call Java send callback, ignore native ctx since Java * handles it */ retval = (*jenv)->CallIntMethod(jenv, ctxRef, sendCbMethodId, (jobject)(*g_cachedSSLObj), outData, (jint)sz); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, outData); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return WOLFSSL_CBIO_ERR_GENERAL; } /* delete local refs */ (*jenv)->DeleteLocalRef(jenv, outData); } /* delete local refs, detach JNIEnv from thread */ (*jenv)->DeleteLocalRef(jenv, ctxRef); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return retval; } JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLContext_setGenCookie (JNIEnv* jenv, jobject jcl, jlong ctxPtr) { WOLFSSL_CTX* ctx = (WOLFSSL_CTX*)(uintptr_t)ctxPtr; jclass excClass = NULL; (void)jcl; /* find exception class in case we need it */ excClass = (*jenv)->FindClass(jenv, "com/wolfssl/WolfSSLJNIException"); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } #ifdef WOLFSSL_DTLS if (ctx != NULL) { /* set gen cookie callback */ wolfSSL_CTX_SetGenCookie(ctx, NativeGenCookieCb); } else { (*jenv)->ThrowNew(jenv, excClass, "Input WolfSSLContext object was null when setting " "genCookieCb"); } #else (*jenv)->ThrowNew(jenv, excClass, "wolfSSL not compiled with DTLS support (WOLFSSL_DTLS)"); #endif } int NativeGenCookieCb(WOLFSSL *ssl, unsigned char *buf, int sz, void *ctx) { jint retval = 0; jint vmret = 0; JNIEnv* jenv; /* JNI environment */ jclass excClass; /* WolfSSLJNIException class */ int needsDetach = 0; /* Should we explicitly detach? */ static jobject* g_cachedSSLObj; /* WolfSSLSession cached object */ jclass sessClass; /* WolfSSLSession class */ jfieldID ctxFid; /* WolfSSLSession->ctx FieldID */ jmethodID getCtxMethodId; /* WolfSSLSession->getAssCtxPtr() ID */ jobject ctxRef; /* WolfSSLContext object */ jclass innerCtxClass; /* WolfSSLContext class */ jmethodID cookieCbMethodId; /* internalGenCookieCallback ID */ jbyteArray inData; /* jbyteArray to hold cookie data */ (void)ctx; if (!g_vm || !ssl || !buf) { /* can't throw exception yet, just return error */ return GEN_COOKIE_E; } /* get JavaEnv from JavaVM */ vmret = (int)((*g_vm)->GetEnv(g_vm, (void**) &jenv, JNI_VERSION_1_6)); if (vmret == JNI_EDETACHED) { #ifdef __ANDROID__ vmret = (*g_vm)->AttachCurrentThread(g_vm, &jenv, NULL); #else vmret = (*g_vm)->AttachCurrentThread(g_vm, (void**) &jenv, NULL); #endif if (vmret) { return GEN_COOKIE_E; } needsDetach = 1; } else if (vmret != JNI_OK) { return GEN_COOKIE_E; } /* find exception class in case we need it */ excClass = (*jenv)->FindClass(jenv, "com/wolfssl/WolfSSLJNIException"); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return GEN_COOKIE_E; } /* get stored WolfSSLSession jobject */ g_cachedSSLObj = (jobject*) wolfSSL_get_jobject((WOLFSSL*)ssl); if (!g_cachedSSLObj) { (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLSession object reference in " "NativeGenCookieCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return GEN_COOKIE_E; } /* lookup WolfSSLSession class from object */ sessClass = (*jenv)->GetObjectClass(jenv, (jobject)(*g_cachedSSLObj)); if (!sessClass) { (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLSession class reference in " "NativeGenCookieCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return GEN_COOKIE_E; } /* lookup WolfSSLContext private member fieldID */ ctxFid = (*jenv)->GetFieldID(jenv, sessClass, "ctx", "Lcom/wolfssl/WolfSSLContext;"); if (!ctxFid) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLContext field ID in " "NativeGenCookieCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return GEN_COOKIE_E; } /* find WolfSSLSession.getAssociatedContextPtr() method */ getCtxMethodId = (*jenv)->GetMethodID(jenv, sessClass, "getAssociatedContextPtr", "()Lcom/wolfssl/WolfSSLContext;"); if (!getCtxMethodId) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Can't get getAssociatedContextPtr() method ID in " "NativeGenCookieCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return GEN_COOKIE_E; } /* get WolfSSLContext(ctx) object from WolfSSLSession object */ ctxRef = (*jenv)->CallObjectMethod(jenv, (jobject)(*g_cachedSSLObj), getCtxMethodId); CheckException(jenv); if (!ctxRef) { (*jenv)->ThrowNew(jenv, excClass, "Can't get WolfSSLContext object in NativeGenCookieCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return GEN_COOKIE_E; } /* get WolfSSLContext class reference from Java land */ innerCtxClass = (*jenv)->GetObjectClass(jenv, ctxRef); if (!innerCtxClass) { (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLContext class reference in " "NativeGenCookieCb"); (*jenv)->DeleteLocalRef(jenv, ctxRef); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return GEN_COOKIE_E; } /* call internal gen cookie callback */ cookieCbMethodId = (*jenv)->GetMethodID(jenv, innerCtxClass, "internalGenCookieCallback", "(Lcom/wolfssl/WolfSSLSession;[BI)I"); if (!cookieCbMethodId) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Error getting internalGenCookieCallback method from JNI"); (*jenv)->DeleteLocalRef(jenv, ctxRef); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return GEN_COOKIE_E; } if (sz >= 0) { /* create jbyteArray to hold cookie data */ inData = (*jenv)->NewByteArray(jenv, sz); if (!inData) { (*jenv)->ThrowNew(jenv, excClass, "Error getting internalGenCookieCallback method from JNI"); (*jenv)->DeleteLocalRef(jenv, ctxRef); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return GEN_COOKIE_E; } /* call Java cookie callback */ retval = (*jenv)->CallIntMethod(jenv, ctxRef, cookieCbMethodId, (jobject)(*g_cachedSSLObj), inData, (jint)sz); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, inData); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return GEN_COOKIE_E; } /* copy jbyteArray into char array */ if (retval >= 0) { (*jenv)->GetByteArrayRegion(jenv, inData, 0, retval, (jbyte*)buf); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, inData); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return GEN_COOKIE_E; } } /* delete local refs */ (*jenv)->DeleteLocalRef(jenv, inData); } /* delete local refs, detach JNIEnv from thread */ (*jenv)->DeleteLocalRef(jenv, ctxRef); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return retval; } JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLContext_enableCRL (JNIEnv* jenv, jobject jcl, jlong ctx, jint options) { (void)jenv; (void)jcl; #ifdef HAVE_CRL if (!ctx) return BAD_FUNC_ARG; return wolfSSL_CTX_EnableCRL((WOLFSSL_CTX*)(uintptr_t)ctx, options); #else return NOT_COMPILED_IN; #endif } JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLContext_disableCRL (JNIEnv* jenv, jobject jcl, jlong ctx) { (void)jenv; (void)jcl; #ifdef HAVE_CRL if (!ctx) return BAD_FUNC_ARG; return wolfSSL_CTX_DisableCRL((WOLFSSL_CTX*)(uintptr_t)ctx); #else return NOT_COMPILED_IN; #endif } JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLContext_loadCRL (JNIEnv* jenv, jobject jcl, jlong ctxPtr, jstring path, jint type, jint monitor) { #if defined(HAVE_CRL) && !defined(NO_FILESYSTEM) int ret; const char* crlPath; WOLFSSL_CTX* ctx = (WOLFSSL_CTX*)(uintptr_t)ctxPtr; (void)jcl; if (jenv == NULL || ctx == NULL || path == NULL) { return BAD_FUNC_ARG; } crlPath = (*jenv)->GetStringUTFChars(jenv, path, 0); ret = wolfSSL_CTX_LoadCRL(ctx, crlPath, type, monitor); (*jenv)->ReleaseStringUTFChars(jenv, path, crlPath); return ret; #else (void)jenv; (void)jcl; (void)ctxPtr; (void)path; (void)type; (void)monitor; return NOT_COMPILED_IN; #endif } JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLContext_setCRLCb (JNIEnv* jenv, jobject jcl, jlong ctxPtr, jobject cb) { #ifdef HAVE_CRL int ret = 0; jclass excClass; WOLFSSL_CTX* ctx = (WOLFSSL_CTX*)(uintptr_t)ctxPtr; (void)jcl; if (jenv == NULL || ctx == NULL) { return BAD_FUNC_ARG; } /* release global CRL callback object if set */ if (g_crlCtxCbIfaceObj != NULL) { (*jenv)->DeleteGlobalRef(jenv, g_crlCtxCbIfaceObj); g_crlCtxCbIfaceObj = NULL; } if (cb != NULL) { /* store Java CRL callback Interface object */ g_crlCtxCbIfaceObj = (*jenv)->NewGlobalRef(jenv, cb); if (!g_crlCtxCbIfaceObj) { excClass = (*jenv)->FindClass(jenv, "com/wolfssl/WolfSSLJNIException"); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "error storing global missing CTX CRL callback interface"); } ret = wolfSSL_CTX_SetCRL_Cb(ctx, NativeCtxMissingCRLCallback); } return ret; #else (void)jenv; (void)jcl; (void)ctxPtr; (void)cb; return NOT_COMPILED_IN; #endif } #ifdef HAVE_CRL void NativeCtxMissingCRLCallback(const char* url) { JNIEnv* jenv; jint vmret = 0; jclass excClass; jclass crlClass = NULL; jmethodID crlMethod; jstring missingUrl = NULL; jobjectRefType refcheck; /* get JNIEnv from JavaVM */ vmret = (int)((*g_vm)->GetEnv(g_vm, (void**) &jenv, JNI_VERSION_1_6)); if (vmret == JNI_EDETACHED) { #ifdef __ANDROID__ vmret = (*g_vm)->AttachCurrentThread(g_vm, &jenv, NULL); #else vmret = (*g_vm)->AttachCurrentThread(g_vm, (void**) &jenv, NULL); #endif if (vmret) { printf("Failed to attach JNIEnv to thread\n"); } } else if (vmret != JNI_OK) { printf("Unable to get JNIEnv from JavaVM\n"); } /* find exception class */ excClass = (*jenv)->FindClass(jenv, "com/wolfssl/WolfSSLJNIException"); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); return; } /* check if our stored object reference is valid */ refcheck = (*jenv)->GetObjectRefType(jenv, g_crlCtxCbIfaceObj); if (refcheck == 2) { /* lookup WolfSSLMissingCRLCallback class from global object ref */ crlClass = (*jenv)->GetObjectClass(jenv, g_crlCtxCbIfaceObj); if (!crlClass) { (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLMissingCRLCallback class reference"); return; } crlMethod = (*jenv)->GetMethodID(jenv, crlClass, "missingCRLCallback", "(Ljava/lang/String;)V"); if (crlMethod == 0) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Error getting missingCRLCallback method from JNI"); return; } /* create jstring from char* */ missingUrl = (*jenv)->NewStringUTF(jenv, url); (*jenv)->CallVoidMethod(jenv, g_crlCtxCbIfaceObj, crlMethod, missingUrl); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); return; } } else { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Object reference invalid in NativeMissingCRLCallback"); } } #endif /* HAVE_CRL */ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLContext_enableOCSP (JNIEnv* jenv, jobject jcl, jlong ctx, jlong options) { (void)jenv; (void)jcl; #ifdef HAVE_OCSP /* wolfSSL checks for null pointer */ return wolfSSL_CTX_EnableOCSP((WOLFSSL_CTX*)(uintptr_t)ctx, (long)options); #else return NOT_COMPILED_IN; #endif } JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLContext_disableOCSP (JNIEnv* jenv, jobject jcl, jlong ctx) { (void)jenv; (void)jcl; #ifdef HAVE_OCSP /* wolfSSL checks for null pointer */ return wolfSSL_CTX_DisableOCSP((WOLFSSL_CTX*)(uintptr_t)ctx); #else return NOT_COMPILED_IN; #endif } JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLContext_setOCSPOverrideUrl (JNIEnv* jenv, jobject jcl, jlong ctxPtr, jstring urlString) { #ifdef HAVE_OCSP jint ret = 0; jclass excClass; const char* url; WOLFSSL_CTX* ctx = (WOLFSSL_CTX*)(uintptr_t)ctxPtr; (void)jcl; /* wolfSSL checks ctx for NULL */ if (jenv == NULL) return BAD_FUNC_ARG; if (urlString == NULL) { excClass = (*jenv)->FindClass(jenv, "java/lang/NullPointerException"); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } /* throw NullPointerException */ (*jenv)->ThrowNew(jenv, excClass, "Input URL is NULL in setOCSPOverrideUrl()"); return SSL_FAILURE; } url = (*jenv)->GetStringUTFChars(jenv, urlString, 0); ret = (jint) wolfSSL_CTX_SetOCSP_OverrideURL(ctx, url); (*jenv)->ReleaseStringUTFChars(jenv, urlString, url); return ret; #else (void)jenv; (void)jcl; (void)ctxPtr; (void)urlString; return NOT_COMPILED_IN; #endif } JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLContext_setMacEncryptCb (JNIEnv* jenv, jobject jcl, jlong ctx) { (void)jcl; /* find exception class */ jclass excClass = (*jenv)->FindClass(jenv, "com/wolfssl/WolfSSLJNIException"); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); return; } #ifdef ATOMIC_USER if(ctx) { /* set MAC encrypt callback */ wolfSSL_CTX_SetMacEncryptCb((WOLFSSL_CTX*)(uintptr_t)ctx, NativeMacEncryptCb); } else { (*jenv)->ThrowNew(jenv, excClass, "Input WolfSSLContext object was null when " "setting MacEncrypt"); } #else (*jenv)->ThrowNew(jenv, excClass, "wolfSSL not compiled with ATOMIC_USER"); #endif } JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLContext_setDecryptVerifyCb (JNIEnv* jenv, jobject jcl, jlong ctx) { jclass excClass = NULL; (void)jcl; /* find exception class */ excClass = (*jenv)->FindClass(jenv, "com/wolfssl/WolfSSLJNIException"); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); return; } #ifdef ATOMIC_USER if(ctx) { /* set decrypt/verify callback */ wolfSSL_CTX_SetDecryptVerifyCb((WOLFSSL_CTX*)(uintptr_t)ctx, NativeDecryptVerifyCb); } else { (*jenv)->ThrowNew(jenv, excClass, "Input WolfSSLContext object was null when " "setting MacDecrypt"); } #else (*jenv)->ThrowNew(jenv, excClass, "wolfSSL not compiled with ATOMIC_USER"); #endif /* ATOMIC_USER */ } #ifdef ATOMIC_USER int NativeMacEncryptCb(WOLFSSL* ssl, unsigned char* macOut, const unsigned char* macIn, unsigned int macInSz, int macContent, int macVerify, unsigned char* encOut, const unsigned char* encIn, unsigned int encSz, void* ctx) { jint retval = 0; jint vmret = 0; JNIEnv* jenv; /* JNI environment */ jclass excClass; /* WolfSSLJNIException class */ int needsDetach = 0; /* Should we explicitly detach? */ static jobject* g_cachedSSLObj; /* WolfSSLSession cached object */ jclass sessClass; /* WolfSSLSession class */ jfieldID ctxFid; /* WolfSSLSession->ctx FieldID */ jmethodID getCtxMethodId; /* WolfSSLSession->getAssCtxPtr() ID */ jobject ctxRef; /* WolfSSLContext object */ jclass innerCtxClass; /* WolfSSLContext class */ jmethodID macEncryptMethodId; /* internalMacEncryptCallback ID */ jobject macOutBB = NULL; jobject encOutBB = NULL; jobject encInBB = NULL; int hmacSize; jbyteArray j_macIn; (void)ctx; if (!g_vm || !ssl || !macOut || !macIn || !encOut || !encIn) { return -1; } /* get JavaEnv from JavaVM */ vmret = (int)((*g_vm)->GetEnv(g_vm, (void**) &jenv, JNI_VERSION_1_6)); if (vmret == JNI_EDETACHED) { #ifdef __ANDROID__ vmret = (*g_vm)->AttachCurrentThread(g_vm, &jenv, NULL); #else vmret = (*g_vm)->AttachCurrentThread(g_vm, (void**) &jenv, NULL); #endif if (vmret) { return -1; } needsDetach = 1; } else if (vmret != JNI_OK) { return -1; } /* find exception class in case we need it */ excClass = (*jenv)->FindClass(jenv, "com/wolfssl/WolfSSLJNIException"); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* get stored WolfSSLSession jobject */ g_cachedSSLObj = (jobject*) wolfSSL_get_jobject((WOLFSSL*)ssl); if (!g_cachedSSLObj) { (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLSession object reference in " "NativeMacEncryptCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* lookup WolfSSLSession class from object */ sessClass = (*jenv)->GetObjectClass(jenv, (jobject)(*g_cachedSSLObj)); if (!sessClass) { (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLSession class reference in " "NativeMacEncryptCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* lookup WolfSSLContext private member fieldID */ ctxFid = (*jenv)->GetFieldID(jenv, sessClass, "ctx", "Lcom/wolfssl/WolfSSLContext;"); if (!ctxFid) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLContext field ID in " "NativeMacEncryptCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* find getContextPtr() method */ getCtxMethodId = (*jenv)->GetMethodID(jenv, sessClass, "getAssociatedContextPtr", "()Lcom/wolfssl/WolfSSLContext;"); if (!getCtxMethodId) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Can't get getAssociatedContextPtr() method ID in " "NativeMacEncryptCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* get WolfSSLContext ctx object from Java land */ ctxRef = (*jenv)->CallObjectMethod(jenv, (jobject)(*g_cachedSSLObj), getCtxMethodId); CheckException(jenv); if (!ctxRef) { (*jenv)->ThrowNew(jenv, excClass, "Can't get WolfSSLContext object in NativeMacEncryptCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* get WolfSSLContext class reference from Java land */ innerCtxClass = (*jenv)->GetObjectClass(jenv, ctxRef); if (!innerCtxClass) { (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLContext class reference in " "NativeMacEncryptCb"); (*jenv)->DeleteLocalRef(jenv, ctxRef); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* get ref to internal MAC encrypt callback */ macEncryptMethodId = (*jenv)->GetMethodID(jenv, innerCtxClass, "internalMacEncryptCallback", "(Lcom/wolfssl/WolfSSLSession;Ljava/nio/ByteBuffer;" "[BJIILjava/nio/ByteBuffer;Ljava/nio/ByteBuffer;J)I"); if (!macEncryptMethodId) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Error getting internalMacEncryptCallback method from JNI"); (*jenv)->DeleteLocalRef(jenv, ctxRef); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); retval = -1; } if (retval == 0) { hmacSize = wolfSSL_GetHmacSize((WOLFSSL*)ssl); /* create ByteBuffer to wrap macOut */ macOutBB = (*jenv)->NewDirectByteBuffer(jenv, macOut, hmacSize); if (!macOutBB) { (*jenv)->ThrowNew(jenv, excClass, "failed to create macOut ByteBuffer"); (*jenv)->DeleteLocalRef(jenv, ctxRef); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* create jbyteArray to hold macIn, since macIn is read-only */ j_macIn = (*jenv)->NewByteArray(jenv, macInSz); if (!j_macIn) { (*jenv)->ThrowNew(jenv, excClass, "failed to create macIn ByteBuffer"); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, macOutBB); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } (*jenv)->SetByteArrayRegion(jenv, j_macIn, 0, macInSz, (jbyte*)macIn); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, macOutBB); (*jenv)->DeleteLocalRef(jenv, j_macIn); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* create ByteBuffer to wrap encOut */ encOutBB = (*jenv)->NewDirectByteBuffer(jenv, encOut, encSz); if (!encOutBB) { (*jenv)->ThrowNew(jenv, excClass, "failed to create encOut ByteBuffer"); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, macOutBB); (*jenv)->DeleteLocalRef(jenv, j_macIn); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* create ByteBuffer to wrap encIn - use encOut b/c it's not a * const, but points to same memory. This will be important * in Java-land in order to have an updated encIn array after * doing the MAC operation. */ encInBB = (*jenv)->NewDirectByteBuffer(jenv, encOut, encSz); if (!encInBB) { (*jenv)->ThrowNew(jenv, excClass, "failed to create encIn ByteBuffer"); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, macOutBB); (*jenv)->DeleteLocalRef(jenv, j_macIn); (*jenv)->DeleteLocalRef(jenv, encOutBB); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* call Java MAC/encrypt callback */ retval = (*jenv)->CallIntMethod(jenv, ctxRef, macEncryptMethodId, (jobject)(*g_cachedSSLObj), macOutBB, j_macIn, (jlong)macInSz, macContent, macVerify, encOutBB, encInBB, (jlong)encSz); if ((*jenv)->ExceptionOccurred(jenv) || retval != 0) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); (*jenv)->ThrowNew(jenv, excClass, "Call to Java callback failed in NativeMacEncryptCb"); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, macOutBB); (*jenv)->DeleteLocalRef(jenv, j_macIn); (*jenv)->DeleteLocalRef(jenv, encOutBB); (*jenv)->DeleteLocalRef(jenv, encInBB); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* delete local refs */ (*jenv)->DeleteLocalRef(jenv, macOutBB); (*jenv)->DeleteLocalRef(jenv, j_macIn); (*jenv)->DeleteLocalRef(jenv, encOutBB); (*jenv)->DeleteLocalRef(jenv, encInBB); } /* detach JNIEnv from thread */ (*jenv)->DeleteLocalRef(jenv, ctxRef); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return retval; } int NativeDecryptVerifyCb(WOLFSSL* ssl, unsigned char* decOut, const unsigned char* decIn, unsigned int decSz, int content, int verify, unsigned int* padSz, void* ctx) { jint retval = 0; jint vmret = 0; JNIEnv* jenv; /* JNI environment */ jclass excClass; /* WolfSSLJNIException class */ int needsDetach = 0; /* Should we explicitly detach? */ static jobject* g_cachedSSLObj; /* WolfSSLSession cached object */ jclass sessClass; /* WolfSSLSession class */ jfieldID ctxFid; /* WolfSSLSession->ctx FieldID */ jmethodID getCtxMethodId; /* WolfSSLSession->getAssCtxPtr() ID */ jobject ctxRef; /* WolfSSLContext object */ jclass innerCtxClass; /* WolfSSLContext class */ jmethodID decryptVerifyMethodId; jbyteArray j_decIn; jlongArray j_padSz; jobject decOutBB = NULL; jlong tmpVal = 0; (void)ctx; if (!g_vm || !ssl || !decOut || !decIn || !padSz) { return -1; } /* get JavaEnv from JavaVM */ vmret = (int)((*g_vm)->GetEnv(g_vm, (void**) &jenv, JNI_VERSION_1_6)); if (vmret == JNI_EDETACHED) { #ifdef __ANDROID__ vmret = (*g_vm)->AttachCurrentThread(g_vm, &jenv, NULL); #else vmret = (*g_vm)->AttachCurrentThread(g_vm, (void**) &jenv, NULL); #endif if (vmret) { return -1; } needsDetach = 1; } else if (vmret != JNI_OK) { return -1; } /* find exception class in case we need it */ excClass = (*jenv)->FindClass(jenv, "com/wolfssl/WolfSSLJNIException"); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* get stored WolfSSLSession jobject */ g_cachedSSLObj = (jobject*) wolfSSL_get_jobject((WOLFSSL*)ssl); if (!g_cachedSSLObj) { (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLSession object reference in " "NativeMacEncryptCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* lookup WolfSSLSession class from object */ sessClass = (*jenv)->GetObjectClass(jenv, (jobject)(*g_cachedSSLObj)); if (!sessClass) { (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLSession class reference in " "NativeMacEncryptCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* lookup WolfSSLContext private member fieldID */ ctxFid = (*jenv)->GetFieldID(jenv, sessClass, "ctx", "Lcom/wolfssl/WolfSSLContext;"); if (!ctxFid) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLContext field ID " "in NativeDecryptVerifyCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* find getContextPtr() method */ getCtxMethodId = (*jenv)->GetMethodID(jenv, sessClass, "getAssociatedContextPtr", "()Lcom/wolfssl/WolfSSLContext;"); if (!getCtxMethodId) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Can't get getAssociatedContextPtr() method ID " "in NativeDecryptVerifyCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* get WolfSSLContext ctx object from Java land */ ctxRef = (*jenv)->CallObjectMethod(jenv, (jobject)(*g_cachedSSLObj), getCtxMethodId); CheckException(jenv); if (!ctxRef) { (*jenv)->ThrowNew(jenv, excClass, "Can't get WolfSSLContext object in NativeDecryptVerifyCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* get WolfSSLContext class reference from Java land */ innerCtxClass = (*jenv)->GetObjectClass(jenv, ctxRef); if (!innerCtxClass) { (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLContext class reference " "in NativeDecryptVerifyCb"); (*jenv)->DeleteLocalRef(jenv, ctxRef); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* call internal decrypt/verify callback */ decryptVerifyMethodId = (*jenv)->GetMethodID(jenv, innerCtxClass, "internalDecryptVerifyCallback", "(Lcom/wolfssl/WolfSSLSession;Ljava/nio/ByteBuffer;[BJII[J)I"); if (!decryptVerifyMethodId) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Error getting internalDecryptVerifyCallback method " "from JNI"); (*jenv)->DeleteLocalRef(jenv, ctxRef); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } if (retval == 0) { /* create ByteBuffer to wrap decOut */ decOutBB = (*jenv)->NewDirectByteBuffer(jenv, decOut, decSz); if (!decOutBB) { (*jenv)->ThrowNew(jenv, excClass, "failed to create decOut ByteBuffer"); (*jenv)->DeleteLocalRef(jenv, ctxRef); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* create jbyteArray to hold decIn */ j_decIn = (*jenv)->NewByteArray(jenv, decSz); if (!j_decIn) { (*jenv)->ThrowNew(jenv, excClass, "failed to create decIn ByteArray"); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, decOutBB); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } (*jenv)->SetByteArrayRegion(jenv, j_decIn, 0, decSz, (jbyte*)decIn); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, decOutBB); (*jenv)->DeleteLocalRef(jenv, j_decIn); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* create jlongArray to hold padSz, since we need to use it as * an OUTPUT parameter from Java. Only needs to have 1 element */ j_padSz = (*jenv)->NewLongArray(jenv, 1); if (!j_padSz) { (*jenv)->ThrowNew(jenv, excClass, "failed to create padSz longArray"); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, decOutBB); (*jenv)->DeleteLocalRef(jenv, j_decIn); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* call Java decrypt/verify callback, java layer handles * adding decrypt/verify CTX reference */ retval = (*jenv)->CallIntMethod(jenv, ctxRef, decryptVerifyMethodId, (jobject)(*g_cachedSSLObj), decOutBB, j_decIn, (jlong)decSz, content, verify, j_padSz); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, decOutBB); (*jenv)->DeleteLocalRef(jenv, j_decIn); (*jenv)->DeleteLocalRef(jenv, j_padSz); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } if (retval == 0) { /* copy j_padSz into padSz */ (*jenv)->GetLongArrayRegion(jenv, j_padSz, 0, 1, &tmpVal); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, decOutBB); (*jenv)->DeleteLocalRef(jenv, j_decIn); (*jenv)->DeleteLocalRef(jenv, j_padSz); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } *padSz = (unsigned int)tmpVal; } /* delete local refs */ (*jenv)->DeleteLocalRef(jenv, decOutBB); (*jenv)->DeleteLocalRef(jenv, j_decIn); (*jenv)->DeleteLocalRef(jenv, j_padSz); } /* delete local refs, detach JNIEnv from thread */ (*jenv)->DeleteLocalRef(jenv, ctxRef); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return retval; } #endif /* ATOMIC_USER */ JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLContext_setEccSignCb (JNIEnv* jenv, jobject jcl, jlong ctx) { jclass excClass = NULL; (void)jcl; /* find exception class */ excClass = (*jenv)->FindClass(jenv, "com/wolfssl/WolfSSLJNIException"); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); return; } #if defined(HAVE_PK_CALLBACKS) && defined(HAVE_ECC) if(ctx) { /* set ECC sign callback */ wolfSSL_CTX_SetEccSignCb((WOLFSSL_CTX*)(uintptr_t)ctx, NativeEccSignCb); } else { (*jenv)->ThrowNew(jenv, excClass, "Input WolfSSLContext object was null when setting " "EccSignCb"); } #else (*jenv)->ThrowNew(jenv, excClass, "wolfSSL not compiled with PK Callback support " "(HAVE_PK_CALLBACKS)"); #endif } #if defined(HAVE_PK_CALLBACKS) && defined(HAVE_ECC) int NativeEccSignCb(WOLFSSL* ssl, const unsigned char* in, unsigned int inSz, unsigned char* out, unsigned int* outSz, const unsigned char* keyDer, unsigned int keySz, void* ctx) { jint retval = 0; jint vmret = 0; JNIEnv* jenv; /* JNI Environment */ jclass excClass; /* WolfSSLJNIException class */ int needsDetach = 0; /* Should we explicitly detach? */ static jobject* g_cachedSSLObj; /* WolfSSLSession cached object */ jclass sessClass; /* WolfSSLSession class */ jfieldID ctxFid; /* WolfSSLSession->ctx FieldID */ jmethodID getCtxMethodId; /* WolfSSLSession->getAssCtxPtr() ID */ jobject ctxRef; /* WolfSSLContext object */ jclass innerCtxClass; /* WolfSSLContext class */ jmethodID eccSignMethodId; jlongArray j_outSz; jobject outBB = NULL; jobject inBB = NULL; jobject keyDerBB = NULL; jlong tmpVal = 0; (void)ctx; if (!g_vm || !ssl || !in || !out || !outSz || !keyDer) return -1; /* get JavaEnv from JavaVM */ vmret = (int)((*g_vm)->GetEnv(g_vm, (void**) &jenv, JNI_VERSION_1_6)); if (vmret == JNI_EDETACHED) { #ifdef __ANDROID__ vmret = (*g_vm)->AttachCurrentThread(g_vm, &jenv, NULL); #else vmret = (*g_vm)->AttachCurrentThread(g_vm, (void**) &jenv, NULL); #endif if (vmret) { return -1; } needsDetach = 1; } else if (vmret != JNI_OK) { return -1; } /* find exception class in case we need it */ excClass = (*jenv)->FindClass(jenv, "com/wolfssl/WolfSSLJNIException"); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* get stored WolfSSLSession jobject */ g_cachedSSLObj = (jobject*) wolfSSL_get_jobject((WOLFSSL*)ssl); if (!g_cachedSSLObj) { (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLSession object reference in " "NativeEccSignCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* lookup WolfSSLSession class from object */ sessClass = (*jenv)->GetObjectClass(jenv, (jobject)(*g_cachedSSLObj)); if (!sessClass) { (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLSession class reference in " "NativeEccSignCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* lookup WolfSSLContext private member fieldID */ ctxFid = (*jenv)->GetFieldID(jenv, sessClass, "ctx", "Lcom/wolfssl/WolfSSLContext;"); if (!ctxFid) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLContext field ID " "in NativeEccSignCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* find getContextPtr() method */ getCtxMethodId = (*jenv)->GetMethodID(jenv, sessClass, "getAssociatedContextPtr", "()Lcom/wolfssl/WolfSSLContext;"); if (!getCtxMethodId) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Can't get getAssociatedContextPtr() method ID " "in NativeEccSignCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* get WolfSSLContext ctx object from Java land */ ctxRef = (*jenv)->CallObjectMethod(jenv, (jobject)(*g_cachedSSLObj), getCtxMethodId); CheckException(jenv); if (!ctxRef) { (*jenv)->ThrowNew(jenv, excClass, "Can't get WolfSSLContext object in NativeEccSignCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* get WolfSSLContext class reference from Java land */ innerCtxClass = (*jenv)->GetObjectClass(jenv, ctxRef); if (!innerCtxClass) { (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLContext class reference " "in NativeEccSignCb"); (*jenv)->DeleteLocalRef(jenv, ctxRef); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* call internal decrypt/verify callback */ eccSignMethodId = (*jenv)->GetMethodID(jenv, innerCtxClass, "internalEccSignCallback", "(Lcom/wolfssl/WolfSSLSession;Ljava/nio/ByteBuffer;" "JLjava/nio/ByteBuffer;[JLjava/nio/ByteBuffer;J)I"); if (!eccSignMethodId) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Error getting internalEccSignCallback method " "from JNI"); (*jenv)->DeleteLocalRef(jenv, ctxRef); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* create ByteBuffer to wrap out */ outBB = (*jenv)->NewDirectByteBuffer(jenv, out, *outSz); if (!outBB) { (*jenv)->ThrowNew(jenv, excClass, "failed to create eccSign out ByteBuffer"); (*jenv)->DeleteLocalRef(jenv, ctxRef); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* create ByteBuffer to wrap in */ inBB = (*jenv)->NewDirectByteBuffer(jenv, (void*)in, inSz); if (!inBB) { (*jenv)->ThrowNew(jenv, excClass, "failed to create eccSign in ByteBuffer"); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, outBB); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* create ByteBuffer to wrap keyDer */ keyDerBB = (*jenv)->NewDirectByteBuffer(jenv, (void*)keyDer, keySz); if (!keyDerBB) { (*jenv)->ThrowNew(jenv, excClass, "failed to create eccSign keyDer ByteBuffer"); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, outBB); (*jenv)->DeleteLocalRef(jenv, inBB); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* create jlongArray to hold outSz, since we need to use it as * an OUTPUT parameter from Java. Only needs to have 1 element */ j_outSz = (*jenv)->NewLongArray(jenv, 1); if (!j_outSz) { (*jenv)->ThrowNew(jenv, excClass, "failed to create outSz longArray"); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, outBB); (*jenv)->DeleteLocalRef(jenv, inBB); (*jenv)->DeleteLocalRef(jenv, keyDerBB); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* copy outSz into j_outSz */ (*jenv)->SetLongArrayRegion(jenv, j_outSz, 0, 1, (jlong*)outSz); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); (*jenv)->ThrowNew(jenv, excClass, "failed to set j_outSz longArray"); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, outBB); (*jenv)->DeleteLocalRef(jenv, inBB); (*jenv)->DeleteLocalRef(jenv, keyDerBB); (*jenv)->DeleteLocalRef(jenv, j_outSz); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* call Java ECC sign callback, java layer handles * adding decrypt/verify CTX reference */ retval = (*jenv)->CallIntMethod(jenv, ctxRef, eccSignMethodId, (jobject)(*g_cachedSSLObj), inBB, (jlong)inSz, outBB, j_outSz, keyDerBB, (jlong)keySz); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } if (retval == 0) { /* copy j_outSz into outSz */ (*jenv)->GetLongArrayRegion(jenv, j_outSz, 0, 1, &tmpVal); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, outBB); (*jenv)->DeleteLocalRef(jenv, inBB); (*jenv)->DeleteLocalRef(jenv, keyDerBB); (*jenv)->DeleteLocalRef(jenv, j_outSz); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } *outSz = (unsigned int)tmpVal; } /* delete local refs */ (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, outBB); (*jenv)->DeleteLocalRef(jenv, inBB); (*jenv)->DeleteLocalRef(jenv, keyDerBB); (*jenv)->DeleteLocalRef(jenv, j_outSz); /* detach JNIEnv from thread */ if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return retval; } #endif /* HAVE_PK_CALLBACKS */ JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLContext_setEccVerifyCb (JNIEnv* jenv, jobject jcl, jlong ctx) { jclass excClass = NULL; (void)jcl; /* find exception class */ excClass = (*jenv)->FindClass(jenv, "com/wolfssl/WolfSSLJNIException"); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); return; } #if defined(HAVE_PK_CALLBACKS) && defined(HAVE_ECC) if(ctx) { /* set ECC verify callback */ wolfSSL_CTX_SetEccVerifyCb((WOLFSSL_CTX*)(uintptr_t)ctx, NativeEccVerifyCb); } else { (*jenv)->ThrowNew(jenv, excClass, "Input WolfSSLContext object was null when setting " "EccVerifyCb"); } #else (*jenv)->ThrowNew(jenv, excClass, "wolfSSL not compiled with PK Callback support " "(HAVE_PK_CALLBACKS)"); #endif } #if defined(HAVE_PK_CALLBACKS) && defined(HAVE_ECC) int NativeEccVerifyCb(WOLFSSL* ssl, const unsigned char* sig, unsigned int sigSz, const unsigned char* hash, unsigned int hashSz, const unsigned char* keyDer, unsigned int keySz, int* result, void* ctx) { jint retval = 0; jint vmret = 0; JNIEnv* jenv; /* JNI Environment */ jclass excClass; /* WolfSSLJNIException class */ int needsDetach = 0; /* Should we explicitly detach? */ static jobject* g_cachedSSLObj; /* WolfSSLSession cached object */ jclass sessClass; /* WolfSSLSession class */ jfieldID ctxFid; /* WolfSSLSession->ctx FieldID */ jmethodID getCtxMethodId; /* WolfSSLSession->getAssCtxPtr() ID */ jobject ctxRef; /* WolfSSLContext object */ jclass innerCtxClass; /* WolfSSLContext class */ jmethodID eccVerifyMethodId; jintArray j_result; jobject sigBB = NULL; jobject hashBB = NULL; jobject keyDerBB = NULL; jint tmpVal = 0; (void)ctx; if (!g_vm || !ssl || !sig || !hash || !keyDer || !result) return -1; /* get JavaEnv from JavaVM */ vmret = (int)((*g_vm)->GetEnv(g_vm, (void**) &jenv, JNI_VERSION_1_6)); if (vmret == JNI_EDETACHED) { #ifdef __ANDROID__ vmret = (*g_vm)->AttachCurrentThread(g_vm, &jenv, NULL); #else vmret = (*g_vm)->AttachCurrentThread(g_vm, (void**) &jenv, NULL); #endif if (vmret) { return -1; } needsDetach = 1; } else if (vmret != JNI_OK) { return -1; } /* find exception class in case we need it */ excClass = (*jenv)->FindClass(jenv, "com/wolfssl/WolfSSLJNIException"); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* get stored WolfSSLSession jobject */ g_cachedSSLObj = (jobject*) wolfSSL_get_jobject((WOLFSSL*)ssl); if (!g_cachedSSLObj) { (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLSession object reference in " "NativeEccVerifyCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* lookup WolfSSLSession class from object */ sessClass = (*jenv)->GetObjectClass(jenv, (jobject)(*g_cachedSSLObj)); if (!sessClass) { (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLSession class reference in " "NativeEccVerifyCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* lookup WolfSSLContext private member fieldID */ ctxFid = (*jenv)->GetFieldID(jenv, sessClass, "ctx", "Lcom/wolfssl/WolfSSLContext;"); if (!ctxFid) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLContext field ID " "in NativeEccVerifyCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* find getContextPtr() method */ getCtxMethodId = (*jenv)->GetMethodID(jenv, sessClass, "getAssociatedContextPtr", "()Lcom/wolfssl/WolfSSLContext;"); if (!getCtxMethodId) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Can't get getAssociatedContextPtr() method ID " "in NativeEccVerifyCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* get WolfSSLContext ctx object from Java land */ ctxRef = (*jenv)->CallObjectMethod(jenv, (jobject)(*g_cachedSSLObj), getCtxMethodId); CheckException(jenv); if (!ctxRef) { (*jenv)->ThrowNew(jenv, excClass, "Can't get WolfSSLContext object in NativeEccVerifyCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* get WolfSSLContext class reference from Java land */ innerCtxClass = (*jenv)->GetObjectClass(jenv, ctxRef); if (!innerCtxClass) { (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLContext class reference " "in NativeEccVerifyCb"); (*jenv)->DeleteLocalRef(jenv, ctxRef); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* call internal ECC verify callback */ eccVerifyMethodId = (*jenv)->GetMethodID(jenv, innerCtxClass, "internalEccVerifyCallback", "(Lcom/wolfssl/WolfSSLSession;Ljava/nio/ByteBuffer;" "JLjava/nio/ByteBuffer;JLjava/nio/ByteBuffer;J[I)I"); if (!eccVerifyMethodId) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Error getting internalEccVerifyCallback method from JNI"); (*jenv)->DeleteLocalRef(jenv, ctxRef); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* create ByteBuffer to wrap 'sig' */ sigBB = (*jenv)->NewDirectByteBuffer(jenv, (void*)sig, sigSz); if (!sigBB) { (*jenv)->ThrowNew(jenv, excClass, "Failed to create eccVerify out ByteBuffer"); (*jenv)->DeleteLocalRef(jenv, ctxRef); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* create ByteBuffer to wrap 'hash' */ hashBB = (*jenv)->NewDirectByteBuffer(jenv, (void*)hash, hashSz); if (!hashBB) { (*jenv)->ThrowNew(jenv, excClass, "Failed to create eccVerify hash ByteBuffer"); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, sigBB); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* create ByteBuffer to wrap 'keyDer' */ keyDerBB = (*jenv)->NewDirectByteBuffer(jenv, (void*)keyDer, keySz); if (!keyDerBB) { (*jenv)->ThrowNew(jenv, excClass, "Failed to create eccVerify keyDer ByteBuffer"); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, sigBB); (*jenv)->DeleteLocalRef(jenv, hashBB); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* create jintArray to hold result, since we need to use it as * an OUTPUT parameter from Java. Only needs to have 1 element */ j_result = (*jenv)->NewIntArray(jenv, 1); if (!j_result) { (*jenv)->ThrowNew(jenv, excClass, "Failed to create result intArray in EccVerifyCb"); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, sigBB); (*jenv)->DeleteLocalRef(jenv, hashBB); (*jenv)->DeleteLocalRef(jenv, keyDerBB); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* call Java ECC verify callback, java layer handles * adding CTX reference */ retval = (*jenv)->CallIntMethod(jenv, ctxRef, eccVerifyMethodId, (jobject)(*g_cachedSSLObj), sigBB, (jlong)sigSz, hashBB, (jlong)hashSz, keyDerBB, (jlong)keySz, j_result); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, sigBB); (*jenv)->DeleteLocalRef(jenv, hashBB); (*jenv)->DeleteLocalRef(jenv, keyDerBB); (*jenv)->DeleteLocalRef(jenv, j_result); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* copy j_result into result */ (*jenv)->GetIntArrayRegion(jenv, j_result, 0, 1, &tmpVal); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, sigBB); (*jenv)->DeleteLocalRef(jenv, hashBB); (*jenv)->DeleteLocalRef(jenv, keyDerBB); (*jenv)->DeleteLocalRef(jenv, j_result); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } *result = tmpVal; /* delete local refs */ (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, sigBB); (*jenv)->DeleteLocalRef(jenv, hashBB); (*jenv)->DeleteLocalRef(jenv, keyDerBB); (*jenv)->DeleteLocalRef(jenv, j_result); /* detach JNIEnv from thread */ if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return retval; } #endif /* HAVE_PK_CALLBACKS */ JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLContext_setEccSharedSecretCb (JNIEnv* jenv, jobject jcl, jlong ctxPtr) { #if defined(HAVE_PK_CALLBACKS) && defined(HAVE_ECC) WOLFSSL_CTX* ctx = (WOLFSSL_CTX*)(uintptr_t)ctxPtr; (void)jcl; if(ctx != NULL) { /* set ECC shared secret callback */ wolfSSL_CTX_SetEccSharedSecretCb(ctx, NativeEccSharedSecretCb); } else { throwWolfSSLJNIExceptionWithMsg(jenv, "Input WolfSSLContext object was null when setting " "EccSharedSecretCb", 0); } #else (void)ctxPtr; (void)jcl; throwWolfSSLJNIExceptionWithMsg(jenv, "wolfSSL not compiled with PK Callback support " "(HAVE_PK_CALLBACKS)", 0); #endif } #if defined(HAVE_PK_CALLBACKS) && defined(HAVE_ECC) /* Get MethodID from provided object, method name, and method signature. * Stores MethodID in mid. * return 0 on success, negative on error. */ static int GetMethodIDFromObject(JNIEnv* jenv, jobject obj, const char* methodName, const char* methodSig, jmethodID* mid) { jclass class; if (jenv == NULL || methodName == NULL || methodSig == NULL) return BAD_FUNC_ARG; class = (*jenv)->GetObjectClass(jenv, obj); if (!class) { printf("GetObjectClass failed in GetMethodIDFromObject"); return -1; } *mid = (*jenv)->GetMethodID(jenv, class, methodName, methodSig); if (*mid == NULL) { printf("GetMethodID failed in GetMethodIDFromObject"); CheckException(jenv); return -1; } return 0; } /* get WolfSSLContext from WolfSSLSession ID, storing context in ctxRef. * return 0 on success, negative on error */ static int GetWolfSSLContextFromSessionObj(JNIEnv* jenv, jobject* sessObj, jobject* ctxRef) { jclass sessClass; /* WolfSSLSession class */ jmethodID getCtxMethodId; /* WolfSSLSession->getAssCtxPtr() ID */ if (jenv == NULL || sessObj == NULL || ctxRef == NULL) return BAD_FUNC_ARG; /* lookup WolfSSLSession class from object */ sessClass = (*jenv)->GetObjectClass(jenv, (jobject)(*sessObj)); if (!sessClass) { printf("Can't get native WolfSSLSession class reference in " "GetWolfSSLContextFromSessionObj"); return -1; } /* find getContextPtr() method */ getCtxMethodId = (*jenv)->GetMethodID(jenv, sessClass, "getAssociatedContextPtr", "()Lcom/wolfssl/WolfSSLContext;"); if (!getCtxMethodId) { CheckException(jenv); printf("Can't get getAssociatedContextPtr() methodID in " "GetWolfSSLContextFromSessionObj"); return -1; } /* get WolfSSLContext ctx object from Java land */ *ctxRef = (*jenv)->CallObjectMethod(jenv, (jobject)(*sessObj), getCtxMethodId); CheckException(jenv); if (!(*ctxRef)) { printf("Can't get WolfSSLContext object in " "GetWolfSSLContextFromSessionObj"); return -1; } return 0; } /* Java JCE uses ECC public keys that are DER formatted with a header * that specifies the key type and curve. wolfSSL requires a raw ECC * public key for ECC shared secret callback. This function strips off * the header, giving the callback the raw key. * * publicKeyDer - IN/OUT ECC DER public key, ECC raw public key * pubKeySz - size of publicKeyDer buffer * * returns size of new publicKeyDer contents */ static int StripEccPublicDerHeaderInline(byte* publicKeyDer, word32 pubKeySz) { int ret = 0; word32 idx = 0; word32 keySz = 0; ecc_key tmpKey; if (publicKeyDer == NULL) return BAD_FUNC_ARG; /* DER encoded header will start with 0x30 sequence */ if (publicKeyDer[0] == (ASN_SEQUENCE | ASN_CONSTRUCTED)) { keySz = pubKeySz; ret = wc_ecc_init(&tmpKey); if (ret < 0) return ret; ret = wc_EccPublicKeyDecode(publicKeyDer, &idx, &tmpKey, pubKeySz); if (ret < 0) { wc_ecc_free(&tmpKey); return ret; } ret = wc_ecc_export_x963(&tmpKey, publicKeyDer, &keySz); if (ret < 0) { wc_ecc_free(&tmpKey); return ret; } wc_ecc_free(&tmpKey); return keySz; } return ret; } int NativeEccSharedSecretCb(WOLFSSL* ssl, ecc_key* otherKey, unsigned char* publicKeyDer, unsigned int* pubKeySz, unsigned char* out, unsigned int* outlen, int side, void* ctx) { int ret; jint retval = 0; JNIEnv* jenv = NULL; /* JNI Environment */ int needsDetach = 0; /* Should we explicitly detach? */ static jobject* g_cachedSSLObj; /* WolfSSLSession cached object */ jobject ctxRef; /* WolfSSLContext object */ jmethodID eccSharedSecretMethodId; jbyteArray j_pubKeyDerSz; jbyteArray j_outSz; jclass eccKeyClass; jmethodID eccKeyMethodId; jobject eccKeyObject; ecc_key tmpKey; /* tmp key, used in conversion */ byte* tmpKeyDer = NULL; /* tmp der buffer, used in conversion */ word32 tmpKeyDerSz; /* stores size of tmpKeyDer */ jobject pubKeyDerBB = NULL; jobject outBB = NULL; jlong tmpVal = 0; (void)ctx; if (!g_vm || !ssl || !otherKey || !publicKeyDer || !pubKeySz || !out || !outlen) return -1; /* get JavaEnv from JavaVM */ ret = GetJNIEnvFromVM(g_vm, &jenv, &needsDetach); if (ret != 0) return ret; /* get stored WolfSSLSession jobject */ g_cachedSSLObj = (jobject*) wolfSSL_get_jobject((WOLFSSL*)ssl); if (!g_cachedSSLObj) { throwWolfSSLJNIExceptionWithMsg(jenv, "Can't get WolfSSLSession reference in NativeEccSharedSecretCb", needsDetach); return -1; } /* get WolfSSLContext ctx object from Java land */ ret = GetWolfSSLContextFromSessionObj(jenv, g_cachedSSLObj, &ctxRef); if (ret != 0) { CheckException(jenv); throwWolfSSLJNIExceptionWithMsg(jenv, "Unable to get WolfSSLContext reference", needsDetach); return ret; } /* find internal ecc shared secret callback */ ret = GetMethodIDFromObject(jenv, ctxRef, "internalEccSharedSecretCallback", "(Lcom/wolfssl/WolfSSLSession;Lcom/wolfssl/wolfcrypt/EccKey;" "Ljava/nio/ByteBuffer;[JLjava/nio/ByteBuffer;[JI)I", &eccSharedSecretMethodId); if (ret != 0) { throwWolfSSLJNIExceptionWithMsg(jenv, "GetMethodIDFromObject failed in NativeEccSharedSecretCb", needsDetach); return -1; } /* SETUP: otherKey - holds server's public key on client end, otherwise * holds server's private key on server end. */ /* find EccKey class */ eccKeyClass = (*jenv)->FindClass(jenv, "com/wolfssl/wolfcrypt/EccKey"); if (!eccKeyClass) { CheckException(jenv); throwWolfSSLJNIExceptionWithMsg(jenv, "Error finding EccKey class for ECC shared secret callback", needsDetach); return -1; } /* find EccKey constructor */ eccKeyMethodId = (*jenv)->GetMethodID(jenv, eccKeyClass, "", "(J)V"); if (!eccKeyMethodId) { CheckException(jenv); throwWolfSSLJNIExceptionWithMsg(jenv, "Error getting EccKey constructor method ID in " "ECC shared secret callback", needsDetach); return -1; } /* create new EccKey object to return otherKey */ eccKeyObject = (*jenv)->NewObject(jenv, eccKeyClass, eccKeyMethodId, (jlong)(uintptr_t)otherKey); if (!eccKeyObject) { CheckException(jenv); throwWolfSSLJNIExceptionWithMsg(jenv, "Error creating EccKey object in native ECC " "shared secret callback", needsDetach); return -1; } /* SETUP: publicKeyDer - create ByteBuffer to wrap publicKeyDer. * publicKeyDer is an output buffer for client's public key to be * placed (client side), otherwise it contains the client's public * key (server side) */ if (side == WOLFSSL_SERVER_END) { /* publicKeyDer is ECC public key without DER header. Add header * back on here before giving to Java callback, since we know * curve details now */ retval = wc_ecc_init(&tmpKey); if (retval != 0) { (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, eccKeyObject); throwWolfSSLJNIExceptionWithMsg(jenv, "Failed to init " "eccSharedSecret tmpKey", needsDetach); return -1; } retval = wc_ecc_import_x963_ex(publicKeyDer, *pubKeySz, &tmpKey, otherKey->dp->id); if (retval != 0) { (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, eccKeyObject); wc_ecc_free(&tmpKey); throwWolfSSLJNIExceptionWithMsg(jenv, "Failed to import " "eccSharedSecret publicKeyDer", needsDetach); return -1; } tmpKeyDer = (byte*)XMALLOC(ECC_BUFSIZE, otherKey->heap, DYNAMIC_TYPE_TMP_BUFFER); if (!tmpKeyDer) { (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, eccKeyObject); wc_ecc_free(&tmpKey); throwWolfSSLJNIExceptionWithMsg(jenv, "Failed to allocate " "eccSharedSecret tmpKeyDer", needsDetach); return -1; } tmpKeyDerSz = wc_EccPublicKeyToDer(&tmpKey, tmpKeyDer, ECC_BUFSIZE, 1); if (tmpKeyDerSz <= 0) { (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, eccKeyObject); wc_ecc_free(&tmpKey); XFREE(tmpKeyDer, key->heap, DYNAMIC_TYPE_TMP_BUFFER); throwWolfSSLJNIExceptionWithMsg(jenv, "Failed to export " "eccSharedSecret public key to DER", needsDetach); return -1; } wc_ecc_free(&tmpKey); pubKeyDerBB = (*jenv)->NewDirectByteBuffer(jenv, tmpKeyDer, tmpKeyDerSz); if (!pubKeyDerBB) { (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, eccKeyObject); XFREE(tmpKeyDer, key->heap, DYNAMIC_TYPE_TMP_BUFFER); throwWolfSSLJNIExceptionWithMsg(jenv, "Failed to create " "eccSharedSecret publicKeyDer ByteBuffer", needsDetach); return -1; } } else { /* CLIENT side */ pubKeyDerBB = (*jenv)->NewDirectByteBuffer(jenv, publicKeyDer, *pubKeySz); if (!pubKeyDerBB) { (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, eccKeyObject); throwWolfSSLJNIExceptionWithMsg(jenv, "Failed to create " "eccSharedSecret publicKeyDer ByteBuffer", needsDetach); return -1; } } /* SETUP: publicKeyDerSz * create jlongArray to hold publicKeyDerSz, since we need to use it as an * OUTPUT parameter from Java. Only needs to have 1 element. */ j_pubKeyDerSz = (*jenv)->NewLongArray(jenv, 1); if (!j_pubKeyDerSz) { (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, eccKeyObject); (*jenv)->DeleteLocalRef(jenv, pubKeyDerBB); if (side == WOLFSSL_SERVER_END) XFREE(tmpKeyDer, key->heap, DYNAMIC_TYPE_TMP_BUFFER); throwWolfSSLJNIExceptionWithMsg(jenv, "Failed to create " "eccSharedSecret array for publicKeyDerSz", needsDetach); return -1; } /* SETUP: out * create ByteBuffer to wrap out */ outBB = (*jenv)->NewDirectByteBuffer(jenv, out, *outlen); if (!outBB) { (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, eccKeyObject); (*jenv)->DeleteLocalRef(jenv, pubKeyDerBB); (*jenv)->DeleteLocalRef(jenv, j_pubKeyDerSz); if (side == WOLFSSL_SERVER_END) XFREE(tmpKeyDer, key->heap, DYNAMIC_TYPE_TMP_BUFFER); throwWolfSSLJNIExceptionWithMsg(jenv, "Failed to create " "eccSharedSecret out ByteBuffer", needsDetach); return -1; } /* SETUP: outSz * create jlongArray to hold outSz, since we need to use it as an * OUTPUT parameter from Java. Only needs to have 1 element. */ j_outSz = (*jenv)->NewLongArray(jenv, 1); if (!j_outSz) { (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, eccKeyObject); (*jenv)->DeleteLocalRef(jenv, pubKeyDerBB); (*jenv)->DeleteLocalRef(jenv, j_pubKeyDerSz); if (side == WOLFSSL_SERVER_END) XFREE(tmpKeyDer, key->heap, DYNAMIC_TYPE_TMP_BUFFER); throwWolfSSLJNIExceptionWithMsg(jenv, "Failed to create " "eccSharedSecret array for outSz", needsDetach); return -1; } /* call Java ECC shared secret callback, java layer handles * adding shared secret CTX reference */ retval = (*jenv)->CallIntMethod(jenv, ctxRef, eccSharedSecretMethodId, (jobject)(*g_cachedSSLObj), eccKeyObject, pubKeyDerBB, j_pubKeyDerSz, outBB, j_outSz, (jint)side); CheckException(jenv); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, eccKeyObject); (*jenv)->DeleteLocalRef(jenv, pubKeyDerBB); if (side == WOLFSSL_SERVER_END) { XFREE(tmpKeyDer, key->heap, DYNAMIC_TYPE_TMP_BUFFER); } if (retval == 0) { /* copy j_outSz into outlen, j_pubKeyDerSz into pubKeySz */ (*jenv)->GetLongArrayRegion(jenv, j_outSz, 0, 1, &tmpVal); if (CheckException(jenv)) { (*jenv)->DeleteLocalRef(jenv, j_pubKeyDerSz); (*jenv)->DeleteLocalRef(jenv, j_outSz); (*jenv)->DeleteLocalRef(jenv, outBB); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } *outlen = (unsigned int)tmpVal; if (side == WOLFSSL_CLIENT_END) { (*jenv)->GetLongArrayRegion(jenv, j_pubKeyDerSz, 0, 1, &tmpVal); if (CheckException(jenv)) { (*jenv)->DeleteLocalRef(jenv, j_pubKeyDerSz); (*jenv)->DeleteLocalRef(jenv, j_outSz); (*jenv)->DeleteLocalRef(jenv, outBB); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } *pubKeySz = (unsigned int)tmpVal; /* attempt to strip off DER header if present, wolfSSL * requires raw ECC public key. ret is 0 if header not detected */ ret = StripEccPublicDerHeaderInline(publicKeyDer, *pubKeySz); if (ret < 0) { (*jenv)->DeleteLocalRef(jenv, j_pubKeyDerSz); (*jenv)->DeleteLocalRef(jenv, j_outSz); (*jenv)->DeleteLocalRef(jenv, outBB); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } else if (ret > 0) { *pubKeySz = ret; } } } /* delete local refs */ (*jenv)->DeleteLocalRef(jenv, j_pubKeyDerSz); (*jenv)->DeleteLocalRef(jenv, j_outSz); (*jenv)->DeleteLocalRef(jenv, outBB); /* detach JNIEnv from thread */ if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return retval; } #endif /* HAVE_PK_CALLBACKS */ JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLContext_setRsaSignCb (JNIEnv* jenv, jobject jcl, jlong ctxPtr) { WOLFSSL_CTX* ctx = (WOLFSSL_CTX*)(uintptr_t)ctxPtr; jclass excClass = NULL; (void)jcl; /* find exception class */ excClass = (*jenv)->FindClass(jenv, "com/wolfssl/WolfSSLJNIException"); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); return; } #if defined(HAVE_PK_CALLBACKS) && !defined(NO_RSA) if(ctx != NULL) { /* set RSA sign callback */ wolfSSL_CTX_SetRsaSignCb(ctx, NativeRsaSignCb); } else { (*jenv)->ThrowNew(jenv, excClass, "Input WolfSSLContext object was null when setting " "RsaSignCb"); } #else (void)ctx; (*jenv)->ThrowNew(jenv, excClass, "wolfSSL not compiled with PK Callback support and/or RSA support"); #endif } #if defined(HAVE_PK_CALLBACKS) && !defined(NO_RSA) int NativeRsaSignCb(WOLFSSL* ssl, const unsigned char* in, unsigned int inSz, unsigned char* out, unsigned int* outSz, const unsigned char* keyDer, unsigned int keySz, void* ctx) { jint retval = 0; jint vmret = 0; JNIEnv* jenv; /* JNI Environment */ jclass excClass; /* WolfSSLJNIException class */ int needsDetach = 0; /* Should we explicitly detach? */ static jobject* g_cachedSSLObj; /* WolfSSLSession cached object */ jclass sessClass; /* WolfSSLSession class */ jfieldID ctxFid; /* WolfSSLSession->ctx FieldID */ jmethodID getCtxMethodId; /* WolfSSLSession->getAssCtxPtr() ID */ jobject ctxRef; /* WolfSSLContext object */ jclass innerCtxClass; /* WolfSSLContext class */ jmethodID rsaSignMethodId; jintArray j_outSz; jobject inBB = NULL; jobject outBB = NULL; jobject keyDerBB = NULL; jint tmpVal = 0; (void)ctx; if (!g_vm || !ssl || !in || !out || !outSz || !keyDer) return -1; /* get JavaEnv from JavaVM */ vmret = (int)((*g_vm)->GetEnv(g_vm, (void**) &jenv, JNI_VERSION_1_6)); if (vmret == JNI_EDETACHED) { #ifdef __ANDROID__ vmret = (*g_vm)->AttachCurrentThread(g_vm, &jenv, NULL); #else vmret = (*g_vm)->AttachCurrentThread(g_vm, (void**) &jenv, NULL); #endif if (vmret) { return -1; } needsDetach = 1; } else if (vmret != JNI_OK) { return -1; } /* find exception class in case we need it */ excClass = (*jenv)->FindClass(jenv, "com/wolfssl/WolfSSLJNIException"); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* get stored WolfSSLSession jobject */ g_cachedSSLObj = (jobject*) wolfSSL_get_jobject((WOLFSSL*)ssl); if (!g_cachedSSLObj) { (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLSession object reference in " "NativeRsaSignCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* lookup WolfSSLSession class from object */ sessClass = (*jenv)->GetObjectClass(jenv, (jobject)(*g_cachedSSLObj)); if (!sessClass) { (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLSession class reference in " "NativeRsaSignCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* lookup WolfSSLContext private member fieldID */ ctxFid = (*jenv)->GetFieldID(jenv, sessClass, "ctx", "Lcom/wolfssl/WolfSSLContext;"); if (!ctxFid) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLContext field ID " "in NativeRsaSignCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* find getContextPtr() method */ getCtxMethodId = (*jenv)->GetMethodID(jenv, sessClass, "getAssociatedContextPtr", "()Lcom/wolfssl/WolfSSLContext;"); if (!getCtxMethodId) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Can't get getAssociatedContextPtr() method ID " "in NativeRsaSignCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* get WolfSSLContext ctx object from Java land */ ctxRef = (*jenv)->CallObjectMethod(jenv, (jobject)(*g_cachedSSLObj), getCtxMethodId); CheckException(jenv); if (!ctxRef) { (*jenv)->ThrowNew(jenv, excClass, "Can't get WolfSSLContext object in NativeRsaSignCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* get WolfSSLContext class reference from Java land */ innerCtxClass = (*jenv)->GetObjectClass(jenv, ctxRef); if (!innerCtxClass) { (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLContext class reference " "in NativeRsaSignCb"); (*jenv)->DeleteLocalRef(jenv, ctxRef); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* call internal RSA sign callback */ rsaSignMethodId = (*jenv)->GetMethodID(jenv, innerCtxClass, "internalRsaSignCallback", "(Lcom/wolfssl/WolfSSLSession;Ljava/nio/ByteBuffer;" "JLjava/nio/ByteBuffer;[ILjava/nio/ByteBuffer;J)I"); if (!rsaSignMethodId) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Error getting internalRsaSignCallback method from JNI"); (*jenv)->DeleteLocalRef(jenv, ctxRef); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* create ByteBuffer to wrap 'in' */ inBB = (*jenv)->NewDirectByteBuffer(jenv, (void*)in, inSz); if (!inBB) { (*jenv)->ThrowNew(jenv, excClass, "Failed to create rsaSign in ByteBuffer"); (*jenv)->DeleteLocalRef(jenv, ctxRef); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* create ByteBuffer to wrap 'out' */ outBB = (*jenv)->NewDirectByteBuffer(jenv, (void*)out, *outSz); if (!outBB) { (*jenv)->ThrowNew(jenv, excClass, "Failed to create rsaSign out ByteBuffer"); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, inBB); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* create ByteBuffer to wrap 'keyDer' */ keyDerBB = (*jenv)->NewDirectByteBuffer(jenv, (void*)keyDer, keySz); if (!keyDerBB) { (*jenv)->ThrowNew(jenv, excClass, "Failed to create rsaSign keyDer ByteBuffer"); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, inBB); (*jenv)->DeleteLocalRef(jenv, outBB); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* create jintArray to hold outSz, since we need to use it as * an OUTPUT parameter from Java. Only needs to have 1 element */ j_outSz = (*jenv)->NewIntArray(jenv, 1); if (!j_outSz) { (*jenv)->ThrowNew(jenv, excClass, "Failed to create result intArray in RsaSignCb"); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, inBB); (*jenv)->DeleteLocalRef(jenv, outBB); (*jenv)->DeleteLocalRef(jenv, keyDerBB); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* copy outSz into j_outSz */ (*jenv)->SetIntArrayRegion(jenv, j_outSz, 0, 1, (jint*)outSz); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); (*jenv)->ThrowNew(jenv, excClass, "Failed to set j_outSz intArray in RsaSignCb"); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, inBB); (*jenv)->DeleteLocalRef(jenv, outBB); (*jenv)->DeleteLocalRef(jenv, keyDerBB); (*jenv)->DeleteLocalRef(jenv, j_outSz); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* call Java RSA sign callback, java layer handles * adding CTX reference */ retval = (*jenv)->CallIntMethod(jenv, ctxRef, rsaSignMethodId, (jobject)(*g_cachedSSLObj), inBB, (jlong)inSz, outBB, j_outSz, keyDerBB, (jlong)keySz); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, inBB); (*jenv)->DeleteLocalRef(jenv, outBB); (*jenv)->DeleteLocalRef(jenv, keyDerBB); (*jenv)->DeleteLocalRef(jenv, j_outSz); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); } if (retval == 0) { /* copy j_outSz into outSz */ (*jenv)->GetIntArrayRegion(jenv, j_outSz, 0, 1, &tmpVal); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, inBB); (*jenv)->DeleteLocalRef(jenv, outBB); (*jenv)->DeleteLocalRef(jenv, keyDerBB); (*jenv)->DeleteLocalRef(jenv, j_outSz); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } *outSz = tmpVal; } /* delete local refs */ (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, inBB); (*jenv)->DeleteLocalRef(jenv, outBB); (*jenv)->DeleteLocalRef(jenv, keyDerBB); (*jenv)->DeleteLocalRef(jenv, j_outSz); /* detach JNIEnv from thread */ if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return retval; } #endif /* HAVE_PK_CALLBACKS */ JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLContext_setRsaVerifyCb (JNIEnv* jenv, jobject jcl, jlong ctxPtr) { WOLFSSL_CTX* ctx = (WOLFSSL_CTX*)(uintptr_t)ctxPtr; jclass excClass = NULL; (void)jcl; /* find exception class */ excClass = (*jenv)->FindClass(jenv, "com/wolfssl/WolfSSLJNIException"); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); return; } #if defined(HAVE_PK_CALLBACKS) && !defined(NO_RSA) if(ctx != NULL) { /* set RSA verify callback */ wolfSSL_CTX_SetRsaVerifyCb(ctx, NativeRsaVerifyCb); } else { (*jenv)->ThrowNew(jenv, excClass, "Input WolfSSLContext object was null when setting " "RsaVerifyCb"); } #else (void)ctx; (*jenv)->ThrowNew(jenv, excClass, "wolfSSL not compiled with PK Callback and/or RSA support"); #endif } #if defined(HAVE_PK_CALLBACKS) && !defined(NO_RSA) int NativeRsaVerifyCb(WOLFSSL* ssl, unsigned char* sig, unsigned int sigSz, unsigned char** out, const unsigned char* keyDer, unsigned int keySz, void* ctx) { jint retval = 0; jint vmret = 0; JNIEnv* jenv; /* JNI Environment */ jclass excClass; /* WolfSSLJNIException class */ int needsDetach = 0; /* Should we explicitly detach? */ static jobject* g_cachedSSLObj; /* WolfSSLSession cached object */ jclass sessClass; /* WolfSSLSession class */ jfieldID ctxFid; /* WolfSSLSession->ctx FieldID */ jmethodID getCtxMethodId; /* WolfSSLSession->getAssCtxPtr() ID */ jobject ctxRef; /* WolfSSLContext object */ jclass innerCtxClass; /* WolfSSLContext class */ jmethodID rsaVerifyMethodId; jobject sigBB = NULL; jobject outBB = NULL; jobject keyDerBB = NULL; (void)ctx; if (!g_vm || !ssl || !sig || !out || !keyDer) return -1; /* get JavaEnv from JavaVM */ vmret = (int)((*g_vm)->GetEnv(g_vm, (void**) &jenv, JNI_VERSION_1_6)); if (vmret == JNI_EDETACHED) { #ifdef __ANDROID__ vmret = (*g_vm)->AttachCurrentThread(g_vm, &jenv, NULL); #else vmret = (*g_vm)->AttachCurrentThread(g_vm, (void**) &jenv, NULL); #endif if (vmret) { return -1; } needsDetach = 1; } else if (vmret != JNI_OK) { return -1; } /* find exception class in case we need it */ excClass = (*jenv)->FindClass(jenv, "com/wolfssl/WolfSSLJNIException"); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* get stored WolfSSLSession jobject */ g_cachedSSLObj = (jobject*) wolfSSL_get_jobject((WOLFSSL*)ssl); if (!g_cachedSSLObj) { (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLSession object reference in " "NativeRsaVerifyCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* lookup WolfSSLSession class from object */ sessClass = (*jenv)->GetObjectClass(jenv, (jobject)(*g_cachedSSLObj)); if (!sessClass) { (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLSession class reference in " "NativeRsaVerifyCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* lookup WolfSSLContext private member fieldID */ ctxFid = (*jenv)->GetFieldID(jenv, sessClass, "ctx", "Lcom/wolfssl/WolfSSLContext;"); if (!ctxFid) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLContext field ID " "in NativeRsaVerifyCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* find getContextPtr() method */ getCtxMethodId = (*jenv)->GetMethodID(jenv, sessClass, "getAssociatedContextPtr", "()Lcom/wolfssl/WolfSSLContext;"); if (!getCtxMethodId) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Can't get getAssociatedContextPtr() method ID " "in NativeRsaVerifyCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* get WolfSSLContext ctx object from Java land */ ctxRef = (*jenv)->CallObjectMethod(jenv, (jobject)(*g_cachedSSLObj), getCtxMethodId); CheckException(jenv); if (!ctxRef) { (*jenv)->ThrowNew(jenv, excClass, "Can't get WolfSSLContext object in NativeRsaVerifyCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* get WolfSSLContext class reference from Java land */ innerCtxClass = (*jenv)->GetObjectClass(jenv, ctxRef); if (!innerCtxClass) { (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLContext class reference " "in NativeRsaVerifyCb"); (*jenv)->DeleteLocalRef(jenv, ctxRef); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* call internal RSA verify callback */ rsaVerifyMethodId = (*jenv)->GetMethodID(jenv, innerCtxClass, "internalRsaVerifyCallback", "(Lcom/wolfssl/WolfSSLSession;Ljava/nio/ByteBuffer;" "JLjava/nio/ByteBuffer;JLjava/nio/ByteBuffer;J)I"); if (!rsaVerifyMethodId) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Error getting internalRsaVerifyCallback method from JNI"); (*jenv)->DeleteLocalRef(jenv, ctxRef); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* create ByteBuffer to wrap 'sig' */ sigBB = (*jenv)->NewDirectByteBuffer(jenv, sig, sigSz); if (!sigBB) { (*jenv)->ThrowNew(jenv, excClass, "Failed to create rsaVerify sig ByteBuffer"); (*jenv)->DeleteLocalRef(jenv, ctxRef); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* create ByteBuffer to wrap 'out', since we're actually * doing this inline, outBB points to the same address as * sigBB */ outBB = (*jenv)->NewDirectByteBuffer(jenv, sig, sigSz); if (!outBB) { (*jenv)->ThrowNew(jenv, excClass, "Failed to create rsaVerify out ByteBuffer"); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, sigBB); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* create ByteBuffer to wrap 'keyDer' */ keyDerBB = (*jenv)->NewDirectByteBuffer(jenv, (void*)keyDer, keySz); if (!keyDerBB) { (*jenv)->ThrowNew(jenv, excClass, "Failed to create rsaVerify keyDer ByteBuffer"); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, sigBB); (*jenv)->DeleteLocalRef(jenv, outBB); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* call Java RSA verify callback, java layer handles * adding CTX reference */ retval = (*jenv)->CallIntMethod(jenv, ctxRef, rsaVerifyMethodId, (jobject)(*g_cachedSSLObj), sigBB, (jlong)sigSz, outBB, (jlong)sigSz, keyDerBB, (jlong)keySz); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } /* point out* to the beginning of our decrypted buffer */ if (retval > 0) *out = sig; /* delete local refs */ (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, sigBB); (*jenv)->DeleteLocalRef(jenv, outBB); (*jenv)->DeleteLocalRef(jenv, keyDerBB); /* detach JNIEnv from thread */ (*g_vm)->DetachCurrentThread(g_vm); return retval; } #endif /* HAVE_PK_CALLBACKS */ JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLContext_setRsaEncCb (JNIEnv* jenv, jobject jcl, jlong ctxPtr) { WOLFSSL_CTX* ctx = (WOLFSSL_CTX*)(uintptr_t)ctxPtr; jclass excClass = NULL; (void)jcl; /* find exception class */ excClass = (*jenv)->FindClass(jenv, "com/wolfssl/WolfSSLJNIException"); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); return; } #if defined(HAVE_PK_CALLBACKS) && !defined(NO_RSA) if(ctx != NULL) { /* set RSA encrypt callback */ wolfSSL_CTX_SetRsaEncCb(ctx, NativeRsaEncCb); } else { (*jenv)->ThrowNew(jenv, excClass, "Input WolfSSLContext object was null when setting " "RsaEncCb"); } #else (void)ctx; (*jenv)->ThrowNew(jenv, excClass, "wolfSSL not compiled with PK Callback and/or RSA support"); #endif } #if defined(HAVE_PK_CALLBACKS) && !defined(NO_RSA) int NativeRsaEncCb(WOLFSSL* ssl, const unsigned char* in, unsigned int inSz, unsigned char* out, unsigned int* outSz, const unsigned char* keyDer, unsigned int keySz, void* ctx) { jint retval = 0; jint vmret = 0; JNIEnv* jenv; /* JNI Environment */ jclass excClass; /* WolfSSLJNIException class */ int needsDetach = 0; /* Should we explicitly detach? */ static jobject* g_cachedSSLObj; /* WolfSSLSession cached object */ jclass sessClass; /* WolfSSLSession class */ jfieldID ctxFid; /* WolfSSLSession->ctx FieldID */ jmethodID getCtxMethodId; /* WolfSSLSession->getAssCtxPtr() ID */ jobject ctxRef; /* WolfSSLContext object */ jclass innerCtxClass; /* WolfSSLContext class */ jmethodID rsaEncMethodId; jintArray j_outSz; jobject inBB = NULL; jobject outBB = NULL; jobject keyDerBB = NULL; jint tmpVal = 0; (void)ctx; if (!g_vm || !ssl || !in || !out || !outSz || !keyDer) return -1; /* get JavaEnv from JavaVM */ vmret = (int)((*g_vm)->GetEnv(g_vm, (void**) &jenv, JNI_VERSION_1_6)); if (vmret == JNI_EDETACHED) { #ifdef __ANDROID__ vmret = (*g_vm)->AttachCurrentThread(g_vm, &jenv, NULL); #else vmret = (*g_vm)->AttachCurrentThread(g_vm, (void**) &jenv, NULL); #endif if (vmret) { return -1; } needsDetach = 1; } else if (vmret != JNI_OK) { return -1; } /* find exception class in case we need it */ excClass = (*jenv)->FindClass(jenv, "com/wolfssl/WolfSSLJNIException"); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* get stored WolfSSLSession jobject */ g_cachedSSLObj = (jobject*) wolfSSL_get_jobject((WOLFSSL*)ssl); if (!g_cachedSSLObj) { (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLSession object reference in " "NativeRsaEncCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* lookup WolfSSLSession class from object */ sessClass = (*jenv)->GetObjectClass(jenv, (jobject)(*g_cachedSSLObj)); if (!sessClass) { (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLSession class reference in " "NativeRsaEncCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* lookup WolfSSLContext private member fieldID */ ctxFid = (*jenv)->GetFieldID(jenv, sessClass, "ctx", "Lcom/wolfssl/WolfSSLContext;"); if (!ctxFid) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLContext field ID " "in NativeRsaEncCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* find getContextPtr() method */ getCtxMethodId = (*jenv)->GetMethodID(jenv, sessClass, "getAssociatedContextPtr", "()Lcom/wolfssl/WolfSSLContext;"); if (!getCtxMethodId) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Can't get getAssociatedContextPtr() method ID " "in NativeRsaEncCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* get WolfSSLContext ctx object from Java land */ ctxRef = (*jenv)->CallObjectMethod(jenv, (jobject)(*g_cachedSSLObj), getCtxMethodId); CheckException(jenv); if (!ctxRef) { (*jenv)->ThrowNew(jenv, excClass, "Can't get WolfSSLContext object in NativeRsaEncCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* get WolfSSLContext class reference from Java land */ innerCtxClass = (*jenv)->GetObjectClass(jenv, ctxRef); if (!innerCtxClass) { (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLContext class reference " "in NativeRsaEncCb"); (*jenv)->DeleteLocalRef(jenv, ctxRef); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* call internal RSA enc callback */ rsaEncMethodId = (*jenv)->GetMethodID(jenv, innerCtxClass, "internalRsaEncCallback", "(Lcom/wolfssl/WolfSSLSession;Ljava/nio/ByteBuffer;" "JLjava/nio/ByteBuffer;[ILjava/nio/ByteBuffer;J)I"); if (!rsaEncMethodId) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Error getting internalRsaEncCallback method from JNI"); (*jenv)->DeleteLocalRef(jenv, ctxRef); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* create ByteBuffer to wrap 'in' */ inBB = (*jenv)->NewDirectByteBuffer(jenv, (void*)in, inSz); if (!inBB) { (*jenv)->ThrowNew(jenv, excClass, "Failed to create rsaEnc in ByteBuffer"); (*jenv)->DeleteLocalRef(jenv, ctxRef); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* create ByteBuffer to wrap 'out' */ outBB = (*jenv)->NewDirectByteBuffer(jenv, (void*)out, *outSz); if (!outBB) { (*jenv)->ThrowNew(jenv, excClass, "Failed to create rsaEnc out ByteBuffer"); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, inBB); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* create ByteBuffer to wrap 'keyDer' */ keyDerBB = (*jenv)->NewDirectByteBuffer(jenv, (void*)keyDer, keySz); if (!keyDerBB) { (*jenv)->ThrowNew(jenv, excClass, "Failed to create rsaEnc keyDer ByteBuffer"); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, inBB); (*jenv)->DeleteLocalRef(jenv, outBB); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* create jintArray to hold outSz, since we need to use it as * an OUTPUT parameter from Java. Only needs to have 1 element */ j_outSz = (*jenv)->NewIntArray(jenv, 1); if (!j_outSz) { (*jenv)->ThrowNew(jenv, excClass, "Failed to create result intArray in RsaEncCb"); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, inBB); (*jenv)->DeleteLocalRef(jenv, outBB); (*jenv)->DeleteLocalRef(jenv, keyDerBB); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* copy outSz into j_outSz */ (*jenv)->SetIntArrayRegion(jenv, j_outSz, 0, 1, (jint*)outSz); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); (*jenv)->ThrowNew(jenv, excClass, "Failed to set j_outSz intArray in RsaEncCb"); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, inBB); (*jenv)->DeleteLocalRef(jenv, outBB); (*jenv)->DeleteLocalRef(jenv, keyDerBB); (*jenv)->DeleteLocalRef(jenv, j_outSz); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* call Java RSA enc callback, java layer handles * adding CTX reference */ retval = (*jenv)->CallIntMethod(jenv, ctxRef, rsaEncMethodId, (jobject)(*g_cachedSSLObj), inBB, (jlong)inSz, outBB, j_outSz, keyDerBB, (jlong)keySz); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } if (retval == 0) { /* copy j_outSz into outSz */ (*jenv)->GetIntArrayRegion(jenv, j_outSz, 0, 1, &tmpVal); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, inBB); (*jenv)->DeleteLocalRef(jenv, outBB); (*jenv)->DeleteLocalRef(jenv, keyDerBB); (*jenv)->DeleteLocalRef(jenv, j_outSz); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } *outSz = tmpVal; } /* delete local refs */ (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, inBB); (*jenv)->DeleteLocalRef(jenv, outBB); (*jenv)->DeleteLocalRef(jenv, keyDerBB); (*jenv)->DeleteLocalRef(jenv, j_outSz); /* detach JNIEnv from thread */ if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return retval; } #endif /* HAVE_PK_CALLBACKS */ JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLContext_setRsaDecCb (JNIEnv* jenv, jobject jcl, jlong ctxPtr) { WOLFSSL_CTX* ctx = (WOLFSSL_CTX*)(uintptr_t)ctxPtr; jclass excClass = NULL; (void)jcl; /* find exception class */ excClass = (*jenv)->FindClass(jenv, "com/wolfssl/WolfSSLJNIException"); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); return; } #if defined(HAVE_PK_CALLBACKS) && !defined(NO_RSA) if(ctx != NULL) { /* set RSA encrypt callback */ wolfSSL_CTX_SetRsaDecCb(ctx, NativeRsaDecCb); } else { (*jenv)->ThrowNew(jenv, excClass, "Input WolfSSLContext object was null when setting " "RsaDecCb"); } #else (void)ctx; (*jenv)->ThrowNew(jenv, excClass, "wolfSSL not compiled with PK Callback and/or RSA support"); #endif } #if defined(HAVE_PK_CALLBACKS) && !defined(NO_RSA) int NativeRsaDecCb(WOLFSSL* ssl, unsigned char* in, unsigned int inSz, unsigned char** out, const unsigned char* keyDer, unsigned int keySz, void* ctx) { jint retval = 0; jint vmret = 0; JNIEnv* jenv; /* JNI Environment */ jclass excClass; /* WolfSSLJNIException class */ int needsDetach = 0; /* Should we explicitly detach? */ static jobject* g_cachedSSLObj; /* WolfSSLSession cached object */ jclass sessClass; /* WolfSSLSession class */ jfieldID ctxFid; /* WolfSSLSession->ctx FieldID */ jmethodID getCtxMethodId; /* WolfSSLSession->getAssCtxPtr() ID */ jobject ctxRef; /* WolfSSLContext object */ jclass innerCtxClass; /* WolfSSLContext class */ jmethodID rsaDecMethodId; jobject inBB = NULL; jobject outBB = NULL; jobject keyDerBB = NULL; (void)ctx; if (!g_vm || !ssl || !in || !out || !keyDer) return -1; /* get JavaEnv from JavaVM */ vmret = (int)((*g_vm)->GetEnv(g_vm, (void**) &jenv, JNI_VERSION_1_6)); if (vmret == JNI_EDETACHED) { #ifdef __ANDROID__ vmret = (*g_vm)->AttachCurrentThread(g_vm, &jenv, NULL); #else vmret = (*g_vm)->AttachCurrentThread(g_vm, (void**) &jenv, NULL); #endif if (vmret) { return -1; } needsDetach = 1; } else if (vmret != JNI_OK) { return -1; } /* find exception class in case we need it */ excClass = (*jenv)->FindClass(jenv, "com/wolfssl/WolfSSLJNIException"); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* get stored WolfSSLSession jobject */ g_cachedSSLObj = (jobject*) wolfSSL_get_jobject((WOLFSSL*)ssl); if (!g_cachedSSLObj) { (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLSession object reference in " "NativeRsaDecCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* lookup WolfSSLSession class from object */ sessClass = (*jenv)->GetObjectClass(jenv, (jobject)(*g_cachedSSLObj)); if (!sessClass) { (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLSession class reference in " "NativeRsaDecCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* lookup WolfSSLContext private member fieldID */ ctxFid = (*jenv)->GetFieldID(jenv, sessClass, "ctx", "Lcom/wolfssl/WolfSSLContext;"); if (!ctxFid) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLContext field ID " "in NativeRsaDecCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* find getContextPtr() method */ getCtxMethodId = (*jenv)->GetMethodID(jenv, sessClass, "getAssociatedContextPtr", "()Lcom/wolfssl/WolfSSLContext;"); if (!getCtxMethodId) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Can't get getAssociatedContextPtr() method ID " "in NativeRsaDecCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* get WolfSSLContext ctx object from Java land */ ctxRef = (*jenv)->CallObjectMethod(jenv, (jobject)(*g_cachedSSLObj), getCtxMethodId); CheckException(jenv); if (!ctxRef) { (*jenv)->ThrowNew(jenv, excClass, "Can't get WolfSSLContext object in NativeRsaDecCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* get WolfSSLContext class reference from Java land */ innerCtxClass = (*jenv)->GetObjectClass(jenv, ctxRef); if (!innerCtxClass) { (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLContext class reference " "in NativeRsaDecCb"); (*jenv)->DeleteLocalRef(jenv, ctxRef); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* call internal ECC verify callback */ rsaDecMethodId = (*jenv)->GetMethodID(jenv, innerCtxClass, "internalRsaDecCallback", "(Lcom/wolfssl/WolfSSLSession;Ljava/nio/ByteBuffer;" "JLjava/nio/ByteBuffer;JLjava/nio/ByteBuffer;J)I"); if (!rsaDecMethodId) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Error getting internalRsaDecCallback method from JNI"); (*jenv)->DeleteLocalRef(jenv, ctxRef); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* create ByteBuffer to wrap 'in' */ inBB = (*jenv)->NewDirectByteBuffer(jenv, in, inSz); if (!inBB) { (*jenv)->ThrowNew(jenv, excClass, "Failed to create rsaDec in ByteBuffer"); (*jenv)->DeleteLocalRef(jenv, ctxRef); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* create ByteBuffer to wrap 'out', since we're actually * doing this inline, outBB points to the same address as * inBB */ outBB = (*jenv)->NewDirectByteBuffer(jenv, in, inSz); if (!outBB) { (*jenv)->ThrowNew(jenv, excClass, "Failed to create rsaDec out ByteBuffer"); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, inBB); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* create ByteBuffer to wrap 'keyDer' */ keyDerBB = (*jenv)->NewDirectByteBuffer(jenv, (void*)keyDer, keySz); if (!keyDerBB) { (*jenv)->ThrowNew(jenv, excClass, "Failed to create rsaDec keyDer ByteBuffer"); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, inBB); (*jenv)->DeleteLocalRef(jenv, outBB); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return -1; } /* call Java RSA decrypt callback, java layer handles * adding CTX reference */ retval = (*jenv)->CallIntMethod(jenv, ctxRef, rsaDecMethodId, (jobject)(*g_cachedSSLObj), inBB, (jlong)inSz, outBB, (jlong)inSz, keyDerBB, (jlong)keySz); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, inBB); (*jenv)->DeleteLocalRef(jenv, outBB); (*jenv)->DeleteLocalRef(jenv, keyDerBB); retval = -1; } /* point out* to the beginning of our decrypted buffer */ if (retval > 0) *out = in; /* delete local refs */ (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, inBB); (*jenv)->DeleteLocalRef(jenv, outBB); (*jenv)->DeleteLocalRef(jenv, keyDerBB); /* detach JNIEnv from thread */ if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return retval; } #endif /* HAVE_PK_CALLBAKCS */ JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLContext_setPskClientCb (JNIEnv* jenv, jobject jcl, jlong ctxPtr) { WOLFSSL_CTX* ctx = (WOLFSSL_CTX*)(uintptr_t)ctxPtr; jclass excClass = NULL; (void)jcl; /* find exception class */ excClass = (*jenv)->FindClass(jenv, "com/wolfssl/WolfSSLJNIException"); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); return; } #ifndef NO_PSK if (ctx != NULL) { /* set PSK client callback */ wolfSSL_CTX_set_psk_client_callback(ctx, NativePskClientCb); } else { (*jenv)->ThrowNew(jenv, excClass, "Input WolfSSLContext object was null when setting " "NativePskClientCb"); } #else (void)ctx; (*jenv)->ThrowNew(jenv, excClass, "wolfSSL not compiled with PSK support"); #endif } #ifndef NO_PSK unsigned int NativePskClientCb(WOLFSSL* ssl, const char* hint, char* identity, unsigned int id_max_len, unsigned char* key, unsigned int max_key_len) { jint vmret = 0; jlong retval = 0; int usingSSLCallback = 0; int needsDetach = 0; /* Should we explicitly detach? */ JNIEnv* jenv; /* JNI environment */ jclass excClass; /* class: WolfSSLJNIException */ static jobject* g_cachedSSLObj; /* WolfSSLSession cached object */ jclass sessClass; /* WolfSSLSession class */ jfieldID ctxFid; /* WolfSSLSession->ctx fieldID */ jmethodID getCtxMethodId; /* WolfSSLSession->getAssCtxPtr() ID */ jfieldID internPskClientCbFid; /* WolfSSLContext->internPskClientCb ID */ jobject internPskClientCbObj; /* " ->internPskClientCb object */ jobject ctxRef; /* WolfSSLContext object */ jclass innerCtxClass; /* WolfSSLContext class */ jmethodID pskClientMethodId; /* internalPskClientCallback ID */ jstring hintString; /* String, for 'hint' */ jclass strBufClass; /* StringBuffer class for 'identity' */ jmethodID strBufMethodId; /* StringBuffer constructor ID */ jobject strBufObj; /* StringBuffer object */ jbyteArray keyArray; /* byte[] for key in/out */ jmethodID toStringId; /* StringBuffer.toString() ID */ jstring bufString; /* StringBuffer.toString() result */ const char* tmpString; /* tmp output char* for String out */ /* Note: since this is called from C, not the JVM, we need to explicitly * free all object refs with DeleteLocalRef() */ if (!g_vm || !ssl || !hint || !identity || !key) { /* we can't throw an exception yet, so just return 0 (failure) */ return 0; } /* get JavaEnv from JavaVM */ vmret = (int)((*g_vm)->GetEnv(g_vm, (void**) &jenv, JNI_VERSION_1_6)); if (vmret == JNI_EDETACHED) { #ifdef __ANDROID__ vmret = (*g_vm)->AttachCurrentThread(g_vm, &jenv, NULL); #else vmret = (*g_vm)->AttachCurrentThread(g_vm, (void**) &jenv, NULL); #endif if (vmret) { return 0; } needsDetach = 1; } else if (vmret != JNI_OK) { return 0; } /* find exception class */ excClass = (*jenv)->FindClass(jenv, "com/wolfssl/WolfSSLJNIException"); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return 0; } /* get stored WolfSSLSession jobject */ g_cachedSSLObj = (jobject*) wolfSSL_get_jobject((WOLFSSL*)ssl); if (!g_cachedSSLObj) { (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLSession object reference in " "NativePskClientCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return 0; } /* lookup WolfSSLSession class from object */ sessClass = (*jenv)->GetObjectClass(jenv, (jobject)(*g_cachedSSLObj)); if (!sessClass) { (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLSession class reference in " "NativePskClientCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return 0; } /* lookup WolfSSLContext private member fieldID */ ctxFid = (*jenv)->GetFieldID(jenv, sessClass, "ctx", "Lcom/wolfssl/WolfSSLContext;"); if (!ctxFid) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLContext field ID in " "NativePSKClientCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return 0; } /* find WolfSSLSession.getAssociatedContextPtr() method */ getCtxMethodId = (*jenv)->GetMethodID(jenv, sessClass, "getAssociatedContextPtr", "()Lcom/wolfssl/WolfSSLContext;"); if (!getCtxMethodId) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Can't get getAssociatedContextPtr() method ID in " "NativePSKClientCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return 0; } /* get WolfSSLContext(ctx) object from Java WolfSSLSession object */ ctxRef = (*jenv)->CallObjectMethod(jenv, (jobject)(*g_cachedSSLObj), getCtxMethodId); CheckException(jenv); if (!ctxRef) { (*jenv)->ThrowNew(jenv, excClass, "Can't get WolfSSLContext object in NativePskClientCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return 0; } /* get WolfSSLContext class reference from object */ innerCtxClass = (*jenv)->GetObjectClass(jenv, ctxRef); if (!innerCtxClass) { (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLContext class reference in " "NativePskClientCb"); (*jenv)->DeleteLocalRef(jenv, ctxRef); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return 0; } /* figure out if we need to call the CTX or SSL level callback */ /* 1. Get internPskClientCb FieldID */ internPskClientCbFid = (*jenv)->GetFieldID(jenv, innerCtxClass, "internPskClientCb", "Lcom/wolfssl/WolfSSLPskClientCallback;"); if (!internPskClientCbFid) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Can't get native internPskClientCb field ID in " "NativePSKClientCb"); (*jenv)->DeleteLocalRef(jenv, ctxRef); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return 0; } /* 2. Get WolfSSLPskClientCallback object (or null) */ internPskClientCbObj = (*jenv)->GetObjectField(jenv, ctxRef, internPskClientCbFid); if (!internPskClientCbObj) { printf("Using SSL level PSK Client callback!!!\n"); usingSSLCallback = 1; } if (usingSSLCallback == 1) { /* WolfSSLSession level callback */ pskClientMethodId = (*jenv)->GetMethodID(jenv, sessClass, "internalPskClientCallback", "(Lcom/wolfssl/WolfSSLSession;Ljava/lang/String;" "Ljava/lang/StringBuffer;J[BJ)J"); } else { /* WolfSSLContext level callback */ pskClientMethodId = (*jenv)->GetMethodID(jenv, innerCtxClass, "internalPskClientCallback", "(Lcom/wolfssl/WolfSSLSession;Ljava/lang/String;" "Ljava/lang/StringBuffer;J[BJ)J"); } if (!pskClientMethodId) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Error getting internalPskClientCallback method from JNI"); (*jenv)->DeleteLocalRef(jenv, ctxRef); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return 0; } /* create String to wrap 'hint' */ hintString = (*jenv)->NewStringUTF(jenv, hint); if (!hintString) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Error creating String for PSK client hint"); (*jenv)->DeleteLocalRef(jenv, ctxRef); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return 0; } /* find StringBuffer class to wrap 'identity' */ strBufClass = (*jenv)->FindClass(jenv, "java/lang/StringBuffer"); if (!strBufClass) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Error finding StringBuffer class for PSK client identity"); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, hintString); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return 0; } /* find StringBuffer Constructor */ strBufMethodId = (*jenv)->GetMethodID(jenv, strBufClass, "", "()V"); if (!strBufMethodId) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Can't get StringBuffer constructor method ID " "in NativePskClientCb"); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, hintString); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return 0; } /* create new StringBuffer object */ strBufObj = (*jenv)->NewObject(jenv, strBufClass, strBufMethodId); if (!strBufObj) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Can't get StringBuffer object in NativePskClientCb"); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, hintString); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return 0; } /* create jbyteArray to hold received key */ keyArray = (*jenv)->NewByteArray(jenv, max_key_len); if (!keyArray) { (*jenv)->ThrowNew(jenv, excClass, "Error creating jbyteArray for PSK client key"); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, hintString); (*jenv)->DeleteLocalRef(jenv, strBufObj); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return 0; } /* call Java PSK client callback */ if (usingSSLCallback == 1) { /* call WolfSSLSession level callback */ retval = (*jenv)->CallLongMethod(jenv, (jobject)(*g_cachedSSLObj), pskClientMethodId, (jobject)(*g_cachedSSLObj), hintString, strBufObj, (jlong)id_max_len, keyArray, (jlong)max_key_len); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, hintString); (*jenv)->DeleteLocalRef(jenv, strBufObj); (*jenv)->DeleteLocalRef(jenv, keyArray); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return 0; } } else { /* call WolfSSLContext level callback */ retval = (*jenv)->CallLongMethod(jenv, ctxRef, pskClientMethodId, (jobject)(*g_cachedSSLObj), hintString, strBufObj, (jlong)id_max_len, keyArray, (jlong)max_key_len); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, hintString); (*jenv)->DeleteLocalRef(jenv, strBufObj); (*jenv)->DeleteLocalRef(jenv, keyArray); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return 0; } } if (retval > 0) { /* copy jbyteArray into char key array */ (*jenv)->GetByteArrayRegion(jenv, keyArray, 0, retval, (jbyte*)key); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, hintString); (*jenv)->DeleteLocalRef(jenv, strBufObj); (*jenv)->DeleteLocalRef(jenv, keyArray); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return 0; } /* get the String from the StringBuffer */ toStringId = (*jenv)->GetMethodID(jenv, strBufClass, "toString", "()Ljava/lang/String;"); if (!toStringId) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Error getting String ID from StringBuffer in PSK CB"); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, hintString); (*jenv)->DeleteLocalRef(jenv, strBufObj); (*jenv)->DeleteLocalRef(jenv, keyArray); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return 0; } bufString = (jstring) (*jenv)->CallObjectMethod(jenv, strBufObj, toStringId); CheckException(jenv); if (!bufString) { (*jenv)->ThrowNew(jenv, excClass, "Error getting String from StringBuffer in PSK CB"); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, hintString); (*jenv)->DeleteLocalRef(jenv, strBufObj); (*jenv)->DeleteLocalRef(jenv, keyArray); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return 0; } /* convert string to C string (char*) */ tmpString = (*jenv)->GetStringUTFChars(jenv, bufString, 0); if (!tmpString) { (*jenv)->ThrowNew(jenv, excClass, "Error with GetStringUTFChars in PSK Client CB"); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, hintString); (*jenv)->DeleteLocalRef(jenv, strBufObj); (*jenv)->DeleteLocalRef(jenv, keyArray); (*jenv)->DeleteLocalRef(jenv, bufString); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return 0; } strcpy(identity, tmpString); (*jenv)->ReleaseStringUTFChars(jenv, bufString, tmpString); (*jenv)->DeleteLocalRef(jenv, bufString); } /* delete local obj refs, detach JNIEnv from thread */ (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, hintString); (*jenv)->DeleteLocalRef(jenv, strBufObj); (*jenv)->DeleteLocalRef(jenv, keyArray); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return retval; } #endif /* NO_PSK */ JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLContext_setPskServerCb (JNIEnv* jenv, jobject jcl, jlong ctxPtr) { WOLFSSL_CTX* ctx = (WOLFSSL_CTX*)(uintptr_t)ctxPtr; jclass excClass = NULL; (void)jcl; /* find exception class */ excClass = (*jenv)->FindClass(jenv, "com/wolfssl/WolfSSLJNIException"); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); return; } #ifndef NO_PSK if (ctx != NULL) { /* set PSK server callback */ wolfSSL_CTX_set_psk_server_callback(ctx, NativePskServerCb); } else { (*jenv)->ThrowNew(jenv, excClass, "Input WolfSSLContext object was null when setting " "NativePskServerCb"); } #else (void)ctx; (*jenv)->ThrowNew(jenv, excClass, "wolfSSL not compiled with PSK support"); #endif } #ifndef NO_PSK unsigned int NativePskServerCb(WOLFSSL* ssl, const char* identity, unsigned char* key, unsigned int max_key_len) { jint vmret = 0; jlong retval = 0; int usingSSLCallback = 0; int needsDetach = 0; /* Should we explicitly detach? */ JNIEnv* jenv; /* JNI environment */ jclass excClass; /* class: WolfSSLJNIException */ static jobject* g_cachedSSLObj; /* WolfSSLSession cached object */ jclass sessClass; /* WolfSSLSession class */ jfieldID ctxFid; /* WolfSSLSession->ctx fieldID */ jmethodID getCtxMethodId; /* WolfSSLSession->getAssCtxPtr() ID */ jfieldID internPskServerCbFid; /* WolfSSLContext->internPskServerCb ID */ jobject internPskServerCbObj; /* " -> internPskServerCb object */ jobject ctxRef; /* WolfSSLContext object */ jclass innerCtxClass; /* WolfSSLContext class */ jmethodID pskServerMethodId; /* internalPskServerCallback ID */ jstring identityString; /* String, for 'hint' */ jbyteArray keyArray; /* byte[] for key in/out */ /* Note: since this is called from C, not the JVM, we need to explicitly * free all object refs with DeleteLocalRef() */ if (!g_vm || !ssl || !identity || !key) { /* we can't throw an exception yet, so just return 0 (failure) */ return 0; } /* get JavaEnv from JavaVM */ vmret = (int)((*g_vm)->GetEnv(g_vm, (void**) &jenv, JNI_VERSION_1_6)); if (vmret == JNI_EDETACHED) { #ifdef __ANDROID__ vmret = (*g_vm)->AttachCurrentThread(g_vm, &jenv, NULL); #else vmret = (*g_vm)->AttachCurrentThread(g_vm, (void**) &jenv, NULL); #endif if (vmret) { return 0; } needsDetach = 1; } else if (vmret != JNI_OK) { return 0; } /* find exception class */ excClass = (*jenv)->FindClass(jenv, "com/wolfssl/WolfSSLJNIException"); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return 0; } /* get stored WolfSSLSession jobject */ g_cachedSSLObj = (jobject*) wolfSSL_get_jobject((WOLFSSL*)ssl); if (!g_cachedSSLObj) { (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLSession object reference in " "NativePskServerCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return 0; } /* lookup WolfSSLSession class from object */ sessClass = (*jenv)->GetObjectClass(jenv, (jobject)(*g_cachedSSLObj)); if (!sessClass) { (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLSession class reference in " "NativePskServerCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return 0; } /* lookup WolfSSLContext private member fieldID */ ctxFid = (*jenv)->GetFieldID(jenv, sessClass, "ctx", "Lcom/wolfssl/WolfSSLContext;"); if (!ctxFid) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLContext field ID in " "NativePSKClientCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return 0; } /* find WolfSSLSession.getAssociatedContextPtr() method */ getCtxMethodId = (*jenv)->GetMethodID(jenv, sessClass, "getAssociatedContextPtr", "()Lcom/wolfssl/WolfSSLContext;"); if (!getCtxMethodId) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Can't get getAssociatedContextPtr() method ID in " "NativePSKClientCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return 0; } /* get WolfSSLContext(ctx) object from Java WolfSSLSession object */ ctxRef = (*jenv)->CallObjectMethod(jenv, (jobject)(*g_cachedSSLObj), getCtxMethodId); CheckException(jenv); if (!ctxRef) { (*jenv)->ThrowNew(jenv, excClass, "Can't get WolfSSLContext object in NativePskServerCb"); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return 0; } /* get WolfSSLContext class reference from object */ innerCtxClass = (*jenv)->GetObjectClass(jenv, ctxRef); if (!innerCtxClass) { (*jenv)->ThrowNew(jenv, excClass, "Can't get native WolfSSLContext class reference in " "NativePskServerCb"); (*jenv)->DeleteLocalRef(jenv, ctxRef); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return 0; } /* figure out if we need to call the CTX or SSL level callback */ /* 1. Get the internPskServerCb FieldID */ internPskServerCbFid = (*jenv)->GetFieldID(jenv, innerCtxClass, "internPskServerCb", "Lcom/wolfssl/WolfSSLPskServerCallback;"); if (!internPskServerCbFid) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Can't get native internPskServerCb field ID in " "NativePskServerCb"); (*jenv)->DeleteLocalRef(jenv, ctxRef); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return 0; } /* 2. Get WolfSSLPskServerCallback object (or null) */ internPskServerCbObj = (*jenv)->GetObjectField(jenv, ctxRef, internPskServerCbFid); if (!internPskServerCbObj) { printf("Using SSL level PSK Server callback!!!\n"); usingSSLCallback = 1; } if (usingSSLCallback == 1) { /* WolfSSLSession level callback */ pskServerMethodId = (*jenv)->GetMethodID(jenv, sessClass, "internalPskServerCallback", "(Lcom/wolfssl/WolfSSLSession;Ljava/lang/String;" "[BJ)J"); } else { /* WolfSSLContext level callback */ pskServerMethodId = (*jenv)->GetMethodID(jenv, innerCtxClass, "internalPskServerCallback", "(Lcom/wolfssl/WolfSSLSession;Ljava/lang/String;" "[BJ)J"); } if (!pskServerMethodId) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Error getting internalPskServerCallback method from JNI"); (*jenv)->DeleteLocalRef(jenv, ctxRef); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return 0; } /* create String to wrap 'identity' */ identityString = (*jenv)->NewStringUTF(jenv, identity); if (!identityString) { if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); } (*jenv)->ThrowNew(jenv, excClass, "Error creating String for PSK client identity"); (*jenv)->DeleteLocalRef(jenv, ctxRef); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return 0; } /* create jbyteArray to hold received key */ keyArray = (*jenv)->NewByteArray(jenv, max_key_len); if (!keyArray) { (*jenv)->ThrowNew(jenv, excClass, "Error creating jbyteArray for PSK server key"); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, identityString); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return 0; } /* call Java PSK server callback */ if (usingSSLCallback == 1) { retval = (*jenv)->CallLongMethod(jenv, (jobject)(*g_cachedSSLObj), pskServerMethodId, (jobject)(*g_cachedSSLObj), identityString, keyArray, (jlong)max_key_len); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, identityString); (*jenv)->DeleteLocalRef(jenv, keyArray); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return 0; } } else { retval = (*jenv)->CallLongMethod(jenv, ctxRef, pskServerMethodId, (jobject)(*g_cachedSSLObj), identityString, keyArray, (jlong)max_key_len); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, identityString); (*jenv)->DeleteLocalRef(jenv, keyArray); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return 0; } } if (retval > 0) { /* copy jbyteArray into char key array */ (*jenv)->GetByteArrayRegion(jenv, keyArray, 0, retval, (jbyte*)key); if ((*jenv)->ExceptionOccurred(jenv)) { (*jenv)->ExceptionDescribe(jenv); (*jenv)->ExceptionClear(jenv); (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, identityString); (*jenv)->DeleteLocalRef(jenv, keyArray); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return 0; } } /* delete local obj refs, detach JNIEnv from thread */ (*jenv)->DeleteLocalRef(jenv, ctxRef); (*jenv)->DeleteLocalRef(jenv, identityString); (*jenv)->DeleteLocalRef(jenv, keyArray); if (needsDetach) (*g_vm)->DetachCurrentThread(g_vm); return retval; } #endif /* NO_PSK */ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLContext_usePskIdentityHint (JNIEnv* jenv, jobject obj, jlong ctxPtr, jstring hint) { #ifndef NO_PSK jint ret; const char* nativeHint; WOLFSSL_CTX* ctx = (WOLFSSL_CTX*)(uintptr_t)ctxPtr; (void)obj; if (jenv == NULL || ctx == NULL || hint == NULL) { return SSL_FAILURE; } nativeHint = (*jenv)->GetStringUTFChars(jenv, hint, 0); ret = (jint)wolfSSL_CTX_use_psk_identity_hint(ctx, nativeHint); (*jenv)->ReleaseStringUTFChars(jenv, hint, nativeHint); return ret; #else (void)jenv; (void)obj; (void)ctxPtr; (void)hint; return NOT_COMPILED_IN; #endif } JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLContext_useSecureRenegotiation (JNIEnv* jenv, jobject jcl, jlong ctx) { (void)jenv; (void)jcl; #ifdef HAVE_SECURE_RENEGOTIATION return (jint)wolfSSL_CTX_UseSecureRenegotiation( (WOLFSSL_CTX*)(uintptr_t)ctx); #else (void)ctx; return NOT_COMPILED_IN; #endif }