wolfssljni/native/com_wolfssl_WolfSSLSession.c

6015 lines
175 KiB
C

/* com_wolfssl_WolfSSLSession.c
*
* Copyright (C) 2006-2025 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 <stdio.h>
#include <stdint.h>
#ifdef WOLFSSL_USER_SETTINGS
#include <wolfssl/wolfcrypt/settings.h>
#else
#include <wolfssl/options.h>
#endif
#ifndef USE_WINDOWS_API
#include <sys/time.h>
#include <arpa/inet.h>
#include <sys/errno.h>
#if defined(WOLFJNI_USE_IO_SELECT)
#include <sys/select.h>
#else
#include <poll.h>
#endif
#endif
#ifndef WOLFSSL_JNI_DEFAULT_PEEK_TIMEOUT
/* Default wolfSSL_peek() timeout for wolfSSL_get_session(), ms */
#define WOLFSSL_JNI_DEFAULT_PEEK_TIMEOUT 2000
#endif
#include <wolfssl/ssl.h>
#include <wolfssl/error-ssl.h>
#include "com_wolfssl_globals.h"
#include "com_wolfssl_WolfSSL.h"
/* custom I/O native fn prototypes */
int NativeSSLIORecvCb(WOLFSSL *ssl, char *buf, int sz, void *ctx);
int NativeSSLIOSendCb(WOLFSSL *ssl, char *buf, int sz, void *ctx);
/* ALPN select native callback prototype */
int NativeALPNSelectCb(WOLFSSL *ssl, const unsigned char **out,
unsigned char *outlen, const unsigned char *in,
unsigned int inlen, void *arg);
/* TLS 1.3 secret native callback prototype */
int NativeTls13SecretCb(WOLFSSL *ssl, int id, const unsigned char* secret,
int secretSz, void* ctx);
#if !defined(NO_WOLFSSL_CLIENT) && defined(HAVE_SESSION_TICKET)
/* Session ticket callback prototype */
int NativeSessionTicketCb(WOLFSSL *ssl, const unsigned char* ticket,
int ticketLen, void* ctx);
#endif
#ifdef HAVE_CRL
/* global object refs for CRL callback */
static jobject g_crlCbIfaceObj;
#endif
/* Data used per-WOLFSSL session that needs to be stored across native
* function calls. Stored inside WOLFSSL app data, set with
* wolfSSL_set_app_data(), retrieved with wolfSSL_get_app_data().
* Global callback objects are created with NewGlobalRef(), then freed
* inside freeSSL() with DeleteGlobalRef().
*
* interruptFds[2] is a pipe() used for non-Windows platforms. This pipe is
* used to interrupt threads blocked inside select()/poll() when a separate
* Java thread calls close() on the SSLSocket. */
typedef struct SSLAppData {
int threadsInPoll; /* number of threads in poll/select() */
#ifndef USE_WINDOWS_API
int interruptFds[2]; /* pipe for interrupting socketSelect() */
wolfSSL_Mutex* pollCountLock; /* lock around threadsInPoll */
#endif
wolfSSL_Mutex* jniSessLock; /* WOLFSSL session lock */
jobject* g_verifySSLCbIfaceObj; /* Java verify callback [global ref] */
} SSLAppData;
/* custom native fn prototypes */
void NativeMissingCRLCallback(const char* url);
int NativeSSLVerifyCallback(int preverify_ok, WOLFSSL_X509_STORE_CTX* store);
int NativeSSLVerifyCallback(int preverify_ok, WOLFSSL_X509_STORE_CTX* store)
{
JNIEnv* jenv;
jint vmret = 0;
jint retval = -1;
jobjectRefType refcheck;
SSLAppData* appData; /* WOLFSSL app data, stored verify cb obj */
jobject* g_verifySSLCbIfaceObj; /* Global jobject, stored in app data */
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 */
}
/* get app data to retrieve stored Java jobject callback object */
appData = (SSLAppData*)wolfSSL_get_app_data(
wolfSSL_X509_STORE_CTX_get_ex_data(store, 0));
if (appData == NULL) {
printf("Error getting app data from WOLFSSL\n");
return -105;
}
/* get global Java verify callback object */
g_verifySSLCbIfaceObj = appData->g_verifySSLCbIfaceObj;
if (g_verifySSLCbIfaceObj == NULL || *g_verifySSLCbIfaceObj == NULL) {
printf("Error getting g_verifySSLCbIfaceObj from appData\n");
return -106;
}
/* check if our stored object reference is valid */
refcheck = (*jenv)->GetObjectRefType(jenv, *g_verifySSLCbIfaceObj);
if (refcheck == 2) {
if (!g_verifyCallbackMethodId) {
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
}
throwWolfSSLJNIException(jenv,
"verifyCallback method ID is null in NativeSSLVerifyCallback");
return -107;
}
retval = (*jenv)->CallIntMethod(jenv, *g_verifySSLCbIfaceObj,
g_verifyCallbackMethodId, 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 -109;
}
} else {
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
}
throwWolfSSLJNIException(jenv,
"Object reference invalid in NativeSSLVerifyCallback");
return -1;
}
return retval;
}
#ifndef USE_WINDOWS_API
/* Close interrupt pipe() descriptors and reset back to -1. */
static void closeInterruptPipe(SSLAppData* appData)
{
if (appData != NULL) {
if (appData->interruptFds[0] != -1) {
close(appData->interruptFds[0]);
appData->interruptFds[0] = -1;
}
if (appData->interruptFds[1] != -1) {
close(appData->interruptFds[1]);
appData->interruptFds[1] = -1;
}
}
}
/* Signal to threads blocked in select() or poll() to wake up, by writing
* one byte to the appData.interruptFds[1] pipe. */
static void writeToInterruptPipe(SSLAppData* appData)
{
if (appData != NULL) {
if (appData->interruptFds[1] != -1) {
write(appData->interruptFds[1], "1", 1);
}
}
}
#endif /* !USE_WINDOWS_API */
/* Return number of threads waiting in poll()/select() */
static int threadsWaitingInPollSelect(SSLAppData* appData)
{
int ret = 0;
#ifndef USE_WINDOWS_API
wolfSSL_Mutex* pollCountLock = NULL;
if (appData != NULL) {
pollCountLock = appData->pollCountLock;
if (pollCountLock != NULL) {
if (wc_LockMutex(pollCountLock) == 0) {
ret = appData->threadsInPoll;
wc_UnLockMutex(pollCountLock);
}
}
}
#endif
return ret;
}
static void incrementThreadPollCount(SSLAppData* appData)
{
#ifndef USE_WINDOWS_API
wolfSSL_Mutex* pollCountLock = NULL;
if (appData == NULL) {
return;
}
pollCountLock = appData->pollCountLock;
if (pollCountLock == NULL) {
return;
}
if (wc_LockMutex(pollCountLock) != 0) {
return;
}
appData->threadsInPoll++;
wc_UnLockMutex(pollCountLock);
#endif
}
static void decrementThreadPollCount(SSLAppData* appData)
{
#ifndef USE_WINDOWS_API
wolfSSL_Mutex* pollCountLock = NULL;
if (appData == NULL) {
return;
}
pollCountLock = appData->pollCountLock;
if (pollCountLock == NULL) {
return;
}
if (wc_LockMutex(pollCountLock) != 0) {
return;
}
if (appData->threadsInPoll > 0) {
appData->threadsInPoll--;
}
wc_UnLockMutex(pollCountLock);
#endif
}
JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLSession_newSSL
(JNIEnv* jenv, jobject jcl, jlong ctx, jboolean withIOPipe)
{
int ret;
jlong sslPtr = 0;
jobject* g_cachedSSLObj = NULL;
wolfSSL_Mutex* jniSessLock = NULL;
#ifndef USE_WINDOWS_API
wolfSSL_Mutex* pollCountLock = NULL;
#endif
SSLAppData* appData = NULL;
if (jenv == NULL) {
return SSL_FAILURE;
}
/* wolfSSL java caller checks for null pointer */
sslPtr = (jlong)(uintptr_t)wolfSSL_new((WOLFSSL_CTX*)(uintptr_t)ctx);
if (sslPtr != 0) {
/* create global reference to WolfSSLSession jobject */
g_cachedSSLObj = (jobject*)XMALLOC(sizeof(jobject), NULL,
DYNAMIC_TYPE_TMP_BUFFER);
if (g_cachedSSLObj == NULL) {
printf("error mallocing memory in newSSL\n");
wolfSSL_free((WOLFSSL*)(uintptr_t)sslPtr);
return SSL_FAILURE;
}
*g_cachedSSLObj = (*jenv)->NewGlobalRef(jenv, jcl);
if (*g_cachedSSLObj == NULL) {
printf("error storing global WolfSSLSession object\n");
XFREE(g_cachedSSLObj, NULL, DYNAMIC_TYPE_TMP_BUFFER);
wolfSSL_free((WOLFSSL*)(uintptr_t)sslPtr);
return SSL_FAILURE;
}
appData = (SSLAppData*)XMALLOC(sizeof(SSLAppData), NULL,
DYNAMIC_TYPE_TMP_BUFFER);
if (appData == NULL) {
printf("error allocating memory in newSSL for SSLAppData\n");
(*jenv)->DeleteGlobalRef(jenv, *g_cachedSSLObj);
XFREE(g_cachedSSLObj, NULL, DYNAMIC_TYPE_TMP_BUFFER);
wolfSSL_free((WOLFSSL*)(uintptr_t)sslPtr);
return SSL_FAILURE;
}
XMEMSET(appData, 0, sizeof(SSLAppData));
/* store mutex lock in SSL app data, used for I/O and session lock.
* This is freed in freeSSL. */
jniSessLock = (wolfSSL_Mutex*)XMALLOC(sizeof(wolfSSL_Mutex), NULL,
DYNAMIC_TYPE_TMP_BUFFER);
if (!jniSessLock) {
printf("error mallocing memory in newSSL for jniSessLock\n");
(*jenv)->DeleteGlobalRef(jenv, *g_cachedSSLObj);
XFREE(appData, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(g_cachedSSLObj, NULL, DYNAMIC_TYPE_TMP_BUFFER);
wolfSSL_free((WOLFSSL*)(uintptr_t)sslPtr);
return SSL_FAILURE;
}
wc_InitMutex(jniSessLock);
appData->jniSessLock = jniSessLock;
/* set up interrupt pipe for SSLSocket.close() to use if/when needed.
* currently only non-Windows platforms supported due to Windows not
* supporting direct/same pipe() operation. Make read pipe non
* blocking since byte read from it could have already been taken
* out by either reader/writer thread before the other has a chance
* to read it. But, we only use it for waking us up and don't care
* much about actually reading the byte passed over the pipe. */
appData->threadsInPoll = 0;
#ifndef USE_WINDOWS_API
pollCountLock = (wolfSSL_Mutex*)XMALLOC(sizeof(wolfSSL_Mutex), NULL,
DYNAMIC_TYPE_TMP_BUFFER);
if (pollCountLock == NULL) {
printf("error mallocing pollCountLock in newSSL for SSLAppData\n");
(*jenv)->DeleteGlobalRef(jenv, *g_cachedSSLObj);
XFREE(jniSessLock, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(appData, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(g_cachedSSLObj, NULL, DYNAMIC_TYPE_TMP_BUFFER);
wolfSSL_free((WOLFSSL*)(uintptr_t)sslPtr);
return SSL_FAILURE;
}
wc_InitMutex(pollCountLock);
appData->pollCountLock = pollCountLock;
appData->interruptFds[0] = -1;
appData->interruptFds[1] = -1;
if (withIOPipe == JNI_TRUE) {
ret = pipe(appData->interruptFds);
if (ret == -1) {
printf("error setting up pipe() for interruptFds[] in newSSL\n");
(*jenv)->DeleteGlobalRef(jenv, *g_cachedSSLObj);
XFREE(pollCountLock, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(jniSessLock, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(appData, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(g_cachedSSLObj, NULL, DYNAMIC_TYPE_TMP_BUFFER);
wolfSSL_free((WOLFSSL*)(uintptr_t)sslPtr);
return SSL_FAILURE;
}
ret = fcntl(appData->interruptFds[0], F_SETFL,
fcntl(appData->interruptFds[0], F_GETFL, 0) | O_NONBLOCK);
if (ret < 0) {
printf("error setting interruptFds[0] non-blocking in newSSL\n");
closeInterruptPipe(appData);
(*jenv)->DeleteGlobalRef(jenv, *g_cachedSSLObj);
XFREE(pollCountLock, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(jniSessLock, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(appData, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(g_cachedSSLObj, NULL, DYNAMIC_TYPE_TMP_BUFFER);
wolfSSL_free((WOLFSSL*)(uintptr_t)sslPtr);
return SSL_FAILURE;
}
}
#endif /* !USE_WINDOWS_API */
/* cache associated WolfSSLSession jobject in native WOLFSSL */
ret = wolfSSL_set_jobject((WOLFSSL*)(uintptr_t)sslPtr, g_cachedSSLObj);
if (ret != SSL_SUCCESS) {
printf("error storing jobject in wolfSSL native session\n");
(*jenv)->DeleteGlobalRef(jenv, *g_cachedSSLObj);
#ifndef USE_WINDOWS_API
closeInterruptPipe(appData);
XFREE(pollCountLock, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
XFREE(jniSessLock, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(appData, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(g_cachedSSLObj, NULL, DYNAMIC_TYPE_TMP_BUFFER);
wolfSSL_free((WOLFSSL*)(uintptr_t)sslPtr);
return SSL_FAILURE;
}
/* cache SSLAppData into native WOLFSSL */
if (wolfSSL_set_app_data(
(WOLFSSL*)(uintptr_t)sslPtr, appData) != SSL_SUCCESS) {
printf("error setting WOLFSSL app data in newSSL\n");
(*jenv)->DeleteGlobalRef(jenv, *g_cachedSSLObj);
#ifndef USE_WINDOWS_API
closeInterruptPipe(appData);
XFREE(pollCountLock, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#endif
XFREE(jniSessLock, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(appData, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(g_cachedSSLObj, NULL, DYNAMIC_TYPE_TMP_BUFFER);
wolfSSL_set_jobject((WOLFSSL*)(uintptr_t)sslPtr, NULL);
wolfSSL_free((WOLFSSL*)(uintptr_t)sslPtr);
return SSL_FAILURE;
}
}
return sslPtr;
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_setFd(JNIEnv* jenv,
jobject jcl, jlong sslPtr, jobject jsock, jint type)
{
int fd;
int ret = SSL_SUCCESS;
jclass jcls;
jfieldID fid;
jobject impl;
jobject fdesc;
#ifdef USE_WINDOWS_API
unsigned long blocking = 0;
#endif
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
if (jenv == NULL || ssl == NULL || jsock == NULL) {
printf("Error: bad function args, native setFd() wrapper\n");
return SSL_FAILURE;
}
/* get SocketImpl (type 1) or DatagramSocketImpl (2) from Java Socket */
jcls = (*jenv)->GetObjectClass(jenv, jsock);
if (type == 1) {
/* Get SocketImpl field 'impl' from Socket class */
fid = (*jenv)->GetFieldID(jenv, jcls, "impl", "Ljava/net/SocketImpl;");
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
printf("Error: Failed to get SocketImpl impl FieldID\n");
return SSL_FAILURE;
}
/* Get SocketImpl 'impl' object */
impl = (*jenv)->GetObjectField(jenv, jsock, fid);
/* SocketImpl object may hold a delegate object inside on
* some Java versions. Delegate SocketImpl is held inside 'impl'
* object in field 'delegate'. Here we try to get the 'delegate'
* field ID. If NULL, there is no 'delegate' member and we fall back
* to using 'impl' directly. */
jcls = (*jenv)->GetObjectClass(jenv, impl);
fid = (*jenv)->GetFieldID(jenv, jcls, "delegate", "Ljava/net/SocketImpl;");
if (fid != NULL) {
/* delegate field exists, try to get object */
impl = (*jenv)->GetObjectField(jenv, impl, fid);
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
/* Exception while getting delegate field, but does exist */
printf("Error: Exception while getting SocketImpl delegate\n");
return SSL_FAILURE;
}
} else {
/* if delegate field does not exist, can cause NoSuchFieldError
* exception. Clear out before continuing, but don't
* print exception description (we expect it to happen). */
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionClear(jenv);
}
}
} else if (type == 2) {
fid = (*jenv)->GetFieldID(jenv, jcls, "impl",
"Ljava/net/DatagramSocketImpl;");
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
printf("Error: Exception while getting DatagramSocketImpl "
"impl FieldID\n");
return SSL_FAILURE;
}
impl = (*jenv)->GetObjectField(jenv, jsock, fid);
} else {
printf("Invalid Socket class type, not supported\n");
return SSL_FAILURE; /* invalid class type */
}
if (impl == NULL) {
printf("Error: SocketImpl impl is NULL! Not valid\n");
return SSL_FAILURE;
}
/* get FileDescriptor from SocketImpl */
jcls = (*jenv)->GetObjectClass(jenv, impl);
fid = (*jenv)->GetFieldID(jenv, jcls, "fd", "Ljava/io/FileDescriptor;");
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
printf("Error: Exception while getting FileDescriptor fd FieldID\n");
return SSL_FAILURE;
}
fdesc = (*jenv)->GetObjectField(jenv, impl, fid);
if (fdesc == NULL) {
printf("Info: FileDescriptor fd object is NULL!\n");
return SSL_FAILURE;
}
/* get fd from FileDescriptor */
jcls = (*jenv)->GetObjectClass(jenv, fdesc);
#ifdef __ANDROID__
fid = (*jenv)->GetFieldID(jenv, jcls, "descriptor", "I");
#else
fid = (*jenv)->GetFieldID(jenv, jcls, "fd", "I");
#endif
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
printf("Error: Exception while getting fd/descriptor FieldID\n");
return SSL_FAILURE;
}
if (jcls == NULL || fid == NULL) {
printf("Error: jcls or fid NULL while getting fd/descriptor\n");
return SSL_FAILURE;
}
fd = (*jenv)->GetIntField(jenv, fdesc, fid);
/* set socket to non-blocking so we can use select() to detect
* WANT_READ / WANT_WRITE */
#ifdef USE_WINDOWS_API
ret = ioctlsocket(fd, FIONBIO, &blocking);
if (ret == SOCKET_ERROR) {
ret = SSL_FAILURE;
}
else {
ret = SSL_SUCCESS;
}
#else
ret = fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
if (ret < 0) {
ret = SSL_FAILURE;
}
else {
ret = SSL_SUCCESS;
}
#endif
if (ret == SSL_SUCCESS) {
ret = wolfSSL_set_fd(ssl, fd);
}
return (jint)ret;
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_useCertificateFile
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jstring file, jint format)
{
#if defined(OPENSSL_EXTRA) && !defined(NO_FILESYSTEM)
jint ret = 0;
const char* certFile;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
if (jenv == NULL || ssl == NULL) {
return SSL_FAILURE;
}
if (file == NULL) {
return SSL_BAD_FILE;
}
certFile = (*jenv)->GetStringUTFChars(jenv, file, 0);
ret = (jint) wolfSSL_use_certificate_file(ssl, certFile, (int)format);
(*jenv)->ReleaseStringUTFChars(jenv, file, certFile);
return ret;
#else
(void)jenv;
(void)jcl;
(void)sslPtr;
(void)file;
(void)format;
return NOT_COMPILED_IN;
#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_usePrivateKeyFile
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jstring file, jint format)
{
#if defined(OPENSSL_EXTRA) && !defined(NO_FILESYSTEM)
jint ret = 0;
const char* keyFile;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
if (jenv == NULL || ssl == NULL) {
return SSL_FAILURE;
}
if (file == NULL) {
return SSL_BAD_FILE;
}
keyFile = (*jenv)->GetStringUTFChars(jenv, file, 0);
ret = (jint) wolfSSL_use_PrivateKey_file(ssl, keyFile, (int)format);
(*jenv)->ReleaseStringUTFChars(jenv, file, keyFile);
return ret;
#else
(void)jenv;
(void)jcl;
(void)sslPtr;
(void)file;
(void)format;
return NOT_COMPILED_IN;
#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_useCertificateChainFile
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jstring file)
{
#if defined(OPENSSL_EXTRA) && !defined(NO_FILESYSTEM)
jint ret = 0;
const char* chainFile;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
if (jenv == NULL || ssl == NULL) {
return SSL_FAILURE;
}
if (file == NULL) {
return SSL_BAD_FILE;
}
chainFile = (*jenv)->GetStringUTFChars(jenv, file, 0);
ret = (jint) wolfSSL_use_certificate_chain_file(ssl, chainFile);
(*jenv)->ReleaseStringUTFChars(jenv, file, chainFile);
return ret;
#else
(void)jenv;
(void)jcl;
(void)sslPtr;
(void)file;
return NOT_COMPILED_IN;
#endif
}
JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLSession_setUsingNonblock
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jint nonblock)
{
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
if (jenv == NULL) {
return;
}
if (ssl == NULL) {
throwWolfSSLJNIException(jenv,
"Input WolfSSLSession object was null in setUsingNonblock");
}
wolfSSL_set_using_nonblock(ssl, nonblock);
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_getUsingNonblock
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
if (jenv == NULL) {
return 0;
}
if (ssl == NULL) {
throwWolfSSLJNIException(jenv,
"Input WolfSSLSession object was null in getUsingNonblock");
}
return wolfSSL_get_using_nonblock(ssl);
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_getFd
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
if (jenv == NULL) {
return 0;
}
if (ssl == NULL) {
throwWolfSSLJNIException(jenv,
"Input WolfSSLSession object was null in getFd");
return 0;
}
return wolfSSL_get_fd(ssl);
}
/* enum values used in socketSelect() and socketPoll(). Some of these
* values are also duplicated in WolfSSL.java for access from Java classes.
* If updated here, make sure to update in WolfSSL.java too. */
enum {
WOLFJNI_IO_EVENT_FAIL = -10,
WOLFJNI_IO_EVENT_TIMEOUT = -11,
WOLFJNI_IO_EVENT_RECV_READY = -12,
WOLFJNI_IO_EVENT_SEND_READY = -13,
WOLFJNI_IO_EVENT_ERROR = -14,
WOLFJNI_IO_EVENT_FD_CLOSED = -15,
WOLFJNI_IO_EVENT_POLLHUP = -16,
WOLFJNI_IO_EVENT_INVALID_TIMEOUT = -17
};
/* Windows doesn't have poll(), use select() */
#if defined(WOLFJNI_USE_IO_SELECT) || defined(USE_WINDOWS_API)
/* Perform a select() call on the underlying socket to wait for socket to be
* ready for read/write, or timeout. Note that we explicitly set the underlying
* socket descriptor to non-blocking.
*
* NOTE: the FD_ISSET macro behavior is undefined if the descriptor value is
* less than 0 or greater than or equal to FD_SETSIZE (1024 by default).
*
* On a Java Socket, a timeout of 0 is an infinite timeout. Greater than zero
* is a timeout in milliseconds. Negative timeout is invalid and not supported.
* For select(), a non-NULL timeval struct specifies maximum timeout to wait,
* a NULL timeval struct is an infinite timeout. A zero-valued timeval struct
* will return immediately (no timeout).
*
* @param sockfd socket descriptor to select()
* @param timeout_ms timeout in milliseconds. 0 indicates infinite timeout, to
* match Java timeout behavior. Negative timeout not
* supported, since not supported on Java Socket.
* @param rx set to 1 to monitor readability on socket descriptor,
* otherwise 0 to monitor writability
* @param shutdown Is this being called from shutdownSSL()? Don't select
* on interruptFds in that case, since we already know
* we are closing in that case.
*
* @return possible return values are:
* WOLFJNI_IO_EVENT_FAIL
* WOLFJNI_IO_EVENT_ERROR
* WOLFJNI_IO_EVENT_FD_CLOSED
* WOLFJNI_IO_EVENT_TIMEOUT
* WOLFJNI_IO_EVENT_RECV_READY
* WOLFJNI_IO_EVENT_SEND_READY
* WOLFJNI_IO_EVENT_INVALID_TIMEOUT
*/
static int socketSelect(SSLAppData* appData, int sockfd, int timeout_ms, int rx,
int shutdown)
{
fd_set fds, errfds;
fd_set* recvfds = NULL;
fd_set* sendfds = NULL;
int nfds = sockfd + 1;
int result = 0;
struct timeval timeout;
#ifndef USE_WINDOWS_API
char tmpBuf[1];
#endif
/* Java Socket does not support negative timeouts, sanitize */
if (timeout_ms < 0) {
return WOLFJNI_IO_EVENT_INVALID_TIMEOUT;
}
if (appData == NULL) {
return WOLFJNI_IO_EVENT_ERROR;
}
#ifndef USE_WINDOWS_API
do {
#endif
timeout.tv_sec = timeout_ms / 1000;
timeout.tv_usec = (timeout_ms % 1000) * 1000;
/* file/socket descriptors */
FD_ZERO(&fds);
FD_SET(sockfd, &fds);
#ifndef USE_WINDOWS_API
if ((shutdown == 0) && (appData->interruptFds[0] != -1)) {
FD_SET(appData->interruptFds[0], &fds);
/* nfds should be set to the highest number descriptor plus 1 */
if (appData->interruptFds[0] > sockfd) {
nfds = appData->interruptFds[0] + 1;
}
}
#endif /* !USE_WINDOWS_API */
/* error descriptors */
FD_ZERO(&errfds);
FD_SET(sockfd, &errfds);
if (rx) {
recvfds = &fds;
} else {
sendfds = &fds;
}
incrementThreadPollCount(appData);
if (timeout_ms == 0) {
result = select(nfds, recvfds, sendfds, &errfds, NULL);
} else {
result = select(nfds, recvfds, sendfds, &errfds, &timeout);
}
decrementThreadPollCount(appData);
if (result == 0) {
return WOLFJNI_IO_EVENT_TIMEOUT;
} else if (result > 0) {
if (FD_ISSET(sockfd, &fds)) {
if (rx) {
return WOLFJNI_IO_EVENT_RECV_READY;
} else {
return WOLFJNI_IO_EVENT_SEND_READY;
}
}
else if (FD_ISSET(sockfd, &errfds)) {
return WOLFJNI_IO_EVENT_ERROR;
}
#ifndef USE_WINDOWS_API
else if ((shutdown == 0) && (appData->interruptFds[0] != -1) &&
(FD_ISSET(appData->interruptFds[0], &fds))) {
/* We got interrupted by our interrupt fd, due to a Java
* thread calling SSLSocket.close(). Try to read byte that
* was placed on our interruptFds[0] descriptor, but not
* an error if not there. Another read/write() may have
* already read it off. We just want to be interrupted,
* byte value does not matter. */
do {
read(appData->interruptFds[0], tmpBuf, 1);
} while (errno == EINTR);
return WOLFJNI_IO_EVENT_FD_CLOSED;
}
#endif /* !USE_WINDOWS_API */
}
#ifndef USE_WINDOWS_API
} while ((result == -1) && ((errno == EINTR) || (errno == EAGAIN)));
#endif
/* Return on error, unless errno EINTR or EAGAIN, try again above */
return WOLFJNI_IO_EVENT_FAIL;
}
#else /* !WOLFJNI_USE_IO_SELECT */
/* Perform poll() on underlying socket descriptor to wait for socket to be
* ready for read/write, or timeout. Note that we are explicitly setting
* the underlying descriptor to non-blocking.
*
* On a Java Socket, a timeout of 0 is an infinite timeout. Greater than zero
* is a timeout in milliseconds. Negative timeout is invalid and not supported.
* For poll(), timeout greater than 0 specifies max timeout in milliseconds,
* zero timeout will return immediately (no timeout), and -1 will block
* indefinitely.
*
* @param sockfd socket descriptor to poll()
* @param timeout_ms timeout in milliseconds. 0 indicates infinite timeout, to
* match Java timeout behavior. Negative timeout not
* supported, since not supported on Java Socket.
* @param rx set to 1 to monitor readability on socket descriptor,
* otherwise 0 to ignore readability events
* @param tx set to 1 to monitor writability on socket descriptor,
* otherwise 0 to ignore writability events
* @param shutdown Is this being called from shutdownSSL()? Don't poll
* on interruptFds in that case, since we already know
* we are closing in that case.
*
* @return possible return values are:
* WOLFJNI_IO_EVENT_FAIL
* WOLFJNI_IO_EVENT_ERROR
* WOLFJNI_IO_EVENT_TIMEOUT
* WOLFJNI_IO_EVENT_RECV_READY
* WOLFJNI_IO_EVENT_SEND_READY
* WOLFJNI_IO_EVENT_FD_CLOSED
* WOLFJNI_IO_EVENT_POLLHUP
* WOLFJNI_IO_EVENT_INVALID_TIMEOUT
*/
static int socketPoll(SSLAppData* appData, int sockfd, int timeout_ms,
int rx, int tx, int shutdown)
{
int ret;
int nfds = 2;
int timeout;
struct pollfd fds[2];
char tmpBuf[1];
if (appData == NULL) {
return WOLFJNI_IO_EVENT_ERROR;
}
/* Sanitize timeout and convert from Java to poll() expectations */
timeout = timeout_ms;
if (timeout < 0) {
return WOLFJNI_IO_EVENT_INVALID_TIMEOUT;
} else if (timeout == 0) {
timeout = -1;
}
/* fd for socket I/O */
fds[0].fd = sockfd;
fds[0].events = 0;
if (tx) {
fds[0].events |= POLLOUT | POLLPRI;
}
if (rx) {
fds[0].events |= POLLIN | POLLPRI;
}
if ((shutdown == 0) && (appData->interruptFds[0] != -1)) {
/* fd for interrupt / signaling SSLSocket.close() */
fds[1].fd = appData->interruptFds[0];
fds[1].events = POLLIN | POLLPRI;
}
else {
nfds--;
}
do {
incrementThreadPollCount(appData);
ret = poll(fds, nfds, timeout);
decrementThreadPollCount(appData);
if (ret == 0) {
return WOLFJNI_IO_EVENT_TIMEOUT;
}
else if (ret > 0) {
if ((shutdown == 0) && (appData->interruptFds[0] != -1) &&
(fds[1].revents & POLLIN)) {
/* received data on interrupt pipe, read and return
* that descriptor is closed (closing) */
do {
read(appData->interruptFds[0], tmpBuf, 1);
} while (errno == EINTR);
return WOLFJNI_IO_EVENT_FD_CLOSED;
}
else if (fds[0].revents & POLLIN ||
fds[0].revents & POLLPRI) { /* read possible */
return WOLFJNI_IO_EVENT_RECV_READY;
}
else if (fds[0].revents & POLLOUT) { /* write possible */
return WOLFJNI_IO_EVENT_SEND_READY;
}
else if (fds[0].revents & POLLNVAL) { /* fd not open */
return WOLFJNI_IO_EVENT_FD_CLOSED;
}
else if (fds[0].revents & POLLERR) { /* exceptional error */
return WOLFJNI_IO_EVENT_ERROR;
}
else if (fds[0].revents & POLLHUP) { /* sock disconnected */
return WOLFJNI_IO_EVENT_POLLHUP;
}
}
} while ((ret == -1) && ((errno == EINTR) || (errno == EAGAIN)));
return WOLFJNI_IO_EVENT_FAIL;
}
#endif /* WOLFJNI_USE_IO_SELECT | USE_WINDOWS_API */
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_connect
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jint timeout)
{
int ret = 0, err = 0, sockfd = 0;
int pollRx = 0;
#if !defined(WOLFJNI_USE_IO_SELECT) && !defined(USE_WINDOWS_API)
int pollTx = 0;
#endif
wolfSSL_Mutex* jniSessLock = NULL;
SSLAppData* appData = NULL;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
if (jenv == NULL || ssl == NULL) {
return SSL_FAILURE;
}
/* make sure we don't have any outstanding exceptions pending */
if ((*jenv)->ExceptionCheck(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
return SSL_FAILURE;
}
/* get session mutex from SSL app data */
appData = (SSLAppData*)wolfSSL_get_app_data(ssl);
if (appData == NULL) {
return WOLFSSL_FAILURE;
}
jniSessLock = appData->jniSessLock;
if (jniSessLock == NULL) {
return WOLFSSL_FAILURE;
}
do {
/* get I/O lock */
if (wc_LockMutex(jniSessLock) != 0) {
ret = WOLFSSL_FAILURE;
break;
}
ret = wolfSSL_connect(ssl);
err = wolfSSL_get_error(ssl, ret);
/* release I/O lock */
if (wc_UnLockMutex(jniSessLock) != 0) {
ret = WOLFSSL_FAILURE;
break;
}
if (ret < 0 && ((err == SSL_ERROR_WANT_READ) ||
(err == SSL_ERROR_WANT_WRITE))) {
sockfd = wolfSSL_get_fd(ssl);
if (sockfd == -1) {
/* For I/O that does not use sockets, sockfd may be -1,
* skip try to call select() */
break;
}
if (err == SSL_ERROR_WANT_READ) {
pollRx = 1;
}
#if !defined(WOLFJNI_USE_IO_SELECT) && !defined(USE_WINDOWS_API)
else if (err == SSL_ERROR_WANT_WRITE) {
pollTx = 1;
}
#endif
#if defined(WOLFJNI_USE_IO_SELECT) || defined(USE_WINDOWS_API)
ret = socketSelect(appData, sockfd, (int)timeout, pollRx, 0);
#else
ret = socketPoll(appData, sockfd, (int)timeout, pollRx, pollTx, 0);
#endif
if ((ret == WOLFJNI_IO_EVENT_RECV_READY) ||
(ret == WOLFJNI_IO_EVENT_SEND_READY)) {
/* I/O ready, continue handshake and try again */
continue;
} else if (ret == WOLFJNI_IO_EVENT_TIMEOUT ||
ret == WOLFJNI_IO_EVENT_FD_CLOSED ||
ret == WOLFJNI_IO_EVENT_ERROR ||
ret == WOLFJNI_IO_EVENT_POLLHUP ||
ret == WOLFJNI_IO_EVENT_FAIL) {
/* Java will throw SocketTimeoutException or SocketException */
break;
} else {
/* error */
ret = SSL_FAILURE;
break;
}
}
} while (err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ);
/* check for Java exceptions beofre returning */
if ((*jenv)->ExceptionCheck(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
return SSL_FAILURE;
}
return ret;
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_write
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jbyteArray raw, jint offset,
jint length, jint timeout)
{
byte* data = NULL;
int ret = SSL_FAILURE, err, sockfd;
int pollRx = 0;
#if !defined(WOLFJNI_USE_IO_SELECT) && !defined(USE_WINDOWS_API)
int pollTx = 0;
#endif
wolfSSL_Mutex* jniSessLock = NULL;
SSLAppData* appData = NULL;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
if (jenv == NULL || ssl == NULL || raw == NULL) {
return BAD_FUNC_ARG;
}
if ((offset >= 0) && (length >= 0)) {
data = (byte*)(*jenv)->GetByteArrayElements(jenv, raw, NULL);
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
return SSL_FAILURE;
}
/* get session mutex from SSL app data */
appData = (SSLAppData*)wolfSSL_get_app_data(ssl);
if (appData == NULL) {
(*jenv)->ReleaseByteArrayElements(jenv, raw, (jbyte*)data,
JNI_ABORT);
return WOLFSSL_FAILURE;
}
jniSessLock = appData->jniSessLock;
if (jniSessLock == NULL) {
(*jenv)->ReleaseByteArrayElements(jenv, raw, (jbyte*)data,
JNI_ABORT);
return SSL_FAILURE;
}
do {
/* lock mutex around session I/O before write attempt */
if (wc_LockMutex(jniSessLock) != 0) {
ret = WOLFSSL_FAILURE;
break;
}
ret = wolfSSL_write(ssl, data + offset, length);
err = wolfSSL_get_error(ssl, ret);
/* unlock mutex around session I/O after write attempt */
if (wc_UnLockMutex(jniSessLock) != 0) {
ret = WOLFSSL_FAILURE;
break;
}
if (ret >= 0) /* return if it is success */
break;
if (err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE) {
sockfd = wolfSSL_get_fd(ssl);
if (sockfd == -1) {
/* For I/O that does not use sockets, sockfd may be -1,
* skip try to call select() */
break;
}
if (err == SSL_ERROR_WANT_READ) {
pollRx = 1;
}
#if !defined(WOLFJNI_USE_IO_SELECT) && !defined(USE_WINDOWS_API)
else if (err == SSL_ERROR_WANT_WRITE) {
pollTx = 1;
}
#endif
#if defined(WOLFJNI_USE_IO_SELECT) || defined(USE_WINDOWS_API)
ret = socketSelect(appData, sockfd, (int)timeout, pollRx, 0);
#else
ret = socketPoll(appData, sockfd, (int)timeout, pollRx,
pollTx, 0);
#endif
if ((ret == WOLFJNI_IO_EVENT_RECV_READY) ||
(ret == WOLFJNI_IO_EVENT_SEND_READY)) {
/* loop around and try wolfSSL_write() again */
continue;
} else if (ret == WOLFJNI_IO_EVENT_TIMEOUT ||
ret == WOLFJNI_IO_EVENT_FD_CLOSED ||
ret == WOLFJNI_IO_EVENT_ERROR ||
ret == WOLFJNI_IO_EVENT_POLLHUP ||
ret == WOLFJNI_IO_EVENT_FAIL) {
/* Java will throw SocketTimeoutException or
* SocketException */
break;
} else {
/* error */
ret = WOLFSSL_FAILURE;
break;
}
}
} while (err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ);
(*jenv)->ReleaseByteArrayElements(jenv, raw, (jbyte*)data, JNI_ABORT);
return ret;
} else {
return SSL_FAILURE;
}
}
/**
* Read len bytes from wolfSSL_read() back into provided output buffer.
*
* Internal function called by WolfSSLSession.read() calls.
*
* If wolfSSL_get_fd(ssl) returns a socket descriptor, try to wait for
* data with select()/poll() up to provided timeout.
*
* Returns number of bytes read on success, or negative on error.
*/
static int SSLReadNonblockingWithSelectPoll(WOLFSSL* ssl, byte* out,
int length, int timeout)
{
int size, ret, err, sockfd;
int pollRx = 0;
#if !defined(WOLFJNI_USE_IO_SELECT) && !defined(USE_WINDOWS_API)
int pollTx = 0;
#endif
wolfSSL_Mutex* jniSessLock = NULL;
SSLAppData* appData = NULL;
if (ssl == NULL || out == NULL) {
return BAD_FUNC_ARG;
}
/* get session mutex from SSL app data */
appData = (SSLAppData*)wolfSSL_get_app_data(ssl);
if (appData == NULL) {
return WOLFSSL_FAILURE;
}
jniSessLock = appData->jniSessLock;
if (jniSessLock == NULL) {
return WOLFSSL_FAILURE;
}
do {
/* lock mutex around session I/O before read attempt */
if (wc_LockMutex(jniSessLock) != 0) {
size = WOLFSSL_FAILURE;
break;
}
size = wolfSSL_read(ssl, out, length);
err = wolfSSL_get_error(ssl, size);
/* unlock mutex around session I/O after read attempt */
if (wc_UnLockMutex(jniSessLock) != 0) {
size = WOLFSSL_FAILURE;
break;
}
if (size < 0 &&
((err == SSL_ERROR_WANT_READ) || (err == SSL_ERROR_WANT_WRITE))) {
sockfd = wolfSSL_get_fd(ssl);
if (sockfd == -1) {
/* For I/O that does not use sockets, sockfd may be -1,
* skip try to call select() */
break;
}
if (err == SSL_ERROR_WANT_READ) {
pollRx = 1;
}
#if !defined(WOLFJNI_USE_IO_SELECT) && !defined(USE_WINDOWS_API)
else if (err == SSL_ERROR_WANT_WRITE) {
pollTx = 1;
}
#endif
#if defined(WOLFJNI_USE_IO_SELECT) || defined(USE_WINDOWS_API)
ret = socketSelect(appData, sockfd, timeout, pollRx, 0);
#else
ret = socketPoll(appData, sockfd, timeout, pollRx, pollTx, 0);
#endif
if ((ret == WOLFJNI_IO_EVENT_RECV_READY) ||
(ret == WOLFJNI_IO_EVENT_SEND_READY)) {
/* loop around and try wolfSSL_read() again */
continue;
} else {
/* Java will throw SocketTimeoutException or
* SocketException if ret equals
* WOLFJNI_IO_EVENT_TIMEOUT, WOLFJNI_IO_EVENT_FD_CLOSED
* WOLFJNI_IO_EVENT_ERROR, WOLFJNI_IO_EVENT_POLLHUP or
* WOLFJNI_IO_EVENT_FAIL */
size = ret;
break;
}
}
} while (err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ);
return size;
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_read__J_3BIII
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jbyteArray raw, jint offset,
jint length, jint timeout)
{
int size = 0;
byte* data = NULL;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
if (jenv == NULL || ssl == NULL || raw == NULL) {
return BAD_FUNC_ARG;
}
if ((offset >= 0) && (length >= 0)) {
data = (byte*)(*jenv)->GetByteArrayElements(jenv, raw, NULL);
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
return SSL_FAILURE;
}
size = SSLReadNonblockingWithSelectPoll(ssl, data + offset,
(int)length, (int)timeout);
if (size < 0) {
(*jenv)->ReleaseByteArrayElements(jenv, raw, (jbyte*)data,
JNI_ABORT);
}
else {
/* JNI_COMMIT commits the data but does not free the local array
* 0 is used here to both commit and free */
(*jenv)->ReleaseByteArrayElements(jenv, raw, (jbyte*)data, 0);
}
}
return size;
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_read__JLjava_nio_ByteBuffer_2II
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jobject buf, jint length, jint timeout)
{
int size = 0;
int maxOutputSz;
int outSz = length;
byte* data = NULL;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
jint position;
jint limit;
jboolean hasArray;
jbyteArray bufArr = NULL;
(void)jcl;
if (jenv == NULL || ssl == NULL || buf == NULL) {
return BAD_FUNC_ARG;
}
if (length > 0) {
/* Get ByteBuffer position */
position = (*jenv)->CallIntMethod(jenv, buf, g_bufferPositionMethodId);
/* Get ByteBuffer limit */
limit = (*jenv)->CallIntMethod(jenv, buf, g_bufferLimitMethodId);
/* Get and call ByteBuffer.hasArray() before calling array() */
hasArray = (*jenv)->CallBooleanMethod(jenv, buf,
g_bufferHasArrayMethodId);
/* Only read up to maximum space we have in this ByteBuffer */
maxOutputSz = (limit - position);
if (outSz > maxOutputSz) {
outSz = maxOutputSz;
}
if (hasArray) {
/* Get reference to underlying byte[] from ByteBuffer */
bufArr = (jbyteArray)(*jenv)->CallObjectMethod(jenv, buf,
g_bufferArrayMethodId);
/* Get array elements */
data = (byte *)(*jenv)->GetByteArrayElements(jenv, bufArr, NULL);
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
throwWolfSSLJNIException(jenv,
"Exception when calling ByteBuffer.array() in native read()");
return -1;
}
}
else {
data = (byte *)(*jenv)->GetDirectBufferAddress(jenv, buf);
if (data == NULL) {
throwWolfSSLJNIException(jenv,
"Failed to get DirectBuffer address in native read()");
return BAD_FUNC_ARG;
}
}
if (data != NULL) {
size = SSLReadNonblockingWithSelectPoll(ssl, data + position,
maxOutputSz, (int)timeout);
/* Relase array elements */
if (hasArray) {
if (size < 0) {
(*jenv)->ReleaseByteArrayElements(jenv, bufArr,
(jbyte *)data, JNI_ABORT);
}
else {
(*jenv)->ReleaseByteArrayElements(jenv, bufArr,
(jbyte *)data, 0);
}
}
/* Note: DirectByteBuffer doesn't need releasing data */
if (size > 0) {
/* Update ByteBuffer position() based on bytes written */
(*jenv)->CallVoidMethod(jenv, buf, g_bufferSetPositionMethodId,
position + size);
}
}
}
return size;
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_pending
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
/* Checks ssl for NULL internally, will return WOLFSSL_FAILURE */
return (jint)wolfSSL_pending(ssl);
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_accept
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jint timeout)
{
int ret = 0, err, sockfd;
int pollRx = 0;
#if !defined(WOLFJNI_USE_IO_SELECT) && !defined(USE_WINDOWS_API)
int pollTx = 0;
#endif
wolfSSL_Mutex* jniSessLock = NULL;
SSLAppData* appData = NULL;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
if (jenv == NULL || ssl == NULL) {
return SSL_FATAL_ERROR;
}
/* make sure we don't have any outstanding exceptions pending */
if ((*jenv)->ExceptionCheck(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
return SSL_FAILURE;
}
/* get session mutex from SSL app data */
appData = (SSLAppData*)wolfSSL_get_app_data(ssl);
if (appData == NULL) {
return WOLFSSL_FAILURE;
}
jniSessLock = appData->jniSessLock;
if (jniSessLock == NULL) {
return SSL_FAILURE;
}
do {
/* get I/O lock */
if (wc_LockMutex(jniSessLock) != 0) {
ret = WOLFSSL_FAILURE;
break;
}
ret = wolfSSL_accept(ssl);
err = wolfSSL_get_error(ssl, ret);
/* release I/O lock */
if (wc_UnLockMutex(jniSessLock) != 0) {
ret = WOLFSSL_FAILURE;
break;
}
if (ret < 0 && ((err == SSL_ERROR_WANT_READ) ||
(err == SSL_ERROR_WANT_WRITE))) {
sockfd = wolfSSL_get_fd(ssl);
if (sockfd == -1) {
/* For I/O that does not use sockets, sockfd may be -1,
* skip try to call select() */
break;
}
if (err == SSL_ERROR_WANT_READ) {
pollRx = 1;
}
#if !defined(WOLFJNI_USE_IO_SELECT) && !defined(USE_WINDOWS_API)
else if (err == SSL_ERROR_WANT_WRITE) {
pollTx = 1;
}
#endif
#if defined(WOLFJNI_USE_IO_SELECT) || defined(USE_WINDOWS_API)
ret = socketSelect(appData, sockfd, (int)timeout, pollRx, 0);
#else
ret = socketPoll(appData, sockfd, (int)timeout, pollRx, pollTx, 0);
#endif
if ((ret == WOLFJNI_IO_EVENT_RECV_READY) ||
(ret == WOLFJNI_IO_EVENT_SEND_READY)) {
/* loop around and try wolfSSL_accept() again */
continue;
} else if (ret == WOLFJNI_IO_EVENT_TIMEOUT ||
ret == WOLFJNI_IO_EVENT_FD_CLOSED ||
ret == WOLFJNI_IO_EVENT_ERROR ||
ret == WOLFJNI_IO_EVENT_POLLHUP ||
ret == WOLFJNI_IO_EVENT_FAIL) {
/* Java will throw SocketTimeoutException or
* SocketException */
break;
} else {
/* other error occurred */
ret = SSL_FAILURE;
break;
}
}
} while (err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ);
/* check for Java exceptions beofre returning */
if ((*jenv)->ExceptionCheck(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
return SSL_FAILURE;
}
return ret;
}
JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLSession_freeSSL
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
jobject* g_cachedSSLObj;
jobject* g_cachedVerifyCb;
SSLAppData* appData;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
#if defined(HAVE_PK_CALLBACKS) && (defined(HAVE_ECC) || !defined(NO_RSA))
internCtx* pkCtx = NULL;
#endif
if (ssl == NULL) {
throwWolfSSLException(jenv,
"Input WolfSSLSession object was null in freeSSL");
return;
}
/* free session mutex lock */
appData = (SSLAppData*)wolfSSL_get_app_data(ssl);
if (appData != NULL) {
if (appData->jniSessLock != NULL) {
wc_FreeMutex(appData->jniSessLock);
XFREE(appData->jniSessLock, NULL, DYNAMIC_TYPE_TMP_BUFFER);
appData->jniSessLock = NULL;
}
g_cachedVerifyCb = appData->g_verifySSLCbIfaceObj;
if (g_cachedVerifyCb != NULL) {
(*jenv)->DeleteGlobalRef(jenv, (jobject)(*g_cachedVerifyCb));
XFREE(g_cachedVerifyCb, NULL, DYNAMIC_TYPE_TMP_BUFFER);
g_cachedVerifyCb = NULL;
}
#ifndef USE_WINDOWS_API
if (appData->pollCountLock != NULL) {
wc_FreeMutex(appData->pollCountLock);
XFREE(appData->pollCountLock, NULL, DYNAMIC_TYPE_TMP_BUFFER);
appData->pollCountLock = NULL;
}
/* close pipe() descriptors */
closeInterruptPipe(appData);
#endif
/* free appData */
XFREE(appData, NULL, DYNAMIC_TYPE_TMP_BUFFER);
appData = NULL;
}
/* delete global WolfSSLSession object reference */
g_cachedSSLObj = (jobject*) wolfSSL_get_jobject(ssl);
if (g_cachedSSLObj != NULL) {
(*jenv)->DeleteGlobalRef(jenv, (jobject)(*g_cachedSSLObj));
XFREE(g_cachedSSLObj, NULL, DYNAMIC_TYPE_TMP_BUFFER);
g_cachedSSLObj = NULL;
}
/* reset internal pointer to NULL to prevent accidental usage */
if (wolfSSL_set_jobject(ssl, NULL) != SSL_SUCCESS) {
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
return;
}
throwWolfSSLException(jenv,
"Error reseting internal wolfSSL JNI pointer to NULL, freeSSL");
return;
}
#ifdef HAVE_CRL
/* release global CRL callback ref if registered */
if (g_crlCbIfaceObj != NULL) {
(*jenv)->DeleteGlobalRef(jenv, g_crlCbIfaceObj);
g_crlCbIfaceObj = NULL;
}
#endif
#if defined(HAVE_PK_CALLBACKS)
#ifdef HAVE_ECC
/* free ECC sign callback CTX global reference if set */
pkCtx = (internCtx*) wolfSSL_GetEccSignCtx(ssl);
if (pkCtx != NULL) {
if (pkCtx->obj != NULL) {
(*jenv)->DeleteGlobalRef(jenv, pkCtx->obj);
}
XFREE(pkCtx, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
/* free ECC verify callback CTX global reference if set */
pkCtx = (internCtx*)wolfSSL_GetEccVerifyCtx(ssl);
if (pkCtx != NULL) {
if (pkCtx->obj != NULL) {
(*jenv)->DeleteGlobalRef(jenv, pkCtx->obj);
}
XFREE(pkCtx, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
/* free ECC shared secret callback CTX global reference if set */
pkCtx = (internCtx*)wolfSSL_GetEccSharedSecretCtx(ssl);
if (pkCtx != NULL) {
if (pkCtx->obj != NULL) {
(*jenv)->DeleteGlobalRef(jenv, pkCtx->obj);
}
XFREE(pkCtx, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
#endif /* HAVE_ECC */
#ifndef NO_RSA
/* free RSA sign callback CTX global reference if set */
pkCtx = (internCtx*) wolfSSL_GetRsaSignCtx(ssl);
if (pkCtx != NULL) {
if (pkCtx->obj != NULL) {
(*jenv)->DeleteGlobalRef(jenv, pkCtx->obj);
}
XFREE(pkCtx, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
/* free RSA verify callback CTX global reference if set */
pkCtx = (internCtx*)wolfSSL_GetRsaVerifyCtx(ssl);
if (pkCtx != NULL) {
if (pkCtx->obj != NULL) {
(*jenv)->DeleteGlobalRef(jenv, pkCtx->obj);
}
XFREE(pkCtx, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
/* free RSA encrypt callback CTX global reference if set */
pkCtx = (internCtx*) wolfSSL_GetRsaEncCtx(ssl);
if (pkCtx != NULL) {
if (pkCtx->obj != NULL) {
(*jenv)->DeleteGlobalRef(jenv, pkCtx->obj);
}
XFREE(pkCtx, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
/* free RSA decrypt callback CTX global reference if set */
pkCtx = (internCtx*) wolfSSL_GetRsaDecCtx(ssl);
if (pkCtx != NULL) {
if (pkCtx->obj != NULL) {
(*jenv)->DeleteGlobalRef(jenv, pkCtx->obj);
}
XFREE(pkCtx, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
#endif /* !NO_RSA */
#endif /* HAVE_PK_CALLBACKS */
/* native cleanup */
wolfSSL_free(ssl);
ssl = 0;
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_shutdownSSL
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jint timeout)
{
int ret = 0, err, sockfd;
int pollRx = 0;
#if !defined(WOLFJNI_USE_IO_SELECT) && !defined(USE_WINDOWS_API)
int pollTx = 0;
#endif
wolfSSL_Mutex* jniSessLock;
SSLAppData* appData = NULL;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
if (jenv == NULL) {
return SSL_FAILURE;
}
/* make sure we don't have any outstanding exceptions pending */
if ((*jenv)->ExceptionCheck(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
return SSL_FAILURE;
}
/* get session mutex from SSL app data */
appData = (SSLAppData*)wolfSSL_get_app_data(ssl);
if (appData == NULL) {
return WOLFSSL_FAILURE;
}
jniSessLock = appData->jniSessLock;
if (jniSessLock == NULL) {
return WOLFSSL_FAILURE;
}
do {
/* get I/O lock */
if (wc_LockMutex(jniSessLock) != 0) {
ret = WOLFSSL_FAILURE;
break;
}
ret = wolfSSL_shutdown(ssl);
err = wolfSSL_get_error(ssl, ret);
/* release I/O lock */
if (wc_UnLockMutex(jniSessLock) != 0) {
ret = WOLFSSL_FAILURE;
break;
}
if (ret < 0 && ((err == SSL_ERROR_WANT_READ) ||
(err == SSL_ERROR_WANT_WRITE))) {
sockfd = wolfSSL_get_fd(ssl);
if (sockfd == -1) {
/* For I/O that does not use sockets, sockfd may be -1,
* skip try to call select() */
break;
}
if (err == SSL_ERROR_WANT_READ) {
pollRx = 1;
}
#if !defined(WOLFJNI_USE_IO_SELECT) && !defined(USE_WINDOWS_API)
else if (err == SSL_ERROR_WANT_WRITE) {
pollTx = 1;
}
#endif
#if defined(WOLFJNI_USE_IO_SELECT) || defined(USE_WINDOWS_API)
ret = socketSelect(appData, sockfd, (int)timeout, pollRx, 1);
#else
ret = socketPoll(appData, sockfd, (int)timeout, pollRx, pollTx, 1);
#endif
if ((ret == WOLFJNI_IO_EVENT_RECV_READY) ||
(ret == WOLFJNI_IO_EVENT_SEND_READY)) {
/* loop around and try wolfSSL_shutdown() again */
continue;
} else if (ret == WOLFJNI_IO_EVENT_TIMEOUT ||
ret == WOLFJNI_IO_EVENT_FD_CLOSED ||
ret == WOLFJNI_IO_EVENT_ERROR ||
ret == WOLFJNI_IO_EVENT_POLLHUP ||
ret == WOLFJNI_IO_EVENT_FAIL) {
/* Java will throw SocketTimeoutException or
* SocketException */
break;
} else {
/* other error occurred */
ret = SSL_FAILURE;
break;
}
}
} while (err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ);
/* check for Java exceptions beofre returning */
if ((*jenv)->ExceptionCheck(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
return SSL_FAILURE;
}
return ret;
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_getError
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jint ret)
{
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
if (jenv == NULL) {
return SSL_FAILURE;
}
/* wolfSSL checks ssl for NULL */
return wolfSSL_get_error(ssl, ret);
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_setSession
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jlong sessionPtr)
{
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
WOLFSSL_SESSION* session = (WOLFSSL_SESSION*)(uintptr_t)sessionPtr;
wolfSSL_Mutex* jniSessLock = NULL;
SSLAppData* appData = NULL;
int ret = 0;
(void)jcl;
if (jenv == NULL || ssl == NULL) {
return SSL_FAILURE;
}
/* get session mutex from SSL app data */
appData = (SSLAppData*)wolfSSL_get_app_data(ssl);
if (appData == NULL) {
printf("Failed to get SSLAppData* in native setSession()\n");
return (jlong)0;
}
jniSessLock = appData->jniSessLock;
if (jniSessLock == NULL) {
printf("SSLAppData* NULL in native setSession()\n");
return (jlong)0;
}
/* get WOLFSSL session I/O lock */
if (wc_LockMutex(jniSessLock) != 0) {
printf("Failed to lock native jniSessLock in setSession()");
return (jlong)0;
}
/* wolfSSL checks session for NULL, but not ssl */
ret = wolfSSL_set_session(ssl, session);
if (wc_UnLockMutex(jniSessLock) != 0) {
printf("Failed to unlock jniSessLock in setSession()");
}
return ret;
}
JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLSession_getSession
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
WOLFSSL_SESSION* sess = NULL;
wolfSSL_Mutex* jniSessLock = NULL;
SSLAppData* appData = NULL;
(void)jenv;
(void)jcl;
/* get session mutex from SSL app data */
appData = (SSLAppData*)wolfSSL_get_app_data(ssl);
if (appData == NULL) {
printf("Failed to get SSLAppData* in native getSession()\n");
return (jlong)0;
}
jniSessLock = appData->jniSessLock;
if (jniSessLock == NULL) {
printf("SSLAppData* NULL in native getSession()\n");
return (jlong)0;
}
/* get WOLFSSL session I/O lock */
if (wc_LockMutex(jniSessLock) != 0) {
printf("Failed to lock native jniSessLock in getSession()");
return (jlong)0;
}
/* wolfSSL checks ssl for NULL, returns pointer into WOLFSSL which is
* freed when wolfSSL_free() is called. */
sess = wolfSSL_get_session(ssl);
if (wc_UnLockMutex(jniSessLock) != 0) {
printf("Failed to unlock jniSessLock in getSession()");
}
return (jlong)(uintptr_t)sess;
}
JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLSession_get1Session
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
int ret = 0;
int err = 0;
int sockfd = 0;
int version = 0;
int hasTicket = 0;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
WOLFSSL_SESSION* sess = NULL;
WOLFSSL_SESSION* dup = NULL;
wolfSSL_Mutex* jniSessLock = NULL;
SSLAppData* appData = NULL;
/* tmpBuf is only 1 byte since wolfSSL_peek() doesn't need to read
* any app data, only session ticket internally */
char tmpBuf[1];
(void)jenv;
(void)jcl;
if (ssl == NULL) {
return (jlong)0;
}
/* get session mutex from SSL app data */
appData = (SSLAppData*)wolfSSL_get_app_data(ssl);
if (appData == NULL) {
printf("Failed to get SSLAppData* in native get1Session()\n");
return (jlong)0;
}
jniSessLock = appData->jniSessLock;
if (jniSessLock == NULL) {
printf("SSLAppData* NULL in native get1Session()\n");
return (jlong)0;
}
/* get WOLFSSL session I/O lock */
if (wc_LockMutex(jniSessLock) != 0) {
printf("Failed to lock native jniSessLock in get1Session()");
return (jlong)0;
}
/* get protocol version for this session */
version = wolfSSL_version(ssl);
/* Use wolfSSL_get_session() only as an indicator if we need to call
* wolfSSL_peek() for TLS 1.3 connections to potentially get the
* session ticket message. */
sess = wolfSSL_get_session(ssl);
/* Check if session has session ticket, checks sess for null internal */
hasTicket = wolfSSL_SESSION_has_ticket((const WOLFSSL_SESSION*)sess);
/* If session is not available yet, or if TLS 1.3 and we have a session
* pointer but no session ticket yet, try peeking to get ticket */
if (sess == NULL ||
((sess != NULL) && (version == TLS1_3_VERSION) && (hasTicket == 0))) {
do {
ret = wolfSSL_peek(ssl, tmpBuf, (int)sizeof(tmpBuf));
err = wolfSSL_get_error(ssl, ret);
if (ret <= 0 && (err == SSL_ERROR_WANT_READ)) {
sockfd = wolfSSL_get_fd(ssl);
if (sockfd == -1) {
/* For I/O that does not use sockets, sockfd may be -1,
* skip try to call select() */
break;
}
#if defined(WOLFJNI_USE_IO_SELECT) || defined(USE_WINDOWS_API)
/* Default to select() on Windows or if WOLFJNI_USE_IO_SELECT */
ret = socketSelect(appData, sockfd,
(int)WOLFSSL_JNI_DEFAULT_PEEK_TIMEOUT, 1, 0);
#else
ret = socketPoll(appData, sockfd,
(int)WOLFSSL_JNI_DEFAULT_PEEK_TIMEOUT, 1, 0, 0);
#endif
if ((ret == WOLFJNI_IO_EVENT_RECV_READY) ||
(ret == WOLFJNI_IO_EVENT_SEND_READY)) {
/* I/O ready, continue handshake and try again */
continue;
} else {
/* other error, continue on */
break;
}
}
} while (err == SSL_ERROR_WANT_READ);
}
/* Call wolfSSL_get1_session() to increase the ref count of the internal
* WOLFSSL_SESSION struct. This is needed in all build option cases,
* since Java callers of this function expect to explicitly free this
* pointer when finished with use. In some build cases, for example
* NO_CLIENT_CACHE or NO_SESSION_CACHE_REF, the poiner returned by
* wolfSSL_get_session() will be a pointer into the WOLFSSL struct, which
* will be freed with wolfSSL_free(). This can cause issues if the Java
* app expects to hold a valid session pointer for resumption and free
* later on. */
dup = wolfSSL_get1_session(ssl);
if (wc_UnLockMutex(jniSessLock) != 0) {
printf("Failed to unlock jniSessLock in get1Session()");
}
return (jlong)(uintptr_t)dup;
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_wolfsslSessionIsSetup
(JNIEnv* jenv, jclass jcl, jlong sessionPtr)
{
#if (LIBWOLFSSL_VERSION_HEX > 0x05007000) || \
defined(WOLFSSL_PR7430_PATCH_APPLIED)
int ret;
WOLFSSL_SESSION* session = (WOLFSSL_SESSION*)(uintptr_t)sessionPtr;
(void)jcl;
if (jenv == NULL) {
return 0;
}
/* wolfSSL_SessionIsSetup() was added after wolfSSL 5.7.0 in PR
* 7430. Version checked above must be greater than 5.7.0 or patch
* from this PR must be applied and WOLFSSL_PR7430_PATCH_APPLIED defined
* when compiling this JNI wrapper */
ret = wolfSSL_SessionIsSetup(session);
return (jint)ret;
#else
(void)jenv;
(void)jcl;
(void)sessionPtr;
return (jint)NOT_COMPILED_IN;
#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_wolfsslSessionIsResumable
(JNIEnv* jenv, jclass jcl, jlong sessionPtr)
{
#ifdef OPENSSL_EXTRA
int ret;
WOLFSSL_SESSION* session = (WOLFSSL_SESSION*)(uintptr_t)sessionPtr;
(void)jcl;
if (jenv == NULL) {
return 0;
}
ret = wolfSSL_SESSION_is_resumable(session);
return (jint)ret;
#else
(void)jenv;
(void)jcl;
(void)sessionPtr;
return (jint)NOT_COMPILED_IN;
#endif
}
JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLSession_wolfsslSessionDup
(JNIEnv* jenv, jclass jcl, jlong sessionPtr)
{
WOLFSSL_SESSION* session = (WOLFSSL_SESSION*)(uintptr_t)sessionPtr;
(void)jcl;
if (jenv == NULL) {
return 0;
}
/* checks session for NULL */
return (jlong)(uintptr_t)wolfSSL_SESSION_dup(session);
}
JNIEXPORT jstring JNICALL Java_com_wolfssl_WolfSSLSession_wolfsslSessionCipherGetName
(JNIEnv* jenv, jclass jcl, jlong sessionPtr)
{
WOLFSSL_SESSION* session = (WOLFSSL_SESSION*)(uintptr_t)sessionPtr;
const char* cipherName;
jstring cipherStr = NULL;
(void)jcl;
if (jenv == NULL || session == NULL) {
return NULL;
}
cipherName = wolfSSL_SESSION_CIPHER_get_name(session);
if (cipherName != NULL) {
cipherStr = (*jenv)->NewStringUTF(jenv, cipherName);
}
return cipherStr;
}
JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLSession_freeNativeSession
(JNIEnv* jenv, jclass jcl, jlong sessionPtr)
{
WOLFSSL_SESSION* session = (WOLFSSL_SESSION*)(uintptr_t)sessionPtr;
(void)jcl;
if (jenv == NULL) {
return;
}
/* checks session for NULL */
wolfSSL_SESSION_free(session);
}
JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_WolfSSLSession_getSessionID
(JNIEnv* jenv, jobject jcl, jlong sessionPtr)
{
unsigned int sz;
const unsigned char* id;
jbyteArray ret;
WOLFSSL_SESSION* session = (WOLFSSL_SESSION*)(uintptr_t)sessionPtr;
id = wolfSSL_SESSION_get_id(session, &sz);
if (id == NULL) {
return NULL;
}
ret = (*jenv)->NewByteArray(jenv, sz);
if (!ret) {
(*jenv)->ThrowNew(jenv, jcl,
"Failed to create byte array in native getSessionID");
return NULL;
}
(*jenv)->SetByteArrayRegion(jenv, ret, 0, sz, (jbyte*)id);
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
return NULL;
}
return ret;
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_setTimeout
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jlong t)
{
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jenv;
(void)jcl;
return wolfSSL_set_timeout(ssl, (unsigned int)t);
}
JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLSession_getTimeout
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jenv;
(void)jcl;
return wolfSSL_get_timeout(ssl);
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_setServerID
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jbyteArray id, jint len, jint newSess)
{
#if !defined(NO_SESSION_CACHE) && !defined(NO_CLIENT_CACHE)
int ret = WOLFSSL_SUCCESS;
byte* idBuf = NULL;
int idBufSz = 0;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
if (jenv == NULL || ssl == NULL || id == NULL) {
return WOLFSSL_FAILURE;
}
idBuf = (byte*)(*jenv)->GetByteArrayElements(jenv, id, NULL);
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
return SSL_FAILURE;
}
idBufSz = (*jenv)->GetArrayLength(jenv, id);
if (idBuf == NULL || idBufSz <= 0) {
ret = WOLFSSL_FAILURE;
}
else {
ret = wolfSSL_SetServerID(ssl, idBuf, idBufSz, (int)newSess);
}
(*jenv)->ReleaseByteArrayElements(jenv, id, (jbyte*)idBuf, JNI_ABORT);
return ret;
#else
(void)jenv;
(void)jcl;
(void)sslPtr;
(void)id;
(void)len;
(void)newSess;
return NOT_COMPILED_IN;
#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_setSessTimeout
(JNIEnv* jenv, jobject jcl, jlong sessionPtr, jlong sz)
{
WOLFSSL_SESSION* session = (WOLFSSL_SESSION*)(uintptr_t)sessionPtr;
(void)jenv;
(void)jcl;
return wolfSSL_SSL_SESSION_set_timeout(session, (long)sz);
}
JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLSession_getSessTimeout
(JNIEnv* jenv, jobject jcl, jlong sessionPtr)
{
WOLFSSL_SESSION* session = (WOLFSSL_SESSION*)(uintptr_t)sessionPtr;
(void)jenv;
(void)jcl;
return wolfSSL_SESSION_get_timeout(session);
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_setCipherList
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jstring list)
{
jint ret = 0;
const char* cipherList;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
if (jenv == NULL || ssl == NULL || list == NULL) {
return SSL_FAILURE;
}
cipherList= (*jenv)->GetStringUTFChars(jenv, list, 0);
ret = (jint) wolfSSL_set_cipher_list(ssl, cipherList);
(*jenv)->ReleaseStringUTFChars(jenv, list, cipherList);
return ret;
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_dtlsGetCurrentTimeout
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
#if !defined(WOLFSSL_LEANPSK) && defined(WOLFSSL_DTLS)
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
if (ssl == NULL) {
throwWolfSSLException(jenv,
"Input WolfSSLSession object was null in "
"dtlsGetCurrentTimeout()");
return 0;
}
return wolfSSL_dtls_get_current_timeout(ssl);
#else
(void)jenv;
(void)jcl;
(void)sslPtr;
return NOT_COMPILED_IN;
#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_dtlsGotTimeout
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
#if !defined(WOLFSSL_LEANPSK) && defined(WOLFSSL_DTLS)
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jenv;
(void)jcl;
if (ssl == NULL) {
return SSL_FATAL_ERROR;
}
return wolfSSL_dtls_got_timeout(ssl);
#else
(void)jenv;
(void)jcl;
(void)sslPtr;
return NOT_COMPILED_IN;
#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_dtlsRetransmit
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
#if !defined(WOLFSSL_LEANPSK) && defined(WOLFSSL_DTLS)
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jenv;
(void)jcl;
if (ssl == NULL) {
return SSL_FATAL_ERROR;
}
return wolfSSL_dtls_retransmit(ssl);
#else
(void)jenv;
(void)jcl;
(void)sslPtr;
return NOT_COMPILED_IN;
#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_dtls
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jenv;
(void)jcl;
if (ssl == NULL) {
return 0;
}
return wolfSSL_dtls(ssl);
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_dtlsSetPeer
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jobject peer)
{
int ret = SSL_SUCCESS;
jstring ipAddr = NULL;
struct sockaddr_in sa;
const char* ipAddress = NULL;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
jclass inetsockaddr = NULL;
jclass inetaddr = NULL;
jmethodID portID = NULL;
jmethodID addrID = NULL;
jmethodID isAnyID = NULL;
jmethodID ipAddrID = NULL;
jobject addrObj = NULL;
jboolean isAny;
jint port = 0;
(void)jcl;
if (jenv == NULL || ssl == NULL || peer == NULL) {
return SSL_FAILURE;
}
/* get class references */
inetsockaddr = (*jenv)->FindClass(jenv, "java/net/InetSocketAddress");
inetaddr = (*jenv)->FindClass(jenv, "java/net/InetAddress");
/* get port */
portID = (*jenv)->GetMethodID(jenv, inetsockaddr, "getPort", "()I");
if (!portID) {
if ((*jenv)->ExceptionOccurred(jenv))
(*jenv)->ExceptionClear(jenv);
throwWolfSSLException(jenv, "Can't get getPort() method ID");
return SSL_FAILURE;
}
(*jenv)->ExceptionClear(jenv);
port = (*jenv)->CallIntMethod(jenv, peer, portID);
if ((*jenv)->ExceptionOccurred(jenv)) {
/* an exception occurred on the Java side, how to handle it? */
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
}
/* get InetAddress object */
addrID = (*jenv)->GetMethodID(jenv, inetsockaddr, "getAddress",
"()Ljava/net/InetAddress;");
if (!addrID) {
if ((*jenv)->ExceptionOccurred(jenv))
(*jenv)->ExceptionClear(jenv);
throwWolfSSLException(jenv, "Can't get getAddress() method ID");
return SSL_FAILURE;
}
(*jenv)->ExceptionClear(jenv);
addrObj = (*jenv)->CallObjectMethod(jenv, peer, addrID);
if ((*jenv)->ExceptionOccurred(jenv)) {
/* an exception occurred on the Java side, how to handle it? */
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
}
/* is this a wildcard address, ie: INADDR_ANY? */
isAnyID = (*jenv)->GetMethodID(jenv, inetaddr, "isAnyLocalAddress", "()Z");
if (!isAnyID) {
if ((*jenv)->ExceptionOccurred(jenv))
(*jenv)->ExceptionClear(jenv);
throwWolfSSLException(jenv, "Can't get isAnyLocalAddress() method ID");
return SSL_FAILURE;
}
(*jenv)->ExceptionClear(jenv);
isAny = (*jenv)->CallBooleanMethod(jenv, addrObj, isAnyID);
if ((*jenv)->ExceptionOccurred(jenv)) {
/* an exception occurred on the Java side, how to handle it? */
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
}
/* get IP address as a String */
if (!isAny) {
ipAddrID = (*jenv)->GetMethodID(jenv, inetaddr,
"getHostAddress", "()Ljava/lang/String;");
if (!ipAddrID) {
if ((*jenv)->ExceptionOccurred(jenv))
(*jenv)->ExceptionClear(jenv);
throwWolfSSLException(jenv, "Can't get getHostAddress() method ID");
return SSL_FAILURE;
}
ipAddr = (*jenv)->CallObjectMethod(jenv, addrObj, ipAddrID);
if ((*jenv)->ExceptionOccurred(jenv)) {
/* an exception occurred on the Java side, how to handle it? */
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
}
/* convert IP string to char* */
ipAddress = (*jenv)->GetStringUTFChars(jenv, ipAddr, 0);
}
/* build sockaddr_in */
memset(&sa, 0, sizeof(struct sockaddr_in));
sa.sin_family = AF_INET;
sa.sin_port = htons((int)port);
if (isAny) {
sa.sin_addr.s_addr = INADDR_ANY;
} else {
if (XINET_PTON(AF_INET, ipAddress, &sa.sin_addr.s_addr) < 1) {
ret = SSL_FAILURE;
}
}
if (ret == SSL_SUCCESS) {
/* call native wolfSSL function */
ret = wolfSSL_dtls_set_peer(ssl, &sa, sizeof(sa));
}
if (!isAny) {
(*jenv)->ReleaseStringUTFChars(jenv, ipAddr, ipAddress);
}
return ret;
}
/* max IP size IPv4 mapped IPv6 */
#define MAX_EXPORT_IP 46
JNIEXPORT jobject JNICALL Java_com_wolfssl_WolfSSLSession_dtlsGetPeer
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
int ret, port;
unsigned int peerSz;
struct sockaddr_in peer;
#ifdef USE_WINDOWS_API
int ipAddrStringSz = MAX_EXPORT_IP;
WCHAR ipAddrWStr[MAX_EXPORT_IP];
char ipAddrString[MAX_EXPORT_IP];
#else
char ipAddrString[MAX_EXPORT_IP];
#endif
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
jmethodID constr;
jstring ipAddr;
jclass isa = NULL;
(void)jcl;
if (jenv == NULL || ssl == NULL) {
return NULL;
}
/* get native sockaddr_in peer */
memset(&peer, 0, sizeof(peer));
peerSz = sizeof(peer);
ret = wolfSSL_dtls_get_peer(ssl, &peer, &peerSz);
if (ret != SSL_SUCCESS) {
return NULL;
}
XMEMSET(ipAddrString, 0, sizeof(ipAddrString));
#ifdef USE_WINDOWS_API
if (XINET_NTOP((int)peer.sin_family, &(peer.sin_addr),
ipAddrWStr, INET_ADDRSTRLEN) == NULL) {
return NULL;
}
/* Convert WCHAR to char* */
if (WideCharToMultiByte(CP_ACP, 0, ipAddrWStr, -1, ipAddrString,
MAX_EXPORT_IP, NULL, NULL) == 0) {
return NULL;
}
#else
if (XINET_NTOP(AF_INET, &(peer.sin_addr),
ipAddrString, INET_ADDRSTRLEN) == NULL) {
return NULL;
}
#endif
port = ntohs(peer.sin_port);
/* create new InetSocketAddress with this IP/port info */
isa = (*jenv)->FindClass(jenv, "java/net/InetSocketAddress");
if (!isa) {
if ((*jenv)->ExceptionOccurred(jenv))
(*jenv)->ExceptionClear(jenv);
throwWolfSSLException(jenv, "Can't find InetSocketAddress class");
return NULL;
}
/* create jstring from char* */
ipAddr = (*jenv)->NewStringUTF(jenv, ipAddrString);
/* find correct InetSocketAddress constructor */
if (peer.sin_addr.s_addr != INADDR_ANY) {
constr = (*jenv)->GetMethodID(jenv, isa, "<init>",
"(Ljava/lang/String;I)V");
if (!constr) {
if ((*jenv)->ExceptionOccurred(jenv))
(*jenv)->ExceptionClear(jenv);
throwWolfSSLException(jenv,
"Can't find InetSocketAddress(String,port)");
return NULL;
}
return (*jenv)->NewObject(jenv, isa, constr, ipAddr, port);
} else { /* sockaddr_in was created with INADDR_ANY, use wildcard IP */
constr = (*jenv)->GetMethodID(jenv, isa, "<init>",
"(I)V");
if (!constr) {
if ((*jenv)->ExceptionOccurred(jenv))
(*jenv)->ExceptionClear(jenv);
throwWolfSSLException(jenv,
"Can't find InetSocketAddress(port)");
return NULL;
}
return (*jenv)->NewObject(jenv, isa, constr, port);
}
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_sendHrrCookie
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jbyteArray secret)
{
int ret = SSL_FAILURE;
#ifdef WOLFSSL_SEND_HRR_COOKIE
byte* secretBuf = NULL;
word32 secretSz = 0;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
if (jenv == NULL || ssl == NULL) {
return BAD_FUNC_ARG;
}
if (secret != NULL) {
secretBuf = (byte*)(*jenv)->GetByteArrayElements(jenv, secret, NULL);
secretSz = (*jenv)->GetArrayLength(jenv, secret);
}
ret = wolfSSL_send_hrr_cookie(ssl, secretBuf, secretSz);
if (secret != NULL) {
(*jenv)->ReleaseByteArrayElements(jenv, secret,
(jbyte*)secretBuf, JNI_ABORT);
}
#else
ret = NOT_COMPILED_IN;
(void)jenv;
(void)jcl;
(void)sslPtr;
(void)secret;
#endif /* WOLFSSL_SEND_HRR_COOKIE */
return (jint)ret;
}
JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLSession_getDtlsMacDropCount
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
word32 dropCount = 0;
#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_DTLS_DROP_STATS)
int ret = 0;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
/* checks ssl for NULL internally */
ret = wolfSSL_dtls_get_drop_stats(ssl, &dropCount, NULL);
if (ret != WOLFSSL_SUCCESS) {
return (jlong)ret;
}
#endif
(void)jenv;
(void)jcl;
return (jlong)dropCount;
}
JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLSession_getDtlsReplayDropCount
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
word32 dropCount = 0;
#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_DTLS_DROP_STATS)
int ret = 0;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
/* checks ssl for NULL internally */
ret = wolfSSL_dtls_get_drop_stats(ssl, NULL, &dropCount);
if (ret != WOLFSSL_SUCCESS) {
return (jlong)ret;
}
#endif
(void)jenv;
(void)jcl;
return (jlong)dropCount;
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_setMTU
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jint mtu)
{
#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_DTLS_MTU)
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
/* wolfSSL_dtls_set_mtu() checks ssl for NULL */
return (jint)wolfSSL_dtls_set_mtu(ssl, (unsigned short)mtu);
#else
(void)jenv;
(void)jcl;
(void)sslPtr;
(void)mtu;
return (jint)NOT_COMPILED_IN;
#endif
}
JNIEXPORT jstring JNICALL Java_com_wolfssl_WolfSSLSession_stateStringLong
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
#ifdef OPENSSL_EXTRA
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
const char* stateString;
jstring stateStr = NULL;
(void)jcl;
if (jenv == NULL || ssl == NULL) {
return NULL;
}
stateString = wolfSSL_state_string_long(ssl);
if (stateString != NULL) {
stateStr = (*jenv)->NewStringUTF(jenv, stateString);
}
return stateStr;
#else
(void)jenv;
(void)jcl;
(void)sslPtr;
return NULL;
#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_getMaxOutputSize
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
#ifndef NO_TLS
int ret;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
if (jenv == NULL || ssl == NULL) {
return 0;
}
ret = wolfSSL_GetMaxOutputSize(ssl);
return (jint)ret;
#else
(void)jenv;
(void)jcl;
(void)sslPtr;
return (jint)NOT_COMPILED_IN;
#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_sessionReused
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
if (ssl == NULL) {
throwWolfSSLException(jenv,
"Input WolfSSLSession object was null in sessionReused()");
return SSL_FAILURE;
}
return wolfSSL_session_reused(ssl);
}
JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLSession_getPeerCertificate
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
#ifdef KEEP_PEER_CERT
WOLFSSL_X509* x509 = NULL;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jenv;
(void)jcl;
if (ssl == NULL) {
return (jlong)0;
}
x509 = wolfSSL_get_peer_certificate(ssl);
return (jlong)(uintptr_t)x509;
#else
(void)jenv;
(void)jcl;
(void)sslPtr;
return (jlong)0;
#endif
}
JNIEXPORT jstring JNICALL Java_com_wolfssl_WolfSSLSession_getPeerX509Issuer
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jlong x509Ptr)
{
#if defined(KEEP_PEER_CERT) || defined(SESSION_CERTS)
char* issuer;
jstring retString;
WOLFSSL_X509* x509 = (WOLFSSL_X509*)(uintptr_t)x509Ptr;
(void)sslPtr;
(void)jcl;
if (x509 == NULL) {
return NULL;
}
issuer = wolfSSL_X509_NAME_oneline(
wolfSSL_X509_get_issuer_name(x509), 0, 0);
retString = (*jenv)->NewStringUTF(jenv, issuer);
XFREE(issuer, 0, DYNAMIC_TYPE_OPENSSL);
return retString;
#else
(void)jenv;
(void)jcl;
(void)sslPtr;
(void)x509Ptr;
return NULL;
#endif
}
JNIEXPORT jstring JNICALL Java_com_wolfssl_WolfSSLSession_getPeerX509Subject
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jlong x509Ptr)
{
#if defined(KEEP_PEER_CERT) || defined(SESSION_CERTS)
char* subject;
jstring retString;
WOLFSSL_X509* x509 = (WOLFSSL_X509*)(uintptr_t)x509Ptr;
(void)sslPtr;
(void)jcl;
if (x509 == NULL) {
return NULL;
}
subject = wolfSSL_X509_NAME_oneline(
wolfSSL_X509_get_subject_name(x509), 0, 0);
retString = (*jenv)->NewStringUTF(jenv, subject);
XFREE(subject, 0, DYNAMIC_TYPE_OPENSSL);
return retString;
#else
(void)jenv;
(void)jcl;
(void)sslPtr;
(void)x509Ptr;
return NULL;
#endif
}
JNIEXPORT jstring JNICALL Java_com_wolfssl_WolfSSLSession_getPeerX509AltName
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jlong x509Ptr)
{
#if defined(KEEP_PEER_CERT) || defined(SESSION_CERTS)
char* altname;
jstring retString;
WOLFSSL_X509* x509 = (WOLFSSL_X509*)(uintptr_t)x509Ptr;
(void)jcl;
(void)sslPtr;
if (x509 == NULL) {
return NULL;
}
altname = wolfSSL_X509_get_next_altname(x509);
retString = (*jenv)->NewStringUTF(jenv, altname);
return retString;
#else
(void)jenv;
(void)jcl;
(void)sslPtr;
(void)x509Ptr;
return NULL;
#endif
}
JNIEXPORT jstring JNICALL Java_com_wolfssl_WolfSSLSession_getVersion
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
if (ssl == NULL) {
throwWolfSSLException(jenv,
"Input WolfSSLSession object was null in getVersion");
return NULL;
}
return (*jenv)->NewStringUTF(jenv, wolfSSL_get_version(ssl));
}
JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLSession_getCurrentCipher
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
if (ssl == NULL) {
throwWolfSSLException(jenv,
"Input WolfSSLSession object was null in getVersion");
return SSL_FAILURE;
}
return (jlong)(uintptr_t)wolfSSL_get_current_cipher(ssl);
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_checkDomainName
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jstring dn)
{
int ret;
const char* dname;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
if(dn == NULL) {
return SSL_FAILURE;
}
if (ssl == NULL) {
throwWolfSSLException(jenv,
"Input WolfSSLSession object was null in checkDomainName");
return SSL_FAILURE;
}
dname = (*jenv)->GetStringUTFChars(jenv, dn, 0);
ret = wolfSSL_check_domain_name(ssl, dname);
(*jenv)->ReleaseStringUTFChars(jenv, dn, dname);
return ret;
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_setTmpDH
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jbyteArray p, jint pSz,
jbyteArray g, jint gSz)
{
#ifndef NO_DH
int ret;
unsigned char* pBuf = NULL;
unsigned char* gBuf = NULL;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
if (jenv == NULL || p == NULL || g == NULL) {
return BAD_FUNC_ARG;
}
if (ssl == NULL) {
throwWolfSSLException(jenv,
"Input WolfSSLSession object was null in setTmpDH");
return SSL_FAILURE;
}
pBuf = (unsigned char*)XMALLOC((int)pSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (pBuf == NULL) {
return MEMORY_E;
}
XMEMSET(pBuf, 0, pSz);
gBuf = (unsigned char*)XMALLOC((int)gSz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (gBuf == NULL) {
XFREE(pBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return MEMORY_E;
}
XMEMSET(gBuf, 0, gSz);
(*jenv)->GetByteArrayRegion(jenv, p, 0, pSz, (jbyte*)pBuf);
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
XFREE(pBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(gBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return SSL_FAILURE;
}
(*jenv)->GetByteArrayRegion(jenv, g, 0, gSz, (jbyte*)gBuf);
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
XFREE(pBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(gBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return SSL_FAILURE;
}
ret = wolfSSL_SetTmpDH(ssl, pBuf, pSz, gBuf, gSz);
XFREE(pBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
XFREE(gBuf, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return ret;
#else
(void)jenv;
(void)jcl;
(void)sslPtr;
(void)p;
(void)pSz;
(void)g;
(void)gSz;
return NOT_COMPILED_IN;
#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_setTmpDHFile
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jstring file, jint format)
{
#if !defined(NO_DH) && !defined(NO_FILESYSTEM)
int ret;
const char* fname;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
if (file == NULL) {
return SSL_BAD_FILE;
}
if (ssl == NULL) {
throwWolfSSLException(jenv,
"Input WolfSSLSession object was null in setTmpDHFile");
return SSL_FAILURE;
}
fname = (*jenv)->GetStringUTFChars(jenv, file, 0);
ret = wolfSSL_SetTmpDH_file(ssl, fname, format);
(*jenv)->ReleaseStringUTFChars(jenv, file, fname);
return ret;
#else
(void)jenv;
(void)jcl;
(void)sslPtr;
(void)file;
(void)format;
return NOT_COMPILED_IN;
#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_useCertificateBuffer
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jbyteArray in, jlong sz,
jint format)
{
int ret = SSL_SUCCESS;
unsigned char* buff = NULL;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
if (jenv == NULL || in == NULL) {
return BAD_FUNC_ARG;
}
if (ssl == NULL) {
throwWolfSSLException(jenv,
"Input WolfSSLSession object was null in useCertificateBuffer");
return SSL_FAILURE;
}
buff = (unsigned char*)XMALLOC((int)sz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (buff == NULL) {
return MEMORY_E;
}
XMEMSET(buff, 0, (int)sz);
(*jenv)->GetByteArrayRegion(jenv, in, 0, (long)sz, (jbyte*)buff);
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
XFREE(buff, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return SSL_FAILURE;
}
ret = wolfSSL_use_certificate_buffer(ssl, buff, (long)sz, format);
XFREE(buff, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return ret;
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_usePrivateKeyBuffer
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jbyteArray in, jlong sz,
jint format)
{
int ret;
unsigned char* buff = NULL;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
if (jenv == NULL || in == NULL) {
return BAD_FUNC_ARG;
}
if (ssl == NULL) {
throwWolfSSLException(jenv,
"Input WolfSSLSession object was null in usePrivateKeyBuffer");
return SSL_FAILURE;
}
buff = (unsigned char*)XMALLOC((long)sz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (buff == NULL) {
return MEMORY_E;
}
XMEMSET(buff, 0, (long)sz);
(*jenv)->GetByteArrayRegion(jenv, in, 0, (long)sz, (jbyte*)buff);
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
XFREE(buff, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return SSL_FAILURE;
}
ret = wolfSSL_use_PrivateKey_buffer(ssl, buff, (long)sz, format);
XFREE(buff, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return ret;
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_useCertificateChainBuffer
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jbyteArray in, jlong sz)
{
int ret;
unsigned char* buff = NULL;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
if (jenv == NULL || in == NULL) {
return BAD_FUNC_ARG;
}
if (ssl == NULL) {
throwWolfSSLException(jenv,
"Input WolfSSLSession object was null in "
"useCertificateChainBuffer");
return SSL_FAILURE;
}
buff = (unsigned char*)XMALLOC((long)sz, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (buff == NULL) {
return MEMORY_E;
}
XMEMSET(buff, 0, (long)sz);
(*jenv)->GetByteArrayRegion(jenv, in, 0, (long)sz, (jbyte*)buff);
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
XFREE(buff, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return SSL_FAILURE;
}
ret = wolfSSL_use_certificate_chain_buffer(ssl, buff, (long)sz);
XFREE(buff, NULL, DYNAMIC_TYPE_TMP_BUFFER);
return ret;
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_useCertificateChainBufferFormat
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jbyteArray in, jlong sz, jint format)
{
int ret = WOLFSSL_FAILURE;
byte* buff = NULL;
word32 buffSz = 0;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
(void)sz;
if (jenv == NULL || ssl == 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_use_certificate_chain_buffer_format(
ssl, buff, buffSz, format);
}
(*jenv)->ReleaseByteArrayElements(jenv, in, (jbyte*)buff, JNI_ABORT);
return (jint)ret;
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_setGroupMessages
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
if (ssl == NULL) {
throwWolfSSLException(jenv,
"Input WolfSSLSession object was null in setGroupMessages");
return BAD_FUNC_ARG;
}
return wolfSSL_set_group_messages(ssl);
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_enableCRL
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jint options)
{
#ifdef HAVE_CRL
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
if (jenv == NULL) {
return BAD_FUNC_ARG;
}
if (ssl == NULL) {
throwWolfSSLException(jenv,
"Input WolfSSLSession object was null in enableCRL");
return SSL_FAILURE;
}
return wolfSSL_EnableCRL(ssl, options);
#else
(void)jenv;
(void)jcl;
(void)sslPtr;
(void)options;
return NOT_COMPILED_IN;
#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_disableCRL
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
#ifdef HAVE_CRL
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
if (jenv == NULL) {
return BAD_FUNC_ARG;
}
if (ssl == NULL) {
throwWolfSSLException(jenv,
"Input WolfSSLSession object was null in disableCRL");
return SSL_FAILURE;
}
return wolfSSL_DisableCRL(ssl);
#else
(void)jenv;
(void)jcl;
(void)sslPtr;
return NOT_COMPILED_IN;
#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_loadCRL
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jstring path, jint type,
jint monitor)
{
#if defined(HAVE_CRL) && !defined(NO_FILESYSTEM)
int ret;
const char* crlPath;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
if (jenv == NULL || path == NULL) {
return BAD_FUNC_ARG;
}
if (ssl == NULL) {
throwWolfSSLException(jenv,
"Input WolfSSLSession object was null in loadCRL");
return SSL_FAILURE;
}
crlPath = (*jenv)->GetStringUTFChars(jenv, path, 0);
ret = wolfSSL_LoadCRL(ssl, crlPath, type, monitor);
(*jenv)->ReleaseStringUTFChars(jenv, path, crlPath);
return ret;
#else
(void)jenv;
(void)jcl;
(void)sslPtr;
(void)path;
(void)type;
(void)monitor;
return NOT_COMPILED_IN;
#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_setCRLCb
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jobject cb)
{
#ifdef HAVE_CRL
int ret = 0;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
if (jenv == NULL) {
return BAD_FUNC_ARG;
}
if (ssl == NULL) {
throwWolfSSLException(jenv,
"Input WolfSSLSession object was NULL in setCRLCb");
return SSL_FAILURE;
}
/* release global CRL callback ref if already registered */
if (g_crlCbIfaceObj != NULL) {
(*jenv)->DeleteGlobalRef(jenv, g_crlCbIfaceObj);
g_crlCbIfaceObj = NULL;
}
if (cb != NULL) {
/* store Java CRL callback Interface object */
g_crlCbIfaceObj = (*jenv)->NewGlobalRef(jenv, cb);
if (g_crlCbIfaceObj == NULL) {
throwWolfSSLException(jenv,
"Error storing global missingCRLCallback interface");
}
ret = wolfSSL_SetCRL_Cb(ssl, NativeMissingCRLCallback);
}
return ret;
#else
(void)jenv;
(void)jcl;
(void)sslPtr;
(void)cb;
return NOT_COMPILED_IN;
#endif
}
#ifdef HAVE_CRL
void NativeMissingCRLCallback(const char* url)
{
JNIEnv* jenv;
jint vmret = 0;
jclass crlClass = NULL;
jmethodID crlMethod = NULL;
jobjectRefType refcheck;
jstring missingUrl = NULL;
/* 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");
}
/* check if our stored object reference is valid */
refcheck = (*jenv)->GetObjectRefType(jenv, g_crlCbIfaceObj);
if (refcheck == 2) {
/* lookup WolfSSLMissingCRLCallback class from global object ref */
crlClass = (*jenv)->GetObjectClass(jenv, g_crlCbIfaceObj);
if (!crlClass) {
throwWolfSSLException(jenv,
"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);
}
throwWolfSSLException(jenv,
"Error getting missingCRLCallback method from JNI");
return;
}
/* create jstring from char* */
missingUrl = (*jenv)->NewStringUTF(jenv, url);
(*jenv)->CallVoidMethod(jenv, g_crlCbIfaceObj, crlMethod, missingUrl);
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
return;
}
} else {
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
}
throwWolfSSLException(jenv,
"Object reference invalid in NativeMissingCRLCallback");
}
}
#endif /* HAVE_CRL */
JNIEXPORT jstring JNICALL Java_com_wolfssl_WolfSSLSession_cipherGetName
(JNIEnv* jenv, jclass jcl, jlong sslPtr)
{
const char* cipherName;
WOLFSSL_CIPHER* cipher;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
if (ssl == NULL) {
throwWolfSSLException(jenv,
"Input WolfSSLSession object was null in "
"cipherGetName");
return NULL;
}
cipher = wolfSSL_get_current_cipher(ssl);
if (cipher != NULL) {
cipherName = wolfSSL_CIPHER_get_name(cipher);
return (*jenv)->NewStringUTF(jenv, cipherName);
} else {
return (*jenv)->NewStringUTF(jenv, "NONE");
}
}
JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_WolfSSLSession_getMacSecret
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jint verify)
{
#ifdef ATOMIC_USER
int macLength;
jbyteArray retSecret;
const unsigned char* secret;
#endif
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
#ifdef ATOMIC_USER
if (ssl == NULL) {
throwWolfSSLException(jenv,
"Input WolfSSLSession object was null in "
"getMacSecret");
return NULL;
}
secret = wolfSSL_GetMacSecret(ssl, (int)verify);
if (secret != NULL) {
/* get mac size */
macLength = wolfSSL_GetHmacSize(ssl);
/* create byte array to return */
retSecret = (*jenv)->NewByteArray(jenv, macLength);
if (!retSecret) {
throwWolfSSLException(jenv,
"Failed to create byte array in native getMacSecret");
return NULL;
}
(*jenv)->SetByteArrayRegion(jenv, retSecret, 0, macLength,
(jbyte*)secret);
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
return NULL;
}
return retSecret;
} else {
return NULL;
}
#else
throwWolfSSLException(jenv,
"wolfSSL not compiled with ATOMIC_USER");
return NULL;
#endif
}
JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_WolfSSLSession_getClientWriteKey
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
#ifdef ATOMIC_USER
int keyLength;
jbyteArray retKey;
const unsigned char* key;
#endif
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
#ifdef ATOMIC_USER
if (ssl == NULL) {
throwWolfSSLException(jenv,
"Input WolfSSLSession object was null in "
"getClientWriteKey");
return NULL;
}
key = wolfSSL_GetClientWriteKey(ssl);
if (key != NULL) {
/* get key size */
keyLength = wolfSSL_GetKeySize(ssl);
/* create byte array to return */
retKey = (*jenv)->NewByteArray(jenv, keyLength);
if (!retKey) {
throwWolfSSLException(jenv,
"Failed to create byte array in native getClientWriteKey");
return NULL;
}
(*jenv)->SetByteArrayRegion(jenv, retKey, 0, keyLength,
(jbyte*)key);
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
return NULL;
}
return retKey;
} else {
return NULL;
}
#else
throwWolfSSLException(jenv,
"wolfSSL not compiled with ATOMIC_USER");
return NULL;
#endif
}
JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_WolfSSLSession_getClientWriteIV
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
#ifdef ATOMIC_USER
jbyteArray retIV;
const unsigned char* iv;
int ivLength;
#endif
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
#ifdef ATOMIC_USER
if (ssl == NULL) {
throwWolfSSLException(jenv,
"Input WolfSSLSession object was null in "
"getClientWriteIV");
return NULL;
}
iv = wolfSSL_GetClientWriteIV(ssl);
if (iv != NULL) {
/* get iv size, is block size for what wolfSSL supports */
ivLength = wolfSSL_GetCipherBlockSize(ssl);
/* create byte array to return */
retIV = (*jenv)->NewByteArray(jenv, ivLength);
if (!retIV) {
throwWolfSSLException(jenv,
"Failed to create byte array in native getClientWriteIV");
return NULL;
}
(*jenv)->SetByteArrayRegion(jenv, retIV, 0, ivLength,
(jbyte*)iv);
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
return NULL;
}
return retIV;
} else {
return NULL;
}
#else
throwWolfSSLException(jenv,
"wolfSSL not compiled with ATOMIC_USER");
return NULL;
#endif
}
JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_WolfSSLSession_getServerWriteKey
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
#ifdef ATOMIC_USER
jbyteArray retKey;
const unsigned char* key;
int keyLength;
#endif
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
#ifdef ATOMIC_USER
if (ssl == NULL) {
throwWolfSSLException(jenv,
"Input WolfSSLSession object was null in "
"getServerWriteKey");
return NULL;
}
key = wolfSSL_GetServerWriteKey(ssl);
if (key != NULL) {
/* get key size */
keyLength = wolfSSL_GetKeySize(ssl);
/* create byte array to return */
retKey = (*jenv)->NewByteArray(jenv, keyLength);
if (!retKey) {
throwWolfSSLException(jenv,
"Failed to create byte array in native getServerWriteKey");
return NULL;
}
(*jenv)->SetByteArrayRegion(jenv, retKey, 0, keyLength,
(jbyte*)key);
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
return NULL;
}
return retKey;
} else {
return NULL;
}
#else
throwWolfSSLException(jenv,
"wolfSSL not compiled with ATOMIC_USER");
return NULL;
#endif
}
JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_WolfSSLSession_getServerWriteIV
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
#ifdef ATOMIC_USER
jbyteArray retIV;
const unsigned char* iv;
int ivLength;
#endif
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
#ifdef ATOMIC_USER
if (ssl == NULL) {
throwWolfSSLException(jenv,
"Input WolfSSLSession object was null in "
"getServerWriteIV");
return NULL;
}
iv = wolfSSL_GetServerWriteIV(ssl);
if (iv != NULL) {
/* get iv size, is block size for what wolfSSL supports */
ivLength = wolfSSL_GetCipherBlockSize(ssl);
/* create byte array to return */
retIV = (*jenv)->NewByteArray(jenv, ivLength);
if (!retIV) {
throwWolfSSLException(jenv,
"Failed to create byte array in native getServerWriteIV");
return NULL;
}
(*jenv)->SetByteArrayRegion(jenv, retIV, 0, ivLength,
(jbyte*)iv);
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
return NULL;
}
return retIV;
} else {
return NULL;
}
#else
throwWolfSSLException(jenv,
"wolfSSL not compiled with ATOMIC_USER");
return NULL;
#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_getKeySize
(JNIEnv* jenv, jobject jcl, jlong ssl)
{
(void)jenv;
(void)jcl;
#ifdef ATOMIC_USER
/* wolfSSL checks ssl for NULL */
return wolfSSL_GetKeySize((WOLFSSL*)(uintptr_t)ssl);
#else
return NOT_COMPILED_IN;
#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_getSide
(JNIEnv* jenv, jobject jcl, jlong ssl)
{
(void)jenv;
(void)jcl;
/* wolfSSL checks ssl for NULL */
return wolfSSL_GetSide((WOLFSSL*)(uintptr_t)ssl);
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_isTLSv1_11
(JNIEnv* jenv, jobject jcl, jlong ssl)
{
(void)jenv;
(void)jcl;
#ifdef ATOMIC_USER
/* wolfSSL checks ssl for NULL */
return wolfSSL_IsTLSv1_1((WOLFSSL*)(uintptr_t)ssl);
#else
return NOT_COMPILED_IN;
#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_getBulkCipher
(JNIEnv* jenv, jobject jcl, jlong ssl)
{
(void)jenv;
(void)jcl;
#ifdef ATOMIC_USER
/* wolfSSL checks ssl for NULL */
return wolfSSL_GetBulkCipher((WOLFSSL*)(uintptr_t)ssl);
#else
return NOT_COMPILED_IN;
#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_getCipherBlockSize
(JNIEnv* jenv, jobject jcl, jlong ssl)
{
(void)jenv;
(void)jcl;
#ifdef ATOMIC_USER
/* wolfSSL checks ssl for NULL */
return wolfSSL_GetCipherBlockSize((WOLFSSL*)(uintptr_t)ssl);
#else
return NOT_COMPILED_IN;
#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_getAeadMacSize
(JNIEnv* jenv, jobject jcl, jlong ssl)
{
(void)jenv;
(void)jcl;
#ifdef ATOMIC_USER
/* wolfSSL checks ssl for NULL */
return wolfSSL_GetAeadMacSize((WOLFSSL*)(uintptr_t)ssl);
#else
return NOT_COMPILED_IN;
#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_getHmacSize
(JNIEnv* jenv, jobject jcl, jlong ssl)
{
(void)jenv;
(void)jcl;
#ifdef ATOMIC_USER
/* wolfSSL checks ssl for NULL */
return wolfSSL_GetHmacSize((WOLFSSL*)(uintptr_t)ssl);
#else
return NOT_COMPILED_IN;
#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_getHmacType
(JNIEnv* jenv, jobject jcl, jlong ssl)
{
(void)jenv;
(void)jcl;
/* wolfSSL checks ssl for NULL */
return wolfSSL_GetHmacType((WOLFSSL*)(uintptr_t)ssl);
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_getCipherType
(JNIEnv* jenv, jobject jcl, jlong ssl)
{
(void)jenv;
(void)jcl;
#ifdef ATOMIC_USER
/* wolfSSL checks ssl for NULL */
return wolfSSL_GetCipherType((WOLFSSL*)(uintptr_t)ssl);
#else
return NOT_COMPILED_IN;
#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_setTlsHmacInner
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jbyteArray inner, jlong sz,
jint content, jint verify)
{
int ret = 0;
unsigned char hmacInner[WOLFSSL_TLS_HMAC_INNER_SZ];
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
if (jenv == NULL || inner == NULL || ssl == NULL) {
return BAD_FUNC_ARG;
}
ret = wolfSSL_SetTlsHmacInner(ssl, hmacInner, (long)sz, content, verify);
/* copy hmacInner back into inner jbyteArray */
(*jenv)->SetByteArrayRegion(jenv, inner, 0, WOLFSSL_TLS_HMAC_INNER_SZ,
(jbyte*)hmacInner);
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
throwWolfSSLException(jenv,
"Failed to set byte region in native setTlsHmacInner");
return -1;
}
return ret;
}
JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLSession_setEccSignCtx
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
#if defined(HAVE_PK_CALLBACKS) && defined(HAVE_ECC)
jclass sslClass;
void* eccSignCtx;
internCtx* myCtx;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
#endif
#if defined(HAVE_PK_CALLBACKS) && defined(HAVE_ECC)
if (ssl == NULL) {
throwWolfSSLException(jenv,
"Input WolfSSLSession object was null in "
"setEccSignCtx");
return;
}
/* get WolfSSLSession class from object ref */
sslClass = (*jenv)->GetObjectClass(jenv, jcl);
if (!sslClass) {
throwWolfSSLException(jenv,
"Can't get WolfSSLSession object class");
return;
}
/* free existing memory if it already exists, before we malloc again */
eccSignCtx = (internCtx*) wolfSSL_GetEccSignCtx(ssl);
/* note: if CTX has not been set up yet, wolfSSL defaults to NULL */
if (eccSignCtx != NULL) {
myCtx = (internCtx*)eccSignCtx;
if (myCtx != NULL) {
if (myCtx->active == 1) {
(*jenv)->DeleteGlobalRef(jenv, myCtx->obj);
}
XFREE(myCtx, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
}
/* allocate memory for internal JNI object reference */
myCtx = XMALLOC(sizeof(internCtx), NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (!myCtx) {
throwWolfSSLException(jenv,
"Unable to allocate memory for ECC sign context\n");
return;
}
/* set CTX as active */
myCtx->active = 1;
/* store global ref to WolfSSLSession object */
myCtx->obj = (*jenv)->NewGlobalRef(jenv, jcl);
if (!myCtx->obj) {
throwWolfSSLException(jenv,
"Unable to store WolfSSLSession object as global reference");
return;
}
wolfSSL_SetEccSignCtx(ssl, myCtx);
#else
(void)jcl;
(void)sslPtr;
throwWolfSSLException(jenv,
"wolfSSL not compiled with PK Callbacks and/or ECC");
return;
#endif
}
JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLSession_setEccVerifyCtx
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
#if defined(HAVE_PK_CALLBACKS) && defined(HAVE_ECC)
jclass sslClass;
void* eccVerifyCtx;
internCtx* myCtx;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
#endif
#if defined(HAVE_PK_CALLBACKS) && defined(HAVE_ECC)
if (ssl == NULL) {
throwWolfSSLException(jenv,
"Input WolfSSLSession object was null in "
"setEccVerifyCtx");
return;
}
/* get WolfSSLSession class from object ref */
sslClass = (*jenv)->GetObjectClass(jenv, jcl);
if (!sslClass) {
throwWolfSSLException(jenv,
"Can't get WolfSSLSession object class");
return;
}
/* free existing memory if it already exists, before we malloc again */
eccVerifyCtx = (internCtx*)wolfSSL_GetEccVerifyCtx(ssl);
/* note: if CTX has not been set up yet, wolfSSL defaults to NULL */
if (eccVerifyCtx != NULL) {
myCtx = (internCtx*)eccVerifyCtx;
if (myCtx != NULL) {
if (myCtx->active == 1) {
(*jenv)->DeleteGlobalRef(jenv, myCtx->obj);
}
XFREE(myCtx, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
}
/* allocate memory for internal JNI object reference */
myCtx = XMALLOC(sizeof(internCtx), NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (!myCtx) {
throwWolfSSLException(jenv,
"Unable to allocate memory for ECC verify context\n");
return;
}
/* set CTX as active */
myCtx->active = 1;
/* store global ref to WolfSSLSession object */
myCtx->obj = (*jenv)->NewGlobalRef(jenv, jcl);
if (myCtx->obj == NULL) {
throwWolfSSLException(jenv,
"Unable to store WolfSSLSession object as global reference");
return;
}
wolfSSL_SetEccVerifyCtx(ssl, myCtx);
#else
(void)jcl;
(void)sslPtr;
throwWolfSSLException(jenv,
"wolfSSL not compiled with PK Callbacks and/or ECC");
return;
#endif
}
JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLSession_setEccSharedSecretCtx
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
#if defined(HAVE_PK_CALLBACKS) && defined(HAVE_ECC)
jclass sslClass;
void* eccSharedSecretCtx;
internCtx* myCtx;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
#endif
#if defined(HAVE_PK_CALLBACKS) && defined(HAVE_ECC)
if (ssl == NULL) {
throwWolfSSLException(jenv,
"Input WolfSSLSession object was null in "
"setEccSharedSecretCtx");
return;
}
/* get WolfSSLSession class from object ref */
sslClass = (*jenv)->GetObjectClass(jenv, jcl);
if (!sslClass) {
throwWolfSSLException(jenv,
"Can't get WolfSSLSession object class");
return;
}
/* free existing memory if it already exists, before we malloc again */
eccSharedSecretCtx = (internCtx*) wolfSSL_GetEccSharedSecretCtx(ssl);
/* note: if CTX has not been set up yet, wolfSSL defaults to NULL */
if (eccSharedSecretCtx != NULL) {
myCtx = (internCtx*)eccSharedSecretCtx;
if (myCtx != NULL) {
if (myCtx->active == 1) {
(*jenv)->DeleteGlobalRef(jenv, myCtx->obj);
}
XFREE(myCtx, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
}
/* allocate memory for internal JNI object reference */
myCtx = XMALLOC(sizeof(internCtx), NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (myCtx == NULL) {
throwWolfSSLException(jenv,
"Unable to allocate memory for ECC shared secret context\n");
return;
}
/* set CTX as active */
myCtx->active = 1;
/* store global ref to WolfSSLSession object */
myCtx->obj = (*jenv)->NewGlobalRef(jenv, jcl);
if (myCtx->obj == NULL) {
throwWolfSSLException(jenv,
"Unable to store WolfSSLSession object as global reference");
return;
}
wolfSSL_SetEccSharedSecretCtx(ssl, myCtx);
#else
(void)jcl;
(void)sslPtr;
throwWolfSSLException(jenv,
"wolfSSL not compiled with PK Callbacks and/or ECC");
return;
#endif
}
JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLSession_setRsaSignCtx
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
#if defined(HAVE_PK_CALLBACKS) && !defined(NO_RSA)
jclass sslClass;
void* rsaSignCtx;
internCtx* myCtx;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
#endif
#if defined(HAVE_PK_CALLBACKS) && !defined(NO_RSA)
if (ssl == NULL) {
throwWolfSSLException(jenv,
"Input WolfSSLSession object was null in "
"setRsaSignCtx");
return;
}
/* get WolfSSLSession class from object ref */
sslClass = (*jenv)->GetObjectClass(jenv, jcl);
if (!sslClass) {
throwWolfSSLException(jenv,
"Can't get WolfSSLSession object class");
return;
}
/* free existing memory if it already exists, before we malloc again */
rsaSignCtx = (internCtx*) wolfSSL_GetRsaSignCtx(ssl);
/* note: if CTX has not been set up yet, wolfSSL defaults to NULL */
if (rsaSignCtx != NULL) {
myCtx = (internCtx*)rsaSignCtx;
if (myCtx != NULL) {
if (myCtx->active == 1) {
(*jenv)->DeleteGlobalRef(jenv, myCtx->obj);
}
XFREE(myCtx, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
}
/* allocate memory for internal JNI object reference */
myCtx = XMALLOC(sizeof(internCtx), NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (myCtx == NULL) {
throwWolfSSLException(jenv,
"Unable to allocate memory for RSA sign context\n");
return;
}
/* set CTX as active */
myCtx->active = 1;
/* store global ref to WolfSSLSession object */
myCtx->obj = (*jenv)->NewGlobalRef(jenv, jcl);
if (myCtx->obj == NULL) {
throwWolfSSLException(jenv,
"Unable to store WolfSSLSession object as global reference");
return;
}
wolfSSL_SetRsaSignCtx(ssl, myCtx);
#else
(void)jcl;
(void)sslPtr;
throwWolfSSLException(jenv,
"wolfSSL not compiled with PK Callbacks and/or RSA support");
return;
#endif
}
JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLSession_setRsaVerifyCtx
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
#if defined(HAVE_PK_CALLBACKS) && !defined(NO_RSA)
jclass sslClass;
void* rsaVerifyCtx;
internCtx* myCtx;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
#endif
#if defined(HAVE_PK_CALLBACKS) && !defined(NO_RSA)
if (ssl == NULL) {
throwWolfSSLException(jenv,
"Input WolfSSLSession object was null in "
"setRsaVerifyCtx");
return;
}
/* get WolfSSLSession class from object ref */
sslClass = (*jenv)->GetObjectClass(jenv, jcl);
if (!sslClass) {
throwWolfSSLException(jenv,
"Can't get WolfSSLSession object class");
return;
}
/* free existing memory if it already exists, before we malloc again */
rsaVerifyCtx = (internCtx*)wolfSSL_GetRsaVerifyCtx(ssl);
/* note: if CTX has not been set up yet, wolfSSL defaults to NULL */
if (rsaVerifyCtx != NULL) {
myCtx = (internCtx*)rsaVerifyCtx;
if (myCtx != NULL) {
if (myCtx->active == 1) {
(*jenv)->DeleteGlobalRef(jenv, myCtx->obj);
}
XFREE(myCtx, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
}
/* allocate memory for internal JNI object reference */
myCtx = XMALLOC(sizeof(internCtx), NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (myCtx == NULL) {
throwWolfSSLException(jenv,
"Unable to allocate memory for RSA verify context\n");
return;
}
/* set CTX as active */
myCtx->active = 1;
/* store global ref to WolfSSLSession object */
myCtx->obj = (*jenv)->NewGlobalRef(jenv, jcl);
if (myCtx->obj == NULL) {
throwWolfSSLException(jenv,
"Unable to store WolfSSLSession object as global reference");
return;
}
wolfSSL_SetRsaVerifyCtx(ssl, myCtx);
#else
(void)jcl;
(void)sslPtr;
throwWolfSSLException(jenv,
"wolfSSL not compiled with PK Callbacks and/or RSA support");
return;
#endif
}
JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLSession_setRsaEncCtx
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
#if defined(HAVE_PK_CALLBACKS) && !defined(NO_RSA)
jclass sslClass;
void* rsaEncCtx;
internCtx* myCtx;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
#endif
#if defined(HAVE_PK_CALLBACKS) && !defined(NO_RSA)
if (ssl == NULL) {
throwWolfSSLException(jenv,
"Input WolfSSLSession object was null in "
"setRsaEncCtx");
return;
}
/* get WolfSSLSession class from object ref */
sslClass = (*jenv)->GetObjectClass(jenv, jcl);
if (!sslClass) {
throwWolfSSLException(jenv,
"Can't get WolfSSLSession object class");
return;
}
/* free existing memory if it already exists, before we malloc again */
rsaEncCtx = (internCtx*) wolfSSL_GetRsaEncCtx(ssl);
/* note: if CTX has not been set up yet, wolfSSL defaults to NULL */
if (rsaEncCtx != NULL) {
myCtx = (internCtx*)rsaEncCtx;
if (myCtx != NULL) {
if (myCtx->active == 1) {
(*jenv)->DeleteGlobalRef(jenv, myCtx->obj);
}
XFREE(myCtx, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
}
/* allocate memory for internal JNI object reference */
myCtx = XMALLOC(sizeof(internCtx), NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (myCtx == NULL) {
throwWolfSSLException(jenv,
"Unable to allocate memory for RSA encrypt context\n");
return;
}
/* set CTX as active */
myCtx->active = 1;
/* store global ref to WolfSSLSession object */
myCtx->obj = (*jenv)->NewGlobalRef(jenv, jcl);
if (myCtx->obj == NULL) {
throwWolfSSLException(jenv,
"Unable to store WolfSSLSession object as global reference");
return;
}
wolfSSL_SetRsaEncCtx(ssl, myCtx);
#else
(void)jcl;
(void)sslPtr;
throwWolfSSLException(jenv,
"wolfSSL not compiled with PK Callbacks and/or RSA support");
return;
#endif
}
JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLSession_setRsaDecCtx
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
#if defined(HAVE_PK_CALLBACKS) && !defined(NO_RSA)
jclass sslClass;
void* rsaDecCtx;
internCtx* myCtx;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
#endif
#if defined(HAVE_PK_CALLBACKS) && !defined(NO_RSA)
if (ssl == NULL) {
throwWolfSSLException(jenv,
"Input WolfSSLSession object was null in "
"setRsaDecCtx");
return;
}
/* get WolfSSLSession class from object ref */
sslClass = (*jenv)->GetObjectClass(jenv, jcl);
if (!sslClass) {
throwWolfSSLException(jenv,
"Can't get WolfSSLSession object class");
return;
}
/* free existing memory if it already exists, before we malloc again */
rsaDecCtx = (internCtx*) wolfSSL_GetRsaDecCtx(ssl);
/* note: if CTX has not been set up yet, wolfSSL defaults to NULL */
if (rsaDecCtx != NULL) {
myCtx = (internCtx*)rsaDecCtx;
if (myCtx != NULL) {
if (myCtx->active == 1) {
(*jenv)->DeleteGlobalRef(jenv, myCtx->obj);
}
XFREE(myCtx, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
}
/* allocate memory for internal JNI object reference */
myCtx = XMALLOC(sizeof(internCtx), NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (myCtx == NULL) {
throwWolfSSLException(jenv,
"Unable to allocate memory for RSA decrypt context\n");
return;
}
/* set CTX as active */
myCtx->active = 1;
/* store global ref to WolfSSLSession object */
myCtx->obj = (*jenv)->NewGlobalRef(jenv, jcl);
if (myCtx->obj == NULL) {
throwWolfSSLException(jenv,
"Unable to store WolfSSLSession object as global reference");
return;
}
wolfSSL_SetRsaDecCtx(ssl, myCtx);
#else
(void)jcl;
(void)sslPtr;
throwWolfSSLException(jenv,
"wolfSSL not compiled with PK Callbacks and/or RSA support");
return;
#endif
}
JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLSession_setPskClientCb
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
#ifndef NO_PSK
if (ssl != NULL) {
/* set PSK client callback */
wolfSSL_set_psk_client_callback(ssl, NativePskClientCb);
} else {
throwWolfSSLJNIException(jenv,
"Input WolfSSLSession object was null when setting "
"NativePskClientCb");
return;
}
#else
throwWolfSSLJNIException(jenv,
"wolfSSL not compiled with PSK support");
return;
#endif
}
JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLSession_setPskServerCb
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
#ifndef NO_PSK
if (ssl != NULL) {
/* set PSK server callback */
wolfSSL_set_psk_server_callback(ssl, NativePskServerCb);
} else {
throwWolfSSLJNIException(jenv,
"Input WolfSSLSession object was null when setting "
"NativePskServerCb");
return;
}
#else
throwWolfSSLJNIException(jenv,
"wolfSSL not compiled with PSK support");
return;
#endif
}
JNIEXPORT jstring JNICALL Java_com_wolfssl_WolfSSLSession_getPskIdentityHint
(JNIEnv* jenv, jobject obj, jlong sslPtr)
{
#ifndef NO_PSK
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)obj;
if (jenv == NULL || ssl == NULL) {
return NULL;
}
return (*jenv)->NewStringUTF(jenv, wolfSSL_get_psk_identity_hint(ssl));
#else
(void)jenv;
(void)obj;
(void)sslPtr;
return NULL;
#endif
}
JNIEXPORT jstring JNICALL Java_com_wolfssl_WolfSSLSession_getPskIdentity
(JNIEnv* jenv, jobject obj, jlong sslPtr)
{
#ifndef NO_PSK
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)obj;
if (jenv == NULL || ssl == NULL) {
return NULL;
}
return (*jenv)->NewStringUTF(jenv, wolfSSL_get_psk_identity(ssl));
#else
(void)jenv;
(void)obj;
(void)sslPtr;
return NULL;
#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_usePskIdentityHint
(JNIEnv* jenv, jobject obj, jlong sslPtr, jstring hint)
{
#ifndef NO_PSK
jint ret;
const char* nativeHint;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)obj;
if (jenv == NULL || ssl == NULL || hint == NULL) {
return SSL_FAILURE;
}
nativeHint = (*jenv)->GetStringUTFChars(jenv, hint, 0);
ret = (jint)wolfSSL_use_psk_identity_hint(ssl, nativeHint);
(*jenv)->ReleaseStringUTFChars(jenv, hint, nativeHint);
return ret;
#else
(void)jenv;
(void)sslPtr;
(void)hint;
return NOT_COMPILED_IN;
#endif
}
JNIEXPORT jboolean JNICALL Java_com_wolfssl_WolfSSLSession_handshakeDone
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
if (jenv == NULL || ssl == NULL) {
return JNI_FALSE;
}
if (wolfSSL_is_init_finished(ssl)) {
return JNI_TRUE;
}
return JNI_FALSE;
}
JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLSession_setConnectState
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
if (jenv == NULL || ssl == NULL) {
return;
}
wolfSSL_set_connect_state(ssl);
}
JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLSession_setAcceptState
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
if (jenv == NULL || ssl == NULL) {
return;
}
wolfSSL_set_accept_state(ssl);
}
JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLSession_setVerify
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jint mode, jobject callbackIface)
{
jobject* verifyCb = NULL;
SSLAppData* appData = NULL;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
if (jenv == NULL || ssl == NULL) {
return;
}
/* Release global reference if already set, before setting again */
appData = (SSLAppData*)wolfSSL_get_app_data(ssl);
if (appData != NULL) {
verifyCb = appData->g_verifySSLCbIfaceObj;
if (verifyCb != NULL) {
(*jenv)->DeleteGlobalRef(jenv, (jobject)(*verifyCb));
XFREE(verifyCb, NULL, DYNAMIC_TYPE_TMP_BUFFER);
verifyCb = NULL;
appData->g_verifySSLCbIfaceObj = NULL;
}
}
/* Set verify callback to NULL (reset), or passed in callback */
if (!callbackIface) {
wolfSSL_set_verify(ssl, mode, NULL);
}
else {
/* Get app data to store verify callback jobject */
appData = (SSLAppData*)wolfSSL_get_app_data(ssl);
if (appData == NULL) {
printf("Error getting app data from WOLFSSL\n");
}
if (appData != NULL) {
verifyCb = (jobject*)XMALLOC(sizeof(jobject), NULL,
DYNAMIC_TYPE_TMP_BUFFER);
if (verifyCb == NULL) {
printf("Error allocating memory for verifyCb\n");
}
}
if ((appData != NULL) && (verifyCb != NULL)) {
/* store Java verify Interface object */
*verifyCb = (*jenv)->NewGlobalRef(jenv, callbackIface);
if (*verifyCb == NULL) {
printf("error storing global callback interface\n");
XFREE(verifyCb, NULL, DYNAMIC_TYPE_TMP_BUFFER);
}
else {
appData->g_verifySSLCbIfaceObj = verifyCb;
/* set verify mode, register Java callback with wolfSSL */
wolfSSL_set_verify(ssl, mode, NativeSSLVerifyCallback);
}
}
}
}
JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLSession_setOptions
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jlong op)
{
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
if (jenv == NULL || ssl == NULL) {
return 0;
}
return wolfSSL_set_options(ssl, (long)op);
}
JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLSession_getOptions
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
if (jenv == NULL || ssl == NULL) {
return 0;
}
return wolfSSL_get_options(ssl);
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_getShutdown
(JNIEnv *jenv, jobject jcl, jlong sslPtr)
{
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jenv;
(void)jcl;
return (jint)wolfSSL_get_shutdown(ssl);
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_useSNI
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jbyte type, jbyteArray data)
{
int ret = SSL_FAILURE;
#ifdef HAVE_SNI
byte* dataBuf = NULL;
word32 dataSz = 0;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
if (jenv == NULL || ssl == NULL) {
return BAD_FUNC_ARG;
}
dataBuf = (byte*)(*jenv)->GetByteArrayElements(jenv, data, NULL);
dataSz = (*jenv)->GetArrayLength(jenv, data);
if (dataBuf != NULL && dataSz > 0) {
ret = wolfSSL_UseSNI(ssl, (byte)type, dataBuf, (word16)dataSz);
}
(*jenv)->ReleaseByteArrayElements(jenv, data, (jbyte*)dataBuf, JNI_ABORT);
#else
ret = NOT_COMPILED_IN;
(void)jenv;
(void)jcl;
(void)sslPtr;
(void)type;
(void)data;
#endif /* HAVE_SNI */
return (jint)ret;
}
JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_WolfSSLSession_getSNIRequest
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jbyte type)
{
#ifdef HAVE_SNI
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
void* request = NULL;
jbyteArray sniRequest;
word16 ret = 0;
(void)jcl;
if (jenv == NULL || ssl == NULL) {
return NULL;
}
ret = wolfSSL_SNI_GetRequest(ssl, (byte)type, &request);
if (ret > 0) {
sniRequest = (*jenv)->NewByteArray(jenv, ret);
if (sniRequest == NULL) {
(*jenv)->ThrowNew(jenv, jcl,
"Failed to create byte array in native getSNIRequest");
return NULL;
}
(*jenv)->SetByteArrayRegion(jenv, sniRequest, 0, ret,
(jbyte*)request);
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
return NULL;
}
return sniRequest;
}
return NULL;
#else
(void)jenv;
(void)jcl;
(void)sslPtr;
(void)type;
return NULL;
#endif /* HAVE_SNI */
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_useSessionTicket
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
int ret = SSL_FAILURE;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
#ifdef HAVE_SESSION_TICKET
(void)jcl;
if (jenv == NULL || ssl == NULL) {
return BAD_FUNC_ARG;
}
ret = wolfSSL_UseSessionTicket(ssl);
#else
(void)jenv;
(void)jcl;
(void)sslPtr;
ret = NOT_COMPILED_IN;
#endif
return ret;
}
/* return 1 if last alert received was a close_notify alert, otherwise 0 */
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_gotCloseNotify
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
int ret, gotCloseNotify = 0;
WOLFSSL_ALERT_HISTORY alert_history;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
if (jenv == NULL || ssl == NULL) {
return gotCloseNotify;
}
ret = wolfSSL_get_alert_history(ssl, &alert_history);
if (ret == WOLFSSL_SUCCESS) {
if (alert_history.last_rx.code == 0) {
gotCloseNotify = 1;
}
}
return gotCloseNotify;
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_sslSetAlpnProtos
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jbyteArray alpnProtos)
{
int ret = SSL_FAILURE;
#if defined(HAVE_ALPN) && (LIBWOLFSSL_VERSION_HEX >= 0x04002000)
/* wolfSSL_set_alpn_protos() added as of wolfSSL 4.2.0 */
byte* buff = NULL;
word32 buffSz = 0;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
if (jenv == NULL || ssl == NULL || alpnProtos == NULL) {
return BAD_FUNC_ARG;
}
buff = (byte*)(*jenv)->GetByteArrayElements(jenv, alpnProtos, NULL);
buffSz = (*jenv)->GetArrayLength(jenv, alpnProtos);
if (buff != NULL && buffSz > 0) {
ret = wolfSSL_set_alpn_protos(ssl, buff, buffSz);
#ifdef WOLFSSL_ERROR_CODE_OPENSSL
if (ret == 0) {
/* wolfSSL_set_alpn_protos() returns 0 on success if
* WOLFSSL_ERROR_CODE_OPENSSL is defined, to match behavior of
* OpenSSL for compatibility layer. We translate back to
* a consistent SSL_SUCCESS here */
ret = SSL_SUCCESS;
}
else {
ret = SSL_FAILURE;
}
#endif
}
(*jenv)->ReleaseByteArrayElements(jenv, alpnProtos,
(jbyte*)buff, JNI_ABORT);
#else
(void)jenv;
(void)jcl;
(void)sslPtr;
(void)alpnProtos;
ret = NOT_COMPILED_IN;
#endif
return ret;
}
JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_WolfSSLSession_sslGet0AlpnSelected
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
#ifdef HAVE_ALPN
int err = 0;
char* protocol_name = NULL;
word16 protocol_nameSz = 0;
jbyteArray alpnArray;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
if (jenv == NULL || ssl == NULL) {
return NULL;
}
/* get ALPN protocol received from server:
* WOLFSSL_SUCCESS - on success
* WOLFSSL_ALPN_NOT_FOUND - no ALPN received (no match with server)
* other - error case */
err = wolfSSL_ALPN_GetProtocol(ssl, &protocol_name, &protocol_nameSz);
if (err != WOLFSSL_SUCCESS) {
return NULL;
}
alpnArray = (*jenv)->NewByteArray(jenv, protocol_nameSz);
if (alpnArray == NULL) {
(*jenv)->ThrowNew(jenv, jcl,
"Failed to create byte array in native sslGet0AlpnSelected");
return NULL;
}
(*jenv)->SetByteArrayRegion(jenv, alpnArray, 0, protocol_nameSz,
(jbyte*)protocol_name);
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
return NULL;
}
return alpnArray;
#else
(void)jenv;
(void)jcl;
(void)sslPtr;
return NULL;
#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_useALPN
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jstring protocols, jint options)
{
int ret = SSL_FAILURE;
#ifdef HAVE_ALPN
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
char* protoList = NULL;
jsize protocolsLen = 0;
(void)jcl;
if (jenv == NULL || ssl == 0 || protocols == NULL || options < 0) {
return BAD_FUNC_ARG;
}
protocolsLen = (*jenv)->GetStringUTFLength(jenv, protocols);
if (protocolsLen == 0) {
return BAD_FUNC_ARG;
}
/* Allocate size + 1 to guarantee we are null terminated */
protoList = (char*)XMALLOC(protocolsLen + 1, NULL, DYNAMIC_TYPE_TMP_BUFFER);
if (protoList == NULL) {
return MEMORY_E;
}
/* GetStringUTFRegion() does not need to be freed/released */
(*jenv)->GetStringUTFRegion(jenv, protocols, 0, protocolsLen, protoList);
protoList[protocolsLen] = '\0';
ret = wolfSSL_UseALPN(ssl, protoList, protocolsLen, (int)options);
XFREE(protoList, NULL, DYNAMIC_TYPE_TMP_BUFFER);
#else
(void)jenv;
(void)jcl;
(void)sslPtr;
(void)protocols;
(void)options;
ret = NOT_COMPILED_IN;
#endif
return (jint)ret;
}
JNIEXPORT int JNICALL Java_com_wolfssl_WolfSSLSession_setALPNSelectCb
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
#if defined(HAVE_ALPN) && (LIBWOLFSSL_VERSION_HEX >= 0x05006006)
/* wolfSSL_set_alpn_select_cb() added as of wolfSSL 5.6.6 */
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
int ret = SSL_SUCCESS;
(void)jcl;
if (jenv == NULL || ssl == NULL) {
return BAD_FUNC_ARG;
}
/* set ALPN select callback */
wolfSSL_set_alpn_select_cb(ssl, NativeALPNSelectCb, NULL);
return ret;
#else
(void)jenv;
(void)jcl;
(void)sslPtr;
return NOT_COMPILED_IN;
#endif
}
#ifdef HAVE_ALPN
int NativeALPNSelectCb(WOLFSSL *ssl, const unsigned char **out,
unsigned char *outlen, const unsigned char *in,
unsigned int inlen, void *arg)
{
JNIEnv* jenv; /* JNI environment */
int needsDetach = 0; /* Should we explicitly detach? */
jint vmret = 0;
jobject* g_cachedSSLObj; /* WolfSSLSession cached object */
jclass sslClass; /* WolfSSLSession class */
jmethodID alpnSelectMethodId; /* internalAlpnSelectCallback ID */
int ret = 0;
unsigned int idx = 0;
int peerProtoCount = 0;
char* peerProtos = NULL;
char* peerProtosCopy = NULL;
word16 peerProtosSz = 0;
char* curr = NULL;
char* ptr = NULL;
jobjectArray peerProtosArr = NULL;
jobjectArray outProtoArr = NULL;
int outProtoArrSz = 0;
jstring selectedProto = NULL;
const char* selectedProtoCharArr = NULL;
int selectedProtoCharArrSz = 0;
if (g_vm == NULL || ssl == NULL || out == NULL || outlen == NULL ||
in == NULL) {
return SSL_TLSEXT_ERR_ALERT_FATAL;
}
/* 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 SSL_TLSEXT_ERR_ALERT_FATAL;
}
needsDetach = 1;
}
else if (vmret != JNI_OK) {
return SSL_TLSEXT_ERR_ALERT_FATAL;
}
/* get stored WolfSSLSession object */
g_cachedSSLObj = (jobject*) wolfSSL_get_jobject(ssl);
if (!g_cachedSSLObj) {
throwWolfSSLJNIException(jenv,
"Can't get native WolfSSLSession object reference in "
"NativeALPNSelectCb");
if (needsDetach) {
(*g_vm)->DetachCurrentThread(g_vm);
}
return SSL_TLSEXT_ERR_ALERT_FATAL;
}
/* lookup WolfSSLSession class from object */
sslClass = (*jenv)->GetObjectClass(jenv, (jobject)(*g_cachedSSLObj));
if (sslClass == NULL) {
throwWolfSSLJNIException(jenv,
"Can't get native WolfSSLSession class reference in "
"NativeALPNSelectCb");
if (needsDetach) {
(*g_vm)->DetachCurrentThread(g_vm);
}
return SSL_TLSEXT_ERR_ALERT_FATAL;
}
/* call internal ALPN select callback */
alpnSelectMethodId = (*jenv)->GetMethodID(jenv, sslClass,
"internalAlpnSelectCallback",
"(Lcom/wolfssl/WolfSSLSession;[Ljava/lang/String;[Ljava/lang/String;)I");
if (alpnSelectMethodId == NULL) {
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
}
throwWolfSSLJNIException(jenv,
"Error getting internalAlpnSelectCallback method from JNI");
if (needsDetach) {
(*g_vm)->DetachCurrentThread(g_vm);
}
return SSL_TLSEXT_ERR_ALERT_FATAL;
}
/* Use wolfSSL_ALPN_GetPeerProtocol() here to get ALPN protocols sent
* by the peer instead of directly using in/inlen, since this API
* splits/formats into a comma-separated list. peerProtosSz does not
* include the null terminator byte in the size. It is only the size
* of the ALPN list chars proper.*/
ret = wolfSSL_ALPN_GetPeerProtocol(ssl, &peerProtos, &peerProtosSz);
if (ret != WOLFSSL_SUCCESS) {
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
}
throwWolfSSLJNIException(jenv,
"Error in wolfSSL_ALPN_GetPeerProtocol()");
if (needsDetach) {
(*g_vm)->DetachCurrentThread(g_vm);
}
return SSL_TLSEXT_ERR_ALERT_FATAL;
}
/* Make a copy of peer protos since we have to scan through it first
* to get total number of tokens. Allocate peerProtosSz+1 to make
* sure our list is null terminated for XSTRTOK(). */
peerProtosCopy = (char*)XMALLOC(peerProtosSz + 1, NULL,
DYNAMIC_TYPE_TMP_BUFFER);
if (peerProtosCopy == NULL) {
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
}
throwWolfSSLJNIException(jenv,
"Error allocating memory for peer protocols array");
if (needsDetach) {
(*g_vm)->DetachCurrentThread(g_vm);
}
return SSL_TLSEXT_ERR_ALERT_FATAL;
}
XMEMSET(peerProtosCopy, 0, peerProtosSz + 1);
XMEMCPY(peerProtosCopy, peerProtos, peerProtosSz);
/* get count of protocols, used to create Java array of proper size */
curr = XSTRTOK(peerProtosCopy, ",", &ptr);
while (curr != NULL) {
peerProtoCount++;
curr = XSTRTOK(NULL, ",", &ptr);
}
XFREE(peerProtosCopy, NULL, DYNAMIC_TYPE_TMP_BUFFER);
peerProtosCopy = NULL;
if (peerProtoCount == 0) {
wolfSSL_ALPN_FreePeerProtocol(ssl, &peerProtos);
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
}
throwWolfSSLJNIException(jenv,
"ALPN peer protocol list size is 0");
if (needsDetach) {
(*g_vm)->DetachCurrentThread(g_vm);
}
return SSL_TLSEXT_ERR_ALERT_FATAL;
}
/* create Java String[] of size peerProtoCount */
peerProtosArr = (*jenv)->NewObjectArray(jenv, peerProtoCount,
(*jenv)->FindClass(jenv, "java/lang/String"), NULL);
if (peerProtosArr == NULL) {
wolfSSL_ALPN_FreePeerProtocol(ssl, &peerProtos);
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
}
throwWolfSSLJNIException(jenv,
"Failed to create JNI String[] for ALPN protocols");
if (needsDetach) {
(*g_vm)->DetachCurrentThread(g_vm);
}
return SSL_TLSEXT_ERR_ALERT_FATAL;
}
/* add each char* to String[] for call to Java callback method */
curr = XSTRTOK(peerProtos, ",", &ptr);
while (curr != NULL) {
(*jenv)->SetObjectArrayElement(jenv, peerProtosArr, idx++,
(*jenv)->NewStringUTF(jenv, curr));
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
wolfSSL_ALPN_FreePeerProtocol(ssl, &peerProtos);
throwWolfSSLJNIException(jenv,
"Failed to add String to JNI String[] for ALPN protocols");
if (needsDetach) {
(*g_vm)->DetachCurrentThread(g_vm);
}
return SSL_TLSEXT_ERR_ALERT_FATAL;
}
curr = XSTRTOK(NULL, ",", &ptr);
}
/* free native peer protocol list, no longer needed */
wolfSSL_ALPN_FreePeerProtocol(ssl, &peerProtos);
/* create new String[1] to let Java callback put output selection into
* first array offset, ie String[0] */
outProtoArr = (*jenv)->NewObjectArray(jenv, 1,
(*jenv)->FindClass(jenv, "java/lang/String"), NULL);
if (outProtoArr == NULL) {
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
}
throwWolfSSLJNIException(jenv,
"Failed to create JNI String[1] for output ALPN protocol");
if (needsDetach) {
(*g_vm)->DetachCurrentThread(g_vm);
}
return SSL_TLSEXT_ERR_ALERT_FATAL;
}
/* call Java callback */
ret = (*jenv)->CallIntMethod(jenv, (jobject)(*g_cachedSSLObj),
alpnSelectMethodId, (jobject)(*g_cachedSSLObj), outProtoArr,
peerProtosArr);
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
throwWolfSSLJNIException(jenv,
"Exception while calling internalAlpnSelectCallback()");
if (needsDetach) {
(*g_vm)->DetachCurrentThread(g_vm);
}
return SSL_TLSEXT_ERR_ALERT_FATAL;
}
if (ret == SSL_TLSEXT_ERR_OK) {
/* convert returned String[0] into char* */
outProtoArrSz = (*jenv)->GetArrayLength(jenv, outProtoArr);
if (outProtoArrSz != 1) {
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
}
throwWolfSSLJNIException(jenv,
"Output String[] for ALPN result not size 1");
if (needsDetach) {
(*g_vm)->DetachCurrentThread(g_vm);
}
return SSL_TLSEXT_ERR_ALERT_FATAL;
}
/* get jstring from String[0] */
selectedProto = (jstring)(*jenv)->GetObjectArrayElement(
jenv, outProtoArr, 0);
if (selectedProto == NULL) {
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
}
throwWolfSSLJNIException(jenv,
"Selected ALPN protocol in String[] is NULL");
if (needsDetach) {
(*g_vm)->DetachCurrentThread(g_vm);
}
return SSL_TLSEXT_ERR_ALERT_FATAL;
}
/* get char* from jstring */
selectedProtoCharArr = (*jenv)->GetStringUTFChars(jenv,
selectedProto, 0);
selectedProtoCharArrSz = (int)XSTRLEN(selectedProtoCharArr);
/* see if selected ALPN protocol is in original sent list */
if (selectedProtoCharArr != NULL) {
for (idx = 0; idx < inlen; idx++) {
if (idx + selectedProtoCharArrSz > inlen) {
/* No match found, fatal error. in not long enough for
* search. Reset ret to error condition, match not set
* correctly */
ret = SSL_TLSEXT_ERR_ALERT_FATAL;
break;
}
if (XMEMCMP(in + idx, selectedProtoCharArr,
selectedProtoCharArrSz) == 0) {
/* Match found. Format of input array is length byte of
* ALPN protocol, followed by ALPN protocol,
* ie (LEN+ALPN|LEN+ALPN|...) We set *out to ALPN selected
* protocol and *outlen to length of protocol (idx - 1) */
*out = in + idx;
*outlen = in[idx - 1];
break;
}
}
}
else {
/* Not able to get selected ALPN protocol from Java, fatal error */
ret = SSL_TLSEXT_ERR_ALERT_FATAL;
}
}
return ret;
}
#endif /* HAVE_ALPN */
JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLSession_keepArrays
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
(void)jenv;
(void)jcl;
#ifndef WOLFCRYPT_ONLY
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
/* Checks ssl for null internally */
wolfSSL_KeepArrays(ssl);
#endif
}
JNIEXPORT jbyteArray JNICALL Java_com_wolfssl_WolfSSLSession_getClientRandom
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
#if !defined(WOLFCRYPT_ONLY) && (defined(OPENSSL_EXTRA) || \
defined(WOLFSSL_WPAS_SMALL) || defined(HAVE_SECRET_CALLBACK)) && \
!defined(NO_WOLFSSL_CLIENT)
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
int clientRandomSz;
byte clientRandom[32];
jbyteArray randomArr = NULL;
(void)jcl;
if (jenv == NULL || ssl == NULL) {
return NULL;
}
clientRandomSz = (int)wolfSSL_get_client_random(ssl, clientRandom,
sizeof(clientRandom));
if (clientRandomSz <= 0) {
return NULL;
}
randomArr = (*jenv)->NewByteArray(jenv, clientRandomSz);
if (randomArr == NULL) {
(*jenv)->ThrowNew(jenv, jcl,
"Failed to create byte array in native getClientRandom()");
return NULL;
}
(*jenv)->SetByteArrayRegion(jenv, randomArr, 0, clientRandomSz,
(jbyte*)clientRandom);
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
return NULL;
}
return randomArr;
#else
(void)jenv;
(void)jcl;
(void)sslPtr;
return NULL;
#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_setTls13SecretCb
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
#if defined(WOLFSSL_TLS13) && !defined(WOLFCRYPT_ONLY) && \
defined(HAVE_SECRET_CALLBACK)
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
int ret = SSL_SUCCESS;
(void)jcl;
if (jenv == NULL || ssl == NULL) {
return BAD_FUNC_ARG;
}
/* Java layer handles setting and giving back user CTX */
ret = wolfSSL_set_tls13_secret_cb(ssl, NativeTls13SecretCb, NULL);
return ret;
#else
(void)jenv;
(void)jcl;
(void)sslPtr;
return NOT_COMPILED_IN;
#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_setSessionTicketCb
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
#if !defined(NO_WOLFSSL_CLIENT) && defined(HAVE_SESSION_TICKET)
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
int ret = SSL_SUCCESS;
(void)jcl;
if (jenv == NULL || ssl == NULL) {
return BAD_FUNC_ARG;
}
/* Java layer handles setting and giving back user CTX */
ret = wolfSSL_set_SessionTicket_cb(ssl, NativeSessionTicketCb, NULL);
return ret;
#else
(void)jenv;
(void)jcl;
(void)sslPtr;
return NOT_COMPILED_IN;
#endif
}
#if defined(WOLFSSL_TLS13) && !defined(WOLFCRYPT_ONLY) && \
defined(HAVE_SECRET_CALLBACK)
int NativeTls13SecretCb(WOLFSSL *ssl, int id, const unsigned char* secret,
int secretSz, void* ctx)
{
JNIEnv* jenv; /* JNI environment */
int needsDetach = 0; /* Should we explicitly detach? */
jint retval = 0;
jint vmret = 0;
jobject* g_cachedSSLObj; /* WolfSSLSession cached object */
jclass sslClass; /* WolfSSLSession class */
jmethodID tls13SecretMethodId; /* internalTls13SecretCallback ID */
jbyteArray secretArr = NULL;
if (g_vm == NULL || ssl == NULL) {
return BAD_FUNC_ARG;
}
/* 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 TLS13_SECRET_CB_E;
}
needsDetach = 1;
}
else if (vmret != JNI_OK) {
return TLS13_SECRET_CB_E;
}
/* Get stored WolfSSLSession object */
g_cachedSSLObj = (jobject*) wolfSSL_get_jobject(ssl);
if (!g_cachedSSLObj) {
throwWolfSSLJNIException(jenv,
"Can't get native WolfSSLSession object reference in "
"NativeTls13SecretCb");
if (needsDetach) {
(*g_vm)->DetachCurrentThread(g_vm);
}
return TLS13_SECRET_CB_E;
}
/* Lookup WolfSSLSession class from object */
sslClass = (*jenv)->GetObjectClass(jenv, (jobject)(*g_cachedSSLObj));
if (sslClass == NULL) {
throwWolfSSLJNIException(jenv,
"Can't get native WolfSSLSession class reference in "
"NativeTls13SecretCb");
if (needsDetach) {
(*g_vm)->DetachCurrentThread(g_vm);
}
return TLS13_SECRET_CB_E;
}
/* Call internal TLS 1.3 secret callback */
tls13SecretMethodId = (*jenv)->GetMethodID(jenv, sslClass,
"internalTls13SecretCallback", "(Lcom/wolfssl/WolfSSLSession;I[B)I");
if (tls13SecretMethodId == NULL) {
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
}
throwWolfSSLJNIException(jenv,
"Error getting internalTls13SecretCallback method from JNI");
if (needsDetach) {
(*g_vm)->DetachCurrentThread(g_vm);
}
return TLS13_SECRET_CB_E;
}
if (secretSz > 0) {
/* Create jbyteArray to hold secret data */
secretArr = (*jenv)->NewByteArray(jenv, secretSz);
if (secretArr == NULL) {
throwWolfSSLJNIException(jenv,
"Error creating new jbyteArray in NativeTls13SecretCb");
if (needsDetach) {
(*g_vm)->DetachCurrentThread(g_vm);
}
return TLS13_SECRET_CB_E;
}
(*jenv)->SetByteArrayRegion(jenv, secretArr, 0, secretSz,
(jbyte*)secret);
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
if (needsDetach) {
(*g_vm)->DetachCurrentThread(g_vm);
}
return TLS13_SECRET_CB_E;
}
/* Call Java TLS 1.3 secret callback, ignore native CTX since Java
* handles it */
retval = (*jenv)->CallIntMethod(jenv, (jobject)(*g_cachedSSLObj),
tls13SecretMethodId, (jobject)(*g_cachedSSLObj), (jint)id,
secretArr);
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
throwWolfSSLJNIException(jenv,
"Exception while calling internalTls13SecretCallback()");
if (needsDetach) {
(*g_vm)->DetachCurrentThread(g_vm);
}
return TLS13_SECRET_CB_E;
}
/* Delete local refs */
(*jenv)->DeleteLocalRef(jenv, secretArr);
}
/* Detach JNIEnv from thread */
if (needsDetach) {
(*g_vm)->DetachCurrentThread(g_vm);
}
return (int)retval;
}
#endif /* WOLFSSL_TLS13 && !WOLFCRYPT_ONLY && HAVE_SECRET_CALLBACK */
#if !defined(NO_WOLFSSL_CLIENT) && defined(HAVE_SESSION_TICKET)
int NativeSessionTicketCb(WOLFSSL* ssl, const unsigned char* ticket,
int ticketLen, void* ctx)
{
JNIEnv* jenv; /* JNI environment */
int needsDetach = 0; /* Should we explicitly detach? */
jint retval = 0;
jint vmret = 0;
jobject* g_cachedSSLObj; /* WolfSSLSession cached object */
jclass sslClass; /* WolfSSLSession class */
jmethodID sessTicketCbMethodId; /* internalTls13SecretCallback ID */
jbyteArray ticketArr = NULL;
if (g_vm == NULL || ssl == NULL) {
return BAD_FUNC_ARG;
}
/* 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;
}
/* Get stored WolfSSLSession object */
g_cachedSSLObj = (jobject*) wolfSSL_get_jobject(ssl);
if (!g_cachedSSLObj) {
throwWolfSSLJNIException(jenv,
"Can't get native WolfSSLSession object reference in "
"NativeSessionTicketCb");
if (needsDetach) {
(*g_vm)->DetachCurrentThread(g_vm);
}
return -1;
}
/* Lookup WolfSSLSession class from object */
sslClass = (*jenv)->GetObjectClass(jenv, (jobject)(*g_cachedSSLObj));
if (sslClass == NULL) {
throwWolfSSLJNIException(jenv,
"Can't get native WolfSSLSession class reference in "
"NativeSessionTicketCb");
if (needsDetach) {
(*g_vm)->DetachCurrentThread(g_vm);
}
return -1;
}
/* Call internal TLS 1.3 secret callback */
sessTicketCbMethodId = (*jenv)->GetMethodID(jenv, sslClass,
"internalSessionTicketCallback", "(Lcom/wolfssl/WolfSSLSession;[B)I");
if (sessTicketCbMethodId == NULL) {
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
}
throwWolfSSLJNIException(jenv,
"Error getting internalSessionTicketCallback method from JNI");
if (needsDetach) {
(*g_vm)->DetachCurrentThread(g_vm);
}
return -1;
}
if (ticketLen > 0) {
/* Create jbyteArray to hold session ticket */
ticketArr = (*jenv)->NewByteArray(jenv, ticketLen);
if (ticketArr == NULL) {
throwWolfSSLJNIException(jenv,
"Error creating new jbyteArray in NativeSessionTicketCb");
if (needsDetach) {
(*g_vm)->DetachCurrentThread(g_vm);
}
return -1;
}
(*jenv)->SetByteArrayRegion(jenv, ticketArr, 0, ticketLen,
(jbyte*)ticket);
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
if (needsDetach) {
(*g_vm)->DetachCurrentThread(g_vm);
}
return -1;
}
/* Call Java session ticket callback, ignore native CTX since Java
* handles it */
retval = (*jenv)->CallIntMethod(jenv, (jobject)(*g_cachedSSLObj),
sessTicketCbMethodId, (jobject)(*g_cachedSSLObj), ticketArr);
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
throwWolfSSLJNIException(jenv,
"Exception while calling internalSessionTicketCallback()");
if (needsDetach) {
(*g_vm)->DetachCurrentThread(g_vm);
}
return -1;
}
/* Delete local refs */
(*jenv)->DeleteLocalRef(jenv, ticketArr);
}
/* Detach JNIEnv from thread */
if (needsDetach) {
(*g_vm)->DetachCurrentThread(g_vm);
}
return (int)retval;
}
#endif /* WOLFSSL_TLS13 && !WOLFCRYPT_ONLY && HAVE_SECRET_CALLBACK */
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_useSecureRenegotiation
(JNIEnv* jenv, jobject jcl, jlong ssl)
{
(void)jenv;
(void)jcl;
#ifdef HAVE_SECURE_RENEGOTIATION
return (jint)wolfSSL_UseSecureRenegotiation((WOLFSSL*)(uintptr_t)ssl);
#else
(void)ssl;
return NOT_COMPILED_IN;
#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_rehandshake
(JNIEnv* jenv, jobject jcl, jlong ssl)
{
(void)jenv;
(void)jcl;
#ifdef HAVE_SECURE_RENEGOTIATION
return (jint)wolfSSL_Rehandshake((WOLFSSL*)(uintptr_t)ssl);
#else
(void)ssl;
return NOT_COMPILED_IN;
#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_set1SigAlgsList
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jstring list)
{
#ifdef OPENSSL_EXTRA
int ret = 0;
const char* sigAlgList = NULL;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
if (jenv == NULL || ssl == NULL || list == NULL) {
return SSL_FAILURE;
}
sigAlgList = (*jenv)->GetStringUTFChars(jenv, list, 0);
ret = wolfSSL_set1_sigalgs_list(ssl, sigAlgList);
(*jenv)->ReleaseStringUTFChars(jenv, list, sigAlgList);
return (jint)ret;
#else
(void)jenv;
(void)ssl;
(void)list;
return (jint)NOT_COMPILED_IN;
#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_useSupportedCurve
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jint name)
{
#ifdef HAVE_SUPPORTED_CURVES
int ret = 0;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
if (jenv == NULL || ssl == NULL) {
return (jint)SSL_FAILURE;
}
ret = wolfSSL_UseSupportedCurve(ssl, (word16)name);
return (jint)ret;
#else
(void)jenv;
(void)jcl;
(void)sslPtr;
(void)name;
return (jint)NOT_COMPILED_IN;
#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_disableExtendedMasterSecret
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
#if defined(HAVE_EXTENDED_MASTER) && !defined(NO_WOLFSSL_CLIENT)
int ret = 0;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
/* Checks ssl for null internally */
ret = wolfSSL_DisableExtendedMasterSecret(ssl);
return (jint)ret;
#else
(void)jenv;
(void)jcl;
(void)sslPtr;
return (jint)NOT_COMPILED_IN;
#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_hasTicket
(JNIEnv* jenv, jobject jcl, jlong sessionPtr)
{
#if !defined(NO_SESSION_CACHE) && \
(defined(OPENSSL_EXTRA) || defined(HAVE_EXT_CACHE))
WOLFSSL_SESSION* session = (WOLFSSL_SESSION*)(uintptr_t)sessionPtr;
(void)jcl;
if (jenv == NULL || session == NULL) {
return WOLFSSL_FAILURE;
}
return (jint)wolfSSL_SESSION_has_ticket((const WOLFSSL_SESSION*)session);
#else
(void)jenv;
(void)jcl;
(void)sessionPtr;
return (jint)WolfSSL.SSL_FAILURE;
#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_interruptBlockedIO
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
#ifndef USE_WINDOWS_API
SSLAppData* appData = NULL;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
#endif
(void)jenv;
(void)jcl;
#ifndef USE_WINDOWS_API
/* get session mutex from SSL app data */
appData = (SSLAppData*)wolfSSL_get_app_data(ssl);
if (appData == NULL) {
return WOLFSSL_FAILURE;
}
/* signal any blocked threads in select()/poll() to wake up, so we
* don't have a deadlock when trying to lock jniSessLock next */
writeToInterruptPipe(appData);
writeToInterruptPipe(appData);
#endif /* USE_WINDOWS_API */
return SSL_SUCCESS;
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_getThreadsBlockedInPoll
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
SSLAppData* appData = NULL;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jenv;
(void)jcl;
/* get session mutex from SSL app data */
appData = (SSLAppData*)wolfSSL_get_app_data(ssl);
if (appData == NULL) {
return 0;
}
return (jint)threadsWaitingInPollSelect(appData);
}
JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLSession_setSSLIORecv
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jenv;
(void)jcl;
if (ssl != NULL) {
/* set I/O recv callback */
wolfSSL_SSLSetIORecv(ssl, NativeSSLIORecvCb);
}
}
int NativeSSLIORecvCb(WOLFSSL *ssl, char *buf, int sz, void *ctx)
{
jint retval = 0;
jint vmret = 0;
JNIEnv* jenv; /* JNI environment */
int needsDetach = 0; /* Should we explicitly detach? */
jobject* g_cachedSSLObj; /* WolfSSLSession cached object */
jbyteArray inData;
jobject directBuf;
if (g_vm == NULL || ssl == NULL || buf == NULL || ctx == NULL) {
/* 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;
}
/* get stored WolfSSLSession jobject */
g_cachedSSLObj = (jobject*) wolfSSL_get_jobject(ssl);
if (!g_cachedSSLObj) {
throwWolfSSLJNIException(jenv,
"Can't get native WolfSSLSession object reference in "
"NativeSSLIORecvCb");
if (needsDetach) {
(*g_vm)->DetachCurrentThread(g_vm);
}
return 0;
}
/* Detect if we should use ByteBuffer or byte[] I/O callbacks */
if ((*jenv)->CallBooleanMethod(jenv, (jobject)(*g_cachedSSLObj),
g_isByteBufferIORecvCallbackSet)) {
/* Call receive callback using ByteBuffer */
if (!g_sslIORecvMethodId_BB) {
throwWolfSSLJNIException(jenv,
"Cached recv callback method ID is null in "
"internalIORecvCallback");
if (needsDetach) {
(*g_vm)->DetachCurrentThread(g_vm);
}
return WOLFSSL_CBIO_ERR_GENERAL;
}
/* create ByteBuffer to hold received data */
directBuf = (*jenv)->NewDirectByteBuffer(jenv, buf, sz);
if (!directBuf) {
throwWolfSSLJNIException(jenv,
"Error creating ByteBuffer in NativeSSLIORecvCb");
if (needsDetach) {
(*g_vm)->DetachCurrentThread(g_vm);
}
return WOLFSSL_CBIO_ERR_GENERAL;
}
/* call Java receive callback, ignore ctx since Java handles it */
retval = (*jenv)->CallIntMethod(jenv, (jobject)(*g_cachedSSLObj),
g_sslIORecvMethodId_BB, (jobject)(*g_cachedSSLObj), directBuf,
(jint)sz);
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
(*jenv)->DeleteLocalRef(jenv, directBuf);
if (needsDetach) {
(*g_vm)->DetachCurrentThread(g_vm);
}
return WOLFSSL_CBIO_ERR_GENERAL;
}
/* delete local refs */
(*jenv)->DeleteLocalRef(jenv, directBuf);
}
else {
/* Call receive callback using byte[] */
if (!g_sslIORecvMethodId) {
throwWolfSSLJNIException(jenv,
"Cached recv callback method ID is null in "
"internalIORecvCallback");
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 == NULL) {
throwWolfSSLJNIException(jenv,
"Error getting internalIORecvCallback method from JNI");
if (needsDetach) {
(*g_vm)->DetachCurrentThread(g_vm);
}
return WOLFSSL_CBIO_ERR_GENERAL;
}
/* call Java send callback, ignore ctx since Java handles it */
retval = (*jenv)->CallIntMethod(jenv, (jobject)(*g_cachedSSLObj),
g_sslIORecvMethodId, (jobject)(*g_cachedSSLObj), inData, (jint)sz);
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
(*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, inData);
if (needsDetach) {
(*g_vm)->DetachCurrentThread(g_vm);
}
return WOLFSSL_CBIO_ERR_GENERAL;
}
}
/* delete local refs */
(*jenv)->DeleteLocalRef(jenv, inData);
}
/* detach JNIEnv from thread */
if (needsDetach) {
(*g_vm)->DetachCurrentThread(g_vm);
}
return retval;
}
JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLSession_setSSLIOSend
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jenv;
(void)jcl;
if (ssl != NULL) {
/* set I/O send callback */
wolfSSL_SSLSetIOSend(ssl, NativeSSLIOSendCb);
}
}
int NativeSSLIOSendCb(WOLFSSL *ssl, char *buf, int sz, void *ctx)
{
jint retval = 0;
jint vmret = 0;
JNIEnv* jenv; /* JNI environment */
int needsDetach = 0; /* Should we explicitly detach? */
jobject* g_cachedSSLObj; /* WolfSSLSession cached object */
jbyteArray outData; /* jbyteArray for data to send */
jobject directBuf;
if (g_vm == NULL || ssl == NULL || buf == NULL || ctx == NULL) {
/* 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;
}
/* get stored WolfSSLSession jobject */
g_cachedSSLObj = (jobject*) wolfSSL_get_jobject(ssl);
if (!g_cachedSSLObj) {
throwWolfSSLJNIException(jenv,
"Can't get native WolfSSLSession object reference in "
"NativeSSLIOSendCb");
if (needsDetach) {
(*g_vm)->DetachCurrentThread(g_vm);
}
return 0;
}
/* Detect if we should use ByteBuffer or byte[] I/O callbacks */
if ((*jenv)->CallBooleanMethod(jenv, (jobject)(*g_cachedSSLObj),
g_isByteBufferIOSendCallbackSet)) {
/* Call send callback using ByteBuffer */
if (!g_sslIOSendMethodId_BB) {
throwWolfSSLJNIException(jenv,
"Cached send callback method ID is null in internalIOSendCb");
if (needsDetach) {
(*g_vm)->DetachCurrentThread(g_vm);
}
return WOLFSSL_CBIO_ERR_GENERAL;
}
/* create ByteBuffer to wrap data to send */
directBuf = (*jenv)->NewDirectByteBuffer(jenv, buf, sz);
if (!directBuf) {
throwWolfSSLJNIException(jenv,
"Error creating ByteBuffer in NativeSSLIOSendCb, not direct");
if (needsDetach) {
(*g_vm)->DetachCurrentThread(g_vm);
}
return WOLFSSL_CBIO_ERR_GENERAL;
}
/* call Java send callback, ignore ctx since Java handles it */
retval = (*jenv)->CallIntMethod(jenv, (jobject)(*g_cachedSSLObj),
g_sslIOSendMethodId_BB, (jobject)(*g_cachedSSLObj), directBuf,
(jint)sz);
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
(*jenv)->DeleteLocalRef(jenv, directBuf);
if (needsDetach) {
(*g_vm)->DetachCurrentThread(g_vm);
}
return WOLFSSL_CBIO_ERR_GENERAL;
}
/* delete local refs */
(*jenv)->DeleteLocalRef(jenv, directBuf);
}
else {
/* Call send callbaack using byte[] */
if (!g_sslIOSendMethodId) {
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
}
throwWolfSSLJNIException(jenv,
"internalIOSendCallback method ID is null in internalIOSendCb");
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) {
throwWolfSSLJNIException(jenv,
"Error getting internalIOSendCallback method from JNI");
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, outData);
if (needsDetach) {
(*g_vm)->DetachCurrentThread(g_vm);
}
return WOLFSSL_CBIO_ERR_GENERAL;
}
/* call Java send callback, ignore ctx since Java handles it */
retval = (*jenv)->CallIntMethod(jenv, (jobject)(*g_cachedSSLObj),
g_sslIOSendMethodId, (jobject)(*g_cachedSSLObj), outData,
(jint)sz);
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
(*jenv)->DeleteLocalRef(jenv, outData);
if (needsDetach) {
(*g_vm)->DetachCurrentThread(g_vm);
}
return WOLFSSL_CBIO_ERR_GENERAL;
}
/* delete local refs */
(*jenv)->DeleteLocalRef(jenv, outData);
}
}
/* detach JNIEnv from thread */
if (needsDetach) {
(*g_vm)->DetachCurrentThread(g_vm);
}
return retval;
}