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 */
|
/* global object refs for logging callbacks */
|
||||||
static jobject g_loggingCbIfaceObj;
|
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
|
#ifdef HAVE_FIPS
|
||||||
/* global object ref for FIPS error callback */
|
/* global object ref for FIPS error callback */
|
||||||
static jobject g_fipsCbIfaceObj;
|
static jobject g_fipsCbIfaceObj;
|
||||||
|
@ -61,16 +77,192 @@ static jobject g_fipsCbIfaceObj;
|
||||||
/* custom native fn prototypes */
|
/* custom native fn prototypes */
|
||||||
void NativeLoggingCallback(const int logLevel, const char *const logMessage);
|
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)
|
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved)
|
||||||
{
|
{
|
||||||
|
JNIEnv* env = NULL;
|
||||||
|
jclass sslClass = NULL;
|
||||||
|
jclass byteBufferClass = NULL;
|
||||||
|
jclass verifyClass = NULL;
|
||||||
(void)reserved;
|
(void)reserved;
|
||||||
|
|
||||||
/* store JavaVM */
|
/* store JavaVM */
|
||||||
g_vm = vm;
|
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;
|
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
|
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSL_init
|
||||||
(JNIEnv* jenv, jobject jcl)
|
(JNIEnv* jenv, jobject jcl)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1028,7 +1028,6 @@ int NativeIORecvCb(WOLFSSL *ssl, char *buf, int sz, void *ctx)
|
||||||
|
|
||||||
jobject ctxRef; /* WolfSSLContext object */
|
jobject ctxRef; /* WolfSSLContext object */
|
||||||
jclass innerCtxClass; /* WolfSSLContext class */
|
jclass innerCtxClass; /* WolfSSLContext class */
|
||||||
jmethodID recvCbMethodId; /* internalIORecvCallback ID */
|
|
||||||
jbyteArray inData;
|
jbyteArray inData;
|
||||||
|
|
||||||
if (!g_vm || !ssl || !buf || !ctx) {
|
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;
|
return WOLFSSL_CBIO_ERR_GENERAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* call internal I/O recv callback */
|
/* make sure cached recv callback method ID is not null */
|
||||||
recvCbMethodId = (*jenv)->GetMethodID(jenv, innerCtxClass,
|
if (!g_sslIORecvMethodId) {
|
||||||
"internalIORecvCallback",
|
|
||||||
"(Lcom/wolfssl/WolfSSLSession;[BI)I");
|
|
||||||
if (!recvCbMethodId) {
|
|
||||||
if ((*jenv)->ExceptionOccurred(jenv)) {
|
|
||||||
(*jenv)->ExceptionDescribe(jenv);
|
|
||||||
(*jenv)->ExceptionClear(jenv);
|
|
||||||
}
|
|
||||||
(*jenv)->ThrowNew(jenv, excClass,
|
(*jenv)->ThrowNew(jenv, excClass,
|
||||||
"Error getting internalIORecvCallback method from JNI");
|
"Cached recv callback method ID is null in NativeIORecvCb");
|
||||||
(*jenv)->DeleteLocalRef(jenv, ctxRef);
|
|
||||||
if (needsDetach)
|
if (needsDetach)
|
||||||
(*g_vm)->DetachCurrentThread(g_vm);
|
(*g_vm)->DetachCurrentThread(g_vm);
|
||||||
return WOLFSSL_CBIO_ERR_GENERAL;
|
return WOLFSSL_CBIO_ERR_GENERAL;
|
||||||
|
@ -1161,7 +1152,7 @@ int NativeIORecvCb(WOLFSSL *ssl, char *buf, int sz, void *ctx)
|
||||||
inData = (*jenv)->NewByteArray(jenv, sz);
|
inData = (*jenv)->NewByteArray(jenv, sz);
|
||||||
if (!inData) {
|
if (!inData) {
|
||||||
(*jenv)->ThrowNew(jenv, excClass,
|
(*jenv)->ThrowNew(jenv, excClass,
|
||||||
"Error getting internalIORecvCallback method from JNI");
|
"Error creating jbyteArray in NativeIORecvCb");
|
||||||
(*jenv)->DeleteLocalRef(jenv, ctxRef);
|
(*jenv)->DeleteLocalRef(jenv, ctxRef);
|
||||||
if (needsDetach)
|
if (needsDetach)
|
||||||
(*g_vm)->DetachCurrentThread(g_vm);
|
(*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
|
/* call Java send callback, ignore native ctx since Java
|
||||||
* handles it */
|
* handles it */
|
||||||
retval = (*jenv)->CallIntMethod(jenv, ctxRef, recvCbMethodId,
|
retval = (*jenv)->CallIntMethod(jenv, ctxRef, g_sslIORecvMethodId,
|
||||||
(jobject)(*g_cachedSSLObj),
|
(jobject)(*g_cachedSSLObj),
|
||||||
inData, (jint)sz);
|
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
|
JNIEXPORT jstring JNICALL Java_com_wolfssl_WolfSSLSession_stateStringLong
|
||||||
(JNIEnv *, jobject, jlong);
|
(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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -25,7 +25,25 @@
|
||||||
#define _Included_com_wolfssl_globals
|
#define _Included_com_wolfssl_globals
|
||||||
|
|
||||||
/* global JavaVM reference for JNIEnv lookup */
|
/* 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 */
|
/* struct to hold I/O class, object refs */
|
||||||
typedef struct {
|
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 int NativePskServerCb(WOLFSSL* ssl, const char* identity,
|
||||||
unsigned char* key, unsigned int max_key_len);
|
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 \
|
infer --fail-on-issue run -- javac \
|
||||||
src/java/com/wolfssl/WolfSSL.java \
|
src/java/com/wolfssl/WolfSSL.java \
|
||||||
src/java/com/wolfssl/WolfSSLALPNSelectCallback.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/WolfSSLCertManager.java \
|
||||||
src/java/com/wolfssl/WolfSSLCertRequest.java \
|
src/java/com/wolfssl/WolfSSLCertRequest.java \
|
||||||
src/java/com/wolfssl/WolfSSLCertificate.java \
|
src/java/com/wolfssl/WolfSSLCertificate.java \
|
||||||
|
|
|
@ -626,6 +626,9 @@ public class WolfSSL {
|
||||||
getTls13SecretEnum_EXPORTER_SECRET();
|
getTls13SecretEnum_EXPORTER_SECRET();
|
||||||
|
|
||||||
this.active = true;
|
this.active = true;
|
||||||
|
|
||||||
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
|
||||||
|
WolfSSLDebug.INFO, "wolfSSL library initialization done");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------- private/protected methods -------------------- */
|
/* ------------------- 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 WolfSSLPskClientCallback internPskClientCb = null;
|
||||||
private WolfSSLPskServerCallback internPskServerCb = null;
|
private WolfSSLPskServerCallback internPskServerCb = null;
|
||||||
|
|
||||||
/* user-registerd I/O callbacks, called by internal WolfSSLSession
|
/* User-registerd I/O callbacks:
|
||||||
* I/O callback. This is done in order to pass references to
|
*
|
||||||
* WolfSSLSession object */
|
* These are called by internal WolfSSLSession I/O callback. This is done
|
||||||
private WolfSSLIORecvCallback internRecvSSLCb;
|
* in order to pass references to WolfSSLSession object. There are two sets
|
||||||
private WolfSSLIOSendCallback internSendSSLCb;
|
* 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
|
/* user-registered ALPN select callback, called by internal WolfSSLSession
|
||||||
* ALPN select callback */
|
* ALPN select callback */
|
||||||
|
@ -237,20 +247,66 @@ public class WolfSSLSession {
|
||||||
return this.rsaDecCtx;
|
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 */
|
/* 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 */
|
/* call user-registered recv method */
|
||||||
return internRecvSSLCb.receiveCallback(ssl, buf, sz,
|
return internRecvSSLCb_array.receiveCallback(ssl, buf, sz,
|
||||||
ssl.getIOReadCtx());
|
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 */
|
/* 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());
|
ssl.getIOWriteCtx());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -440,6 +496,7 @@ public class WolfSSLSession {
|
||||||
private native int getThreadsBlockedInPoll(long ssl);
|
private native int getThreadsBlockedInPoll(long ssl);
|
||||||
private native int setMTU(long ssl, int mtu);
|
private native int setMTU(long ssl, int mtu);
|
||||||
private native String stateStringLong(long ssl);
|
private native String stateStringLong(long ssl);
|
||||||
|
private native int getMaxOutputSize(long ssl);
|
||||||
|
|
||||||
/* ------------------- session-specific methods --------------------- */
|
/* ------------------- session-specific methods --------------------- */
|
||||||
|
|
||||||
|
@ -2556,6 +2613,35 @@ public class WolfSSLSession {
|
||||||
return state;
|
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
|
* Determine if a reused session was negotiated during the SSL
|
||||||
* handshake.
|
* handshake.
|
||||||
|
@ -3098,9 +3184,6 @@ public class WolfSSLSession {
|
||||||
confirmObjectIsActive();
|
confirmObjectIsActive();
|
||||||
|
|
||||||
synchronized (sslLock) {
|
synchronized (sslLock) {
|
||||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
|
|
||||||
WolfSSLDebug.INFO, this.sslPtr, "entered getIOReadCtx()");
|
|
||||||
|
|
||||||
return this.ioReadCtx;
|
return this.ioReadCtx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3149,9 +3232,6 @@ public class WolfSSLSession {
|
||||||
confirmObjectIsActive();
|
confirmObjectIsActive();
|
||||||
|
|
||||||
synchronized (sslLock) {
|
synchronized (sslLock) {
|
||||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
|
|
||||||
WolfSSLDebug.INFO, this.sslPtr, "entered getIOWriteCtx()");
|
|
||||||
|
|
||||||
return this.ioWriteCtx;
|
return this.ioWriteCtx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4338,11 +4418,18 @@ public class WolfSSLSession {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers a receive callback for wolfSSL to get input data.
|
* 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
|
* This receive callback uses WolfSSLIORecvCallback which uses
|
||||||
* function to get input from memory, some other network module, or from
|
* byte arrays (byte[]). To use direct ByteBuffers, and avoid an extra
|
||||||
* anywhere. Please see the EmbedReceive() function in src/io.c as a
|
* JNI array allocaiton, use
|
||||||
* guide for how the function should work and for error codes.
|
* 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>
|
* <p>
|
||||||
* In particular, <b>IO_ERR_WANT_READ</b> should be returned for
|
* In particular, <b>IO_ERR_WANT_READ</b> should be returned for
|
||||||
* non-blocking receive when no data is ready.
|
* non-blocking receive when no data is ready.
|
||||||
|
@ -4364,10 +4451,16 @@ public class WolfSSLSession {
|
||||||
synchronized (sslLock) {
|
synchronized (sslLock) {
|
||||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
|
||||||
WolfSSLDebug.INFO, this.sslPtr,
|
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 */
|
/* set user I/O recv */
|
||||||
internRecvSSLCb = callback;
|
internRecvSSLCb_array = callback;
|
||||||
|
|
||||||
if (callback != null) {
|
if (callback != null) {
|
||||||
/* register internal callback with native library */
|
/* 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,
|
* By default, wolfSSL uses EmbedSend() in src/io.c as the callback,
|
||||||
* which uses the system's TCP send() function. The user can register
|
* which uses the system TCP send() function. The user can register
|
||||||
* a function to send output to memory, some other network module, or
|
* a method here to send TLS-encoded output data to memory, some other
|
||||||
* to anywhere. Please see the EmbedSend() function in src/io.c as a
|
* network module, or to anywhere else. Please see the EmbedSend() function
|
||||||
* guide for how the function should work and for error codes.
|
* in src/io.c as a guide for how the function should work and for error
|
||||||
|
* codes.
|
||||||
* <p>
|
* <p>
|
||||||
* In particular, <b>IO_ERR_WANT_WRITE</b> should be returned for
|
* In particular, <b>IO_ERR_WANT_WRITE</b> should be returned for
|
||||||
* non-blocking send when the action cannot be taken yet.
|
* non-blocking send when the action cannot be taken yet.
|
||||||
|
@ -4404,13 +4559,78 @@ public class WolfSSLSession {
|
||||||
synchronized (sslLock) {
|
synchronized (sslLock) {
|
||||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
|
||||||
WolfSSLDebug.INFO, this.sslPtr,
|
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 */
|
/* set user I/O send */
|
||||||
internSendSSLCb = callback;
|
internSendSSLCb_array = callback;
|
||||||
|
|
||||||
if (callback != null) {
|
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);
|
setSSLIOSend(this.sslPtr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,8 +24,8 @@ package com.wolfssl.provider.jsse;
|
||||||
import com.wolfssl.WolfSSL;
|
import com.wolfssl.WolfSSL;
|
||||||
import com.wolfssl.WolfSSLDebug;
|
import com.wolfssl.WolfSSLDebug;
|
||||||
import com.wolfssl.WolfSSLException;
|
import com.wolfssl.WolfSSLException;
|
||||||
import com.wolfssl.WolfSSLIORecvCallback;
|
import com.wolfssl.WolfSSLByteBufferIORecvCallback;
|
||||||
import com.wolfssl.WolfSSLIOSendCallback;
|
import com.wolfssl.WolfSSLByteBufferIOSendCallback;
|
||||||
import com.wolfssl.WolfSSLJNIException;
|
import com.wolfssl.WolfSSLJNIException;
|
||||||
import com.wolfssl.WolfSSLSession;
|
import com.wolfssl.WolfSSLSession;
|
||||||
import com.wolfssl.WolfSSLALPNSelectCallback;
|
import com.wolfssl.WolfSSLALPNSelectCallback;
|
||||||
|
@ -37,7 +37,6 @@ import java.util.function.BiFunction;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.logging.Level;
|
|
||||||
import java.security.cert.CertificateEncodingException;
|
import java.security.cert.CertificateEncodingException;
|
||||||
import javax.net.ssl.SSLEngine;
|
import javax.net.ssl.SSLEngine;
|
||||||
import javax.net.ssl.SSLEngineResult;
|
import javax.net.ssl.SSLEngineResult;
|
||||||
|
@ -72,7 +71,6 @@ public class WolfSSLEngine extends SSLEngine {
|
||||||
private com.wolfssl.WolfSSLContext ctx = null;
|
private com.wolfssl.WolfSSLContext ctx = null;
|
||||||
private WolfSSLAuthStore authStore = null;
|
private WolfSSLAuthStore authStore = null;
|
||||||
private WolfSSLParameters params = null;
|
private WolfSSLParameters params = null;
|
||||||
private byte[] toSend = null; /* encrypted packet to send */
|
|
||||||
private int nativeWantsToWrite = 0;
|
private int nativeWantsToWrite = 0;
|
||||||
private int nativeWantsToRead = 0;
|
private int nativeWantsToRead = 0;
|
||||||
private HandshakeStatus hs = SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING;
|
private HandshakeStatus hs = SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING;
|
||||||
|
@ -126,6 +124,22 @@ public class WolfSSLEngine extends SSLEngine {
|
||||||
private ByteBuffer netData = null;
|
private ByteBuffer netData = null;
|
||||||
private final Object netDataLock = new Object();
|
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 */
|
/* Locks for synchronization */
|
||||||
private final Object ioLock = new Object();
|
private final Object ioLock = new Object();
|
||||||
private final Object toSendLock = new Object();
|
private final Object toSendLock = new Object();
|
||||||
|
@ -308,8 +322,8 @@ public class WolfSSLEngine extends SSLEngine {
|
||||||
if (recvCb == null) {
|
if (recvCb == null) {
|
||||||
recvCb = new RecvCB();
|
recvCb = new RecvCB();
|
||||||
}
|
}
|
||||||
ssl.setIORecv(recvCb);
|
ssl.setIORecvByteBuffer(recvCb);
|
||||||
ssl.setIOSend(sendCb);
|
ssl.setIOSendByteBuffer(sendCb);
|
||||||
ssl.setIOReadCtx(this);
|
ssl.setIOReadCtx(this);
|
||||||
ssl.setIOWriteCtx(this);
|
ssl.setIOWriteCtx(this);
|
||||||
|
|
||||||
|
@ -335,8 +349,8 @@ public class WolfSSLEngine extends SSLEngine {
|
||||||
private void unsetSSLCallbacks() throws WolfSSLJNIException {
|
private void unsetSSLCallbacks() throws WolfSSLJNIException {
|
||||||
|
|
||||||
synchronized (ioLock) {
|
synchronized (ioLock) {
|
||||||
ssl.setIORecv(null);
|
ssl.setIORecvByteBuffer(null);
|
||||||
ssl.setIOSend(null);
|
ssl.setIOSendByteBuffer(null);
|
||||||
ssl.setIOReadCtx(null);
|
ssl.setIOReadCtx(null);
|
||||||
ssl.setIOWriteCtx(null);
|
ssl.setIOWriteCtx(null);
|
||||||
}
|
}
|
||||||
|
@ -373,19 +387,18 @@ public class WolfSSLEngine extends SSLEngine {
|
||||||
int sendSz = 0;
|
int sendSz = 0;
|
||||||
|
|
||||||
synchronized (toSendLock) {
|
synchronized (toSendLock) {
|
||||||
if (this.toSend != null) {
|
if (this.internalIOSendBuf != null) {
|
||||||
sendSz = Math.min(this.toSend.length, out.remaining());
|
sendSz = Math.min(this.internalIOSendBufOffset, out.remaining());
|
||||||
out.put(this.toSend, 0, sendSz);
|
out.put(this.internalIOSendBuf, 0, sendSz);
|
||||||
|
|
||||||
if (sendSz != this.toSend.length) {
|
if (sendSz != this.internalIOSendBufOffset) {
|
||||||
/* resize and adjust remaining toSend data */
|
System.arraycopy(this.internalIOSendBuf, sendSz,
|
||||||
byte[] tmp = new byte[this.toSend.length - sendSz];
|
this.internalIOSendBuf, 0,
|
||||||
System.arraycopy(this.toSend, sendSz, tmp, 0,
|
this.internalIOSendBufOffset - sendSz);
|
||||||
this.toSend.length - sendSz);
|
|
||||||
this.toSend = tmp;
|
|
||||||
}
|
}
|
||||||
else {
|
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.closeNotifySent = true;
|
||||||
this.closeNotifyReceived = true;
|
this.closeNotifyReceived = true;
|
||||||
this.inBoundOpen = false;
|
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
|
/* Don't close outbound if we have a close_notify alert
|
||||||
* send back to peer. Native wolfSSL may have already generated
|
* send back to peer. Native wolfSSL may have already generated
|
||||||
* it and is reflected in SSL_SENT_SHUTDOWN flag, but we
|
* 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[] pos = new int[len]; /* in[] positions */
|
||||||
int[] limit = new int[len]; /* in[] limits */
|
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++) {
|
for (i = ofst; i < ofst + len; i++) {
|
||||||
totalIn += in[i].remaining();
|
totalIn += in[i].remaining();
|
||||||
pos[i] = in[i].position();
|
pos[i] = in[i].position();
|
||||||
limit[i] = in[i].limit();
|
limit[i] = in[i].limit();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* only send up to maximum app data size chunk */
|
/* Allocate static buffer for application data, clear before use */
|
||||||
sendSz = Math.min(totalIn,
|
sendSz = this.engineHelper.getSession().getApplicationBufferSize();
|
||||||
this.engineHelper.getSession().getApplicationBufferSize());
|
if (this.staticAppDataBuf == null) {
|
||||||
dataBuf = ByteBuffer.allocate(sendSz);
|
/* 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 */
|
/* gather byte array of sendSz bytes from input buffers */
|
||||||
inputLeft = sendSz;
|
inputLeft = sendSz;
|
||||||
|
@ -608,7 +627,7 @@ public class WolfSSLEngine extends SSLEngine {
|
||||||
int bufChunk = Math.min(in[i].remaining(), inputLeft);
|
int bufChunk = Math.min(in[i].remaining(), inputLeft);
|
||||||
|
|
||||||
in[i].limit(in[i].position() + bufChunk); /* set limit */
|
in[i].limit(in[i].position() + bufChunk); /* set limit */
|
||||||
dataBuf.put(in[i]); /* get data */
|
this.staticAppDataBuf.put(in[i]); /* get data */
|
||||||
inputLeft -= bufChunk;
|
inputLeft -= bufChunk;
|
||||||
in[i].limit(limit[i]); /* reset limit */
|
in[i].limit(limit[i]); /* reset limit */
|
||||||
|
|
||||||
|
@ -618,8 +637,8 @@ public class WolfSSLEngine extends SSLEngine {
|
||||||
}
|
}
|
||||||
|
|
||||||
dataArr = new byte[sendSz];
|
dataArr = new byte[sendSz];
|
||||||
dataBuf.rewind();
|
this.staticAppDataBuf.rewind();
|
||||||
dataBuf.get(dataArr);
|
this.staticAppDataBuf.get(dataArr);
|
||||||
|
|
||||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||||
"calling ssl.write() with size: " + sendSz);
|
"calling ssl.write() with size: " + sendSz);
|
||||||
|
@ -707,13 +726,8 @@ public class WolfSSLEngine extends SSLEngine {
|
||||||
"out.position(): " + out.position());
|
"out.position(): " + out.position());
|
||||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||||
"out.limit(): " + out.limit());
|
"out.limit(): " + out.limit());
|
||||||
if (this.toSend != null) {
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
"internalIOSendBufOffset: " + this.internalIOSendBufOffset);
|
||||||
"toSend.length: " + this.toSend.length);
|
|
||||||
} else {
|
|
||||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
|
||||||
"toSend.length: 0");
|
|
||||||
}
|
|
||||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||||
"closeNotifySent: " + this.closeNotifySent);
|
"closeNotifySent: " + this.closeNotifySent);
|
||||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
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 */
|
/* Force out buffer to be large enough to hold max packet size */
|
||||||
if (out.remaining() <
|
if (out.remaining() <
|
||||||
this.engineHelper.getSession().getPacketBufferSize()) {
|
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);
|
return new SSLEngineResult(Status.BUFFER_OVERFLOW, hs, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -832,13 +850,8 @@ public class WolfSSLEngine extends SSLEngine {
|
||||||
"out.position(): " + out.position());
|
"out.position(): " + out.position());
|
||||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||||
"out.limit(): " + out.limit());
|
"out.limit(): " + out.limit());
|
||||||
if (this.toSend != null) {
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
"internalIOSendBufOffset: " + this.internalIOSendBufOffset);
|
||||||
"toSend.length: " + this.toSend.length);
|
|
||||||
} else {
|
|
||||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
|
||||||
"toSend.length: 0");
|
|
||||||
}
|
|
||||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||||
"closeNotifySent: " + this.closeNotifySent);
|
"closeNotifySent: " + this.closeNotifySent);
|
||||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||||
|
@ -1064,7 +1077,7 @@ public class WolfSSLEngine extends SSLEngine {
|
||||||
public synchronized SSLEngineResult unwrap(ByteBuffer in, ByteBuffer[] out,
|
public synchronized SSLEngineResult unwrap(ByteBuffer in, ByteBuffer[] out,
|
||||||
int ofst, int length) throws SSLException {
|
int ofst, int length) throws SSLException {
|
||||||
|
|
||||||
int i, ret = 0, sz = 0, err = 0;
|
int i, ret = 0, err = 0;
|
||||||
int inPosition = 0;
|
int inPosition = 0;
|
||||||
int inRemaining = 0;
|
int inRemaining = 0;
|
||||||
int consumed = 0;
|
int consumed = 0;
|
||||||
|
@ -1072,7 +1085,6 @@ public class WolfSSLEngine extends SSLEngine {
|
||||||
long dtlsPrevDropCount = 0;
|
long dtlsPrevDropCount = 0;
|
||||||
long dtlsCurrDropCount = 0;
|
long dtlsCurrDropCount = 0;
|
||||||
int prevSessionTicketCount = 0;
|
int prevSessionTicketCount = 0;
|
||||||
byte[] tmp;
|
|
||||||
|
|
||||||
/* Set initial status for SSLEngineResult return */
|
/* Set initial status for SSLEngineResult return */
|
||||||
Status status = SSLEngineResult.Status.OK;
|
Status status = SSLEngineResult.Status.OK;
|
||||||
|
@ -1130,13 +1142,8 @@ public class WolfSSLEngine extends SSLEngine {
|
||||||
}
|
}
|
||||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||||
"ofst: " + ofst + ", length: " + length);
|
"ofst: " + ofst + ", length: " + length);
|
||||||
if (this.toSend != null) {
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
"internalIOSendBufOffset: " + this.internalIOSendBufOffset);
|
||||||
"toSend.length: " + this.toSend.length);
|
|
||||||
} else {
|
|
||||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
|
||||||
"toSend.length: 0");
|
|
||||||
}
|
|
||||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||||
"closeNotifySent: " + this.closeNotifySent);
|
"closeNotifySent: " + this.closeNotifySent);
|
||||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||||
|
@ -1174,7 +1181,7 @@ public class WolfSSLEngine extends SSLEngine {
|
||||||
hs = SSLEngineResult.HandshakeStatus.NEED_WRAP;
|
hs = SSLEngineResult.HandshakeStatus.NEED_WRAP;
|
||||||
}
|
}
|
||||||
else if (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,
|
/* Already have data buffered to send and in NEED_WRAP state,
|
||||||
* just return so wrap() can be called */
|
* just return so wrap() can be called */
|
||||||
hs = SSLEngineResult.HandshakeStatus.NEED_WRAP;
|
hs = SSLEngineResult.HandshakeStatus.NEED_WRAP;
|
||||||
|
@ -1343,10 +1350,10 @@ public class WolfSSLEngine extends SSLEngine {
|
||||||
synchronized (toSendLock) {
|
synchronized (toSendLock) {
|
||||||
synchronized (netDataLock) {
|
synchronized (netDataLock) {
|
||||||
if (ret <= 0 && err == WolfSSL.SSL_ERROR_WANT_READ &&
|
if (ret <= 0 && err == WolfSSL.SSL_ERROR_WANT_READ &&
|
||||||
in.remaining() == 0 && (this.toSend == null ||
|
in.remaining() == 0 &&
|
||||||
(this.toSend != null && this.toSend.length == 0))
|
(this.internalIOSendBufOffset == 0) &&
|
||||||
&& (prevSessionTicketCount ==
|
(prevSessionTicketCount ==
|
||||||
this.sessionTicketCount)) {
|
this.sessionTicketCount)) {
|
||||||
|
|
||||||
if ((this.ssl.dtls() == 0) ||
|
if ((this.ssl.dtls() == 0) ||
|
||||||
(this.handshakeFinished &&
|
(this.handshakeFinished &&
|
||||||
|
@ -1376,8 +1383,7 @@ public class WolfSSLEngine extends SSLEngine {
|
||||||
if (this.getUseClientMode() && this.handshakeFinished &&
|
if (this.getUseClientMode() && this.handshakeFinished &&
|
||||||
this.ssl.hasSessionTicket() &&
|
this.ssl.hasSessionTicket() &&
|
||||||
this.sessionTicketReceived == false) {
|
this.sessionTicketReceived == false) {
|
||||||
if (this.ssl.dtls() == 1 && this.toSend != null &&
|
if (this.ssl.dtls() == 1 && this.internalIOSendBufOffset > 0) {
|
||||||
this.toSend.length > 0) {
|
|
||||||
/* DTLS 1.3 ACK has been produced in response to
|
/* DTLS 1.3 ACK has been produced in response to
|
||||||
* session ticket message, let's set HS status to
|
* session ticket message, let's set HS status to
|
||||||
* NEED_WRAP so application knows it needs to be sent. */
|
* NEED_WRAP so application knows it needs to be sent. */
|
||||||
|
@ -1414,13 +1420,8 @@ public class WolfSSLEngine extends SSLEngine {
|
||||||
}
|
}
|
||||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||||
"ofst: " + ofst + ", length: " + length);
|
"ofst: " + ofst + ", length: " + length);
|
||||||
if (this.toSend != null) {
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
"internalIOSendBufOffset: " + this.internalIOSendBufOffset);
|
||||||
"toSend.length: " + this.toSend.length);
|
|
||||||
} else {
|
|
||||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
|
||||||
"toSend.length: 0");
|
|
||||||
}
|
|
||||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||||
"handshakeFinished: " + this.handshakeFinished);
|
"handshakeFinished: " + this.handshakeFinished);
|
||||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||||
|
@ -1500,12 +1501,12 @@ public class WolfSSLEngine extends SSLEngine {
|
||||||
err = ssl.getError(ret);
|
err = ssl.getError(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Lock access to this.toSend and this.toRead */
|
/* Lock access to this.internalIOSendBuf and this.toRead */
|
||||||
synchronized (toSendLock) {
|
synchronized (toSendLock) {
|
||||||
if (this.handshakeFinished == true) {
|
if (this.handshakeFinished == true) {
|
||||||
/* close_notify sent by wolfSSL but not across transport yet */
|
/* close_notify sent by wolfSSL but not across transport yet */
|
||||||
if (this.closeNotifySent == true &&
|
if (this.closeNotifySent == true &&
|
||||||
this.toSend != null && this.toSend.length > 0) {
|
this.internalIOSendBufOffset > 0) {
|
||||||
hs = SSLEngineResult.HandshakeStatus.NEED_WRAP;
|
hs = SSLEngineResult.HandshakeStatus.NEED_WRAP;
|
||||||
}
|
}
|
||||||
/* close_notify received, need to send one back */
|
/* close_notify received, need to send one back */
|
||||||
|
@ -1533,7 +1534,7 @@ public class WolfSSLEngine extends SSLEngine {
|
||||||
synchronized (netDataLock) {
|
synchronized (netDataLock) {
|
||||||
synchronized (ioLock) {
|
synchronized (ioLock) {
|
||||||
if (sslConnectAcceptSuccess() && ssl.handshakeDone() &&
|
if (sslConnectAcceptSuccess() && ssl.handshakeDone() &&
|
||||||
(this.toSend == null) &&
|
(this.internalIOSendBufOffset == 0) &&
|
||||||
(this.nativeWantsToWrite == 0) &&
|
(this.nativeWantsToWrite == 0) &&
|
||||||
(this.nativeWantsToRead == 0)) {
|
(this.nativeWantsToRead == 0)) {
|
||||||
|
|
||||||
|
@ -1552,7 +1553,7 @@ public class WolfSSLEngine extends SSLEngine {
|
||||||
}
|
}
|
||||||
/* give priority of WRAP/UNWRAP to state of our internal
|
/* give priority of WRAP/UNWRAP to state of our internal
|
||||||
* I/O data buffers first, then wolfSSL err status */
|
* 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;
|
hs = SSLEngineResult.HandshakeStatus.NEED_WRAP;
|
||||||
}
|
}
|
||||||
else if (this.netData != null &&
|
else if (this.netData != null &&
|
||||||
|
@ -2110,9 +2111,7 @@ public class WolfSSLEngine extends SSLEngine {
|
||||||
*
|
*
|
||||||
* @return number of bytes placed into send queue
|
* @return number of bytes placed into send queue
|
||||||
*/
|
*/
|
||||||
protected synchronized int internalSendCb(byte[] in, int sz) {
|
protected synchronized int internalSendCb(ByteBuffer in, int sz) {
|
||||||
int totalSz = sz, idx = 0;
|
|
||||||
byte[] prevToSend = null;
|
|
||||||
|
|
||||||
synchronized (toSendLock) {
|
synchronized (toSendLock) {
|
||||||
/* As per JSSE Reference Guide, Section 8 DTLS implementation
|
/* 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
|
/* TODO - do we need to fragment data here if larger than
|
||||||
* SSLParameters.getMaximumPacketSize() with DTLS? */
|
* SSLParameters.getMaximumPacketSize() with DTLS? */
|
||||||
if (this.ssl.dtls() == 1) {
|
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.
|
/* Cause SSLEngine to only send one packet at a time.
|
||||||
* Keep track if wolfSSL had wanted to send data. We will
|
* Keep track if wolfSSL had wanted to send data. We will
|
||||||
* use that information when setting the handshake
|
* use that information when setting the handshake
|
||||||
|
@ -2139,27 +2139,39 @@ public class WolfSSLEngine extends SSLEngine {
|
||||||
this.nativeWantsToWrite = 0;
|
this.nativeWantsToWrite = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make copy of existing toSend array before expanding */
|
if (sz <= 0) {
|
||||||
if (this.toSend != null) {
|
/* No data to send */
|
||||||
prevToSend = this.toSend.clone();
|
return 0;
|
||||||
totalSz += this.toSend.length;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allocate new array to hold data to be sent */
|
/* If we have more data than internal static buffer,
|
||||||
this.toSend = new byte[totalSz];
|
* grow buffer 2x (or up to sz needed) and copy data over */
|
||||||
|
if ((this.internalIOSendBufSz -
|
||||||
/* Copy existing toSend data over */
|
this.internalIOSendBufOffset) < sz) {
|
||||||
if (prevToSend != null) {
|
/* Allocate new buffer to hold data to be sent */
|
||||||
System.arraycopy(prevToSend, 0, this.toSend, idx,
|
int newSz = this.internalIOSendBufSz * 2;
|
||||||
prevToSend.length);
|
if (newSz < sz) {
|
||||||
idx += prevToSend.length;
|
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) {
|
/* Add data to end of internal static buffer */
|
||||||
WolfSSLDebug.logHex(getClass(), WolfSSLDebug.INFO,
|
in.get(this.internalIOSendBuf, this.internalIOSendBufOffset, sz);
|
||||||
"CB Write", in, 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;
|
return sz;
|
||||||
|
@ -2169,15 +2181,16 @@ public class WolfSSLEngine extends SSLEngine {
|
||||||
* Internal receive callback. Reads from netData and gives bytes back
|
* Internal receive callback. Reads from netData and gives bytes back
|
||||||
* to native wolfSSL for processing.
|
* 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
|
* @param sz number of bytes that should be read/copied from transport
|
||||||
*
|
*
|
||||||
* @return number of bytes read into toRead array or negative
|
* @return number of bytes read into toRead array or negative
|
||||||
* value on error
|
* value on error
|
||||||
*/
|
*/
|
||||||
protected synchronized int internalRecvCb(byte[] toRead, int sz) {
|
protected synchronized int internalRecvCb(ByteBuffer toRead, int sz) {
|
||||||
|
|
||||||
int max = 0;
|
int max = 0;
|
||||||
|
int originalLimit = 0;
|
||||||
|
|
||||||
synchronized (netDataLock) {
|
synchronized (netDataLock) {
|
||||||
if (ioDebugEnabled == true) {
|
if (ioDebugEnabled == true) {
|
||||||
|
@ -2211,13 +2224,22 @@ public class WolfSSLEngine extends SSLEngine {
|
||||||
this.nativeWantsToRead = 0;
|
this.nativeWantsToRead = 0;
|
||||||
|
|
||||||
max = (sz < this.netData.remaining()) ? sz : this.netData.remaining();
|
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) {
|
if (ioDebugEnabled == true) {
|
||||||
|
int toReadPos = toRead.position();
|
||||||
|
byte[] tmpArr = new byte[max];
|
||||||
|
toRead.get(tmpArr, 0, max);
|
||||||
WolfSSLDebug.logHex(getClass(), WolfSSLDebug.INFO,
|
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;
|
return max;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2248,28 +2270,28 @@ public class WolfSSLEngine extends SSLEngine {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private class SendCB implements WolfSSLIOSendCallback {
|
private class SendCB implements WolfSSLByteBufferIOSendCallback {
|
||||||
|
|
||||||
protected SendCB() {
|
protected SendCB() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int sendCallback(WolfSSLSession ssl, byte[] toSend, int sz,
|
public int sendCallback(WolfSSLSession ssl, ByteBuffer toSend, int sz,
|
||||||
Object engine) {
|
Object engine) {
|
||||||
return ((WolfSSLEngine)engine).internalSendCb(toSend, sz);
|
return ((WolfSSLEngine)engine).internalSendCb(toSend, sz);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class RecvCB implements WolfSSLIORecvCallback {
|
private class RecvCB implements WolfSSLByteBufferIORecvCallback {
|
||||||
|
|
||||||
protected RecvCB() {
|
protected RecvCB() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int receiveCallback(WolfSSLSession ssl, byte[] out, int sz,
|
public int receiveCallback(WolfSSLSession ssl, ByteBuffer buf, int sz,
|
||||||
Object engine) {
|
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.freeSSL();
|
||||||
this.ssl = null;
|
this.ssl = null;
|
||||||
}
|
}
|
||||||
|
/* Clear our reference to static application direct ByteBuffer */
|
||||||
|
if (this.staticAppDataBuf != null) {
|
||||||
|
this.staticAppDataBuf.clear();
|
||||||
|
this.staticAppDataBuf = null;
|
||||||
|
}
|
||||||
super.finalize();
|
super.finalize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -760,15 +760,52 @@ public class WolfSSLImplementSSLSession extends ExtendedSSLSession
|
||||||
return this.port;
|
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
|
@Override
|
||||||
public int getPacketBufferSize() {
|
public synchronized int getPacketBufferSize() {
|
||||||
/* Match conscrypt's calculations here for maximum potential
|
|
||||||
* SSL/TLS record length. Used by SSLEngine consumers to allocate
|
/* JSSE implementations seem to set the SSL/TLS maximum packet size
|
||||||
* output buffer size.
|
* (record size) differently.
|
||||||
|
*
|
||||||
|
* Conscrypt calculates this as 18437 bytes:
|
||||||
*
|
*
|
||||||
* type(1) + version(2) + length(2) + 2^14 plaintext +
|
* type(1) + version(2) + length(2) + 2^14 plaintext +
|
||||||
* max compression overhead (1024) + max AEAD overhead (1024) */
|
* max compression overhead (1024) + max AEAD overhead (1024)
|
||||||
return 18437;
|
*
|
||||||
|
* 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
|
@Override
|
||||||
|
|
|
@ -1662,8 +1662,8 @@ public class WolfSSLEngineTest {
|
||||||
session = engine.getSession();
|
session = engine.getSession();
|
||||||
packetBufSz = session.getPacketBufferSize();
|
packetBufSz = session.getPacketBufferSize();
|
||||||
|
|
||||||
/* expected to be 18437 */
|
/* expected to be 17k */
|
||||||
if (packetBufSz != 18437) {
|
if (packetBufSz != (17 * 1024)) {
|
||||||
error("\t\t... failed");
|
error("\t\t... failed");
|
||||||
fail("got incorrect packet buffer size (" +
|
fail("got incorrect packet buffer size (" +
|
||||||
enabledProtocols.get(i) + ")");
|
enabledProtocols.get(i) + ")");
|
||||||
|
|
|
@ -3393,7 +3393,7 @@ public class WolfSSLSocketTest {
|
||||||
throw cliException;
|
throw cliException;
|
||||||
}
|
}
|
||||||
|
|
||||||
System.out.println("\t\t... passed");
|
System.out.println("\t... passed");
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
/* Restore original property value */
|
/* Restore original property value */
|
||||||
|
|
|
@ -644,13 +644,6 @@ public class WolfSSLContextTest {
|
||||||
fail("setMinECCKeySize should fail with negative key size");
|
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 */
|
/* valid key length should succeed */
|
||||||
ret = ctx.setMinECCKeySize(128);
|
ret = ctx.setMinECCKeySize(128);
|
||||||
if (ret != WolfSSL.SSL_SUCCESS) {
|
if (ret != WolfSSL.SSL_SUCCESS) {
|
||||||
|
|
|
@ -23,13 +23,10 @@ package com.wolfssl.test;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
import org.junit.runners.JUnit4;
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
import java.io.ByteArrayOutputStream;
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.PrintStream;
|
import java.io.PrintStream;
|
||||||
import java.io.IOException;
|
|
||||||
import java.net.Socket;
|
import java.net.Socket;
|
||||||
import java.net.ServerSocket;
|
import java.net.ServerSocket;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
|
@ -43,6 +40,8 @@ import java.util.concurrent.Future;
|
||||||
import java.util.concurrent.Callable;
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.CountDownLatch;
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import com.wolfssl.WolfSSL;
|
import com.wolfssl.WolfSSL;
|
||||||
import com.wolfssl.WolfSSLDebug;
|
import com.wolfssl.WolfSSLDebug;
|
||||||
|
@ -53,12 +52,11 @@ import com.wolfssl.WolfSSLPskClientCallback;
|
||||||
import com.wolfssl.WolfSSLPskServerCallback;
|
import com.wolfssl.WolfSSLPskServerCallback;
|
||||||
import com.wolfssl.WolfSSLTls13SecretCallback;
|
import com.wolfssl.WolfSSLTls13SecretCallback;
|
||||||
import com.wolfssl.WolfSSLSession;
|
import com.wolfssl.WolfSSLSession;
|
||||||
|
import com.wolfssl.WolfSSLByteBufferIORecvCallback;
|
||||||
|
import com.wolfssl.WolfSSLByteBufferIOSendCallback;
|
||||||
|
|
||||||
public class WolfSSLSessionTest {
|
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 cliCert = "./examples/certs/client-cert.pem";
|
||||||
private static String cliKey = "./examples/certs/client-key.pem";
|
private static String cliKey = "./examples/certs/client-key.pem";
|
||||||
private static String srvCert = "./examples/certs/server-cert.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 String exampleHost = "www.example.com";
|
||||||
private final static int examplePort = 443;
|
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;
|
private static WolfSSLContext ctx = null;
|
||||||
|
|
||||||
@BeforeClass
|
@BeforeClass
|
||||||
|
@ -889,7 +890,6 @@ public class WolfSSLSessionTest {
|
||||||
public void test_WolfSSLSession_setTls13SecretCb()
|
public void test_WolfSSLSession_setTls13SecretCb()
|
||||||
throws WolfSSLJNIException {
|
throws WolfSSLJNIException {
|
||||||
|
|
||||||
int ret;
|
|
||||||
WolfSSL sslLib = null;
|
WolfSSL sslLib = null;
|
||||||
WolfSSLContext sslCtx = null;
|
WolfSSLContext sslCtx = null;
|
||||||
WolfSSLSession ssl = null;
|
WolfSSLSession ssl = null;
|
||||||
|
@ -1413,5 +1413,409 @@ public class WolfSSLSessionTest {
|
||||||
|
|
||||||
System.out.println("\t... passed");
|
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