JSSE: only resume sessions from Java client cache if same cipher suite and protocol are enabled
parent
4e70b6827d
commit
7231009800
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -183,6 +183,14 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_wolfsslSessionIsResumable
|
|||
JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLSession_wolfsslSessionDup
|
||||
(JNIEnv *, jclass, jlong);
|
||||
|
||||
/*
|
||||
* Class: com_wolfssl_WolfSSLSession
|
||||
* Method: wolfsslSessionCipherGetName
|
||||
* Signature: (J)Ljava/lang/String;
|
||||
*/
|
||||
JNIEXPORT jstring JNICALL Java_com_wolfssl_WolfSSLSession_wolfsslSessionCipherGetName
|
||||
(JNIEnv *, jclass, jlong);
|
||||
|
||||
/*
|
||||
* Class: com_wolfssl_WolfSSLSession
|
||||
* Method: freeNativeSession
|
||||
|
|
|
@ -260,6 +260,7 @@ public class WolfSSLSession {
|
|||
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 class WolfSSLSession {
|
|||
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.
|
||||
*
|
||||
|
|
|
@ -296,13 +296,24 @@ public class WolfSSLAuthStore {
|
|||
* @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 @@ public class WolfSSLAuthStore {
|
|||
* 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 @@ public class WolfSSLAuthStore {
|
|||
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 @@ public class WolfSSLAuthStore {
|
|||
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,
|
||||
|
|
|
@ -1199,7 +1199,7 @@ public class WolfSSLEngineHelper {
|
|||
|
||||
/* 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 @@ public class WolfSSLEngineHelper {
|
|||
(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 @@ public class WolfSSLEngineHelper {
|
|||
*/
|
||||
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. */
|
||||
|
|
|
@ -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 class WolfSSLImplementSSLSession extends ExtendedSSLSession
|
|||
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 class WolfSSLImplementSSLSession extends ExtendedSSLSession
|
|||
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 class WolfSSLImplementSSLSession extends ExtendedSSLSession
|
|||
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 class WolfSSLImplementSSLSession extends ExtendedSSLSession
|
|||
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 class WolfSSLImplementSSLSession extends ExtendedSSLSession
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized String getProtocol() {
|
||||
if (ssl == null) {
|
||||
return this.nullProtocol;
|
||||
}
|
||||
|
||||
try {
|
||||
return this.ssl.getVersion();
|
||||
} catch (IllegalStateException | WolfSSLJNIException ex) {
|
||||
Logger.getLogger(
|
||||
WolfSSLImplementSSLSession.class.getName()).log(
|
||||
Level.SEVERE, null, ex);
|
||||
}
|
||||
return null;
|
||||
return this.protocol;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -816,6 +824,20 @@ public class WolfSSLImplementSSLSession extends ExtendedSSLSession
|
|||
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");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue