Merge pull request #257 from cconlon/sslEngineFixups
SSLEngine Performance Optimizationspull/260/head
commit
e858d7590d
|
@ -53,6 +53,22 @@ JavaVM* g_vm;
|
|||
/* global object refs for logging callbacks */
|
||||
static jobject g_loggingCbIfaceObj;
|
||||
|
||||
/* global method IDs we can cache for performance */
|
||||
jmethodID g_sslIORecvMethodId = NULL;
|
||||
jmethodID g_sslIORecvMethodId_BB = NULL;
|
||||
jmethodID g_sslIOSendMethodId = NULL;
|
||||
jmethodID g_sslIOSendMethodId_BB = NULL;
|
||||
jmethodID g_isArrayIORecvCallbackSet = NULL;
|
||||
jmethodID g_isArrayIOSendCallbackSet = NULL;
|
||||
jmethodID g_isByteBufferIORecvCallbackSet = NULL;
|
||||
jmethodID g_isByteBufferIOSendCallbackSet = NULL;
|
||||
jmethodID g_bufferPositionMethodId = NULL;
|
||||
jmethodID g_bufferLimitMethodId = NULL;
|
||||
jmethodID g_bufferHasArrayMethodId = NULL;
|
||||
jmethodID g_bufferArrayMethodId = NULL;
|
||||
jmethodID g_bufferSetPositionMethodId = NULL;
|
||||
jmethodID g_verifyCallbackMethodId = NULL;
|
||||
|
||||
#ifdef HAVE_FIPS
|
||||
/* global object ref for FIPS error callback */
|
||||
static jobject g_fipsCbIfaceObj;
|
||||
|
@ -61,16 +77,192 @@ static jobject g_fipsCbIfaceObj;
|
|||
/* custom native fn prototypes */
|
||||
void NativeLoggingCallback(const int logLevel, const char *const logMessage);
|
||||
|
||||
/* called when native library is loaded */
|
||||
/* Called when native library is loaded.
|
||||
* We also cache global jmethodIDs here for performance. */
|
||||
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
|
||||
{
|
||||
JNIEnv* env = NULL;
|
||||
jclass sslClass = NULL;
|
||||
jclass byteBufferClass = NULL;
|
||||
jclass verifyClass = NULL;
|
||||
(void)reserved;
|
||||
|
||||
/* store JavaVM */
|
||||
g_vm = vm;
|
||||
|
||||
/* get JNIEnv from JavaVM */
|
||||
if ((*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_6) != JNI_OK) {
|
||||
printf("Unable to get JNIEnv from JavaVM in JNI_OnLoad()\n");
|
||||
return JNI_ERR;
|
||||
}
|
||||
|
||||
/* Cache the method ID for IO send and recv callbacks */
|
||||
sslClass = (*env)->FindClass(env, "com/wolfssl/WolfSSLSession");
|
||||
if (sslClass == NULL) {
|
||||
return JNI_ERR;
|
||||
}
|
||||
|
||||
g_sslIORecvMethodId = (*env)->GetMethodID(env, sslClass,
|
||||
"internalIOSSLRecvCallback",
|
||||
"(Lcom/wolfssl/WolfSSLSession;[BI)I");
|
||||
if (g_sslIORecvMethodId == NULL) {
|
||||
return JNI_ERR;
|
||||
}
|
||||
|
||||
g_sslIORecvMethodId_BB = (*env)->GetMethodID(env, sslClass,
|
||||
"internalIOSSLRecvCallback",
|
||||
"(Lcom/wolfssl/WolfSSLSession;Ljava/nio/ByteBuffer;I)I");
|
||||
if (g_sslIORecvMethodId_BB == NULL) {
|
||||
return JNI_ERR;
|
||||
}
|
||||
|
||||
g_sslIOSendMethodId = (*env)->GetMethodID(env, sslClass,
|
||||
"internalIOSSLSendCallback",
|
||||
"(Lcom/wolfssl/WolfSSLSession;[BI)I");
|
||||
if (g_sslIOSendMethodId == NULL) {
|
||||
return JNI_ERR;
|
||||
}
|
||||
|
||||
g_sslIOSendMethodId_BB = (*env)->GetMethodID(env, sslClass,
|
||||
"internalIOSSLSendCallback",
|
||||
"(Lcom/wolfssl/WolfSSLSession;Ljava/nio/ByteBuffer;I)I");
|
||||
if (g_sslIOSendMethodId_BB == NULL) {
|
||||
return JNI_ERR;
|
||||
}
|
||||
|
||||
g_isArrayIORecvCallbackSet = (*env)->GetMethodID(env, sslClass,
|
||||
"isArrayIORecvCallbackSet", "()Z");
|
||||
if (g_isArrayIORecvCallbackSet == NULL) {
|
||||
return JNI_ERR;
|
||||
}
|
||||
|
||||
g_isArrayIOSendCallbackSet = (*env)->GetMethodID(env, sslClass,
|
||||
"isArrayIOSendCallbackSet", "()Z");
|
||||
if (g_isArrayIOSendCallbackSet == NULL) {
|
||||
return JNI_ERR;
|
||||
}
|
||||
|
||||
g_isByteBufferIORecvCallbackSet = (*env)->GetMethodID(env, sslClass,
|
||||
"isByteBufferIORecvCallbackSet", "()Z");
|
||||
if (g_isByteBufferIORecvCallbackSet == NULL) {
|
||||
return JNI_ERR;
|
||||
}
|
||||
|
||||
g_isByteBufferIOSendCallbackSet = (*env)->GetMethodID(env, sslClass,
|
||||
"isByteBufferIOSendCallbackSet", "()Z");
|
||||
if (g_isByteBufferIOSendCallbackSet == NULL) {
|
||||
return JNI_ERR;
|
||||
}
|
||||
|
||||
/* Cache ByteBuffer method IDs */
|
||||
byteBufferClass = (*env)->FindClass(env, "java/nio/ByteBuffer");
|
||||
if (byteBufferClass == NULL) {
|
||||
return JNI_ERR;
|
||||
}
|
||||
|
||||
g_bufferPositionMethodId = (*env)->GetMethodID(env, byteBufferClass,
|
||||
"position", "()I");
|
||||
if (g_bufferPositionMethodId == NULL) {
|
||||
return JNI_ERR;
|
||||
}
|
||||
|
||||
g_bufferLimitMethodId = (*env)->GetMethodID(env, byteBufferClass,
|
||||
"limit", "()I");
|
||||
if (g_bufferLimitMethodId == NULL) {
|
||||
return JNI_ERR;
|
||||
}
|
||||
|
||||
g_bufferHasArrayMethodId = (*env)->GetMethodID(env, byteBufferClass,
|
||||
"hasArray", "()Z");
|
||||
if (g_bufferHasArrayMethodId == NULL) {
|
||||
return JNI_ERR;
|
||||
}
|
||||
|
||||
g_bufferArrayMethodId = (*env)->GetMethodID(env, byteBufferClass,
|
||||
"array", "()[B");
|
||||
if (g_bufferArrayMethodId == NULL) {
|
||||
return JNI_ERR;
|
||||
}
|
||||
|
||||
g_bufferSetPositionMethodId = (*env)->GetMethodID(env, byteBufferClass,
|
||||
"position", "(I)Ljava/nio/Buffer;");
|
||||
if (g_bufferSetPositionMethodId == NULL) {
|
||||
return JNI_ERR;
|
||||
}
|
||||
|
||||
/* Cache verify callback method ID */
|
||||
verifyClass = (*env)->FindClass(env, "com/wolfssl/WolfSSLVerifyCallback");
|
||||
if (verifyClass == NULL) {
|
||||
return JNI_ERR;
|
||||
}
|
||||
|
||||
g_verifyCallbackMethodId = (*env)->GetMethodID(env, verifyClass,
|
||||
"verifyCallback", "(IJ)I");
|
||||
if (g_verifyCallbackMethodId == NULL) {
|
||||
return JNI_ERR;
|
||||
}
|
||||
|
||||
/* Clean up local reference to class, not needed */
|
||||
(*env)->DeleteLocalRef(env, sslClass);
|
||||
(*env)->DeleteLocalRef(env, byteBufferClass);
|
||||
(*env)->DeleteLocalRef(env, verifyClass);
|
||||
|
||||
return JNI_VERSION_1_6;
|
||||
}
|
||||
|
||||
/* Called when native library is unloaded.
|
||||
* We clear cached method IDs here. */
|
||||
JNIEXPORT void JNICALL JNI_OnUnload(JavaVM* vm, void* reserved)
|
||||
{
|
||||
JNIEnv* env;
|
||||
|
||||
if ((*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_6) != JNI_OK) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Clear cached method ID */
|
||||
g_sslIORecvMethodId = NULL;
|
||||
g_sslIORecvMethodId_BB = NULL;
|
||||
g_sslIOSendMethodId = NULL;
|
||||
g_sslIOSendMethodId_BB = NULL;
|
||||
g_isArrayIORecvCallbackSet = NULL;
|
||||
g_isArrayIOSendCallbackSet = NULL;
|
||||
g_isByteBufferIORecvCallbackSet = NULL;
|
||||
g_isByteBufferIOSendCallbackSet = NULL;
|
||||
g_bufferPositionMethodId = NULL;
|
||||
g_bufferLimitMethodId = NULL;
|
||||
g_bufferHasArrayMethodId = NULL;
|
||||
g_bufferArrayMethodId = NULL;
|
||||
g_bufferSetPositionMethodId = NULL;
|
||||
g_verifyCallbackMethodId = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Throw WolfSSLJNIException
|
||||
*/
|
||||
void throwWolfSSLJNIException(JNIEnv* jenv, const char* msg)
|
||||
{
|
||||
jclass excClass = (*jenv)->FindClass(jenv, "com/wolfssl/WolfSSLJNIException");
|
||||
if (excClass == NULL) {
|
||||
/* Unable to find exception class, give up trying to throw */
|
||||
return;
|
||||
}
|
||||
(*jenv)->ThrowNew(jenv, excClass, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* Throw WolfSSLException
|
||||
*/
|
||||
void throwWolfSSLException(JNIEnv* jenv, const char* msg)
|
||||
{
|
||||
jclass excClass = (*jenv)->FindClass(jenv, "com/wolfssl/WolfSSLException");
|
||||
if (excClass == NULL) {
|
||||
/* Unable to find exception class, give up trying to throw */
|
||||
return;
|
||||
}
|
||||
(*jenv)->ThrowNew(jenv, excClass, msg);
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSL_init
|
||||
(JNIEnv* jenv, jobject jcl)
|
||||
{
|
||||
|
|
|
@ -1028,7 +1028,6 @@ int NativeIORecvCb(WOLFSSL *ssl, char *buf, int sz, void *ctx)
|
|||
|
||||
jobject ctxRef; /* WolfSSLContext object */
|
||||
jclass innerCtxClass; /* WolfSSLContext class */
|
||||
jmethodID recvCbMethodId; /* internalIORecvCallback ID */
|
||||
jbyteArray inData;
|
||||
|
||||
if (!g_vm || !ssl || !buf || !ctx) {
|
||||
|
@ -1140,18 +1139,10 @@ int NativeIORecvCb(WOLFSSL *ssl, char *buf, int sz, void *ctx)
|
|||
return WOLFSSL_CBIO_ERR_GENERAL;
|
||||
}
|
||||
|
||||
/* call internal I/O recv callback */
|
||||
recvCbMethodId = (*jenv)->GetMethodID(jenv, innerCtxClass,
|
||||
"internalIORecvCallback",
|
||||
"(Lcom/wolfssl/WolfSSLSession;[BI)I");
|
||||
if (!recvCbMethodId) {
|
||||
if ((*jenv)->ExceptionOccurred(jenv)) {
|
||||
(*jenv)->ExceptionDescribe(jenv);
|
||||
(*jenv)->ExceptionClear(jenv);
|
||||
}
|
||||
/* make sure cached recv callback method ID is not null */
|
||||
if (!g_sslIORecvMethodId) {
|
||||
(*jenv)->ThrowNew(jenv, excClass,
|
||||
"Error getting internalIORecvCallback method from JNI");
|
||||
(*jenv)->DeleteLocalRef(jenv, ctxRef);
|
||||
"Cached recv callback method ID is null in NativeIORecvCb");
|
||||
if (needsDetach)
|
||||
(*g_vm)->DetachCurrentThread(g_vm);
|
||||
return WOLFSSL_CBIO_ERR_GENERAL;
|
||||
|
@ -1161,7 +1152,7 @@ int NativeIORecvCb(WOLFSSL *ssl, char *buf, int sz, void *ctx)
|
|||
inData = (*jenv)->NewByteArray(jenv, sz);
|
||||
if (!inData) {
|
||||
(*jenv)->ThrowNew(jenv, excClass,
|
||||
"Error getting internalIORecvCallback method from JNI");
|
||||
"Error creating jbyteArray in NativeIORecvCb");
|
||||
(*jenv)->DeleteLocalRef(jenv, ctxRef);
|
||||
if (needsDetach)
|
||||
(*g_vm)->DetachCurrentThread(g_vm);
|
||||
|
@ -1170,7 +1161,7 @@ int NativeIORecvCb(WOLFSSL *ssl, char *buf, int sz, void *ctx)
|
|||
|
||||
/* call Java send callback, ignore native ctx since Java
|
||||
* handles it */
|
||||
retval = (*jenv)->CallIntMethod(jenv, ctxRef, recvCbMethodId,
|
||||
retval = (*jenv)->CallIntMethod(jenv, ctxRef, g_sslIORecvMethodId,
|
||||
(jobject)(*g_cachedSSLObj),
|
||||
inData, (jint)sz);
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -967,6 +967,14 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_setMTU
|
|||
JNIEXPORT jstring JNICALL Java_com_wolfssl_WolfSSLSession_stateStringLong
|
||||
(JNIEnv *, jobject, jlong);
|
||||
|
||||
/*
|
||||
* Class: com_wolfssl_WolfSSLSession
|
||||
* Method: getMaxOutputSize
|
||||
* Signature: (J)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_getMaxOutputSize
|
||||
(JNIEnv *, jobject, jlong);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -25,7 +25,25 @@
|
|||
#define _Included_com_wolfssl_globals
|
||||
|
||||
/* global JavaVM reference for JNIEnv lookup */
|
||||
extern JavaVM* g_vm;
|
||||
extern JavaVM* g_vm;
|
||||
|
||||
/* Cache static jmethodIDs for performance, since they are guaranteed to be the
|
||||
* same across all threads once cached. Initialized in JNI_OnLoad() and freed in
|
||||
* JNI_OnUnload(). */
|
||||
extern jmethodID g_sslIORecvMethodId; /* WolfSSLSession.internalIOSSLRecvCallback */
|
||||
extern jmethodID g_sslIORecvMethodId_BB; /* WolfSSLSession.internalIOSSLRecvCallback_BB */
|
||||
extern jmethodID g_sslIOSendMethodId; /* WolfSSLSession.internalIOSSLSendCallback */
|
||||
extern jmethodID g_sslIOSendMethodId_BB; /* WolfSSLSession.internalIOSSLSendCallback_BB */
|
||||
extern jmethodID g_isArrayIORecvCallbackSet; /* WolfSSL.isArrayIORecvCallbackSet */
|
||||
extern jmethodID g_isArrayIOSendCallbackSet; /* WolfSSL.isArrayIOSendCallbackSet */
|
||||
extern jmethodID g_isByteBufferIORecvCallbackSet; /* WolfSSL.isByteBufferIORecvCallbackSet */
|
||||
extern jmethodID g_isByteBufferIOSendCallbackSet; /* WolfSSL.isByteBufferIOSendCallbackSet */
|
||||
extern jmethodID g_bufferPositionMethodId; /* ByteBuffer.position() */
|
||||
extern jmethodID g_bufferLimitMethodId; /* ByteBuffer.limit() */
|
||||
extern jmethodID g_bufferHasArrayMethodId; /* ByteBuffer.hasArray() */
|
||||
extern jmethodID g_bufferArrayMethodId; /* ByteBuffer.array() */
|
||||
extern jmethodID g_bufferSetPositionMethodId; /* ByteBuffer.position(int) */
|
||||
extern jmethodID g_verifyCallbackMethodId; /* WolfSSLVerifyCallback.verifyCallback */
|
||||
|
||||
/* struct to hold I/O class, object refs */
|
||||
typedef struct {
|
||||
|
@ -38,5 +56,8 @@ unsigned int NativePskClientCb(WOLFSSL* ssl, const char* hint, char* identity,
|
|||
unsigned int NativePskServerCb(WOLFSSL* ssl, const char* identity,
|
||||
unsigned char* key, unsigned int max_key_len);
|
||||
|
||||
#endif
|
||||
/* Helper functions to throw exceptions */
|
||||
void throwWolfSSLJNIException(JNIEnv* jenv, const char* msg);
|
||||
void throwWolfSSLException(JNIEnv* jenv, const char* msg);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -35,6 +35,8 @@ done
|
|||
infer --fail-on-issue run -- javac \
|
||||
src/java/com/wolfssl/WolfSSL.java \
|
||||
src/java/com/wolfssl/WolfSSLALPNSelectCallback.java \
|
||||
src/java/com/wolfssl/WolfSSLByteBufferIORecvCallback.java \
|
||||
src/java/com/wolfssl/WolfSSLByteBufferIOSendCallback.java \
|
||||
src/java/com/wolfssl/WolfSSLCertManager.java \
|
||||
src/java/com/wolfssl/WolfSSLCertRequest.java \
|
||||
src/java/com/wolfssl/WolfSSLCertificate.java \
|
||||
|
|
|
@ -626,6 +626,9 @@ public class WolfSSL {
|
|||
getTls13SecretEnum_EXPORTER_SECRET();
|
||||
|
||||
this.active = true;
|
||||
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
|
||||
WolfSSLDebug.INFO, "wolfSSL library initialization done");
|
||||
}
|
||||
|
||||
/* ------------------- private/protected methods -------------------- */
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
/* WolfSSLByteBufferIORecvCallback.java
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
package com.wolfssl;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* wolfSSL ByteBuffer I/O Receive Callback Interface.
|
||||
*
|
||||
* This interface specifies how applicaitons should implement the I/O receive
|
||||
* callback class to be used by wolfSSL, using a ByteBuffer as the buffer.
|
||||
* <p>
|
||||
* After implementing this interface, it should be passed as a parameter
|
||||
* to the {@link WolfSSLContext#setIORecv(WolfSSLIORecvCallback)
|
||||
* WolfSSLContext.setIORecv()} or
|
||||
* {@link WolfSSLSession#setIORecv(WolfSSLIORecvCallback)
|
||||
* WolfSSLSession.setIORecv()} methods to be registered with the native wolfSSL
|
||||
* library.
|
||||
*/
|
||||
public interface WolfSSLByteBufferIORecvCallback {
|
||||
|
||||
/**
|
||||
* I/O receive callback method, using ByteBuffer.
|
||||
*
|
||||
* This method acts as the I/O receive callback to be used with wolfSSL.
|
||||
* This can be registered with an SSL session at the WolfSSLContext level
|
||||
* using WolfSSLContext#setIORecv(WolfSSLIORecvCallback), or at the
|
||||
* WolfSSLSession level using
|
||||
* WolfSSLSession#setIORecv(WolfSSLIORecvCallback).
|
||||
*
|
||||
* This method will be called by native wolfSSL when it needs data to
|
||||
* be read from the transport layer. The callback should read data and
|
||||
* place the data into the buffer provided. The number of bytes read should
|
||||
* be returned. The callback should return an error code on error.
|
||||
*
|
||||
* @param ssl the current SSL session object from which the callback was
|
||||
* initiated.
|
||||
* @param buf buffer in which the application should place data which
|
||||
* has been received from the peer.
|
||||
* @param sz size of buffer, <b>buf</b>
|
||||
* @param ctx I/O context to be used.
|
||||
* @return the number of bytes read, or an error. For possible error
|
||||
* codes, see the default EmbedRecv() function in
|
||||
* wolfssl_package/src/io.c
|
||||
*/
|
||||
public int receiveCallback(WolfSSLSession ssl, ByteBuffer buf, int sz,
|
||||
Object ctx);
|
||||
}
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
/* WolfSSLByteBufferIOSendCallback.java
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
package com.wolfssl;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/**
|
||||
* wolfSSL I/O Send Callback Interface.
|
||||
*
|
||||
* This interface specifies how applicaitons should implement the I/O send
|
||||
* callback class to be used by wolfSSL.
|
||||
* <p>
|
||||
* After implementing this interface, it should be passed as a parameter
|
||||
* to the {@link WolfSSLContext#setIOSend(WolfSSLIOSendCallback)
|
||||
* WolfSSLContext.setIOSend()} or
|
||||
* {@link WolfSSLSession#setIOSend(WolfSSLIOSendCallback)
|
||||
* WolfSSLSession.setIOSend()} methods to be registered with the native wolfSSL
|
||||
* library.
|
||||
*/
|
||||
public interface WolfSSLByteBufferIOSendCallback {
|
||||
|
||||
/**
|
||||
* I/O send callback method, using ByteBuffer.
|
||||
*
|
||||
* This method acts as the I/O send callback to be used with wolfSSL.
|
||||
* This can be registered with an SSL session at the WolfSSLContext level
|
||||
* using WolfSSLContext#setIOSend(WolfSSLIOSendCallback), or at the
|
||||
* WolfSSLSession level using
|
||||
* WolfSSLSession#setIOSend(WolfSSLIOSendCallback).
|
||||
*
|
||||
* This method will be called by native wolfSSL when it needs to send data.
|
||||
* The callback should send data from the provided ByteBuffer (buf) across
|
||||
* the transport layer. The number of bytes sent should be returned, or
|
||||
* a negative error code on error.
|
||||
*
|
||||
* @param ssl the current SSL session object from which the callback was
|
||||
* initiated.
|
||||
* @param buf buffer containing data to be sent to the peer.
|
||||
* @param sz size of data in buffer "<b>buf</b>"
|
||||
* @param ctx I/O context to be used.
|
||||
* @return the number of bytes sent, or an error. For possible error
|
||||
* codes, see the default EmbedSend() function in
|
||||
* wolfssl_package/src/io.c
|
||||
*/
|
||||
public int sendCallback(WolfSSLSession ssl, ByteBuffer buf, int sz,
|
||||
Object ctx);
|
||||
}
|
||||
|
|
@ -71,11 +71,21 @@ public class WolfSSLSession {
|
|||
private WolfSSLPskClientCallback internPskClientCb = null;
|
||||
private WolfSSLPskServerCallback internPskServerCb = null;
|
||||
|
||||
/* user-registerd I/O callbacks, called by internal WolfSSLSession
|
||||
* I/O callback. This is done in order to pass references to
|
||||
* WolfSSLSession object */
|
||||
private WolfSSLIORecvCallback internRecvSSLCb;
|
||||
private WolfSSLIOSendCallback internSendSSLCb;
|
||||
/* User-registerd I/O callbacks:
|
||||
*
|
||||
* These are called by internal WolfSSLSession I/O callback. This is done
|
||||
* in order to pass references to WolfSSLSession object. There are two sets
|
||||
* of I/O callbacks here, one set that will use byte[] and one that will
|
||||
* use ByteBuffer. Only one send and one recv callback can be set at a time
|
||||
* between the two. Native JNI code will give preference to using the
|
||||
* ByteBuffer variants for performance if set, since this will avoid an
|
||||
* extra native allocation (NewByteArray()). The ByteBuffer variant will
|
||||
* wrap the pre-allocated wolfSSL array in a Java direct ByteBuffer
|
||||
* to pass back up to Java. */
|
||||
private WolfSSLIORecvCallback internRecvSSLCb_array;
|
||||
private WolfSSLIOSendCallback internSendSSLCb_array;
|
||||
private WolfSSLByteBufferIORecvCallback internRecvSSLCb_BB;
|
||||
private WolfSSLByteBufferIOSendCallback internSendSSLCb_BB;
|
||||
|
||||
/* user-registered ALPN select callback, called by internal WolfSSLSession
|
||||
* ALPN select callback */
|
||||
|
@ -237,20 +247,66 @@ public class WolfSSLSession {
|
|||
return this.rsaDecCtx;
|
||||
}
|
||||
|
||||
/* Methods to detect which I/O callback variants have been set */
|
||||
private boolean isArrayIOSendCallbackSet() {
|
||||
return (internSendSSLCb_array != null);
|
||||
}
|
||||
|
||||
private boolean isByteBufferIOSendCallbackSet() {
|
||||
return (internSendSSLCb_BB != null);
|
||||
}
|
||||
|
||||
private boolean isArrayIORecvCallbackSet() {
|
||||
return (internRecvSSLCb_array != null);
|
||||
}
|
||||
|
||||
private boolean isByteBufferIORecvCallbackSet() {
|
||||
return (internRecvSSLCb_BB != null);
|
||||
}
|
||||
|
||||
/* These callbacks will be registered with native wolfSSL library */
|
||||
private int internalIOSSLRecvCallback(WolfSSLSession ssl, byte[] buf,
|
||||
int sz)
|
||||
|
||||
/**
|
||||
* Internal wolfSSL I/O receive callback, using byte array.
|
||||
*/
|
||||
private int internalIOSSLRecvCallback(WolfSSLSession ssl,
|
||||
byte[] buf, int sz)
|
||||
{
|
||||
/* call user-registered recv method */
|
||||
return internRecvSSLCb.receiveCallback(ssl, buf, sz,
|
||||
return internRecvSSLCb_array.receiveCallback(ssl, buf, sz,
|
||||
ssl.getIOReadCtx());
|
||||
}
|
||||
|
||||
private int internalIOSSLSendCallback(WolfSSLSession ssl, byte[] buf,
|
||||
int sz)
|
||||
/**
|
||||
* Internal wolfSSL I/O receive callback, using ByteBuffer.
|
||||
*/
|
||||
private int internalIOSSLRecvCallback(WolfSSLSession ssl,
|
||||
ByteBuffer buf, int sz)
|
||||
{
|
||||
/* call user-registered recv method */
|
||||
return internSendSSLCb.sendCallback(ssl, buf, sz,
|
||||
return internRecvSSLCb_BB.receiveCallback(ssl, buf, sz,
|
||||
ssl.getIOReadCtx());
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal wolfSSL I/O send callback, using byte array.
|
||||
*/
|
||||
private int internalIOSSLSendCallback(WolfSSLSession ssl,
|
||||
byte[] buf, int sz)
|
||||
{
|
||||
/* call user-registered recv method */
|
||||
return internSendSSLCb_array.sendCallback(ssl, buf, sz,
|
||||
ssl.getIOWriteCtx());
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal wolfSSL I/O send callback, using ByteBuffer.
|
||||
*/
|
||||
private int internalIOSSLSendCallback(WolfSSLSession ssl,
|
||||
ByteBuffer buf, int sz)
|
||||
{
|
||||
/* call user-registered recv method */
|
||||
return internSendSSLCb_BB.sendCallback(ssl, buf, sz,
|
||||
ssl.getIOWriteCtx());
|
||||
}
|
||||
|
||||
|
@ -440,6 +496,7 @@ public class WolfSSLSession {
|
|||
private native int getThreadsBlockedInPoll(long ssl);
|
||||
private native int setMTU(long ssl, int mtu);
|
||||
private native String stateStringLong(long ssl);
|
||||
private native int getMaxOutputSize(long ssl);
|
||||
|
||||
/* ------------------- session-specific methods --------------------- */
|
||||
|
||||
|
@ -2556,6 +2613,35 @@ public class WolfSSLSession {
|
|||
return state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return max record layer size plaintext input size
|
||||
*
|
||||
* @return max record layer size plaintext input size in bytes, or
|
||||
* negative value on error.
|
||||
*
|
||||
* @throws IllegalStateException WolfSSLContext has been freed
|
||||
*/
|
||||
public int getMaxOutputSize() throws IllegalStateException {
|
||||
|
||||
int ret;
|
||||
|
||||
confirmObjectIsActive();
|
||||
|
||||
synchronized (sslLock) {
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
|
||||
WolfSSLDebug.INFO, this.sslPtr,
|
||||
"entered getOutputSize()");
|
||||
|
||||
ret = getMaxOutputSize(this.sslPtr);
|
||||
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
|
||||
WolfSSLDebug.INFO, this.sslPtr,
|
||||
"max output size: " + ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if a reused session was negotiated during the SSL
|
||||
* handshake.
|
||||
|
@ -3098,9 +3184,6 @@ public class WolfSSLSession {
|
|||
confirmObjectIsActive();
|
||||
|
||||
synchronized (sslLock) {
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
|
||||
WolfSSLDebug.INFO, this.sslPtr, "entered getIOReadCtx()");
|
||||
|
||||
return this.ioReadCtx;
|
||||
}
|
||||
}
|
||||
|
@ -3149,9 +3232,6 @@ public class WolfSSLSession {
|
|||
confirmObjectIsActive();
|
||||
|
||||
synchronized (sslLock) {
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
|
||||
WolfSSLDebug.INFO, this.sslPtr, "entered getIOWriteCtx()");
|
||||
|
||||
return this.ioWriteCtx;
|
||||
}
|
||||
}
|
||||
|
@ -4338,11 +4418,18 @@ public class WolfSSLSession {
|
|||
|
||||
/**
|
||||
* Registers a receive callback for wolfSSL to get input data.
|
||||
* By default, wolfSSL uses EmbedReceive() in src/io.c as the callback.
|
||||
* This uses the system's TCP recv() function. The user can register a
|
||||
* function to get input from memory, some other network module, or from
|
||||
* anywhere. Please see the EmbedReceive() function in src/io.c as a
|
||||
* guide for how the function should work and for error codes.
|
||||
*
|
||||
* This receive callback uses WolfSSLIORecvCallback which uses
|
||||
* byte arrays (byte[]). To use direct ByteBuffers, and avoid an extra
|
||||
* JNI array allocaiton, use
|
||||
* setIORecvByteBuffer(WolfSSLByteBufferIORecvCallback).
|
||||
*
|
||||
* By default, wolfSSL uses EmbedReceive() in src/io.c as the callback
|
||||
* which uses the system TCP recv() function. The user can register a
|
||||
* method here to get receive TLS-encoded data from memory, some other
|
||||
* network module, or anywhere else. Please see the EmbedReceive() function
|
||||
* in src/io.c as a guide for how the function should work and for error
|
||||
* codes.
|
||||
* <p>
|
||||
* In particular, <b>IO_ERR_WANT_READ</b> should be returned for
|
||||
* non-blocking receive when no data is ready.
|
||||
|
@ -4364,10 +4451,16 @@ public class WolfSSLSession {
|
|||
synchronized (sslLock) {
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
|
||||
WolfSSLDebug.INFO, this.sslPtr,
|
||||
"entered setIORecv(" + callback + ")");
|
||||
"entered setIORecv(" + callback + ") - byte array");
|
||||
|
||||
/* Only allow one recv callback registered at a time, if ByteBuffer
|
||||
* version has been set, set to null before setting byte variant. */
|
||||
if (internRecvSSLCb_BB != null) {
|
||||
internRecvSSLCb_BB = null;
|
||||
}
|
||||
|
||||
/* set user I/O recv */
|
||||
internRecvSSLCb = callback;
|
||||
internRecvSSLCb_array = callback;
|
||||
|
||||
if (callback != null) {
|
||||
/* register internal callback with native library */
|
||||
|
@ -4377,12 +4470,74 @@ public class WolfSSLSession {
|
|||
}
|
||||
|
||||
/**
|
||||
* Registers a send callback for wolfSSL to write output data.
|
||||
* Registers a receive callback for wolfSSL to get input data.
|
||||
*
|
||||
* This receive callback uses WolfSSLByteBufferIORecvCallback which uses
|
||||
* a direct ByteBuffer. To use a byte array instead use
|
||||
* setIORecv(WolfSSLIORecvCallback), but this will incur one additional
|
||||
* native JNI array allocation.
|
||||
*
|
||||
* By default, wolfSSL uses EmbedReceive() in src/io.c as the callback
|
||||
* which uses the system TCP recv() function. The user can register a
|
||||
* method here to get receive TLS-encoded data from memory, some other
|
||||
* network module, or anywhere else. Please see the EmbedReceive() function
|
||||
* in src/io.c as a guide for how the function should work and for error
|
||||
* codes.
|
||||
* <p>
|
||||
* In particular, <b>IO_ERR_WANT_READ</b> should be returned for
|
||||
* non-blocking receive when no data is ready.
|
||||
*
|
||||
* @param callback method to be registered as the receive callback for
|
||||
* the wolfSSL context. The signature of this function
|
||||
* must follow that as shown in
|
||||
* WolfSSLByteBufferIORecvCallback#receiveCallback(
|
||||
* WolfSSLSession, ByteBuffer, int, long).
|
||||
* @throws IllegalStateException WolfSSLContext has been freed
|
||||
* @throws WolfSSLJNIException Internal JNI error
|
||||
* @see #setIOSend(WolfSSLIOSendCallback)
|
||||
*/
|
||||
public void setIORecvByteBuffer(WolfSSLByteBufferIORecvCallback callback)
|
||||
throws IllegalStateException, WolfSSLJNIException {
|
||||
|
||||
confirmObjectIsActive();
|
||||
|
||||
synchronized (sslLock) {
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
|
||||
WolfSSLDebug.INFO, this.sslPtr,
|
||||
"entered setIORecv(" + callback + ") - ByteBuffer");
|
||||
|
||||
/* Only allow one recv callback registered at a time, if array
|
||||
* version has been set, set to null before setting ByteBuffer. */
|
||||
if (internRecvSSLCb_array != null) {
|
||||
internRecvSSLCb_array = null;
|
||||
}
|
||||
|
||||
/* set user I/O recv */
|
||||
internRecvSSLCb_BB = callback;
|
||||
|
||||
if (callback != null) {
|
||||
/* Register internal callback with native library, registers
|
||||
* JNI NativeSSLIORecvCb() with native wolfSSL.
|
||||
* NativeSSLIORecvCb() will then call back into
|
||||
* internRecvSSLCb_array/BB(). */
|
||||
setSSLIORecv(this.sslPtr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a send callback for wolfSSL to write TLS encoded output data.
|
||||
*
|
||||
* This send callback uses WolfSSLIOSendCallback which uses byte arrays
|
||||
* (byte[]). To use direct ByteBuffers, and avoid an extra JNI array
|
||||
* allocation, use setIOSendByteBuffer(WolfSSLByteBufferIOSendCallback).
|
||||
*
|
||||
* By default, wolfSSL uses EmbedSend() in src/io.c as the callback,
|
||||
* which uses the system's TCP send() function. The user can register
|
||||
* a function to send output to memory, some other network module, or
|
||||
* to anywhere. Please see the EmbedSend() function in src/io.c as a
|
||||
* guide for how the function should work and for error codes.
|
||||
* which uses the system TCP send() function. The user can register
|
||||
* a method here to send TLS-encoded output data to memory, some other
|
||||
* network module, or to anywhere else. Please see the EmbedSend() function
|
||||
* in src/io.c as a guide for how the function should work and for error
|
||||
* codes.
|
||||
* <p>
|
||||
* In particular, <b>IO_ERR_WANT_WRITE</b> should be returned for
|
||||
* non-blocking send when the action cannot be taken yet.
|
||||
|
@ -4404,13 +4559,78 @@ public class WolfSSLSession {
|
|||
synchronized (sslLock) {
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
|
||||
WolfSSLDebug.INFO, this.sslPtr,
|
||||
"entered setIOSend(" + callback + ")");
|
||||
"entered setIOSend(" + callback + ") - byte array");
|
||||
|
||||
/* Only allow one send callback registered at a time, if ByteBuffer
|
||||
* version has been set, set to null before setting byte variant. */
|
||||
if (internSendSSLCb_BB != null) {
|
||||
internSendSSLCb_BB = null;
|
||||
}
|
||||
|
||||
/* set user I/O send */
|
||||
internSendSSLCb = callback;
|
||||
internSendSSLCb_array = callback;
|
||||
|
||||
if (callback != null) {
|
||||
/* register internal callback with native library */
|
||||
/* Register internal callback with native library, registers
|
||||
* JNI NativeSSLIOSendCb() with native wolfSSL.
|
||||
* NativeSSLIOSendCb() will then call back into
|
||||
* internSendSSLCb_array/BB(). */
|
||||
setSSLIOSend(this.sslPtr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a send callback for wolfSSL to write TLS encoded output data.
|
||||
*
|
||||
* This send callback uses WolfSSLByteBufferIOSendCallback which uses a
|
||||
* ByteBuffer. To use a byte array instead, use
|
||||
* setIOSend(WolfSSLIOSendCallback), but this will incur one
|
||||
* additional native JNI array allocation.
|
||||
*
|
||||
* By default, wolfSSL uses EmbedSend() in src/io.c as the callback,
|
||||
* which uses the system TCP send() function. The user can register
|
||||
* a method here to send TLS-encoded output data to memory, some other
|
||||
* network module, or to anywhere else. Please see the EmbedSend() function
|
||||
* in src/io.c as a guide for how the function should work and for error
|
||||
* codes.
|
||||
* <p>
|
||||
* In particular, <b>IO_ERR_WANT_WRITE</b> should be returned for
|
||||
* non-blocking send when the action cannot be taken yet.
|
||||
*
|
||||
* @param callback method to be registered as the send callback for
|
||||
* the wolfSSL context. The signature of this function
|
||||
* must follow that as shown in
|
||||
* WolfSSLByteBufferIOSendCallback#sendCallback(
|
||||
* WolfSSLSession, ByteBuffer, int, Object).
|
||||
* @throws IllegalStateException WolfSSLSession has been freed
|
||||
* @throws WolfSSLJNIException Internal JNI error
|
||||
* @see #setIORecv(WolfSSLIORecvCallback)
|
||||
*/
|
||||
public void setIOSendByteBuffer(WolfSSLByteBufferIOSendCallback callback)
|
||||
throws IllegalStateException, WolfSSLJNIException {
|
||||
|
||||
confirmObjectIsActive();
|
||||
|
||||
synchronized (sslLock) {
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
|
||||
WolfSSLDebug.INFO, this.sslPtr,
|
||||
"entered setIOSend(" + callback + ") - ByteBuffer");
|
||||
|
||||
/* Only allow one recv callback registered at a time, if array
|
||||
* version has been set, set to null before setting ByteBuffer. */
|
||||
if (internSendSSLCb_array != null) {
|
||||
internSendSSLCb_array = null;
|
||||
}
|
||||
|
||||
/* set user I/O send */
|
||||
internSendSSLCb_BB = callback;
|
||||
|
||||
if (callback != null) {
|
||||
/* Register internal callback with native library, registers
|
||||
* JNI NativeSSLIOSendCb() with native wolfSSL.
|
||||
* NativeSSLIOSendCb() will then call back into
|
||||
* internSendSSLCb_array/BB(). */
|
||||
setSSLIOSend(this.sslPtr);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,8 +24,8 @@ package com.wolfssl.provider.jsse;
|
|||
import com.wolfssl.WolfSSL;
|
||||
import com.wolfssl.WolfSSLDebug;
|
||||
import com.wolfssl.WolfSSLException;
|
||||
import com.wolfssl.WolfSSLIORecvCallback;
|
||||
import com.wolfssl.WolfSSLIOSendCallback;
|
||||
import com.wolfssl.WolfSSLByteBufferIORecvCallback;
|
||||
import com.wolfssl.WolfSSLByteBufferIOSendCallback;
|
||||
import com.wolfssl.WolfSSLJNIException;
|
||||
import com.wolfssl.WolfSSLSession;
|
||||
import com.wolfssl.WolfSSLALPNSelectCallback;
|
||||
|
@ -37,7 +37,6 @@ import java.util.function.BiFunction;
|
|||
import java.util.List;
|
||||
import java.util.Arrays;
|
||||
import java.util.ArrayList;
|
||||
import java.util.logging.Level;
|
||||
import java.security.cert.CertificateEncodingException;
|
||||
import javax.net.ssl.SSLEngine;
|
||||
import javax.net.ssl.SSLEngineResult;
|
||||
|
@ -72,7 +71,6 @@ public class WolfSSLEngine extends SSLEngine {
|
|||
private com.wolfssl.WolfSSLContext ctx = null;
|
||||
private WolfSSLAuthStore authStore = null;
|
||||
private WolfSSLParameters params = null;
|
||||
private byte[] toSend = null; /* encrypted packet to send */
|
||||
private int nativeWantsToWrite = 0;
|
||||
private int nativeWantsToRead = 0;
|
||||
private HandshakeStatus hs = SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING;
|
||||
|
@ -126,6 +124,22 @@ public class WolfSSLEngine extends SSLEngine {
|
|||
private ByteBuffer netData = null;
|
||||
private final Object netDataLock = new Object();
|
||||
|
||||
/* Single buffer used to hold application data to be sent, allocated once
|
||||
* inside SendAppData, of size SSLSession.getApplicationBufferSize() */
|
||||
private ByteBuffer staticAppDataBuf = null;
|
||||
|
||||
/* Default size of internalIOSendBuf, 16k to match TLS record size.
|
||||
* TODO - add upper bound on I/O send buf resize allocations. */
|
||||
private static final int INTERNAL_IOSEND_BUF_SZ = 16 * 1024;
|
||||
/* static buffer used to hold encrypted data to be sent, allocated inside
|
||||
* internalSendCb() and expanded only if needed. Synchronize on toSendLock
|
||||
* when accessing this buffer. */
|
||||
private byte[] internalIOSendBuf = new byte[INTERNAL_IOSEND_BUF_SZ];
|
||||
/* Total size of internalIOSendBuf */
|
||||
private int internalIOSendBufSz = INTERNAL_IOSEND_BUF_SZ;
|
||||
/* Offset into internalIOSendBuf to start writing data */
|
||||
private int internalIOSendBufOffset = 0;
|
||||
|
||||
/* Locks for synchronization */
|
||||
private final Object ioLock = new Object();
|
||||
private final Object toSendLock = new Object();
|
||||
|
@ -308,8 +322,8 @@ public class WolfSSLEngine extends SSLEngine {
|
|||
if (recvCb == null) {
|
||||
recvCb = new RecvCB();
|
||||
}
|
||||
ssl.setIORecv(recvCb);
|
||||
ssl.setIOSend(sendCb);
|
||||
ssl.setIORecvByteBuffer(recvCb);
|
||||
ssl.setIOSendByteBuffer(sendCb);
|
||||
ssl.setIOReadCtx(this);
|
||||
ssl.setIOWriteCtx(this);
|
||||
|
||||
|
@ -335,8 +349,8 @@ public class WolfSSLEngine extends SSLEngine {
|
|||
private void unsetSSLCallbacks() throws WolfSSLJNIException {
|
||||
|
||||
synchronized (ioLock) {
|
||||
ssl.setIORecv(null);
|
||||
ssl.setIOSend(null);
|
||||
ssl.setIORecvByteBuffer(null);
|
||||
ssl.setIOSendByteBuffer(null);
|
||||
ssl.setIOReadCtx(null);
|
||||
ssl.setIOWriteCtx(null);
|
||||
}
|
||||
|
@ -373,19 +387,18 @@ public class WolfSSLEngine extends SSLEngine {
|
|||
int sendSz = 0;
|
||||
|
||||
synchronized (toSendLock) {
|
||||
if (this.toSend != null) {
|
||||
sendSz = Math.min(this.toSend.length, out.remaining());
|
||||
out.put(this.toSend, 0, sendSz);
|
||||
if (this.internalIOSendBuf != null) {
|
||||
sendSz = Math.min(this.internalIOSendBufOffset, out.remaining());
|
||||
out.put(this.internalIOSendBuf, 0, sendSz);
|
||||
|
||||
if (sendSz != this.toSend.length) {
|
||||
/* resize and adjust remaining toSend data */
|
||||
byte[] tmp = new byte[this.toSend.length - sendSz];
|
||||
System.arraycopy(this.toSend, sendSz, tmp, 0,
|
||||
this.toSend.length - sendSz);
|
||||
this.toSend = tmp;
|
||||
if (sendSz != this.internalIOSendBufOffset) {
|
||||
System.arraycopy(this.internalIOSendBuf, sendSz,
|
||||
this.internalIOSendBuf, 0,
|
||||
this.internalIOSendBufOffset - sendSz);
|
||||
}
|
||||
else {
|
||||
this.toSend = null;
|
||||
/* reset internalIOSendBufOffset to zero, no data left */
|
||||
this.internalIOSendBufOffset = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -407,7 +420,7 @@ public class WolfSSLEngine extends SSLEngine {
|
|||
this.closeNotifySent = true;
|
||||
this.closeNotifyReceived = true;
|
||||
this.inBoundOpen = false;
|
||||
if (this.toSend == null || this.toSend.length == 0) {
|
||||
if (this.internalIOSendBufOffset == 0) {
|
||||
/* Don't close outbound if we have a close_notify alert
|
||||
* send back to peer. Native wolfSSL may have already generated
|
||||
* it and is reflected in SSL_SENT_SHUTDOWN flag, but we
|
||||
|
@ -590,17 +603,23 @@ public class WolfSSLEngine extends SSLEngine {
|
|||
int[] pos = new int[len]; /* in[] positions */
|
||||
int[] limit = new int[len]; /* in[] limits */
|
||||
|
||||
/* get total input data size, store input array positions */
|
||||
/* Get total input data size, store input array positions */
|
||||
for (i = ofst; i < ofst + len; i++) {
|
||||
totalIn += in[i].remaining();
|
||||
pos[i] = in[i].position();
|
||||
limit[i] = in[i].limit();
|
||||
}
|
||||
|
||||
/* only send up to maximum app data size chunk */
|
||||
sendSz = Math.min(totalIn,
|
||||
this.engineHelper.getSession().getApplicationBufferSize());
|
||||
dataBuf = ByteBuffer.allocate(sendSz);
|
||||
/* Allocate static buffer for application data, clear before use */
|
||||
sendSz = this.engineHelper.getSession().getApplicationBufferSize();
|
||||
if (this.staticAppDataBuf == null) {
|
||||
/* allocate static buffer for application data */
|
||||
this.staticAppDataBuf = ByteBuffer.allocateDirect(sendSz);
|
||||
}
|
||||
this.staticAppDataBuf.clear();
|
||||
|
||||
/* Only send up to maximum app data size chunk */
|
||||
sendSz = Math.min(totalIn, sendSz);
|
||||
|
||||
/* gather byte array of sendSz bytes from input buffers */
|
||||
inputLeft = sendSz;
|
||||
|
@ -608,7 +627,7 @@ public class WolfSSLEngine extends SSLEngine {
|
|||
int bufChunk = Math.min(in[i].remaining(), inputLeft);
|
||||
|
||||
in[i].limit(in[i].position() + bufChunk); /* set limit */
|
||||
dataBuf.put(in[i]); /* get data */
|
||||
this.staticAppDataBuf.put(in[i]); /* get data */
|
||||
inputLeft -= bufChunk;
|
||||
in[i].limit(limit[i]); /* reset limit */
|
||||
|
||||
|
@ -618,8 +637,8 @@ public class WolfSSLEngine extends SSLEngine {
|
|||
}
|
||||
|
||||
dataArr = new byte[sendSz];
|
||||
dataBuf.rewind();
|
||||
dataBuf.get(dataArr);
|
||||
this.staticAppDataBuf.rewind();
|
||||
this.staticAppDataBuf.get(dataArr);
|
||||
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||
"calling ssl.write() with size: " + sendSz);
|
||||
|
@ -707,13 +726,8 @@ public class WolfSSLEngine extends SSLEngine {
|
|||
"out.position(): " + out.position());
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||
"out.limit(): " + out.limit());
|
||||
if (this.toSend != null) {
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||
"toSend.length: " + this.toSend.length);
|
||||
} else {
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||
"toSend.length: 0");
|
||||
}
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||
"internalIOSendBufOffset: " + this.internalIOSendBufOffset);
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||
"closeNotifySent: " + this.closeNotifySent);
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||
|
@ -756,6 +770,10 @@ public class WolfSSLEngine extends SSLEngine {
|
|||
/* Force out buffer to be large enough to hold max packet size */
|
||||
if (out.remaining() <
|
||||
this.engineHelper.getSession().getPacketBufferSize()) {
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||
"out.remaining() too small (" +
|
||||
out.remaining() + "), need at least: " +
|
||||
this.engineHelper.getSession().getPacketBufferSize());
|
||||
return new SSLEngineResult(Status.BUFFER_OVERFLOW, hs, 0, 0);
|
||||
}
|
||||
|
||||
|
@ -832,13 +850,8 @@ public class WolfSSLEngine extends SSLEngine {
|
|||
"out.position(): " + out.position());
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||
"out.limit(): " + out.limit());
|
||||
if (this.toSend != null) {
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||
"toSend.length: " + this.toSend.length);
|
||||
} else {
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||
"toSend.length: 0");
|
||||
}
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||
"internalIOSendBufOffset: " + this.internalIOSendBufOffset);
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||
"closeNotifySent: " + this.closeNotifySent);
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||
|
@ -1064,7 +1077,7 @@ public class WolfSSLEngine extends SSLEngine {
|
|||
public synchronized SSLEngineResult unwrap(ByteBuffer in, ByteBuffer[] out,
|
||||
int ofst, int length) throws SSLException {
|
||||
|
||||
int i, ret = 0, sz = 0, err = 0;
|
||||
int i, ret = 0, err = 0;
|
||||
int inPosition = 0;
|
||||
int inRemaining = 0;
|
||||
int consumed = 0;
|
||||
|
@ -1072,7 +1085,6 @@ public class WolfSSLEngine extends SSLEngine {
|
|||
long dtlsPrevDropCount = 0;
|
||||
long dtlsCurrDropCount = 0;
|
||||
int prevSessionTicketCount = 0;
|
||||
byte[] tmp;
|
||||
|
||||
/* Set initial status for SSLEngineResult return */
|
||||
Status status = SSLEngineResult.Status.OK;
|
||||
|
@ -1130,13 +1142,8 @@ public class WolfSSLEngine extends SSLEngine {
|
|||
}
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||
"ofst: " + ofst + ", length: " + length);
|
||||
if (this.toSend != null) {
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||
"toSend.length: " + this.toSend.length);
|
||||
} else {
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||
"toSend.length: 0");
|
||||
}
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||
"internalIOSendBufOffset: " + this.internalIOSendBufOffset);
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||
"closeNotifySent: " + this.closeNotifySent);
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||
|
@ -1174,7 +1181,7 @@ public class WolfSSLEngine extends SSLEngine {
|
|||
hs = SSLEngineResult.HandshakeStatus.NEED_WRAP;
|
||||
}
|
||||
else if (hs == SSLEngineResult.HandshakeStatus.NEED_WRAP &&
|
||||
(this.toSend != null) && (this.toSend.length > 0)) {
|
||||
this.internalIOSendBufOffset > 0) {
|
||||
/* Already have data buffered to send and in NEED_WRAP state,
|
||||
* just return so wrap() can be called */
|
||||
hs = SSLEngineResult.HandshakeStatus.NEED_WRAP;
|
||||
|
@ -1343,10 +1350,10 @@ public class WolfSSLEngine extends SSLEngine {
|
|||
synchronized (toSendLock) {
|
||||
synchronized (netDataLock) {
|
||||
if (ret <= 0 && err == WolfSSL.SSL_ERROR_WANT_READ &&
|
||||
in.remaining() == 0 && (this.toSend == null ||
|
||||
(this.toSend != null && this.toSend.length == 0))
|
||||
&& (prevSessionTicketCount ==
|
||||
this.sessionTicketCount)) {
|
||||
in.remaining() == 0 &&
|
||||
(this.internalIOSendBufOffset == 0) &&
|
||||
(prevSessionTicketCount ==
|
||||
this.sessionTicketCount)) {
|
||||
|
||||
if ((this.ssl.dtls() == 0) ||
|
||||
(this.handshakeFinished &&
|
||||
|
@ -1376,8 +1383,7 @@ public class WolfSSLEngine extends SSLEngine {
|
|||
if (this.getUseClientMode() && this.handshakeFinished &&
|
||||
this.ssl.hasSessionTicket() &&
|
||||
this.sessionTicketReceived == false) {
|
||||
if (this.ssl.dtls() == 1 && this.toSend != null &&
|
||||
this.toSend.length > 0) {
|
||||
if (this.ssl.dtls() == 1 && this.internalIOSendBufOffset > 0) {
|
||||
/* DTLS 1.3 ACK has been produced in response to
|
||||
* session ticket message, let's set HS status to
|
||||
* NEED_WRAP so application knows it needs to be sent. */
|
||||
|
@ -1414,13 +1420,8 @@ public class WolfSSLEngine extends SSLEngine {
|
|||
}
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||
"ofst: " + ofst + ", length: " + length);
|
||||
if (this.toSend != null) {
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||
"toSend.length: " + this.toSend.length);
|
||||
} else {
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||
"toSend.length: 0");
|
||||
}
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||
"internalIOSendBufOffset: " + this.internalIOSendBufOffset);
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||
"handshakeFinished: " + this.handshakeFinished);
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||
|
@ -1500,12 +1501,12 @@ public class WolfSSLEngine extends SSLEngine {
|
|||
err = ssl.getError(ret);
|
||||
}
|
||||
|
||||
/* Lock access to this.toSend and this.toRead */
|
||||
/* Lock access to this.internalIOSendBuf and this.toRead */
|
||||
synchronized (toSendLock) {
|
||||
if (this.handshakeFinished == true) {
|
||||
/* close_notify sent by wolfSSL but not across transport yet */
|
||||
if (this.closeNotifySent == true &&
|
||||
this.toSend != null && this.toSend.length > 0) {
|
||||
this.internalIOSendBufOffset > 0) {
|
||||
hs = SSLEngineResult.HandshakeStatus.NEED_WRAP;
|
||||
}
|
||||
/* close_notify received, need to send one back */
|
||||
|
@ -1533,7 +1534,7 @@ public class WolfSSLEngine extends SSLEngine {
|
|||
synchronized (netDataLock) {
|
||||
synchronized (ioLock) {
|
||||
if (sslConnectAcceptSuccess() && ssl.handshakeDone() &&
|
||||
(this.toSend == null) &&
|
||||
(this.internalIOSendBufOffset == 0) &&
|
||||
(this.nativeWantsToWrite == 0) &&
|
||||
(this.nativeWantsToRead == 0)) {
|
||||
|
||||
|
@ -1552,7 +1553,7 @@ public class WolfSSLEngine extends SSLEngine {
|
|||
}
|
||||
/* give priority of WRAP/UNWRAP to state of our internal
|
||||
* I/O data buffers first, then wolfSSL err status */
|
||||
else if (this.toSend != null && this.toSend.length > 0) {
|
||||
else if (this.internalIOSendBufOffset > 0) {
|
||||
hs = SSLEngineResult.HandshakeStatus.NEED_WRAP;
|
||||
}
|
||||
else if (this.netData != null &&
|
||||
|
@ -2110,9 +2111,7 @@ public class WolfSSLEngine extends SSLEngine {
|
|||
*
|
||||
* @return number of bytes placed into send queue
|
||||
*/
|
||||
protected synchronized int internalSendCb(byte[] in, int sz) {
|
||||
int totalSz = sz, idx = 0;
|
||||
byte[] prevToSend = null;
|
||||
protected synchronized int internalSendCb(ByteBuffer in, int sz) {
|
||||
|
||||
synchronized (toSendLock) {
|
||||
/* As per JSSE Reference Guide, Section 8 DTLS implementation
|
||||
|
@ -2122,7 +2121,8 @@ public class WolfSSLEngine extends SSLEngine {
|
|||
/* TODO - do we need to fragment data here if larger than
|
||||
* SSLParameters.getMaximumPacketSize() with DTLS? */
|
||||
if (this.ssl.dtls() == 1) {
|
||||
if (this.toSend != null) {
|
||||
if ((this.internalIOSendBuf != null) &&
|
||||
(this.internalIOSendBufOffset > 0)) {
|
||||
/* Cause SSLEngine to only send one packet at a time.
|
||||
* Keep track if wolfSSL had wanted to send data. We will
|
||||
* use that information when setting the handshake
|
||||
|
@ -2139,27 +2139,39 @@ public class WolfSSLEngine extends SSLEngine {
|
|||
this.nativeWantsToWrite = 0;
|
||||
}
|
||||
|
||||
/* Make copy of existing toSend array before expanding */
|
||||
if (this.toSend != null) {
|
||||
prevToSend = this.toSend.clone();
|
||||
totalSz += this.toSend.length;
|
||||
if (sz <= 0) {
|
||||
/* No data to send */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Allocate new array to hold data to be sent */
|
||||
this.toSend = new byte[totalSz];
|
||||
|
||||
/* Copy existing toSend data over */
|
||||
if (prevToSend != null) {
|
||||
System.arraycopy(prevToSend, 0, this.toSend, idx,
|
||||
prevToSend.length);
|
||||
idx += prevToSend.length;
|
||||
/* If we have more data than internal static buffer,
|
||||
* grow buffer 2x (or up to sz needed) and copy data over */
|
||||
if ((this.internalIOSendBufSz -
|
||||
this.internalIOSendBufOffset) < sz) {
|
||||
/* Allocate new buffer to hold data to be sent */
|
||||
int newSz = this.internalIOSendBufSz * 2;
|
||||
if (newSz < sz) {
|
||||
newSz = sz;
|
||||
}
|
||||
byte[] newBuf = new byte[newSz];
|
||||
System.arraycopy(this.internalIOSendBuf, 0,
|
||||
newBuf, 0,
|
||||
this.internalIOSendBufOffset);
|
||||
this.internalIOSendBuf = newBuf;
|
||||
this.internalIOSendBufSz = newSz;
|
||||
}
|
||||
System.arraycopy(in, 0, this.toSend, idx, sz);
|
||||
}
|
||||
|
||||
if (ioDebugEnabled == true) {
|
||||
WolfSSLDebug.logHex(getClass(), WolfSSLDebug.INFO,
|
||||
"CB Write", in, sz);
|
||||
/* Add data to end of internal static buffer */
|
||||
in.get(this.internalIOSendBuf, this.internalIOSendBufOffset, sz);
|
||||
|
||||
if (ioDebugEnabled == true) {
|
||||
WolfSSLDebug.logHex(getClass(), WolfSSLDebug.INFO,
|
||||
"CB Write", Arrays.copyOfRange(this.internalIOSendBuf,
|
||||
this.internalIOSendBufOffset,
|
||||
this.internalIOSendBufOffset + sz), sz);
|
||||
}
|
||||
|
||||
this.internalIOSendBufOffset += sz;
|
||||
}
|
||||
|
||||
return sz;
|
||||
|
@ -2169,15 +2181,16 @@ public class WolfSSLEngine extends SSLEngine {
|
|||
* Internal receive callback. Reads from netData and gives bytes back
|
||||
* to native wolfSSL for processing.
|
||||
*
|
||||
* @param toRead byte array into which to place data read from transport
|
||||
* @param toRead ByteBuffer into which to place data read from transport
|
||||
* @param sz number of bytes that should be read/copied from transport
|
||||
*
|
||||
* @return number of bytes read into toRead array or negative
|
||||
* value on error
|
||||
*/
|
||||
protected synchronized int internalRecvCb(byte[] toRead, int sz) {
|
||||
protected synchronized int internalRecvCb(ByteBuffer toRead, int sz) {
|
||||
|
||||
int max = 0;
|
||||
int originalLimit = 0;
|
||||
|
||||
synchronized (netDataLock) {
|
||||
if (ioDebugEnabled == true) {
|
||||
|
@ -2211,13 +2224,22 @@ public class WolfSSLEngine extends SSLEngine {
|
|||
this.nativeWantsToRead = 0;
|
||||
|
||||
max = (sz < this.netData.remaining()) ? sz : this.netData.remaining();
|
||||
this.netData.get(toRead, 0, max);
|
||||
|
||||
/* Print out bytes read from toRead buffer */
|
||||
if (ioDebugEnabled == true) {
|
||||
int toReadPos = toRead.position();
|
||||
byte[] tmpArr = new byte[max];
|
||||
toRead.get(tmpArr, 0, max);
|
||||
WolfSSLDebug.logHex(getClass(), WolfSSLDebug.INFO,
|
||||
"CB Read", toRead, max);
|
||||
"CB Read", tmpArr, max);
|
||||
toRead.position(toReadPos);
|
||||
}
|
||||
|
||||
originalLimit = this.netData.limit();
|
||||
this.netData.limit(this.netData.position() + max);
|
||||
toRead.put(this.netData);
|
||||
this.netData.limit(originalLimit);
|
||||
|
||||
return max;
|
||||
}
|
||||
}
|
||||
|
@ -2248,28 +2270,28 @@ public class WolfSSLEngine extends SSLEngine {
|
|||
return 0;
|
||||
}
|
||||
|
||||
private class SendCB implements WolfSSLIOSendCallback {
|
||||
private class SendCB implements WolfSSLByteBufferIOSendCallback {
|
||||
|
||||
protected SendCB() {
|
||||
|
||||
}
|
||||
|
||||
public int sendCallback(WolfSSLSession ssl, byte[] toSend, int sz,
|
||||
public int sendCallback(WolfSSLSession ssl, ByteBuffer toSend, int sz,
|
||||
Object engine) {
|
||||
return ((WolfSSLEngine)engine).internalSendCb(toSend, sz);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class RecvCB implements WolfSSLIORecvCallback {
|
||||
private class RecvCB implements WolfSSLByteBufferIORecvCallback {
|
||||
|
||||
protected RecvCB() {
|
||||
|
||||
}
|
||||
|
||||
public int receiveCallback(WolfSSLSession ssl, byte[] out, int sz,
|
||||
public int receiveCallback(WolfSSLSession ssl, ByteBuffer buf, int sz,
|
||||
Object engine) {
|
||||
return ((WolfSSLEngine)engine).internalRecvCb(out, sz);
|
||||
return ((WolfSSLEngine)engine).internalRecvCb(buf, sz);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -2292,6 +2314,11 @@ public class WolfSSLEngine extends SSLEngine {
|
|||
this.ssl.freeSSL();
|
||||
this.ssl = null;
|
||||
}
|
||||
/* Clear our reference to static application direct ByteBuffer */
|
||||
if (this.staticAppDataBuf != null) {
|
||||
this.staticAppDataBuf.clear();
|
||||
this.staticAppDataBuf = null;
|
||||
}
|
||||
super.finalize();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -760,15 +760,52 @@ public class WolfSSLImplementSSLSession extends ExtendedSSLSession
|
|||
return this.port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be called by SSLEngine consumers to determine maximum
|
||||
* output buffer size, to be used for buffer allocations.
|
||||
*
|
||||
* @return maximum output buffer size
|
||||
*/
|
||||
@Override
|
||||
public int getPacketBufferSize() {
|
||||
/* Match conscrypt's calculations here for maximum potential
|
||||
* SSL/TLS record length. Used by SSLEngine consumers to allocate
|
||||
* output buffer size.
|
||||
public synchronized int getPacketBufferSize() {
|
||||
|
||||
/* JSSE implementations seem to set the SSL/TLS maximum packet size
|
||||
* (record size) differently.
|
||||
*
|
||||
* Conscrypt calculates this as 18437 bytes:
|
||||
*
|
||||
* type(1) + version(2) + length(2) + 2^14 plaintext +
|
||||
* max compression overhead (1024) + max AEAD overhead (1024) */
|
||||
return 18437;
|
||||
* max compression overhead (1024) + max AEAD overhead (1024)
|
||||
*
|
||||
* wolfJSSE originally matched the Conscrypt value, but it conflicts
|
||||
* with the maximum allowed/used by the tls-channel project, which
|
||||
* we have a few customers using. tls-channel uses a maximum size of
|
||||
* 17k.
|
||||
*
|
||||
* Native wolfSSL has the wolfSSL_GetMaxOutputSize() function, but
|
||||
* it only works post-handshake. getPacketBufferSize() can be called
|
||||
* pre-handshake, so we set a default value here that matches
|
||||
* the upper limit for tls-channel, which is 17k, then if
|
||||
* wolfSSL_GetMaxOutputSize() is larger, we increase to that value.
|
||||
*/
|
||||
int nativeMax;
|
||||
int ret = 17 * 1024;
|
||||
|
||||
/* Try to get maximum TLS record size from native wolfSSL */
|
||||
if (ssl != null) {
|
||||
nativeMax = ssl.getMaxOutputSize();
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||
"ssl.getMaxOutputSize() returned: " + nativeMax);
|
||||
|
||||
if ((nativeMax > 0) && (nativeMax > ret)) {
|
||||
ret = nativeMax;
|
||||
}
|
||||
}
|
||||
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||
"getPacketBufferSize() returning: " + ret);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1662,8 +1662,8 @@ public class WolfSSLEngineTest {
|
|||
session = engine.getSession();
|
||||
packetBufSz = session.getPacketBufferSize();
|
||||
|
||||
/* expected to be 18437 */
|
||||
if (packetBufSz != 18437) {
|
||||
/* expected to be 17k */
|
||||
if (packetBufSz != (17 * 1024)) {
|
||||
error("\t\t... failed");
|
||||
fail("got incorrect packet buffer size (" +
|
||||
enabledProtocols.get(i) + ")");
|
||||
|
|
|
@ -3393,7 +3393,7 @@ public class WolfSSLSocketTest {
|
|||
throw cliException;
|
||||
}
|
||||
|
||||
System.out.println("\t\t... passed");
|
||||
System.out.println("\t... passed");
|
||||
|
||||
} finally {
|
||||
/* Restore original property value */
|
||||
|
|
|
@ -644,13 +644,6 @@ public class WolfSSLContextTest {
|
|||
fail("setMinECCKeySize should fail with negative key size");
|
||||
}
|
||||
|
||||
/* key length not % 8 should fail */
|
||||
ret = ctx.setMinECCKeySize(255);
|
||||
if (ret != WolfSSL.BAD_FUNC_ARG) {
|
||||
System.out.println("\t\t... failed");
|
||||
fail("setMinECCKeySize should fail with non % 8 size");
|
||||
}
|
||||
|
||||
/* valid key length should succeed */
|
||||
ret = ctx.setMinECCKeySize(128);
|
||||
if (ret != WolfSSL.SSL_SUCCESS) {
|
||||
|
|
|
@ -23,13 +23,10 @@ package com.wolfssl.test;
|
|||
|
||||
import org.junit.Test;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
import java.net.ServerSocket;
|
||||
import java.net.InetAddress;
|
||||
|
@ -43,6 +40,8 @@ import java.util.concurrent.Future;
|
|||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.Arrays;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import com.wolfssl.WolfSSL;
|
||||
import com.wolfssl.WolfSSLDebug;
|
||||
|
@ -53,12 +52,11 @@ import com.wolfssl.WolfSSLPskClientCallback;
|
|||
import com.wolfssl.WolfSSLPskServerCallback;
|
||||
import com.wolfssl.WolfSSLTls13SecretCallback;
|
||||
import com.wolfssl.WolfSSLSession;
|
||||
import com.wolfssl.WolfSSLByteBufferIORecvCallback;
|
||||
import com.wolfssl.WolfSSLByteBufferIOSendCallback;
|
||||
|
||||
public class WolfSSLSessionTest {
|
||||
|
||||
private final static int TEST_FAIL = -1;
|
||||
private final static int TEST_SUCCESS = 0;
|
||||
|
||||
private static String cliCert = "./examples/certs/client-cert.pem";
|
||||
private static String cliKey = "./examples/certs/client-key.pem";
|
||||
private static String srvCert = "./examples/certs/server-cert.pem";
|
||||
|
@ -69,6 +67,9 @@ public class WolfSSLSessionTest {
|
|||
private final static String exampleHost = "www.example.com";
|
||||
private final static int examplePort = 443;
|
||||
|
||||
/* Maximum network buffer size, for test I/O callbacks */
|
||||
private final static int MAX_NET_BUF_SZ = 17 * 1024;
|
||||
|
||||
private static WolfSSLContext ctx = null;
|
||||
|
||||
@BeforeClass
|
||||
|
@ -889,7 +890,6 @@ public class WolfSSLSessionTest {
|
|||
public void test_WolfSSLSession_setTls13SecretCb()
|
||||
throws WolfSSLJNIException {
|
||||
|
||||
int ret;
|
||||
WolfSSL sslLib = null;
|
||||
WolfSSLContext sslCtx = null;
|
||||
WolfSSLSession ssl = null;
|
||||
|
@ -1413,5 +1413,409 @@ public class WolfSSLSessionTest {
|
|||
|
||||
System.out.println("\t... passed");
|
||||
}
|
||||
|
||||
/**
|
||||
* wolfSSL I/O context, is passed to I/O callbacks when called
|
||||
* by native wolfSSL.
|
||||
*/
|
||||
private class MyIOCtx {
|
||||
private byte[] cliToSrv = new byte[MAX_NET_BUF_SZ];
|
||||
private byte[] srvToCli = new byte[MAX_NET_BUF_SZ];
|
||||
|
||||
private int cliToSrvUsed = 0;
|
||||
private int srvToCliUsed = 0;
|
||||
|
||||
private int CLIENT_END = 1;
|
||||
private int SERVER_END = 2;
|
||||
|
||||
private final Object cliLock = new Object();
|
||||
private final Object srvLock = new Object();
|
||||
|
||||
private int insertData(byte[] dest, int destUsed,
|
||||
ByteBuffer src, int len) {
|
||||
|
||||
int freeBufSpace = dest.length - destUsed;
|
||||
|
||||
/* Check if buffer is full */
|
||||
if ((len > 0) && (freeBufSpace == 0)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int bytesToCopy = Math.min(len, freeBufSpace);
|
||||
if (bytesToCopy > 0) {
|
||||
src.get(dest, destUsed, bytesToCopy);
|
||||
}
|
||||
return bytesToCopy;
|
||||
}
|
||||
|
||||
private int getData(byte[] src, int srcUsed,
|
||||
ByteBuffer dest, int len) {
|
||||
|
||||
/* src buffer is empty */
|
||||
if ((len > 0) && (srcUsed == 0)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int bytesToCopy = Math.min(len, srcUsed);
|
||||
if (bytesToCopy > 0) {
|
||||
dest.put(src, 0, bytesToCopy);
|
||||
srcUsed -= bytesToCopy;
|
||||
/* Shift remaining data to front of buffer */
|
||||
if (srcUsed > 0) {
|
||||
System.arraycopy(src, bytesToCopy, src, 0, srcUsed);
|
||||
}
|
||||
}
|
||||
return bytesToCopy;
|
||||
}
|
||||
|
||||
public int insertCliToSrvData(ByteBuffer buf, int len) {
|
||||
synchronized (cliLock) {
|
||||
int ret = insertData(cliToSrv, cliToSrvUsed, buf, len);
|
||||
if (ret > 0) {
|
||||
cliToSrvUsed += ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
public int insertSrvToCliData(ByteBuffer buf, int len) {
|
||||
synchronized (srvLock) {
|
||||
int ret = insertData(srvToCli, srvToCliUsed, buf, len);
|
||||
if (ret > 0) {
|
||||
srvToCliUsed += ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
public int getCliToSrvData(ByteBuffer buf, int len) {
|
||||
synchronized (cliLock) {
|
||||
int ret = getData(cliToSrv, cliToSrvUsed, buf, len);
|
||||
if (ret > 0) {
|
||||
cliToSrvUsed -= ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
public int getSrvToCliData(ByteBuffer buf, int len) {
|
||||
synchronized (srvLock) {
|
||||
int ret = getData(srvToCli, srvToCliUsed, buf, len);
|
||||
if (ret > 0) {
|
||||
srvToCliUsed -= ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Client I/O callback using ByteBuffers */
|
||||
private class ClientByteBufferIOCallback
|
||||
implements WolfSSLByteBufferIORecvCallback,
|
||||
WolfSSLByteBufferIOSendCallback {
|
||||
/**
|
||||
* Receive data is called when wolfSSL needs to read data from the
|
||||
* transport layer. In this case, we read data from the beginning
|
||||
* of the internal byte[] (buffer) and place it into the ByteBuffer buf.
|
||||
*
|
||||
* Return the number of bytes copied to the ByteBuffer buf, or negative
|
||||
* on error.
|
||||
*/
|
||||
@Override
|
||||
public synchronized int receiveCallback(WolfSSLSession ssl,
|
||||
ByteBuffer buf, int len, Object ctx) {
|
||||
|
||||
int ret;
|
||||
MyIOCtx ioCtx = (MyIOCtx) ctx;
|
||||
|
||||
ret = ioCtx.getSrvToCliData(buf, len);
|
||||
if (ret == -1) {
|
||||
/* No data available, return WOLFSSL_CBIO_ERR_WANT_READ */
|
||||
ret = WolfSSL.WOLFSSL_CBIO_ERR_WANT_READ;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send data is called when wolfSSL needs to write data to the
|
||||
* transport layer. In this case, we read data from the ByteBuffer
|
||||
* buf and place it into our internal byte[] (buffer).
|
||||
*
|
||||
* Return the number of bytes copied from the ByteBuffer buf, or
|
||||
* negative on error.
|
||||
*/
|
||||
@Override
|
||||
public synchronized int sendCallback(
|
||||
WolfSSLSession ssl, ByteBuffer buf, int len, Object ctx) {
|
||||
|
||||
int ret;
|
||||
MyIOCtx ioCtx = (MyIOCtx) ctx;
|
||||
|
||||
ret = ioCtx.insertCliToSrvData(buf, len);
|
||||
if (ret == -1) {
|
||||
/* No space available, return WOLFSSL_CBIO_ERR_WANT_WRITE */
|
||||
ret = WolfSSL.WOLFSSL_CBIO_ERR_WANT_WRITE;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/* Server I/O callback using ByteBuffers */
|
||||
private class ServerByteBufferIOCallback
|
||||
implements WolfSSLByteBufferIORecvCallback,
|
||||
WolfSSLByteBufferIOSendCallback {
|
||||
/**
|
||||
* Receive data is called when wolfSSL needs to read data from the
|
||||
* transport layer. In this case, we read data from the beginning
|
||||
* of the internal byte[] (buffer) and place it into the ByteBuffer buf.
|
||||
*
|
||||
* Return the number of bytes copied to the ByteBuffer buf, or negative
|
||||
* on error.
|
||||
*/
|
||||
@Override
|
||||
public synchronized int receiveCallback(WolfSSLSession ssl,
|
||||
ByteBuffer buf, int len, Object ctx) {
|
||||
|
||||
int ret;
|
||||
MyIOCtx ioCtx = (MyIOCtx) ctx;
|
||||
|
||||
ret = ioCtx.getCliToSrvData(buf, len);
|
||||
if (ret == -1) {
|
||||
/* No data available, return WOLFSSL_CBIO_ERR_WANT_READ */
|
||||
ret = WolfSSL.WOLFSSL_CBIO_ERR_WANT_READ;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send data is called when wolfSSL needs to write data to the
|
||||
* transport layer. In this case, we read data from the ByteBuffer
|
||||
* buf and place it into our internal byte[] (buffer).
|
||||
*
|
||||
* Return the number of bytes copied from the ByteBuffer buf, or
|
||||
* negative on error.
|
||||
*/
|
||||
@Override
|
||||
public synchronized int sendCallback(
|
||||
WolfSSLSession ssl, ByteBuffer buf, int len, Object ctx) {
|
||||
|
||||
int ret;
|
||||
MyIOCtx ioCtx = (MyIOCtx) ctx;
|
||||
|
||||
ret = ioCtx.insertSrvToCliData(buf, len);
|
||||
if (ret == -1) {
|
||||
/* No space available, return WOLFSSL_CBIO_ERR_WANT_WRITE */
|
||||
ret = WolfSSL.WOLFSSL_CBIO_ERR_WANT_WRITE;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void test_WolfSSLSession_ioBuffers() throws Exception {
|
||||
int ret = 0;
|
||||
int err = 0;
|
||||
Socket cliSock = null;
|
||||
WolfSSLSession cliSes = null;
|
||||
byte[] testData = "Hello from client".getBytes();
|
||||
byte[] servAppBuffer = new byte[MAX_NET_BUF_SZ];
|
||||
byte[] cliAppBuffer = new byte[MAX_NET_BUF_SZ];
|
||||
int bytesRead = 0;
|
||||
|
||||
/* Create client/server WolfSSLContext objects */
|
||||
final WolfSSLContext srvCtx;
|
||||
WolfSSLContext cliCtx;
|
||||
|
||||
System.out.print("\tTesting I/O CB with ByteBuffers");
|
||||
|
||||
/* Initialize library */
|
||||
WolfSSL lib = new WolfSSL();
|
||||
|
||||
/* Create ServerSocket first to get ephemeral port */
|
||||
final ServerSocket srvSocket = new ServerSocket(0);
|
||||
|
||||
srvCtx = createAndSetupWolfSSLContext(srvCert, srvKey,
|
||||
WolfSSL.SSL_FILETYPE_PEM, cliCert,
|
||||
WolfSSL.SSLv23_ServerMethod());
|
||||
cliCtx = createAndSetupWolfSSLContext(cliCert, cliKey,
|
||||
WolfSSL.SSL_FILETYPE_PEM, caCert,
|
||||
WolfSSL.SSLv23_ClientMethod());
|
||||
|
||||
MyIOCtx myIOCb = new MyIOCtx();
|
||||
ClientByteBufferIOCallback cliIOCb = new ClientByteBufferIOCallback();
|
||||
ServerByteBufferIOCallback srvIOCb = new ServerByteBufferIOCallback();
|
||||
|
||||
ExecutorService es = Executors.newSingleThreadExecutor();
|
||||
|
||||
/* Start server */
|
||||
try {
|
||||
es.submit(new Callable<Void>() {
|
||||
@Override
|
||||
public Void call() throws Exception {
|
||||
int ret;
|
||||
int err;
|
||||
Socket server = null;
|
||||
WolfSSLSession srvSes = null;
|
||||
int bytesRead = 0;
|
||||
|
||||
try {
|
||||
server = srvSocket.accept();
|
||||
srvSes = new WolfSSLSession(srvCtx);
|
||||
|
||||
/* Set I/O callback and ctx */
|
||||
srvSes.setIOSendByteBuffer(srvIOCb);
|
||||
srvSes.setIORecvByteBuffer(srvIOCb);
|
||||
srvSes.setIOWriteCtx(myIOCb);
|
||||
srvSes.setIOReadCtx(myIOCb);
|
||||
|
||||
/* Do handshake */
|
||||
do {
|
||||
ret = srvSes.accept();
|
||||
err = srvSes.getError(ret);
|
||||
} while (ret != WolfSSL.SSL_SUCCESS &&
|
||||
(err == WolfSSL.SSL_ERROR_WANT_READ ||
|
||||
err == WolfSSL.SSL_ERROR_WANT_WRITE));
|
||||
|
||||
if (ret != WolfSSL.SSL_SUCCESS) {
|
||||
throw new Exception(
|
||||
"Server accept failed: " + err);
|
||||
}
|
||||
|
||||
/* Read data from client */
|
||||
bytesRead = srvSes.read(servAppBuffer,
|
||||
servAppBuffer.length, 0);
|
||||
if (bytesRead <= 0) {
|
||||
throw new Exception(
|
||||
"Server read failed: " + bytesRead);
|
||||
}
|
||||
|
||||
/* Send same data back to client */
|
||||
ret = srvSes.write(servAppBuffer, bytesRead, 0);
|
||||
if (ret != bytesRead) {
|
||||
throw new Exception("Server write failed: " + ret);
|
||||
}
|
||||
|
||||
srvSes.shutdownSSL();
|
||||
srvSes.freeSSL();
|
||||
srvSes = null;
|
||||
server.close();
|
||||
server = null;
|
||||
|
||||
} finally {
|
||||
if (srvSes != null) {
|
||||
srvSes.freeSSL();
|
||||
}
|
||||
if (server != null) {
|
||||
server.close();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
} catch (Exception e) {
|
||||
System.out.println("\t... failed");
|
||||
e.printStackTrace();
|
||||
fail();
|
||||
}
|
||||
|
||||
try {
|
||||
/* Client connection */
|
||||
cliSock = new Socket(InetAddress.getLocalHost(),
|
||||
srvSocket.getLocalPort());
|
||||
|
||||
cliSes = new WolfSSLSession(cliCtx);
|
||||
|
||||
/* Set I/O callback and ctx */
|
||||
cliSes.setIOSendByteBuffer(cliIOCb);
|
||||
cliSes.setIORecvByteBuffer(cliIOCb);
|
||||
cliSes.setIOWriteCtx(myIOCb);
|
||||
cliSes.setIOReadCtx(myIOCb);
|
||||
|
||||
/* Do handshake */
|
||||
do {
|
||||
ret = cliSes.connect();
|
||||
err = cliSes.getError(ret);
|
||||
} while (ret != WolfSSL.SSL_SUCCESS &&
|
||||
(err == WolfSSL.SSL_ERROR_WANT_READ ||
|
||||
err == WolfSSL.SSL_ERROR_WANT_WRITE));
|
||||
|
||||
if (ret != WolfSSL.SSL_SUCCESS) {
|
||||
throw new Exception(
|
||||
"Client connect failed: " + err);
|
||||
}
|
||||
|
||||
/* Send test data */
|
||||
ret = cliSes.write(testData, testData.length, 0);
|
||||
if (ret != testData.length) {
|
||||
throw new Exception(
|
||||
"Client write failed: " + ret);
|
||||
}
|
||||
|
||||
/* Read response */
|
||||
do {
|
||||
bytesRead = cliSes.read(cliAppBuffer, cliAppBuffer.length, 0);
|
||||
err = cliSes.getError(bytesRead);
|
||||
} while (ret != WolfSSL.SSL_SUCCESS &&
|
||||
err == WolfSSL.SSL_ERROR_WANT_READ ||
|
||||
err == WolfSSL.SSL_ERROR_WANT_WRITE);
|
||||
|
||||
if (bytesRead != testData.length) {
|
||||
throw new Exception(
|
||||
"Client read failed: " + bytesRead);
|
||||
}
|
||||
|
||||
/* Verify received data matches sent data using Java 8 compatible
|
||||
* array comparison */
|
||||
boolean arraysMatch = true;
|
||||
if (testData.length != bytesRead) {
|
||||
arraysMatch = false;
|
||||
} else {
|
||||
for (int i = 0; i < testData.length; i++) {
|
||||
if (testData[i] != cliAppBuffer[i]) {
|
||||
arraysMatch = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!arraysMatch) {
|
||||
throw new Exception("Received data does not match sent data");
|
||||
}
|
||||
|
||||
cliSes.shutdownSSL();
|
||||
cliSes.freeSSL();
|
||||
cliSes = null;
|
||||
cliSock.close();
|
||||
cliSock = null;
|
||||
|
||||
} catch (Exception e) {
|
||||
System.out.println("\t... failed");
|
||||
e.printStackTrace();
|
||||
fail();
|
||||
|
||||
} finally {
|
||||
/* Free resources */
|
||||
if (cliSes != null) {
|
||||
cliSes.freeSSL();
|
||||
}
|
||||
if (cliSock != null) {
|
||||
cliSock.close();
|
||||
}
|
||||
if (srvSocket != null) {
|
||||
srvSocket.close();
|
||||
}
|
||||
if (srvCtx != null) {
|
||||
srvCtx.free();
|
||||
}
|
||||
es.shutdown();
|
||||
}
|
||||
|
||||
System.out.println("\t... passed");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue