diff --git a/README.md b/README.md
index 9facb71a..b178bf13 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
@@ -531,6 +534,11 @@ are enabled in different ways depending on the JDK implementation. For
Oracle/OpenJDK and variants, this System property enables session tickets and
was added in Java 13. Should be set to "true" to enable.
+**jdk.tls.useExtendedMasterSecret (boolean)** - Can be used to enable or
+disable the use of the Extended Master Secret (EMS) extension. This extension
+is enabled by default, unless explicitly disabled by setting this property to
+false.
+
**wolfjsse.autoSNI (boolean)** - Controls automatic Server Name Indication (SNI)
extension setting based on hostname or peer address. When set to "true", enables
legacy behavior where SNI is automatically configured from hostname/peer information
diff --git a/examples/Client.java b/examples/Client.java
index e2f32ed8..a03ea934 100644
--- a/examples/Client.java
+++ b/examples/Client.java
@@ -222,10 +222,15 @@ public void run(String[] args) {
/* sort out DTLS versus TLS versions */
if (doDTLS == 1) {
- if (sslVersion == 3)
+ if (sslVersion == 4) {
+ sslVersion = -3;
+ }
+ else if (sslVersion == 3) {
sslVersion = -2;
- else
+ }
+ else {
sslVersion = -1;
+ }
}
/* init library */
@@ -260,6 +265,9 @@ public void run(String[] args) {
case -2:
method = WolfSSL.DTLSv1_2_ClientMethod();
break;
+ case -3:
+ method = WolfSSL.DTLSv1_3_ClientMethod();
+ break;
default:
System.err.println("Bad SSL version");
System.exit(1);
@@ -786,7 +794,7 @@ void printUsage() {
System.out.println("-d\t\tDisable peer checks");
if (WolfSSL.isEnabledDTLS() == 1)
System.out.println("-u\t\tUse UDP DTLS, add -v 2 for DTLSv1 " +
- "(default), -v 3 for DTLSv1.2");
+ "(default), -v 3 for DTLSv1.2, -v 4 for DTLSv1.3");
System.out.println("-iocb\t\tEnable test I/O callbacks");
System.out.println("-logtest\tEnable test logging callback");
if (WolfSSL.isEnabledOCSP() == 1) {
diff --git a/examples/Server.java b/examples/Server.java
index cfe36b2e..43e02e68 100644
--- a/examples/Server.java
+++ b/examples/Server.java
@@ -209,10 +209,15 @@ public void run(String[] args) {
/* sort out DTLS versus TLS versions */
if (doDTLS == 1) {
- if (sslVersion == 3)
+ if (sslVersion == 4) {
+ sslVersion = -3;
+ }
+ else if (sslVersion == 3) {
sslVersion = -2;
- else
+ }
+ else {
sslVersion = -1;
+ }
}
/* init library */
@@ -247,6 +252,9 @@ public void run(String[] args) {
case -2:
method = WolfSSL.DTLSv1_2_ServerMethod();
break;
+ case -3:
+ method = WolfSSL.DTLSv1_3_ServerMethod();
+ break;
default:
System.err.println("Bad SSL version");
System.exit(1);
@@ -683,7 +691,7 @@ void printUsage() {
System.out.println("-s\t\tUse pre shared keys");
if (WolfSSL.isEnabledDTLS() == 1)
System.out.println("-u\t\tUse UDP DTLS, add -v 2 for DTLSv1 (default)" +
- ", -v 3 for DTLSv1.2");
+ ", -v 3 for DTLSv1.2, -v 4 for DTLSv1.3");
System.out.println("-iocb\t\tEnable test I/O callbacks");
System.out.println("-logtest\tEnable test logging callback");
if (WolfSSL.isEnabledOCSP() == 1) {
diff --git a/native/com_wolfssl_WolfSSL.c b/native/com_wolfssl_WolfSSL.c
index c0ac139c..f8a279f4 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)
{
@@ -747,7 +760,7 @@ JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSL_SSLv3_1ServerMethod
#if defined(WOLFSSL_ALLOW_SSLV3) && !defined(NO_OLD_TLS)
return (jlong)(uintptr_t)wolfSSLv3_server_method();
#else
- return NOT_COMPILED_IN;
+ return 0;
#endif
}
@@ -760,7 +773,7 @@ JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSL_SSLv3_1ClientMethod
#if defined(WOLFSSL_ALLOW_SSLV3) && !defined(NO_OLD_TLS)
return (jlong)(uintptr_t)wolfSSLv3_client_method();
#else
- return NOT_COMPILED_IN;
+ return 0;
#endif
}
@@ -773,7 +786,7 @@ JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSL_TLSv1_1Method
#if !defined(NO_OLD_TLS) && defined(WOLFSSL_ALLOW_TLSV10)
return (jlong)(uintptr_t)wolfTLSv1_method();
#else
- return NOT_COMPILED_IN;
+ return 0;
#endif
}
@@ -786,7 +799,7 @@ JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSL_TLSv1_1ServerMethod
#if !defined(NO_OLD_TLS) && defined(WOLFSSL_ALLOW_TLSV10)
return (jlong)(uintptr_t)wolfTLSv1_server_method();
#else
- return NOT_COMPILED_IN;
+ return 0;
#endif
}
@@ -799,7 +812,7 @@ JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSL_TLSv1_1ClientMethod
#if !defined(NO_OLD_TLS) && defined(WOLFSSL_ALLOW_TLSV10)
return (jlong)(uintptr_t)wolfTLSv1_client_method();
#else
- return NOT_COMPILED_IN;
+ return 0;
#endif
}
@@ -812,7 +825,7 @@ JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSL_TLSv1_11_1Method
#ifndef NO_OLD_TLS
return (jlong)(uintptr_t)wolfTLSv1_1_method();
#else
- return NOT_COMPILED_IN;
+ return 0;
#endif
}
@@ -825,7 +838,7 @@ JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSL_TLSv1_11_1ServerMethod
#ifndef NO_OLD_TLS
return (jlong)(uintptr_t)wolfTLSv1_1_server_method();
#else
- return NOT_COMPILED_IN;
+ return 0;
#endif
}
@@ -838,7 +851,7 @@ JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSL_TLSv1_11_1ClientMethod
#ifndef NO_OLD_TLS
return (jlong)(uintptr_t)wolfTLSv1_1_client_method();
#else
- return NOT_COMPILED_IN;
+ return 0;
#endif
}
@@ -878,7 +891,7 @@ JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSL_TLSv1_13_1Method
#ifdef WOLFSSL_TLS13
return (jlong)(uintptr_t)wolfTLSv1_3_method();
#else
- return NOT_COMPILED_IN;
+ return 0;
#endif
}
@@ -891,7 +904,7 @@ JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSL_TLSv1_13_1ServerMethod
#ifdef WOLFSSL_TLS13
return (jlong)(uintptr_t)wolfTLSv1_3_server_method();
#else
- return NOT_COMPILED_IN;
+ return 0;
#endif
}
@@ -904,7 +917,7 @@ JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSL_TLSv1_13_1ClientMethod
#ifdef WOLFSSL_TLS13
return (jlong)(uintptr_t)wolfTLSv1_3_client_method();
#else
- return NOT_COMPILED_IN;
+ return 0;
#endif
}
@@ -917,7 +930,7 @@ JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSL_DTLSv1_1Method
#if defined(WOLFSSL_DTLS) && !defined(NO_OLD_TLS)
return (jlong)(uintptr_t)wolfDTLSv1_method();
#else
- return NOT_COMPILED_IN;
+ return 0;
#endif
}
@@ -930,7 +943,7 @@ JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSL_DTLSv1_1ClientMethod
#if defined(WOLFSSL_DTLS) && !defined(NO_OLD_TLS)
return (jlong)(uintptr_t)wolfDTLSv1_client_method();
#else
- return NOT_COMPILED_IN;
+ return 0;
#endif
}
@@ -943,7 +956,7 @@ JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSL_DTLSv1_1ServerMethod
#if defined(WOLFSSL_DTLS) && !defined(NO_OLD_TLS)
return (jlong)(uintptr_t)wolfDTLSv1_server_method();
#else
- return NOT_COMPILED_IN;
+ return 0;
#endif
}
@@ -956,7 +969,7 @@ JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSL_DTLSv1_12_1Method
#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12)
return (jlong)(uintptr_t)wolfDTLSv1_2_method();
#else
- return NOT_COMPILED_IN;
+ return 0;
#endif
}
@@ -969,7 +982,7 @@ JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSL_DTLSv1_12_1ClientMethod
#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12)
return (jlong)(uintptr_t)wolfDTLSv1_2_client_method();
#else
- return NOT_COMPILED_IN;
+ return 0;
#endif
}
@@ -982,7 +995,46 @@ JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSL_DTLSv1_12_1ServerMethod
#if defined(WOLFSSL_DTLS) && !defined(WOLFSSL_NO_TLS12)
return (jlong)(uintptr_t)wolfDTLSv1_2_server_method();
#else
- return NOT_COMPILED_IN;
+ return 0;
+#endif
+}
+
+JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSL_DTLSv1_13_1Method
+ (JNIEnv* jenv, jclass jcl)
+{
+ (void)jenv;
+ (void)jcl;
+
+#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_DTLS13)
+ return (jlong)(uintptr_t)wolfDTLSv1_3_method();
+#else
+ return 0;
+#endif
+}
+
+JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSL_DTLSv1_13_1ServerMethod
+ (JNIEnv* jenv, jclass jcl)
+{
+ (void)jenv;
+ (void)jcl;
+
+#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_DTLS13)
+ return (jlong)(uintptr_t)wolfDTLSv1_3_server_method();
+#else
+ return 0;
+#endif
+}
+
+JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSL_DTLSv1_13_1ClientMethod
+ (JNIEnv* jenv, jclass jcl)
+{
+ (void)jenv;
+ (void)jcl;
+
+#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_DTLS13)
+ return (jlong)(uintptr_t)wolfDTLSv1_3_client_method();
+#else
+ return 0;
#endif
}
@@ -1110,11 +1162,18 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSL_setLoggingCb
return ret;
}
+/**
+ * Native wolfSSL logging callback.
+ *
+ * We skip throwing exceptions in this function and just move on without
+ * printing the log. Otherwise, our non-important exception here could cause
+ * bad things to happen at the Java level - ie, causing the
+ * certificate verify callback to fail unnecessarily.
+ */
void NativeLoggingCallback(const int logLevel, const char *const logMessage)
{
JNIEnv* jenv = NULL;
jint vmret = 0;
- jclass excClass;
jclass logClass;
jmethodID logMethod;
jstring logMsg;
@@ -1145,17 +1204,6 @@ void NativeLoggingCallback(const int logLevel, const char *const logMessage)
return;
}
- /* find exception class */
- excClass = (*jenv)->FindClass(jenv, "java/lang/Exception");
- if ((*jenv)->ExceptionOccurred(jenv)) {
- (*jenv)->ExceptionDescribe(jenv);
- (*jenv)->ExceptionClear(jenv);
- if (needsDetach == 1) {
- (*g_vm)->DetachCurrentThread(g_vm);
- }
- return;
- }
-
/* check if our stored object reference is valid */
refcheck = (*jenv)->GetObjectRefType(jenv, g_loggingCbIfaceObj);
if (refcheck == 2) {
@@ -1168,9 +1216,6 @@ void NativeLoggingCallback(const int logLevel, const char *const logMessage)
(*jenv)->ExceptionClear(jenv);
}
- (*jenv)->ThrowNew(jenv, excClass,
- "Can't get native WolfSSLLoggingCallback class reference");
-
if (needsDetach == 1) {
(*g_vm)->DetachCurrentThread(g_vm);
}
@@ -1185,8 +1230,6 @@ void NativeLoggingCallback(const int logLevel, const char *const logMessage)
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
}
- (*jenv)->ThrowNew(jenv, excClass,
- "Error getting loggingCallback method from JNI");
if (needsDetach == 1) {
(*g_vm)->DetachCurrentThread(g_vm);
}
@@ -1203,22 +1246,16 @@ void NativeLoggingCallback(const int logLevel, const char *const logMessage)
(*jenv)->ExceptionDescribe(jenv);
(*jenv)->ExceptionClear(jenv);
- (*jenv)->ThrowNew(jenv, excClass,
- "Error calling logging callback from JNI");
+ /* Not throwing exception, just move on without printing the log.
+ * Otherwise, our non-important exception here could cause
+ * bad things to happen at the Java level - ie, causing the
+ * certificate verify callback to fail unnecessarily. */
if (needsDetach == 1) {
(*g_vm)->DetachCurrentThread(g_vm);
}
return;
}
- } else {
- if ((*jenv)->ExceptionOccurred(jenv)) {
- (*jenv)->ExceptionDescribe(jenv);
- (*jenv)->ExceptionClear(jenv);
- }
-
- (*jenv)->ThrowNew(jenv, excClass,
- "Object reference invalid in NativeLoggingCallback");
}
if (needsDetach == 1) {
@@ -1652,7 +1689,7 @@ JNIEXPORT jstring JNICALL Java_com_wolfssl_WolfSSL_getAvailableCipherSuitesIana
return NULL;
}
- if (protocolVersion < 0 || protocolVersion > 5) {
+ if (protocolVersion < 0 || protocolVersion > 8) {
printf("Input protocol version invalid: %d\n", protocolVersion);
return NULL;
}
@@ -1683,6 +1720,23 @@ JNIEXPORT jstring JNICALL Java_com_wolfssl_WolfSSL_getAvailableCipherSuitesIana
case 5:
method = wolfSSLv23_client_method();
break;
+#ifdef WOLFSSL_DTLS
+ #ifndef NO_OLD_TLS
+ case 6:
+ method = wolfDTLSv1_client_method();
+ break;
+ #endif
+ #ifndef WOLFSSL_NO_TLS12
+ case 7:
+ method = wolfDTLSv1_2_client_method();
+ break;
+ #endif
+ #ifdef WOLFSSL_DTLS13
+ case 8:
+ method = wolfDTLSv1_3_client_method();
+ break;
+ #endif
+#endif
default:
printf("Input protocol version invalid: %d\n", protocolVersion);
return NULL;
@@ -1900,6 +1954,19 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSL_isEnabledDTLS
#endif
}
+JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSL_isEnabledSendHrrCookie
+ (JNIEnv* jenv, jclass jcl)
+{
+ (void)jenv;
+ (void)jcl;
+
+#ifdef WOLFSSL_SEND_HRR_COOKIE
+ return 1;
+#else
+ return 0;
+#endif
+}
+
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSL_isEnabledAtomicUser
(JNIEnv* jenv, jclass jcl)
{
@@ -1926,6 +1993,19 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSL_isEnabledPKCallbacks
#endif
}
+JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSL_isEnabledTLSExtendedMasterSecret
+ (JNIEnv* jenv, jclass jcl)
+{
+ (void)jenv;
+ (void)jcl;
+
+#if defined(HAVE_EXTENDED_MASTER) && !defined(NO_WOLFSSL_CLIENT)
+ return 1;
+#else
+ return 0;
+#endif
+}
+
JNIEXPORT jobjectArray JNICALL Java_com_wolfssl_WolfSSL_getProtocols
(JNIEnv* jenv, jclass jcl)
{
@@ -1940,26 +2020,42 @@ 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
ret = (*jenv)->NewObjectArray(jenv, numProtocols,
@@ -2031,6 +2127,45 @@ JNIEXPORT jobjectArray JNICALL Java_com_wolfssl_WolfSSL_getProtocolsMask
}
}
#endif
+
+#ifdef WOLFSSL_DTLS
+ #ifndef NO_OLD_TLS
+ 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
+ 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
+ #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
return ret;
}
diff --git a/native/com_wolfssl_WolfSSL.h b/native/com_wolfssl_WolfSSL.h
index 3c774fff..350216a4 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
@@ -885,6 +897,30 @@ JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSL_DTLSv1_12_1ServerMethod
JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSL_DTLSv1_12_1ClientMethod
(JNIEnv *, jclass);
+/*
+ * Class: com_wolfssl_WolfSSL
+ * Method: DTLSv1_3_Method
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSL_DTLSv1_13_1Method
+ (JNIEnv *, jclass);
+
+/*
+ * Class: com_wolfssl_WolfSSL
+ * Method: DTLSv1_3_ServerMethod
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSL_DTLSv1_13_1ServerMethod
+ (JNIEnv *, jclass);
+
+/*
+ * Class: com_wolfssl_WolfSSL
+ * Method: DTLSv1_3_ClientMethod
+ * Signature: ()J
+ */
+JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSL_DTLSv1_13_1ClientMethod
+ (JNIEnv *, jclass);
+
/*
* Class: com_wolfssl_WolfSSL
* Method: SSLv23_Method
@@ -1061,6 +1097,14 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSL_isEnabledPSK
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSL_isEnabledDTLS
(JNIEnv *, jclass);
+/*
+ * Class: com_wolfssl_WolfSSL
+ * Method: isEnabledSendHrrCookie
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSL_isEnabledSendHrrCookie
+ (JNIEnv *, jclass);
+
/*
* Class: com_wolfssl_WolfSSL
* Method: isEnabledAtomicUser
@@ -1077,6 +1121,14 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSL_isEnabledAtomicUser
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSL_isEnabledPKCallbacks
(JNIEnv *, jclass);
+/*
+ * Class: com_wolfssl_WolfSSL
+ * Method: isEnabledTLSExtendedMasterSecret
+ * Signature: ()I
+ */
+JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSL_isEnabledTLSExtendedMasterSecret
+ (JNIEnv *, jclass);
+
/*
* Class: com_wolfssl_WolfSSL
* Method: getProtocols
diff --git a/native/com_wolfssl_WolfSSLSession.c b/native/com_wolfssl_WolfSSLSession.c
index 3e88820d..897e5305 100644
--- a/native/com_wolfssl_WolfSSLSession.c
+++ b/native/com_wolfssl_WolfSSLSession.c
@@ -63,6 +63,12 @@ int NativeALPNSelectCb(WOLFSSL *ssl, const unsigned char **out,
int NativeTls13SecretCb(WOLFSSL *ssl, int id, const unsigned char* secret,
int secretSz, void* ctx);
+#if !defined(NO_WOLFSSL_CLIENT) && defined(HAVE_SESSION_TICKET)
+/* Session ticket callback prototype */
+int NativeSessionTicketCb(WOLFSSL *ssl, const unsigned char* ticket,
+ int ticketLen, void* ctx);
+#endif
+
#ifdef HAVE_CRL
/* global object refs for CRL callback */
static jobject g_crlCbIfaceObj;
@@ -1568,6 +1574,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 +2430,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 +2447,35 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_dtlsGotTimeout
#endif
}
+JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_dtlsRetransmit
+ (JNIEnv* jenv, jobject jcl, jlong sslPtr)
+{
+#if !defined(WOLFSSL_LEANPSK) && defined(WOLFSSL_DTLS)
+ WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
+ (void)jenv;
+ (void)jcl;
+
+ if (ssl == NULL) {
+ return SSL_FATAL_ERROR;
+ }
+
+ return wolfSSL_dtls_retransmit(ssl);
+#else
+ (void)jenv;
+ (void)jcl;
+ (void)sslPtr;
+ return NOT_COMPILED_IN;
+#endif
+}
+
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_dtls
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
- 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 0;
- }
- (*jenv)->ThrowNew(jenv, excClass,
- "Input WolfSSLSession object was null in dtls()");
return 0;
}
@@ -2694,6 +2714,128 @@ JNIEXPORT jobject JNICALL Java_com_wolfssl_WolfSSLSession_dtlsGetPeer
}
}
+JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_sendHrrCookie
+ (JNIEnv* jenv, jobject jcl, jlong sslPtr, jbyteArray secret)
+{
+ int ret = SSL_FAILURE;
+#ifdef WOLFSSL_SEND_HRR_COOKIE
+ byte* secretBuf = NULL;
+ word32 secretSz = 0;
+ WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
+ (void)jcl;
+
+ if (jenv == NULL || ssl == NULL) {
+ return BAD_FUNC_ARG;
+ }
+
+ if (secret != NULL) {
+ secretBuf = (byte*)(*jenv)->GetByteArrayElements(jenv, secret, NULL);
+ secretSz = (*jenv)->GetArrayLength(jenv, secret);
+ }
+
+ ret = wolfSSL_send_hrr_cookie(ssl, secretBuf, secretSz);
+
+ if (secret != NULL) {
+ (*jenv)->ReleaseByteArrayElements(jenv, secret,
+ (jbyte*)secretBuf, JNI_ABORT);
+ }
+
+#else
+ ret = NOT_COMPILED_IN;
+ (void)jenv;
+ (void)jcl;
+ (void)sslPtr;
+ (void)secret;
+#endif /* WOLFSSL_SEND_HRR_COOKIE */
+
+ return (jint)ret;
+}
+
+JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLSession_getDtlsMacDropCount
+ (JNIEnv* jenv, jobject jcl, jlong sslPtr)
+{
+ word32 dropCount = 0;
+#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_DTLS_DROP_STATS)
+ int ret = 0;
+ WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
+
+ /* checks ssl for NULL internally */
+ ret = wolfSSL_dtls_get_drop_stats(ssl, &dropCount, NULL);
+ if (ret != WOLFSSL_SUCCESS) {
+ return (jlong)ret;
+ }
+#endif
+ (void)jenv;
+ (void)jcl;
+
+ return (jlong)dropCount;
+}
+
+JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLSession_getDtlsReplayDropCount
+ (JNIEnv* jenv, jobject jcl, jlong sslPtr)
+{
+ word32 dropCount = 0;
+#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_DTLS_DROP_STATS)
+ int ret = 0;
+ WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
+
+ /* checks ssl for NULL internally */
+ ret = wolfSSL_dtls_get_drop_stats(ssl, NULL, &dropCount);
+ if (ret != WOLFSSL_SUCCESS) {
+ return (jlong)ret;
+ }
+#endif
+ (void)jenv;
+ (void)jcl;
+
+ return (jlong)dropCount;
+}
+
+JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_setMTU
+ (JNIEnv* jenv, jobject jcl, jlong sslPtr, jint mtu)
+{
+#if defined(WOLFSSL_DTLS) && defined(WOLFSSL_DTLS_MTU)
+ WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
+
+ /* wolfSSL_dtls_set_mtu() checks ssl for NULL */
+ return (jint)wolfSSL_dtls_set_mtu(ssl, (unsigned short)mtu);
+#else
+ (void)jenv;
+ (void)jcl;
+ (void)sslPtr;
+ (void)mtu;
+ return (jint)NOT_COMPILED_IN;
+#endif
+}
+
+JNIEXPORT jstring JNICALL Java_com_wolfssl_WolfSSLSession_stateStringLong
+ (JNIEnv* jenv, jobject jcl, jlong sslPtr)
+{
+#ifdef OPENSSL_EXTRA
+ WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
+ const char* stateString;
+ jstring stateStr = NULL;
+ (void)jcl;
+
+ if (jenv == NULL || ssl == NULL) {
+ return NULL;
+ }
+
+ stateString = wolfSSL_state_string_long(ssl);
+
+ if (stateString != NULL) {
+ stateStr = (*jenv)->NewStringUTF(jenv, stateString);
+ }
+
+ return stateStr;
+#else
+ (void)jenv;
+ (void)jcl;
+ (void)sslPtr;
+ return NULL;
+#endif
+}
+
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_sessionReused
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
{
@@ -4681,9 +4823,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
@@ -5487,6 +5628,30 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_setTls13SecretCb
#endif
}
+JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_setSessionTicketCb
+ (JNIEnv* jenv, jobject jcl, jlong sslPtr)
+{
+#if !defined(NO_WOLFSSL_CLIENT) && defined(HAVE_SESSION_TICKET)
+ WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
+ int ret = SSL_SUCCESS;
+ (void)jcl;
+
+ if (jenv == NULL || ssl == NULL) {
+ return BAD_FUNC_ARG;
+ }
+
+ /* Java layer handles setting and giving back user CTX */
+ ret = wolfSSL_set_SessionTicket_cb(ssl, NativeSessionTicketCb, NULL);
+
+ return ret;
+#else
+ (void)jenv;
+ (void)jcl;
+ (void)sslPtr;
+ return NOT_COMPILED_IN;
+#endif
+}
+
#if defined(WOLFSSL_TLS13) && !defined(WOLFCRYPT_ONLY) && \
defined(HAVE_SECRET_CALLBACK)
@@ -5629,6 +5794,146 @@ int NativeTls13SecretCb(WOLFSSL *ssl, int id, const unsigned char* secret,
#endif /* WOLFSSL_TLS13 && !WOLFCRYPT_ONLY && HAVE_SECRET_CALLBACK */
+#if !defined(NO_WOLFSSL_CLIENT) && defined(HAVE_SESSION_TICKET)
+
+int NativeSessionTicketCb(WOLFSSL* ssl, const unsigned char* ticket,
+ int ticketLen, void* ctx)
+{
+ JNIEnv* jenv; /* JNI environment */
+ jclass excClass; /* WolfSSLJNIException class */
+ int needsDetach = 0; /* Should we explicitly detach? */
+ jint retval = 0;
+ jint vmret = 0;
+
+ jobject* g_cachedSSLObj; /* WolfSSLSession cached object */
+ jclass sslClass; /* WolfSSLSession class */
+ jmethodID sessTicketCbMethodId; /* internalTls13SecretCallback ID */
+ jbyteArray ticketArr = NULL;
+
+ if (g_vm == NULL || ssl == NULL) {
+ return BAD_FUNC_ARG;
+ }
+
+ /* get JavaEnv from JavaVM */
+ vmret = (int)((*g_vm)->GetEnv(g_vm, (void**) &jenv, JNI_VERSION_1_6));
+ if (vmret == JNI_EDETACHED) {
+#ifdef __ANDROID__
+ vmret = (*g_vm)->AttachCurrentThread(g_vm, &jenv, NULL);
+#else
+ vmret = (*g_vm)->AttachCurrentThread(g_vm, (void**) &jenv, NULL);
+#endif
+ if (vmret) {
+ return -1;
+ }
+ needsDetach = 1;
+ }
+ else if (vmret != JNI_OK) {
+ return -1;
+ }
+
+ /* 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 (needsDetach) {
+ (*g_vm)->DetachCurrentThread(g_vm);
+ }
+ return -1;
+ }
+
+ /* Get stored WolfSSLSession object */
+ g_cachedSSLObj = (jobject*) wolfSSL_get_jobject(ssl);
+ if (!g_cachedSSLObj) {
+ (*jenv)->ThrowNew(jenv, excClass,
+ "Can't get native WolfSSLSession object reference in "
+ "NativeSessionTicketCb");
+ if (needsDetach) {
+ (*g_vm)->DetachCurrentThread(g_vm);
+ }
+ return -1;
+ }
+
+ /* Lookup WolfSSLSession class from object */
+ sslClass = (*jenv)->GetObjectClass(jenv, (jobject)(*g_cachedSSLObj));
+ if (sslClass == NULL) {
+ (*jenv)->ThrowNew(jenv, excClass,
+ "Can't get native WolfSSLSession class reference in "
+ "NativeSessionTicketCb");
+ if (needsDetach) {
+ (*g_vm)->DetachCurrentThread(g_vm);
+ }
+ return -1;
+ }
+
+ /* Call internal TLS 1.3 secret callback */
+ sessTicketCbMethodId = (*jenv)->GetMethodID(jenv, sslClass,
+ "internalSessionTicketCallback", "(Lcom/wolfssl/WolfSSLSession;[B)I");
+ if (sessTicketCbMethodId == NULL) {
+ if ((*jenv)->ExceptionOccurred(jenv)) {
+ (*jenv)->ExceptionDescribe(jenv);
+ (*jenv)->ExceptionClear(jenv);
+ }
+ (*jenv)->ThrowNew(jenv, excClass,
+ "Error getting internalSessionTicketCallback method from JNI");
+ if (needsDetach) {
+ (*g_vm)->DetachCurrentThread(g_vm);
+ }
+ return -1;
+ }
+
+ if (ticketLen > 0) {
+ /* Create jbyteArray to hold session ticket */
+ ticketArr = (*jenv)->NewByteArray(jenv, ticketLen);
+ if (ticketArr == NULL) {
+ (*jenv)->ThrowNew(jenv, excClass,
+ "Error creating new jbyteArray in NativeSessionTicketCb");
+ if (needsDetach) {
+ (*g_vm)->DetachCurrentThread(g_vm);
+ }
+ return -1;
+ }
+
+ (*jenv)->SetByteArrayRegion(jenv, ticketArr, 0, ticketLen,
+ (jbyte*)ticket);
+ if ((*jenv)->ExceptionOccurred(jenv)) {
+ (*jenv)->ExceptionDescribe(jenv);
+ (*jenv)->ExceptionClear(jenv);
+ if (needsDetach) {
+ (*g_vm)->DetachCurrentThread(g_vm);
+ }
+ return -1;
+ }
+
+ /* Call Java session ticket callback, ignore native CTX since Java
+ * handles it */
+ retval = (*jenv)->CallIntMethod(jenv, (jobject)(*g_cachedSSLObj),
+ sessTicketCbMethodId, (jobject)(*g_cachedSSLObj), ticketArr);
+ if ((*jenv)->ExceptionOccurred(jenv)) {
+ (*jenv)->ExceptionDescribe(jenv);
+ (*jenv)->ExceptionClear(jenv);
+ (*jenv)->ThrowNew(jenv, excClass,
+ "Exception while calling internalSessionTicketCallback()");
+ if (needsDetach) {
+ (*g_vm)->DetachCurrentThread(g_vm);
+ }
+ return -1;
+ }
+
+ /* Delete local refs */
+ (*jenv)->DeleteLocalRef(jenv, ticketArr);
+ }
+
+ /* Detach JNIEnv from thread */
+ if (needsDetach) {
+ (*g_vm)->DetachCurrentThread(g_vm);
+ }
+
+ return (int)retval;
+}
+
+#endif /* WOLFSSL_TLS13 && !WOLFCRYPT_ONLY && HAVE_SECRET_CALLBACK */
+
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_useSecureRenegotiation
(JNIEnv* jenv, jobject jcl, jlong ssl)
{
@@ -5707,6 +6012,26 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_useSupportedCurve
#endif
}
+JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_disableExtendedMasterSecret
+ (JNIEnv* jenv, jobject jcl, jlong sslPtr)
+{
+#if defined(HAVE_EXTENDED_MASTER) && !defined(NO_WOLFSSL_CLIENT)
+ int ret = 0;
+ WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
+ (void)jcl;
+
+ /* Checks ssl for null internally */
+ ret = wolfSSL_DisableExtendedMasterSecret(ssl);
+
+ return (jint)ret;
+#else
+ (void)jenv;
+ (void)jcl;
+ (void)sslPtr;
+ return (jint)NOT_COMPILED_IN;
+#endif
+}
+
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_hasTicket
(JNIEnv* jenv, jobject jcl, jlong sessionPtr)
{
@@ -5777,24 +6102,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 +6244,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 260032ca..017e4577 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
@@ -295,6 +311,30 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_dtls
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_dtlsSetPeer
(JNIEnv *, jobject, jlong, jobject);
+/*
+ * Class: com_wolfssl_WolfSSLSession
+ * Method: sendHrrCookie
+ * Signature: (J[B)I
+ */
+JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_sendHrrCookie
+ (JNIEnv *, jobject, jlong, jbyteArray);
+
+/*
+ * Class: com_wolfssl_WolfSSLSession
+ * Method: getDtlsMacDropCount
+ * Signature: (J)J
+ */
+JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLSession_getDtlsMacDropCount
+ (JNIEnv *, jobject, jlong);
+
+/*
+ * Class: com_wolfssl_WolfSSLSession
+ * Method: getDtlsReplayDropCount
+ * Signature: (J)J
+ */
+JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLSession_getDtlsReplayDropCount
+ (JNIEnv *, jobject, jlong);
+
/*
* Class: com_wolfssl_WolfSSLSession
* Method: dtlsGetPeer
@@ -823,6 +863,14 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_setALPNSelectCb
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_setTls13SecretCb
(JNIEnv *, jobject, jlong);
+/*
+ * Class: com_wolfssl_WolfSSLSession
+ * Method: setSessionTicketCb
+ * Signature: (J)I
+ */
+JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_setSessionTicketCb
+ (JNIEnv *, jobject, jlong);
+
/*
* Class: com_wolfssl_WolfSSLSession
* Method: keepArrays
@@ -871,6 +919,14 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_set1SigAlgsList
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_useSupportedCurve
(JNIEnv *, jobject, jlong, jint);
+/*
+ * Class: com_wolfssl_WolfSSLSession
+ * Method: disableExtendedMasterSecret
+ * Signature: (J)I
+ */
+JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_disableExtendedMasterSecret
+ (JNIEnv *, jobject, jlong);
+
/*
* Class: com_wolfssl_WolfSSLSession
* Method: hasTicket
@@ -895,6 +951,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/scripts/infer.sh b/scripts/infer.sh
index 97bc30d2..531b0d48 100755
--- a/scripts/infer.sh
+++ b/scripts/infer.sh
@@ -61,6 +61,7 @@ infer --fail-on-issue run -- javac \
src/java/com/wolfssl/WolfSSLRsaSignCallback.java \
src/java/com/wolfssl/WolfSSLRsaVerifyCallback.java \
src/java/com/wolfssl/WolfSSLSession.java \
+ src/java/com/wolfssl/WolfSSLSessionTicketCallback.java \
src/java/com/wolfssl/WolfSSLTls13SecretCallback.java \
src/java/com/wolfssl/WolfSSLVerifyCallback.java \
src/java/com/wolfssl/WolfSSLVerifyDecryptCallback.java \
diff --git a/src/java/com/wolfssl/WolfSSL.java b/src/java/com/wolfssl/WolfSSL.java
index 98adadab..e4c9b4ad 100644
--- a/src/java/com/wolfssl/WolfSSL.java
+++ b/src/java/com/wolfssl/WolfSSL.java
@@ -51,7 +51,13 @@ public enum TLS_VERSION {
/** TLS 1.3 */
TLSv1_3,
/** Downgrade starting from highest supported SSL/TLS version */
- SSLv23
+ SSLv23,
+ /** DTLS 1.0 */
+ DTLSv1,
+ /** DTLS 1.2 */
+ DTLSv1_2,
+ /** DTLS 1.3 */
+ DTLSv1_3
}
/* ------------------ wolfSSL JNI error codes ----------------------- */
@@ -208,10 +214,14 @@ public enum TLS_VERSION {
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 */
@@ -838,6 +848,13 @@ protected static byte[] fileToBytes(File file)
*/
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.
*
@@ -1234,6 +1251,46 @@ protected static byte[] fileToBytes(File file)
*/
public static final native long DTLSv1_2_ClientMethod();
+ /**
+ * Indicates that the application will only support the DTLS 1.3 protocol.
+ * Application is side-independent at this time, and client/server side
+ * will be determined at connect/accept stage.
+ * This method allocates memory for and initializes a new native
+ * WOLFSSL_METHOD structure to be used when creating the SSL/TLS
+ * context with newContext().
+ *
+ * @return A pointer to the created WOLFSSL_METHOD structure if
+ * successful, null on failure.
+ * @see WolfSSLContext#newContext(long)
+ */
+ public static final native long DTLSv1_3_Method();
+
+ /**
+ * Indicates that the application is a server and will only support the
+ * DTLS 1.3 protocol.
+ * This method allocates memory for and initializes a new native
+ * WOLFSSL_METHOD structure to be used when creating the SSL/TLS
+ * context with newContext().
+ *
+ * @return A pointer to the created WOLFSSL_METHOD structure if
+ * successful, null on failure.
+ * @see WolfSSLContext#newContext(long)
+ */
+ public static final native long DTLSv1_3_ServerMethod();
+
+ /**
+ * Indicates that the application is a client and will only support the
+ * DTLS 1.3 protocol.
+ * This method allocates memory for and initializes a new native
+ * WOLFSSL_METHOD structure to be used when creating the SSL/TLS
+ * context with newContext().
+ *
+ * @return A pointer to the created WOLFSSL_METHOD structure if
+ * successful, null on failure.
+ * @see WolfSSLContext#newContext(long)
+ */
+ public static final native long DTLSv1_3_ClientMethod();
+
/**
* Indicates that the application will use the highest possible SSL/TLS
* version from SSL 3.0 up to TLS 1.2, but is side-independent at creation
@@ -1590,6 +1647,14 @@ public static int cryptoCbUnRegisterDevice(int devId) {
*/
public static native int isEnabledDTLS();
+ /**
+ * Checks if (D)TLS 1.3 HRR Cookie is enabled in the native wolfSSL
+ * library. Checks if native WOLFSSL_SEND_HRR_COOKIE is defined.
+ *
+ * @return 1 if enabled, 9 if not compiled in.
+ */
+ public static native int isEnabledSendHrrCookie();
+
/**
* Checks if Atomic User support is enabled in wolfSSL native library.
*
@@ -1605,6 +1670,14 @@ public static int cryptoCbUnRegisterDevice(int devId) {
*/
public static native int isEnabledPKCallbacks();
+ /**
+ * Checks if TLS Extended Master Secret support has been compiled into
+ * native wolfSSL library.
+ *
+ * @return 1 if available, 0 if not compiled in.
+ */
+ public static native int isEnabledTLSExtendedMasterSecret();
+
/**
* Checks which protocols where built into wolfSSL
*
diff --git a/src/java/com/wolfssl/WolfSSLSession.java b/src/java/com/wolfssl/WolfSSLSession.java
index 987a29c8..dd39fb65 100644
--- a/src/java/com/wolfssl/WolfSSLSession.java
+++ b/src/java/com/wolfssl/WolfSSLSession.java
@@ -62,6 +62,7 @@ public class WolfSSLSession {
private Object rsaDecCtx;
private Object alpnSelectArg;
private Object tls13SecretCtx;
+ private Object sessionTicketCtx;
/* reference to the associated WolfSSLContext */
private WolfSSLContext ctx = null;
@@ -80,10 +81,14 @@ public class WolfSSLSession {
* ALPN select callback */
private WolfSSLALPNSelectCallback internAlpnSelectCb;
- /* user-registered TLS 1.3 secret callbcak, called by internal
+ /* user-registered TLS 1.3 secret callback, called by internal
* WolfSSLSession TLS 1.3 secret callback */
private WolfSSLTls13SecretCallback internTls13SecretCb;
+ /* user-registered session ticket callback, called by internal
+ * WolfSSLSession session ticket callback */
+ private WolfSSLSessionTicketCallback internSessionTicketCb;
+
/* have session tickets been enabled for this session? Default to false. */
private boolean sessionTicketsEnabled = false;
@@ -282,6 +287,13 @@ private int internalTls13SecretCallback(WolfSSLSession ssl, int id,
this.tls13SecretCtx);
}
+ private int internalSessionTicketCallback(WolfSSLSession ssl, byte[] ticket)
+ {
+ /* call user-registered session ticket callback */
+ return internSessionTicketCb.sessionTicketCallback(ssl, ticket,
+ this.sessionTicketCtx);
+ }
+
/**
* Verifies that the current WolfSSLSession object is active.
*
@@ -316,6 +328,7 @@ private native int read(long ssl, byte[] data, int offset, int sz,
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,8 +350,12 @@ private native int read(long ssl, ByteBuffer data, int sz, int timeout)
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 int sendHrrCookie(long ssl, byte[] secret);
+ private native long getDtlsMacDropCount(long ssl);
+ private native long getDtlsReplayDropCount(long ssl);
private native InetSocketAddress dtlsGetPeer(long ssl);
private native int sessionReused(long ssl);
private native long getPeerCertificate(long ssl);
@@ -410,15 +427,19 @@ private native int setTlsHmacInner(long ssl, byte[] inner, long sz,
private native int useALPN(long ssl, String protocols, int options);
private native int setALPNSelectCb(long ssl);
private native int setTls13SecretCb(long ssl);
+ private native int setSessionTicketCb(long ssl);
private native void keepArrays(long ssl);
private native byte[] getClientRandom(long ssl);
private native int useSecureRenegotiation(long ssl);
private native int rehandshake(long ssl);
private native int set1SigAlgsList(long ssl, String list);
private native int useSupportedCurve(long ssl, int name);
+ private native int disableExtendedMasterSecret(long ssl);
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 +1160,7 @@ public int read(byte[] data, int sz, int timeout)
* 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 +1278,29 @@ public int read(ByteBuffer data, int sz, int timeout)
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
@@ -2214,6 +2258,23 @@ public int useSupportedCurves(String[] curveNames)
return ret;
}
+ /**
+ * Disable TLS Extended Master Secret usage.
+ *
+ * @return WolfSSL.SSL_SUCCESS
on success, otherwise
+ * negative on error.
+ * @throws IllegalStateException WolfSSLSession has been freed
+ */
+ public int disableExtendedMasterSecret()
+ throws IllegalStateException {
+
+ confirmObjectIsActive();
+
+ synchronized (sslLock) {
+ return disableExtendedMasterSecret(this.sslPtr);
+ }
+ }
+
/* ---------------- Nonblocking DTLS helper functions -------------- */
/**
@@ -2260,14 +2321,12 @@ public int dtlsGetCurrentTimeout()
* 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 +2338,47 @@ public int dtlsGotTimeout()
}
}
+ /**
+ * 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();
@@ -2332,6 +2418,70 @@ public int dtlsSetPeer(InetSocketAddress peer)
}
}
+ /**
+ * Send a cookie with the HelloRetryRequest to avoid storing state.
+ *
+ * @param secret Secret to use when generating integrity check for cookie.
+ * A value of null indicates to generate a new random secret.
+ *
+ * @return WolfSSL.SSL_SUCCESS
on success,
+ * WolfSSL.BAD_FUNC_ARG
when not using (D)TLS 1.3,
+ * WolfSSL.SIDE_ERROR
when called on a client.
+ *
+ * @throws IllegalStateException WolfSSLContext has been freed
+ */
+ public int sendHrrCookie(byte[] secret)
+ throws IllegalStateException {
+
+ confirmObjectIsActive();
+
+ synchronized (sslLock) {
+ return sendHrrCookie(this.sslPtr, secret);
+ }
+ }
+
+ /**
+ * Get the number of DTLS packets that have been dropped due
+ * to verify MAC decrypt errors.
+ *
+ * Native wolfSSL must be compiled with WOLFSSL_DTLS_DROP_STATS
+ * defined for this functionality to be available, otherwise this
+ * method will return 0.
+ *
+ * @return number of dropped packets
+ *
+ * @throws IllegalStateException WolfSSLSession has been freed
+ */
+ public long getDtlsMacDropCount() throws IllegalStateException {
+
+ confirmObjectIsActive();
+
+ synchronized (sslLock) {
+ return getDtlsMacDropCount(this.sslPtr);
+ }
+ }
+
+ /**
+ * Get the number of DTLS packets that have been dropped due to
+ * receiving a replayed / duplicated packet.
+ *
+ * Native wolfSSL must be compiled with WOLFSSL_DTLS_DROP_STATS
+ * defined for this functionality to be available, otherwise this
+ * method will return 0.
+ *
+ * @return number of dropped packets
+ *
+ * @throws IllegalStateException WolfSSLSession has been freed
+ */
+ public long getDtlsReplayDropCount() throws IllegalStateException {
+
+ confirmObjectIsActive();
+
+ synchronized (sslLock) {
+ return getDtlsReplayDropCount(this.sslPtr);
+ }
+ }
+
/**
* Gets the InetSocketAddress of the DTLS peer.
*
@@ -2355,6 +2505,57 @@ public InetSocketAddress dtlsGetPeer() throws IllegalStateException {
}
}
+ /**
+ * 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.
@@ -2511,8 +2712,8 @@ public String getPeerX509AltName(long x509)
/**
* Returns the SSL/TLS version being used with this session object in
* String format.
- * Examples include "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2", "DTLS", and
- * "DTLS 1.2".
+ * Examples include "SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2", "DTLS",
+ * "DTLS 1.2", and "DTLS 1.3.
*
* @return SSL/TLS protocol version being used in String format,
* or "unknown".
@@ -4168,8 +4369,10 @@ public void setIORecv(WolfSSLIORecvCallback callback)
/* 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 +4409,10 @@ public void setIOSend(WolfSSLIOSendCallback callback)
/* 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);
+ }
}
}
@@ -4627,6 +4832,47 @@ public int setTls13SecretCb(WolfSSLTls13SecretCallback cb, Object ctx)
return ret;
}
+ /**
+ * Register session ticket callback.
+ *
+ * The callback registered by this method is called by native wolfSSL
+ * when a session ticket is received from the peer.
+ *
+ * @param cb callback to be registered with this SSL session
+ * @param ctx Object that will be passed back to user inside callback
+ *
+ * @return SSL_SUCCESS
on success.
+ * NOT_COMPILED_IN
if wolfSSL was not compiled with
+ * session ticket support, and other negative value on error.
+ *
+ * @throws IllegalStateException WolfSSLSession has been freed
+ * @throws WolfSSLJNIException Internal JNI error
+ */
+ public int setSessionTicketCb(WolfSSLSessionTicketCallback cb, Object ctx)
+ throws IllegalStateException, WolfSSLJNIException {
+
+ int ret = 0;
+
+ confirmObjectIsActive();
+
+ synchronized (sslLock) {
+ WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
+ WolfSSLDebug.INFO, this.sslPtr, "entered setSessionTicketCb(" +
+ cb + ", ctx: " + ctx + ")");
+
+ ret = setSessionTicketCb(this.sslPtr);
+ if (ret == WolfSSL.SSL_SUCCESS) {
+ /* Set session ticket callback */
+ internSessionTicketCb = cb;
+
+ /* Set session ticket ctx Object, returned to user in cb */
+ this.sessionTicketCtx = ctx;
+ }
+ }
+
+ return ret;
+ }
+
/**
* Do not free temporary arrays at end of handshake.
*
diff --git a/src/java/com/wolfssl/WolfSSLSessionTicketCallback.java b/src/java/com/wolfssl/WolfSSLSessionTicketCallback.java
new file mode 100644
index 00000000..08bffc67
--- /dev/null
+++ b/src/java/com/wolfssl/WolfSSLSessionTicketCallback.java
@@ -0,0 +1,59 @@
+/* WolfSSLSessionTicketCallback.java
+ *
+ * Copyright (C) 2006-2025 wolfSSL Inc.
+ *
+ * This file is part of wolfSSL.
+ *
+ * wolfSSL is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * wolfSSL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
+ */
+
+package com.wolfssl;
+
+/**
+ * wolfSSL session ticket callback interface.
+ * This interface specifies how applications should implement the session
+ * ticket callback class, to be used by wolfSSL when receiving a session
+ * ticket message.
+ *
+ * To use this interface, native wolfSSL must be compiled with + * HAVE_SESSION_TICKET defined. + *
+ * After implementing this interface, it should be passed as a parameter + * to the + * {@link WolfSSLSession#setSessionTicketCb(WolfSSLSessionTicketCallback, Object) + * WolfSSLSession.setSessionTicketCb()} method to be registered with the native + * wolfSSL library. + */ +public interface WolfSSLSessionTicketCallback { + + /** + * Callback method which is called when native wolfSSL receives a + * session ticket message. + * + * @param ssl the current SSL session object from which the + * callback was initiated + * @param ticket Session ticket received as a byte array + * @param ctx Optional user context if set when callback was + * registered + * + * @return 0 on success. wolfSSL does not currently do anything with + * the return value of this method, but is in place for + * future expansion if needed. + */ + public int sessionTicketCallback(WolfSSLSession ssl, byte[] ticket, + Object ctx); +} + + diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLContext.java b/src/java/com/wolfssl/provider/jsse/WolfSSLContext.java index eb4666fa..6e7e9593 100644 --- a/src/java/com/wolfssl/provider/jsse/WolfSSLContext.java +++ b/src/java/com/wolfssl/provider/jsse/WolfSSLContext.java @@ -91,7 +91,8 @@ private void createCtx() throws WolfSSLException { 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 @@ private void createCtx() throws WolfSSLException { 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 @@ private void createCtx() throws WolfSSLException { * 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 TLSV23_Context() { } } + /** + * 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 b2699402..c25dd0f7 100644 --- a/src/java/com/wolfssl/provider/jsse/WolfSSLEngine.java +++ b/src/java/com/wolfssl/provider/jsse/WolfSSLEngine.java @@ -29,6 +29,7 @@ import com.wolfssl.WolfSSLJNIException; import com.wolfssl.WolfSSLSession; import com.wolfssl.WolfSSLALPNSelectCallback; +import com.wolfssl.WolfSSLSessionTicketCallback; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.ReadOnlyBufferException; @@ -72,6 +73,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 */ @@ -93,6 +96,12 @@ public class WolfSSLEngine extends SSLEngine { /* handshake completed */ private boolean handshakeFinished = false; + /* Last return values of ssl.connect() / ssl.accept(). Protected + * by ioLock. Can be used during state transitions to see if handshake + * has finished successfully from native wolfSSL perspective. */ + private int lastSSLConnectRet = WolfSSL.SSL_FAILURE; + private int lastSSLAcceptRet = WolfSSL.SSL_FAILURE; + /* closeNotify status when shutting down */ private boolean closeNotifySent = false; private boolean closeNotifyReceived = false; @@ -103,11 +112,16 @@ public class WolfSSLEngine extends SSLEngine { /* TLS 1.3 session ticket received (on client side) */ private boolean sessionTicketReceived = false; + /* Number of session tickets received, incremented in + * SessionTicketCB callback */ + private int sessionTicketCount = 0; + /* client/server mode has been set */ private boolean clientModeSet = false; private SendCB sendCb = null; private RecvCB recvCb = null; + private SessionTicketCB sessTicketCb = null; private ByteBuffer netData = null; private final Object netDataLock = new Object(); @@ -218,6 +232,7 @@ private synchronized void LoadCertAndKey() throws SSLException { try { this.engineHelper.LoadKeyAndCertChain(null, this); + certKeyLoaded = true; } catch (CertificateEncodingException | IOException | WolfSSLException e) { WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, @@ -239,6 +254,8 @@ private synchronized void LoadCertAndKey() throws SSLException { */ private void checkAndInitSSLEngine() throws SSLException { + int ret = 0; + synchronized (initLock) { if (!needInit) { @@ -248,6 +265,21 @@ private void checkAndInitSSLEngine() throws SSLException { LoadCertAndKey(); this.engineHelper.initHandshake(this); + + if ((this.ssl.dtls() == 1) && + (!this.engineHelper.getUseClientMode())) { + ret = this.ssl.sendHrrCookie(null); + if (ret == WolfSSL.SSL_SUCCESS) { + WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, + "Enabled sending of DTLS cookie in HelloRetryRequest"); + } + else if (ret < 0) { + WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, + "Failed to enable DTLS cookie in HelloRetryRequest, " + + "ret: " + ret); + } + } + needInit = false; closed = false; /* opened a connection */ } @@ -280,6 +312,12 @@ private void setSSLCallbacks() throws WolfSSLJNIException { ssl.setIOSend(sendCb); ssl.setIOReadCtx(this); ssl.setIOWriteCtx(this); + + /* Session ticket callback */ + if (sessTicketCb == null) { + sessTicketCb = new SessionTicketCB(); + } + ssl.setSessionTicketCb(sessTicketCb, this); } } @@ -305,12 +343,16 @@ private void unsetSSLCallbacks() throws WolfSSLJNIException { } private void initSSL() throws WolfSSLException, WolfSSLJNIException { + if (sendCb == null) { sendCb = new SendCB(); } if (recvCb == null) { recvCb = new RecvCB(); } + if (sessTicketCb == null) { + sessTicketCb = new SessionTicketCB(); + } /* will throw WolfSSLException if issue creating WOLFSSL */ ssl = new WolfSSLSession(ctx, false); @@ -383,6 +425,33 @@ private synchronized void UpdateCloseNotifyStatus() { } } + /** + * Returns if current error in WOLFSSL session should be considered + * fatal. Used in ClosingConnection() for detection of storing + * client cache entry. + * + * @param ssl WOLFSSL session to check error on + * + * @return true if error is not fatal, false if fatal + */ + private synchronized boolean sslErrorNotFatal(WolfSSLSession ssl) { + + int err; + + if (ssl == null) { + return false; + } + + err = ssl.getError(0); + if (err == 0 || + err == WolfSSL.SSL_ERROR_WANT_READ || + err == WolfSSL.SSL_ERROR_WANT_WRITE) { + return true; + } + + return false; + } + /** * Handles logic during shutdown * @@ -403,10 +472,17 @@ private synchronized int ClosingConnection() * not have an active error state, and the session has not been * stored previously. */ synchronized (ioLock) { - if (this.handshakeFinished && (ssl.getError(0) == 0) && + if (this.handshakeFinished && sslErrorNotFatal(ssl) && !this.sessionStored) { + WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, + "saving WOLFSSL_SESSION into cache"); this.engineHelper.saveSession(); } + else { + WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, + "not saving WOLFSSL_SESSION into cache, " + + "handshake not complete or already stored"); + } } /* get current close_notify state */ @@ -441,26 +517,45 @@ private synchronized int ClosingConnection() * 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(); + lastSSLConnectRet = ret; - 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(); + lastSSLAcceptRet = ret; + + WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, + "ssl.accept() ret:err = " + ret + " : " + + ssl.getError(ret)); + } } } @@ -633,6 +728,12 @@ public synchronized SSLEngineResult wrap(ByteBuffer[] in, int ofst, int len, "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 +792,7 @@ else if ((produced > 0) && !inBoundOpen && else if (produced == 0) { /* continue handshake or application data */ if (!this.handshakeFinished) { - ret = DoHandshake(); + ret = DoHandshake(true); } else { try { @@ -756,6 +857,12 @@ else if (produced == 0) { "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 +937,22 @@ private synchronized int RecvAppData(ByteBuffer[] out, int ofst, int length) * 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 +974,11 @@ private synchronized int RecvAppData(ByteBuffer[] out, int ofst, int length) "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: @@ -945,6 +1069,9 @@ public synchronized SSLEngineResult unwrap(ByteBuffer in, ByteBuffer[] out, int inRemaining = 0; int consumed = 0; int produced = 0; + long dtlsPrevDropCount = 0; + long dtlsCurrDropCount = 0; + int prevSessionTicketCount = 0; byte[] tmp; /* Set initial status for SSLEngineResult return */ @@ -1024,6 +1151,12 @@ public synchronized SSLEngineResult unwrap(ByteBuffer in, ByteBuffer[] out, "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 +1199,19 @@ else if (hs == SSLEngineResult.HandshakeStatus.NEED_WRAP && } } else { + /* Get previous DTLS drop count and session ticket count, + * before we process any incomming data. Allows us to set + * BUFFER_UNDERFLOW status (or not if packet decrypt failed + * and was dropped) */ + synchronized (ioLock) { + dtlsPrevDropCount = ssl.getDtlsMacDropCount(); + prevSessionTicketCount = this.sessionTicketCount; + } 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 @@ -1084,6 +1224,7 @@ else if (hs == SSLEngineResult.HandshakeStatus.NEED_WRAP && status = SSLEngineResult.Status.BUFFER_OVERFLOW; } else { + WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, "receiving application data"); ret = RecvAppData(out, ofst, length); @@ -1093,17 +1234,32 @@ else if (hs == SSLEngineResult.HandshakeStatus.NEED_WRAP && 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 +1281,7 @@ else if (hs == SSLEngineResult.HandshakeStatus.NEED_WRAP && } } } - } + } /* end DoHandshake() / RecvAppData() */ if (outBoundOpen == false || this.closeNotifySent) { /* Mark SSLEngine status as CLOSED */ @@ -1138,9 +1294,18 @@ else if (hs == SSLEngineResult.HandshakeStatus.NEED_WRAP && 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 */ @@ -1165,13 +1330,33 @@ else if (hs == SSLEngineResult.HandshakeStatus.NEED_WRAP && } } + /* Get DTLS drop count after data has been processed. To be + * used below when setting BUFFER_UNDERFLOW status. */ + synchronized (ioLock) { + dtlsCurrDropCount = ssl.getDtlsMacDropCount(); + } + + /* Detect if we need to set BUFFER_UNDERFLOW. + * If we consume data in unwrap() but it's just a session + * ticket, we don't set BUFFER_UNDERFLOW and just continue + * on to set status as OK. */ 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; + (this.toSend != null && this.toSend.length == 0)) + && (prevSessionTicketCount == + this.sessionTicketCount)) { + + if ((this.ssl.dtls() == 0) || + (this.handshakeFinished && + (dtlsPrevDropCount == dtlsCurrDropCount))) { + /* 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 +1376,19 @@ else if (hs == SSLEngineResult.HandshakeStatus.NEED_WRAP && 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 +1439,12 @@ else if (hs == SSLEngineResult.HandshakeStatus.NEED_WRAP && "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, "==========================================================="); } @@ -1261,6 +1461,32 @@ else if (hs == SSLEngineResult.HandshakeStatus.NEED_WRAP && return new SSLEngineResult(status, hs, consumed, produced); } + /** + * Return if native ssl.connect() or ssl.accept() have finished + * successfully or not. Used to correctly set this.handshakeFinished + * from SetHandshakeStatus(). + * + * Caller of this method should protect it with lock on ioLock. + * + * @return true if native handshake finished, otherwise false. + */ + private boolean sslConnectAcceptSuccess() { + boolean client = this.engineHelper.getUseClientMode(); + + if (client) { + if (this.lastSSLConnectRet == WolfSSL.SSL_SUCCESS) { + return true; + } + } + else { + if (this.lastSSLAcceptRet == WolfSSL.SSL_SUCCESS) { + return true; + } + } + + return false; + } + /** * Sets handshake status after I/O operation of unwrap(), helper function. */ @@ -1306,7 +1532,11 @@ else if (!this.outBoundOpen && !this.closeNotifySent) { else { synchronized (netDataLock) { synchronized (ioLock) { - if (ssl.handshakeDone() && this.toSend == null) { + if (sslConnectAcceptSuccess() && ssl.handshakeDone() && + (this.toSend == null) && + (this.nativeWantsToWrite == 0) && + (this.nativeWantsToRead == 0)) { + this.handshakeFinished = true; hs = SSLEngineResult.HandshakeStatus.FINISHED; this.engineHelper.getSession().updateStoredSessionValues(); @@ -1336,6 +1566,9 @@ else if (err == WolfSSL.SSL_ERROR_WANT_READ) { 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 +1722,13 @@ public synchronized boolean sessionResumed() throws SSLException { 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 +1765,20 @@ public synchronized void beginHandshake() throws SSLException { "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 +1797,9 @@ else if (!this.needInit && !this.handshakeFinished) { 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 +2104,30 @@ protected synchronized int internalSendCb(byte[] in, int sz) { 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 +2190,15 @@ protected synchronized int internalRecvCb(byte[] toRead, int sz) { 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); @@ -1942,6 +2211,32 @@ protected synchronized int internalRecvCb(byte[] toRead, int sz) { } } + /** + * Internal session ticket callback. Called when native wolfSSL + * receives a session ticket from peer. + * + * @param ticket byte array containing session ticket data + * + * @return 0 on success, negative value on error + */ + protected synchronized int internalSessionTicketCb(byte[] ticket) { + WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, + "entered internalSessionTicketCb()"); + + if (ticket != null) { + WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, + "Session ticket received, length = " + ticket.length); + if (ticket.length > 0) { + this.sessionTicketCount++; + } + WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, + "Total session tickets received by this SSLEngine: " + + this.sessionTicketCount); + } + + return 0; + } + private class SendCB implements WolfSSLIOSendCallback { protected SendCB() { @@ -1968,6 +2263,17 @@ public int receiveCallback(WolfSSLSession ssl, byte[] out, int sz, } + private class SessionTicketCB implements WolfSSLSessionTicketCallback { + + protected SessionTicketCB() { + } + + public int sessionTicketCallback(WolfSSLSession ssl, byte[] ticket, + Object engine) { + return ((WolfSSLEngine)engine).internalSessionTicketCb(ticket); + } + } + @SuppressWarnings("deprecation") @Override protected synchronized void finalize() throws Throwable { diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLEngineHelper.java b/src/java/com/wolfssl/provider/jsse/WolfSSLEngineHelper.java index 099cb75c..cff34248 100644 --- a/src/java/com/wolfssl/provider/jsse/WolfSSLEngineHelper.java +++ b/src/java/com/wolfssl/provider/jsse/WolfSSLEngineHelper.java @@ -495,7 +495,8 @@ protected synchronized void setCiphers(String[] suites) 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 @@ protected synchronized void setProtocols(String[] p) } } - this.params.setProtocols(WolfSSLUtil.sanitizeProtocols(p)); + this.params.setProtocols( + WolfSSLUtil.sanitizeProtocols(p, WolfSSL.TLS_VERSION.INVALID)); } /** @@ -541,7 +543,8 @@ protected synchronized void setProtocols(String[] p) * @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 @@ protected synchronized String[] getProtocols() { * @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 @@ private void setLocalProtocol(String[] p) } 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 @@ private void setLocalProtocol(String[] p) } } + /* Note: No SSL_OP_NO_* for DTLS in native wolfSSL */ if (set[0] == false) { mask |= WolfSSL.SSL_OP_NO_TLSv1_3; } @@ -1140,13 +1147,75 @@ private void setLocalSupportedCurves() throws SSLException { } } + 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 setLocalExtendedMasterSecret() { + /* Native wolfSSL enables TLS Extended Master Secret by default. + * Check the Java System property (jdk.tls.useExtendedMasterSecret) + * to see if the user has explicitly disabled it. */ + int ret; + boolean useEMS = WolfSSLUtil.useExtendedMasterSecret(); + + if (!useEMS) { + ret = this.ssl.disableExtendedMasterSecret(); + if (ret == WolfSSL.SSL_SUCCESS) { + WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, + "TLS Extended Master Secret disabled due to " + + "jdk.tls.useExtendedMasterSecret System property"); + } + else { + WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, + "Failed to disable TLS Extended Master Secret, " + + "ret = " + ret); + } + } + else { + if (WolfSSL.isEnabledTLSExtendedMasterSecret() == 1) { + WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, + "using TLS Extended Master Secret"); + } + else { + WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO, + "not using TLS Extended Master Secret, not compiled in"); + } + } + } + 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 +1223,8 @@ private void setLocalParams(SSLSocket socket, SSLEngine engine) this.setLocalSecureRenegotiation(); this.setLocalSigAlgorithms(); this.setLocalSupportedCurves(); + this.setLocalMaximumPacketSize(); + this.setLocalExtendedMasterSecret(); } /** diff --git a/src/java/com/wolfssl/provider/jsse/WolfSSLParameters.java b/src/java/com/wolfssl/provider/jsse/WolfSSLParameters.java index b7e79a36..8adc437f 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 @@ protected synchronized WolfSSLParameters copy() { 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 @@ void setApplicationProtocols(String[] protocols) { 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 33be2265..a2b34743 100644 --- a/src/java/com/wolfssl/provider/jsse/WolfSSLParametersHelper.java +++ b/src/java/com/wolfssl/provider/jsse/WolfSSLParametersHelper.java @@ -21,9 +21,11 @@ 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; +import com.wolfssl.provider.jsse.WolfSSLJDK8Helper; /** * WolfSSLParametersHelper class @@ -37,6 +39,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 +77,12 @@ public Object run() { case "setEndpointIdentificationAlgorithm": setEndpointIdentificationAlgorithm = m; continue; + case "getMaximumPacketSize": + getMaximumPacketSize = m; + continue; + case "setMaximumPacketSize": + setMaximumPacketSize = m; + continue; default: continue; } @@ -112,15 +122,17 @@ protected static SSLParameters decoupleParams(WolfSSLParameters in) { 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 +145,15 @@ protected static SSLParameters decoupleParams(WolfSSLParameters in) { 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 +161,18 @@ protected static SSLParameters decoupleParams(WolfSSLParameters in) { } } + /* 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 +218,15 @@ protected static void importParams(SSLParameters in, 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 +238,13 @@ protected static void importParams(SSLParameters in, 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 +253,19 @@ protected static void importParams(SSLParameters in, } } + /* 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 76fff4b4..a6aa1c3f 100644 --- a/src/java/com/wolfssl/provider/jsse/WolfSSLProvider.java +++ b/src/java/com/wolfssl/provider/jsse/WolfSSLProvider.java @@ -134,6 +134,10 @@ public WolfSSLProvider() { 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 fc9fe2cd..49d6e255 100644 --- a/src/java/com/wolfssl/provider/jsse/WolfSSLServerSocket.java +++ b/src/java/com/wolfssl/provider/jsse/WolfSSLServerSocket.java @@ -211,7 +211,8 @@ synchronized public String[] getSupportedProtocols() { 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 @@ synchronized public String[] getEnabledProtocols() { 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 @@ synchronized public void setEnabledProtocols(String[] protocols) List