Skip to content

Commit 46a3388

Browse files
committed
BCJSSE: Configurable (client) early key_share groups
- via BCSSLParameters.earlyNamedGroups property - via "org.bouncycastle.jsse.client.earlyNamedGroups" system property - see #2095
1 parent a066f00 commit 46a3388

File tree

6 files changed

+191
-6
lines changed

6 files changed

+191
-6
lines changed

tls/src/main/java/org/bouncycastle/jsse/BCSSLParameters.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ private static <T> List<T> copyList(Collection<T> list)
4444
private String[] signatureSchemes = null;
4545
private String[] signatureSchemesCert = null;
4646
private String[] namedGroups = null;
47+
private String[] earlyNamedGroups = null;
4748

4849
public BCSSLParameters()
4950
{
@@ -326,4 +327,34 @@ public void setNamedGroups(String[] namedGroups)
326327

327328
this.namedGroups = check;
328329
}
330+
331+
public String[] getEarlyNamedGroups()
332+
{
333+
return TlsUtils.clone(earlyNamedGroups);
334+
}
335+
336+
public void setEarlyNamedGroups(String[] earlyNamedGroups)
337+
{
338+
String[] check = null;
339+
340+
if (earlyNamedGroups != null)
341+
{
342+
check = TlsUtils.clone(earlyNamedGroups);
343+
HashSet<String> seenEntries = new HashSet<String>();
344+
for (String entry : check)
345+
{
346+
if (TlsUtils.isNullOrEmpty(entry))
347+
{
348+
throw new IllegalArgumentException("'earlyNamedGroups' entries cannot be null or empty strings");
349+
}
350+
351+
if (!seenEntries.add(entry))
352+
{
353+
throw new IllegalArgumentException("'earlyNamedGroups' contains duplicate entry: " + entry);
354+
}
355+
}
356+
}
357+
358+
this.earlyNamedGroups = check;
359+
}
329360
}

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

Lines changed: 100 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ class NamedGroupInfo
2929

3030
private static final String PROPERTY_NAMED_GROUPS = "jdk.tls.namedGroups";
3131

