Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JSSE: Session resumption check for enabled cipher suite and protocol #209

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions native/com_wolfssl_WolfSSLSession.c
Original file line number Diff line number Diff line change
@@ -1733,6 +1733,27 @@ JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLSession_wolfsslSessionDup
return (jlong)(uintptr_t)wolfSSL_SESSION_dup(session);
}

JNIEXPORT jstring JNICALL Java_com_wolfssl_WolfSSLSession_wolfsslSessionCipherGetName
(JNIEnv* jenv, jclass jcl, jlong sessionPtr)
{
WOLFSSL_SESSION* session = (WOLFSSL_SESSION*)(uintptr_t)sessionPtr;
const char* cipherName;
jstring cipherStr = NULL;
(void)jcl;

if (jenv == NULL || session == NULL) {
return NULL;
}

cipherName = wolfSSL_SESSION_CIPHER_get_name(session);

if (cipherName != NULL) {
cipherStr = (*jenv)->NewStringUTF(jenv, cipherName);
}

return cipherStr;
}

JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLSession_freeNativeSession
(JNIEnv* jenv, jclass jcl, jlong sessionPtr)
{
8 changes: 8 additions & 0 deletions native/com_wolfssl_WolfSSLSession.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 24 additions & 0 deletions src/java/com/wolfssl/WolfSSLSession.java
Original file line number Diff line number Diff line change
@@ -260,6 +260,7 @@ private native int read(long ssl, byte[] data, int offset, int sz,
private static native int wolfsslSessionIsSetup(long ssl);
private static native int wolfsslSessionIsResumable(long ssl);
private static native long wolfsslSessionDup(long session);
private static native String wolfsslSessionCipherGetName(long ssl);
private static native void freeNativeSession(long session);
private native byte[] getSessionID(long session);
private native int setServerID(long ssl, byte[] id, int len, int newSess);
@@ -1389,6 +1390,29 @@ public static long duplicateSession(long session) {
return wolfsslSessionDup(session);
}

/**
* Get cipher suite name from WOLFSSL_SESSION, calling native
* wolfSSL_SESSION_CIPHER_get_name().
*
* This method is static and does not check active state since this
* takes a native pointer and has no interaction with the rest of this
* object.
*
* @param session pointer to native WOLFSSL_SESSION structure. May have
* been obtained from getSession().
* @return String representation of the cipher suite used in native
* WOLFSSL_SESSION structure, or NULL if not able to find the
* session.
*/
public static String sessionGetCipherName(long session) {

if (session == 0) {
return null;
}

return wolfsslSessionCipherGetName(session);
}

/**
* Free the native WOLFSSL_SESSION structure pointed to be session.
*
173 changes: 139 additions & 34 deletions src/java/com/wolfssl/provider/jsse/WolfSSLAuthStore.java
Original file line number Diff line number Diff line change
@@ -296,13 +296,24 @@ protected void resizeCache(int sz, int side) {
* @param port port number of peer being connected to
* @param host host of the peer being connected to
* @param clientMode if is client side then true, otherwise false
* @param enabledCipherSuites String array containing enabled cipher
* suites for the SSLSocket/SSLEngine requesting this session.
* Used to compare cipher suite of cached session against enabled
* cipher suites.
* @param enabledProtocols String array containing enabled protocols
* for the SSLSocket/SSLEngine requesting this session.
* Used to compare protocol of cached session against enabled
* protocols.
*
* @return an existing SSLSession from Java session cache, or a new
* object if not in cache, called on server side, or host
* is null
*/
protected synchronized WolfSSLImplementSSLSession getSession(
WolfSSLSession ssl, int port, String host, boolean clientMode) {
WolfSSLSession ssl, int port, String host, boolean clientMode,
String[] enabledCipherSuites, String[] enabledProtocols) {

boolean needNewSession = false;
WolfSSLImplementSSLSession ses = null;
String toHash = null;

@@ -327,16 +338,51 @@ protected synchronized WolfSSLImplementSSLSession getSession(
* is shared between all threads */
synchronized (storeLock) {

/* generate cache key hash (host:port) */
/* Generate cache key hash (host:port) */
toHash = host.concat(Integer.toString(port));

/* try getting session out of Java store */
/* Try getting session out of Java store */
ses = store.get(toHash.hashCode());

if (ses == null) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"session not found in cache table, creating new");
/* not found in stored sessions create a new one */
/* Remove old entry from table. TLS 1.3 binder changes between
* resumptions and stored session should only be used to
* resume once. New session structure/object will be cached
* after the resumed session completes the handshake, for
* subsequent resumption attempts to use. */
store.remove(toHash.hashCode());

/* Check conditions where we need to create a new new session:
* 1. Session not found in cache
* 2. Session marked as not resumable
* 3. Original session cipher suite not available
* 4. Original session protocol version not available
*/
if (ses == null ||
!ses.isResumable() ||
!sessionCipherSuiteAvailable(ses, enabledCipherSuites) ||
!sessionProtocolAvailable(ses, enabledProtocols)) {
needNewSession = true;
}

if (needNewSession) {
if (ses == null) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"session not found in cache table, " +
"creating new session");
}
else if (!ses.isResumable()) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"native WOLFSSL_SESSION not resumable, " +
"creating new session");
}
else if (!sessionCipherSuiteAvailable(
ses, enabledCipherSuites)) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"cipher suite used in original WOLFSSL_SESSION not " +
"available, creating new session");
}

