Skip to content

Commit c403460

Browse files
committed
BCJSSE: Single shared map of session bindings across session lifetime
- see #2136
1 parent faf4e27 commit c403460

File tree

11 files changed

+110
-36
lines changed

11 files changed

+110
-36
lines changed

tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLEngine.java

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ class ProvSSLEngine
5757
protected TlsProtocol protocol = null;
5858
protected ProvTlsPeer protocolPeer = null;
5959
protected ProvSSLConnection connection = null;
60+
protected ProvSSLSession dummySession = null;
6061
protected ProvSSLSessionHandshake handshakeSession = null;
6162

6263
protected SSLException deferredException = null;
@@ -225,7 +226,12 @@ public synchronized BCApplicationProtocolSelector<SSLEngine> getBCHandshakeAppli
225226
return sslParameters.getEngineAPSelector();
226227
}
227228

228-
public synchronized BCExtendedSSLSession getBCHandshakeSession()
229+
public BCExtendedSSLSession getBCHandshakeSession()
230+
{
231+
return getBCHandshakeSessionImpl();
232+
}
233+
234+
public synchronized ProvSSLSessionHandshake getBCHandshakeSessionImpl()
229235
{
230236
return handshakeSession;
231237
}
@@ -703,7 +709,7 @@ public synchronized void notifyHandshakeSession(ProvSSLSessionContext sslSession
703709
if (null != resumedSession)
704710
{
705711
this.handshakeSession = new ProvSSLSessionResumed(sslSessionContext, peerHost, peerPort, securityParameters,
706-
jsseSecurityParameters, resumedSession.getTlsSession(), resumedSession.getJsseSessionParameters());
712+
jsseSecurityParameters, resumedSession);
707713
}
708714
else
709715
{
@@ -717,9 +723,19 @@ public synchronized String selectApplicationProtocol(List<String> protocols)
717723
return sslParameters.getEngineAPSelector().select(this, protocols);
718724
}
719725

720-
ProvSSLSession getSessionImpl()
726+
synchronized ProvSSLSession getSessionImpl()
721727
{
722-
return null == connection ? ProvSSLSession.NULL_SESSION : connection.getSession();
728+
if (connection != null)
729+
{
730+
return connection.getSession();
731+
}
732+
733+
if (dummySession == null)
734+
{
735+
dummySession = ProvSSLSession.createDummySession();
736+
}
737+
738+
return dummySession;
723739
}
724740

725741
private RecordPreview getRecordPreview(ByteBuffer src)

tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSession.java

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.bouncycastle.jsse.provider;
22

33
import java.util.List;
4+
import java.util.concurrent.ConcurrentHashMap;
45

