JSSE: add initial SSLEngine support for DTLSv1.3

pull/254/head
Chris Conlon 2024-10-21 13:21:12 -06:00
parent 36a1057366
commit 372ef97746
16 changed files with 728 additions and 205 deletions

View File

@ -373,9 +373,12 @@ Additional instructions can be found on the wolfSSL.com website:
### JSSE Class Implementation Support
wolfJSSE extends or implements the following JSSE classes:
wolfJSSE extends or implements the following JSSE classes. Note that
SSLContext `DTLSv1.3` support is only supported through the `SSLEngine`
interface.
- javax.net.ssl.SSLContextSpi
- SSL, TLS, DEFAULT, TLSv1, TLSv1.1, TLSv1.2, TLSv1.3
- SSL, TLS, DEFAULT, TLSv1, TLSv1.1, TLSv1.2, TLSv1.3, DTLSv1.3
- javax.net.ssl.KeyManagerFactorySpi
- PKIX, X509, SunX509
- javax.net.ssl.TrustManagerFactorySpi

View File

@ -530,6 +530,19 @@ JNIEXPORT jboolean JNICALL Java_com_wolfssl_WolfSSL_TLSv13Enabled
#endif
}
JNIEXPORT jboolean JNICALL Java_com_wolfssl_WolfSSL_DTLSv13Enabled
(JNIEnv* jenv, jclass jcl)
{
(void)jenv;
(void)jcl;
#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_DTLS13)
return JNI_TRUE;
#else
return JNI_FALSE;
#endif
}
JNIEXPORT jboolean JNICALL Java_com_wolfssl_WolfSSL_ShaEnabled
(JNIEnv* jenv, jclass jcl)
{
@ -1996,41 +2009,43 @@ JNIEXPORT jobjectArray JNICALL Java_com_wolfssl_WolfSSL_getProtocolsMask
(void)jcl;
/* get the number of protocols enabled */
/* Get the number of protocols enabled, based on provided mask. Native
* wolfSSL doesn't have mask values for DTLS, so we lump them together
* with their corresponding TLS version, if correct defines are set. */
#ifdef WOLFSSL_TLS13
if(!(mask & SSL_OP_NO_TLSv1_3))
if(!(mask & SSL_OP_NO_TLSv1_3)) {
numProtocols += 1;
#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_DTLS13)
numProtocols += 1;
#endif
}
#endif
#ifndef WOLFSSL_NO_TLS12
if(!(mask & SSL_OP_NO_TLSv1_2))
if(!(mask & SSL_OP_NO_TLSv1_2)) {
numProtocols += 1;
#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12)
numProtocols += 1;
#endif
}
#endif
#ifndef NO_OLD_TLS
if(!(mask & SSL_OP_NO_TLSv1_1))
if(!(mask & SSL_OP_NO_TLSv1_1)) {
numProtocols += 1;
}
#ifdef WOLFSSL_ALLOW_TLSV10
if(!(mask & SSL_OP_NO_TLSv1))
if(!(mask & SSL_OP_NO_TLSv1)) {
numProtocols += 1;
#ifdef WOLFSSL_DTLS
numProtocols += 1;
#endif
}
#endif /* WOLFSSL_ALLOW_TLSv10 */
#endif /* !NO_OLD_TLS */
#ifdef WOLFSSL_ALLOW_SSLv3
if(!(mask & SSL_OP_NO_SSLv3))
if(!(mask & SSL_OP_NO_SSLv3)) {
numProtocols += 1;
}
#endif
#ifdef WOLFSSL_DTLS
#ifndef NO_OLD_TLS
/* DTLS 1.0 */
numProtocols += 1;
#endif
#ifndef WOLFSSL_NO_TLS12
/* DTLS 1.2 */
numProtocols += 1;
#endif
#ifdef WOLFSSL_DTLS13
/* DTLS 1.3 */
numProtocols += 1;
#endif
#endif /* WOLFSSL_DTLS */
ret = (*jenv)->NewObjectArray(jenv, numProtocols,
(*jenv)->FindClass(jenv, "java/lang/String"), NULL);
@ -2104,36 +2119,39 @@ JNIEXPORT jobjectArray JNICALL Java_com_wolfssl_WolfSSL_getProtocolsMask
#ifdef WOLFSSL_DTLS
#ifndef NO_OLD_TLS
/* DTLS 1.0 */
(*jenv)->SetObjectArrayElement(jenv, ret, idx++,
(*jenv)->NewStringUTF(jenv, "DTLSv1"));
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
(*jenv)->ThrowNew(jenv, jcl, "Error setting DTLSv1 string");
return NULL;
if(!(mask & SSL_OP_NO_TLSv1)) {
(*jenv)->SetObjectArrayElement(jenv, ret, idx++,
(*jenv)->NewStringUTF(jenv, "DTLSv1"));
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
(*jenv)->ThrowNew(jenv, jcl, "Error setting DTLSv1 string");
return NULL;
}
}
#endif
#ifndef WOLFSSL_NO_TLS12
/* DTLS 1.2 */
(*jenv)->SetObjectArrayElement(jenv, ret, idx++,
(*jenv)->NewStringUTF(jenv, "DTLSv1.2"));
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
(*jenv)->ThrowNew(jenv, jcl, "Error setting DTLSv1.2 string");
return NULL;
if(!(mask & SSL_OP_NO_TLSv1_2)) {
(*jenv)->SetObjectArrayElement(jenv, ret, idx++,
(*jenv)->NewStringUTF(jenv, "DTLSv1.2"));
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
(*jenv)->ThrowNew(jenv, jcl, "Error setting DTLSv1.2 string");
return NULL;
}
}
#endif
#ifdef WOLFSSL_DTLS13
/* DTLS 1.3 */
(*jenv)->SetObjectArrayElement(jenv, ret, idx++,
(*jenv)->NewStringUTF(jenv, "DTLSv1.3"));
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
(*jenv)->ThrowNew(jenv, jcl, "Error setting DTLSv1.3 string");
return NULL;
#if defined(WOLFSSL_TLS13) && defined(WOLFSSL_DTLS13)
if(!(mask & SSL_OP_NO_TLSv1_3)) {
(*jenv)->SetObjectArrayElement(jenv, ret, idx++,
(*jenv)->NewStringUTF(jenv, "DTLSv1.3"));
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
(*jenv)->ThrowNew(jenv, jcl, "Error setting DTLSv1.3 string");
return NULL;
}
}
#endif
#endif

View File

