Skip to content

Commit f23ae91

Browse files
authored
Merge pull request #343 from cconlon/numCiphersFix
Handle empty cipher stack from wolfSSL_get_ciphers_compat(), filter anon ciphers by default
2 parents 7aa2a0d + 0920b7c commit f23ae91

14 files changed

Lines changed: 514 additions & 44 deletions

native/com_wolfssl_WolfSSL.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2237,6 +2237,11 @@ JNIEXPORT jstring JNICALL Java_com_wolfssl_WolfSSL_getAvailableCipherSuitesIana
22372237
}
22382238

22392239
numCiphers = sk_num(supportedCiphers);
2240+
if (numCiphers == 0) {
2241+
wolfSSL_free(ssl);
2242+
wolfSSL_CTX_free(ctx);
2243+
return NULL;
2244+
}
22402245

22412246
for (i = 0; i < numCiphers; i++) {
22422247
cipher = (const WOLFSSL_CIPHER*)sk_value(supportedCiphers, i);

src/java/com/wolfssl/provider/jsse/WolfSSLContext.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,9 +180,9 @@ private void createCtx() throws WolfSSLException {
180180
if (WolfSSLUtil.isSecurityPropertyStringSet(
181181
"wolfjsse.enabledCipherSuites")) {
182182
/* User is overriding cipher suites, set CTX list */
183-
this.setCtxCiphers(WolfSSLUtil.sanitizeSuites(ciphersIana));
183+
this.setCtxCiphers(WolfSSLUtil.sanitizeSuites(ciphersIana, true));
184184
}
185-
params.setCipherSuites(WolfSSLUtil.sanitizeSuites(ciphersIana));
185+
params.setCipherSuites(WolfSSLUtil.sanitizeSuites(ciphersIana, true));
186186

187187
/* Auto-populate enabled protocols with supported ones. Protocols
188188
* which have been disabled via system property get filtered in

src/java/com/wolfssl/provider/jsse/WolfSSLEngineHelper.java

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -478,28 +478,33 @@ protected synchronized WolfSSLImplementSSLSession getSession() {
478478
/**
479479
* Get all supported cipher suites in native wolfSSL library, which
480480
* are also allowed by "wolfjsse.enabledCipherSuites" system Security
481-
* property, if set.
481+
* property, if set. Does not auto-filter out anon suites, since this
482+
* returns all supported suites in native wolfSSL.
482483
*
483484
* @return String array of all supported cipher suites
484485
*/
485486
protected static synchronized String[] getAllCiphers() {
486-
return WolfSSLUtil.sanitizeSuites(WolfSSL.getCiphersIana());
487+
return WolfSSLUtil.sanitizeSuites(WolfSSL.getCiphersIana(), false);
487488
}
488489

489490
/**
490-
* Get all enabled cipher suites, and allowed via
491-
* wolfjsse.enabledCipherSuites system Security property (if set).
491+
* Get all enabled cipher suites, filtered by
492+
* wolfjsse.enabledCipherSuites system Security property (if set). Does
493+
* not auto-filter out anon suites, since this returns all enabled suites in
494+
* native wolfSSL.
492495
*
493496
* @return String array of all enabled cipher suites
494497
*/
495498
protected synchronized String[] getCiphers() {
496-
return WolfSSLUtil.sanitizeSuites(this.params.getCipherSuites());
499+
return WolfSSLUtil.sanitizeSuites(this.params.getCipherSuites(), false);
497500
}
498501

499502
/**
500-
* Set cipher suites enabled in WolfSSLParameters
503+
* Set cipher suites enabled in WolfSSLParameters.
501504
*
502-
* Sanitizes input array for invalid suites
505+
* Validates input array against supported cipher suites but does
506+
* not filter anonymous suites, allowing applications to explicitly
507+
* enable them if needed.
503508
*
504509
* @param suites String array of cipher suites to be enabled
505510
*
@@ -528,7 +533,7 @@ protected synchronized void setCiphers(String[] suites)
528533
}
529534
}
530535

531-
this.params.setCipherSuites(WolfSSLUtil.sanitizeSuites(suites));
536+
this.params.setCipherSuites(WolfSSLUtil.sanitizeSuites(suites, false));
532537
}
533538

534539
/**
@@ -1251,7 +1256,7 @@ private void setLocalParams(SSLSocket socket, SSLEngine engine)
12511256
throws SSLException {
12521257

12531258
this.setLocalCiphers(
1254-
WolfSSLUtil.sanitizeSuites(this.params.getCipherSuites()));
1259+
WolfSSLUtil.sanitizeSuites(this.params.getCipherSuites(), false));
12551260
this.setLocalProtocol(
12561261
WolfSSLUtil.sanitizeProtocols(
12571262
this.params.getProtocols(), WolfSSL.TLS_VERSION.INVALID));

src/java/com/wolfssl/provider/jsse/WolfSSLServerSocket.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ synchronized public String[] getEnabledCipherSuites() {
160160
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
161161
() -> "entered getEnabledCipherSuites()");
162162

163-
return WolfSSLUtil.sanitizeSuites(params.getCipherSuites());
163+
return WolfSSLUtil.sanitizeSuites(params.getCipherSuites(), false);
164164
}
165165

166166
@Override
@@ -178,9 +178,10 @@ synchronized public void setEnabledCipherSuites(String[] suites)
178178
throw new IllegalArgumentException("input array has length zero");
179179
}
180180

181-
/* sanitize cipher array for unsupported strings */
181+
/* validate cipher array for unsupported strings. Not filtering
182+
* anon suites in case user wants to explicitly set. */
182183
List<String> supported = Arrays.asList(
183-
WolfSSLUtil.sanitizeSuites(WolfSSL.getCiphersIana()));
184+
WolfSSLUtil.sanitizeSuites(WolfSSL.getCiphersIana(), false));
184185
for (int i = 0; i < suites.length; i++) {
185186
if (!supported.contains(suites[i])) {
186187
throw new IllegalArgumentException("Unsupported CipherSuite: " +
@@ -200,7 +201,7 @@ public String[] getSupportedCipherSuites() {
200201
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
201202
() -> "entered getSupportedCipherSuites()");
202203

203-
return WolfSSLUtil.sanitizeSuites(WolfSSL.getCiphersIana());
204+
return WolfSSLUtil.sanitizeSuites(WolfSSL.getCiphersIana(), false);
204205
}
205206

206207
@Override

src/java/com/wolfssl/provider/jsse/WolfSSLServerSocketFactory.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ public WolfSSLServerSocketFactory(com.wolfssl.WolfSSLContext ctx,
6262
/**
6363
* Returns the default cipher suite list for wolfJSSE.
6464
*
65+
* Filters out anon suites by default. User can explicitly set
66+
* if needed.
67+
*
6568
* @return default array of cipher suite Strings for wolfSSL
6669
*/
6770
@Override
@@ -70,7 +73,7 @@ public String[] getDefaultCipherSuites() {
7073
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
7174
() -> "entered getDefaultCipherSuites()");
7275

73-
return WolfSSLUtil.sanitizeSuites(WolfSSL.getCiphersIana());
76+
return WolfSSLUtil.sanitizeSuites(WolfSSL.getCiphersIana(), true);
7477
}
7578

7679
/**
@@ -84,7 +87,8 @@ public String[] getSupportedCipherSuites() {
8487
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
8588
() -> "entered getSupportedCipherSuites()");
8689

87-
return getDefaultCipherSuites();
90+
return WolfSSLUtil.sanitizeSuites(
91+
WolfSSL.getCiphersIana(), false);
8892
}
8993

9094
/**

src/java/com/wolfssl/provider/jsse/WolfSSLSocketFactory.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ private void initDefaultContext() throws WolfSSLException {
118118
/**
119119
* Returns the default cipher suite list for wolfJSSE.
120120
*
121+
* Filters out anon suites by default.
122+
*
121123
* @return default array of cipher suite Strings for wolfSSL
122124
*/
123125
@Override
@@ -126,7 +128,7 @@ public String[] getDefaultCipherSuites() {
126128
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
127129
() -> "entered getDefaultCipherSuites()");
128130

129-
return WolfSSLUtil.sanitizeSuites(WolfSSL.getCiphersIana());
131+
return WolfSSLUtil.sanitizeSuites(WolfSSL.getCiphersIana(), true);
130132
}
131133

132134
/**
@@ -140,7 +142,7 @@ public String[] getSupportedCipherSuites() {
140142
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
141143
() -> "entered getSupportedCipherSuites()");
142144

143-
return getDefaultCipherSuites();
145+
return WolfSSLUtil.sanitizeSuites(WolfSSL.getCiphersIana(), false);
144146
}
145147

146148
/**

src/java/com/wolfssl/provider/jsse/WolfSSLUtil.java

Lines changed: 49 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -125,37 +125,64 @@ protected static String[] sanitizeProtocols(String[] protocols,
125125
* Sanitize or filter SSL/TLS cipher suite list based on custom wolfJSSE
126126
* system property limitations.
127127
*
128-
* Supported system Security properties which limit cipher suite list are:
129-
* - wolfjsse.enabledCipherSuites
128+
* When filterAnon is true, this method filters the default enabled cipher
129+
* suite list, removing anonymous cipher suites to match SunJSSE behavior.
130+
* When filterAnon is false, anonymous cipher suites are preserved, allowing
131+
* applications to explicitly enable them via
132+
* SSLEngine.setEnabledCipherSuites() or SSLSocket.setEnabledCipherSuites().
130133
*
131-
* This security property should contain a comma-separated list of
132-
* values, for example:
134+
* Filtering applied:
135+
*
136+
* 1. If filterAnon is true, anonymous cipher suites (containing
137+
* "_anon_" in IANA name) are removed, matching SunJSSE behavior.
138+
*
139+
* 2. If the wolfjsse.enabledCipherSuites security property is set,
140+
* the list is further filtered to only include suites in that
141+
* property. This should contain a comma-separated list of values,
142+
* for example:
133143
*
134144
* wolfjsse.enabledCipherSuites=
135145
* "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, \
136146
* TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"
137147
*
138-
* Only the cipher suites included in this list will be allowed to be used
139-
* in JSSE TLS connections. Applications can still set cipher suites,
140-
* using for example SSLParameters, but the set cipher suite list will be
141-
* filtered by this function to remove any suites not included in the
142-
* system property mentioned here if it has been set.
143-
*
144148
* @param suites Full list of TLS cipher suites to sanitize/filter,
145-
* should be in format similar to: "SUITE1", "SUITE2", etc.
146-
*
147-
* @return New filtered String array of cipher suites.
149+
* should be in format similar to: "SUITE1", "SUITE2",
150+
* etc.
151+
* @param filterAnon If true, anonymous cipher suites (containing "_anon_"
152+
* in IANA name) will be filtered out. If false, anonymous
153+
* suites are preserved.
154+
*
155+
* @return New filtered String array of cipher suites, or null if input
156+
* is null.
148157
*/
149-
protected static String[] sanitizeSuites(String[] suites) {
158+
protected static String[] sanitizeSuites(String[] suites,
159+
boolean filterAnon) {
160+
150161
ArrayList<String> filtered = new ArrayList<String>();
151162

163+
if (suites == null) {
164+
return null;
165+
}
166+
167+
/* Filter out anonymous cipher suites if requested. SunJSSE also
168+
* excludes them from the default enabled list. Anonymous suites
169+
* contain "_anon_" in IANA format. When filterAnon is false, all
170+
* non-null suites pass through. */
171+
for (int i = 0; i < suites.length; i++) {
172+
if (suites[i] != null) {
173+
if (!filterAnon || !suites[i].contains("_anon_")) {
174+
filtered.add(suites[i]);
175+
}
176+
}
177+
}
178+
152179
String enabledSuites =
153180
Security.getProperty("wolfjsse.enabledCipherSuites");
154181
List<?> enabledList = null;
155182

156-
/* If system property not set, no filtering needed */
183+
/* If system property not set, return filtered list */
157184
if (enabledSuites == null || enabledSuites.isEmpty()) {
158-
return suites;
185+
return filtered.toArray(new String[filtered.size()]);
159186
}
160187

161188
final String tmpSuites = enabledSuites;
@@ -168,13 +195,15 @@ protected static String[] sanitizeSuites(String[] suites) {
168195
enabledSuites = enabledSuites.replaceAll(", ",",");
169196
enabledList = Arrays.asList(enabledSuites.split(","));
170197

171-
for (int i = 0; i < suites.length; i++) {
172-
if (enabledList.contains(suites[i])) {
173-
filtered.add(suites[i]);
198+
/* Further filter by wolfjsse.enabledCipherSuites property */
199+
ArrayList<String> propFiltered = new ArrayList<String>();
200+
for (int i = 0; i < filtered.size(); i++) {
201+
if (enabledList.contains(filtered.get(i))) {
202+
propFiltered.add(filtered.get(i));
174203
}
175204
}
176205

177-
return filtered.toArray(new String[filtered.size()]);
206+
return propFiltered.toArray(new String[propFiltered.size()]);
178207
}
179208

180209
/**

src/test/com/wolfssl/provider/jsse/test/WolfSSLContextTest.java

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -796,8 +796,19 @@ public void testWolfJSSEEnabledCipherSuites()
796796
fail("Invalid TLS version");
797797
}
798798

799-
/* String[] of all available native wolfSSL suites for version */
800-
nativeSuites = WolfSSL.getCiphersAvailableIana(version);
799+
/* String[] of all available native wolfSSL suites for version,
800+
* filtered to remove anonymous cipher suites to match what
801+
* SSLContext will return (wolfJSSE filters anon suites) */
802+
String[] rawSuites = WolfSSL.getCiphersAvailableIana(version);
803+
ArrayList<String> nonAnon = new ArrayList<String>();
804+
if (rawSuites != null) {
805+
for (String s : rawSuites) {
806+
if (s != null && !s.contains("_anon_")) {
807+
nonAnon.add(s);
808+
}
809+
}
810+
}
811+
nativeSuites = nonAnon.toArray(new String[nonAnon.size()]);
801812

802813
/* ------------------------------------------------------------- */
803814

@@ -991,12 +1002,57 @@ public void testSanitizeProtocolsNullInput() {
9911002
return;
9921003
}
9931004

994-
System.out.println("\t\t... passed");
1005+
System.out.println("\t... passed");
9951006

9961007
} catch (Exception e) {
9971008
System.out.println("\t... failed");
9981009
fail("Exception during sanitizeProtocols test: " + e.getMessage());
9991010
}
10001011
}
1012+
1013+
/* Helper: check if array has any anon suite */
1014+
private boolean arrayHasAnonSuite(String[] arr) {
1015+
if (arr == null) {
1016+
return false;
1017+
}
1018+
for (String s : arr) {
1019+
if (s != null && s.contains("_anon_")) {
1020+
return true;
1021+
}
1022+
}
1023+
return false;
1024+
}
1025+
1026+
@Test
1027+
public void testContextDefaultParamsExcludeAnon() throws Exception {
1028+
1029+
System.out.print("\tdefault params exclude anon");
1030+
1031+
String[] allCiphers = WolfSSL.getCiphersIana();
1032+
boolean haveAnon = false;
1033+
for (String s : allCiphers) {
1034+
if (s != null && s.contains("_anon_")) {
1035+
haveAnon = true;
1036+
break;
1037+
}
1038+
}
1039+
1040+
if (!haveAnon) {
1041+
System.out.println("\t... skipped (no anon suites)");
1042+
return;
1043+
}
1044+
1045+
Security.setProperty("wolfjsse.enabledCipherSuites", "");
1046+
SSLContext ctx = SSLContext.getInstance("TLS", ctxProvider);
1047+
ctx.init(null, null, null);
1048+
1049+
String[] defaults =
1050+
ctx.getDefaultSSLParameters().getCipherSuites();
1051+
assertNotNull(defaults);
1052+
assertFalse("Default params should not contain anon",
1053+
arrayHasAnonSuite(defaults));
1054+
1055+
System.out.println("\t... passed");
1056+
}
10011057
}
10021058

0 commit comments

Comments
 (0)