56
import org.bouncycastle.jsse.BCSNIServerName;
67
import org.bouncycastle.tls.CipherSuite;
@@ -11,19 +12,14 @@
1112
class ProvSSLSession
1213
extends ProvSSLSessionBase
1314
{
14-
// TODO[jsse] Ensure this behaves according to the javadoc for SSLSocket.getSession and SSLEngine.getSession
15-
// TODO[jsse] This would make more sense as a ProvSSLSessionHandshake
16-
static final ProvSSLSession NULL_SESSION = new ProvSSLSession(null, null, -1, null,
17-
new JsseSessionParameters(null, null));
18-
1915
protected final TlsSession tlsSession;
2016
protected final SessionParameters sessionParameters;
2117
protected final JsseSessionParameters jsseSessionParameters;
2218

23-
ProvSSLSession(ProvSSLSessionContext sslSessionContext, String peerHost, int peerPort, TlsSession tlsSession,
24-
JsseSessionParameters jsseSessionParameters)
19+
ProvSSLSession(ProvSSLSessionContext sslSessionContext, ConcurrentHashMap<String, Object> valueMap, String peerHost,
20+
int peerPort, TlsSession tlsSession, JsseSessionParameters jsseSessionParameters)
2521
{
26-
super(sslSessionContext, peerHost, peerPort);
22+
super(sslSessionContext, valueMap, peerHost, peerPort);
2723

2824
this.tlsSession = tlsSession;
2925
this.sessionParameters = tlsSession == null ? null : tlsSession.exportSessionParameters();
@@ -110,4 +106,10 @@ public boolean isValid()
110106
{
111107
return super.isValid() && null != tlsSession && tlsSession.isResumable();
112108
}
109+
110+
static final ProvSSLSession createDummySession()
111+
{
112+
// NB: Allow session value binding on failed connections for SunJSSE compatibility
113+
return new ProvSSLSession(null, createValueMap(), null, -1, null, new JsseSessionParameters(null, null));
114+
}
113115
}

tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSessionBase.java

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,8 @@
2525
abstract class ProvSSLSessionBase
2626
extends BCExtendedSSLSession
2727
{
28-
protected final ConcurrentHashMap<String, Object> valueMap = new ConcurrentHashMap<String, Object>();
29-
3028
protected final AtomicReference<ProvSSLSessionContext> sslSessionContext;
29+
protected final ConcurrentHashMap<String, Object> valueMap;
3130
protected final boolean fipsMode;
3231
protected final JcaTlsCrypto crypto;
3332
protected final String peerHost;
@@ -36,9 +35,11 @@ abstract class ProvSSLSessionBase
3635
protected final SSLSession exportSSLSession;
3736
protected final AtomicLong lastAccessedTime;
3837

39-
ProvSSLSessionBase(ProvSSLSessionContext sslSessionContext, String peerHost, int peerPort)
38+
ProvSSLSessionBase(ProvSSLSessionContext sslSessionContext, ConcurrentHashMap<String, Object> valueMap,
39+
String peerHost, int peerPort)
4040
{
4141
this.sslSessionContext = new AtomicReference<ProvSSLSessionContext>(sslSessionContext);
42+
this.valueMap = valueMap;
4243
this.fipsMode = (null == sslSessionContext) ? false : sslSessionContext.getContextData().isFipsMode();
4344
this.crypto = (null == sslSessionContext) ? null : sslSessionContext.getContextData().getCrypto();
4445
this.peerHost = peerHost;
@@ -243,6 +244,11 @@ public Object getValue(String name)
243244
return valueMap.get(name);
244245
}
245246

247+
ConcurrentHashMap<String, Object> getValueMap()
248+
{
249+
return valueMap;
250+
}
251+
246252
public String[] getValueNames()
247253
{
248254
return valueMap.keySet().toArray(new String[0]);
@@ -351,4 +357,9 @@ private void implInvalidate(boolean removeFromSessionContext)
351357

352358
invalidateTLS();
353359
}
360+
361+
protected static ConcurrentHashMap<String, Object> createValueMap()
362+
{
363+
return new ConcurrentHashMap<String, Object>();
364+
}
354365
}

tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSessionContext.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,14 +89,15 @@ synchronized void removeSession(byte[] sessionID)
8989
}
9090
}
9191