/* Not found in stored sessions create a new one */
ses = new WolfSSLImplementSSLSession(ssl, port, host, this);
ses.setValid(true); /* new sessions marked as valid */

@@ -345,35 +391,11 @@ protected synchronized WolfSSLImplementSSLSession getSession(
Integer.toString(ssl.hashCode()).getBytes());
}
else {
/* Remove old entry from table. TLS 1.3 binder changes between
* resumptions and stored session should only be used to
* resume once. New session structure/object will be cached
* after the resumed session completes the handshake, for
* subsequent resumption attempts to use. */
store.remove(toHash.hashCode());

/* Check if native WOLFSSL_SESSION is resumable before
* returning it for resumption. If not, create a new
* session instead. */
if (!ses.isResumable()) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"native WOLFSSL_SESSION not resumable, " +
"creating new session");
ses = new WolfSSLImplementSSLSession(ssl, port, host, this);
ses.setValid(true); /* new sessions marked as valid */

ses.isFromTable = false;
ses.setPseudoSessionId(
Integer.toString(ssl.hashCode()).getBytes());

return ses;
}

ses.isFromTable = true;

WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"session found in cache, trying to resume");

ses.isFromTable = true;

if (ses.resume(ssl) != WolfSSL.SSL_SUCCESS) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"native wolfSSL_set_session() failed, " +
@@ -384,13 +406,96 @@ protected synchronized WolfSSLImplementSSLSession getSession(
ses.isFromTable = false;
ses.setPseudoSessionId(
Integer.toString(ssl.hashCode()).getBytes());

}
}

return ses;
}
}

/**
* Check if cipher suite from original WOLFSSL_SESSION
* (WolfSSLImplementSSLSession) is available in new WolfSSLSession
* WolfSSLParameters.
*
* This is used in getSession(), since if we try resuming an old session
* but the cipher suite used in that session is not available in the
* ClientHello, the server will close the connection and send back an
* alert. If wolfSSL on the server side, this will be an illegal_parameter
* alert.
*
* @param ses WolfSSLImplementSSLSession to get existing cipher suite from
* to check.
* @param enabledCipherSuites cipher suites enabled, usually coming from
* WolfSSLEngineHelper.getCiphers().
*
* @return true if cipher suite from session is available in
* WolfSSLParameters enabled suites, otherwise false.
*/
private boolean sessionCipherSuiteAvailable(WolfSSLImplementSSLSession ses,
String[] enabledCipherSuites) {

String sessionCipher = null;

if (ses == null || enabledCipherSuites == null) {
return false;
}

sessionCipher = ses.getSessionCipherSuite();

if (Arrays.asList(enabledCipherSuites).contains(sessionCipher)) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"WOLFSSL_SESSION cipher suite available in enabled ciphers");
return true;
}

WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"WOLFSSL_SESSION cipher suite (" + sessionCipher + ") differs " +
"from enabled suites list");

return false;
}

/**
* Check if protocol from original WOLFSSL_SESSION
* (WolfSSLImplementSSLSession) is available in new WolfSSLSession
* WolfSSLParameters.
*
* @param ses WolfSSLImplementSSLSession to get existing protocol from
* to check
* @param enabledProtocols protocols enabled on this SSLSocket/SSLEngine,
* usually coming from WolfSSLEngineHelper.getProtocols().
*
* @return true if protocol from session is available in WolfSSLParameters
* enabled protocols, otherwise false.
*/
private boolean sessionProtocolAvailable(WolfSSLImplementSSLSession ses,
String[] enabledProtocols) {

String sessionProtocol = null;

if (ses == null || enabledProtocols == null) {
return false;
}

sessionProtocol = ses.getProtocol();
if (sessionProtocol == null) {
return false;
}

if (Arrays.asList(enabledProtocols).contains(sessionProtocol)) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"WOLFSSL_SESSION protocol available in enabled protocols");
return true;
}

WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"WOLFSSL_SESSION protocol (" + sessionProtocol + ") differs " +
"from enabled protocol list: " + Arrays.asList(enabledProtocols));

return false;
}