@ -93,10 +93,14 @@ extern "C" {
#define com_wolfssl_WolfSSL_SOCKET_ERROR_E -308L
#undef com_wolfssl_WolfSSL_FATAL_ERROR
#define com_wolfssl_WolfSSL_FATAL_ERROR -313L
#undef com_wolfssl_WolfSSL_OUT_OF_ORDER_E
#define com_wolfssl_WolfSSL_OUT_OF_ORDER_E -373L
#undef com_wolfssl_WolfSSL_SSL_ERROR_SOCKET_PEER_CLOSED
#define com_wolfssl_WolfSSL_SSL_ERROR_SOCKET_PEER_CLOSED -397L
#undef com_wolfssl_WolfSSL_UNKNOWN_ALPN_PROTOCOL_NAME_E
#define com_wolfssl_WolfSSL_UNKNOWN_ALPN_PROTOCOL_NAME_E -405L
#undef com_wolfssl_WolfSSL_APP_DATA_READY
#define com_wolfssl_WolfSSL_APP_DATA_READY -441L
#undef com_wolfssl_WolfSSL_WOLFSSL_CRL_CHECKALL
#define com_wolfssl_WolfSSL_WOLFSSL_CRL_CHECKALL 1L
#undef com_wolfssl_WolfSSL_WOLFSSL_OCSP_URL_OVERRIDE
@ -597,6 +601,14 @@ JNIEXPORT jboolean JNICALL Java_com_wolfssl_WolfSSL_TLSv12Enabled
JNIEXPORT jboolean JNICALL Java_com_wolfssl_WolfSSL_TLSv13Enabled
(JNIEnv *, jclass);
/*
* Class: com_wolfssl_WolfSSL
* Method: DTLSv13Enabled
* Signature: ()Z
*/
JNIEXPORT jboolean JNICALL Java_com_wolfssl_WolfSSL_DTLSv13Enabled
(JNIEnv *, jclass);
/*
* Class: com_wolfssl_WolfSSL
* Method: ShaEnabled

View File

@ -1568,6 +1568,16 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_read__JLjava_nio_ByteBuff
return size;
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_pending
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jcl;
/* Checks ssl for NULL internally, will return WOLFSSL_FAILURE */
return (jint)wolfSSL_pending(ssl);
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_accept
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jint timeout)
{
@ -2414,20 +2424,11 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_dtlsGotTimeout
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
#if !defined(WOLFSSL_LEANPSK) && defined(WOLFSSL_DTLS)
jclass excClass;
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jenv;
(void)jcl;
if (ssl == NULL) {
excClass = (*jenv)->FindClass(jenv, "com/wolfssl/WolfSSLException");
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
return SSL_FATAL_ERROR;
}
(*jenv)->ThrowNew(jenv, excClass,
"Input WolfSSLSession object was null in "
"dtlsGotTimeout()");
return SSL_FATAL_ERROR;
}
@ -2440,22 +2441,35 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_dtlsGotTimeout
#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_dtls
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_dtlsRetransmit
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
jclass excClass;
#if !defined(WOLFSSL_LEANPSK) && defined(WOLFSSL_DTLS)
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jenv;
(void)jcl;
if (ssl == NULL) {
return SSL_FATAL_ERROR;
}
return wolfSSL_dtls_retransmit(ssl);
#else
(void)jenv;
(void)jcl;
(void)sslPtr;
return NOT_COMPILED_IN;
#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_dtls
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jenv;
(void)jcl;
if (ssl == NULL) {
excClass = (*jenv)->FindClass(jenv, "com/wolfssl/WolfSSLException");
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
return 0;
}
(*jenv)->ThrowNew(jenv, excClass,
"Input WolfSSLSession object was null in dtls()");
return 0;
}
@ -2694,6 +2708,51 @@ JNIEXPORT jobject JNICALL Java_com_wolfssl_WolfSSLSession_dtlsGetPeer
}
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_setMTU
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jint mtu)
{
#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_DTLS_MTU)
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
/* wolfSSL_dtls_set_mtu() checks ssl for NULL */
return (jint)wolfSSL_dtls_set_mtu(ssl, (unsigned short)mtu);
#else
(void)jenv;
(void)jcl;
(void)sslPtr;
(void)mtu;
return (jint)NOT_COMPILED_IN;
#endif
}
JNIEXPORT jstring JNICALL Java_com_wolfssl_WolfSSLSession_stateStringLong
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
#ifdef OPENSSL_EXTRA
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
const char* stateString;
jstring stateStr = NULL;
(void)jcl;
if (jenv == NULL || ssl == NULL) {
return NULL;
}
stateString = wolfSSL_state_string_long(ssl);
if (stateString != NULL) {
stateStr = (*jenv)->NewStringUTF(jenv, stateString);
}
return stateStr;
#else
(void)jenv;
(void)jcl;
(void)sslPtr;
return NULL;
#endif
}
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_sessionReused
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
@ -4681,9 +4740,8 @@ JNIEXPORT jboolean JNICALL Java_com_wolfssl_WolfSSLSession_handshakeDone
if (wolfSSL_is_init_finished(ssl)) {
return JNI_TRUE;
}
else {
return JNI_FALSE;
}
return JNI_FALSE;
}
JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLSession_setConnectState
@ -5777,24 +5835,12 @@ JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLSession_setSSLIORecv
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
(void)jenv;
(void)jcl;
/* find exception class */
jclass excClass = (*jenv)->FindClass(jenv,
"com/wolfssl/WolfSSLJNIException");
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
return;
}
if (ssl != NULL) {
/* set I/O recv callback */
wolfSSL_SSLSetIORecv(ssl, NativeSSLIORecvCb);
} else {
(*jenv)->ThrowNew(jenv, excClass,
"Input WolfSSLContext object was null when setting IORecv");
}
}
@ -5931,23 +5977,12 @@ JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLSession_setSSLIOSend
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
jclass excClass = NULL;
(void)jenv;
(void)jcl;
/* find exception class in case we need it */
excClass = (*jenv)->FindClass(jenv, "com/wolfssl/WolfSSLJNIException");
if ((*jenv)->ExceptionOccurred(jenv)) {
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
}
if (ssl != NULL) {
/* set I/O send callback */
wolfSSL_SSLSetIOSend(ssl, NativeSSLIOSendCb);
} else {
(*jenv)->ThrowNew(jenv, excClass,
"Input WolfSSLContext object was null when setting IOSend");
}
}

View File

