diff --git a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java b/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java index d70c952544..0644023ee7 100644 --- a/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java +++ b/handler/src/main/java/io/netty/handler/ssl/OpenSslEngine.java @@ -222,6 +222,12 @@ public final class OpenSslEngine extends SSLEngine { // Set the client auth mode, this needs to be done via setClientAuth(...) method so we actually call the // needed JNI methods. setClientAuth(clientMode ? ClientAuth.NONE : checkNotNull(clientAuth, "clientAuth")); + + // Use SNI if peerHost was specified + // See https://github.com/netty/netty/issues/4746 + if (clientMode && peerHost != null) { + SSL.setTlsExtHostName(ssl, peerHost); + } } @Override diff --git a/handler/src/test/java/io/netty/handler/ssl/SniClientTest.java b/handler/src/test/java/io/netty/handler/ssl/SniClientTest.java new file mode 100644 index 0000000000..2af2da48b1 --- /dev/null +++ b/handler/src/test/java/io/netty/handler/ssl/SniClientTest.java @@ -0,0 +1,104 @@ +/* + * Copyright 2016 The Netty Project + * + * The Netty Project licenses this file to you under the Apache License, + * version 2.0 (the "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + */ +package io.netty.handler.ssl; + +import io.netty.bootstrap.Bootstrap; +import io.netty.bootstrap.ServerBootstrap; +import io.netty.buffer.ByteBufAllocator; +import io.netty.channel.Channel; +import io.netty.channel.ChannelInitializer; +import io.netty.channel.DefaultEventLoopGroup; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.local.LocalAddress; +import io.netty.channel.local.LocalChannel; +import io.netty.channel.local.LocalServerChannel; +import io.netty.handler.ssl.util.InsecureTrustManagerFactory; +import io.netty.handler.ssl.util.SelfSignedCertificate; +import io.netty.util.Mapping; +import io.netty.util.concurrent.Promise; +import org.junit.Assert; +import org.junit.Assume; +import org.junit.Test; + +public class SniClientTest { + + @Test + public void testSniClientJdkSslServerJdkSsl() throws Exception { + testSniClient(SslProvider.JDK, SslProvider.JDK); + } + + @Test + public void testSniClientOpenSslServerOpenSsl() throws Exception { + Assume.assumeTrue(OpenSsl.isAvailable()); + testSniClient(SslProvider.OPENSSL, SslProvider.OPENSSL); + } + + @Test + public void testSniClientJdkSslServerOpenSsl() throws Exception { + Assume.assumeTrue(OpenSsl.isAvailable()); + testSniClient(SslProvider.JDK, SslProvider.OPENSSL); + } + + @Test + public void testSniClientOpenSslServerJdkSsl() throws Exception { + Assume.assumeTrue(OpenSsl.isAvailable()); + testSniClient(SslProvider.OPENSSL, SslProvider.JDK); + } + + private static void testSniClient(SslProvider sslClientProvider, SslProvider sslServerProvider) throws Exception { + final String sniHost = "sni.netty.io"; + LocalAddress address = new LocalAddress("test"); + EventLoopGroup group = new DefaultEventLoopGroup(1); + Channel sc = null; + Channel cc = null; + try { + SelfSignedCertificate cert = new SelfSignedCertificate(); + final SslContext sslServerContext = SslContextBuilder.forServer(cert.key(), cert.cert()) + .sslProvider(sslServerProvider).build(); + + final Promise promise = group.next().newPromise(); + ServerBootstrap sb = new ServerBootstrap(); + sc = sb.group(group).channel(LocalServerChannel.class).childHandler(new ChannelInitializer() { + @Override + protected void initChannel(Channel ch) throws Exception { + ch.pipeline().addFirst(new SniHandler(new Mapping() { + @Override + public SslContext map(String input) { + promise.setSuccess(input); + return sslServerContext; + } + })); + } + }).bind(address).syncUninterruptibly().channel(); + + SslContext sslContext = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE) + .sslProvider(sslClientProvider).build(); + Bootstrap cb = new Bootstrap(); + cc = cb.group(group).channel(LocalChannel.class).handler(new SslHandler( + sslContext.newEngine(ByteBufAllocator.DEFAULT, sniHost, -1))) + .connect(address).syncUninterruptibly().channel(); + Assert.assertEquals(sniHost, promise.syncUninterruptibly().getNow()); + } finally { + if (cc != null) { + cc.close(); + } + if (sc != null) { + sc.close(); + } + group.shutdownGracefully(); + } + } +} diff --git a/pom.xml b/pom.xml index e5ae5d4f92..be65203dbb 100644 --- a/pom.xml +++ b/pom.xml @@ -216,7 +216,7 @@ fedora netty-tcnative - 1.1.33.Fork11 + 1.1.33.Fork12 ${os.detected.classifier} ${os.detected.name}-${os.detected.arch}