Skip to content

Commit 8d339ef

Browse files
committed
TLS: Add negotiatedGroup property to SecurityParameters (TLS 1.3+)
- see #2117
1 parent c2e3896 commit 8d339ef

File tree

12 files changed

+112
-15
lines changed

12 files changed

+112
-15
lines changed

tls/src/main/java/org/bouncycastle/tls/SecurityParameters.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ public class SecurityParameters
5555
Certificate localCertificate = null;
5656
Certificate peerCertificate = null;
5757
ProtocolVersion negotiatedVersion = null;
58+
int negotiatedGroup = -1;
5859
int statusRequestVersion = 0;
5960
short clientCertificateType = CertificateType.X509;
6061
short serverCertificateType = CertificateType.X509;
@@ -372,6 +373,17 @@ public ProtocolVersion getNegotiatedVersion()
372373
return negotiatedVersion;
373374
}
374375

376+
/**
377+
* The named group selected by the server for key exchange (if any), or -1 when not negotiated.
378+
* <br/>
379+
* See {@link NamedGroup} for group constants. Currently not set (i.e. -1) when pre-1.3 version negotiated. Not all
380+
* TLS 1.3 key exchanges negotiate a group (e.g. PskKeyExchangeMode.psk_ke).
381+
*/
382+
public int getNegotiatedGroup()
383+
{
384+
return negotiatedGroup;
385+
}
386+
375387
public int getStatusRequestVersion()
376388
{
377389
return statusRequestVersion;

tls/src/main/java/org/bouncycastle/tls/TlsClientProtocol.java

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -956,6 +956,8 @@ protected void process13HelloRetryRequest(ServerHello helloRetryRequest)
956956
TlsUtils.negotiatedCipherSuite(securityParameters, cipherSuite);
957957
tlsClient.notifySelectedCipherSuite(cipherSuite);
958958

959+
securityParameters.negotiatedGroup = selectedGroup;
960+
959961
this.clientAgreements = null;
960962
this.retryCookie = cookie;
961963
this.retryGroup = selectedGroup;
@@ -1066,17 +1068,17 @@ protected void process13ServerHello(ServerHello serverHello, boolean afterHelloR
10661068
KeyShareEntry serverShare = TlsExtensionsUtils.getKeyShareServerHello(extensions);
10671069
if (null == serverShare)
10681070
{
1069-
if (afterHelloRetryRequest
1070-
|| null == pskEarlySecret
1071-
|| !Arrays.contains(clientBinders.pskKeyExchangeModes, PskKeyExchangeMode.psk_ke))
1071+
if (afterHelloRetryRequest ||
1072+
pskEarlySecret == null ||
1073+
!Arrays.contains(clientBinders.pskKeyExchangeModes, PskKeyExchangeMode.psk_ke))
10721074
{
10731075
throw new TlsFatalAlert(AlertDescription.illegal_parameter);
10741076
}
10751077
}
10761078
else
10771079
{
1078-
if (null != pskEarlySecret
1079-
&& !Arrays.contains(clientBinders.pskKeyExchangeModes, PskKeyExchangeMode.psk_dhe_ke))
1080+
if (pskEarlySecret != null &&
1081+
!Arrays.contains(clientBinders.pskKeyExchangeModes, PskKeyExchangeMode.psk_dhe_ke))
10801082
{
10811083
throw new TlsFatalAlert(AlertDescription.illegal_parameter);
10821084
}
@@ -1091,6 +1093,11 @@ protected void process13ServerHello(ServerHello serverHello, boolean afterHelloR
10911093

10921094
agreement.receivePeerValue(serverShare.getKeyExchange());
10931095
sharedSecret = agreement.calculateSecret();
1096+
1097+
if (!afterHelloRetryRequest)
1098+
{
1099+
securityParameters.negotiatedGroup = namedGroup;
1100+
}
10941101
}
10951102
}
10961103

tls/src/main/java/org/bouncycastle/tls/TlsProtocol.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,7 @@ protected boolean isTLSv13ConnectionState()
158158
protected TlsSecret sessionMasterSecret = null;
159159

160160
protected byte[] retryCookie = null;
161+
// TODO[api] Remove and manage via SecurityParameters.negotiatedGroup
161162
protected int retryGroup = -1;
162163
protected Hashtable clientExtensions = null;
163164
protected Hashtable serverExtensions = null;

tls/src/main/java/org/bouncycastle/tls/TlsServerProtocol.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,8 @@ protected ServerHello generate13ServerHello(ClientHello clientHello, HandshakeMe
302302
throw new TlsFatalAlert(AlertDescription.handshake_failure);
303303
}
304304

305+
securityParameters.negotiatedGroup = selectedGroup;
306+
305307
clientShare = TlsUtils.findEarlyKeyShare(clientShares, selectedGroup);
306308

307309
if (null == clientShare)
@@ -332,7 +334,7 @@ protected ServerHello generate13ServerHello(ClientHello clientHello, HandshakeMe
332334
int[] serverSupportedGroups = securityParameters.getServerSupportedGroups();
333335

334336
if (!TlsUtils.isNullOrEmpty(serverSupportedGroups) &&
335-
clientShare.getNamedGroup() != serverSupportedGroups[0] &&
337+
serverSupportedGroups[0] != securityParameters.getNegotiatedGroup() &&
336338
!serverEncryptedExtensions.containsKey(TlsExtensionsUtils.EXT_supported_groups))
337339
{
338340
TlsExtensionsUtils.addSupportedGroupsExtension(serverEncryptedExtensions, serverSupportedGroups);
@@ -397,9 +399,14 @@ protected ServerHello generate13ServerHello(ClientHello clientHello, HandshakeMe
397399

398400
TlsSecret sharedSecret;
399401
{
400-
int namedGroup = clientShare.getNamedGroup();
402+
int negotiatedGroup = securityParameters.getNegotiatedGroup();
403+
404+
if (clientShare.getNamedGroup() != negotiatedGroup)
405+
{
406+
throw new TlsFatalAlert(AlertDescription.illegal_parameter);
407+
}
401408

402-
TlsAgreement agreement = TlsUtils.createKeyShare(crypto, namedGroup, true);
409+
TlsAgreement agreement = TlsUtils.createKeyShare(crypto, negotiatedGroup, true);
403410
if (agreement == null)
404411
{
405412
throw new TlsFatalAlert(AlertDescription.internal_error);
@@ -408,7 +415,7 @@ protected ServerHello generate13ServerHello(ClientHello clientHello, HandshakeMe
408415
agreement.receivePeerValue(clientShare.getKeyExchange());
409416

410417
byte[] key_exchange = agreement.generateEphemeral();
411-
KeyShareEntry serverShare = new KeyShareEntry(namedGroup, key_exchange);
418+
KeyShareEntry serverShare = new KeyShareEntry(negotiatedGroup, key_exchange);
412419
TlsExtensionsUtils.addKeyShareServerHello(serverHelloExtensions, serverShare);
413420

414421
sharedSecret = agreement.calculateSecret();

tls/src/test/java/org/bouncycastle/tls/test/MockPSKTls13Client.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,11 @@
1010
import org.bouncycastle.tls.AlertLevel;
1111
import org.bouncycastle.tls.BasicTlsPSKExternal;
1212
import org.bouncycastle.tls.CipherSuite;
13+
import org.bouncycastle.tls.NamedGroup;
1314
import org.bouncycastle.tls.PRFAlgorithm;
1415
import org.bouncycastle.tls.ProtocolName;
1516
import org.bouncycastle.tls.ProtocolVersion;
17+
import org.bouncycastle.tls.SecurityParameters;
1618
import org.bouncycastle.tls.TlsAuthentication;
1719
import org.bouncycastle.tls.TlsFatalAlert;
1820
import org.bouncycastle.tls.TlsPSK;
@@ -121,11 +123,19 @@ public void notifyHandshakeComplete() throws IOException
121123
{
122124
super.notifyHandshakeComplete();
123125

124-
ProtocolName protocolName = context.getSecurityParametersConnection().getApplicationProtocol();
126+
SecurityParameters securityParameters = context.getSecurityParametersConnection();
127+
128+
ProtocolName protocolName = securityParameters.getApplicationProtocol();
125129
if (protocolName != null)
126130
{
127131
System.out.println("Client ALPN: " + protocolName.getUtf8Decoding());
128132
}
133+
134+
int negotiatedGroup = securityParameters.getNegotiatedGroup();
135+
if (negotiatedGroup >= 0)
136+
{
137+
System.out.println("Client negotiated group: " + NamedGroup.getText(negotiatedGroup));
138+
}
129139
}
130140

131141
public Hashtable getClientExtensions() throws IOException

tls/src/test/java/org/bouncycastle/tls/test/MockPSKTls13Server.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@
1010
import org.bouncycastle.tls.AlertLevel;
1111
import org.bouncycastle.tls.BasicTlsPSKExternal;
1212
import org.bouncycastle.tls.CipherSuite;
13+
import org.bouncycastle.tls.NamedGroup;
1314
import org.bouncycastle.tls.PRFAlgorithm;
1415
import org.bouncycastle.tls.ProtocolName;
1516
import org.bouncycastle.tls.ProtocolVersion;
1617
import org.bouncycastle.tls.PskIdentity;
18+
import org.bouncycastle.tls.SecurityParameters;
1719
import org.bouncycastle.tls.TlsCredentials;
1820
import org.bouncycastle.tls.TlsFatalAlert;
1921
import org.bouncycastle.tls.TlsPSKExternal;
@@ -119,11 +121,19 @@ public void notifyHandshakeComplete() throws IOException
119121
{
120122
super.notifyHandshakeComplete();
121123

122-
ProtocolName protocolName = context.getSecurityParametersConnection().getApplicationProtocol();
124+
SecurityParameters securityParameters = context.getSecurityParametersConnection();
125+
126+
ProtocolName protocolName = securityParameters.getApplicationProtocol();
123127
if (protocolName != null)
124128
{
125129
System.out.println("Server ALPN: " + protocolName.getUtf8Decoding());
126130
}
131+
132+
int negotiatedGroup = securityParameters.getNegotiatedGroup();
133+
if (negotiatedGroup >= 0)
134+
{
135+
System.out.println("Server negotiated group: " + NamedGroup.getText(negotiatedGroup));
136+
}
127137
}
128138

129139
public void processClientExtensions(Hashtable clientExtensions) throws IOException

tls/src/test/java/org/bouncycastle/tls/test/MockTlsHybridClient.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import org.bouncycastle.tls.NamedGroupRole;
1818
import org.bouncycastle.tls.ProtocolName;
1919
import org.bouncycastle.tls.ProtocolVersion;
20+
import org.bouncycastle.tls.SecurityParameters;
2021
import org.bouncycastle.tls.SignatureAlgorithm;
2122
import org.bouncycastle.tls.TlsAuthentication;
2223
import org.bouncycastle.tls.TlsCredentials;
@@ -187,12 +188,20 @@ public void notifyHandshakeComplete() throws IOException
187188
{
188189
super.notifyHandshakeComplete();
189190

190-
ProtocolName protocolName = context.getSecurityParametersConnection().getApplicationProtocol();
191+
SecurityParameters securityParameters = context.getSecurityParametersConnection();
192+
193+
ProtocolName protocolName = securityParameters.getApplicationProtocol();
191194
if (protocolName != null)
192195
{
193196
System.out.println("Client ALPN: " + protocolName.getUtf8Decoding());
194197
}
195198

199+
int negotiatedGroup = securityParameters.getNegotiatedGroup();
200+
if (negotiatedGroup >= 0)
201+
{
202+
System.out.println("Client negotiated group: " + NamedGroup.getText(negotiatedGroup));
203+
}
204+
196205
TlsSession newSession = context.getSession();
197206
if (newSession != null)
198207
{

tls/src/test/java/org/bouncycastle/tls/test/MockTlsHybridServer.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import org.bouncycastle.tls.NamedGroup;
1717
import org.bouncycastle.tls.ProtocolName;
1818
import org.bouncycastle.tls.ProtocolVersion;
19+
import org.bouncycastle.tls.SecurityParameters;
1920
import org.bouncycastle.tls.SignatureAlgorithm;
2021
import org.bouncycastle.tls.TlsCredentialedDecryptor;
2122
import org.bouncycastle.tls.TlsCredentialedSigner;
@@ -181,12 +182,20 @@ public void notifyHandshakeComplete() throws IOException
181182
{
182183
super.notifyHandshakeComplete();
183184

184-
ProtocolName protocolName = context.getSecurityParametersConnection().getApplicationProtocol();
185+
SecurityParameters securityParameters = context.getSecurityParametersConnection();
186+
187+
ProtocolName protocolName = securityParameters.getApplicationProtocol();
185188
if (protocolName != null)
186189
{
187190
System.out.println("Server ALPN: " + protocolName.getUtf8Decoding());
188191
}
189192

193+
int negotiatedGroup = securityParameters.getNegotiatedGroup();
194+
if (negotiatedGroup >= 0)
195+
{
196+
System.out.println("Server negotiated group: " + NamedGroup.getText(negotiatedGroup));
197+
}
198+
190199
byte[] tlsServerEndPoint = context.exportChannelBinding(ChannelBinding.tls_server_end_point);
191200
System.out.println("Server 'tls-server-end-point': " + hex(tlsServerEndPoint));
192201

tls/src/test/java/org/bouncycastle/tls/test/MockTlsKemClient.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import org.bouncycastle.tls.NamedGroupRole;
1818
import org.bouncycastle.tls.ProtocolName;
1919
import org.bouncycastle.tls.ProtocolVersion;
20+
import org.bouncycastle.tls.SecurityParameters;
2021
import org.bouncycastle.tls.SignatureAlgorithm;
2122
import org.bouncycastle.tls.TlsAuthentication;
2223
import org.bouncycastle.tls.TlsCredentials;
@@ -187,12 +188,20 @@ public void notifyHandshakeComplete() throws IOException
187188
{
188189
super.notifyHandshakeComplete();
189190

190-
ProtocolName protocolName = context.getSecurityParametersConnection().getApplicationProtocol();
191+
SecurityParameters securityParameters = context.getSecurityParametersConnection();
192+
193+
ProtocolName protocolName = securityParameters.getApplicationProtocol();
191194
if (protocolName != null)
192195
{
193196
System.out.println("Client ALPN: " + protocolName.getUtf8Decoding());
194197
}
195198

199+
int negotiatedGroup = securityParameters.getNegotiatedGroup();
200+
if (negotiatedGroup >= 0)
201+
{
202+
System.out.println("Client negotiated group: " + NamedGroup.getText(negotiatedGroup));
203+
}
204+
196205
TlsSession newSession = context.getSession();
197206
if (newSession != null)
198207
{

tls/src/test/java/org/bouncycastle/tls/test/MockTlsKemServer.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import org.bouncycastle.tls.NamedGroup;
1717
import org.bouncycastle.tls.ProtocolName;
1818
import org.bouncycastle.tls.ProtocolVersion;
19+
import org.bouncycastle.tls.SecurityParameters;
1920
import org.bouncycastle.tls.SignatureAlgorithm;
2021
import org.bouncycastle.tls.TlsCredentialedDecryptor;
2122
import org.bouncycastle.tls.TlsCredentialedSigner;
@@ -181,12 +182,20 @@ public void notifyHandshakeComplete() throws IOException
181182
{
182183
super.notifyHandshakeComplete();
183184

184-
ProtocolName protocolName = context.getSecurityParametersConnection().getApplicationProtocol();
185+
SecurityParameters securityParameters = context.getSecurityParametersConnection();
186+
187+
ProtocolName protocolName = securityParameters.getApplicationProtocol();
185188
if (protocolName != null)
186189
{
187190
System.out.println("Server ALPN: " + protocolName.getUtf8Decoding());
188191
}
189192

193+
int negotiatedGroup = securityParameters.getNegotiatedGroup();
194+
if (negotiatedGroup >= 0)
195+
{
196+
System.out.println("Server negotiated group: " + NamedGroup.getText(negotiatedGroup));
197+
}
198+
190199
byte[] tlsServerEndPoint = context.exportChannelBinding(ChannelBinding.tls_server_end_point);
191200
System.out.println("Server 'tls-server-end-point': " + hex(tlsServerEndPoint));
192201

0 commit comments

Comments
 (0)