/**
* Print summary of current SessionStore (LinkedHashMap) status.
* Prints out size of current SessionStore. If size is greater than zero,
11 changes: 10 additions & 1 deletion src/java/com/wolfssl/provider/jsse/WolfSSLEngineHelper.java
Original file line number Diff line number Diff line change
@@ -1199,7 +1199,7 @@ private void initHandshakeInternal(SSLSocket socket, SSLEngine engine)

/* create non null session */
this.session = this.authStore.getSession(ssl, this.port,
sessCacheHostname, this.clientMode);
sessCacheHostname, this.clientMode, getCiphers(), getProtocols());

if (this.session != null) {
if (this.clientMode) {
@@ -1345,6 +1345,11 @@ else if (peerAddr != null) {
(err == WolfSSL.SSL_ERROR_WANT_READ ||
err == WolfSSL.SSL_ERROR_WANT_WRITE));

/* Update cached values in WolfSSLImplementSSLSession from
* WolfSSLSession, in case that goes out of scope and is garbage
* collected (ex: protocol version). */
this.session.updateStoredSessionValues();

return ret;
}

@@ -1385,6 +1390,10 @@ protected synchronized void unsetVerifyCallback() {
*/
protected synchronized int saveSession() {
if (this.session != null && this.session.isValid()) {
/* Update values from WOLFSSL which are stored in
* WolfSSLImplementSSLSession (ex: protocol) */
this.session.updateStoredSessionValues();

if (this.clientMode) {
/* Only need to set resume on client side, server-side
* maintains session cache at native level. */
46 changes: 34 additions & 12 deletions src/java/com/wolfssl/provider/jsse/WolfSSLImplementSSLSession.java
Original file line number Diff line number Diff line change
@@ -66,6 +66,7 @@ public class WolfSSLImplementSSLSession extends ExtendedSSLSession
private final HashMap<String, Object> binding;
private final int port;
private final String host;
String protocol = null;
Date creation = null;
Date accessed = null; /* when new connection was made using session */
byte[] pseudoSessionID = null; /* used with TLS 1.3*/
@@ -130,6 +131,7 @@ public WolfSSLImplementSSLSession (WolfSSLSession in, int port, String host,
this.valid = false; /* flag if joining or resuming session is allowed */
this.peerCerts = null;
this.sesPtr = 0;
this.protocol = this.nullProtocol;
binding = new HashMap<String, Object>();

creation = new Date();
@@ -154,6 +156,7 @@ public WolfSSLImplementSSLSession (WolfSSLSession in,
this.valid = false; /* flag if joining or resuming session is allowed */
this.peerCerts = null;
this.sesPtr = 0;
this.protocol = this.nullProtocol;
binding = new HashMap<String, Object>();

creation = new Date();
@@ -175,6 +178,7 @@ public WolfSSLImplementSSLSession (WolfSSLAuthStore params) {
this.valid = false; /* flag if joining or resuming session is allowed */
this.peerCerts = null;
this.sesPtr = 0;
this.protocol = this.nullProtocol;
binding = new HashMap<String, Object>();

creation = new Date();
@@ -224,6 +228,8 @@ public WolfSSLImplementSSLSession (WolfSSLImplementSSLSession orig) {
if (orig.peerCerts != null) {
this.peerCerts = orig.peerCerts.clone();
}
this.protocol = orig.protocol;

/* This session has been copied and is therefore not inside the
* WolfSSLAuthStore session cache table currently */
this.isInTable = false;
@@ -690,20 +696,22 @@ public synchronized String getCipherSuite() {
return null;
}

@Override
public synchronized String getProtocol() {
if (ssl == null) {
return this.nullProtocol;
/**
* Return the cipher suite from the native WOLFSSL_SESSION structure.
*
* @return String representation of the cipher suite from the native
* WOLFSSL_SESSION structure, or NULL if not able to be
* retrieved.
*/
public synchronized String getSessionCipherSuite() {
synchronized (sesPtrLock) {
return WolfSSLSession.sessionGetCipherName(this.sesPtr);
}
}

try {
return this.ssl.getVersion();
} catch (IllegalStateException | WolfSSLJNIException ex) {
Logger.getLogger(
WolfSSLImplementSSLSession.class.getName()).log(
Level.SEVERE, null, ex);
}
return null;
@Override
public synchronized String getProtocol() {
return this.protocol;
}

@Override
@@ -816,6 +824,20 @@ protected synchronized void setResume() {
this.sesPtrUpdatedAfterTable = true;
}
}

/* Update cached values in this SSLSession from WolfSSLSession,
* in case that goes out of scope and is garbage collected. */
updateStoredSessionValues();
}
}

protected synchronized void updateStoredSessionValues() {

try {
this.protocol = this.ssl.getVersion();
} catch (IllegalStateException | WolfSSLJNIException ex) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"Not able to update stored WOLFSSL protocol");
}
}