@ -111,6 +111,14 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_read__J_3BIII
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_read__JLjava_nio_ByteBuffer_2II
(JNIEnv *, jobject, jlong, jobject, jint, jint);
/*
* Class: com_wolfssl_WolfSSLSession
* Method: pending
* Signature: (J)I
*/
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_pending
(JNIEnv *, jobject, jlong);
/*
* Class: com_wolfssl_WolfSSLSession
* Method: accept
@ -279,6 +287,14 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_dtlsGetCurrentTimeout
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_dtlsGotTimeout
(JNIEnv *, jobject, jlong);
/*
* Class: com_wolfssl_WolfSSLSession
* Method: dtlsRetransmit
* Signature: (J)I
*/
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_dtlsRetransmit
(JNIEnv *, jobject, jlong);
/*
* Class: com_wolfssl_WolfSSLSession
* Method: dtls
@ -895,6 +911,22 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_interruptBlockedIO
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_getThreadsBlockedInPoll
(JNIEnv *, jobject, jlong);
/*
* Class: com_wolfssl_WolfSSLSession
* Method: setMTU
* Signature: (JI)I
*/
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_setMTU
(JNIEnv *, jobject, jlong, jint);
/*
* Class: com_wolfssl_WolfSSLSession
* Method: stateStringLong
* Signature: (J)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_wolfssl_WolfSSLSession_stateStringLong
(JNIEnv *, jobject, jlong);
#ifdef __cplusplus
}
#endif

View File

@ -214,10 +214,14 @@ public class WolfSSL {
public static final int SOCKET_ERROR_E = -308;
/** Received fatal alert error */
public static final int FATAL_ERROR = -313;
/** Out of order message */
public static final int OUT_OF_ORDER_E = -373;
/** Peer closed socket */
public static final int SSL_ERROR_SOCKET_PEER_CLOSED = -397;
/** Unrecognized ALPN protocol name */
public static final int UNKNOWN_ALPN_PROTOCOL_NAME_E = -405;
/** DTLS application data ready for read */
public static final int APP_DATA_READY = -441;
/* extra definitions from ssl.h */
/** CertManager: check all cert CRLs */
@ -844,6 +848,13 @@ public class WolfSSL {
*/
public static native boolean TLSv13Enabled();
/**
* Tests if DTLS 1.3 has been compiled into the native wolfSSL library.
*
* @return true if enabled, otherwise false if not compiled in.
*/
public static native boolean DTLSv13Enabled();
/**
* Tests if SHA-1 is enabled in the native wolfSSL library.
*

View File

@ -316,6 +316,7 @@ public class WolfSSLSession {
int timeout);
private native int read(long ssl, ByteBuffer data, int sz, int timeout)
throws WolfSSLException;
private native int pending(long ssl);
private native int accept(long ssl, int timeout);
private native void freeSSL(long ssl);
private native int shutdownSSL(long ssl, int timeout);
@ -337,6 +338,7 @@ public class WolfSSLSession {
private native int setCipherList(long ssl, String list);
private native int dtlsGetCurrentTimeout(long ssl);
private native int dtlsGotTimeout(long ssl);
private native int dtlsRetransmit(long ssl);
private native int dtls(long ssl);
private native int dtlsSetPeer(long ssl, InetSocketAddress peer);
private native InetSocketAddress dtlsGetPeer(long ssl);
@ -419,6 +421,8 @@ public class WolfSSLSession {
private native int hasTicket(long session);
private native int interruptBlockedIO(long ssl);
private native int getThreadsBlockedInPoll(long ssl);
private native int setMTU(long ssl, int mtu);
private native String stateStringLong(long ssl);
/* ------------------- session-specific methods --------------------- */
@ -1139,7 +1143,7 @@ public class WolfSSLSession {
* <code>read()</code> again. Use <code>getError</code> to
* get a specific error code.
* <code>BAD_FUNC_ARC</code> when bad arguments are used.
* @throws IllegalStateException WolfSSLContext has been freed
* @throws IllegalStateException WolfSSLSession has been freed
* @throws SocketTimeoutException if socket timeout occurs
* @throws SocketException Native socket select/poll() failed
*/
@ -1257,6 +1261,29 @@ public class WolfSSLSession {
return ret;
}
/**
* Return number of bytes available on the internal output buffer that
* have already been decrypted and available immediately via a call to
* read().
*
* @return number of bytes available on success, WolfSSL.SSL_FAILURE
* on error.
*
* @throws IllegalStateException WolfSSLSession has been freed
*/
public int pending() throws IllegalStateException {
int ret = 0;
confirmObjectIsActive();
synchronized (sslLock) {
ret = pending(this.sslPtr);
}
return ret;
}
/**
* Waits for an SSL client to initiate the SSL/TLS handshake.
* This method is called on the server side. When it is called, the
@ -2260,14 +2287,12 @@ public class WolfSSLSession {
* the peer. <code>NOT_COMPILED_IN</code> if wolfSSL was
* not compiled with DTLS support.
* @throws IllegalStateException WolfSSLContext has been freed
* @throws WolfSSLJNIException Internal JNI error
* @see #dtlsGetCurrentTimeout()
* @see #dtlsGetPeer()
* @see #dtlsSetPeer(InetSocketAddress)
* @see #dtls()
*/
public int dtlsGotTimeout()
throws IllegalStateException, WolfSSLJNIException {
public int dtlsGotTimeout() throws IllegalStateException {
confirmObjectIsActive();
@ -2279,20 +2304,47 @@ public class WolfSSLSession {
}
}
/**
* When using non-blocking sockets with DTLS, this function retransmits
* the last handshake flight ignoring the expected timeout value and
* retransmit count.
*
* It is useful for applications that are using DTLS and need to manage
* even the timeout and retry count.
*
* @return <code>SSL_SUCCESS</code> upon success. <code>
* SSL_FATAL_ERROR</code> if there have been too many
* retransmissions/timeouts without getting a response from
* the peer. <code>NOT_COMPILED_IN</code> if wolfSSL was
* not compiled with DTLS support.
* @throws IllegalStateException WolfSSLContext has been freed
* @see #dtlsGetCurrentTimeout()
* @see #dtlsGetPeer()
* @see #dtlsSetPeer(InetSocketAddress)
* @see #dtlsGotTimeout()
* @see #dtls()
*/
public int dtlsRetransmit() throws IllegalStateException {
confirmObjectIsActive();
synchronized (sslLock) {
return dtlsRetransmit(this.sslPtr);
}
}
/**
* Used to determine if the SSL session has been configured to use DTLS.
*
* @return <code>1</code> if the SSL has been configured to use DTLS,
* otherwise, <code>0</code>.
* @throws IllegalStateException WolfSSLContext has been freed
* @throws WolfSSLJNIException Internal JNI error
* @see #dtlsGetCurrentTimeout()
* @see #dtlsGetPeer()
* @see #dtlsGotTimeout()
* @see #dtlsSetPeer(InetSocketAddress)
*/
public int dtls()
throws IllegalStateException, WolfSSLJNIException {
public int dtls() throws IllegalStateException {
confirmObjectIsActive();
@ -2355,6 +2407,57 @@ public class WolfSSLSession {
}
}
/**
* Set the DTLS MTU to use.
*
* Native wolfSSL must be compiled with "--enable-dtls-mtu" in addition
* to "--enable-dtls".
*
* @param mtu DTLS MTU value, must be lower than MAX_RECORD_SIZE (16k)
*
* @return <code>SSL_SUCCESS</code> on success,
* <code>SSL_FAILURE</code> on error, or
* <code>NOT_COMPILED_IN</code> if native support has not
* been compiled into native wolfSSL.
*
* @throws IllegalStateException WolfSSLContext has been freed
*/
public int dtlsSetMTU(int mtu) throws IllegalStateException {
confirmObjectIsActive();
synchronized (sslLock) {
return setMTU(this.sslPtr, mtu);
}
}
/**
* Return the current handshake state of the native WOLFSSL object as
* a String.
*
* @return String representing current state of handshake or empty
* String if not able to retrieve one.
*
* @throws IllegalStateException WolfSSLContext has been freed
*/
public String getStateStringLong() throws IllegalStateException {
String state = null;
confirmObjectIsActive();
synchronized (sslLock) {
state = stateStringLong(this.sslPtr);
if (state == null) {
/* Return empty string instead of null, may prevent some
* NullPoinerExceptions from callers */
state = "";
}
}
return state;
}
/**
* Determine if a reused session was negotiated during the SSL
* handshake.
@ -4168,8 +4271,10 @@ public class WolfSSLSession {
/* set user I/O recv */
internRecvSSLCb = callback;
/* register internal callback with native library */
setSSLIORecv(this.sslPtr);
if (callback != null) {
/* register internal callback with native library */
setSSLIORecv(this.sslPtr);
}
}
}
@ -4206,8 +4311,10 @@ public class WolfSSLSession {
/* set user I/O send */
internSendSSLCb = callback;
/* register internal callback with native library */
setSSLIOSend(this.sslPtr);
if (callback != null) {
/* register internal callback with native library */
setSSLIOSend(this.sslPtr);
}
}
}

View File

@ -91,7 +91,8 @@ public class WolfSSLContext extends SSLContextSpi {
ctxAttr.version == TLS_VERSION.TLSv1_1 ||
ctxAttr.version == TLS_VERSION.TLSv1_2 ||
ctxAttr.version == TLS_VERSION.TLSv1_3 ||
ctxAttr.version == TLS_VERSION.SSLv23) {
ctxAttr.version == TLS_VERSION.SSLv23 ||
ctxAttr.version == TLS_VERSION.DTLSv1_3) {
this.currentVersion = ctxAttr.version;
} else {
throw new IllegalArgumentException(
@ -134,6 +135,11 @@ public class WolfSSLContext extends SSLContextSpi {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"creating WolfSSLContext with SSLv23");
break;
case DTLSv1_3:
method = WolfSSL.DTLSv1_3_Method();
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"creating WolfSSLContext with DTLSv1_3");
break;
default:
throw new IllegalArgumentException(
"Invalid SSL/TLS protocol version");
@ -175,7 +181,7 @@ public class WolfSSLContext extends SSLContextSpi {
* which have been disabled via system property get filtered in
* WolfSSLEngineHelper.sanitizeProtocols() */
params.setProtocols(WolfSSLUtil.sanitizeProtocols(
this.getProtocolsMask(ctxAttr.noOptions)));
this.getProtocolsMask(ctxAttr.noOptions), this.currentVersion));
try {
LoadTrustedRootCerts();
@ -677,6 +683,20 @@ public class WolfSSLContext extends SSLContextSpi {
}
}
/**
* SSLContext implementation supporting DTLS 1.3
*/
public static final class DTLSV13_Context extends WolfSSLContext {
/**
* Create new DTLSv13_Context, calls parent WolfSSLContext constructor
*/
public DTLSV13_Context() {
super(TLS_VERSION.DTLSv1_3);
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"creating new WolfSSLContext using DTLSV13_Context");
}
}
/**
* DEFAULT SSLContext class.

View File

@ -72,6 +72,8 @@ public class WolfSSLEngine extends SSLEngine {
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;
/* Does TLS handshake need initialization */
@ -218,6 +220,7 @@ public class WolfSSLEngine extends SSLEngine {
try {
this.engineHelper.LoadKeyAndCertChain(null, this);
certKeyLoaded = true;
} catch (CertificateEncodingException | IOException |
WolfSSLException e) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
@ -441,26 +444,43 @@ public class WolfSSLEngine extends SSLEngine {
* times out. This should not happen since infinite timeout is
* being used for these calls.
*/
private synchronized int DoHandshake() throws SSLException {
private synchronized int DoHandshake(boolean fromWrap) throws SSLException {
int ret = WolfSSL.SSL_SUCCESS;
try {
if (this.getUseClientMode()) {
/* If DTLS and calling from wrap() but HandshakeStatus is
* actually NEED_UNWRAP, this is a signal from the application
* that we need to retransmit messages */
if ((this.ssl.dtls() == 1) && fromWrap &&
(this.hs == SSLEngineResult.HandshakeStatus.NEED_UNWRAP)) {
synchronized (ioLock) {
ret = this.ssl.connect();
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"ssl.connect() ret:err = " + ret + " : " +
ssl.getError(ret));
"Calling wrap() while status is NEED_UNWRAP, " +
"retransmitting DTLS messages");
ret = this.ssl.dtlsGotTimeout();
if (ret == 0) {
ret = WolfSSL.SSL_SUCCESS;
}
}
}
else {
synchronized (ioLock) {
ret = this.ssl.accept();
if (ret == WolfSSL.SSL_SUCCESS) {
if (this.getUseClientMode()) {
synchronized (ioLock) {
ret = this.ssl.connect();
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"ssl.accept() ret:err = " + ret + " : " +
ssl.getError(ret));
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"ssl.connect() ret:err = " + ret + " : " +
ssl.getError(ret));
}
}
else {
synchronized (ioLock) {
ret = this.ssl.accept();
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"ssl.accept() ret:err = " + ret + " : " +
ssl.getError(ret));
}
}
}
@ -633,6 +653,12 @@ public class WolfSSLEngine extends SSLEngine {
"handshakeStatus: " + hs);
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"handshakeFinished: " + this.handshakeFinished);
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"nativeHandshakeState: " + this.ssl.getStateStringLong());
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"nativeWantsToRead: " + this.nativeWantsToRead);
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"nativeWantsToWrite: " + this.nativeWantsToWrite);
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"===========================================================");
}
@ -691,7 +717,7 @@ public class WolfSSLEngine extends SSLEngine {
else if (produced == 0) {
/* continue handshake or application data */
if (!this.handshakeFinished) {
ret = DoHandshake();
ret = DoHandshake(true);
}
else {
try {
@ -756,6 +782,12 @@ public class WolfSSLEngine extends SSLEngine {
"consumed: " + consumed);
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"produced: " + produced);
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"nativeHandshakeState: " + this.ssl.getStateStringLong());
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"nativeWantsToRead: " + this.nativeWantsToRead);
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"nativeWantsToWrite: " + this.nativeWantsToWrite);
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"===========================================================");
}
@ -830,10 +862,22 @@ public class WolfSSLEngine extends SSLEngine {
* ByteBuffer array */
if (out.length == 1) {
ret = this.ssl.read(out[0], maxOutSz, 0);
if ((ret < 0) &&
(ssl.getError(ret) == WolfSSL.APP_DATA_READY)) {
/* If DTLS, we may need to call SSL_read() again
* right away again if app data was received */
ret = this.ssl.read(out[0], maxOutSz, 0);
}
}
else {
tmp = new byte[maxOutSz];
ret = this.ssl.read(tmp, maxOutSz);
if ((ret < 0) &&
(ssl.getError(ret) == WolfSSL.APP_DATA_READY)) {
/* If DTLS, we may need to call SSL_read() again
* right away again if app data was received */
ret = this.ssl.read(tmp, maxOutSz);
}
}
} catch (SocketTimeoutException | SocketException e) {
throw new SSLException(e);
@ -855,6 +899,11 @@ public class WolfSSLEngine extends SSLEngine {
"RecvAppData(), got WANT_READ/WANT_WRITE");
break;
case WolfSSL.APP_DATA_READY:
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"RecvAppData(), got APP_DATA_READY");
break;
/* In 0 and ZERO_RETURN cases we may have gotten a
* close_notify alert, check on shutdown status */
case WolfSSL.SSL_ERROR_ZERO_RETURN:
@ -1024,6 +1073,12 @@ public class WolfSSLEngine extends SSLEngine {
"handshakeStatus: " + hs);
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"status: " + status);
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"nativeHandshakeState: " + this.ssl.getStateStringLong());
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"nativeWantsToRead: " + this.nativeWantsToRead);
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"nativeWantsToWrite: " + this.nativeWantsToWrite);
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"===========================================================");
}
@ -1066,12 +1121,10 @@ public class WolfSSLEngine extends SSLEngine {
}
}
else {
if (this.handshakeFinished == false) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"starting or continuing handshake");
ret = DoHandshake();
ret = DoHandshake(false);
}
else {
/* If we have input data, make sure output buffer length is
@ -1093,17 +1146,32 @@ public class WolfSSLEngine extends SSLEngine {
if (ret > 0) {
produced += ret;
}
else {
synchronized (netDataLock) {
if (ret == 0 && in.remaining() > 0 &&
getTotalOutputSize(out, ofst,
length) == 0) {
/* We have more data to read, but no more
* out space left in ByteBuffer[], ask for
* more */
status =
SSLEngineResult.Status.BUFFER_OVERFLOW;
}
/* Check for BUFFER_OVERFLOW status. This can happen
* if either we have data cached internally
* (in.remaining()) and we have no more output space,
* or if we have more decrypted plaintext in the native
* wolfSSL output buffer and ssl.pending() is > 0. */
synchronized (ioLock) {
if ((ret > 0) && (ssl.pending() > 0)) {
status =
SSLEngineResult.Status.BUFFER_OVERFLOW;
}
else if ((ret == 0) && (ssl.pending() > 0) &&
getTotalOutputSize(out, ofst, length) == 0) {
status =
SSLEngineResult.Status.BUFFER_OVERFLOW;
}
}
synchronized (netDataLock) {
if (ret == 0 && in.remaining() > 0 &&
getTotalOutputSize(out, ofst,
length) == 0) {
/* We have more data to read, but no more
* out space left in ByteBuffer[], ask for
* more */
status =
SSLEngineResult.Status.BUFFER_OVERFLOW;
}
}
}
@ -1125,7 +1193,7 @@ public class WolfSSLEngine extends SSLEngine {
}
}
}
}
} /* end DoHandshake() / RecvAppData() */
if (outBoundOpen == false || this.closeNotifySent) {
/* Mark SSLEngine status as CLOSED */
@ -1138,9 +1206,18 @@ public class WolfSSLEngine extends SSLEngine {
synchronized (ioLock) {
err = ssl.getError(ret);
}
if (ret < 0 &&
if (ret < 0 && (this.ssl.dtls() == 1) &&
(err == WolfSSL.OUT_OF_ORDER_E)) {
/* Received out of order DTLS message. Ignore and set our
* status to NEED_UNWRAP again to wait for correct data */
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"out of order message, dropping and putting state " +
"back to NEED_UNWRAP");
}
else if (ret < 0 &&
(err != WolfSSL.SSL_ERROR_WANT_READ) &&
(err != WolfSSL.SSL_ERROR_WANT_WRITE)) {
if (err == WolfSSL.UNKNOWN_ALPN_PROTOCOL_NAME_E) {
/* Native wolfSSL could not negotiate a common ALPN
* protocol */
@ -1167,11 +1244,17 @@ public class WolfSSLEngine extends SSLEngine {
synchronized (toSendLock) {
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 ||
(this.toSend != null && this.toSend.length == 0))) {
/* Need more data */
status = SSLEngineResult.Status.BUFFER_UNDERFLOW;
if ((this.ssl.dtls() == 0) ||
this.handshakeFinished) {
/* Need more data. For DTLS only set
* after handshake has completed, since
* apps expect to switch on NEED_UNWRAP
* HandshakeStatus at that point */
status = SSLEngineResult.Status.BUFFER_UNDERFLOW;
}
}
}
}
@ -1191,10 +1274,19 @@ public class WolfSSLEngine extends SSLEngine {
if (this.getUseClientMode() && this.handshakeFinished &&
this.ssl.hasSessionTicket() &&
this.sessionTicketReceived == false) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"received session ticket, returning " +
"HandshakeStatus FINISHED");
hs = SSLEngineResult.HandshakeStatus.FINISHED;
if (this.ssl.dtls() == 1 && this.toSend != null &&
this.toSend.length > 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. */
hs = SSLEngineResult.HandshakeStatus.NEED_WRAP;
}
else {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"received session ticket, returning " +
"HandshakeStatus FINISHED");
hs = SSLEngineResult.HandshakeStatus.FINISHED;
}
this.sessionTicketReceived = true;
}
}
@ -1245,6 +1337,12 @@ public class WolfSSLEngine extends SSLEngine {
"consumed: " + consumed);
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"produced: " + produced);
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"nativeHandshakeState: " + this.ssl.getStateStringLong());
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"nativeWantsToRead: " + this.nativeWantsToRead);
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"nativeWantsToWrite: " + this.nativeWantsToWrite);
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"===========================================================");
}
@ -1306,7 +1404,9 @@ public class WolfSSLEngine extends SSLEngine {
else {
synchronized (netDataLock) {
synchronized (ioLock) {
if (ssl.handshakeDone() && this.toSend == null) {
if (ssl.handshakeDone() && (this.toSend == null) &&
(this.nativeWantsToWrite == 0) &&
(this.nativeWantsToRead == 0)) {
this.handshakeFinished = true;
hs = SSLEngineResult.HandshakeStatus.FINISHED;
this.engineHelper.getSession().updateStoredSessionValues();
@ -1336,6 +1436,9 @@ public class WolfSSLEngine extends SSLEngine {
else if (err == WolfSSL.SSL_ERROR_WANT_WRITE) {
hs = SSLEngineResult.HandshakeStatus.NEED_WRAP;
}
else if (err == WolfSSL.OUT_OF_ORDER_E) {
hs = SSLEngineResult.HandshakeStatus.NEED_UNWRAP;
}
else {
hs = SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING;
}
@ -1489,7 +1592,13 @@ public class WolfSSLEngine extends SSLEngine {
public synchronized SSLSession getHandshakeSession() {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"entered getHandshakeSession()");
return this.engineHelper.getSession();
if (!this.handshakeFinished) {
/* Only return handshake session during the handshake */
return this.engineHelper.getSession();
}
return null;
}
/**
@ -1526,18 +1635,20 @@ public class WolfSSLEngine extends SSLEngine {
"setUseClientMode() has not been called on this SSLEngine");
}
if (this.handshakeStartedExplicitly) {
/* Renegotiation (thus calling beginHandshake() multiple times)
* is not supported in wolfJSSE SSLEngine implementation yet. If
* already called once by user, throw SSLException. */
throw new SSLException("Renegotiation not supported");
}
else if (!this.needInit && !this.handshakeFinished) {
/* Handshake has started implicitly by wrap() or unwrap(). Simply
* return since this is the first time that the user has called
* beginHandshake() themselves. */
this.handshakeStartedExplicitly = true;
return;
synchronized (initLock) {
if (this.handshakeStartedExplicitly) {
/* Renegotiation (thus calling beginHandshake() multiple times)
* is not supported in wolfJSSE SSLEngine implementation yet. If
* already called once by user, throw SSLException. */
throw new SSLException("Renegotiation not supported");
}
else if (!this.needInit && !this.handshakeFinished) {
/* Handshake has started implicitly by wrap() or unwrap(). Simply
* return since this is the first time that the user has called
* beginHandshake() themselves. */
this.handshakeStartedExplicitly = true;
return;
}
}
/* No network data source yet */
@ -1556,11 +1667,9 @@ public class WolfSSLEngine extends SSLEngine {
throw new SSLException(e);
}
if (needInit == true) {
/* will throw SSLHandshakeException if session creation is
not allowed */
checkAndInitSSLEngine();
}
/* will throw SSLHandshakeException if session creation is
not allowed */
checkAndInitSSLEngine();
try {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
@ -1865,6 +1974,30 @@ public class WolfSSLEngine extends SSLEngine {
byte[] prevToSend = null;
synchronized (toSendLock) {
/* As per JSSE Reference Guide, Section 8 DTLS implementation
* of wrap() contains at most one record so every DTLS record
* can be marshaled and delivered to datagram individually. As
* such, if we have data wait to send before caching more */
/* TODO - do we need to fragment data here if larger than
* SSLParameters.getMaximumPacketSize() with DTLS? */
if (this.ssl.dtls() == 1) {
if (this.toSend != null) {
/* 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
* status */
if (sz > 0) {
this.nativeWantsToWrite = sz;
}
return -2;
}
/* Reset native wants to send data flag. We have cleared
* cached data in the object, so this call of the send CB
* should be with the desired native data now. */
this.nativeWantsToWrite = 0;
}
/* Make copy of existing toSend array before expanding */
if (this.toSend != null) {
prevToSend = this.toSend.clone();
@ -1927,9 +2060,15 @@ public class WolfSSLEngine extends SSLEngine {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"CB Read: returning WOLFSSL_CBIO_ERR_WANT_READ");
}
if (this.ssl.dtls() == 1 && this.handshakeFinished) {
this.nativeWantsToRead = 1;
}
return WolfSSL.WOLFSSL_CBIO_ERR_WANT_READ;
}
/* Reset native wants to read flag */
this.nativeWantsToRead = 0;
max = (sz < this.netData.remaining()) ? sz : this.netData.remaining();
this.netData.get(toRead, 0, max);

View File

@ -495,7 +495,8 @@ public class WolfSSLEngineHelper {
for (int i = 0; i < suites.length; i++) {
if (!supported.contains(suites[i])) {
throw new IllegalArgumentException("Unsupported CipherSuite: " +
suites[i]);
suites[i] + "(Supported: " +
Arrays.toString(getAllCiphers()) + ")");
}
}
@ -532,7 +533,8 @@ public class WolfSSLEngineHelper {
}
}
this.params.setProtocols(WolfSSLUtil.sanitizeProtocols(p));
this.params.setProtocols(
WolfSSLUtil.sanitizeProtocols(p, WolfSSL.TLS_VERSION.INVALID));
}
/**
@ -541,7 +543,8 @@ public class WolfSSLEngineHelper {
* @return String array of enabled SSL/TLS protocols
*/
protected synchronized String[] getProtocols() {
return WolfSSLUtil.sanitizeProtocols(this.params.getProtocols());
return WolfSSLUtil.sanitizeProtocols(
this.params.getProtocols(), WolfSSL.TLS_VERSION.INVALID);
}
/**
@ -552,7 +555,8 @@ public class WolfSSLEngineHelper {
* @return String array of supported protocols
*/
protected static synchronized String[] getAllProtocols() {
return WolfSSLUtil.sanitizeProtocols(WolfSSL.getProtocols());
return WolfSSLUtil.sanitizeProtocols(
WolfSSL.getProtocols(), WolfSSL.TLS_VERSION.INVALID);
}
/**
@ -751,10 +755,12 @@ public class WolfSSLEngineHelper {
}
for (i = 0; i < p.length; i++) {
if (p[i].equals("TLSv1.3")) {
/* TLS 1.3 needs to be enabled for DTLS 1.3 */
if (p[i].equals("TLSv1.3") || p[i].equals("DTLSv1.3")) {
set[0] = true;
}
if (p[i].equals("TLSv1.2")) {
/* TLS 1.2 needs to be enabled for DTLS 1.2 */
if (p[i].equals("TLSv1.2") || p[i].equals("DTLSv1.2")) {
set[1] = true;
}
if (p[i].equals("TLSv1.1")) {
@ -768,6 +774,7 @@ public class WolfSSLEngineHelper {
}
}
/* Note: No SSL_OP_NO_* for DTLS in native wolfSSL */
if (set[0] == false) {
mask |= WolfSSL.SSL_OP_NO_TLSv1_3;
}
@ -1140,13 +1147,43 @@ public class WolfSSLEngineHelper {
}
}
private void setLocalMaximumPacketSize() {
/* Set maximum packet size, currently only makes a differnce if
* DTLS is enabled and used. Calling application will set this via
* SSLParameters.setMaximumPacketSize(). */
int ret;
int maxPacketSize = this.params.getMaximumPacketSize();
if (maxPacketSize != 0) {
/* Zero size means use implicit sizing logic of implementation,
* take no special action here if 0. */
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"Maximum packet size found in SSLParameters: " + maxPacketSize);
ret = this.ssl.dtlsSetMTU(maxPacketSize);
if (ret == WolfSSL.SSL_SUCCESS) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"set maximum packet size (DTLS MTU): " + maxPacketSize);
}
else if (ret == WolfSSL.NOT_COMPILED_IN) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"DTLS or MTU not compiled in, skipping setting " +
"max packet size");
}
else {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"error setting DTLS MTU, ret = " + ret);
}
}
}
private void setLocalParams(SSLSocket socket, SSLEngine engine)
throws SSLException {
this.setLocalCiphers(
WolfSSLUtil.sanitizeSuites(this.params.getCipherSuites()));
this.setLocalProtocol(
WolfSSLUtil.sanitizeProtocols(this.params.getProtocols()));
WolfSSLUtil.sanitizeProtocols(
this.params.getProtocols(), WolfSSL.TLS_VERSION.INVALID));
this.setLocalAuth(socket, engine);
this.setLocalServerNames();
this.setLocalSessionTicket();
@ -1154,6 +1191,7 @@ public class WolfSSLEngineHelper {
this.setLocalSecureRenegotiation();
this.setLocalSigAlgorithms();
this.setLocalSupportedCurves();
this.setLocalMaximumPacketSize();
}
/**

View File

@ -49,6 +49,8 @@ final class WolfSSLParameters {
String[] applicationProtocols = new String[0];
private boolean useSessionTickets = false;
private byte[] alpnProtocols = null;
/* Default to 0, means use implicit implementation size */
private int maxPacketSize = 0;
/* create duplicate copy of these parameters */
protected synchronized WolfSSLParameters copy() {
@ -62,6 +64,7 @@ final class WolfSSLParameters {
cp.endpointIdAlgorithm = this.endpointIdAlgorithm;
cp.setApplicationProtocols(this.applicationProtocols);
cp.useCipherSuiteOrder = this.useCipherSuiteOrder;
cp.maxPacketSize = this.maxPacketSize;
if (alpnProtocols != null && alpnProtocols.length != 0) {
cp.setAlpnProtocols(this.alpnProtocols);
@ -213,5 +216,13 @@ final class WolfSSLParameters {
this.applicationProtocols = protocols.clone();
}
}
int getMaximumPacketSize() {
return this.maxPacketSize;
}
void setMaximumPacketSize(int maximumPacketSize) {
this.maxPacketSize = maximumPacketSize;
}
}

View File

@ -21,6 +21,7 @@
package com.wolfssl.provider.jsse;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.security.AccessController;
import java.security.PrivilegedAction;
import javax.net.ssl.SSLParameters;
@ -37,6 +38,8 @@ public class WolfSSLParametersHelper
private static Method setApplicationProtocols = null;
private static Method getEndpointIdentificationAlgorithm = null;
private static Method setEndpointIdentificationAlgorithm = null;
private static Method getMaximumPacketSize = null;
private static Method setMaximumPacketSize = null;
/** Default WolfSSLParametersHelper constructor */
public WolfSSLParametersHelper() { }
@ -73,6 +76,12 @@ public class WolfSSLParametersHelper
case "setEndpointIdentificationAlgorithm":
setEndpointIdentificationAlgorithm = m;
continue;
case "getMaximumPacketSize":
getMaximumPacketSize = m;
continue;
case "setMaximumPacketSize":
setMaximumPacketSize = m;
continue;
default:
continue;
}
@ -112,15 +121,17 @@ public class WolfSSLParametersHelper
ret.setWantClientAuth(in.getWantClientAuth());
}
/* Methods added as of JDK 1.8, older JDKs will not have them. Using
* Java reflection to detect availability. */
/* Methods added as of JDK 1.8 that rely on specific classes that
* do not existing in older JDKs. Since older JDKs will not have them,
* use Java reflection to detect availability in helper class. */
if (setServerNames != null || setApplicationProtocols != null ||
setEndpointIdentificationAlgorithm != null) {
try {
/* load WolfSSLJDK8Helper at runtime, not compiled on older JDKs */
Class<?> cls = Class.forName("com.wolfssl.provider.jsse.WolfSSLJDK8Helper");
/* load WolfSSLJDK8Helper at runtime, not compiled
* on older JDKs */
Class<?> cls = Class.forName(
"com.wolfssl.provider.jsse.WolfSSLJDK8Helper");
Object obj = cls.getConstructor().newInstance();
Class<?>[] paramList = new Class<?>[3];
paramList[0] = javax.net.ssl.SSLParameters.class;
@ -133,12 +144,15 @@ public class WolfSSLParametersHelper
mth.invoke(obj, ret, setServerNames, in);
}
if (setApplicationProtocols != null) {
mth = cls.getDeclaredMethod("setApplicationProtocols", paramList);
mth = cls.getDeclaredMethod(
"setApplicationProtocols", paramList);
mth.invoke(obj, ret, setApplicationProtocols, in);
}
if (setEndpointIdentificationAlgorithm != null) {
mth = cls.getDeclaredMethod("setEndpointIdentificationAlgorithm", paramList);
mth.invoke(obj, ret, setEndpointIdentificationAlgorithm, in);
mth = cls.getDeclaredMethod(
"setEndpointIdentificationAlgorithm", paramList);
mth.invoke(obj, ret,
setEndpointIdentificationAlgorithm, in);
}
} catch (Exception e) {
@ -146,6 +160,18 @@ public class WolfSSLParametersHelper
}
}
/* Methods added in later versions of SSLParameters which do not
* use any additional classes. Since no unique class names, these
* are called here directly instead of placed into a separate helper
* class. */
try {
if (setMaximumPacketSize != null) {
setMaximumPacketSize.invoke(ret, in.getMaximumPacketSize());
}
} catch (IllegalAccessException | InvocationTargetException e) {
/* Not available, just ignore and continue */
}
/* The following SSLParameters features are not yet supported
* by wolfJSSE (see Android API 23 note above). They are supported
* with newer versions of SSLParameters, but will need to be added
@ -191,14 +217,15 @@ public class WolfSSLParametersHelper
out.setWantClientAuth(in.getWantClientAuth());
}
/* Methods added as of JDK 1.8, older JDKs will not have them. Using
* Java reflection to detect availability. */
/* Methods added as of JDK 1.8 that rely on specific classes that
* do not existing in older JDKs. Since older JDKs will not have them,
* use Java reflection to detect availability in helper class. */
if (getServerNames != null || getApplicationProtocols != null ||
getEndpointIdentificationAlgorithm != null) {
try {
/* load WolfSSLJDK8Helper at runtime, not compiled on older JDKs */
Class<?> cls = Class.forName("com.wolfssl.provider.jsse.WolfSSLJDK8Helper");
Class<?> cls = Class.forName(
"com.wolfssl.provider.jsse.WolfSSLJDK8Helper");
Object obj = cls.getConstructor().newInstance();
Class<?>[] paramList = new Class<?>[2];
paramList[0] = javax.net.ssl.SSLParameters.class;
@ -210,11 +237,13 @@ public class WolfSSLParametersHelper
mth.invoke(obj, in, out);
}
if (getApplicationProtocols != null) {
mth = cls.getDeclaredMethod("getApplicationProtocols", paramList);
mth = cls.getDeclaredMethod(
"getApplicationProtocols", paramList);
mth.invoke(obj, in, out);
}
if (getEndpointIdentificationAlgorithm != null) {
mth = cls.getDeclaredMethod("getEndpointIdentificationAlgorithm", paramList);
mth = cls.getDeclaredMethod(
"getEndpointIdentificationAlgorithm", paramList);
mth.invoke(obj, in, out);
}
@ -223,6 +252,19 @@ public class WolfSSLParametersHelper
}
}
/* Methods added in later versions of SSLParameters which do not
* use any additional classes. Since no unique class names, these
* are called here directly instead of placed into a separate helper
* class. */
try {
if (getMaximumPacketSize != null) {
int maxPacketSz = (int)getMaximumPacketSize.invoke(in);
out.setMaximumPacketSize(maxPacketSz);
}
} catch (IllegalAccessException | InvocationTargetException e) {
/* Not available, just ignore and continue */
}
/* The following SSLParameters features are not yet supported
* by wolfJSSE (see Android API 23 note above). They are supported
* with newer versions of SSLParameters, but will need to be added

View File

@ -134,6 +134,10 @@ public final class WolfSSLProvider extends Provider {
put("SSLContext.TLSv1.3",
"com.wolfssl.provider.jsse.WolfSSLContext$TLSV13_Context");
}
if (WolfSSL.DTLSv13Enabled()) {
put("SSLContext.DTLSv1.3",
"com.wolfssl.provider.jsse.WolfSSLContext$DTLSV13_Context");
}
put("SSLContext.SSL",
"com.wolfssl.provider.jsse.WolfSSLContext$TLSV23_Context");
put("SSLContext.TLS",

View File

@ -211,7 +211,8 @@ public class WolfSSLServerSocket extends SSLServerSocket {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"entered getSupportedProtocols()");
return WolfSSLUtil.sanitizeProtocols(params.getProtocols());
return WolfSSLUtil.sanitizeProtocols(
params.getProtocols(), WolfSSL.TLS_VERSION.INVALID);
}
@Override
@ -220,7 +221,8 @@ public class WolfSSLServerSocket extends SSLServerSocket {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"entered getEnabledProtocols()");
return WolfSSLUtil.sanitizeProtocols(params.getProtocols());
return WolfSSLUtil.sanitizeProtocols(
params.getProtocols(), WolfSSL.TLS_VERSION.INVALID);
}
@Override
@ -242,7 +244,8 @@ public class WolfSSLServerSocket extends SSLServerSocket {
List<String> supported;
supported = Arrays.asList(
WolfSSLUtil.sanitizeProtocols(WolfSSL.getProtocols()));
WolfSSLUtil.sanitizeProtocols(
WolfSSL.getProtocols(), WolfSSL.TLS_VERSION.INVALID));
for (int i = 0; i < protocols.length; i++) {
if (!supported.contains(protocols[i])) {

View File

@ -33,6 +33,7 @@ import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import com.wolfssl.WolfSSL;
import com.wolfssl.WolfSSLDebug;
import com.wolfssl.WolfSSLException;
@ -50,7 +51,8 @@ public class WolfSSLUtil {
}
/**
* Sanitize or filter protocol list based on system property limitations.
* Sanitize or filter protocol list based on system property limitations
* and current TLS/DTLS protocol being established.
*
* Supported system properties which limit protocol list are:
* - java.security.Security:
@ -61,17 +63,18 @@ public class WolfSSLUtil {
*
* jdk.tls.disabledAlgorithms="TLSv1, TLSv1.1"
*
* This method force-removes DTLSv1.2 and DTLSv1.3 if the input
* protocols list advertises support for it. This is because native
* wolfSSL JNI supports DTLS but the JSSE layer does not yet. When
* DTLS support is added to wolfJSSE, this restriction can/will be removed.
*
* @param protocols Full list of protocols to sanitize/filter, should be
* in a format similar to: "TLSv1", "TLSv1.1", etc.
* @param currentVersion current protocol being used by the object
* that is calling this method. If WolfSSL.INVALID
* is passed in, no filtering is done on protocol
* list based on currentVersion.
*
* @return New filtered String array of protocol strings
*/
protected static String[] sanitizeProtocols(String[] protocols) {
protected static String[] sanitizeProtocols(String[] protocols,
WolfSSL.TLS_VERSION currentVersion) {
ArrayList<String> filtered = new ArrayList<String>();
String disabledAlgos =
@ -83,14 +86,17 @@ public class WolfSSLUtil {
WolfSSLDebug.log(WolfSSLUtil.class, WolfSSLDebug.INFO,
"jdk.tls.disabledAlgorithms: " + disabledAlgos);
/* Force remove DTLS from supported JSSE protocols. Currently only
* JNI layer supports DTLS, not JSSE. When JSSE layer gets DTLS
* support added, take this restriction out. */
if (disabledAlgos == null) {
disabledAlgos = "DTLSv1.2, DTLSv1.3";
}
else {
disabledAlgos += ",DTLSv1.2,DTLSv1.3";
/* If WolfSSL.INVALID is passed in as currentVersion, no filtering
* is done based on current protocol */
if (currentVersion != WolfSSL.TLS_VERSION.INVALID) {
/* Remove DTLS protocols if using TLS explicitly. Needed
* since native wolfSSL doesn't have protocol masks for DTLS. */
if (currentVersion != WolfSSL.TLS_VERSION.DTLSv1_2) {
disabledAlgos += ",DTLSv1.2";
}
if (currentVersion != WolfSSL.TLS_VERSION.DTLSv1_3) {
disabledAlgos += ",DTLSv1.3";
}
}
/* Remove spaces after commas, split into List */

View File

@ -1212,6 +1212,7 @@ public class WolfSSLEngineTest {
ByteBuffer netData = null;
ByteBuffer peerAppData = null;
ByteBuffer peerNetData = null;
boolean readAgain = false;
SocketChannel sock = null;
@ -1350,7 +1351,7 @@ public class WolfSSLEngineTest {
}
}
/* read response */
/* read response (might get TLS 1.3 session ticket instead) */
peerNetData.clear();
int recvd = sock.read(peerNetData);
if (recvd > 0) {
@ -1370,14 +1371,55 @@ public class WolfSSLEngineTest {
throw new Exception(
"BUFFER_OVERFLOW during engine.unwrp()");
case BUFFER_UNDERFLOW:
throw new Exception(
"BUFFER_UNDERFLOW during engine.unwrap()");
/* With TLS 1.3, we may get a session ticket
* message post handshake, resulting in BUFFER_UNDERFLOW
* status since we read the ticket but didn't get the
* chance to read the response waiting from the peer. */
sess = engine.getSession();
if (sess.getProtocol().equals("TLSv1.3")) {
readAgain = true;
break;
}
else {
throw new Exception(
"BUFFER_UNDERFLOW during engine.unwrap()");
}
default:
throw new Exception(
"Unknown HandshakeStatus");
}
}
if (readAgain) {
/* read response */
peerNetData.clear();
recvd = sock.read(peerNetData);
if (recvd > 0) {
peerNetData.flip();
result = engine.unwrap(peerNetData, peerAppData);
peerNetData.compact();
switch (result.getStatus()) {
case OK:
peerAppData.flip();
/* not doing anything with returned data */
break;
case CLOSED:
engine.closeOutbound();
engine.closeInbound();
break;
case BUFFER_OVERFLOW:
throw new Exception(
"BUFFER_OVERFLOW during engine.unwrp()");
case BUFFER_UNDERFLOW:
throw new Exception(
"BUFFER_UNDERFLOW during engine.unwrap()");
default:
throw new Exception(
"Unknown HandshakeStatus");
}
}
}
/* shutdown */
engine.closeOutbound();
while (engine.isOutboundDone() == false) {