JNI/JSSE: pass socket timeout to select() for wolfSSL_accept()
parent
15a1c90a8c
commit
3d6ceb09a3
|
@ -33,6 +33,11 @@
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef WOLFSSL_JNI_DEFAULT_PEEK_TIMEOUT
|
||||||
|
/* Default wolfSSL_peek() timeout for wolfSSL_get_session(), ms */
|
||||||
|
#define WOLFSSL_JNI_DEFAULT_PEEK_TIMEOUT 2000
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <wolfssl/ssl.h>
|
#include <wolfssl/ssl.h>
|
||||||
#include <wolfssl/error-ssl.h>
|
#include <wolfssl/error-ssl.h>
|
||||||
|
|
||||||
|
@ -898,7 +903,7 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_read(JNIEnv* jenv,
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_accept
|
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_accept
|
||||||
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
|
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jint timeout)
|
||||||
{
|
{
|
||||||
int ret = 0, err, sockfd;
|
int ret = 0, err, sockfd;
|
||||||
wolfSSL_Mutex* jniSessLock = NULL;
|
wolfSSL_Mutex* jniSessLock = NULL;
|
||||||
|
@ -954,7 +959,7 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_accept
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = socketSelect(sockfd, 0, 1);
|
ret = socketSelect(sockfd, (int)timeout, 1);
|
||||||
if (ret == WOLFJNI_RECV_READY || ret == WOLFJNI_SEND_READY) {
|
if (ret == WOLFJNI_RECV_READY || ret == WOLFJNI_SEND_READY) {
|
||||||
/* I/O ready, continue handshake and try again */
|
/* I/O ready, continue handshake and try again */
|
||||||
continue;
|
continue;
|
||||||
|
@ -1221,26 +1226,82 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_setSession
|
||||||
{
|
{
|
||||||
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
|
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
|
||||||
WOLFSSL_SESSION* session = (WOLFSSL_SESSION*)(uintptr_t)sessionPtr;
|
WOLFSSL_SESSION* session = (WOLFSSL_SESSION*)(uintptr_t)sessionPtr;
|
||||||
|
wolfSSL_Mutex* jniSessLock = NULL;
|
||||||
|
SSLAppData* appData = NULL;
|
||||||
|
int ret = 0;
|
||||||
(void)jcl;
|
(void)jcl;
|
||||||
|
|
||||||
if (jenv == NULL || ssl == NULL) {
|
if (jenv == NULL || ssl == NULL) {
|
||||||
return SSL_FAILURE;
|
return SSL_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* get session mutex from SSL app data */
|
||||||
|
appData = (SSLAppData*)wolfSSL_get_app_data(ssl);
|
||||||
|
if (appData == NULL) {
|
||||||
|
printf("Failed to get SSLAppData* in native setSession()\n");
|
||||||
|
return (jlong)0;
|
||||||
|
}
|
||||||
|
|
||||||
|
jniSessLock = appData->jniSessLock;
|
||||||
|
if (jniSessLock == NULL) {
|
||||||
|
printf("SSLAppData* NULL in native setSession()\n");
|
||||||
|
return (jlong)0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get WOLFSSL session I/O lock */
|
||||||
|
if (wc_LockMutex(jniSessLock) != 0) {
|
||||||
|
printf("Failed to lock native jniSessLock in setSession()");
|
||||||
|
return (jlong)0;
|
||||||
|
}
|
||||||
|
|
||||||
/* wolfSSL checks session for NULL, but not ssl */
|
/* wolfSSL checks session for NULL, but not ssl */
|
||||||
return wolfSSL_set_session(ssl, session);
|
ret = wolfSSL_set_session(ssl, session);
|
||||||
|
|
||||||
|
if (wc_UnLockMutex(jniSessLock) != 0) {
|
||||||
|
printf("Failed to unlock jniSessLock in setSession()");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLSession_getSession
|
JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLSession_getSession
|
||||||
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
|
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
|
||||||
{
|
{
|
||||||
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
|
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
|
||||||
|
WOLFSSL_SESSION* sess = NULL;
|
||||||
|
wolfSSL_Mutex* jniSessLock = NULL;
|
||||||
|
SSLAppData* appData = NULL;
|
||||||
(void)jenv;
|
(void)jenv;
|
||||||
(void)jcl;
|
(void)jcl;
|
||||||
|
|
||||||
|
/* get session mutex from SSL app data */
|
||||||
|
appData = (SSLAppData*)wolfSSL_get_app_data(ssl);
|
||||||
|
if (appData == NULL) {
|
||||||
|
printf("Failed to get SSLAppData* in native getSession()\n");
|
||||||
|
return (jlong)0;
|
||||||
|
}
|
||||||
|
|
||||||
|
jniSessLock = appData->jniSessLock;
|
||||||
|
if (jniSessLock == NULL) {
|
||||||
|
printf("SSLAppData* NULL in native getSession()\n");
|
||||||
|
return (jlong)0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get WOLFSSL session I/O lock */
|
||||||
|
if (wc_LockMutex(jniSessLock) != 0) {
|
||||||
|
printf("Failed to lock native jniSessLock in getSession()");
|
||||||
|
return (jlong)0;
|
||||||
|
}
|
||||||
|
|
||||||
/* wolfSSL checks ssl for NULL, returns pointer into WOLFSSL which is
|
/* wolfSSL checks ssl for NULL, returns pointer into WOLFSSL which is
|
||||||
* freed when wolfSSL_free() is called. */
|
* freed when wolfSSL_free() is called. */
|
||||||
return (jlong)(uintptr_t)wolfSSL_get_session(ssl);
|
sess = wolfSSL_get_session(ssl);
|
||||||
|
|
||||||
|
if (wc_UnLockMutex(jniSessLock) != 0) {
|
||||||
|
printf("Failed to unlock jniSessLock in getSession()");
|
||||||
|
}
|
||||||
|
|
||||||
|
return (jlong)(uintptr_t)sess;
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLSession_get1Session
|
JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLSession_get1Session
|
||||||
|
@ -1254,6 +1315,9 @@ JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLSession_get1Session
|
||||||
/* tmpBuf is only 1 byte since wolfSSL_peek() doesn't need to read
|
/* tmpBuf is only 1 byte since wolfSSL_peek() doesn't need to read
|
||||||
* any app data, only session ticket internally */
|
* any app data, only session ticket internally */
|
||||||
char tmpBuf[1];
|
char tmpBuf[1];
|
||||||
|
int ret = 0;
|
||||||
|
int err = 0;
|
||||||
|
int sockfd = 0;
|
||||||
(void)jenv;
|
(void)jenv;
|
||||||
(void)jcl;
|
(void)jcl;
|
||||||
|
|
||||||
|
@ -1281,8 +1345,32 @@ JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLSession_get1Session
|
||||||
* session ticket message. */
|
* session ticket message. */
|
||||||
sess = wolfSSL_get_session(ssl);
|
sess = wolfSSL_get_session(ssl);
|
||||||
if (sess == NULL) {
|
if (sess == NULL) {
|
||||||
|
|
||||||
/* session not available yet (TLS 1.3), try peeking to get ticket */
|
/* session not available yet (TLS 1.3), try peeking to get ticket */
|
||||||
wolfSSL_peek(ssl, tmpBuf, (int)sizeof(tmpBuf));
|
do {
|
||||||
|
ret = wolfSSL_peek(ssl, tmpBuf, (int)sizeof(tmpBuf));
|
||||||
|
err = wolfSSL_get_error(ssl, ret);
|
||||||
|
|
||||||
|
if (ret <= 0 && (err == SSL_ERROR_WANT_READ)) {
|
||||||
|
|
||||||
|
sockfd = wolfSSL_get_fd(ssl);
|
||||||
|
if (sockfd == -1) {
|
||||||
|
/* For I/O that does not use sockets, sockfd may be -1,
|
||||||
|
* skip try to call select() */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = socketSelect(sockfd,
|
||||||
|
(int)WOLFSSL_JNI_DEFAULT_PEEK_TIMEOUT, 1);
|
||||||
|
if (ret == WOLFJNI_RECV_READY || ret == WOLFJNI_SEND_READY) {
|
||||||
|
/* I/O ready, continue handshake and try again */
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
/* other error, continue on */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (err == SSL_ERROR_WANT_READ);
|
||||||
|
|
||||||
sess = wolfSSL_get_session(ssl);
|
sess = wolfSSL_get_session(ssl);
|
||||||
}
|
}
|
||||||
|
|
|
@ -106,10 +106,10 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_read
|
||||||
/*
|
/*
|
||||||
* Class: com_wolfssl_WolfSSLSession
|
* Class: com_wolfssl_WolfSSLSession
|
||||||
* Method: accept
|
* Method: accept
|
||||||
* Signature: (J)I
|
* Signature: (JI)I
|
||||||
*/
|
*/
|
||||||
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_accept
|
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_accept
|
||||||
(JNIEnv *, jobject, jlong);
|
(JNIEnv *, jobject, jlong, jint);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Class: com_wolfssl_WolfSSLSession
|
* Class: com_wolfssl_WolfSSLSession
|
||||||
|
|
|
@ -212,7 +212,7 @@ public class WolfSSLSession {
|
||||||
private native int connect(long ssl, int timeout);
|
private native int connect(long ssl, int timeout);
|
||||||
private native int write(long ssl, byte[] data, int length, int timeout);
|
private native int write(long ssl, byte[] data, int length, int timeout);
|
||||||
private native int read(long ssl, byte[] data, int sz, int timeout);
|
private native int read(long ssl, byte[] data, int sz, int timeout);
|
||||||
private native int accept(long ssl);
|
private native int accept(long ssl, int timeout);
|
||||||
private native void freeSSL(long ssl);
|
private native void freeSSL(long ssl);
|
||||||
private native int shutdownSSL(long ssl, int timeout);
|
private native int shutdownSSL(long ssl, int timeout);
|
||||||
private native int getError(long ssl, int ret);
|
private native int getError(long ssl, int ret);
|
||||||
|
@ -847,16 +847,76 @@ public class WolfSSLSession {
|
||||||
* </code> if an error occurred. To get a more detailed
|
* </code> if an error occurred. To get a more detailed
|
||||||
* error code, call <code>getError()</code>.
|
* error code, call <code>getError()</code>.
|
||||||
* @throws IllegalStateException WolfSSLContext has been freed
|
* @throws IllegalStateException WolfSSLContext has been freed
|
||||||
|
* @throws SocketTimeoutException if underlying socket timed out
|
||||||
* @see #getError(int)
|
* @see #getError(int)
|
||||||
* @see #connect()
|
* @see #connect()
|
||||||
*/
|
*/
|
||||||
public int accept() throws IllegalStateException {
|
public int accept()
|
||||||
|
throws IllegalStateException, SocketTimeoutException {
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
|
||||||
confirmObjectIsActive();
|
confirmObjectIsActive();
|
||||||
|
|
||||||
synchronized (sslLock) {
|
synchronized (sslLock) {
|
||||||
return accept(getSessionPtr());
|
ret = accept(getSessionPtr(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ret == WolfSSL.WOLFJNI_TIMEOUT) {
|
||||||
|
throw new SocketTimeoutException(
|
||||||
|
"Native socket timed out during SSL_accept()");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Waits for an SSL client to initiate the SSL/TLS handshake, using socket
|
||||||
|
* timeout value in milliseconds.
|
||||||
|
* This method is called on the server side. When it is called, the
|
||||||
|
* underlying communication channel has already been set up.
|
||||||
|
* <p>
|
||||||
|
* <code>accept()</code> works with both blocking and non-blocking I/O.
|
||||||
|
* When the underlying I/O is non-blocking, <code>accept()</code> will
|
||||||
|
* return when the underlying I/O could not satisfy the needs of
|
||||||
|
* <code>accept()</code> to continue the handshake. In this case, a call to
|
||||||
|
* <code>getError()</code> will yield either <b>SSL_ERROR_WANT_READ</b> or
|
||||||
|
* <b>SSL_ERROR_WANT_WRITE</b>. The calling process must then repeat the
|
||||||
|
* call to <code>accept()</code> when data is available to be read and
|
||||||
|
* wolfSSL will pick up where it left off. When using a non-blocking
|
||||||
|
* socket, nothing needs to be done, but <code>select()</code> can be used
|
||||||
|
* to check for the required condition.
|
||||||
|
* <p>
|
||||||
|
* If the underlying I/O is blocking, <code>accept()</code> will only
|
||||||
|
* return once the handshake has been finished or an error occurred.
|
||||||
|
*
|
||||||
|
* @param timeout read timeout, milliseconds.
|
||||||
|
*
|
||||||
|
* @return <code>SSL_SUCCESS</code> on success. <code>SSL_FATAL_ERROR
|
||||||
|
* </code> if an error occurred. To get a more detailed
|
||||||
|
* error code, call <code>getError()</code>.
|
||||||
|
* @throws IllegalStateException WolfSSLContext has been freed
|
||||||
|
* @throws SocketTimeoutException if underlying socket timed out
|
||||||
|
* @see #getError(int)
|
||||||
|
* @see #connect()
|
||||||
|
*/
|
||||||
|
public int accept(int timeout)
|
||||||
|
throws IllegalStateException, SocketTimeoutException {
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
confirmObjectIsActive();
|
||||||
|
|
||||||
|
synchronized (sslLock) {
|
||||||
|
ret = accept(getSessionPtr(), timeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret == WolfSSL.WOLFJNI_TIMEOUT) {
|
||||||
|
throw new SocketTimeoutException(
|
||||||
|
"Native socket timed out during SSL_accept()");
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1038,7 +1098,7 @@ public class WolfSSLSession {
|
||||||
* the connection without a new handshake.
|
* the connection without a new handshake.
|
||||||
* <p>
|
* <p>
|
||||||
* For session resumption, before calling <code>shutdownSSL()</code>
|
* For session resumption, before calling <code>shutdownSSL()</code>
|
||||||
* with your session object, an appliation should save the session ID
|
* with your session object, an application should save the session ID
|
||||||
* from the object with a call to <code>getSession()</code>, which returns
|
* from the object with a call to <code>getSession()</code>, which returns
|
||||||
* a pointer to the session. Later, the application should create a new
|
* a pointer to the session. Later, the application should create a new
|
||||||
* SSL object and assign the saved session with <code>setSession</code>.
|
* SSL object and assign the saved session with <code>setSession</code>.
|
||||||
|
|
|
@ -138,7 +138,12 @@ public class WolfSSLEngineHelper {
|
||||||
* @return WolfSSLImplementSession for this object
|
* @return WolfSSLImplementSession for this object
|
||||||
*/
|
*/
|
||||||
protected WolfSSLImplementSSLSession getSession() {
|
protected WolfSSLImplementSSLSession getSession() {
|
||||||
|
|
||||||
if (this.session == null) {
|
if (this.session == null) {
|
||||||
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||||
|
"this.session is null, creating new " +
|
||||||
|
"WolfSSLImplementSSLSession");
|
||||||
|
|
||||||
this.session = new WolfSSLImplementSSLSession(authStore);
|
this.session = new WolfSSLImplementSSLSession(authStore);
|
||||||
}
|
}
|
||||||
return this.session;
|
return this.session;
|
||||||
|
@ -795,7 +800,6 @@ public class WolfSSLEngineHelper {
|
||||||
* or not.
|
* or not.
|
||||||
* @param timeout socket timeout (milliseconds) for connect(), or 0 for
|
* @param timeout socket timeout (milliseconds) for connect(), or 0 for
|
||||||
* infinite/no timeout.
|
* infinite/no timeout.
|
||||||
*
|
|
||||||
* @return WolfSSL.SSL_SUCCESS on success or either WolfSSL.SSL_FAILURE
|
* @return WolfSSL.SSL_SUCCESS on success or either WolfSSL.SSL_FAILURE
|
||||||
* or WolfSSL.SSL_HANDSHAKE_FAILURE on error
|
* or WolfSSL.SSL_HANDSHAKE_FAILURE on error
|
||||||
*
|
*
|
||||||
|
@ -826,7 +830,7 @@ public class WolfSSLEngineHelper {
|
||||||
|
|
||||||
if ((this.session == null) || !this.session.isValid()) {
|
if ((this.session == null) || !this.session.isValid()) {
|
||||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||||
"session is marked as invalid, try creating a new seesion");
|
"session is marked as invalid, try creating a new session");
|
||||||
if (this.sessionCreation == false) {
|
if (this.sessionCreation == false) {
|
||||||
/* new handshakes can not be made in this case. */
|
/* new handshakes can not be made in this case. */
|
||||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||||
|
@ -834,7 +838,7 @@ public class WolfSSLEngineHelper {
|
||||||
|
|
||||||
return WolfSSL.SSL_HANDSHAKE_FAILURE;
|
return WolfSSL.SSL_HANDSHAKE_FAILURE;
|
||||||
}
|
}
|
||||||
this.session = this.authStore.getSession(ssl);
|
this.session = this.authStore.getSession(ssl, this.clientMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.clientMode) {
|
if (this.clientMode) {
|
||||||
|
@ -863,7 +867,7 @@ public class WolfSSLEngineHelper {
|
||||||
} else {
|
} else {
|
||||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||||
"calling native wolfSSL_accept()");
|
"calling native wolfSSL_accept()");
|
||||||
ret = this.ssl.accept();
|
ret = this.ssl.accept(timeout);
|
||||||
}
|
}
|
||||||
err = ssl.getError(ret);
|
err = ssl.getError(ret);
|
||||||
|
|
||||||
|
@ -871,32 +875,26 @@ public class WolfSSLEngineHelper {
|
||||||
(err == WolfSSL.SSL_ERROR_WANT_READ ||
|
(err == WolfSSL.SSL_ERROR_WANT_READ ||
|
||||||
err == WolfSSL.SSL_ERROR_WANT_WRITE));
|
err == WolfSSL.SSL_ERROR_WANT_WRITE));
|
||||||
|
|
||||||
if (this.sessionCreation && ret == WolfSSL.SSL_SUCCESS) {
|
|
||||||
/* can only add new sessions to the resumption table if session
|
|
||||||
* creation is allowed */
|
|
||||||
if (this.clientMode) {
|
|
||||||
/* Only need to set resume on client side, server-side
|
|
||||||
* maintains session cache at native level. */
|
|
||||||
this.session.setResume();
|
|
||||||
}
|
|
||||||
this.authStore.addSession(this.session);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saves session on connection close for resumption
|
* Saves session on connection close for resumption
|
||||||
|
*
|
||||||
|
* @return WolfSSL.SSL_SUCCESS if session was saved into cache, otherwise
|
||||||
|
* WolfSSL.SSL_FAILURE
|
||||||
*/
|
*/
|
||||||
protected synchronized void saveSession() {
|
protected synchronized int saveSession() {
|
||||||
if (this.session != null && this.session.isValid()) {
|
if (this.session != null && this.session.isValid()) {
|
||||||
if (this.clientMode) {
|
if (this.clientMode) {
|
||||||
/* Only need to set resume on client side, server-side
|
/* Only need to set resume on client side, server-side
|
||||||
* maintains session cache at native level. */
|
* maintains session cache at native level. */
|
||||||
this.session.setResume();
|
this.session.setResume();
|
||||||
}
|
}
|
||||||
this.authStore.addSession(this.session);
|
return this.authStore.addSession(this.session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return WolfSSL.SSL_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
|
|
Loading…
Reference in New Issue