Skip to content

Commit 33176b6

Browse files
committed
SNI fixes
1 parent e0f5d62 commit 33176b6

File tree

9 files changed

+1719
-1174
lines changed

9 files changed

+1719
-1174
lines changed

quickfixj-core/pom.xml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,13 @@
123123
<version>4.2.6.Final</version>
124124
<scope>test</scope>
125125
</dependency>
126-
<dependency>
126+
<dependency>
127+
<groupId>org.burningwave</groupId>
128+
<artifactId>tools</artifactId>
129+
<version>0.27.2</version>
130+
<scope>test</scope>
131+
</dependency>
132+
<dependency>
127133
<groupId>org.apache.mina</groupId>
128134
<artifactId>mina-core</artifactId>
129135
</dependency>

quickfixj-core/src/main/doc/usermanual/usage/configuration.html

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -714,6 +714,22 @@ <H3>QuickFIX Settings</H3>
714714
<TD></TD>
715715
<TD></TD>
716716
</TR>
717+
<TR ALIGN="left" VALIGN="middle">
718+
<TD valign="top"> <I>UseSNI</I></TD>
719+
<TD>
720+
Enables the SSL engine to use Server Name Indication (SNI). This option is only applicable for initiators.
721+
<p>If provided, <i>SNIHostName</i> will be used as the server name. Otherwise, <i>SocketConnectHost</i> or <i>SocketConnectHost&lt;n&gt;</i> will be used.</p>
722+
<p>Note: When this option is disabled, the JVM may still implicitly send the SSL <code>server_name</code> extension.</p>
723+
</TD>
724+
<TD>Y<BR>N</TD>
725+
<TD>N</TD>
726+
</TR>
727+
<TR ALIGN="left" VALIGN="middle">
728+
<TD valign="top"> <I>SNIHostName</I></TD>
729+
<TD>SNI host name to be used as desired Server Name Indication (SNI) parameter.</TD>
730+
<TD></TD>
731+
<TD></TD>
732+
</TR>
717733

718734
<TR ALIGN="center" VALIGN="middle">
719735
<TD COLSPAN="4" class="subsection"><A NAME="Security">Socks Proxy Options (Initiator only)</A></TD>

quickfixj-core/src/main/java/quickfix/mina/initiator/IoSessionInitiator.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import quickfix.mina.ProtocolFactory;
4040
import quickfix.mina.SessionConnector;
4141
import quickfix.mina.message.FIXProtocolCodecFactory;
42+
import quickfix.mina.ssl.InitiatorSslFilter;
4243
import quickfix.mina.ssl.SSLConfig;
4344
import quickfix.mina.ssl.SSLContextFactory;
4445
import quickfix.mina.ssl.SSLSupport;
@@ -193,7 +194,7 @@ private void setupIoConnector() throws ConfigError, GeneralSecurityException {
193194
private void installSslFilter(CompositeIoFilterChainBuilder ioFilterChainBuilder)
194195
throws GeneralSecurityException {
195196
final SSLContext sslContext = SSLContextFactory.getInstance(sslConfig);
196-
final SslFilter sslFilter = new SslFilter(sslContext, false);
197+
final SslFilter sslFilter = new InitiatorSslFilter(sslContext, getSniHostName(sslConfig));
197198
sslFilter.setEnabledCipherSuites(sslConfig.getEnabledCipherSuites() != null ? sslConfig.getEnabledCipherSuites()
198199
: SSLSupport.getDefaultCipherSuites(sslContext));
199200
sslFilter.setEnabledProtocols(sslConfig.getEnabledProtocols() != null ? sslConfig.getEnabledProtocols()
@@ -202,6 +203,22 @@ private void installSslFilter(CompositeIoFilterChainBuilder ioFilterChainBuilder
202203
ioFilterChainBuilder.addLast(SSLSupport.FILTER_NAME, sslFilter);
203204
}
204205

206+
public String getSniHostName(SSLConfig sslConfig) {
207+
if (!sslConfig.isUseSNI()) {
208+
return null;
209+
}
210+
211+
if (sslConfig.getSniHostName() != null) {
212+
return sslConfig.getSniHostName();
213+
}
214+
215+
if (socketAddresses[nextSocketAddressIndex] instanceof InetSocketAddress) {
216+
return ((InetSocketAddress) socketAddresses[nextSocketAddressIndex]).getHostName();
217+
}
218+
219+
return null;
220+
}
221+
205222
@Override
206223
public void run() {
207224
resetIoConnector();
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package quickfix.mina.ssl;
2+
3+
import org.apache.mina.core.session.IoSession;
4+
import org.apache.mina.filter.ssl.SslFilter;
5+
6+
import javax.net.ssl.SNIHostName;
7+
import javax.net.ssl.SSLContext;
8+
import javax.net.ssl.SSLEngine;
9+
import javax.net.ssl.SSLParameters;
10+
import java.net.InetSocketAddress;
11+
import java.util.Arrays;
12+
13+
public final class InitiatorSslFilter extends SslFilter {
14+
15+
private final String sniHostName;
16+
17+
public InitiatorSslFilter(SSLContext sslContext, String sniHostName) {
18+
super(sslContext, false);
19+
this.sniHostName = sniHostName;
20+
}
21+
22+
@Override
23+
protected SSLEngine createEngine(IoSession session, InetSocketAddress addr) {
24+
SSLEngine sslEngine;
25+
26+
if (addr != null) {
27+
sslEngine = sslContext.createSSLEngine(addr.getHostName(), addr.getPort());
28+
} else {
29+
sslEngine = sslContext.createSSLEngine();
30+
}
31+
32+
if (wantClientAuth) {
33+
sslEngine.setWantClientAuth(true);
34+
}
35+
36+
if (needClientAuth) {
37+
sslEngine.setNeedClientAuth(true);
38+
}
39+
40+
if (enabledCipherSuites != null) {
41+
sslEngine.setEnabledCipherSuites(enabledCipherSuites);
42+
}
43+
44+
if (enabledProtocols != null) {
45+
sslEngine.setEnabledProtocols(enabledProtocols);
46+
}
47+
48+
if (getEndpointIdentificationAlgorithm() != null) {
49+
SSLParameters sslParameters = sslEngine.getSSLParameters();
50+
sslParameters.setEndpointIdentificationAlgorithm(getEndpointIdentificationAlgorithm());
51+
sslEngine.setSSLParameters(sslParameters);
52+
}
53+
54+
if (sniHostName != null) {
55+
SSLParameters sslParameters = sslEngine.getSSLParameters();
56+
sslParameters.setServerNames(Arrays.asList(new SNIHostName(sniHostName)));
57+
sslEngine.setSSLParameters(sslParameters);
58+
}
59+
60+
sslEngine.setUseClientMode(!session.isServer());
61+
62+
return sslEngine;
63+
}
64+
}

quickfixj-core/src/main/java/quickfix/mina/ssl/SSLConfig.java

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ public class SSLConfig {
3838
private String[] enabledCipherSuites;
3939
private boolean needClientAuth;
4040
private String endpointIdentificationAlgorithm;
41+
private boolean useSNI;
42+
private String sniHostName;
4143

4244
public String[] getEnabledCipherSuites() {
4345
return enabledCipherSuites;
@@ -87,7 +89,15 @@ public String getEndpointIdentificationAlgorithm() {
8789
return endpointIdentificationAlgorithm;
8890
}
8991

90-
public void setEnabledCipherSuites(String[] enabledCipherSuites) {
92+
public boolean isUseSNI() {
93+
return useSNI;
94+
}
95+
96+
public String getSniHostName() {
97+
return sniHostName;
98+
}
99+
100+
public void setEnabledCipherSuites(String[] enabledCipherSuites) {
91101
this.enabledCipherSuites = enabledCipherSuites;
92102
}
93103

@@ -119,7 +129,15 @@ public void setEndpointIdentificationAlgorithm(String endpointIdentificationAlgo
119129
this.endpointIdentificationAlgorithm = endpointIdentificationAlgorithm;
120130
}
121131

122-
public void setTrustManagerFactoryAlgorithm(String trustManagerFactoryAlgorithm) {
132+
public void setUseSNI(boolean useSNI) {
133+
this.useSNI = useSNI;
134+
}
135+
136+
public void setSniHostName(String sniHostName) {
137+
this.sniHostName = sniHostName;
138+
}
139+
140+
public void setTrustManagerFactoryAlgorithm(String trustManagerFactoryAlgorithm) {
123141
this.trustManagerFactoryAlgorithm = trustManagerFactoryAlgorithm;
124142
}
125143

@@ -151,12 +169,14 @@ public boolean equals(Object o) {
151169
Objects.equals(trustStoreType, sslConfig.trustStoreType) &&
152170
Arrays.equals(enabledProtocols, sslConfig.enabledProtocols) &&
153171
Arrays.equals(enabledCipherSuites, sslConfig.enabledCipherSuites) &&
154-
Objects.equals(endpointIdentificationAlgorithm, sslConfig.endpointIdentificationAlgorithm);
172+
Objects.equals(endpointIdentificationAlgorithm, sslConfig.endpointIdentificationAlgorithm) &&
173+
Objects.equals(useSNI, sslConfig.useSNI) &&
174+
Objects.equals(sniHostName, sslConfig.sniHostName);
155175
}
156176

157177
@Override
158178
public int hashCode() {
159-
int result = Objects.hash(keyStoreName, keyManagerFactoryAlgorithm, keyStoreType, trustStoreName, trustManagerFactoryAlgorithm, trustStoreType, needClientAuth, endpointIdentificationAlgorithm);
179+
int result = Objects.hash(keyStoreName, keyManagerFactoryAlgorithm, keyStoreType, trustStoreName, trustManagerFactoryAlgorithm, trustStoreType, needClientAuth, endpointIdentificationAlgorithm, useSNI, sniHostName);
160180
result = 31 * result + Arrays.hashCode(keyStorePassword);
161181
result = 31 * result + Arrays.hashCode(trustStorePassword);
162182
result = 31 * result + Arrays.hashCode(enabledProtocols);

quickfixj-core/src/main/java/quickfix/mina/ssl/SSLSupport.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ public class SSLSupport {
4040
public static final String SETTING_TRUST_STORE_TYPE = "TrustStoreType";
4141
public static final String SETTING_NEED_CLIENT_AUTH = "NeedClientAuth";
4242
public static final String SETTING_ENDPOINT_IDENTIFICATION_ALGORITHM = "EndpointIdentificationAlgorithm";
43+
public static final String SETTING_USE_SNI = "UseSNI";
44+
public static final String SETTING_SNI_HOST_NAME = "SNIHostName";
4345
public static final String SETTING_ENABLED_PROTOCOLS = "EnabledProtocols";
4446
public static final String SETTING_CIPHER_SUITES = "CipherSuites";
4547
static final String DEFAULT_STORE_TYPE = "JKS";
@@ -112,6 +114,8 @@ public static SSLConfig getSslConfig(SessionSettings sessionSettings, SessionID
112114
sslConfig.setEnabledProtocols(getEnabledProtocols(sessionSettings, sessionID));
113115
sslConfig.setNeedClientAuth(isNeedClientAuth(sessionSettings, sessionID));
114116
sslConfig.setEndpointIdentificationAlgorithm(getEndpointIdentificationAlgorithm(sessionSettings, sessionID));
117+
sslConfig.setUseSNI(isUseSNI(sessionSettings, sessionID));
118+
sslConfig.setSniHostName(getSNIHostName(sessionSettings, sessionID));
115119

116120
return sslConfig;
117121
}
@@ -153,4 +157,12 @@ public static boolean isNeedClientAuth(SessionSettings sessionSettings, SessionI
153157
public static String getEndpointIdentificationAlgorithm(SessionSettings sessionSettings, SessionID sessionID) {
154158
return getString(sessionSettings, sessionID, SETTING_ENDPOINT_IDENTIFICATION_ALGORITHM, null);
155159
}
160+
161+
public static boolean isUseSNI(SessionSettings sessionSettings, SessionID sessionID) {
162+
return "Y".equals(getString(sessionSettings, sessionID, SETTING_USE_SNI, "N"));
163+
}
164+
165+
public static String getSNIHostName(SessionSettings sessionSettings, SessionID sessionID) {
166+
return getString(sessionSettings, sessionID, SETTING_SNI_HOST_NAME, null);
167+
}
156168
}

0 commit comments

Comments
 (0)