JNI/JSSE: pass socket timeout to select() for wolfSSL_accept()
parent
15a1c90a8c
commit
3d6ceb09a3
|
@ -33,6 +33,11 @@
|
|||
#include <arpa/inet.h>
|
||||
#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/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
|
||||
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
|
||||
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jint timeout)
|
||||
{
|
||||
int ret = 0, err, sockfd;
|
||||
wolfSSL_Mutex* jniSessLock = NULL;
|
||||
|
@ -954,7 +959,7 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_accept
|
|||
break;
|
||||
}
|
||||
|
||||
ret = socketSelect(sockfd, 0, 1);
|
||||
ret = socketSelect(sockfd, (int)timeout, 1);
|
||||
if (ret == WOLFJNI_RECV_READY || ret == WOLFJNI_SEND_READY) {
|
||||
/* I/O ready, continue handshake and try again */
|
||||
continue;
|
||||
|
@ -1221,26 +1226,82 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_setSession
|
|||
{
|
||||
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
|
||||
WOLFSSL_SESSION* session = (WOLFSSL_SESSION*)(uintptr_t)sessionPtr;
|
||||
wolfSSL_Mutex* jniSessLock = NULL;
|
||||
SSLAppData* appData = NULL;
|
||||
int ret = 0;
|
||||
(void)jcl;
|
||||
|
||||
if (jenv == NULL || ssl == NULL) {
|
||||
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 */
|
||||
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
|
||||
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
|
||||
{
|
||||
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
|
||||
WOLFSSL_SESSION* sess = NULL;
|
||||
wolfSSL_Mutex* jniSessLock = NULL;
|
||||
SSLAppData* appData = NULL;
|
||||
(void)jenv;
|
||||
(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
|
||||
* 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
|
||||
|
@ -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
|
||||
* any app data, only session ticket internally */
|
||||
char tmpBuf[1];
|
||||
int ret = 0;
|
||||
int err = 0;
|
||||
int sockfd = 0;
|
||||
(void)jenv;
|
||||
(void)jcl;
|
||||
|
||||
|
@ -1281,8 +1345,32 @@ JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLSession_get1Session
|
|||
* session ticket message. */
|
||||
sess = wolfSSL_get_session(ssl);
|
||||
if (sess == NULL) {
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
|
|
@ -106,10 +106,10 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_read
|
|||
/*
|
||||
* Class: com_wolfssl_WolfSSLSession
|
||||
* Method: accept
|
||||
* Signature: (J)I
|
||||
* Signature: (JI)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_accept
|
||||
(JNIEnv *, jobject, jlong);
|
||||
(JNIEnv *, jobject, jlong, jint);
|
||||
|
||||
/*
|
||||
* Class: com_wolfssl_WolfSSLSession
|
||||
|
|
|
@ -212,7 +212,7 @@ public class WolfSSLSession {
|
|||
private native int connect(long ssl, 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 accept(long ssl);
|
||||
private native int accept(long ssl, int timeout);
|
||||
private native void freeSSL(long ssl);
|
||||
private native int shutdownSSL(long ssl, int timeout);
|
||||
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
|
||||
* 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() throws IllegalStateException {
|
||||
public int accept()
|
||||
throws IllegalStateException, SocketTimeoutException {
|
||||
|
||||
int ret;
|
||||
|
||||
confirmObjectIsActive();
|
||||
|
||||
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.
|
||||
* <p>
|
||||
* 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
|
||||
* a pointer to the session. Later, the application should create a new
|
||||
* SSL object and assign the saved session with <code>setSession</code>.
|
||||
|
|
|
@ -138,7 +138,12 @@ public class WolfSSLEngineHelper {
|
|||
* @return WolfSSLImplementSession for this object
|
||||
*/
|
||||
protected WolfSSLImplementSSLSession getSession() {
|
||||
|
||||
if (this.session == null) {
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||
"this.session is null, creating new " +
|
||||
"WolfSSLImplementSSLSession");
|
||||
|
||||
this.session = new WolfSSLImplementSSLSession(authStore);
|
||||
}
|
||||
return this.session;
|
||||
|
@ -795,7 +800,6 @@ public class WolfSSLEngineHelper {
|
|||
* or not.
|
||||
* @param timeout socket timeout (milliseconds) for connect(), or 0 for
|
||||
* infinite/no timeout.
|
||||
*
|
||||
* @return WolfSSL.SSL_SUCCESS on success or either WolfSSL.SSL_FAILURE
|
||||
* or WolfSSL.SSL_HANDSHAKE_FAILURE on error
|
||||
*
|
||||
|
@ -826,7 +830,7 @@ public class WolfSSLEngineHelper {
|
|||
|
||||
if ((this.session == null) || !this.session.isValid()) {
|
||||
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) {
|
||||
/* new handshakes can not be made in this case. */
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||
|
@ -834,7 +838,7 @@ public class WolfSSLEngineHelper {
|
|||
|
||||
return WolfSSL.SSL_HANDSHAKE_FAILURE;
|
||||
}
|
||||
this.session = this.authStore.getSession(ssl);
|
||||
this.session = this.authStore.getSession(ssl, this.clientMode);
|
||||
}
|
||||
|
||||
if (this.clientMode) {
|
||||
|
@ -863,7 +867,7 @@ public class WolfSSLEngineHelper {
|
|||
} else {
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||
"calling native wolfSSL_accept()");
|
||||
ret = this.ssl.accept();
|
||||
ret = this.ssl.accept(timeout);
|
||||
}
|
||||
err = ssl.getError(ret);
|
||||
|
||||
|
@ -871,32 +875,26 @@ public class WolfSSLEngineHelper {
|
|||
(err == WolfSSL.SSL_ERROR_WANT_READ ||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.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 this.authStore.addSession(this.session);
|
||||
}
|
||||
|
||||
return WolfSSL.SSL_FAILURE;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
|
|
Loading…
Reference in New Issue