92-
synchronized ProvSSLSession reportSession(String peerHost, int peerPort, TlsSession tlsSession,
93-
JsseSessionParameters jsseSessionParameters, boolean addToCache)
92+
synchronized ProvSSLSession reportSession(ProvSSLSessionHandshake handshakeSession, String peerHost, int peerPort,
93+
TlsSession tlsSession, JsseSessionParameters jsseSessionParameters, boolean addToCache)
9494
{
9595
processQueue();
9696

9797
if (!addToCache)
9898
{
99-
return new ProvSSLSession(this, peerHost, peerPort, tlsSession, jsseSessionParameters);
99+
return new ProvSSLSession(this, handshakeSession.getValueMap(), peerHost, peerPort, tlsSession,
100+
jsseSessionParameters);
100101
}
101102

102103
SessionID sessionID = makeSessionID(tlsSession.getSessionID());
@@ -105,7 +106,8 @@ synchronized ProvSSLSession reportSession(String peerHost, int peerPort, TlsSess
105106
ProvSSLSession session = sessionEntry == null ? null : sessionEntry.get();
106107
if (null == session || session.getTlsSession() != tlsSession)
107108
{
108-
session = new ProvSSLSession(this, peerHost, peerPort, tlsSession, jsseSessionParameters);
109+
session = new ProvSSLSession(this, handshakeSession.getValueMap(), peerHost, peerPort, tlsSession,
110+
jsseSessionParameters);
109111

110112
if (null != sessionID)
111113
{

tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSessionHandshake.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import java.util.Collections;
55
import java.util.List;
66
import java.util.Vector;
7+
import java.util.concurrent.ConcurrentHashMap;
78

89
import org.bouncycastle.jsse.BCSNIServerName;
910
import org.bouncycastle.tls.ProtocolVersion;
@@ -19,7 +20,14 @@ class ProvSSLSessionHandshake
1920
ProvSSLSessionHandshake(ProvSSLSessionContext sslSessionContext, String peerHost, int peerPort,
2021
SecurityParameters securityParameters, JsseSecurityParameters jsseSecurityParameters)
2122
{
22-
super(sslSessionContext, peerHost, peerPort);
23+
this(sslSessionContext, createValueMap(), peerHost, peerPort, securityParameters, jsseSecurityParameters);
24+
}
25+
26+
protected ProvSSLSessionHandshake(ProvSSLSessionContext sslSessionContext,
27+
ConcurrentHashMap<String, Object> valueMap, String peerHost, int peerPort,
28+
SecurityParameters securityParameters, JsseSecurityParameters jsseSecurityParameters)
29+
{
30+
super(sslSessionContext, valueMap, peerHost, peerPort);
2331

2432
this.securityParameters = securityParameters;
2533
this.jsseSecurityParameters = jsseSecurityParameters;

tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSessionResumed.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,15 @@ class ProvSSLSessionResumed
1313
protected final JsseSessionParameters jsseSessionParameters;
1414

1515
ProvSSLSessionResumed(ProvSSLSessionContext sslSessionContext, String peerHost, int peerPort,
16-
SecurityParameters securityParameters, JsseSecurityParameters jsseSecurityParameters, TlsSession tlsSession,
17-
JsseSessionParameters jsseSessionParameters)
16+
SecurityParameters securityParameters, JsseSecurityParameters jsseSecurityParameters,
17+
ProvSSLSession resumedSession)
1818
{
19-
super(sslSessionContext, peerHost, peerPort, securityParameters, jsseSecurityParameters);
19+
super(sslSessionContext, resumedSession.getValueMap(), peerHost, peerPort, securityParameters,
20+
jsseSecurityParameters);
2021

21-
this.tlsSession = tlsSession;
22+
this.tlsSession = resumedSession.getTlsSession();
2223
this.sessionParameters = tlsSession.exportSessionParameters();
23-
this.jsseSessionParameters = jsseSessionParameters;
24+
this.jsseSessionParameters = resumedSession.getJsseSessionParameters();
2425
}
2526

2627
@Override

tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSocketDirect.java

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ class ProvSSLSocketDirect
5151
protected TlsProtocol protocol = null;
5252
protected ProvTlsPeer protocolPeer = null;
5353
protected ProvSSLConnection connection = null;
54+
protected ProvSSLSession dummySession = null;
5455
protected ProvSSLSessionHandshake handshakeSession = null;
5556

5657
/** This constructor is the one used (only) by ProvSSLServerSocket */
@@ -183,7 +184,12 @@ public synchronized BCApplicationProtocolSelector<SSLSocket> getBCHandshakeAppli
183184
return sslParameters.getSocketAPSelector();
184185
}
185186

186-
public synchronized BCExtendedSSLSession getBCHandshakeSession()
187+
public BCExtendedSSLSession getBCHandshakeSession()
188+
{
189+
return getBCHandshakeSessionImpl();
190+
}
191+
192+
public synchronized ProvSSLSessionHandshake getBCHandshakeSessionImpl()
187193
{
188194
return handshakeSession;
189195
}
@@ -490,7 +496,7 @@ public synchronized void notifyHandshakeSession(ProvSSLSessionContext sslSession
490496
if (null != resumedSession)
491497
{
492498
this.handshakeSession = new ProvSSLSessionResumed(sslSessionContext, peerHost, peerPort, securityParameters,
493-
jsseSecurityParameters, resumedSession.getTlsSession(), resumedSession.getJsseSessionParameters());
499+
jsseSecurityParameters, resumedSession);
494500
}
495501
else
496502
{
@@ -508,7 +514,17 @@ synchronized ProvSSLSession getSessionImpl()
508514
{
509515
getConnection();
510516

511-
return null == connection ? ProvSSLSession.NULL_SESSION : connection.getSession();
517+
if (connection != null)
518+
{
519+
return connection.getSession();
520+
}
521+
522+
if (dummySession == null)
523+
{
524+
dummySession = ProvSSLSession.createDummySession();
525+
}
526+
527+
return dummySession;
512528
}
513529

514530
synchronized void handshakeIfNecessary(boolean resumable) throws IOException

tls/src/main/java/org/bouncycastle/jsse/provider/ProvSSLSocketWrap.java

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ private static Socket checkSocket(Socket s) throws SocketException
6868
protected TlsProtocol protocol = null;
6969
protected ProvTlsPeer protocolPeer = null;
7070
protected ProvSSLConnection connection = null;
71+
protected ProvSSLSession dummySession = null;
7172
protected ProvSSLSessionHandshake handshakeSession = null;
7273

7374
protected ProvSSLSocketWrap(ContextData contextData, Socket s, InputStream consumed, boolean autoClose)
@@ -188,7 +189,12 @@ public synchronized BCApplicationProtocolSelector<SSLSocket> getBCHandshakeAppli
188189
return sslParameters.getSocketAPSelector();
189190
}
190191

191-
public synchronized BCExtendedSSLSession getBCHandshakeSession()
192+
public BCExtendedSSLSession getBCHandshakeSession()
193+
{
194+
return getBCHandshakeSessionImpl();
195+
}
196+
197+
public synchronized ProvSSLSessionHandshake getBCHandshakeSessionImpl()
192198
{
193199
return handshakeSession;
194200
}
@@ -679,7 +685,7 @@ public synchronized void notifyHandshakeSession(ProvSSLSessionContext sslSession
679685
if (null != resumedSession)
680686
{
681687
this.handshakeSession = new ProvSSLSessionResumed(sslSessionContext, peerHost, peerPort, securityParameters,
682-
jsseSecurityParameters, resumedSession.getTlsSession(), resumedSession.getJsseSessionParameters());
688+
jsseSecurityParameters, resumedSession);
683689
}
684690
else
685691
{
@@ -697,7 +703,17 @@ synchronized ProvSSLSession getSessionImpl()
697703
{
698704
getConnection();
699705

700-
return null == connection ? ProvSSLSession.NULL_SESSION : connection.getSession();
706+
if (connection != null)
707+
{
708+
return connection.getSession();
709+
}
710+
711+
if (dummySession == null)
712+
{
713+
dummySession = ProvSSLSession.createDummySession();
714+
}
715+
716+
return dummySession;
701717
}
702718

703719
synchronized void handshakeIfNecessary(boolean resumable) throws IOException

tls/src/main/java/org/bouncycastle/jsse/provider/ProvTlsClient.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -530,8 +530,8 @@ public synchronized void notifyHandshakeComplete() throws IOException
530530
// TODO[tls13] Resumption/PSK
531531
boolean addToCache = provClientEnableSessionResumption && !TlsUtils.isTLSv13(context);
532532

533-
this.sslSession = sslSessionContext.reportSession(peerHost, peerPort, connectionTlsSession,
534-
jsseSessionParameters, addToCache);
533+
this.sslSession = sslSessionContext.reportSession(manager.getBCHandshakeSessionImpl(), peerHost, peerPort,
534+
connectionTlsSession, jsseSessionParameters, addToCache);
535535
}
536536

537537
manager.notifyHandshakeComplete(new ProvSSLConnection(this));

tls/src/main/java/org/bouncycastle/jsse/provider/ProvTlsManager.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,12 @@ interface ProvTlsManager
1818

1919
BCX509Key chooseServerKey(String[] keyTypes, Principal[] issuers);
2020

21-
boolean getEnableSessionCreation();
21+
ProvSSLSessionHandshake getBCHandshakeSessionImpl();
2222

2323
ContextData getContextData();
2424

25+
boolean getEnableSessionCreation();
26+
2527
String getPeerHost();
2628

2729
String getPeerHostSNI();

0 commit comments

Comments
 (0)