Merge pull request #274 from cconlon/WolfSSLAuthStoreLock
Reduce synchronization overhead in WolfSSLAuthStoremaster
commit
b85d4a18a4
|
@ -548,9 +548,13 @@ public class WolfSSLDebug {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if debug logging is enabled for the specified component
|
* Check if debug logging is enabled for the specified component.
|
||||||
|
*
|
||||||
|
* @param component the component to check (JNI or JSSE)
|
||||||
|
*
|
||||||
|
* @return true if debug logging is enabled for the component,
|
||||||
*/
|
*/
|
||||||
private static boolean isDebugEnabled(Component component) {
|
public static boolean isDebugEnabled(Component component) {
|
||||||
if (component == Component.JSSE && DEBUG) {
|
if (component == Component.JSSE && DEBUG) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -314,13 +314,14 @@ public class WolfSSLAuthStore {
|
||||||
* object if not in cache, called on server side, or host
|
* object if not in cache, called on server side, or host
|
||||||
* is null
|
* is null
|
||||||
*/
|
*/
|
||||||
protected synchronized WolfSSLImplementSSLSession getSession(
|
protected WolfSSLImplementSSLSession getSession(
|
||||||
WolfSSLSession ssl, int port, String host, boolean clientMode,
|
WolfSSLSession ssl, int port, String host, boolean clientMode,
|
||||||
String[] enabledCipherSuites, String[] enabledProtocols) {
|
String[] enabledCipherSuites, String[] enabledProtocols) {
|
||||||
|
|
||||||
boolean needNewSession = false;
|
boolean needNewSession = false;
|
||||||
WolfSSLImplementSSLSession ses = null;
|
WolfSSLImplementSSLSession ses = null;
|
||||||
String toHash = null;
|
String toHash = null;
|
||||||
|
int hashCode = 0;
|
||||||
|
|
||||||
if (ssl == null) {
|
if (ssl == null) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -339,104 +340,106 @@ public class WolfSSLAuthStore {
|
||||||
* Synchronizes on storeLock internally. */
|
* Synchronizes on storeLock internally. */
|
||||||
printSessionStoreStatus();
|
printSessionStoreStatus();
|
||||||
|
|
||||||
/* Lock on static/global storeLock, since Java session cache table
|
/* Generate cache key hash (host:port), outside lock */
|
||||||
* is shared between all threads */
|
toHash = host.concat(Integer.toString(port));
|
||||||
|
hashCode = toHash.hashCode();
|
||||||
|
|
||||||
|
/* Lock on static/global storeLock while getting session out of
|
||||||
|
* store, since Java session cache table is shared between all
|
||||||
|
* threads */
|
||||||
synchronized (storeLock) {
|
synchronized (storeLock) {
|
||||||
|
|
||||||
/* 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());
|
ses = store.get(hashCode);
|
||||||
|
|
||||||
/* Remove old entry from table. TLS 1.3 binder changes between
|
/* Remove old entry from table. TLS 1.3 binder changes between
|
||||||
* resumptions and stored session should only be used to
|
* resumptions and stored session should only be used to
|
||||||
* resume once. New session structure/object will be cached
|
* resume once. New session structure/object will be cached
|
||||||
* after the resumed session completes the handshake, for
|
* after the resumed session completes the handshake, for
|
||||||
* subsequent resumption attempts to use. */
|
* subsequent resumption attempts to use. */
|
||||||
store.remove(toHash.hashCode());
|
store.remove(hashCode);
|
||||||
|
}
|
||||||
|
|
||||||
/* Check conditions where we need to create a new new session:
|
/* Check conditions where we need to create a new new session:
|
||||||
* 1. Session not found in cache
|
* 1. Session not found in cache
|
||||||
* 2. Session marked as not resumable
|
* 2. Session marked as not resumable
|
||||||
* 3. Original session cipher suite not available
|
* 3. Original session cipher suite not available
|
||||||
* 4. Original session protocol version not available
|
* 4. Original session protocol version not available
|
||||||
*/
|
*/
|
||||||
if (ses == null ||
|
if (ses == null ||
|
||||||
!ses.isResumable() ||
|
!ses.isResumable() ||
|
||||||
!sessionCipherSuiteAvailable(ses, enabledCipherSuites) ||
|
!sessionCipherSuiteAvailable(ses, enabledCipherSuites) ||
|
||||||
!sessionProtocolAvailable(ses, enabledProtocols)) {
|
!sessionProtocolAvailable(ses, enabledProtocols)) {
|
||||||
needNewSession = true;
|
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");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needNewSession) {
|
/* Not found in stored sessions create a new one */
|
||||||
if (ses == null) {
|
ses = new WolfSSLImplementSSLSession(ssl, port, host, this);
|
||||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
ses.setValid(true); /* new sessions marked as valid */
|
||||||
() -> "session not found in cache table, " +
|
|
||||||
"creating new session");
|
ses.isFromTable = false;
|
||||||
}
|
ses.setPseudoSessionId(
|
||||||
else if (!ses.isResumable()) {
|
Integer.toString(ssl.hashCode()).getBytes());
|
||||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
}
|
||||||
() -> "native WOLFSSL_SESSION not resumable, " +
|
else {
|
||||||
"creating new session");
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||||
}
|
() -> "session found in cache, trying to resume");
|
||||||
else if (!sessionCipherSuiteAvailable(
|
|
||||||
ses, enabledCipherSuites)) {
|
ses.isFromTable = true;
|
||||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
|
||||||
() -> "cipher suite used in original WOLFSSL_SESSION " +
|
/* Check if the session has stored SNI server names */
|
||||||
"not available, creating new session");
|
List<SNIServerName> sniNames = ses.getSNIServerNames();
|
||||||
}
|
if (sniNames != null && !sniNames.isEmpty()) {
|
||||||
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||||
|
() -> "Found SNI server names in cached session");
|
||||||
|
|
||||||
|
/* Apply SNI settings to the SSL connection */
|
||||||
|
for (SNIServerName name : sniNames) {
|
||||||
|
if (name instanceof SNIHostName) {
|
||||||
|
String hostName = ((SNIHostName)name).getAsciiName();
|
||||||
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||||
|
() -> "Applying SNI hostname for resumption: " +
|
||||||
|
hostName);
|
||||||
|
|
||||||
|
/* Set the SNI directly on the SSL object */
|
||||||
|
ssl.useSNI((byte)WolfSSL.WOLFSSL_SNI_HOST_NAME,
|
||||||
|
hostName.getBytes());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ses.resume(ssl) != WolfSSL.SSL_SUCCESS) {
|
||||||
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||||
|
() -> "native wolfSSL_set_session() failed, " +
|
||||||
|
"creating new session");
|
||||||
|
|
||||||
/* Not found in stored sessions create a new one */
|
|
||||||
ses = new WolfSSLImplementSSLSession(ssl, port, host, this);
|
ses = new WolfSSLImplementSSLSession(ssl, port, host, this);
|
||||||
ses.setValid(true); /* new sessions marked as valid */
|
ses.setValid(true);
|
||||||
|
|
||||||
ses.isFromTable = false;
|
ses.isFromTable = false;
|
||||||
ses.setPseudoSessionId(
|
ses.setPseudoSessionId(
|
||||||
Integer.toString(ssl.hashCode()).getBytes());
|
Integer.toString(ssl.hashCode()).getBytes());
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
|
||||||
() -> "session found in cache, trying to resume");
|
|
||||||
|
|
||||||
ses.isFromTable = true;
|
|
||||||
|
|
||||||
/* Check if the session has stored SNI server names */
|
|
||||||
List<SNIServerName> sniNames = ses.getSNIServerNames();
|
|
||||||
if (sniNames != null && !sniNames.isEmpty()) {
|
|
||||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
|
||||||
() -> "Found SNI server names in cached session");
|
|
||||||
|
|
||||||
/* Apply SNI settings to the SSL connection */
|
|
||||||
for (SNIServerName name : sniNames) {
|
|
||||||
if (name instanceof SNIHostName) {
|
|
||||||
String hostName = ((SNIHostName)name).getAsciiName();
|
|
||||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
|
||||||
() -> "Applying SNI hostname for resumption: " +
|
|
||||||
hostName);
|
|
||||||
|
|
||||||
/* Set the SNI directly on the SSL object */
|
|
||||||
ssl.useSNI((byte)WolfSSL.WOLFSSL_SNI_HOST_NAME,
|
|
||||||
hostName.getBytes());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ses.resume(ssl) != WolfSSL.SSL_SUCCESS) {
|
|
||||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
|
||||||
() -> "native wolfSSL_set_session() failed, " +
|
|
||||||
"creating new session");
|
|
||||||
|
|
||||||
ses = new WolfSSLImplementSSLSession(ssl, port, host, this);
|
|
||||||
ses.setValid(true);
|
|
||||||
ses.isFromTable = false;
|
|
||||||
ses.setPseudoSessionId(
|
|
||||||
Integer.toString(ssl.hashCode()).getBytes());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ses;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ses;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -531,6 +534,11 @@ public class WolfSSLAuthStore {
|
||||||
* prints out host:port of all sessions stored in the store.
|
* prints out host:port of all sessions stored in the store.
|
||||||
* Called by getSession(). */
|
* Called by getSession(). */
|
||||||
private void printSessionStoreStatus() {
|
private void printSessionStoreStatus() {
|
||||||
|
|
||||||
|
if (!WolfSSLDebug.isDebugEnabled(WolfSSLDebug.Component.JSSE)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
synchronized (storeLock) {
|
synchronized (storeLock) {
|
||||||
Collection<WolfSSLImplementSSLSession> values =
|
Collection<WolfSSLImplementSSLSession> values =
|
||||||
store.values();
|
store.values();
|
||||||
|
@ -640,39 +648,41 @@ public class WolfSSLAuthStore {
|
||||||
return WolfSSL.SSL_FAILURE;
|
return WolfSSL.SSL_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Lock access to store while adding new session, store is global */
|
if (session.getPeerHost() != null) {
|
||||||
synchronized (storeLock) {
|
/* Generate key for storing into session table (host:port) */
|
||||||
if (session.getPeerHost() != null) {
|
toHash = session.getPeerHost().concat(Integer.toString(
|
||||||
/* Generate key for storing into session table (host:port) */
|
session.getPeerPort()));
|
||||||
toHash = session.getPeerHost().concat(Integer.toString(
|
hashCode = toHash.hashCode();
|
||||||
session.getPeerPort()));
|
}
|
||||||
hashCode = toHash.hashCode();
|
else {
|
||||||
|
/* If no peer host is available then create hash key from
|
||||||
|
* session ID if not null, not zero length, and not all zeros */
|
||||||
|
byte[] sessionId = session.getId();
|
||||||
|
if (sessionId != null && sessionId.length > 0 &&
|
||||||
|
(idAllZeros(sessionId) == false)) {
|
||||||
|
hashCode = Arrays.toString(session.getId()).hashCode();
|
||||||
|
} else {
|
||||||
|
hashCode = 0;
|
||||||
}
|
}
|
||||||
else {
|
}
|
||||||
/* If no peer host is available then create hash key from
|
|
||||||
* session ID if not null, not zero length, and not all zeros */
|
/* Always try to store session into cache table, as long as we
|
||||||
byte[] sessionId = session.getId();
|
* have a hashCode. If session already exists for hashCode, it
|
||||||
if (sessionId != null && sessionId.length > 0 &&
|
* will be overwritten with new/refreshed version */
|
||||||
(idAllZeros(sessionId) == false)) {
|
if (hashCode != 0) {
|
||||||
hashCode = Arrays.toString(session.getId()).hashCode();
|
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||||
} else {
|
() -> "stored session in cache table (host: " +
|
||||||
hashCode = 0;
|
session.getPeerHost() + ", port: " +
|
||||||
}
|
session.getPeerPort() + ") " + "hashCode = " + hashCode +
|
||||||
|
" side = " + session.getSideString());
|
||||||
|
session.isInTable = true;
|
||||||
|
|
||||||
|
/* Lock access to store while adding new session, store is global */
|
||||||
|
synchronized (storeLock) {
|
||||||
|
store.put(hashCode, session);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Always try to store session into cache table, as long as we
|
printSessionStoreStatus();
|
||||||
* have a hashCode. If session already exists for hashCode, it
|
|
||||||
* will be overwritten with new/refreshed version */
|
|
||||||
if (hashCode != 0) {
|
|
||||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
|
||||||
() -> "stored session in cache table (host: " +
|
|
||||||
session.getPeerHost() + ", port: " +
|
|
||||||
session.getPeerPort() + ") " + "hashCode = " + hashCode +
|
|
||||||
" side = " + session.getSideString());
|
|
||||||
store.put(hashCode, session);
|
|
||||||
session.isInTable = true;
|
|
||||||
printSessionStoreStatus();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return WolfSSL.SSL_SUCCESS;
|
return WolfSSL.SSL_SUCCESS;
|
||||||
|
|
Loading…
Reference in New Issue