Skip to content

Commit 8eaead4

Browse files
committed
Add sni name to SSLEngine in nio transport
This commit is related to elastic#32517. It allows an "sni_server_name" attribute on a DiscoveryNode to be propagated to the server using the TLS SNI extentsion. Prior to this commit, this functionality was only support for the netty transport. This commit adds this functionality to the security nio transport.
1 parent 3f7cae3 commit 8eaead4

File tree

6 files changed

+225
-197
lines changed

6 files changed

+225
-197
lines changed

libs/nio/src/main/java/org/elasticsearch/nio/ChannelFactory.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ private static void closeRawChannel(Closeable c, Exception e) {
146146
}
147147
}
148148

149-
protected static class RawChannelFactory {
149+
public static class RawChannelFactory {
150150

151151
private final boolean tcpNoDelay;
152152
private final boolean tcpKeepAlive;

plugins/transport-nio/src/main/java/org/elasticsearch/transport/nio/NioTransport.java

+11-7
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
import java.nio.channels.SocketChannel;
5252
import java.util.concurrent.ConcurrentMap;
5353
import java.util.function.Consumer;
54+
import java.util.function.Function;
5455
import java.util.function.Supplier;
5556

5657
import static org.elasticsearch.common.util.concurrent.ConcurrentCollections.newConcurrentMap;
@@ -67,7 +68,7 @@ public class NioTransport extends TcpTransport {
6768
protected final PageCacheRecycler pageCacheRecycler;
6869
private final ConcurrentMap<String, TcpChannelFactory> profileToChannelFactory = newConcurrentMap();
6970
private volatile NioGroup nioGroup;
70-
private volatile TcpChannelFactory clientChannelFactory;
71+
private volatile Function<DiscoveryNode, TcpChannelFactory> clientChannelFactory;
7172

7273
protected NioTransport(Settings settings, Version version, ThreadPool threadPool, NetworkService networkService, BigArrays bigArrays,
7374
PageCacheRecycler pageCacheRecycler, NamedWriteableRegistry namedWriteableRegistry,
@@ -85,8 +86,7 @@ protected NioTcpServerChannel bind(String name, InetSocketAddress address) throw
8586
@Override
8687
protected NioTcpChannel initiateChannel(DiscoveryNode node) throws IOException {
8788
InetSocketAddress address = node.getAddress().address();
88-
NioTcpChannel channel = nioGroup.openChannel(address, clientChannelFactory);
89-
return channel;
89+
return nioGroup.openChannel(address, clientChannelFactory.apply(node));
9090
}
9191

9292
@Override
@@ -97,13 +97,13 @@ protected void doStart() {
9797
NioTransport.NIO_WORKER_COUNT.get(settings), (s) -> new EventHandler(this::onNonChannelException, s));
9898

9999
ProfileSettings clientProfileSettings = new ProfileSettings(settings, "default");
100-
clientChannelFactory = channelFactory(clientProfileSettings, true);
100+
clientChannelFactory = clientChannelFactoryFunction(clientProfileSettings);
101101

102102
if (NetworkService.NETWORK_SERVER.get(settings)) {
103103
// loop through all profiles and start them up, special handling for default one
104104
for (ProfileSettings profileSettings : profileSettings) {
105105
String profileName = profileSettings.profileName;
106-
TcpChannelFactory factory = channelFactory(profileSettings, false);
106+
TcpChannelFactory factory = serverChannelFactory(profileSettings);
107107
profileToChannelFactory.putIfAbsent(profileName, factory);
108108
bindServer(profileSettings);
109109
}
@@ -134,8 +134,12 @@ protected void acceptChannel(NioSocketChannel channel) {
134134
serverAcceptedChannel((NioTcpChannel) channel);
135135
}
136136

137-
protected TcpChannelFactory channelFactory(ProfileSettings settings, boolean isClient) {
138-
return new TcpChannelFactoryImpl(settings);
137+
protected TcpChannelFactory serverChannelFactory(ProfileSettings profileSettings) {
138+
return new TcpChannelFactoryImpl(profileSettings);
139+
}
140+
141+
protected Function<DiscoveryNode, TcpChannelFactory> clientChannelFactoryFunction(ProfileSettings profileSettings) {
142+
return (n) -> new TcpChannelFactoryImpl(profileSettings);
139143
}
140144

141145
protected abstract class TcpChannelFactory extends ChannelFactory<NioTcpServerChannel, NioTcpChannel> {

x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/ssl/SSLService.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -262,14 +262,14 @@ public boolean isSSLClientAuthEnabled(SSLConfiguration sslConfiguration) {
262262
/**
263263
* Returns the {@link SSLContext} for the global configuration. Mainly used for testing
264264
*/
265-
SSLContext sslContext() {
265+
public SSLContext sslContext() {
266266
return sslContextHolder(globalSSLConfiguration).sslContext();
267267
}
268268

269269
/**
270-
* Returns the {@link SSLContext} for the configuration
270+
* Returns the {@link SSLContext} for the configuration. Mainly used for testing
271271
*/
272-
SSLContext sslContext(SSLConfiguration configuration) {
272+
public SSLContext sslContext(SSLConfiguration configuration) {
273273
return sslContextHolder(configuration).sslContext();
274274
}
275275

x-pack/plugin/security/src/main/java/org/elasticsearch/xpack/security/transport/nio/SecurityNioTransport.java

+78-17
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import org.apache.logging.log4j.Logger;
1010
import org.apache.logging.log4j.message.ParameterizedMessage;
1111
import org.elasticsearch.Version;
12+
import org.elasticsearch.cluster.node.DiscoveryNode;
1213
import org.elasticsearch.common.Nullable;
1314
import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
1415
import org.elasticsearch.common.network.CloseableChannel;
@@ -19,12 +20,14 @@
1920
import org.elasticsearch.common.util.PageCacheRecycler;
2021
import org.elasticsearch.indices.breaker.CircuitBreakerService;
2122
import org.elasticsearch.nio.BytesChannelContext;
23+
import org.elasticsearch.nio.ChannelFactory;
2224
import org.elasticsearch.nio.InboundChannelBuffer;
2325
import org.elasticsearch.nio.NioSelector;
2426
import org.elasticsearch.nio.NioSocketChannel;
2527
import org.elasticsearch.nio.ServerChannelContext;
2628
import org.elasticsearch.nio.SocketChannelContext;
2729
import org.elasticsearch.threadpool.ThreadPool;
30+
import org.elasticsearch.transport.ConnectTransportException;
2831
import org.elasticsearch.transport.TcpChannel;
2932
import org.elasticsearch.transport.TcpTransport;
3033
import org.elasticsearch.transport.nio.NioTcpChannel;
@@ -38,7 +41,9 @@
3841
import org.elasticsearch.xpack.core.ssl.SSLService;
3942
import org.elasticsearch.xpack.security.transport.filter.IPFilter;
4043

44+
import javax.net.ssl.SNIHostName;
4145
import javax.net.ssl.SSLEngine;
46+
import javax.net.ssl.SSLParameters;
4247
import java.io.IOException;
4348
import java.net.InetSocketAddress;
4449
import java.nio.ByteBuffer;
@@ -47,6 +52,7 @@
4752
import java.util.Collections;
4853
import java.util.Map;
4954
import java.util.function.Consumer;
55+
import java.util.function.Function;
5056
import java.util.function.Supplier;
5157

5258
import static org.elasticsearch.xpack.core.security.SecurityField.setting;
@@ -128,8 +134,29 @@ public void onException(TcpChannel channel, Exception e) {
128134
}
129135

130136
@Override
131-
protected TcpChannelFactory channelFactory(ProfileSettings profileSettings, boolean isClient) {
132-
return new SecurityTcpChannelFactory(profileSettings, isClient);
137+
protected TcpChannelFactory serverChannelFactory(ProfileSettings profileSettings) {
138+
return new SecurityTcpChannelFactory(profileSettings, false);
139+
}
140+
141+
@Override
142+
protected Function<DiscoveryNode, TcpChannelFactory> clientChannelFactoryFunction(ProfileSettings profileSettings) {
143+
return (node) -> {
144+
final ChannelFactory.RawChannelFactory rawChannelFactory = new ChannelFactory.RawChannelFactory(profileSettings.tcpNoDelay,
145+
profileSettings.tcpKeepAlive, profileSettings.reuseAddress, Math.toIntExact(profileSettings.sendBufferSize.getBytes()),
146+
Math.toIntExact(profileSettings.receiveBufferSize.getBytes()));
147+
SNIHostName serverName;
148+
String configuredServerName = node.getAttributes().get("server_name");
149+
if (configuredServerName != null) {
150+
try {
151+
serverName = new SNIHostName(configuredServerName);
152+
} catch (IllegalArgumentException e) {
153+
throw new ConnectTransportException(node, "invalid DiscoveryNode server_name [" + configuredServerName + "]", e);
154+
}
155+
} else {
156+
serverName = null;
157+
}
158+
return new SecurityClientTcpChannelFactory(rawChannelFactory, serverName);
159+
};
133160
}
134161

135162
private class SecurityTcpChannelFactory extends TcpChannelFactory {
@@ -139,12 +166,16 @@ private class SecurityTcpChannelFactory extends TcpChannelFactory {
139166
private final NioIPFilter ipFilter;
140167

141168
private SecurityTcpChannelFactory(ProfileSettings profileSettings, boolean isClient) {
142-
super(new RawChannelFactory(profileSettings.tcpNoDelay,
169+
this(new RawChannelFactory(profileSettings.tcpNoDelay,
143170
profileSettings.tcpKeepAlive,
144171
profileSettings.reuseAddress,
145172
Math.toIntExact(profileSettings.sendBufferSize.getBytes()),
146-
Math.toIntExact(profileSettings.receiveBufferSize.getBytes())));
147-
this.profileName = profileSettings.profileName;
173+
Math.toIntExact(profileSettings.receiveBufferSize.getBytes())), profileSettings.profileName, isClient);
174+
}
175+
176+
private SecurityTcpChannelFactory(RawChannelFactory rawChannelFactory, String profileName, boolean isClient) {
177+
super(rawChannelFactory);
178+
this.profileName = profileName;
148179
this.isClient = isClient;
149180
this.ipFilter = new NioIPFilter(authenticator, profileName);
150181
}
@@ -162,18 +193,7 @@ public NioTcpChannel createChannel(NioSelector selector, SocketChannel channel)
162193

163194
SocketChannelContext context;
164195
if (sslEnabled) {
165-
SSLEngine sslEngine;
166-
SSLConfiguration defaultConfig = profileConfiguration.get(TcpTransport.DEFAULT_PROFILE);
167-
SSLConfiguration sslConfig = profileConfiguration.getOrDefault(profileName, defaultConfig);
168-
boolean hostnameVerificationEnabled = sslConfig.verificationMode().isHostnameVerificationEnabled();
169-
if (hostnameVerificationEnabled) {
170-
InetSocketAddress inetSocketAddress = (InetSocketAddress) channel.getRemoteAddress();
171-
// we create the socket based on the name given. don't reverse DNS
172-
sslEngine = sslService.createSSLEngine(sslConfig, inetSocketAddress.getHostString(), inetSocketAddress.getPort());
173-
} else {
174-
sslEngine = sslService.createSSLEngine(sslConfig, null, -1);
175-
}
176-
SSLDriver sslDriver = new SSLDriver(sslEngine, isClient);
196+
SSLDriver sslDriver = new SSLDriver(createSSLEngine(channel), isClient);
177197
context = new SSLChannelContext(nioChannel, selector, exceptionHandler, sslDriver, readWriteHandler, buffer, ipFilter);
178198
} else {
179199
context = new BytesChannelContext(nioChannel, selector, exceptionHandler, readWriteHandler, buffer, ipFilter);
@@ -192,5 +212,46 @@ public NioTcpServerChannel createServerChannel(NioSelector selector, ServerSocke
192212
nioChannel.setContext(context);
193213
return nioChannel;
194214
}
215+
216+
protected SSLEngine createSSLEngine(SocketChannel channel) throws IOException {
217+
SSLEngine sslEngine;
218+
SSLConfiguration defaultConfig = profileConfiguration.get(TcpTransport.DEFAULT_PROFILE);
219+
SSLConfiguration sslConfig = profileConfiguration.getOrDefault(profileName, defaultConfig);
220+
boolean hostnameVerificationEnabled = sslConfig.verificationMode().isHostnameVerificationEnabled();
221+
if (hostnameVerificationEnabled) {
222+
InetSocketAddress inetSocketAddress = (InetSocketAddress) channel.getRemoteAddress();
223+
// we create the socket based on the name given. don't reverse DNS
224+
sslEngine = sslService.createSSLEngine(sslConfig, inetSocketAddress.getHostString(), inetSocketAddress.getPort());
225+
} else {
226+
sslEngine = sslService.createSSLEngine(sslConfig, null, -1);
227+
}
228+
return sslEngine;
229+
}
230+
}
231+
232+
private class SecurityClientTcpChannelFactory extends SecurityTcpChannelFactory {
233+
234+
private final SNIHostName serverName;
235+
236+
private SecurityClientTcpChannelFactory(RawChannelFactory rawChannelFactory, SNIHostName serverName) {
237+
super(rawChannelFactory, TcpTransport.DEFAULT_PROFILE, true);
238+
this.serverName = serverName;
239+
}
240+
241+
@Override
242+
public NioTcpServerChannel createServerChannel(NioSelector selector, ServerSocketChannel channel) {
243+
throw new AssertionError("Cannot create TcpServerChannel with client factory");
244+
}
245+
246+
@Override
247+
protected SSLEngine createSSLEngine(SocketChannel channel) throws IOException {
248+
SSLEngine sslEngine = super.createSSLEngine(channel);
249+
if (serverName != null) {
250+
SSLParameters sslParameters = sslEngine.getSSLParameters();
251+
sslParameters.setServerNames(Collections.singletonList(serverName));
252+
sslEngine.setSSLParameters(sslParameters);
253+
}
254+
return sslEngine;
255+
}
195256
}
196257
}

0 commit comments

Comments
 (0)