JSSE: implement SNIMatcher logic for wolfSSLSockets

add thread safety
pull/259/head
Ruby Martin 2025-04-30 08:33:26 -06:00
parent 26b542cf8c
commit 74bf974354
4 changed files with 116 additions and 9 deletions

View File

@ -30,6 +30,8 @@ import java.net.InetAddress;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SNIMatcher;
import javax.net.ssl.SNIServerName;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLException;
import javax.net.ssl.X509TrustManager;
@ -1474,6 +1476,11 @@ public class WolfSSLEngineHelper {
* collected (ex: protocol version). */
this.session.updateStoredSessionValues();
if (!this.clientMode && !matchSNI()) {
throw new SSLHandshakeException(
"Unrecognized Server Name");
}
return ret;
}
@ -1531,6 +1538,59 @@ public class WolfSSLEngineHelper {
return "legacy".equals(dhKeySize);
}
/**
* Validates Server Name Indication (SNI) match between client request and
* server matchers.
*
* This helper method is used only on the server side during the TLS
* handshake to check if there is a server name in the list of requested
* server names that matches the SNI matcher parameter. The check will be
* ignored (return true) if no requested server name were sent by client
* or if the SNI matcher parameter has not been set.
*
* Triggers an SSLHandshakeException on server side during handshake when
* false.
*
* @return true on success or false if no match was found
*/
protected synchronized boolean matchSNI(){
List <SNIMatcher> matchers = this.params.getSNIMatchers();
if (matchers != null && !matchers.isEmpty()) {
/* Match a server name to SNI requested by Client */
List <SNIServerName> serverNames = this.session
.getRequestedServerNames();
if (serverNames != null && !serverNames.isEmpty()) {
for (SNIServerName serverName : serverNames) {
if (serverName.getType() == WolfSSL.WOLFSSL_SNI_HOST_NAME) {
/* If the SNI is of type WOLFSSL_SNI_HOST_NAME, compare
* the name to matchers list */
for (SNIMatcher matcher : matchers) {
if (matcher.matches(serverName)) {
/* If a match is found, accept the server name
* and return true value, break from loop */
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
() -> "Accepted SNI: " + serverName);
return true;
}
}
}
}
} else {
/* If server names are null or empty, ignore server name
* indication */
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
() -> "No server names found, ignoring SNI");
return true;
}
} else {
/* If matchers are null or empty, ignore server name indication */
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
() -> "No SNIMatchers set");
return true;
}
return false;
}
/**
* Unset the native verify callback and reset internal verify
* callback state.

View File

@ -21,7 +21,9 @@
package com.wolfssl.provider.jsse;
import java.util.List;
import javax.net.ssl.SNIMatcher;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
/**
@ -45,6 +47,7 @@ final class WolfSSLParameters {
private boolean needClientAuth = false;
private String endpointIdAlgorithm = null;
private List<WolfSSLSNIServerName> serverNames;
private List<SNIMatcher> sniMatchers;
private boolean useCipherSuiteOrder = true;
String[] applicationProtocols = new String[0];
private boolean useSessionTickets = false;
@ -72,7 +75,7 @@ final class WolfSSLParameters {
/* TODO: duplicate other properties here when WolfSSLParameters
* can handle them */
cp.setSNIMatchers(this.getSNIMatchers());
return cp;
}
@ -184,14 +187,27 @@ final class WolfSSLParameters {
}
/* TODO, create our own class for SNIMatcher, in case Java doesn't support it */
//void setSNIMatchers(Collection<SNIMatcher> matchers) {
// /* TODO */
//}
void setSNIMatchers(Collection<SNIMatcher> matchers) {
if (matchers != null && !matchers.isEmpty()) {
if (this.sniMatchers == null) {
this.sniMatchers = new ArrayList<SNIMatcher>();
}
for (SNIMatcher matcher : matchers) {
this.sniMatchers.add(matcher);
}
} else {
this.sniMatchers = new ArrayList<SNIMatcher>();
}
}
/* TODO, create our own class for SNIMatcher, in case Java doesn't support it */
//Collection<SNIMatcher> getSNIMatchers() {
// return null; /* TODO */
//}
List<SNIMatcher> getSNIMatchers() {
if (this.sniMatchers != null && !this.sniMatchers.isEmpty()) {
return Collections.unmodifiableList(new ArrayList<SNIMatcher>(sniMatchers));
} else {
return Collections.emptyList();
}
}
void setUseCipherSuitesOrder(boolean honorOrder) {
this.useCipherSuiteOrder = honorOrder;

View File

@ -39,6 +39,8 @@ public class WolfSSLParametersHelper
private static Method setApplicationProtocols = null;
private static Method getEndpointIdentificationAlgorithm = null;
private static Method setEndpointIdentificationAlgorithm = null;
private static Method getSNIMatchers = null;
private static Method setSNIMatchers = null;
private static Method getMaximumPacketSize = null;
private static Method setMaximumPacketSize = null;
@ -77,6 +79,12 @@ public class WolfSSLParametersHelper
case "setEndpointIdentificationAlgorithm":
setEndpointIdentificationAlgorithm = m;
continue;
case "getSNIMatchers":
getSNIMatchers = m;
continue;
case "setSNIMatchers":
setSNIMatchers = m;
continue;
case "getMaximumPacketSize":
getMaximumPacketSize = m;
continue;
@ -126,7 +134,7 @@ public class WolfSSLParametersHelper
* do not existing in older JDKs. Since older JDKs will not have them,
* use Java reflection to detect availability in helper class. */
if (setServerNames != null || setApplicationProtocols != null ||
setEndpointIdentificationAlgorithm != null) {
setEndpointIdentificationAlgorithm != null || setSNIMatchers != null) {
try {
/* load WolfSSLJDK8Helper at runtime, not compiled
@ -155,6 +163,10 @@ public class WolfSSLParametersHelper
mth.invoke(obj, ret,
setEndpointIdentificationAlgorithm, in);
}
if (setSNIMatchers != null) {
mth = cls.getDeclaredMethod("setSNIMatchers", paramList);
mth.invoke(obj, ret, setSNIMatchers, in);
}
} catch (Exception e) {
/* ignore, class not found */
@ -173,6 +185,14 @@ public class WolfSSLParametersHelper
/* Not available, just ignore and continue */
}
try {
if (setSNIMatchers != null) {
ret.setSNIMatchers(in.getSNIMatchers());
}
} catch (Exception e) {
/* Not available, just ignore and continue */
}
/* The following SSLParameters features are not yet supported
* by wolfJSSE (see Android API 23 note above). They are supported
* with newer versions of SSLParameters, but will need to be added
@ -222,7 +242,7 @@ public class WolfSSLParametersHelper
* do not existing in older JDKs. Since older JDKs will not have them,
* use Java reflection to detect availability in helper class. */
if (getServerNames != null || getApplicationProtocols != null ||
getEndpointIdentificationAlgorithm != null) {
getEndpointIdentificationAlgorithm != null || getSNIMatchers != null) {
try {
/* load WolfSSLJDK8Helper at runtime, not compiled on older JDKs */
Class<?> cls = Class.forName(
@ -247,6 +267,10 @@ public class WolfSSLParametersHelper
"getEndpointIdentificationAlgorithm", paramList);
mth.invoke(obj, in, out);
}
if (getSNIMatchers != null){
mth = cls.getDeclaredMethod("getSNIMatchers", paramList);
mth.invoke(obj, in, out);
}
} catch (Exception e) {
/* ignore, class not found */
@ -276,6 +300,9 @@ public class WolfSSLParametersHelper
out.setSNIMatchers(in.getSNIMatchers());
out.setUseCipherSuitesOrder(in.getUseCipherSuitesOrder());
*/
out.setSNIMatchers(in.getSNIMatchers());
}
}

View File

@ -1569,6 +1569,10 @@ public class WolfSSLSocket extends SSLSocket {
close();
throw e;
} catch (SSLHandshakeException e){
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
() -> "got SSLHandshakeException in doHandshake()");
throw e;
} catch (SSLException e) {
final int tmpErr = err;
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,