32+
private static final String PROPERTY_BC_EARLY_NAMED_GROUPS = "org.bouncycastle.jsse.client.earlyNamedGroups";
33+
3234
// NOTE: Not all of these are necessarily enabled/supported; it will be checked at runtime
3335
private enum All
3436
{
@@ -162,21 +164,28 @@ private All(int namedGroup, String jcaAlgorithm1, String jcaAlgorithm2)
162164
static class PerConnection
163165
{
164166
private final Map<Integer, NamedGroupInfo> local;
167+
private final Vector localEarly;
165168
private final boolean localECDSA;
166169
private final AtomicReference<List<NamedGroupInfo>> peer;
167170

168-
PerConnection(Map<Integer, NamedGroupInfo> local, boolean localECDSA)
171+
PerConnection(Map<Integer, NamedGroupInfo> local, Vector localEarly, boolean localECDSA)
169172
{
170173
if (local == null)
171174
{
172175
throw new NullPointerException("local");
173176
}
174177

175178
this.local = local;
179+
this.localEarly = localEarly;
176180
this.localECDSA = localECDSA;
177181
this.peer = new AtomicReference<List<NamedGroupInfo>>();
178182
}
179183

184+
Vector getLocalEarly()
185+
{
186+
return localEarly;
187+
}
188+
180189
List<NamedGroupInfo> getPeer()
181190
{
182191
return peer.get();
@@ -195,11 +204,13 @@ static class PerContext
195204
{
196205
private final Map<Integer, NamedGroupInfo> index;
197206
private final int[] candidates;
207+
private final int[] earlyCandidates;
198208

199-
PerContext(Map<Integer, NamedGroupInfo> index, int[] candidates)
209+
PerContext(Map<Integer, NamedGroupInfo> index, int[] candidates, int[] earlyCandidates)
200210
{
201211
this.index = index;
202212
this.candidates = candidates;
213+
this.earlyCandidates = earlyCandidates;
203214
}
204215
}
205216

@@ -276,15 +287,52 @@ private static PerConnection createPerConnection(PerContext perContext, ProvSSLP
276287

277288
boolean localECDSA = hasAnyECDSA(local);
278289

279-
return new PerConnection(local, localECDSA);
290+
Vector localEarly = null;
291+
{
292+
String[] earlyNamedGroups = sslParameters.getEarlyNamedGroups();
293+
294+
int[] earlyCandidates;
295+
if (earlyNamedGroups == null)
296+
{
297+
earlyCandidates = perContext.earlyCandidates;
298+
}
299+
else
300+
{
301+
earlyCandidates = createEarlyCandidates(perContext.index, earlyNamedGroups,
302+
"BCSSLParameters.earlyNamedGroups");
303+
}
304+
305+
if (earlyCandidates != null)
306+
{
307+
int earlyCount = earlyCandidates.length;
308+
localEarly = new Vector(earlyCount);
309+
for (int i = 0; i < earlyCount; ++i)
310+
{
311+
Integer earlyCandidate = Integers.valueOf(earlyCandidates[i]);
312+
313+
NamedGroupInfo earlyNamedGroupInfo = local.get(earlyCandidate);
314+
if (earlyNamedGroupInfo == null || !earlyNamedGroupInfo.isEnabled())
315+
{
316+
LOG.warning("Candidate early named group not an enabled named group: "
317+
+ NamedGroup.getName(earlyCandidates[i]));
318+
continue;
319+
}
320+
321+
localEarly.add(earlyCandidate);
322+
}
323+
}
324+
}
325+
326+
return new PerConnection(local, localEarly, localECDSA);
280327
}
281328

282329
static PerContext createPerContext(boolean isFipsContext, JcaTlsCrypto crypto)
283330
{
284331
Map<Integer, NamedGroupInfo> index = createIndex(isFipsContext, crypto);
285332
int[] candidates = createCandidatesFromProperty(index, PROPERTY_NAMED_GROUPS);
333+
int[] earlyCandidates = createEarlyCandidatesFromProperty(index, PROPERTY_BC_EARLY_NAMED_GROUPS);
286334

287-
return new PerContext(index, candidates);
335+
return new PerContext(index, candidates, earlyCandidates);
288336
}
289337

290338
static DefaultedResult getMaximumBitsServerECDH(PerConnection perConnection)
@@ -537,7 +585,7 @@ private static int[] createCandidates(Map<Integer, NamedGroupInfo> index, String
537585
continue;
538586
}
539587

540-
NamedGroupInfo namedGroupInfo = index.get(namedGroup);
588+
NamedGroupInfo namedGroupInfo = index.get(Integers.valueOf(namedGroup));
541589
if (null == namedGroupInfo)
542590
{
543591
LOG.warning("'" + description + "' contains unsupported NamedGroup: " + name);
@@ -563,6 +611,52 @@ private static int[] createCandidates(Map<Integer, NamedGroupInfo> index, String
563611
return result;
564612
}
565613

614+
private static int[] createEarlyCandidatesFromProperty(Map<Integer, NamedGroupInfo> index, String propertyName)
615+
{
616+
String[] names = PropertyUtils.getStringArraySystemProperty(propertyName);
617+
if (null == names)
618+
{
619+
return null;
620+
}
621+
622+
return createEarlyCandidates(index, names, propertyName);
623+
}
624+
625+
private static int[] createEarlyCandidates(Map<Integer, NamedGroupInfo> index, String[] names, String description)
626+
{
627+
int[] result = new int[names.length];
628+
int count = 0;
629+
for (String name : names)
630+
{
631+
int namedGroup = getNamedGroupByName(name);
632+
if (namedGroup < 0)
633+
{
634+
LOG.warning("'" + description + "' contains unrecognised NamedGroup: " + name);
635+
continue;
636+
}
637+
638+
NamedGroupInfo namedGroupInfo = index.get(Integers.valueOf(namedGroup));
639+
if (null == namedGroupInfo)
640+
{
641+
LOG.warning("'" + description + "' contains unsupported NamedGroup: " + name);
642+
continue;
643+
}
644+
645+
if (!namedGroupInfo.isEnabled())
646+
{
647+
LOG.warning("'" + description + "' contains disabled NamedGroup: " + name);
648+
continue;
649+
}
650+
651+
result[count++] = namedGroup;
652+
}
653+
if (count < result.length)
654+
{
655+
result = Arrays.copyOf(result, count);
656+
}
657+
return result;
658+
}
659+
566660
private static Map<Integer, NamedGroupInfo> createIndex(boolean isFipsContext, JcaTlsCrypto crypto)
567661
{
568662
Map<Integer, NamedGroupInfo> ng = new TreeMap<Integer, NamedGroupInfo>();
@@ -618,7 +712,7 @@ private static List<NamedGroupInfo> getNamedGroupInfos(Map<Integer, NamedGroupIn
618712
{
619713
int namedGroup = namedGroups[i];
620714

621-
NamedGroupInfo namedGroupInfo = namedGroupInfos.get(namedGroup);
715+
NamedGroupInfo namedGroupInfo = namedGroupInfos.get(Integers.valueOf(namedGroup));
622716
if (null != namedGroupInfo)
623717
{
624718
result.add(namedGroupInfo);

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ private static <T> List<T> copyList(Collection<T> list)
4747
private String[] signatureSchemes = null;
4848
private String[] signatureSchemesCert = null;
4949
private String[] namedGroups = null;
50+
private String[] earlyNamedGroups = null;
5051

5152
private BCApplicationProtocolSelector<SSLEngine> engineAPSelector;
5253
private BCApplicationProtocolSelector<SSLSocket> socketAPSelector;
@@ -77,6 +78,7 @@ ProvSSLParameters copy()
7778
p.signatureSchemes = signatureSchemes;
7879
p.signatureSchemesCert = signatureSchemesCert;
7980
p.namedGroups = namedGroups;
81+
p.earlyNamedGroups = earlyNamedGroups;
8082
p.engineAPSelector = engineAPSelector;
8183
p.socketAPSelector = socketAPSelector;
8284
p.sessionToResume = sessionToResume;
@@ -291,6 +293,16 @@ public void setNamedGroups(String[] namedGroups)
291293
this.namedGroups = TlsUtils.clone(namedGroups);
292294
}
293295

296+
public String[] getEarlyNamedGroups()
297+
{
298+
return TlsUtils.clone(earlyNamedGroups);
299+
}
300+
301+
public void setEarlyNamedGroups(String[] earlyNamedGroups)
302+
{
303+
this.earlyNamedGroups = TlsUtils.clone(earlyNamedGroups);
304+
}
305+
294306
public BCApplicationProtocolSelector<SSLEngine> getEngineAPSelector()
295307
{
296308
return engineAPSelector;

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,18 @@ public JcaTlsCrypto getCrypto()
393393
return manager.getContextData().getCrypto();
394394
}
395395

396+
@Override
397+
public Vector getEarlyKeyShareGroups()
398+
{
399+
Vector jsse = jsseSecurityParameters.namedGroups.getLocalEarly();
400+
if (jsse != null)
401+
{
402+
return jsse;
403+
}
404+
405+
return super.getEarlyKeyShareGroups();
406+
}
407+
396408
@Override
397409
public int getMaxCertificateChainLength()
398410
{

tls/src/main/jdk1.5/org/bouncycastle/jsse/provider/SSLParametersUtil.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ static BCSSLParameters getParameters(ProvSSLParameters prov)
8686
ssl.setSignatureSchemes(prov.getSignatureSchemes());
8787
ssl.setSignatureSchemesCert(prov.getSignatureSchemesCert());
8888
ssl.setNamedGroups(prov.getNamedGroups());
89+
ssl.setEarlyNamedGroups(prov.getEarlyNamedGroups());
8990

9091
return ssl;
9192
}
@@ -181,6 +182,11 @@ static SSLParameters getSSLParameters(ProvSSLParameters prov)
181182

182183
// Unsupported as of JDK 21
183184

185+
// if (null != setEarlyNamedGroups)
186+
// {
187+
// set(ssl, setEarlyNamedGroups, prov.getEarlyNamedGroups());
188+
// }
189+
184190
// if (null != setUseNamedGroupsOrder)
185191
// {
186192
// set(ssl, setUseNamedGroupsOrder, prov.getUseNamedGroupsOrder());
@@ -292,6 +298,11 @@ static BCSSLParameters importSSLParameters(SSLParameters ssl)
292298

293299
// Unsupported as of JDK 21
294300

301+
// if (null != getEarlyNamedGroups)
302+
// {
303+
// bc.setEarlyNamedGroups((String[])get(ssl, getEarlyNamedGroups));
304+
// }
305+
295306
// if (null != getUseNamedGroupsOrder)
296307
// {
297308
// bc.setUseNamedGroupsOrder((Boolean)get(ssl, getUseNamedGroupsOrder));
@@ -371,6 +382,8 @@ static void setParameters(ProvSSLParameters prov, BCSSLParameters ssl)
371382

372383
prov.setNamedGroups(ssl.getNamedGroups());
373384

385+
prov.setEarlyNamedGroups(ssl.getEarlyNamedGroups());
386+
374387
prov.setSignatureSchemesCert(ssl.getSignatureSchemesCert());
375388
}
376389

@@ -482,6 +495,11 @@ static void setSSLParameters(ProvSSLParameters prov, SSLParameters ssl)
482495

483496
// Unsupported as of JDK 21
484497

498+
// if (null != getEarlyNamedGroups)
499+
// {
500+
// prov.setEarlyNamedGroups((String[])get(ssl, getEarlyNamedGroups));
501+
// }
502+
485503
// if (null != getUseNamedGroupsOrder)
486504
// {
487505
// prov.setUseNamedGroupsOrder((Boolean)get(ssl, getUseNamedGroupsOrder));

tls/src/main/jdk1.9/org/bouncycastle/jsse/provider/SSLParametersUtil.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ static BCSSLParameters getParameters(ProvSSLParameters prov)
5757
ssl.setSignatureSchemes(prov.getSignatureSchemes());
5858
ssl.setSignatureSchemesCert(prov.getSignatureSchemesCert());
5959
ssl.setNamedGroups(prov.getNamedGroups());
60+
ssl.setEarlyNamedGroups(prov.getEarlyNamedGroups());
6061

6162
return ssl;
6263
}
@@ -133,6 +134,11 @@ static SSLParameters getSSLParameters(ProvSSLParameters prov)
133134

134135
// Unsupported as of JDK 21
135136

137+
// if (null != setEarlyNamedGroups)
138+
// {
139+
// set(ssl, setEarlyNamedGroups, prov.getEarlyNamedGroups());
140+
// }
141+
136142
// if (null != setUseNamedGroupsOrder)
137143
// {
138144
// set(ssl, setUseNamedGroupsOrder, prov.getUseNamedGroupsOrder());
@@ -230,6 +236,11 @@ static BCSSLParameters importSSLParameters(SSLParameters ssl)
230236

231237
// Unsupported as of JDK 21
232238

239+
// if (null != getEarlyNamedGroups)
240+
// {
241+
// bc.setEarlyNamedGroups((String[])get(ssl, getEarlyNamedGroups));
242+
// }
243+
233244
// if (null != getUseNamedGroupsOrder)
234245
// {
235246
// bc.setUseNamedGroupsOrder((Boolean)get(ssl, getUseNamedGroupsOrder));
@@ -309,6 +320,8 @@ static void setParameters(ProvSSLParameters prov, BCSSLParameters ssl)
309320

310321
prov.setNamedGroups(ssl.getNamedGroups());
311322

323+
prov.setEarlyNamedGroups(ssl.getEarlyNamedGroups());
324+
312325
prov.setSignatureSchemesCert(ssl.getSignatureSchemesCert());
313326
}
314327

@@ -406,6 +419,11 @@ static void setSSLParameters(ProvSSLParameters prov, SSLParameters ssl)
406419

407420
// Unsupported as of JDK 21
408421

422+
// if (null != getEarlyNamedGroups)
423+
// {
424+
// prov.setEarlyNamedGroups((String[])get(ssl, getEarlyNamedGroups));
425+
// }
426+
409427
// if (null != getUseNamedGroupsOrder)
410428
// {
411429
// prov.setUseNamedGroupsOrder((Boolean)get(ssl, getUseNamedGroupsOrder));

0 commit comments

Comments
 (0)