diff --git a/README.md b/README.md
index 9facb71..d79076c 100644
--- a/README.md
+++ b/README.md
@@ -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
diff --git a/native/com_wolfssl_WolfSSL.c b/native/com_wolfssl_WolfSSL.c
index d5a4b5b..4de663d 100644
--- a/native/com_wolfssl_WolfSSL.c
+++ b/native/com_wolfssl_WolfSSL.c
@@ -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
diff --git a/native/com_wolfssl_WolfSSL.h b/native/com_wolfssl_WolfSSL.h
index 2c5ce87..a052493 100644
--- a/native/com_wolfssl_WolfSSL.h
+++ b/native/com_wolfssl_WolfSSL.h
@@ -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
diff --git a/native/com_wolfssl_WolfSSLSession.c b/native/com_wolfssl_WolfSSLSession.c
index 3e88820..fac9ea7 100644
--- a/native/com_wolfssl_WolfSSLSession.c
+++ b/native/com_wolfssl_WolfSSLSession.c
@@ -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");
}
}
diff --git a/native/com_wolfssl_WolfSSLSession.h b/native/com_wolfssl_WolfSSLSession.h
index 260032c..7c7e8eb 100644
--- a/native/com_wolfssl_WolfSSLSession.h
+++ b/native/com_wolfssl_WolfSSLSession.h
@@ -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
diff --git a/src/java/com/wolfssl/WolfSSL.java b/src/java/com/wolfssl/WolfSSL.java
index 28b1e05..7f76971 100644
--- a/src/java/com/wolfssl/WolfSSL.java
+++ b/src/java/com/wolfssl/WolfSSL.java
@@ -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.
*
diff --git a/src/java/com/wolfssl/WolfSSLSession.java b/src/java/com/wolfssl/WolfSSLSession.java
index d5a996f..22f1ed0 100644
--- a/src/java/com/wolfssl/WolfSSLSession.java
+++ b/src/java/com/wolfssl/WolfSSLSession.java
@@ -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 {
* read() again. Use getError to
* get a specific error code.
* BAD_FUNC_ARC 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. NOT_COMPILED_IN 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 SSL_SUCCESS upon success.
+ * SSL_FATAL_ERROR if there have been too many
+ * retransmissions/timeouts without getting a response from
+ * the peer. NOT_COMPILED_IN 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 1 if the SSL has been configured to use DTLS,
* otherwise, 0.
* @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 SSL_SUCCESS on success,
+ * SSL_FAILURE on error, or
+ * NOT_COMPILED_IN 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);
+ }
}
}
diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLContext.java b/src/java/com/wolfssl/provider/jsse/WolfSSLContext.java
index eb4666f..6e7e959 100644
--- a/src/java/com/wolfssl/provider/jsse/WolfSSLContext.java
+++ b/src/java/com/wolfssl/provider/jsse/WolfSSLContext.java
@@ -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.
diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLEngine.java b/src/java/com/wolfssl/provider/jsse/WolfSSLEngine.java
index b269940..f233040 100644
--- a/src/java/com/wolfssl/provider/jsse/WolfSSLEngine.java
+++ b/src/java/com/wolfssl/provider/jsse/WolfSSLEngine.java
@@ -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);
diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLEngineHelper.java b/src/java/com/wolfssl/provider/jsse/WolfSSLEngineHelper.java
index 099cb75..d6fab69 100644
--- a/src/java/com/wolfssl/provider/jsse/WolfSSLEngineHelper.java
+++ b/src/java/com/wolfssl/provider/jsse/WolfSSLEngineHelper.java
@@ -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();
}
/**
diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLParameters.java b/src/java/com/wolfssl/provider/jsse/WolfSSLParameters.java
index b7e79a3..8adc437 100644
--- a/src/java/com/wolfssl/provider/jsse/WolfSSLParameters.java
+++ b/src/java/com/wolfssl/provider/jsse/WolfSSLParameters.java
@@ -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;
+ }
}
diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLParametersHelper.java b/src/java/com/wolfssl/provider/jsse/WolfSSLParametersHelper.java
index 33be226..a761268 100644
--- a/src/java/com/wolfssl/provider/jsse/WolfSSLParametersHelper.java
+++ b/src/java/com/wolfssl/provider/jsse/WolfSSLParametersHelper.java
@@ -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
diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLProvider.java b/src/java/com/wolfssl/provider/jsse/WolfSSLProvider.java
index 76fff4b..a6aa1c3 100644
--- a/src/java/com/wolfssl/provider/jsse/WolfSSLProvider.java
+++ b/src/java/com/wolfssl/provider/jsse/WolfSSLProvider.java
@@ -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",
diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLServerSocket.java b/src/java/com/wolfssl/provider/jsse/WolfSSLServerSocket.java
index fc9fe2c..49d6e25 100644
--- a/src/java/com/wolfssl/provider/jsse/WolfSSLServerSocket.java
+++ b/src/java/com/wolfssl/provider/jsse/WolfSSLServerSocket.java
@@ -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 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])) {
diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLUtil.java b/src/java/com/wolfssl/provider/jsse/WolfSSLUtil.java
index c57de09..c2c9805 100644
--- a/src/java/com/wolfssl/provider/jsse/WolfSSLUtil.java
+++ b/src/java/com/wolfssl/provider/jsse/WolfSSLUtil.java
@@ -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 filtered = new ArrayList();
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 */
diff --git a/src/test/com/wolfssl/provider/jsse/test/WolfSSLEngineTest.java b/src/test/com/wolfssl/provider/jsse/test/WolfSSLEngineTest.java
index 2f503bb..bdd7591 100644
--- a/src/test/com/wolfssl/provider/jsse/test/WolfSSLEngineTest.java
+++ b/src/test/com/wolfssl/provider/jsse/test/WolfSSLEngineTest.java
@@ -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) {